<commit_before>var Point = Base.extend({
	beans: true,

	initialize: function() {
		if (arguments.length == 2) {
			this.x = arguments[0];
			this.y = arguments[1];
		} else if (arguments.length == 1) {
			var arg = arguments[0];
			if (arg == null) {
				this.x = this.y = 0;
			} else if (arg.x !== undefined) {
				this.x = arg.x;
				this.y = arg.y;
			} else if (arg.width !== undefined) {
				this.x = arg.width;
				this.y = arg.height;
			} else if (Array.isArray(arg)) {
				this.x = arg[0];
				this.y = arg.length > 1 ? arg[1] : arg[0];
			} else if (typeof arg === 'number') {
				this.x = this.y = arg;
			} else {
				this.x = this.y = 0;
			}
		} else {
			this.x = this.y = 0;
		}
	},

	clone: function() {
		return Point.create(this.x, this.y);
	},

	add: function() {
		var point = Point.read(arguments);
		return Point.create(this.x + point.x, this.y + point.y);
	},

	subtract: function() {
		var point = Point.read(arguments);
		return Point.create(this.x - point.x, this.y - point.y);
	},

	multiply: function() {
		var point = Point.read(arguments);
		return Point.create(this.x * point.x, this.y * point.y);
	},

	divide: function() {
		var point = Point.read(arguments);
		return Point.create(this.x / point.x, this.y / point.y);
	},

	modulo: function() {
		var point = Point.read(arguments);
		return Point.create(this.x % point.x, this.y % point.y);
	},

	negate: function() {
		return Point.create(-this.x, -this.y);
	},

	equals: function() {
		var point = Point.read(arguments);
		return this.x == point.x && this.y == point.y;
	},

	transform: function(matrix) {
		return matrix.transform(this);
	},

	getDistance: function() {
		var point = Point.read(arguments);
		var px = point.x - this.x;
		var py = point.y - this.y;
		return Math.sqrt(px * px + py * py);
	},

	getDistanceSquared: function() {
		var point = Point.read(arguments);
		var px = point.x - this.x;
		var py = point.y - this.y;
		return px * px + py * py;
	},

	getLength: function() {
		var point = Point.read(arguments);
		return Math.sqrt(this.x * this.x + this.y * this.y);
	},

	setLength: function(length) {
		if (this.isZero()) {
			if (this._angle != null) {
				var a = this._angle;
				this.x = Math.cos(a) * length;
				this.y = Math.sin(a) * length;
			} else {
				// Assume angle = 0
				this.x = length;
				// y is already 0
			}
		} else {
			var scale = length / this.length;
			if (scale == 0.0) {
				// Calculate angle now, so it will be preserved even when
				// x and y are 0
				this.getAngle();
			}
			this.x *= scale;
			this.y *= scale;
		}
	},

	normalize: function(length) {
		if (length === null)
			length = 1;
		var len = this.length;
		var scale = len != 0 ? length / len : 0;
		var res = Point.create(this.x * scale, this.y * scale);
		// Preserve angle.
		res._angle = this._angle;
		return res;
	},

	getAngleInRadians: function() {
		// TODO: Not sur we want this one, but if so, just rely on
		// this.getAngle(), which caches values internally?
		return Math.atan2(this.y, this.x);
	},

	getAngleInDegrees: function() {
		// TODO: Not sur we want this one, but if so, just rely on
		// this.getAngle(), which caches values internally?
		return Math.atan2(this.y, this.x) * 180 / Math.PI;
	},

	getQuadrant: function() {
		if (this.x >= 0) {
			if (this.y >= 0) {
				return 1;
			} else {
				return 4;
			}
		} else {
			if (this.y >= 0) {
				return 2;
			} else {
				return 3;
			}
		}
	},

	setAngle: function(angle) {
		angle = this._angle = angle * Math.PI / 180;
		if (!this.isZero()) {
			var length = this.length;
			this.x = Math.cos(angle) * length;
			this.y = Math.sin(angle) * length;
		}
	},

	getAngle: function() {
		var angle;
		if (arguments.length) {
			var point = Point.read(arguments);
			var div = this.length * point.length;
			if (div == 0) {
				return NaN;
			} else {
				angle = Math.acos(this.dot(point) / div);
			}
		} else {
			if (this._angle == null)
				this._angle = Math.atan2(this.y, this.x);
			angle = this._angle;
		}
		return angle * 180 / Math.PI;
	},

	getDirectedAngle: function() {
		var point = Point.read(arguments);
		var angle = this.angle - point.angle;
		var bounds = 180;
		if (angle < - bounds) {
			return angle + bounds * 2;
		} else if (angle > bounds) {
			return angle - bounds * 2;
		} else {
			return angle;
		}
	},

	// TODO: Add center parameter support back to Scriptographer
	rotate: function(angle, center) {
		var point = center ? this.subtract(center) : this;
		angle = angle * Math.PI / 180;
		var s = Math.sin(angle);
		var c = Math.cos(angle);
		point = Point.create(
			point.x * c - point.y * s,
			point.y * c + point.x * s
		);
		return center ? point.add(center) : point;
	},

	interpolate: function(point, t) {
		return Point.create(
			this.x * (1 - t) + point.x * t,
			this.y * (1 - t) + point.y * t
		);
	},

	isInside: function(rect) {
		return rect.contains(this);
	},

	isClose: function(point, tolerance) {
		return this.getDistance(point) < tolerance;
	},

	isParallel: function(point) {
		return Math.abs(this.x / point.x - this.y / point.y) < 0.00001;
	},

	isZero: function() {
		return this.x == 0 && this.y == 0;
	},

	isNaN: function() {
		return isNaN(this.x) || isNaN(this.y);
	},

	round: function() {
		return Point.create(Math.round(this.x), Math.round(this.y));
	},

	ceil: function() {
		return Point.create(Math.ceil(this.x), Math.ceil(this.y));
	},

	floor: function() {
		return Point.create(Math.floor(this.x), Math.floor(this.y));
	},

	abs: function() {
		return Point.create(Math.abs(this.x), Math.abs(this.y));
	},

	dot: function() {
		var point = Point.read(arguments);
		return this.x * point.x + this.y * point.y;
	},

	cross: function() {
		var point = Point.read(arguments);
		return this.x * point.y - this.y - point.x;
	},

	project: function() {
		var point = Point.read(arguments);
		if (point.isZero()) {
			return Point.create(0, 0);
		} else {
			var scale = this.dot(point) / point.dot(point);
			return Point.create(
				point.x * scale,
				point.y * scale
			);
		}
	},

	toString: function() {
		return '{ x: ' + this.x + ', y: ' + this.y + ' }';
	},

	statics: {
		/**
		 * Provide a faster creator for Points out of two coordinates that
		 * does not rely on Point#initialize at all. This speeds up all math
		 * operations a lot.
		 */
		create: function(x, y) {
			var point = new Point(Point.dont);
			point.x = x;
			point.y = y;
			return point;
		},

		read: function(args, index) {
			var index = index || 0, length = args.length - index;
			if (length == 1 && args[index] instanceof Point) {
				return args[index];
			} else if (length != 0) {
				var point = new Point(Point.dont);
				point.initialize.apply(point, index > 0
						? Array.prototype.slice.call(args, index) : args);
				return point;
			}
			return null;
		},

		min: function(point1, point2) {
			return Point.create(
				Math.min(point1.x, point2.x),
				Math.min(point1.y, point2.y));
		},

		max: function(point1, point2) {
			return Point.create(
				Math.max(point1.x, point2.x),
				Math.max(point1.y, point2.y));
		},

		random: function() {
			return Point.create(Math.random(), Math.random());
		}
	}
});
<commit_msg>Add documentation from Point.java to Point.js, remove TODO about adding back center support to Scriptographer for Point#rotate, since it is already there.<commit_after>var Point = Base.extend({
	beans: true,

	initialize: function() {
		if (arguments.length == 2) {
			this.x = arguments[0];
			this.y = arguments[1];
		} else if (arguments.length == 1) {
			var arg = arguments[0];
			if (arg == null) {
				this.x = this.y = 0;
			} else if (arg.x !== undefined) {
				this.x = arg.x;
				this.y = arg.y;
			} else if (arg.width !== undefined) {
				this.x = arg.width;
				this.y = arg.height;
			} else if (Array.isArray(arg)) {
				this.x = arg[0];
				this.y = arg.length > 1 ? arg[1] : arg[0];
			} else if (typeof arg === 'number') {
				this.x = this.y = arg;
			} else {
				this.x = this.y = 0;
			}
		} else {
			this.x = this.y = 0;
		}
	},

	clone: function() {
		return Point.create(this.x, this.y);
	},

	add: function() {
		var point = Point.read(arguments);
		return Point.create(this.x + point.x, this.y + point.y);
	},

	subtract: function() {
		var point = Point.read(arguments);
		return Point.create(this.x - point.x, this.y - point.y);
	},

	multiply: function() {
		var point = Point.read(arguments);
		return Point.create(this.x * point.x, this.y * point.y);
	},

	divide: function() {
		var point = Point.read(arguments);
		return Point.create(this.x / point.x, this.y / point.y);
	},

	modulo: function() {
		var point = Point.read(arguments);
		return Point.create(this.x % point.x, this.y % point.y);
	},

	negate: function() {
		return Point.create(-this.x, -this.y);
	},

	equals: function() {
		var point = Point.read(arguments);
		return this.x == point.x && this.y == point.y;
	},

	transform: function(matrix) {
		return matrix.transform(this);
	},

	/**
	 * Returns the distance between the point and another point.
	 *
	 * Sample code:
	 *
	 * var firstPoint = new Point(5, 10);
	 * var secondPoint = new Point(5, 20);
	 *
	 * var distance = firstPoint.getDistance(secondPoint);
	 *
	 * print(distance); // 10
	 *
	 *
	 * @param px
	 * @param py
	 */
	getDistance: function() {
		var point = Point.read(arguments);
		var px = point.x - this.x;
		var py = point.y - this.y;
		return Math.sqrt(px * px + py * py);
	},

	getDistanceSquared: function() {
		var point = Point.read(arguments);
		var px = point.x - this.x;
		var py = point.y - this.y;
		return px * px + py * py;
	},

	/**
	 * The length of the vector that is represented by this point's coordinates.
	 * Each point can be interpreted as a vector that points from the origin
	 * ({@code x = 0},{@code y = 0}) to the point's location.
	 * Setting the length changes the location but keeps the vector's angle.
	 */
	getLength: function() {
		var point = Point.read(arguments);
		return Math.sqrt(this.x * this.x + this.y * this.y);
	},

	setLength: function(length) {
		if (this.isZero()) {
			if (this._angle != null) {
				var a = this._angle;
				this.x = Math.cos(a) * length;
				this.y = Math.sin(a) * length;
			} else {
				// Assume angle = 0
				this.x = length;
				// y is already 0
			}
		} else {
			var scale = length / this.length;
			if (scale == 0.0) {
				// Calculate angle now, so it will be preserved even when
				// x and y are 0
				this.getAngle();
			}
			this.x *= scale;
			this.y *= scale;
		}
	},

	normalize: function(length) {
		if (length === null)
			length = 1;
		var len = this.length;
		var scale = len != 0 ? length / len : 0;
		var res = Point.create(this.x * scale, this.y * scale);
		// Preserve angle.
		res._angle = this._angle;
		return res;
	},

	getAngleInRadians: function() {
		// TODO: Not sur we want this one, but if so, just rely on
		// this.getAngle(), which caches values internally?
		return Math.atan2(this.y, this.x);
	},

	getAngleInDegrees: function() {
		// TODO: Not sur we want this one, but if so, just rely on
		// this.getAngle(), which caches values internally?
		return Math.atan2(this.y, this.x) * 180 / Math.PI;
	},

	getQuadrant: function() {
		if (this.x >= 0) {
			if (this.y >= 0) {
				return 1;
			} else {
				return 4;
			}
		} else {
			if (this.y >= 0) {
				return 2;
			} else {
				return 3;
			}
		}
	},

	/**
	 * {@grouptitle Angle & Rotation}
	 *
	 * The vector's angle, measured from the x-axis to the vector.
	 *
	 * When supplied with a point, returns the smaller angle between two
	 * vectors. The angle is unsigned, no information about rotational
	 * direction is given.
	 *
	 * Read more about angle units and orientation in the description of the
	 * {@link #getAngle()} property.
	 *
	 * @param point
	 */
	getAngle: function() {
		var angle;
		if (arguments.length) {
			var point = Point.read(arguments);
			var div = this.length * point.length;
			if (div == 0) {
				return NaN;
			} else {
				angle = Math.acos(this.dot(point) / div);
			}
		} else {
			if (this._angle == null)
				this._angle = Math.atan2(this.y, this.x);
			angle = this._angle;
		}
		return angle * 180 / Math.PI;
	},

	setAngle: function(angle) {
		angle = this._angle = angle * Math.PI / 180;
		if (!this.isZero()) {
			var length = this.length;
			this.x = Math.cos(angle) * length;
			this.y = Math.sin(angle) * length;
		}
	},

	/**
	 * Returns the angle between two vectors. The angle is directional and
	 * signed, giving information about the rotational direction.
	 *
	 * Read more about angle units and orientation in the description of the
	 * {@link #getAngle()} property.
	 *
	 * @param point
	 */
	getDirectedAngle: function() {
		var point = Point.read(arguments);
		var angle = this.angle - point.angle;
		var bounds = 180;
		if (angle < - bounds) {
			return angle + bounds * 2;
		} else if (angle > bounds) {
			return angle - bounds * 2;
		} else {
			return angle;
		}
	},

	/**
	 * Rotates the point by the given angle around an optional center point.
	 * The object itself is not modified.
	 *
	 * Read more about angle units and orientation in the description of the
	 * {@link #getAngle()} property.
	 *
	 * @param angle the rotation angle
	 * @param center the center point of the rotation
	 * @return the rotated point
	 */
	rotate: function(angle, center) {
		var point = center ? this.subtract(center) : this;
		angle = angle * Math.PI / 180;
		var s = Math.sin(angle);
		var c = Math.cos(angle);
		point = Point.create(
			point.x * c - point.y * s,
			point.y * c + point.x * s
		);
		return center ? point.add(center) : point;
	},

	/**
	 * Returns the interpolation point between the point and another point.
	 * The object itself is not modified!
	 *
	 * @param point
	 * @param t the position between the two points as a value between 0 and 1
	 * @return the interpolation point
	 *
	 * @jshide
	 */
	interpolate: function(point, t) {
		return Point.create(
			this.x * (1 - t) + point.x * t,
			this.y * (1 - t) + point.y * t
		);
	},

	/**
	 * {@grouptitle Tests}
	 *
	 * Checks whether the point is inside the boundaries of the rectangle.
	 *
	 * @param rect the rectangle to check against
	 * @return {@true if the point is inside the rectangle}
	 */
	isInside: function(rect) {
		return rect.contains(this);
	},

	/**
	 * Checks if the point is within a given distance of another point.
	 *
	 * @param point the point to check against
	 * @param tolerance the maximum distance allowed
	 * @return {@true if it is within the given distance}
	 */
	isClose: function(point, tolerance) {
		return this.getDistance(point) < tolerance;
	},

	/**
	 * Checks if the vector represented by this point is parallel (collinear) to
	 * another vector.
	 *
	 * @param point the vector to check against
	 * @return {@true if it is parallel}
	 */
	isParallel: function(point) {
		return Math.abs(this.x / point.x - this.y / point.y) < 0.00001;
	},

	/**
	 * Checks if this point has both the x and y coordinate set to 0.
	 *
	 * @return {@true if both x and y are 0}
	 */
	isZero: function() {
		return this.x == 0 && this.y == 0;
	},

	/**
	 * Checks if this point has an undefined value for at least one of its
	 * coordinates.
	 *
	 * @return {@true if either x or y are not a number}
	 */
	isNaN: function() {
		return isNaN(this.x) || isNaN(this.y);
	},

	/**
	 * {@grouptitle Math Functions}
	 *
	 * Returns a new point with rounded {@link #x} and {@link #y} values. The
	 * object itself is not modified!
	 *
	 * Sample code:
	 *
	 * var point = new Point(10.2, 10.9);
	 * var roundPoint = point.round();
	 * print(roundPoint); // { x: 10.0, y: 11.0 }
	 *
	 */
	round: function() {
		return Point.create(Math.round(this.x), Math.round(this.y));
	},

	/**
	 * Returns a new point with the nearest greater non-fractional values to the
	 * specified {@link #x} and {@link #y} values. The object itself is not
	 * modified!
	 *
	 * Sample code:
	 *
	 * var point = new Point(10.2, 10.9);
	 * var ceilPoint = point.ceil();
	 * print(ceilPoint); // { x: 11.0, y: 11.0 }
	 *
	 */
	ceil: function() {
		return Point.create(Math.ceil(this.x), Math.ceil(this.y));
	},

	/**
	 * Returns a new point with the nearest smaller non-fractional values to the
	 * specified {@link #x} and {@link #y} values. The object itself is not
	 * modified!
	 *
	 * Sample code:
	 *
	 * var point = new Point(10.2, 10.9);
	 * var floorPoint = point.floor();
	 * print(floorPoint); // { x: 10.0, y: 10.0 }
	 *
	 */
	floor: function() {
		return Point.create(Math.floor(this.x), Math.floor(this.y));
	},

	/**
	 * Returns a new point with the absolute values of the specified {@link #x}
	 * and {@link #y} values. The object itself is not modified!
	 *
	 * Sample code:
	 *
	 * var point = new Point(-5, 10);
	 * var absPoint = point.abs();
	 * print(absPoint); // { x: 5.0, y: 10.0 }
	 *
	 */
	abs: function() {
		return Point.create(Math.abs(this.x), Math.abs(this.y));
	},

	/**
	 * {@grouptitle Vectorial Math Functions}
	 *
	 * Returns the dot product of the point and another point.
	 * @param point
	 * @return the dot product of the two points
	 */
	dot: function() {
		var point = Point.read(arguments);
		return this.x * point.x + this.y * point.y;
	},

	/**
	 * Returns the cross product of the point and another point.
	 * @param point
	 * @return the cross product of the two points
	 */
	cross: function() {
		var point = Point.read(arguments);
		return this.x * point.y - this.y - point.x;
	},

	/**
	 * Returns the projection of the point on another point.
	 * Both points are interpreted as vectors.
	 *
	 * @param point
	 * @return the project of the point on another point
	 */
	project: function() {
		var point = Point.read(arguments);
		if (point.isZero()) {
			return Point.create(0, 0);
		} else {
			var scale = this.dot(point) / point.dot(point);
			return Point.create(
				point.x * scale,
				point.y * scale
			);
		}
	},

	toString: function() {
		return '{ x: ' + this.x + ', y: ' + this.y + ' }';
	},

	statics: {
		/**
		 * Provide a faster creator for Points out of two coordinates that
		 * does not rely on Point#initialize at all. This speeds up all math
		 * operations a lot.
		 */
		create: function(x, y) {
			var point = new Point(Point.dont);
			point.x = x;
			point.y = y;
			return point;
		},

		read: function(args, index) {
			var index = index || 0, length = args.length - index;
			if (length == 1 && args[index] instanceof Point) {
				return args[index];
			} else if (length != 0) {
				var point = new Point(Point.dont);
				point.initialize.apply(point, index > 0
						? Array.prototype.slice.call(args, index) : args);
				return point;
			}
			return null;
		},

		/**
		 * Returns a new point object with the smallest {@link #x} and
		 * {@link #y} of the supplied points.
		 *
		 * Sample code:
		 *
		 * var point1 = new Point(10, 100);
		 * var point2 = new Point(200, 5);
		 * var minPoint = Point.min(point1, point2);
		 * print(minPoint); // { x: 10.0, y: 5.0 }
		 *
		 *
		 * @param point1
		 * @param point2
		 * @return The newly created point object
		 */
		min: function(point1, point2) {
			return Point.create(
				Math.min(point1.x, point2.x),
				Math.min(point1.y, point2.y));
		},

		/**
		 * Returns a new point object with the largest {@link #x} and
		 * {@link #y} of the supplied points.
		 *
		 * Sample code:
		 *
		 * var point1 = new Point(10, 100);
		 * var point2 = new Point(200, 5);
		 * var maxPoint = Point.max(point1, point2);
		 * print(maxPoint); // { x: 200.0, y: 100.0 }
		 *
		 *
		 * @param point1
		 * @param point2
		 * @return The newly created point object
		 */
		max: function(point1, point2) {
			return Point.create(
				Math.max(point1.x, point2.x),
				Math.max(point1.y, point2.y));
		},

		/**
		 * Returns a point object with random {@link #x} and {@link #y} values
		 * between {@code 0} and {@code 1}.
		 *
		 * Sample code:
		 *
		 * var maxPoint = new Point(100, 100);
		 * var randomPoint = Point.random();
		 *
		 * // A point between {x:0, y:0} and {x:100, y:100}:
		 * var point = maxPoint * randomPoint;
		 *
		 */
		random: function() {
			return Point.create(Math.random(), Math.random());
		}
	}
});
<|endoftext|>


<commit_before>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    interval = typeof interval !== 'undefined' ? interval : 30;
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && _dubug(uninstalled.length.toString()+" nodes to update");
    uninstalled.length && installbot(uninstalled);
}

function chatbot() {
    botupdate();

    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    //reply in current chat window
    if ( $('.activeColumn:has(".bot.active")').length ) {
        var observer = new MutationObserver(function(mutations) {
         mutations.forEach(function(mutation) {
            e = mutation.addNodes;
            console.log(e);
            //dirty hack: disconnect every time bot runs
            if (mutation.addNodes.length && mutation.addedNodes[1].className == 'chatItem you'){
                observer.disconnect();
            }
         });
        });
        observer.observe($('#chat_chatmsglist')[0], { childList: true});
    }

    //reply for red dotted item
    //$('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(runtimeGlobal.interval);
botupdate();
<commit_msg>测试mutation observer<commit_after>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    interval = typeof interval !== 'undefined' ? interval : 30;
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && _dubug(uninstalled.length.toString()+" nodes to update");
    uninstalled.length && installbot(uninstalled);
}

function chatbot() {
    botupdate();

    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    //reply in current chat window
    if ( $('.activeColumn:has(".bot.active")').length ) {
        var observer = new MutationObserver(function(mutations) {
         mutations.forEach(function(mutation) {
            e = mutation.addNodes;
            console.log(e);
            //dirty hack: disconnect every time bot runs
            if (mutation.addNodes !== undefined && mutation.addedNodes[1].className == 'chatItem you'){
                observer.disconnect();
            }
         });
        });
        observer.observe($('#chat_chatmsglist')[0], { childList: true});
    }

    //reply for red dotted item
    //$('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(runtimeGlobal.interval);
botupdate();
<|endoftext|>


<commit_before>Mac OS X        	2GyATTRyr%com.apple.metadata:kMDItemWhereFroms:?com.apple.quarantinebplist00_Cftp://waaar@ftp.dinhosting.fr/www/sites/milk/flappy_bird/01/main.js
Pq/0001;56e5b5a6;Cyberduck;BD53144E-B066-4750-8164-C5788EEC8269<commit_msg>Delete ._main.js<commit_after><|endoftext|>


<commit_before>'use strict';

// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
process.on('unhandledRejection', (err) => { throw err; });

const fs = require('fs');
const childProcess = require('child_process');
const semver = require('semver');

/*

Usage

node src/bin/release.js patch

*/
const usage =
    'node src/bin/release.js [patch/minor/major] -- example: "node src/bin/release.js patch"';

const release = process.argv[2];

if (!release) {
  console.log(usage);
  throw new Error('No release type included');
}

const changelog = fs.readFileSync('CHANGELOG.md', {encoding: 'utf8', flag: 'r'});
let packageJson = fs.readFileSync('./src/package.json', {encoding: 'utf8', flag: 'r'});
packageJson = JSON.parse(packageJson);
const currentVersion = packageJson.version;

const newVersion = semver.inc(currentVersion, release);
if (!newVersion) {
  console.log(usage);
  throw new Error('Unable to generate new version from input');
}

const changelogIncludesVersion = changelog.indexOf(newVersion) !== -1;

if (!changelogIncludesVersion) {
  throw new Error(`No changelog record for ${newVersion}, please create changelog record`);
}

console.log('Okay looks good, lets create the package.json and package-lock.json');

packageJson.version = newVersion;

fs.writeFileSync('src/package.json', JSON.stringify(packageJson, null, 2));

// run npm version `release` where release is patch, minor or major
childProcess.execSync('npm install --package-lock-only', {cwd: 'src/'});
// run npm install --package-lock-only <-- required???

childProcess.execSync(`git checkout -b release/${newVersion}`);
childProcess.execSync('git add src/package.json');
childProcess.execSync('git add src/package-lock.json');
childProcess.execSync('git commit -m "bump version"');
childProcess.execSync(`git push origin release/${newVersion}`);

childProcess.execSync('make docs');
childProcess.execSync('cd .. && git clone git@github.com:ether/ether.github.com.git');
childProcess.execSync(`cp -R out/doc/ ../ether.github.com/doc/v${newVersion}`);

console.log('Once merged into master please run the following commands');
console.log(`git tag -a ${newVersion} -m ${newVersion} && git push origin master`);
console.log(`cd ../ether.github.com && git add . && git commit -m '${newVersion} docs'`);
console.log('Build the windows zip');
console.log('Visit https://github.com/ether/etherpad-lite/releases/new and create a new release ' +
            `with 'master' as the target and the version is ${newVersion}.  Include the windows ` +
            'zip as an asset');
console.log(`Once the new docs are uploaded then modify the download
   link on etherpad.org and then pull master onto develop`);
console.log('Finally go public with an announcement via our comms channels :)');
<commit_msg>release: Better steps for release procedure<commit_after>'use strict';

// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
process.on('unhandledRejection', (err) => { throw err; });

const fs = require('fs');
const childProcess = require('child_process');
const semver = require('semver');

/*

Usage

node src/bin/release.js patch

*/
const usage =
    'node src/bin/release.js [patch/minor/major] -- example: "node src/bin/release.js patch"';

const release = process.argv[2];

if (!release) {
  console.log(usage);
  throw new Error('No release type included');
}

const changelog = fs.readFileSync('CHANGELOG.md', {encoding: 'utf8', flag: 'r'});
let packageJson = fs.readFileSync('./src/package.json', {encoding: 'utf8', flag: 'r'});
packageJson = JSON.parse(packageJson);
const currentVersion = packageJson.version;

const newVersion = semver.inc(currentVersion, release);
if (!newVersion) {
  console.log(usage);
  throw new Error('Unable to generate new version from input');
}

const changelogIncludesVersion = changelog.indexOf(newVersion) !== -1;

if (!changelogIncludesVersion) {
  throw new Error(`No changelog record for ${newVersion}, please create changelog record`);
}

console.log('Okay looks good, lets create the package.json and package-lock.json');

packageJson.version = newVersion;

fs.writeFileSync('src/package.json', JSON.stringify(packageJson, null, 2));

// run npm version `release` where release is patch, minor or major
childProcess.execSync('npm install --package-lock-only', {cwd: 'src/'});
// run npm install --package-lock-only <-- required???

childProcess.execSync(`git checkout -b release/${newVersion}`);
childProcess.execSync('git add src/package.json');
childProcess.execSync('git add src/package-lock.json');
childProcess.execSync('git commit -m "bump version"');
childProcess.execSync(`git push origin release/${newVersion}`);

childProcess.execSync('make docs');
childProcess.execSync('cd .. && git clone git@github.com:ether/ether.github.com.git');
childProcess.execSync(`cp -R out/doc/ ../ether.github.com/doc/v${newVersion}`);

console.log('Once merged into master please run the following commands');
console.log(`git checkout master && git tag -a ${newVersion} -m ${newVersion} && git push origin master`);
console.log(`cd ../ether.github.com && git add . && git commit -m '${newVersion} docs' && git push`);
console.log('bin/buildForWindows.sh');
console.log('Visit https://github.com/ether/etherpad-lite/releases/new and create a new release ' +
            `with 'master' as the target and the version is ${newVersion}.  Include the windows ` +
            'zip as an asset');
console.log(`Once the new docs are uploaded then modify the download
   links (replace ${currentVersion} with ${newVersion} on etherpad.org and then pull master onto develop`);
console.log('Finally go public with an announcement via our comms channels :)');
<|endoftext|>


<commit_before>enyo.kind({
	name: "App",
	kind: "FittableRows",
	fit: true,
  tokens: [],
	components:[
		{kind: "onyx.Toolbar", content: "WebLetter"},
		{kind: "enyo.Scroller", fit: true,
      components: [
      //{name: "mylogger", content: "log", allowHtml: true},
			{name: "main", classes: "nice-padding", allowHtml: true, components: [
        {kind: "onyx.Groupbox", name: "settings", components: [
          {kind: "WebLetter.BooleanToken", key: "folding", description: "Folding Marks"},
          {kind: "WebLetter.BooleanToken", key: "togglefromphone", description: "Phone"},
          {kind: "WebLetter.BooleanToken", key: "togglefromlogo", description: "Logo"}
          ]
        },
        {kind: "WebLetter.AddressToken", name: "addresser", description: "Addresser", key: "from"},
        {kind: "WebLetter.AddressToken", name: "addressee", description: "Addressee", key: "to"},
        {kind: "onyx.Groupbox", name: "contentGroup", components: [
          {kind: "WebLetter.TextToken", description: "Subject", key: "subject", isOptional: true},
          {kind: "WebLetter.TextToken", description: "Opening", key: "opening"},
          {kind: "WebLetter.TextAreaToken", name: "lettercontent", allowHtml: true, key: "content", description: "Content", inputWidth: "800px", inputHeight: "400px"},
          {kind: "WebLetter.TextToken", key: "closing", description: "Closing"}
          ]
        },
        {tag: "form", name: "pdfform", attributes: {action: "http://localhost/webletter/server/letter.php", method: "post"}, showing: false},
          {kind: "onyx.Button", name: "go", content: "Generate PDF", ontap: "go"}
        ]
      }
		]}
	],
  create: function() {
    this.inherited(arguments);
    this.$.tokens = new Array();
  },
  handlers: {
    onNewToken: "registerToken",
    onDisableToken: "deregisterToken"
  },
  registerToken: function(inSender, inEvent) {
    this.tokens.push(inEvent.originator);
  },
  deregisterToken: function(inSender, inEvent) {
    var index = this.tokens.indexOf(inEvent.originator);
    while (index != -1) {
      this.tokens.splice(index, 1);
      index = this.tokens.indexOf(inEvent.originator);
    }
  },
  go: function() {
    //this.$.mylogger.addContent(this.$.lettercontent.getValue());
    this.$.pdfform.destroyComponents();
    for (i in this.tokens) {
      var type;
      var content = "";
      var value = "";
      if (this.tokens[i].multiline) {
        type = "textarea";
        content = this.tokens[i].getInput();
      } else {
        type = "input";
        value = this.tokens[i].getInput();
      }
      var keyprefix = "token-";
      var key = keyprefix + this.tokens[i].key;
      this.$.pdfform.createComponent({tag: type, attributes: {name: key, value: value}, content: content});
    }
    this.$.pdfform.render();
    document.getElementById(this.$.pdfform.getAttribute("id")).submit();
  }

});
<commit_msg>add opt-tokens to form if token is optional<commit_after>enyo.kind({
	name: "App",
	kind: "FittableRows",
	fit: true,
  tokens: [],
	components:[
		{kind: "onyx.Toolbar", content: "WebLetter"},
		{kind: "enyo.Scroller", fit: true,
      components: [
      //{name: "mylogger", content: "log", allowHtml: true},
			{name: "main", classes: "nice-padding", allowHtml: true, components: [
        {kind: "onyx.Groupbox", name: "settings", components: [
          {kind: "WebLetter.BooleanToken", key: "folding", description: "Folding Marks"},
          {kind: "WebLetter.BooleanToken", key: "togglefromphone", description: "Phone"},
          {kind: "WebLetter.BooleanToken", key: "togglefromlogo", description: "Logo"}
          ]
        },
        {kind: "WebLetter.AddressToken", name: "addresser", description: "Addresser", key: "from"},
        {kind: "WebLetter.AddressToken", name: "addressee", description: "Addressee", key: "to"},
        {kind: "onyx.Groupbox", name: "contentGroup", components: [
          {kind: "WebLetter.TextToken", description: "Subject", key: "subject", isOptional: true},
          {kind: "WebLetter.TextToken", description: "Opening", key: "opening"},
          {kind: "WebLetter.TextAreaToken", name: "lettercontent", allowHtml: true, key: "content", description: "Content", inputWidth: "800px", inputHeight: "400px"},
          {kind: "WebLetter.TextToken", key: "closing", description: "Closing"}
          ]
        },
        {tag: "form", name: "pdfform", attributes: {action: "http://localhost/webletter/server/letter.php", method: "post"}, showing: false},
          {kind: "onyx.Button", name: "go", content: "Generate PDF", ontap: "go"}
        ]
      }
		]}
	],
  create: function() {
    this.inherited(arguments);
    this.$.tokens = new Array();
  },
  handlers: {
    onNewToken: "registerToken",
    onDisableToken: "deregisterToken"
  },
  registerToken: function(inSender, inEvent) {
    this.tokens.push(inEvent.originator);
  },
  deregisterToken: function(inSender, inEvent) {
    var index = this.tokens.indexOf(inEvent.originator);
    while (index != -1) {
      this.tokens.splice(index, 1);
      index = this.tokens.indexOf(inEvent.originator);
    }
  },
  go: function() {
    //this.$.mylogger.addContent(this.$.lettercontent.getValue());
    this.$.pdfform.destroyComponents();
    for (i in this.tokens) {
      // add opt-token if the token is optional
      // note that only active tokens are in the token array,
      // thus we don't need to check if the token is enabled (it always is)
      if (this.tokens[i].isOptional) {
        var key = "%opt-token-" + this.tokens[i].key;
        this.$.pdfform.createComponent({tag: "input", attributes: {name: key, value: ""}});
      }
      var type;
      var content = "";
      var value = "";
      if (this.tokens[i].multiline) {
        type = "textarea";
        content = this.tokens[i].getInput();
      } else {
        type = "input";
        value = this.tokens[i].getInput();
      }
      var keyprefix = "token-";
      var key = keyprefix + this.tokens[i].key;
      this.$.pdfform.createComponent({tag: type, attributes: {name: key, value: value}, content: content});
    }
    this.$.pdfform.render();
    document.getElementById(this.$.pdfform.getAttribute("id")).submit();
  }

});
<|endoftext|>


<commit_before>enyo.kind({
	name: "App",
	kind: "FittableRows",
	fit: true,
  tokens: [],
	components:[
    {kind: WebLetter.Config, name: "config"},
		{kind: "onyx.Toolbar", content: "WebLetter"},
		{kind: "enyo.Scroller", fit: true,
      components: [
			{name: "main", classes: "nice-padding", allowHtml: true, components: [
        {kind: "onyx.Groupbox", name: "settings", components: [
          {kind: "WebLetter.BooleanToken", key: "folding", description: "Folding Marks"},
          {kind: "WebLetter.BooleanToken", key: "footer", description: "Footer"},
          {kind: "WebLetter.BooleanToken", key: "logo", description: "Logo"}
          ]
        },
        {kind: "WebLetter.AddressToken", name: "addresser", description: "Addresser", key: "from"},
        {kind: "WebLetter.AddressToken", name: "addressee", description: "Addressee", key: "to"},
        {kind: "onyx.Groupbox", name: "contentGroup", components: [
          {kind: "WebLetter.TextToken", description: "Subject", key: "subject", isOptional: true},
          {kind: "WebLetter.TextToken", description: "Opening", key: "opening"},
          {kind: "WebLetter.TextAreaToken", name: "lettercontent", allowHtml: true, key: "content", description: "Content", inputWidth: "100%", inputHeight: "400px"},
          {kind: "WebLetter.TextToken", key: "closing", description: "Closing"},
          {kind: "WebLetter.TextToken", key: "signatureaddition", description: "Signature Addition", isOptional: true, isEnabled: false},
          {kind: "WebLetter.TextToken", key: "ps", description: "PS", isOptional: true, isEnabled: false},
          {kind: "WebLetter.TextToken", key: "encl", description: "Enclosure", isOptional: true, isEnabled: false}
          ]
        },
        {tag: "form", name: "pdfform", showing: false},
          {kind: "onyx.Button", name: "go", content: "Generate PDF", ontap: "go"}
        ]
      }
		]}
	],
  create: function() {
    this.tokens = new Array();
    this.inherited(arguments);
    // set up form
    this.$.pdfform.attributes.method=this.$.config.getMethod();
    this.$.pdfform.attributes.action=this.$.config.getServerUrl();
  },
  handlers: {
    onNewToken: "registerToken",
    onDisableToken: "deregisterToken"
  },
  registerToken: function(inSender, inEvent) {
    this.tokens.push(inEvent.originator);
    return true;
  },
  deregisterToken: function(inSender, inEvent) {
    // do nothing since disabled tokens might be optional and
    // need the %nopt-token to be replaced
    return true;
  },
  go: function() {
    //this.$.mylogger.addContent(this.$.lettercontent.getValue());
    this.$.pdfform.destroyComponents();
    for (i in this.tokens) {
      if (this.tokens[i].isEnabled) {
        // add opt-token if the token is optional
        if (this.tokens[i].isOptional) {
          var key = "%opt-" + this.tokens[i].key;
          this.$.pdfform.createComponent({tag: "input", attributes: {name: key, value: ""}});
        }
        if (this.tokens[i].topToken) {
          var type;
          var content = "";
          var value = "";
          if (this.tokens[i].multiline) {
            type = "textarea";
            content = this.tokens[i].getInput();
          } else {
            type = "input";
            value = this.tokens[i].getInput();
          }
          var keyprefix = "token-";
          var key = keyprefix + this.tokens[i].key;
          this.$.pdfform.createComponent({tag: type, attributes: {name: key, value: value}, content: content});
        }
      }
      else { // !this.tokens[i].isEnabled
        // only add the nopt token
        if (this.tokens[i].isOptional) {
          var key = "%nopt-" + this.tokens[i].key;
          this.$.pdfform.createComponent({tag: "input", attributes: {name: key, value: ""}});
        }
      }
    }
    this.$.pdfform.render();
    if (this.$.config.getDebugging()) {
      var components = this.$.pdfform.getComponents();
      for (i in components) {
        var attrs = components[i].attributes;
        enyo.log("'" + attrs.name + "': '" + attrs.value + "'");
      }
    }
    else {
      document.getElementById(this.$.pdfform.getAttribute("id")).submit();
    }
  }

});
<commit_msg>main app: autosave data before submitting the form<commit_after>enyo.kind({
	name: "App",
	kind: "FittableRows",
	fit: true,
  tokens: [],
	components:[
    {kind: WebLetter.Config, name: "config"},
		{kind: "onyx.Toolbar", content: "WebLetter"},
		{kind: "enyo.Scroller", fit: true,
      components: [
			{name: "main", classes: "nice-padding", allowHtml: true, components: [
        {kind: "onyx.Groupbox", name: "settings", components: [
          {kind: "WebLetter.BooleanToken", key: "folding", description: "Folding Marks"},
          {kind: "WebLetter.BooleanToken", key: "footer", description: "Footer"},
          {kind: "WebLetter.BooleanToken", key: "logo", description: "Logo"}
          ]
        },
        {kind: "WebLetter.AddressToken", name: "addresser", description: "Addresser", key: "from"},
        {kind: "WebLetter.AddressToken", name: "addressee", description: "Addressee", key: "to"},
        {kind: "onyx.Groupbox", name: "contentGroup", components: [
          {kind: "WebLetter.TextToken", description: "Subject", key: "subject", isOptional: true},
          {kind: "WebLetter.TextToken", description: "Opening", key: "opening"},
          {kind: "WebLetter.TextAreaToken", name: "lettercontent", allowHtml: true, key: "content", description: "Content", inputWidth: "100%", inputHeight: "400px"},
          {kind: "WebLetter.TextToken", key: "closing", description: "Closing"},
          {kind: "WebLetter.TextToken", key: "signatureaddition", description: "Signature Addition", isOptional: true, isEnabled: false},
          {kind: "WebLetter.TextToken", key: "ps", description: "PS", isOptional: true, isEnabled: false},
          {kind: "WebLetter.TextToken", key: "encl", description: "Enclosure", isOptional: true, isEnabled: false}
          ]
        },
        {tag: "form", name: "pdfform", showing: false},
          {kind: "onyx.Button", name: "go", content: "Generate PDF", ontap: "go"}
        ]
      }
		]}
	],
  create: function() {
    this.tokens = new Array();
    this.inherited(arguments);
    // set up form
    this.$.pdfform.attributes.method=this.$.config.getMethod();
    this.$.pdfform.attributes.action=this.$.config.getServerUrl();
  },
  handlers: {
    onNewToken: "registerToken",
    onDisableToken: "deregisterToken"
  },
  registerToken: function(inSender, inEvent) {
    this.tokens.push(inEvent.originator);
    return true;
  },
  deregisterToken: function(inSender, inEvent) {
    // do nothing since disabled tokens might be optional and
    // need the %nopt-token to be replaced
    return true;
  },
  go: function() {
    //this.$.mylogger.addContent(this.$.lettercontent.getValue());
    this.$.pdfform.destroyComponents();
    for (i in this.tokens) {
      // autosave
      this.tokens[i].saveAllData(this, "autosave");
      if (this.tokens[i].isEnabled) {
        // add opt-token if the token is optional
        if (this.tokens[i].isOptional) {
          var key = "%opt-" + this.tokens[i].key;
          this.$.pdfform.createComponent({tag: "input", attributes: {name: key, value: ""}});
        }
        if (this.tokens[i].topToken) {
          var type;
          var content = "";
          var value = "";
          if (this.tokens[i].multiline) {
            type = "textarea";
            content = this.tokens[i].getInput();
          } else {
            type = "input";
            value = this.tokens[i].getInput();
          }
          var keyprefix = "token-";
          var key = keyprefix + this.tokens[i].key;
          this.$.pdfform.createComponent({tag: type, attributes: {name: key, value: value}, content: content});
        }
      }
      else { // !this.tokens[i].isEnabled
        // only add the nopt token
        if (this.tokens[i].isOptional) {
          var key = "%nopt-" + this.tokens[i].key;
          this.$.pdfform.createComponent({tag: "input", attributes: {name: key, value: ""}});
        }
      }
    }
    this.$.pdfform.render();
    if (this.$.config.getDebugging()) {
      var components = this.$.pdfform.getComponents();
      for (i in components) {
        var attrs = components[i].attributes;
        enyo.log("'" + attrs.name + "': '" + attrs.value + "'");
      }
    }
    else {
      document.getElementById(this.$.pdfform.getAttribute("id")).submit();
    }
  }

});
<|endoftext|>


<commit_before>// polyfills
import 'babel-polyfill';

// core modules
import {
	readFile as readFileNodeback
} from 'fs';

// npm modules
import chalk from 'chalk';
import denodeify from 'denodeify';
import gitRawCommits from 'git-raw-commits';
import meow from 'meow';
import merge from 'lodash.merge';
import pick from 'lodash.pick';
import stdin from 'get-stdin';
import rc from 'rc';

// local modules
import lint from './';
import pkg from '../package';

// denodeifications
const readFile = denodeify(readFileNodeback);

/**
 * Behavioural rules
 */
const rules = {
	fromStdin: (input, settings) => input.length === 0 &&
		settings.from === null &&
		settings.to === null &&
		settings.edit === null
};

// Init meow 😸cli
const cli = meow({
	help: [''],
	description: `${pkg.name}@${pkg.version} - ${pkg.description}`
}, {
	// flags of string type
	string: ['from', 'to', 'preset'],
	// flags of bool type
	boolean: ['edit', 'quiet', 'color'],
	// flag aliases
	alias: {
		c: 'color',
		e: 'edit',
		f: 'from',
		p: 'preset',
		t: 'to',
		q: 'quiet'
	},
	// flag defaults
	default: {
		color: true,
		edit: false,
		from: null,
		preset: 'angular',
		to: null,
		quiet: false
	},
	// fail on unknown
	unknown(arg) {
		throw new Error(`unknown flags: ${arg}`);
	}
});

// Get commit messages
// TODO: move this to an own moduleddd
function getCommits(options) {
	return new Promise((resolve, reject) => {
		const data = [];
		gitRawCommits(options)
		.on('data', chunk => data.push(chunk.toString('utf-8')))
		.on('error', reject)
		.on('end', () => {
			resolve(data);
		});
	});
}

// Get commit messages
// TODO: move this to an own module
async function getMessages(settings) {
	const {from, to, edit} = settings;

	if (edit) {
		const editFile = await readFile(`.git/COMMIT_EDITMSG`);
		return [editFile.toString('utf-8')];
	} else {
		return await getCommits({
			from,
			to
		});
	}

	// throw new Error(`Reading from git history not supported yet.`);
}

// Resolve extend configs
// TODO: move this to own module
function resolveExtends(config, prefix = '', key = 'extends') {
	return Object.values(config[key] || [])
		.reduce((merged, extender) => {
			const name = [prefix, extender]
				.filter(String)
				.join('-');
			return merge(
				{},
				merged,
				resolveExtends(require(name))
			);
		}, config);
}

// Get linting config
// TODO: move this to own module
function getConfiguration(name, settings) {
	const config = rc(name, settings.defaults);
	return resolveExtends(config, settings.prefix);
}

// Get commit messages
// TODO: move this to an own module
function format(report, options = {}) {
	const {signs, colors, color: enabled} = options;
	const fmt = new chalk.constructor({enabled});

	const problems = [...report.errors, ...report.warnings]
		.map(problem => {
			const sign = signs[problem.level];
			const color = colors[problem.level];
			const decoration = fmt[color](sign);
			const name = chalk.grey(`[${problem.name}]`);
			return `${decoration}   ${problem.message} ${name}`
		});

	const sign = report.errors.length ?
		'✖' :
		report.warnings.length ?
		'⚠' :
		'✔' ;

	const color = report.errors.length ?
		'red' :
		report.warnings.length ?
		'yellow' :
		'green' ;

	const decoration = fmt[color](sign);
	const summary = `${decoration}   found ${report.errors.length} problems, ${report.warnings.length} warnings`;
	return [...problems, chalk.bold(summary)];
}

// Assmeble the engine
async function main(options) {
	const {input: raw, flags} = options;
	const fromStdin = rules.fromStdin(raw, flags);

	const input = fromStdin ?
		[await stdin()] :
		await getMessages(
			pick(flags, ['edit', 'from', 'to'])
		);

	return Promise.all(input
		.map(async commit => {
			const report = lint(commit, {
				preset: await require(`conventional-changelog-${flags.preset}`),
				configuration: getConfiguration('conventional-changelog-lint', {
					prefix: `conventional-changelog-lint-config`
				})
			});

			const formatted = format(report, {
				color: flags.color,
				signs: [' ', '⚠', '✖'],
				colors: ['white', 'yellow', 'red']
			});

			if (!flags.quiet) {
				console.log(`validating: ${commit.split('\n')[0]}`);
				console.log(
					formatted
						.join('\n')
				);
			}

			if (report.errors.length > 0) {
				throw new Error(formatted[formatted.length - 1]);
			}

			console.log('');
		}));
}

// Start the engine
main(cli)
	.catch(error =>
		setTimeout(() => {
			if (error.type === pkg.name) {
				process.exit(1);
			}
			throw error;
		})
	)
<commit_msg>style: correct typos<commit_after>// polyfills
import 'babel-polyfill';

// core modules
import {
	readFile as readFileNodeback
} from 'fs';

// npm modules
import chalk from 'chalk';
import denodeify from 'denodeify';
import gitRawCommits from 'git-raw-commits';
import meow from 'meow';
import merge from 'lodash.merge';
import pick from 'lodash.pick';
import stdin from 'get-stdin';
import rc from 'rc';

// local modules
import lint from './';
import pkg from '../package';

// denodeifications
const readFile = denodeify(readFileNodeback);

/**
 * Behavioural rules
 */
const rules = {
	fromStdin: (input, settings) => input.length === 0 &&
		settings.from === null &&
		settings.to === null &&
		settings.edit === null
};

// Init meow 😸cli
const cli = meow({
	help: [''],
	description: `${pkg.name}@${pkg.version} - ${pkg.description}`
}, {
	// flags of string type
	string: ['from', 'to', 'preset'],
	// flags of bool type
	boolean: ['edit', 'quiet', 'color'],
	// flag aliases
	alias: {
		c: 'color',
		e: 'edit',
		f: 'from',
		p: 'preset',
		t: 'to',
		q: 'quiet'
	},
	// flag defaults
	default: {
		color: true,
		edit: false,
		from: null,
		preset: 'angular',
		to: null,
		quiet: false
	},
	// fail on unknown
	unknown(arg) {
		throw new Error(`unknown flags: ${arg}`);
	}
});

// Get commit messages
// TODO: move this to an own moduleddd
function getCommits(options) {
	return new Promise((resolve, reject) => {
		const data = [];
		gitRawCommits(options)
		.on('data', chunk => data.push(chunk.toString('utf-8')))
		.on('error', reject)
		.on('end', () => {
			resolve(data);
		});
	});
}

// Get commit messages
// TODO: move this to an own module
async function getMessages(settings) {
	const {from, to, edit} = settings;

	if (edit) {
		const editFile = await readFile(`.git/COMMIT_EDITMSG`);
		return [editFile.toString('utf-8')];
	} else {
		return await getCommits({
			from,
			to
		});
	}
}

// Resolve extend configs
// TODO: move this to own module
function resolveExtends(config, prefix = '', key = 'extends') {
	return Object.values(config[key] || [])
		.reduce((merged, extender) => {
			const name = [prefix, extender]
				.filter(String)
				.join('-');
			return merge(
				{},
				merged,
				resolveExtends(require(name))
			);
		}, config);
}

// Get linting config
// TODO: move this to own module
function getConfiguration(name, settings) {
	const config = rc(name, settings.defaults);
	return resolveExtends(config, settings.prefix);
}

// Get commit messages
// TODO: move this to an own module
function format(report, options = {}) {
	const {signs, colors, color: enabled} = options;
	const fmt = new chalk.constructor({enabled});

	const problems = [...report.errors, ...report.warnings]
		.map(problem => {
			const sign = signs[problem.level];
			const color = colors[problem.level];
			const decoration = fmt[color](sign);
			const name = chalk.grey(`[${problem.name}]`);
			return `${decoration}   ${problem.message} ${name}`
		});

	const sign = report.errors.length ?
		'✖' :
		report.warnings.length ?
		'⚠' :
		'✔' ;

	const color = report.errors.length ?
		'red' :
		report.warnings.length ?
		'yellow' :
		'green' ;

	const decoration = fmt[color](sign);
	const summary = `${decoration}   found ${report.errors.length} problems, ${report.warnings.length} warnings`;
	return [...problems, chalk.bold(summary)];
}

// Assemble the engine
async function main(options) {
	const {input: raw, flags} = options;
	const fromStdin = rules.fromStdin(raw, flags);

	const input = fromStdin ?
		[await stdin()] :
		await getMessages(
			pick(flags, ['edit', 'from', 'to'])
		);

	return Promise.all(input
		.map(async commit => {
			const report = lint(commit, {
				preset: await require(`conventional-changelog-${flags.preset}`),
				configuration: getConfiguration('conventional-changelog-lint', {
					prefix: `conventional-changelog-lint-config`
				})
			});

			const formatted = format(report, {
				color: flags.color,
				signs: [' ', '⚠', '✖'],
				colors: ['white', 'yellow', 'red']
			});

			if (!flags.quiet) {
				console.log(`validating: ${commit.split('\n')[0]}`);
				console.log(
					formatted
						.join('\n')
				);
			}

			if (report.errors.length > 0) {
				throw new Error(formatted[formatted.length - 1]);
			}

			console.log('');
		}));
}

// Start the engine
main(cli)
	.catch(error =>
		setTimeout(() => {
			if (error.type === pkg.name) {
				process.exit(1);
			}
			throw error;
		})
	)
<|endoftext|>


<commit_before>/**
 * maryamyriameliamurphies.js
 * A library of Haskell-style morphisms ported to ES2015 JavaScript.
 *
 * ord.js
 *
 * @file Ord type class.
 * @license ISC
 */

/** @module ord */

import {partial} from './base';

import {isEq} from './eq';

import {
  Type,
  defines,
  dataType,
  typeCheck
} from './type';

import {error} from './error';

/** @const {Function} Ord
 * The `Ord` type class is used for totally ordered datatypes. Instances of `Ord` must define a
 * `compare` method and must also be instances of `Eq`.
 * @param {*} - Any object.
 * @returns {boolean} - `true` if an object is an instance of `Ord` and `false` otherwise.
 */
const Ord = defines(`isEq`, `compare`);

/** @class Ordering
 * A data constructor for orderings of objects that can be compared, implemented as a class because
 * Ordering in Haskell is a monoid. There is no reason to ever create any other new objects from
 * this class.
 * @extends Type
 * @private
 */
class Ordering extends Type {
  /** @constructor
   * Create a new ordering.
   * @param {string} ord - A string representing the type of ordering.
   */
  constructor(ord) {
    super();
    this.ord = () => ord;
   }
   static mempty() { return EQ; }
   static mappend(a, b) {
     if (a === LT) { return LT; }
     if (a === EQ) { return b; }
     if (a === GT) { return GT; }
   }
   valueOf() { return this.ord(); }
}

/** @const {Ordering} EQ
 * The "equals" Ordering. Equivalent to ===.
 */
export const EQ = new Ordering(`EQ`);

/** @const {Ordering} LT
 * The "less than" Ordering. Equivalent to <.
 */
export const LT = new Ordering(`LT`);

/** @const {Ordering} GT
 * The "greater than" Ordering. Equivalent to >.
 */
export const GT = new Ordering(`GT`);

/** @function compare
 * Compare two objects and return an `Ordering`. Both values must be instances of the `Ord` type
 * class (i.e. they both define a `compare` static method) and must also be the same data type (or
 * the same primitive type). Only a single comparison is required to determine the precise ordering
 * of two objects.
 * Haskell> compare :: a -> a -> Ordering
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {Ordering} - The Ordering value (`EQ`, `LT`, or `GT`).
 * @example
 * const lst1 = list(1,2,3);
 * const lst2 = list(4,5,6);
 * compare(lst1, lst2);      // => LT
 * compare(lst2, lst1);      // => GT
 * const tup1 = tuple(1,2);
 * const tup2 = tuple(2,1);
 * const tup3 = swap(tup2);
 * compare(tup1, tup2);      // => LT
 * compare(tup2, tup3);      // => GT
 * compare(tup3, tup1);      // => EQ
 */
export const compare = (a, b) => {
  const compare_ = (a, b) => {
    if (a === Infinity) { return GT; }
    if (b === Infinity) { return LT; }
    if (typeCheck(a, b)) {
      if (Ord(a)) { return dataType(a).compare(a, b); }
      if (isEq(a, b)) { return EQ; }
      if (a < b) { return LT; }
      if (a > b) { return GT; }
    }
    return error.typeMismatch(a, b, compare);
  }
  return partial(compare_, a, b);
}

/** @function lessThan
 * Determine whether one value is less than another.
 * Haskell> (<) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a < b.
 */
export const lessThan = (a, b) => {
  const lessThan_ = (a, b) => compare(a, b) === LT;
  return partial(lessThan_, a, b);
}

/** @function lessThanOrEqual
 * Determine whether one value is less than or equal to another.
 * Haskell> (<=) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a <= b.
 */
export const lessThanOrEqual = (a, b) => {
  const lessThanOrEqual_ = (a, b) => compare(a, b) !== GT;
  return partial(lessThanOrEqual_, a, b);
}

/** @function greaterThan
 * Determine whether one value is greater than another.
 * Haskell> (>) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a > b.
 */
export const greaterThan = (a, b) => {
  const greaterThan_ = (a, b) => compare(a, b) === GT;
  return partial(greaterThan_, a, b);
}

/** @function greaterThanOrEqual
 * Determine whether one value is greater than or equal to another.
 * Haskell> (>=) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a >= b.
 */
export const greaterThanOrEqual = (a, b) => {
  const greaterThanOrEqual_ = (a, b) => compare(a, b) !== LT;
  return partial(greaterThanOrEqual_, a, b);
}

/** @function max
 * Return the higher in value of two objects.
 * Haskell> max :: a -> a -> a
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {*} - `a` or `b`, whichever is greater.
 * @example
 * const tup1 = tuple(1,2);
 * const tup2 = tuple(2,1);
 * const tup3 = swap(tup2);
 * max(tup1, tup2);         // => (2,1)
 * max(tup2, tup1);         // => (2,1)
 * max(tup3, tup1);         // => (1,2)
 */
export const max = (a, b) => {
  const max_ = (a, b) => lessThanOrEqual(a, b) ? b : a;
  return partial(max_, a, b);
}

/** @function min
 * Return the lower in value of two objects.
 * Haskell> min :: a -> a -> a
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {*} - `a` or `b`, whichever is lesser.
 * @example
 * const tup1 = tuple(1,2);
 * const tup2 = tuple(2,1);
 * const tup3 = swap(tup2);
 * min(tup1, tup2);         // => (1,2)
 * min(tup2, tup1);         // => (1,2)
 * min(tup3, tup1);         // => (1,2)
 */
export const min = (a, b) => {
  const min_ = (a, b) => lessThanOrEqual(a, b) ? a : b;
  return partial(min_, a, b);
}
<commit_msg>Remove Type class dependency from Ordering<commit_after>/**
 * maryamyriameliamurphies.js
 * A library of Haskell-style morphisms ported to ES2015 JavaScript.
 *
 * ord.js
 *
 * @file Ord type class.
 * @license ISC
 */

/** @module ord */

import {partial} from './base';

import {isEq} from './eq';

import {
  defines,
  dataType,
  typeCheck
} from './type';

import {error} from './error';

/** @const {Function} Ord
 * The `Ord` type class is used for totally ordered datatypes. Instances of `Ord` must define a
 * `compare` method and must also be instances of `Eq`.
 * @param {*} - Any object.
 * @returns {boolean} - `true` if an object is an instance of `Ord` and `false` otherwise.
 */
const Ord = defines(`isEq`, `compare`);

/** @class Ordering
 * A data constructor for orderings of objects that can be compared, implemented as a class because
 * Ordering in Haskell is a monoid. There is no reason to ever create any other new objects from
 * this class.
 * @extends Type
 * @private
 */
class Ordering {
  /** @constructor
   * Create a new ordering, a relationship that represents a comparison between two objects.
   * @param {string} ord - A string representing the type of ordering.
   */
  constructor(ord) { this.ord = () => ord; }
   static mempty() { return EQ; }
   static mappend(a, b) {
     if (a === LT) { return LT; }
     if (a === EQ) { return b; }
     if (a === GT) { return GT; }
   }
   valueOf() { return this.ord(); }
}

/** @const {Ordering} EQ
 * The "equals" Ordering. Equivalent to ===.
 */
export const EQ = new Ordering(`EQ`);

/** @const {Ordering} LT
 * The "less than" Ordering. Equivalent to <.
 */
export const LT = new Ordering(`LT`);

/** @const {Ordering} GT
 * The "greater than" Ordering. Equivalent to >.
 */
export const GT = new Ordering(`GT`);

/** @function compare
 * Compare two objects and return an `Ordering`. Both values must be instances of the `Ord` type
 * class (i.e. they both define a `compare` static method) and must also be the same data type (or
 * the same primitive type). Only a single comparison is required to determine the precise ordering
 * of two objects.
 * Haskell> compare :: a -> a -> Ordering
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {Ordering} - The Ordering value (`EQ`, `LT`, or `GT`).
 * @example
 * const lst1 = list(1,2,3);
 * const lst2 = list(4,5,6);
 * compare(lst1, lst2);      // => LT
 * compare(lst2, lst1);      // => GT
 * const tup1 = tuple(1,2);
 * const tup2 = tuple(2,1);
 * const tup3 = swap(tup2);
 * compare(tup1, tup2);      // => LT
 * compare(tup2, tup3);      // => GT
 * compare(tup3, tup1);      // => EQ
 */
export const compare = (a, b) => {
  const compare_ = (a, b) => {
    if (a === Infinity) { return GT; }
    if (b === Infinity) { return LT; }
    if (typeCheck(a, b)) {
      if (Ord(a)) { return dataType(a).compare(a, b); }
      if (isEq(a, b)) { return EQ; }
      if (a < b) { return LT; }
      if (a > b) { return GT; }
    }
    return error.typeMismatch(a, b, compare);
  }
  return partial(compare_, a, b);
}

/** @function lessThan
 * Determine whether one value is less than another.
 * Haskell> (<) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a < b.
 */
export const lessThan = (a, b) => {
  const lessThan_ = (a, b) => compare(a, b) === LT;
  return partial(lessThan_, a, b);
}

/** @function lessThanOrEqual
 * Determine whether one value is less than or equal to another.
 * Haskell> (<=) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a <= b.
 */
export const lessThanOrEqual = (a, b) => {
  const lessThanOrEqual_ = (a, b) => compare(a, b) !== GT;
  return partial(lessThanOrEqual_, a, b);
}

/** @function greaterThan
 * Determine whether one value is greater than another.
 * Haskell> (>) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a > b.
 */
export const greaterThan = (a, b) => {
  const greaterThan_ = (a, b) => compare(a, b) === GT;
  return partial(greaterThan_, a, b);
}

/** @function greaterThanOrEqual
 * Determine whether one value is greater than or equal to another.
 * Haskell> (>=) :: a -> a -> Bool
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {boolean} - a >= b.
 */
export const greaterThanOrEqual = (a, b) => {
  const greaterThanOrEqual_ = (a, b) => compare(a, b) !== LT;
  return partial(greaterThanOrEqual_, a, b);
}

/** @function max
 * Return the higher in value of two objects.
 * Haskell> max :: a -> a -> a
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {*} - `a` or `b`, whichever is greater.
 * @example
 * const tup1 = tuple(1,2);
 * const tup2 = tuple(2,1);
 * const tup3 = swap(tup2);
 * max(tup1, tup2);         // => (2,1)
 * max(tup2, tup1);         // => (2,1)
 * max(tup3, tup1);         // => (1,2)
 */
export const max = (a, b) => {
  const max_ = (a, b) => lessThanOrEqual(a, b) ? b : a;
  return partial(max_, a, b);
}

/** @function min
 * Return the lower in value of two objects.
 * Haskell> min :: a -> a -> a
 * @param {*} a - Any object.
 * @param {*} b - Any object.
 * @returns {*} - `a` or `b`, whichever is lesser.
 * @example
 * const tup1 = tuple(1,2);
 * const tup2 = tuple(2,1);
 * const tup3 = swap(tup2);
 * min(tup1, tup2);         // => (1,2)
 * min(tup2, tup1);         // => (1,2)
 * min(tup3, tup1);         // => (1,2)
 */
export const min = (a, b) => {
  const min_ = (a, b) => lessThanOrEqual(a, b) ? a : b;
  return partial(min_, a, b);
}
<|endoftext|>


<commit_before>    /*
     * Initialize the application.
     */
    // OpenLayers
    <%block name="init_openlayers">\
    OpenLayers.Number.thousandsSeparator = ' ';
    OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
    OpenLayers.DOTS_PER_INCH = 72;
    </%block>\

    // Ext
    <%block name="init_ext">\
    Ext.QuickTips.init();
    </%block>\

    <%block name="init_project">\
    OpenLayers.ImgPath = 'to be overwritten';
    Ext.BLANK_IMAGE_URL = 'to be overwritten';
    </%block>\

    // Apply same language than on the server side
    OpenLayers.Lang.setCode("${lang}");

    // Themes definitions
    /* errors (if any): ${themesError | n} */
    var THEMES = {
        "local": ${themes | n}
    % if external_themes:
        , "external": ${external_themes | n}
    % endif
    };

    <%block name="initial_extent">\
% if user:
    var INITIAL_EXTENT = ${user.role.jsextent};
% else:
    <%block name="default_initial_extent">\
    var INITIAL_EXTENT = [420000, 30000, 900000, 350000];
    </%block>\
% endif
    </%block>\

    <%block name="restricted_extent">\
    var RESTRICTED_EXTENT = [420000, 30000, 900000, 350000];
    </%block>\

    // Used to transmit event throw the application
    var EVENTS = new Ext.util.Observable();

    <%block name="wmts_options">\
    var WMTS_OPTIONS = {
% if len(tilecache_url) == 0:
        url: "${request.route_url('tilecache', path='')}",
% else:
        url: '${tilecache_url}',
% endif
        displayInLayerSwitcher: false,
        requestEncoding: 'REST',
        buffer: 0,
        <%block name="wmts_options_settings">\
        style: 'default',
        dimensions: ['TIME'],
        params: {
            'time': '2011'
        },
        matrixSet: 'swissgrid',
        maxExtent: new OpenLayers.Bounds(420000, 30000, 900000, 350000),
        projection: new OpenLayers.Projection("EPSG:21781"),
        units: "m",
        formatSuffix: 'png',
        serverResolutions: [4000,3750,3500,3250,3000,2750,2500,2250,2000,1750,1500,1250,1000,750,650,500,250,100,50,20,10,5,2.5,2,1.5,1,0.5,0.25,0.1,0.05],
        </%block>\
        getMatrix: function() {
            return { identifier: OpenLayers.Util.indexOf(this.serverResolutions, this.map.getResolution()) };
        }
    }
    </%block>\

    <%block name="viewer">\
    app = new gxp.Viewer({
        portalConfig: {
            <%block name="viewer_portal_config">\
            layout: "border",
            // by configuring items here, we don't need to configure portalItems
            // and save a wrapping container
            items: [{
                region: "north",
                contentEl: 'header-out'
            },
            "app-map",
            {
                id: "featuregrid-container",
                xtype: "panel",
                layout: "fit",
                region: "south",
                height: 160,
                split: true,
                collapseMode: "mini",
                hidden: true,
                bodyStyle: 'background-color: transparent;'
            }, {
                layout: "accordion",
                id: "left-panel",
                region: "west",
                width: 300,
                minWidth: 300,
                split: true,
                collapseMode: "mini",
                border: false,
                defaults: {width: 300},
                items: [{
                    xtype: "panel",
                    title: OpenLayers.i18n("layertree"),
                    id: 'layerpanel',
                    layout: "vbox",
                    layoutConfig: {
                        align: "stretch"
                    }
                }]
            }]
            </%block>\
        },

        // configuration of all tool plugins for this application
        tools: [
        <%block name="viewer_tools">\
        <%block name="viewer_tools_themeselector">\
        {
            ptype: "cgxp_themeselector",
            outputTarget: "layerpanel",
            layerTreeId: "layertree",
            themes: THEMES,
            outputConfig: {
                layout: "fit",
                style: "padding: 3px;"
            }
        },
        </%block>\
        <%block name="viewer_tools_layertree">\
        {
            ptype: "cgxp_layertree",
            id: "layertree",
            outputConfig: {
                header: false,
                flex: 1,
                layout: "fit",
                autoScroll: true,
                themes: THEMES,
                <%block name="viewer_tools_layertree_options">\
                defaultThemes: ["default theme"],
                </%block>\
                wmsURL: "${request.route_url('mapserverproxy', path='')}"
            },
            outputTarget: "layerpanel"
        },
        </%block>\
        <%block name="viewer_tools_querier">\
        {
            ptype: "cgxp_querier",
            outputTarget: "left-panel",
            events: EVENTS,
            mapserverproxyURL: "${request.route_url('mapserverproxy', path='')}",
            // don't work with actual version of mapserver, the proxy will limit to 200
            // it is intended to be reactivated this once mapserver is fixed
            //maxFeatures: 200,
            <%block name="viewer_tools_querier_options">\
            srsName: 'EPSG:21781',
            featureType: "query_layer",
            </%block>\
            outputConfig: {
% if not user:
                hidden: true
% endif
            }
        },
        </%block>\
        <%block name="viewer_tools_print">\
        {
            ptype: "cgxp_print",
            legendPanelId: "legendPanel",
            featureGridId: "featureGrid",
            outputTarget: "left-panel",
            printURL: "${request.route_url('printproxy', path='')}",
            mapserverURL: "${request.route_url('mapserverproxy', path='')}",
            options: {
                labelAlign: 'top',
                defaults: {
                    anchor:'100%'
                }
            },
            outputConfig: {
                autoFit: true
            }
        },
        </%block>\
        <%block name="viewer_tools_featuregrid">\
        {
            ptype: "cgxp_featuregrid",
            id: "featureGrid",
            featureManager: "featuremanager",
            csvURL: "${request.route_url('csvecho')}",
            maxFeatures: 200,
            outputTarget: "featuregrid-container",
            events: EVENTS
        },
        </%block>\
        <%block name="viewer_tools_toolbar">\
        {
            ptype: "gxp_zoomtoextent",
            actionTarget: "map.tbar",
            closest: true,
            extent: INITIAL_EXTENT
        }, {
            ptype: "cgxp_zoom",
            actionTarget: "map.tbar",
            toggleGroup: "maptools"
        }, {
            ptype: "gxp_navigationhistory",
            actionTarget: "map.tbar"
        },
        <%block name="viewer_tools_toolbar_permalink">\
        {
            ptype: "cgxp_permalink",
            actionTarget: "map.tbar"
        },
        </%block>\
        {
            ptype: "cgxp_measure",
            actionTarget: "map.tbar",
            toggleGroup: "maptools"
        },
        <%block name="viewer_tools_toolbar_getfeatureinfo">\
        {
            ptype: "cgxp_wmsgetfeatureinfo",
            featureManager: "featuremanager",
            actionTarget: "map.tbar",
            toggleGroup: "maptools",
            events: EVENTS
        },
        </%block>\
        {
            ptype: "cgxp_fulltextsearch",
            url: "${request.route_url('fulltextsearch', path='')}",
            actionTarget: "map.tbar"
        }, {
            ptype: "cgxp_menushortcut",
            type: '->'
        }, {
            ptype: "cgxp_redlining",
            toggleGroup: "maptools",
            actionTarget: "map.tbar"
        }, {
            ptype: "cgxp_legend",
            id: "legendPanel",
            toggleGroup: "maptools",
            actionTarget: "map.tbar"
        }, {
            ptype: "cgxp_menushortcut",
            type: '-'
        },
        <%block name="viewer_tools_toolbar_login">\
        {
            ptype: "cgxp_login",
            actionTarget: "map.tbar",
            toggleGroup: "maptools",
% if user:
            username: "${user.username}",
% endif
            loginURL: "${request.route_url('login', path='')}",
            logoutURL: "${request.route_url('logout', path='')}"
        },{
            ptype: "cgxp_menushortcut",
            type: '-'
        },
        </%block>\
        {
            ptype: "cgxp_help",
            <%block name="viewer_tools_toolbar_helpurl">\
            url: "#help-url",
            </%block>\
            actionTarget: "map.tbar"
        /*
        }, {
            // shared FeatureManager for feature editing, grid and querying
            ptype: "cgxp_featuremanager",
            id: "featuremanager"
*/        },
        </%block>\
        <%block name="viewer_tools_mapopacityslider">\
        {
            ptype: "cgxp_mapopacityslider"
        }
        </%block>\
        </%block>\
        ],

        // layer sources
        sources: {
            <%block name="viewer_sources">\
            "olsource": {
                ptype: "gxp_olsource",
            }
            </%block>\
        },

        // map and layers
        map: {
            <%block name="viewer_map">\
            <%block name="viewer_map_id">\
            id: "app-map", // id needed to reference map in portalConfig above
            </%block>\
            projection: "EPSG:21781",
            extent: INITIAL_EXTENT,
            maxExtent: RESTRICTED_EXTENT,
            restrictedExtent: RESTRICTED_EXTENT,
            stateId: "map",
            <%block name="viewer_map_options">\
            units: "m",
            resolutions: [4000,2000,1000,500,250,100,50,20,10,5,2.5,1,0.5,0.25,0.1,0.05],
            </%block>\
            controls: [
                <%block name="viewer_controls">\
                new OpenLayers.Control.Navigation(),
                new OpenLayers.Control.KeyboardDefaults(),
                new OpenLayers.Control.PanZoomBar({panIcons: false}),
                new OpenLayers.Control.ArgParser(),
                new OpenLayers.Control.Attribution(),
                new OpenLayers.Control.ScaleLine({
                    bottomInUnits: false,
                    bottomOutUnits: false
                }),
                new OpenLayers.Control.MousePosition({numDigits: 0}),
                <%block name="viewer_add_controls">\
                // OSM version
                new OpenLayers.Control.OverviewMap({
                    size: new OpenLayers.Size(200, 100),
                    minRatio: 64,
                    maxRatio: 64,
                    mapOptions: {
                        theme: null
                    },
                    layers: [new OpenLayers.Layer.OSM("OSM", [
                            'http://a.tile.openstreetmap.org/${"${z}"}/${"${x}"}/${"${y}"}.png',
                            'http://b.tile.openstreetmap.org/${"${z}"}/${"${x}"}/${"${y}"}.png',
                            'http://c.tile.openstreetmap.org/${"${z}"}/${"${x}"}/${"${y}"}.png'
                        ], {
                            transitionEffect: 'resize',
                            attribution: [
                                "(c) OSM",
                                "by-sa"
                            ].join(' ')
                        }
                    )]
                })
                </%block>\
                </%block>\
            ],
            layers: [
            <%block name="viewer_layers">\
            {
                source: "olsource",
                type: "OpenLayers.Layer.WMTS",
                args: [Ext.applyIf({
                    name: OpenLayers.i18n('ortho'),
                    mapserverLayers: 'ortho',
                    ref: 'ortho',
                    layer: 'ortho',
                    formatSuffix: 'jpeg',
                    opacity: 0
                }, WMTS_OPTIONS)]
            }, {
                source: "olsource",
                type: "OpenLayers.Layer.WMTS",
                group: 'background',
                args: [Ext.applyIf({
                    name: OpenLayers.i18n('plan'),
                    mapserverLayers: 'plan',
                    ref: 'plan',
                    layer: 'plan',
                    group: 'background'
                }, WMTS_OPTIONS)]
            },
            {
                source: "olsource",
                type: "OpenLayers.Layer",
                group: 'background',
                args: [OpenLayers.i18n('blank'), {
                    displayInLayerSwitcher: false,
                    ref: 'blank',
                    group: 'background'
                }]
            }
            </%block>\
            ],
            items: []
        }
        </%block>\
    });
    </%block>\

    app.on('ready', function() {
    <%block name="viewer_ready">\
        // remove loading message
        Ext.get('loading').remove();
        Ext.fly('loading-mask').fadeOut({
            remove: true
        });
    </%block>\
    }, app);
<commit_msg>Extended GeoExt.MapPanel to override the getState methode to skipp unneeded OL layer properties<commit_after>    /*
     * Initialize the application.
     */
    // OpenLayers
    <%block name="init_openlayers">\
    OpenLayers.Number.thousandsSeparator = ' ';
    OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
    OpenLayers.DOTS_PER_INCH = 72;
    </%block>\

    // Ext
    <%block name="init_ext">\
    Ext.QuickTips.init();
    </%block>\

    <%block name="init_project">\
    OpenLayers.ImgPath = 'to be overwritten';
    Ext.BLANK_IMAGE_URL = 'to be overwritten';
    </%block>\

    // Apply same language than on the server side
    OpenLayers.Lang.setCode("${lang}");

    // Themes definitions
    /* errors (if any): ${themesError | n} */
    var THEMES = {
        "local": ${themes | n}
    % if external_themes:
        , "external": ${external_themes | n}
    % endif
    };

    <%block name="initial_extent">\
% if user:
    var INITIAL_EXTENT = ${user.role.jsextent};
% else:
    <%block name="default_initial_extent">\
    var INITIAL_EXTENT = [420000, 30000, 900000, 350000];
    </%block>\
% endif
    </%block>\

    <%block name="restricted_extent">\
    var RESTRICTED_EXTENT = [420000, 30000, 900000, 350000];
    </%block>\

    // Used to transmit event throw the application
    var EVENTS = new Ext.util.Observable();

    <%block name="wmts_options">\
    var WMTS_OPTIONS = {
% if len(tilecache_url) == 0:
        url: "${request.route_url('tilecache', path='')}",
% else:
        url: '${tilecache_url}',
% endif
        displayInLayerSwitcher: false,
        requestEncoding: 'REST',
        buffer: 0,
        <%block name="wmts_options_settings">\
        style: 'default',
        dimensions: ['TIME'],
        params: {
            'time': '2011'
        },
        matrixSet: 'swissgrid',
        maxExtent: new OpenLayers.Bounds(420000, 30000, 900000, 350000),
        projection: new OpenLayers.Projection("EPSG:21781"),
        units: "m",
        formatSuffix: 'png',
        serverResolutions: [4000,3750,3500,3250,3000,2750,2500,2250,2000,1750,1500,1250,1000,750,650,500,250,100,50,20,10,5,2.5,2,1.5,1,0.5,0.25,0.1,0.05],
        </%block>\
        getMatrix: function() {
            return { identifier: OpenLayers.Util.indexOf(this.serverResolutions, this.map.getResolution()) };
        }
    }
    </%block>\

    <%block name="viewer">\
    app = new gxp.Viewer({
        portalConfig: {
            <%block name="viewer_portal_config">\
            layout: "border",
            // by configuring items here, we don't need to configure portalItems
            // and save a wrapping container
            items: [{
                region: "north",
                contentEl: 'header-out'
            },
            "app-map",
            {
                id: "featuregrid-container",
                xtype: "panel",
                layout: "fit",
                region: "south",
                height: 160,
                split: true,
                collapseMode: "mini",
                hidden: true,
                bodyStyle: 'background-color: transparent;'
            }, {
                layout: "accordion",
                id: "left-panel",
                region: "west",
                width: 300,
                minWidth: 300,
                split: true,
                collapseMode: "mini",
                border: false,
                defaults: {width: 300},
                items: [{
                    xtype: "panel",
                    title: OpenLayers.i18n("layertree"),
                    id: 'layerpanel',
                    layout: "vbox",
                    layoutConfig: {
                        align: "stretch"
                    }
                }]
            }]
            </%block>\
        },

        // configuration of all tool plugins for this application
        tools: [
        <%block name="viewer_tools">\
        <%block name="viewer_tools_themeselector">\
        {
            ptype: "cgxp_themeselector",
            outputTarget: "layerpanel",
            layerTreeId: "layertree",
            themes: THEMES,
            outputConfig: {
                layout: "fit",
                style: "padding: 3px;"
            }
        },
        </%block>\
        <%block name="viewer_tools_layertree">\
        {
            ptype: "cgxp_layertree",
            id: "layertree",
            outputConfig: {
                header: false,
                flex: 1,
                layout: "fit",
                autoScroll: true,
                themes: THEMES,
                <%block name="viewer_tools_layertree_options">\
                defaultThemes: ["default theme"],
                </%block>\
                wmsURL: "${request.route_url('mapserverproxy', path='')}"
            },
            outputTarget: "layerpanel"
        },
        </%block>\
        <%block name="viewer_tools_querier">\
        {
            ptype: "cgxp_querier",
            outputTarget: "left-panel",
            events: EVENTS,
            mapserverproxyURL: "${request.route_url('mapserverproxy', path='')}",
            // don't work with actual version of mapserver, the proxy will limit to 200
            // it is intended to be reactivated this once mapserver is fixed
            //maxFeatures: 200,
            <%block name="viewer_tools_querier_options">\
            srsName: 'EPSG:21781',
            featureType: "query_layer",
            </%block>\
            outputConfig: {
% if not user:
                hidden: true
% endif
            }
        },
        </%block>\
        <%block name="viewer_tools_print">\
        {
            ptype: "cgxp_print",
            legendPanelId: "legendPanel",
            featureGridId: "featureGrid",
            outputTarget: "left-panel",
            printURL: "${request.route_url('printproxy', path='')}",
            mapserverURL: "${request.route_url('mapserverproxy', path='')}",
            options: {
                labelAlign: 'top',
                defaults: {
                    anchor:'100%'
                }
            },
            outputConfig: {
                autoFit: true
            }
        },
        </%block>\
        <%block name="viewer_tools_featuregrid">\
        {
            ptype: "cgxp_featuregrid",
            id: "featureGrid",
            featureManager: "featuremanager",
            csvURL: "${request.route_url('csvecho')}",
            maxFeatures: 200,
            outputTarget: "featuregrid-container",
            events: EVENTS
        },
        </%block>\
        <%block name="viewer_tools_toolbar">\
        {
            ptype: "gxp_zoomtoextent",
            actionTarget: "map.tbar",
            closest: true,
            extent: INITIAL_EXTENT
        }, {
            ptype: "cgxp_zoom",
            actionTarget: "map.tbar",
            toggleGroup: "maptools"
        }, {
            ptype: "gxp_navigationhistory",
            actionTarget: "map.tbar"
        },
        <%block name="viewer_tools_toolbar_permalink">\
        {
            ptype: "cgxp_permalink",
            actionTarget: "map.tbar"
        },
        </%block>\
        {
            ptype: "cgxp_measure",
            actionTarget: "map.tbar",
            toggleGroup: "maptools"
        },
        <%block name="viewer_tools_toolbar_getfeatureinfo">\
        {
            ptype: "cgxp_wmsgetfeatureinfo",
            featureManager: "featuremanager",
            actionTarget: "map.tbar",
            toggleGroup: "maptools",
            events: EVENTS
        },
        </%block>\
        {
            ptype: "cgxp_fulltextsearch",
            url: "${request.route_url('fulltextsearch', path='')}",
            actionTarget: "map.tbar"
        }, {
            ptype: "cgxp_menushortcut",
            type: '->'
        }, {
            ptype: "cgxp_redlining",
            toggleGroup: "maptools",
            actionTarget: "map.tbar"
        }, {
            ptype: "cgxp_legend",
            id: "legendPanel",
            toggleGroup: "maptools",
            actionTarget: "map.tbar"
        }, {
            ptype: "cgxp_menushortcut",
            type: '-'
        },
        <%block name="viewer_tools_toolbar_login">\
        {
            ptype: "cgxp_login",
            actionTarget: "map.tbar",
            toggleGroup: "maptools",
% if user:
            username: "${user.username}",
% endif
            loginURL: "${request.route_url('login', path='')}",
            logoutURL: "${request.route_url('logout', path='')}"
        },{
            ptype: "cgxp_menushortcut",
            type: '-'
        },
        </%block>\
        {
            ptype: "cgxp_help",
            <%block name="viewer_tools_toolbar_helpurl">\
            url: "#help-url",
            </%block>\
            actionTarget: "map.tbar"
        /*
        }, {
            // shared FeatureManager for feature editing, grid and querying
            ptype: "cgxp_featuremanager",
            id: "featuremanager"
*/        },
        </%block>\
        <%block name="viewer_tools_mapopacityslider">\
        {
            ptype: "cgxp_mapopacityslider"
        }
        </%block>\
        </%block>\
        ],

        // layer sources
        sources: {
            <%block name="viewer_sources">\
            "olsource": {
                ptype: "gxp_olsource",
            }
            </%block>\
        },

        // map and layers
        map: {
            <%block name="viewer_map">\
            <%block name="viewer_map_id">\
            id: "app-map", // id needed to reference map in portalConfig above
            </%block>\
            xtype: 'cgxp_mappanel',
            projection: "EPSG:21781",
            extent: INITIAL_EXTENT,
            maxExtent: RESTRICTED_EXTENT,
            restrictedExtent: RESTRICTED_EXTENT,
            stateId: "map",
            <%block name="viewer_map_options">\
            units: "m",
            resolutions: [4000,2000,1000,500,250,100,50,20,10,5,2.5,1,0.5,0.25,0.1,0.05],
            </%block>\
            controls: [
                <%block name="viewer_controls">\
                new OpenLayers.Control.Navigation(),
                new OpenLayers.Control.KeyboardDefaults(),
                new OpenLayers.Control.PanZoomBar({panIcons: false}),
                new OpenLayers.Control.ArgParser(),
                new OpenLayers.Control.Attribution(),
                new OpenLayers.Control.ScaleLine({
                    bottomInUnits: false,
                    bottomOutUnits: false
                }),
                new OpenLayers.Control.MousePosition({numDigits: 0}),
                <%block name="viewer_add_controls">\
                // OSM version
                new OpenLayers.Control.OverviewMap({
                    size: new OpenLayers.Size(200, 100),
                    minRatio: 64,
                    maxRatio: 64,
                    mapOptions: {
                        theme: null
                    },
                    layers: [new OpenLayers.Layer.OSM("OSM", [
                            'http://a.tile.openstreetmap.org/${"${z}"}/${"${x}"}/${"${y}"}.png',
                            'http://b.tile.openstreetmap.org/${"${z}"}/${"${x}"}/${"${y}"}.png',
                            'http://c.tile.openstreetmap.org/${"${z}"}/${"${x}"}/${"${y}"}.png'
                        ], {
                            transitionEffect: 'resize',
                            attribution: [
                                "(c) OSM",
                                "by-sa"
                            ].join(' ')
                        }
                    )]
                })
                </%block>\
                </%block>\
            ],
            layers: [
            <%block name="viewer_layers">\
            {
                source: "olsource",
                type: "OpenLayers.Layer.WMTS",
                args: [Ext.applyIf({
                    name: OpenLayers.i18n('ortho'),
                    mapserverLayers: 'ortho',
                    ref: 'ortho',
                    layer: 'ortho',
                    formatSuffix: 'jpeg',
                    opacity: 0
                }, WMTS_OPTIONS)]
            }, {
                source: "olsource",
                type: "OpenLayers.Layer.WMTS",
                group: 'background',
                args: [Ext.applyIf({
                    name: OpenLayers.i18n('plan'),
                    mapserverLayers: 'plan',
                    ref: 'plan',
                    layer: 'plan',
                    group: 'background'
                }, WMTS_OPTIONS)]
            },
            {
                source: "olsource",
                type: "OpenLayers.Layer",
                group: 'background',
                args: [OpenLayers.i18n('blank'), {
                    displayInLayerSwitcher: false,
                    ref: 'blank',
                    group: 'background'
                }]
            }
            </%block>\
            ],
            items: []
        }
        </%block>\
    });
    </%block>\

    app.on('ready', function() {
    <%block name="viewer_ready">\
        // remove loading message
        Ext.get('loading').remove();
        Ext.fly('loading-mask').fadeOut({
            remove: true
        });
    </%block>\
    }, app);
<|endoftext|>