<commit_before>/**
	_enyo.UiComponent_ implements a container strategy suitable for presentation
	layers.

	UiComponent itself is abstract.  Concrete subkinds include
	enyo.Control (for HTML/DOM) and
	enyo.canvas.Control
	(for Canvas contexts).
*/
enyo.kind({
	name: "enyo.UiComponent",
	kind: enyo.Component,
	published: {
		//* the UiComponent that physically contains this component in the DOM
		container: null,
		//* the UiComponent that owns this component for the purpose of event propogation
		parent: null,
		//* the UiComponent that will physically contain new items added using createComponent
		controlParentName: "client",
		//* a kind used to manage the size and placement of child components
		layoutKind: ""
	},
	handlers: {
		onresize: "resizeHandler"
	},
	statics: {
		_resizeFlags: {showingOnly: true} // don't waterfall these events into hidden controls
	},
	create: function() {
		this.controls = [];
		this.children = [];
		this.containerChanged();
		this.inherited(arguments);
		this.layoutKindChanged();
	},
	destroy: function() {
		// Destroys all non-chrome controls (regardless of owner).
		this.destroyClientControls();
		// Removes us from our container.
		this.setContainer(null);
		// Destroys chrome controls owned by this.
		this.inherited(arguments);
	},
	importProps: function(inProps) {
		this.inherited(arguments);
		if (!this.owner) {
			//this.log("registering ownerless control [" + this.kindName + "] with enyo.master");
			this.owner = enyo.master;
		}
	},
	// As implemented, _controlParentName_ only works to identify an owned
	// control created via _createComponents_ (i.e., usually in our _components_
	// block).  To attach a _controlParent_ via other means, one must call
	// _discoverControlParent_ or set _controlParent_ directly.
	//
	// We could call _discoverControlParent_ in _addComponent_, but it would
	// cause a lot of useless checking.
	createComponents: function() {
		var results = this.inherited(arguments);
		this.discoverControlParent();
		return results;
	},
	discoverControlParent: function() {
		this.controlParent = this.$[this.controlParentName] || this.controlParent;
	},
	adjustComponentProps: function(inProps) {
		// Components we create have us as a container by default.
		inProps.container = inProps.container || this;
		/*
		// the 'property master' is the object responsible for adjusting component props
		// which may not be the object on which component creation was invoked
		// the first-order property master is our container (this by default)
		var propMaster = inProps.container;
		// if we are the first-order property master, our control parent (if it exists) is the second-order master
		if (propMaster == this) {
			propMaster = this.controlParent || propMaster;
		}
		// if the property master is not us, delegate to him
		if (propMaster != this) {
			propMaster.adjustComponentProps(inProps);
		}
		// otherwise, do the usual
		else {
		*/
			this.inherited(arguments);
		//}
	},
	// containment
	containerChanged: function(inOldContainer) {
		if (inOldContainer) {
			inOldContainer.removeControl(this);
		}
		if (this.container) {
			this.container.addControl(this);
		}
	},
	// parentage
	parentChanged: function(inOldParent) {
		if (inOldParent && inOldParent != this.parent) {
			inOldParent.removeChild(this);
		}
	},
	//* @public
	// Note: Oddly, a Control is considered a descendant of itself.
	isDescendantOf: function(inAncestor) {
		var p = this;
		while (p && p!=inAncestor) {
			p = p.parent;
		}
		return inAncestor && (p == inAncestor);
	},
	/**
		Returns all controls.
	*/
	getControls: function() {
		return this.controls;
	},
	/**
		Returns all non-chrome controls.
	*/
	getClientControls: function() {
		var results = [];
		for (var i=0, cs=this.controls, c; c=cs[i]; i++) {
			if (!c.isChrome) {
				results.push(c);
			}
		}
		return results;
	},
	/**
		Destroys "client controls", the same set of controls returned by
		_getClientControls_.
	*/
	destroyClientControls: function() {
		var c$ = this.getClientControls();
		for (var i=0, c; c=c$[i]; i++) {
			c.destroy();
		}
	},
	//* @protected
	addControl: function(inControl) {
		// Called to add an already created control to the object's control list. It is
		// not used to create controls and should likely not be called directly.
		// It can be overridden to detect when controls are added.
		this.controls.push(inControl);
		// When we add a Control, we also establish a parent.
		this.addChild(inControl);
	},
    removeControl: function(inControl) {
		// Called to remove a control from the object's control list. As with addControl it
		// can be overridden to detect when controls are removed.
		// When we remove a Control, we also remove it from its parent.
		inControl.setParent(null);
		return enyo.remove(inControl, this.controls);
	},
	indexOfControl: function(inControl) {
		return enyo.indexOf(inControl, this.controls);
	},
	indexOfClientControl: function(inControl) {
		return enyo.indexOf(inControl, this.getClientControls());
	},
	indexInContainer: function() {
		return this.container.indexOfControl(this);
	},
	clientIndexInContainer: function() {
		return this.container.indexOfClientControl(this);
	},
	controlAtIndex: function(inIndex) {
		return this.controls[inIndex];
	},
	// children
	addChild: function(inChild) {
		// allow delegating the child to a different container
		if (this.controlParent /*&& !inChild.isChrome*/) {
			// this.controlParent might have a controlParent, and so on; seek the ultimate parent
			this.controlParent.addChild(inChild);
		} else {
			// NOTE: addChild drives setParent.
			// It's the opposite for setContainer, where containerChanged (in Containable)
			// drives addControl.
			// Because of the way 'parent' is derived from 'container', this difference is
			// helpful for implementing controlParent.
			// By the same token, since 'parent' is derived from 'container', setParent is
			// not intended to be called by client code. Therefore, the lack of parallelism
			// should be private to this implementation.
			// Set the child's parent property to this
			inChild.setParent(this);
			// track in children array
			this.children[this.prepend ? "unshift" : "push"](inChild);
			/*
			// FIXME: hacky, allows us to reparent a rendered control; we need better API for dynamic reparenting
			if (inChild.hasNode()) {
				inChild[this.prepend ? "_prepend" : "_append"]();
			}
			*/
		}
	},
	removeChild: function(inChild) {
		return enyo.remove(inChild, this.children);
	},
	indexOfChild: function(inChild) {
		return enyo.indexOf(inChild, this.children);
	},
	layoutKindChanged: function() {
		if (this.layout) {
			this.layout.destroy();
		}
		this.layout = enyo.createFromKind(this.layoutKind, this);
		if (this.generated) {
			this.render();
		}
	},
	flow: function() {
		if (this.layout) {
			this.layout.flow();
		}
	},
	// CAVEAT: currently we use the entry point for both
	// post-render layout work *and* post-resize layout work.
	reflow: function() {
		if (this.layout) {
			this.layout.reflow();
		}
	},
	/**
		Call after this control has been resized to allow it to process the size change.
		To respond to a resize, override _resizeHandler_ instead.
	*/
	// syntactic sugar for 'waterfall("onresize")'
	resized: function() {
		this.waterfall("onresize", enyo.UiComponent._resizeFlags);
		this.waterfall("onpostresize", enyo.UiComponent._resizeFlags);
	},
	//* @protected
	resizeHandler: function() {
		// FIXME: once we are in the business of reflowing layouts on resize, then we have an
		// inside/outside problem: some scenarios will need to reflow before child
		// controls reflow, and some will need to reflow after. Even more complex scenarios
		// have circular dependencies, and can require multiple passes or other resolution.
		// When we can rely on CSS to manage reflows we do not have these problems.
		this.reflow();
	},
	/**
		Sends a message to all my descendents.
	*/
	waterfallDown: function(inMessage, inPayload, inSender) {
		// Note: Controls will generally be both in a $ hash and a child list somewhere.
		// Attempt to avoid duplicated messages by sending only to components that are not
		// UiComponent, as those components are guaranteed not to be in a child list.
		// May cause a problem if there is a scenario where a UiComponent owns a pure
		// Component that in turn owns Controls.
		//
		// waterfall to all pure components
		for (var n in this.$) {
			if (!(this.$[n] instanceof enyo.UiComponent)) {
				this.$[n].waterfall(inMessage, inPayload, inSender);
			}
		}
		// waterfall to my children
		for (var i=0, cs=this.children, c; c=cs[i]; i++) {
			// Do not send {showingOnly: true} events to hidden controls. This flag is set for resize events
			// which are broadcast from within the framework. This saves a *lot* of unnecessary layout.
			// TODO: Maybe remember that we did this, and re-send those messages on setShowing(true)?
			// No obvious problems with it as-is, though
			if (c.showing || !(inPayload && inPayload.showingOnly)) {
				c.waterfall(inMessage, inPayload, inSender);
			}
		}
	},
	getBubbleTarget: function() {
		return this.parent;
	}
});

enyo.createFromKind = function(inKind, inParam) {
	var ctor = inKind && enyo.constructorForKind(inKind);
	if (ctor) {
		return new ctor(inParam);
	}
};

//
// Default owner for ownerless UiComponents to allow notifying such UiComponents
// of important system events like window resize.
//
// NOTE: Ownerless UiComponents will not be garbage collected unless explicitly
// destroyed, as they will be referenced by _enyo.master_.
//
enyo.master = new enyo.Component({
	name: "master",
	notInstanceOwner: true,
	eventFlags: {showingOnly: true}, // don't waterfall these events into hidden controls
	getId: function() {
		return '';
	},
	isDescendantOf: enyo.nop,
	bubble: function(inEventName, inEvent, inSender) {
		//console.log("master event: " + inEventName);
		if (inEventName == "onresize") {
			// Resize is special; waterfall this message.
			// This works because master is a Component, so it waterfalls
			// to its owned Components (i.e., master has no children).
			enyo.master.waterfallDown("onresize", this.eventFlags);
			enyo.master.waterfallDown("onpostresize", this.eventFlags);
		} else {
			// All other top-level events are sent only to interested Signal
			// receivers.
			enyo.Signals.send(inEventName, inEvent);
		}
	}
});
<commit_msg>ENYO-579: add inBefore property to addChild and addControl to allow setting position of new child in component list<commit_after>/**
	_enyo.UiComponent_ implements a container strategy suitable for presentation
	layers.

	UiComponent itself is abstract.  Concrete subkinds include
	enyo.Control (for HTML/DOM) and
	enyo.canvas.Control
	(for Canvas contexts).
*/
enyo.kind({
	name: "enyo.UiComponent",
	kind: enyo.Component,
	published: {
		//* the UiComponent that physically contains this component in the DOM
		container: null,
		//* the UiComponent that owns this component for the purpose of event propogation
		parent: null,
		//* the UiComponent that will physically contain new items added using createComponent
		controlParentName: "client",
		//* a kind used to manage the size and placement of child components
		layoutKind: ""
	},
	handlers: {
		onresize: "resizeHandler"
	},
	statics: {
		_resizeFlags: {showingOnly: true} // don't waterfall these events into hidden controls
	},
	create: function() {
		this.controls = [];
		this.children = [];
		this.containerChanged();
		this.inherited(arguments);
		this.layoutKindChanged();
	},
	destroy: function() {
		// Destroys all non-chrome controls (regardless of owner).
		this.destroyClientControls();
		// Removes us from our container.
		this.setContainer(null);
		// Destroys chrome controls owned by this.
		this.inherited(arguments);
	},
	importProps: function(inProps) {
		this.inherited(arguments);
		if (!this.owner) {
			//this.log("registering ownerless control [" + this.kindName + "] with enyo.master");
			this.owner = enyo.master;
		}
	},
	// As implemented, _controlParentName_ only works to identify an owned
	// control created via _createComponents_ (i.e., usually in our _components_
	// block).  To attach a _controlParent_ via other means, one must call
	// _discoverControlParent_ or set _controlParent_ directly.
	//
	// We could call _discoverControlParent_ in _addComponent_, but it would
	// cause a lot of useless checking.
	createComponents: function() {
		var results = this.inherited(arguments);
		this.discoverControlParent();
		return results;
	},
	discoverControlParent: function() {
		this.controlParent = this.$[this.controlParentName] || this.controlParent;
	},
	adjustComponentProps: function(inProps) {
		// Components we create have us as a container by default.
		inProps.container = inProps.container || this;
		/*
		// the 'property master' is the object responsible for adjusting component props
		// which may not be the object on which component creation was invoked
		// the first-order property master is our container (this by default)
		var propMaster = inProps.container;
		// if we are the first-order property master, our control parent (if it exists) is the second-order master
		if (propMaster == this) {
			propMaster = this.controlParent || propMaster;
		}
		// if the property master is not us, delegate to him
		if (propMaster != this) {
			propMaster.adjustComponentProps(inProps);
		}
		// otherwise, do the usual
		else {
		*/
			this.inherited(arguments);
		//}
	},
	// containment
	containerChanged: function(inOldContainer) {
		if (inOldContainer) {
			inOldContainer.removeControl(this);
		}
		if (this.container) {
			this.container.addControl(this);
		}
	},
	// parentage
	parentChanged: function(inOldParent) {
		if (inOldParent && inOldParent != this.parent) {
			inOldParent.removeChild(this);
		}
	},
	//* @public
	// Note: Oddly, a Control is considered a descendant of itself.
	isDescendantOf: function(inAncestor) {
		var p = this;
		while (p && p!=inAncestor) {
			p = p.parent;
		}
		return inAncestor && (p == inAncestor);
	},
	/**
		Returns all controls.
	*/
	getControls: function() {
		return this.controls;
	},
	/**
		Returns all non-chrome controls.
	*/
	getClientControls: function() {
		var results = [];
		for (var i=0, cs=this.controls, c; c=cs[i]; i++) {
			if (!c.isChrome) {
				results.push(c);
			}
		}
		return results;
	},
	/**
		Destroys "client controls", the same set of controls returned by
		_getClientControls_.
	*/
	destroyClientControls: function() {
		var c$ = this.getClientControls();
		for (var i=0, c; c=c$[i]; i++) {
			c.destroy();
		}
	},
	//* @protected
	addControl: function(inControl, inBefore) {
		// Called to add an already created control to the object's control list. It is
		// not used to create controls and should likely not be called directly.
		// It can be overridden to detect when controls are added.
		this.controls.push(inControl);
		// When we add a Control, we also establish a parent.
		this.addChild(inControl, inBefore);
	},
    removeControl: function(inControl) {
		// Called to remove a control from the object's control list. As with addControl it
		// can be overridden to detect when controls are removed.
		// When we remove a Control, we also remove it from its parent.
		inControl.setParent(null);
		return enyo.remove(inControl, this.controls);
	},
	indexOfControl: function(inControl) {
		return enyo.indexOf(inControl, this.controls);
	},
	indexOfClientControl: function(inControl) {
		return enyo.indexOf(inControl, this.getClientControls());
	},
	indexInContainer: function() {
		return this.container.indexOfControl(this);
	},
	clientIndexInContainer: function() {
		return this.container.indexOfClientControl(this);
	},
	controlAtIndex: function(inIndex) {
		return this.controls[inIndex];
	},
	// children
	addChild: function(inChild, inBefore) {
		// if inBefore is undefined, use the old behavior of adding to front
		// or end of children based in this.prepend property. if it's null,
		// add to end, otherwise add before the specified control.
		//
		// allow delegating the child to a different container
		if (this.controlParent /*&& !inChild.isChrome*/) {
			// this.controlParent might have a controlParent, and so on; seek the ultimate parent
			// inBefore is not passed because that control won't be in the controlParent's scope
			this.controlParent.addChild(inChild);
		} else {
			// NOTE: addChild drives setParent.
			// It's the opposite for setContainer, where containerChanged (in Containable)
			// drives addControl.
			// Because of the way 'parent' is derived from 'container', this difference is
			// helpful for implementing controlParent.
			// By the same token, since 'parent' is derived from 'container', setParent is
			// not intended to be called by client code. Therefore, the lack of parallelism
			// should be private to this implementation.
			// Set the child's parent property to this
			inChild.setParent(this);
			// track in children array
			if (inBefore === undefined) {
				this.children[this.prepend ? "unshift" : "push"](inChild);
			} else if (inBefore === null) {
				// this case is needed to allow adding to end when this.prepend is true
				this.children.push(inChild);
			} else {
				var idx = this.indexOfChild(inBefore);
				this.children.splice(idx, 0, inChild);
			}
			/*
			// FIXME: hacky, allows us to reparent a rendered control; we need better API for dynamic reparenting
			if (inChild.hasNode()) {
				inChild[this.prepend ? "_prepend" : "_append"]();
			}
			*/
		}
	},
	removeChild: function(inChild) {
		return enyo.remove(inChild, this.children);
	},
	indexOfChild: function(inChild) {
		return enyo.indexOf(inChild, this.children);
	},
	layoutKindChanged: function() {
		if (this.layout) {
			this.layout.destroy();
		}
		this.layout = enyo.createFromKind(this.layoutKind, this);
		if (this.generated) {
			this.render();
		}
	},
	flow: function() {
		if (this.layout) {
			this.layout.flow();
		}
	},
	// CAVEAT: currently we use the entry point for both
	// post-render layout work *and* post-resize layout work.
	reflow: function() {
		if (this.layout) {
			this.layout.reflow();
		}
	},
	/**
		Call after this control has been resized to allow it to process the size change.
		To respond to a resize, override _resizeHandler_ instead.
	*/
	// syntactic sugar for 'waterfall("onresize")'
	resized: function() {
		this.waterfall("onresize", enyo.UiComponent._resizeFlags);
		this.waterfall("onpostresize", enyo.UiComponent._resizeFlags);
	},
	//* @protected
	resizeHandler: function() {
		// FIXME: once we are in the business of reflowing layouts on resize, then we have an
		// inside/outside problem: some scenarios will need to reflow before child
		// controls reflow, and some will need to reflow after. Even more complex scenarios
		// have circular dependencies, and can require multiple passes or other resolution.
		// When we can rely on CSS to manage reflows we do not have these problems.
		this.reflow();
	},
	/**
		Sends a message to all my descendents.
	*/
	waterfallDown: function(inMessage, inPayload, inSender) {
		// Note: Controls will generally be both in a $ hash and a child list somewhere.
		// Attempt to avoid duplicated messages by sending only to components that are not
		// UiComponent, as those components are guaranteed not to be in a child list.
		// May cause a problem if there is a scenario where a UiComponent owns a pure
		// Component that in turn owns Controls.
		//
		// waterfall to all pure components
		for (var n in this.$) {
			if (!(this.$[n] instanceof enyo.UiComponent)) {
				this.$[n].waterfall(inMessage, inPayload, inSender);
			}
		}
		// waterfall to my children
		for (var i=0, cs=this.children, c; c=cs[i]; i++) {
			// Do not send {showingOnly: true} events to hidden controls. This flag is set for resize events
			// which are broadcast from within the framework. This saves a *lot* of unnecessary layout.
			// TODO: Maybe remember that we did this, and re-send those messages on setShowing(true)?
			// No obvious problems with it as-is, though
			if (c.showing || !(inPayload && inPayload.showingOnly)) {
				c.waterfall(inMessage, inPayload, inSender);
			}
		}
	},
	getBubbleTarget: function() {
		return this.parent;
	}
});

enyo.createFromKind = function(inKind, inParam) {
	var ctor = inKind && enyo.constructorForKind(inKind);
	if (ctor) {
		return new ctor(inParam);
	}
};

//
// Default owner for ownerless UiComponents to allow notifying such UiComponents
// of important system events like window resize.
//
// NOTE: Ownerless UiComponents will not be garbage collected unless explicitly
// destroyed, as they will be referenced by _enyo.master_.
//
enyo.master = new enyo.Component({
	name: "master",
	notInstanceOwner: true,
	eventFlags: {showingOnly: true}, // don't waterfall these events into hidden controls
	getId: function() {
		return '';
	},
	isDescendantOf: enyo.nop,
	bubble: function(inEventName, inEvent, inSender) {
		//console.log("master event: " + inEventName);
		if (inEventName == "onresize") {
			// Resize is special; waterfall this message.
			// This works because master is a Component, so it waterfalls
			// to its owned Components (i.e., master has no children).
			enyo.master.waterfallDown("onresize", this.eventFlags);
			enyo.master.waterfallDown("onpostresize", this.eventFlags);
		} else {
			// All other top-level events are sent only to interested Signal
			// receivers.
			enyo.Signals.send(inEventName, inEvent);
		}
	}
});
<|endoftext|>


<commit_before>/*
Plugin Name: amCharts smoothCustomBullets
Description: Adds clip-path on images to smooth the corners of the custom bullet images
Author: Benjamin Maertz, amCharts
Version: 1.0.4
Author URI: http://www.amcharts.com/

Copyright 2016 amCharts

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Please note that the above license covers only this plugin. It by all means does
not apply to any other amCharts products that are covered by different licenses.
*/
AmCharts.addInitHandler( function( chart ) {
    var DEFAULTS = {
        "version": "1.0.4",

        "borderRadius": "auto",

        "fillAlpha": 0,
        "fillColor": undefined,

        "borderAlpha": 0,
        "borderColor": undefined,
        "borderThickness": undefined,
        "borderLinejoin": undefined,
        "borderLinecap": undefined,
        "borderDasharray": undefined,

        "positiveOffset": 0,
        "negativeOffset": 3
    }
    var TIMER = 0;
    var INITIALIZED = false;

    // GET CHILDREN
    function getChildNodes( elm, tagName ) {
        if ( tagName ) {
            return elm.getElementsByTagName( tagName );
        }
        return elm.childNodes ? elm.childNodes : elm.children;
    }

    // UPDATE ATTRIBUTE
    function updateAttribute( node, key, val ) {
        if ( val !== undefined ) {
            node.setAttribute( key, val );
        }
    }

    // GET OPTION
    function getOption( key, alt ) {
        var cfg = chart.smoothCustomBullets;
        var val = cfg[ key ];

        // EXCEPTION
        if ( val == "0" && key == "borderAlpha" && ( cfg.borderColor !== undefined || cfg.borderThickness ) ) {
            val = 1;
        }

        if ( val === undefined || val == "auto" ) {
            val = alt;
        }

        return val;
    }

    // CREATES OVERLAYING RECT (BORDER)
    function createBorder( image, target, graph, dataPoint ) {
        var border, color;
        var cfg = chart.smoothCustomBullets;
        var width = image.getAttribute( "width" );
        var height = image.getAttribute( "height" );
        var transform = image.getAttribute( "transform" );
        var bR = cfg.borderRadius == "auto" ? width : cfg.borderRadius;

        // GET RIGHT COLOR
        if ( dataPoint.isNegative && graph.negativeLineColor ) {
            color = graph.negativeLineColor;
        } else if ( graph.lineColorField && dataPoint[ graph.lineColorField ] ) {
            color = dataPoint[ graph.lineColorField ];
        } else if ( graph.colorField && dataPoint[ graph.colorField ] ) {
            color = dataPoint[ graph.colorField ];
        } else {
            color = graph.bulletColorR;
        }

        // CREATE RECT
        border = document.createElementNS( AmCharts.SVG_NS, "rect" );

        // APPLY SOME SUGAR
        updateAttribute( border, "fill", getOption( "fillColor", color ) );
        updateAttribute( border, "fill-opacity", getOption( "fillAlpha" ) );
        updateAttribute( border, "stroke", getOption( "borderColor", color ) );
        updateAttribute( border, "stroke-width", getOption( "borderThickness" ) );
        updateAttribute( border, "stroke-opacity", getOption( "borderAlpha" ) );
        updateAttribute( border, "stroke-linecap", getOption( "borderLinecap" ) );
        updateAttribute( border, "stroke-linejoin", getOption( "borderLinejoin" ) );
        updateAttribute( border, "stroke-dasharray", getOption( "borderDasharray" ) );

        // REQUIRED STUFF
        updateAttribute( border, "width", width );
        updateAttribute( border, "height", height );
        updateAttribute( border, "rx", getOption( "borderRadius", width ) );
        updateAttribute( border, "ry", getOption( "borderRadius", width ) );
        updateAttribute( border, "transform", transform );

        // APPEND TO TARGET
        target.appendChild( border );
    }

    // GET OFFSET VALUE
    function getOffsetValue( value, graph ) {
        if ( value instanceof Function ) {
            return value( graph );
        } else if ( !isNaN( value ) ) {
            return Number( value );
        } else {
            return 0
        }
    }

    // UPDATE CLIP PATHS
    function updateClipPaths( e ) {
        var i1, i2, i3;
        var clipPaths = [];
        var i1s = chart.graphs;
        var cfg = chart.smoothCustomBullets;
        var eventType = e ? e.type : undefined;

        // WAIT FOR INITIALIZATION
        if ( !INITIALIZED ) {
            return;
        }

        // DELAYING EXCEPTION
        clearTimeout( TIMER );
        if ( [ "axisChanged", "axisZoomed" ].indexOf( eventType ) != -1 ) {
            TIMER = setTimeout( updateClipPaths, AmCharts.updateRate );
            return;
        }

        // WALKTHOUGH GRAPHS
        for ( i1 = 0; i1 < i1s.length; i1++ ) {
            var graph = i1s[ i1 ];
            var valueAxis = graph.valueAxis;
            var i2s = graph.data;
            var baseCoord = graph.baseCoord;

            // WALKTHOUGH DATAPOINTS
            for ( i2 = 0; i2 < i2s.length; i2++ ) {
                var i3s = Object.keys( i2s[ i2 ].axes );

                // WALKTHOUGH AXES
                for ( i3 = 0; i3 < i3s.length; i3++ ) {
                    var dataPoint = i2s[ i2 ].axes[ i3s[ i3 ] ].graphs[ graph.id ];

                    // HAS BULLETGRAPHICS
                    if ( dataPoint.bulletGraphics !== undefined ) {
                        var bulletGroup = dataPoint.bulletGraphics.node;
                        var i4s = getChildNodes( bulletGroup, "image" );
                        var bulletCTM = bulletGroup.getCTM();

                        // WALKTHOUGH IMAGES
                        for ( i4 = 0; i4 < i4s.length; i4++ ) {
                            var image = i4s[ i4 ];
                            var uid = AmCharts.getUniqueId();
                            var width = image.getAttribute( "width" );
                            var height = image.getAttribute( "height" );
                            var bR = cfg.borderRadius == "auto" ? width : cfg.borderRadius;
                            var imageCTM;

                            // APPLY OFFSET
                            if ( image.transform && image.transform.baseVal && image.transform.baseVal.numberOfItems ) {
                                imageCTM = image.transform.baseVal.getItem( 0 );

                                if ( bulletCTM.f < baseCoord ) {
                                    imageCTM.matrix.f += getOffsetValue( cfg.positiveOffset, graph );
                                } else {
                                    imageCTM.matrix.f += getOffsetValue( cfg.negativeOffset, graph );
                                }
                            }

                            // UPDATE IMAGE AND LINK WITH CLIPPATH
                            updateAttribute( image, "clip-path", [ "url(#", uid, ")" ].join( "" ) );

                            // CREATE BORDER
                            createBorder( image, bulletGroup, graph, dataPoint );

                            // CREATE CLIPPATH
                            clipPaths.push( {
                                id: uid,
                                rect: {
                                    width: width,
                                    height: height,
                                    rx: bR
                                }
                            } );
                        }
                    }
                }
            }
        }

        // UPDATE DEFS
        AmCharts.extend( chart.defs, {
            clipPath: clipPaths
        } );

        // PARSE DEFS
        AmCharts.parseDefs( chart.defs, chart.container.defs );
    }

    // ENABLED?!
    if ( chart.smoothCustomBullets !== undefined ) {

        // MERGE SETTINGS
        chart.smoothCustomBullets = AmCharts.extend( DEFAULTS, chart.smoothCustomBullets || {} )

        // PLACEHOLDER
        if ( chart.defs === undefined ) {
            chart.defs = {};
        }

        // EXPORT
        chart.smoothCustomBullets.updateClipPaths = updateClipPaths;

        // REAPPLY ON UPDATES
        chart.addListener( "init", function() {
            // FLAG AS INITIALIZED DUE ZOOMED EVENT
            INITIALIZED = true;

            // VALUE AXES
            if ( chart.valueAxes ) {
                for ( i1 = 0; i1 < chart.valueAxes.length; i1++ ) {
                    chart.valueAxes[ i1 ].addListener( "axisChanged", updateClipPaths );
                    chart.valueAxes[ i1 ].addListener( "axisZoomed", updateClipPaths );
                }
            }

            // CHART CURSOR
            if ( chart.chartCursor ) {
                chart.chartCursor.addListener( "zoomed", updateClipPaths );
            }
        } );
        chart.addListener( "drawn", updateClipPaths );
        chart.addListener( "zoomed", updateClipPaths );

    }
}, [ "serial", "xy", "radar", "stock", "gantt" ] );<commit_msg>Fix issue with several graphs<commit_after>/*
Plugin Name: amCharts smoothCustomBullets
Description: Adds clip-path on images to smooth the corners of the custom bullet images
Author: Benjamin Maertz, amCharts
Version: 1.0.4
Author URI: http://www.amcharts.com/

Copyright 2016 amCharts

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Please note that the above license covers only this plugin. It by all means does
not apply to any other amCharts products that are covered by different licenses.
*/
AmCharts.addInitHandler( function( chart ) {
    var DEFAULTS = {
        "version": "1.0.4",

        "borderRadius": "auto",

        "fillAlpha": 0,
        "fillColor": undefined,

        "borderAlpha": 0,
        "borderColor": undefined,
        "borderThickness": undefined,
        "borderLinejoin": undefined,
        "borderLinecap": undefined,
        "borderDasharray": undefined,

        "positiveOffset": 0,
        "negativeOffset": 3
    }
    var TIMER = 0;
    var INITIALIZED = false;

    // GET CHILDREN
    function getChildNodes( elm, tagName ) {
        if ( tagName ) {
            return elm.getElementsByTagName( tagName );
        }
        return elm.childNodes ? elm.childNodes : elm.children;
    }

    // UPDATE ATTRIBUTE
    function updateAttribute( node, key, val ) {
        if ( val !== undefined ) {
            node.setAttribute( key, val );
        }
    }

    // GET OPTION
    function getOption( key, alt ) {
        var cfg = chart.smoothCustomBullets;
        var val = cfg[ key ];

        // EXCEPTION
        if ( val == "0" && key == "borderAlpha" && ( cfg.borderColor !== undefined || cfg.borderThickness ) ) {
            val = 1;
        }

        if ( val === undefined || val == "auto" ) {
            val = alt;
        }

        return val;
    }

    // CREATES OVERLAYING RECT (BORDER)
    function createBorder( image, target, graph, dataPoint ) {
        var border, color;
        var cfg = chart.smoothCustomBullets;
        var width = image.getAttribute( "width" );
        var height = image.getAttribute( "height" );
        var transform = image.getAttribute( "transform" );
        var bR = cfg.borderRadius == "auto" ? width : cfg.borderRadius;

        // GET RIGHT COLOR
        if ( dataPoint.isNegative && graph.negativeLineColor ) {
            color = graph.negativeLineColor;
        } else if ( graph.lineColorField && dataPoint[ graph.lineColorField ] ) {
            color = dataPoint[ graph.lineColorField ];
        } else if ( graph.colorField && dataPoint[ graph.colorField ] ) {
            color = dataPoint[ graph.colorField ];
        } else {
            color = graph.bulletColorR;
        }

        // CREATE RECT
        border = document.createElementNS( AmCharts.SVG_NS, "rect" );

        // APPLY SOME SUGAR
        updateAttribute( border, "fill", getOption( "fillColor", color ) );
        updateAttribute( border, "fill-opacity", getOption( "fillAlpha" ) );
        updateAttribute( border, "stroke", getOption( "borderColor", color ) );
        updateAttribute( border, "stroke-width", getOption( "borderThickness" ) );
        updateAttribute( border, "stroke-opacity", getOption( "borderAlpha" ) );
        updateAttribute( border, "stroke-linecap", getOption( "borderLinecap" ) );
        updateAttribute( border, "stroke-linejoin", getOption( "borderLinejoin" ) );
        updateAttribute( border, "stroke-dasharray", getOption( "borderDasharray" ) );

        // REQUIRED STUFF
        updateAttribute( border, "width", width );
        updateAttribute( border, "height", height );
        updateAttribute( border, "rx", getOption( "borderRadius", width ) );
        updateAttribute( border, "ry", getOption( "borderRadius", width ) );
        updateAttribute( border, "transform", transform );

        // APPEND TO TARGET
        target.appendChild( border );
    }

    // GET OFFSET VALUE
    function getOffsetValue( value, graph ) {
        if ( value instanceof Function ) {
            return value( graph );
        } else if ( !isNaN( value ) ) {
            return Number( value );
        } else {
            return 0
        }
    }

    // UPDATE CLIP PATHS
    function updateClipPaths( e ) {
        var i1, i2, i3;
        var clipPaths = [];
        var i1s = chart.graphs;
        var cfg = chart.smoothCustomBullets;
        var eventType = e ? e.type : undefined;

        // WAIT FOR INITIALIZATION
        if ( !INITIALIZED ) {
            return;
        }

        // DELAYING EXCEPTION
        clearTimeout( TIMER );
        if ( [ "axisChanged", "axisZoomed" ].indexOf( eventType ) != -1 ) {
            TIMER = setTimeout( updateClipPaths, AmCharts.updateRate );
            return;
        }

        // WALKTHOUGH GRAPHS
        for ( i1 = 0; i1 < i1s.length; i1++ ) {
            var graph = i1s[ i1 ];
            var valueAxis = graph.valueAxis;
            var i2s = graph.data;
            var baseCoord = graph.baseCoord;

            // WALKTHOUGH DATAPOINTS
            for ( i2 = 0; i2 < i2s.length; i2++ ) {
                var i3s = Object.keys( i2s[ i2 ].axes );

                // WALKTHOUGH AXES
                for ( i3 = 0; i3 < i3s.length; i3++ ) {
                    var dataPoint = i2s[ i2 ].axes[ i3s[ i3 ] ].graphs[ graph.id ];

                    // HAS BULLETGRAPHICS
                    if (dataPoint !== undefined) {
                        if (dataPoint.bulletGraphics !== undefined) {
                            var bulletGroup = dataPoint.bulletGraphics.node;
                            var i4s = getChildNodes(bulletGroup, "image");
                            var bulletCTM = bulletGroup.getCTM();

                            // WALKTHOUGH IMAGES
                            for (i4 = 0; i4 < i4s.length; i4++) {
                                var image = i4s[i4];
                                var uid = AmCharts.getUniqueId();
                                var width = image.getAttribute("width");
                                var height = image.getAttribute("height");
                                var bR = cfg.borderRadius == "auto" ? width : cfg.borderRadius;
                                var imageCTM;

                                // APPLY OFFSET
                                if (image.transform && image.transform.baseVal && image.transform.baseVal.numberOfItems) {
                                    imageCTM = image.transform.baseVal.getItem(0);

                                    if (bulletCTM.f < baseCoord) {
                                        imageCTM.matrix.f += getOffsetValue(cfg.positiveOffset, graph);
                                    } else {
                                        imageCTM.matrix.f += getOffsetValue(cfg.negativeOffset, graph);
                                    }
                                }

                                // UPDATE IMAGE AND LINK WITH CLIPPATH
                                updateAttribute(image, "clip-path", ["url(#", uid, ")"].join(""));

                                // CREATE BORDER
                                createBorder(image, bulletGroup, graph, dataPoint);

                                // CREATE CLIPPATH
                                clipPaths.push({
                                    id: uid,
                                    rect: {
                                        width: width,
                                        height: height,
                                        rx: bR
                                    }
                                });
                            }
                        }
                    }
                }
            }
        }

        // UPDATE DEFS
        AmCharts.extend( chart.defs, {
            clipPath: clipPaths
        } );

        // PARSE DEFS
        AmCharts.parseDefs( chart.defs, chart.container.defs );
    }

    // ENABLED?!
    if ( chart.smoothCustomBullets !== undefined ) {

        // MERGE SETTINGS
        chart.smoothCustomBullets = AmCharts.extend( DEFAULTS, chart.smoothCustomBullets || {} )

        // PLACEHOLDER
        if ( chart.defs === undefined ) {
            chart.defs = {};
        }

        // EXPORT
        chart.smoothCustomBullets.updateClipPaths = updateClipPaths;

        // REAPPLY ON UPDATES
        chart.addListener( "init", function() {
            // FLAG AS INITIALIZED DUE ZOOMED EVENT
            INITIALIZED = true;

            // VALUE AXES
            if ( chart.valueAxes ) {
                for ( i1 = 0; i1 < chart.valueAxes.length; i1++ ) {
                    chart.valueAxes[ i1 ].addListener( "axisChanged", updateClipPaths );
                    chart.valueAxes[ i1 ].addListener( "axisZoomed", updateClipPaths );
                }
            }

            // CHART CURSOR
            if ( chart.chartCursor ) {
                chart.chartCursor.addListener( "zoomed", updateClipPaths );
            }
        } );
        chart.addListener( "drawn", updateClipPaths );
        chart.addListener( "zoomed", updateClipPaths );

    }
}, [ "serial", "xy", "radar", "stock", "gantt" ] );
<|endoftext|>


<commit_before>
if (Math.random() > 0.5) {
  var css = document.createElement('style');
  css.type = 'text/css';
  css.appendChild(document.createTextNode("#mypic:hover { background-image:url(/files/images/eugene.png); }"))
  document.querySelector("body").appendChild(css);
}
<commit_msg>updated site<commit_after>if (!/pic=true/.test(document.cookie)) {
  document.cookie = "pic=true;max-age=315360000";
} else {
  document.cookie = "pic=false;max-age=315360000";
  var css = document.createElement('style');
  css.type = 'text/css';
  css.appendChild(document.createTextNode("#mypic:hover { background-image:url(/files/images/eugene.png); }"))
  document.querySelector("body").appendChild(css);
}

if (Math.random() > 0.5) {
}
<|endoftext|>


<commit_before>/*
A jQuery plugin to convert a well formatted table into a table with fixed
rows and columns.

About License:
Copyright (C) 2013 Selvakumar Arumugam
You may use attrchange plugin under the terms of the MIT Licese.
https://github.com/meetselva/fixed-table-rows-cols/blob/master/MIT-License.txt
*/
(function ($) {

	$.fn.fxdHdrCol = function (o) {
		var cfg = {
			height: 0,
			width: 0,
			fixedCols: 0,
			colModal: [],
			tableTmpl: function () {
				return '
';
			}
		};
		$.extend(cfg, o);

		return this.each (function () {
			var lc = {
					ft_container: null,
					ft_rel_container: null,
					ft_wrapper: null,
					ft_rc: null,
					ft_r: null,
					ft_c: null,
					tableWidth: 0
			};

			var $this = $(this);
			$this.addClass('ui-widget-header');
			$this.find('tbody tr').addClass('ui-widget-content');

			//add base container
			$this.wrap('
');
			lc.ft_container = $this.parent();

			var $ths = $('thead tr', $this).first().find('th');
			var $thFirst = $ths.first();
			var thSpace = parseInt($thFirst.css('paddingLeft'), 10) + parseInt($thFirst.css('paddingRight'), 10) + 3;

			/* set width and textAlign from colModal */
			var ct = 0;
			$ths.each(function (i, el) {
				var calcWidth = 0;
				for (var j = 0; j < el.colSpan; j++) {
					calcWidth += cfg.colModal[ct].width;
					ct++;
				}
				$(el).css({width: calcWidth, textAlign: cfg.colModal[ct-1].align});
				lc.tableWidth += calcWidth + thSpace;
			});

			$this.width(lc.tableWidth);

			$('tbody', $this).find('tr').each(function (i, el) {
				$('td', el).each(function (i, tdel) {
					tdel.style.textAlign = cfg.colModal[i].align;
				});
			});

			//add relative container
			$this.wrap('
');
			lc.ft_rel_container = $this.parent();

			//set width and height for rel container
			lc.ft_rel_container.css({width: cfg.width, height: cfg.height});

			//add wrapper to base table which will have the scrollbars
			$this.wrap('
');
			lc.ft_wrapper = $this.parent();

			var theadTr = $('thead', $this);

			//clone the thead->tr
			var theadTrClone = theadTr.clone();

			//construct fixed row (full row)
			lc.ft_rel_container
				.prepend($(cfg.tableTmpl(), {'class': 'ft_r ui-widget-header'})
				.append(theadTrClone));

			//an instance of fixed row
			lc.ft_r = $('.ft_r', lc.ft_rel_container);
			lc.ft_r.wrap($('
', {'class': 'ft_rwrapper'}));

			lc.ft_r.width(lc.tableWidth);

			if (cfg.fixedCols > 0) {
				//clone the thead again to construct the
				theadTrClone = theadTr.clone();

				//calculate the actual column's count (support for colspan)
				var r1c1ColSpan = 0;
				for (var i = 0; i < cfg.fixedCols; i++ ) {
					r1c1ColSpan += this.rows[0].cells[i].colSpan;
				}

				//prepare rows/cols for fixed row col section
				var tdct = 0;
				$('tr', theadTrClone).first().find('th').filter( function () {
					tdct += this.colSpan;
					return tdct > r1c1ColSpan;
				}).remove();

				//add fixed row col section
				lc.ft_rel_container
					.prepend($(cfg.tableTmpl(), {'class': 'ft_rc ui-widget-header'})
					.append(theadTrClone));

				//an instance of fixed row column
				lc.ft_rc = $('.ft_rc', lc.ft_rel_container);

				//now clone the fixed row column and append tbody for the remaining rows
				lc.ft_c = lc.ft_rc.clone();
				lc.ft_c[0].className = 'ft_c';

				//append tbody
				lc.ft_c.append('
');

				//append row by row while just keeping the frozen cols
				var ftc_tbody = lc.ft_c.find('tbody');
				$.each ($this.find('tbody > tr'), function (idx, el) {
					var tr = $(el).clone();

					tdct = 0;
					tr.find('td').filter(function (){
						tdct += this.colSpan;
						return tdct > r1c1ColSpan;
					}).remove();

					ftc_tbody.append(tr);
				});

				lc.ft_rc.after(lc.ft_c);
				lc.ft_c.wrap($('
', {'class': 'ft_cwrapper'}));

				var tw = 0;
				for (var i = 0; i < cfg.fixedCols; i++) {
					tw += $(this.rows[0].cells[i]).outerWidth(true);
				}
				lc.ft_c.add(lc.ft_rc).width(tw);
				lc.ft_c.height($this.outerHeight(true));

				//set height of fixed_rc and fixed_c
				for (var i = 0; i < this.rows.length; i++) {
					var ch = $(this.rows[i]).outerHeight();
					var fch = $(lc.ft_c[0].rows[i]).outerHeight(true);

					ch = (ch>fch)?ch:fch;

					if (i < lc.ft_rc[0].rows.length) {
						$(lc.ft_r[0].rows[i])
							.add(lc.ft_rc[0].rows[i])
							.height(ch);
					}

					$(lc.ft_c[0].rows[i])
						.add(this.rows[i])
						.height(ch);
				}

				lc.ft_c
					.parent()
					.css({height: cfg.height-17})
					.width(lc.ft_rc.outerWidth(true) + 1);
			}

			lc.ft_r
				.parent()
				.css({width: lc.ft_rel_container.width()- 17});

			//events (scroll and resize)
			lc.ft_wrapper.scroll(function () {
				if (cfg.fixedCols > 0) {
					lc.ft_c.css('top', ($(this).scrollTop()*-1));
				}
				lc.ft_r.css('left', ($(this).scrollLeft()*-1));
			});

			/*$(window).on('resize', function () {
				lc.ft_r
				.parent()
				.css({width: lc.ft_rel_container.width()- 17});
			});*/
		});

	};

})(jQuery);<commit_msg>Fix for Chrome and Added Sorting feature.<commit_after>/*
A jQuery plugin to convert a well formatted table into a table with fixed
rows and columns.

About License:
Copyright (C) 2013 Selvakumar Arumugam
You may use attrchange plugin under the terms of the MIT Licese.
https://github.com/meetselva/fixed-table-rows-cols/blob/master/MIT-License.txt
*/
/*
A jQuery plugin to convert a well formatted table into a table with fixed
rows and columns.

Copyright (C) (2011-2012) Selvakumar Arumugam

This program is free software: you  can redistribute it and/or modify it
under the  terms of the GNU  General Public License as  published by the
Free Software Foundation,  either version 3 of the License,  or (at your
option) any later version.

This  program  is distributed  in  the  hope  that  it will  be  useful,
but  WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy  of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function ($) {

	$.fn.fxdHdrCol = function (o) {
		var cfg = {
			height: 0,
			width: 0,
			fixedCols: 0,
			colModal: [],
			tableTmpl: function () {
				return '
';
			},
			sort: false
		};
		$.extend(cfg, o);

		return this.each (function () {
			var lc = {
					ft_container: null,
					ft_rel_container: null,
					ft_wrapper: null,
					ft_rc: null,
					ft_r: null,
					ft_c: null,
					tableWidth: 0
			};

			var $this = $(this);
			$this.addClass('ui-widget-header');
			$this.find('tbody tr').addClass('ui-widget-content');

			//add base container
			$this.wrap('
');
			lc.ft_container = $this.parent();

			var $ths = $('thead tr', $this).first().find('th');

			if (cfg.sort && sorttable && cfg.fixedCols == 0) {
				$ths.addClass('fx_sort_bg');
			}

			var $thFirst = $ths.first();
			var thSpace = parseInt($thFirst.css('paddingLeft'), 10) + parseInt($thFirst.css('paddingRight'), 10);

			/* set width and textAlign from colModal */
			var ct = 0;
			$ths.each(function (i, el) {
				var calcWidth = 0;
				for (var j = 0; j < el.colSpan; j++) {
					calcWidth += cfg.colModal[ct].width;
					ct++;
				}
				$(el).css({width: calcWidth, textAlign: cfg.colModal[ct-1].align});

				lc.tableWidth += calcWidth + thSpace + ((i == 0)?2:1);
			});

			$('tbody', $this).find('tr').each(function (i, el) {
				$('td', el).each(function (i, tdel) {
					tdel.style.textAlign = cfg.colModal[i].align;
				});
			});

			$this.width(lc.tableWidth);

			//add relative container
			$this.wrap('
');
			lc.ft_rel_container = $this.parent();

			//set width and height for rel container
			lc.ft_rel_container.css({width: cfg.width, height: cfg.height});

			//add wrapper to base table which will have the scrollbars
			$this.wrap('
');
			lc.ft_wrapper = $this.parent();

			var theadTr = $('thead', $this);
			//clone the thead->tr
			var theadTrClone = theadTr.clone();

			//construct fixed row (full row)
			lc.ft_rel_container
				.prepend($(cfg.tableTmpl(), {'class': 'ft_r ui-widget-header'})
				.append(theadTrClone));

			//an instance of fixed row
			lc.ft_r = $('.ft_r', lc.ft_rel_container);
			lc.ft_r.wrap($('
', {'class': 'ft_rwrapper'}));

			lc.ft_r.width(lc.tableWidth);

			if (cfg.fixedCols > 0) {
				//clone the thead again to construct the
				theadTrClone = theadTr.clone();

				//calculate the actual column's count (support for colspan)
				var r1c1ColSpan = 0;
				for (var i = 0; i < cfg.fixedCols; i++ ) {
					r1c1ColSpan += this.rows[0].cells[i].colSpan;
				}

				//prepare rows/cols for fixed row col section
				var tdct = 0;
				$('tr', theadTrClone).first().find('th').filter( function () {
					tdct += this.colSpan;
					return tdct > r1c1ColSpan;
				}).remove();

				//add fixed row col section
				lc.ft_rel_container
					.prepend($(cfg.tableTmpl(), {'class': 'ft_rc ui-widget-header'})
					.append(theadTrClone));

				//an instance of fixed row column
				lc.ft_rc = $('.ft_rc', lc.ft_rel_container);

				//now clone the fixed row column and append tbody for the remaining rows
				lc.ft_c = lc.ft_rc.clone();
				lc.ft_c[0].className = 'ft_c';

				//append tbody
				lc.ft_c.append('
');

				//append row by row while just keeping the frozen cols
				var ftc_tbody = lc.ft_c.find('tbody');
				$.each ($this.find('tbody > tr'), function (idx, el) {
					var tr = $(el).clone();

					tdct = 0;
					tr.find('td').filter(function (){
						tdct += this.colSpan;
						return tdct > r1c1ColSpan;
					}).remove();

					ftc_tbody.append(tr);
				});

				lc.ft_rc.after(lc.ft_c);
				lc.ft_c.wrap($('
', {'class': 'ft_cwrapper'}));

				var tw = 0;
				for (var i = 0; i < cfg.fixedCols; i++) {
					tw += $(this.rows[0].cells[i]).outerWidth(true);
				}
				lc.ft_c.add(lc.ft_rc).width(tw);
				lc.ft_c.height($this.outerHeight(true));

				//set height of fixed_rc and fixed_c
				for (var i = 0; i < this.rows.length; i++) {
					var ch = $(this.rows[i]).outerHeight();
					var fch = $(lc.ft_c[0].rows[i]).outerHeight(true);

					ch = (ch>fch)?ch:fch;

					if (i < lc.ft_rc[0].rows.length) {
						$(lc.ft_r[0].rows[i])
							.add(lc.ft_rc[0].rows[i])
							.height(ch);
					}

					$(lc.ft_c[0].rows[i])
						.add(this.rows[i])
						.height(ch);
				}

				lc.ft_c
					.parent()
					.css({height: cfg.height-17})
					.width(lc.ft_rc.outerWidth(true) + 1);
			}

			lc.ft_r
				.parent()
				.css({width: lc.ft_rel_container.width()- 17});

			//events (scroll and resize)
			lc.ft_wrapper.scroll(function () {
				if (cfg.fixedCols > 0) {
					lc.ft_c.css('top', ($(this).scrollTop()*-1));
				}
				lc.ft_r.css('left', ($(this).scrollLeft()*-1));
			});

			/*$(window).on('resize', function () {
				lc.ft_r
				.parent()
				.css({width: lc.ft_rel_container.width()- 17});
			});*/

			if (cfg.sort && sorttable && cfg.fixedCols == 0) {

				$('table', lc.ft_container).addClass('sorttable');

				sorttable.makeSortable(this);

				var $sortableTh = $('.fx_sort_bg', lc.ft_rel_container);

				$sortableTh.click (function () {
					var $this = $(this);
					var isAscSort = $this.hasClass('fx_sort_asc');

					$sortableTh.removeClass('fx_sort_asc fx_sort_desc');

					if (isAscSort) {
						$this.addClass('fx_sort_desc').removeClass('fx_sort_asc');
					} else {
						$this.addClass('fx_sort_asc').removeClass('fx_sort_desc');
					}

					var idx = $(this).index();

					sorttable.innerSortFunction.apply(lc.ft_wrapper.find('th').get(idx), []);
				});
			}

		});

	};

})(jQuery);<|endoftext|>


<commit_before>var showDownloadLinks = (function ($) {
  return function (options) {
    var typeOfInstallersToShow = options.typeOfInstallersToShow;

    var settingsForAllTypes = {
      stable: {
        download_info_url: 'https://download.gocd.org/releases.json',
        download_prefix: 'https://download.gocd.org/binaries/',
        version_to_show: function (release) {
          return release['go_version'];
        },
        cloud_info_url: 'https://download.gocd.org/cloud.json'
      },
      experimental: {
        download_info_url: 'https://download.gocd.org/experimental/releases.json',
        download_prefix: 'https://download.gocd.org/experimental/binaries/',
        version_to_show: function (release) {
          return release['go_full_version'];
        },
        cloud_info_url: 'https://download.gocd.org/cloud.json'
      }
    };

    var settings = settingsForAllTypes[typeOfInstallersToShow];

    var dateFilter = R.curry(function (timeInSecondsSinceEpoch) {
      return (new Date() - new Date(timeInSecondsSinceEpoch * 1000)) < 3600 * 24 * 366 * 1000;
    });

    var releasesLessThanAYearOld = R.filter(R.where({
      release_time: dateFilter
    }));

    var addURLToFiles = function (release) {
      var addDetailsFrom = R.curry(function (release, analyticsIDPrefix, o) {
        var afterAddingURL = R.assoc('url', settings.download_prefix + release['go_full_version'] + '/' + o["file"], o);
        var afterAddingFilename = R.assoc('filename', R.last(o["file"].split("/")), afterAddingURL, o);
        var afterAddingAnalyticsID = R.assoc('analytics_id', analyticsIDPrefix + "_" + release['go_full_version'], afterAddingFilename, o);
        return afterAddingAnalyticsID;
      });

      return R.evolve({
        win: {
          server: addDetailsFrom(release, 'Windows-Server'),
          agent: addDetailsFrom(release, 'Windows-Agent'),
          server32bit: addDetailsFrom(release, 'Windows-Server-32bit'),
          agent32bit: addDetailsFrom(release, 'Windows-Agent-32bit')
        },
        osx: {
          server: addDetailsFrom(release, 'Mac-Server'),
          agent: addDetailsFrom(release, 'Mac-Agent')
        },
        deb: {
          server: addDetailsFrom(release, 'LinuxDeb-Server'),
          agent: addDetailsFrom(release, 'LinuxDeb-Agent')
        },
        rpm: {
          server: addDetailsFrom(release, 'LinuxRpm-Server'),
          agent: addDetailsFrom(release, 'LinuxRpm-Agent')
        },
        generic: {
          server: addDetailsFrom(release, 'Package-Server'),
          agent: addDetailsFrom(release, 'Package-Agent')
        }
      }, release);
    };

    var addDisplayVersion = R.curry(function (release) {
      return R.assoc('display_version', settings.version_to_show(release), release);
    });

    var compareVersions = function (propertyToCompareOn) {
      return function (a, b) {
        var i, diff;

        var segmentsA = a[propertyToCompareOn].replace('-', '.').split('.');
        var segmentsB = b[propertyToCompareOn].replace('-', '.').split('.');

        var l = Math.min(segmentsA.length, segmentsB.length);

        for (i = 0; i < l; i++) {
          diff = parseInt(segmentsB[i], 10) - parseInt(segmentsA[i], 10);
          if (diff) {
            return diff;
          }
        }
        return segmentsA.length - segmentsB.length;
      }
    };

    var showReleases = function (releaseData, amiData) {
      var addInfo = function (latestRelease) {
        var notes = {
          win: 'GoCD server and agent installers for Windows are packaged with 64 bit JRE. Starting with GoCD release v18.12.0, GoCD server and agent windows installers will not be shipped with 32 bit JRE.',
          deb: 'Note: If you prefer to use the APT repository to install, please follow these instructions.',
          rpm: 'Note: If you prefer to use the YUM repository to install, please follow these instructions.'
        };

        for (var key in notes) {
          var installerInfo = R.assoc('info', notes[key], latestRelease[key]);
          latestRelease = R.assoc(key, installerInfo, latestRelease)
        }
        return latestRelease;
      };

      var releases = R.compose(releasesLessThanAYearOld, R.sort(compareVersions('go_full_version')), R.map(addURLToFiles), R.map(addDisplayVersion))(releaseData[0]);
      var amiReleases = R.compose(releasesLessThanAYearOld, R.sort(compareVersions('go_version')))(amiData[0]);

      var latest_cloud_release = R.head(amiReleases);
      var other_cloud_releases = R.tail(amiReleases);
      var latestRelease = addInfo(R.head(releases));
      var template = Handlebars.compile($("#download-revisions-template").html());

      $("#downloads").html(template({
        latest_release: latestRelease,
        all_other_releases: R.tail(releases),
        latest_version: releases[0].go_version,
        latest_cloud_release: latest_cloud_release,
        all_other_cloud_releases: other_cloud_releases
      }));

      // add additional padding if there are 32 bit and 64 bit installers to show
      $("#downloads #tab-windows .files:has(.download-files)").css("padding-top", "40px");
    };

    var showFailureMessage = function (error) {
      $("#downloads").html('
Sorry. Something went wrong and we could not list the download links. \
        Please report this issue.
');
      console.log("Error: " + error);
    };

    $("#downloads").html($(".loading-message-template").html());

    return $.when(downloadOrGetFromCache(settings.download_info_url), downloadOrGetFromCache(settings.cloud_info_url))
      .done(showReleases)
      .fail(showFailureMessage);
  };
})(jQuery);

var downloadOrGetFromCache = (function ($) {
  var storedJSON = {};

  return function (url) {
    var deferred = $.Deferred();

    if (storedJSON.hasOwnProperty(url)) {
      deferred.resolve([storedJSON[url], "success"]);
      return deferred.promise();
    }

    return $.getJSON(url).done(function (data) {
      storedJSON[url] = data;
    });
  };
})(jQuery);

var setupShowVerifyChecksumMessage = (function ($) {
  return function () {
    $("body").on('click', '#downloads .verify-checksum', function (evt) {
      var checksumElement = $(evt.currentTarget);
      var template = Handlebars.compile($("#verify-checksum-message-template").html());
      $("#verify-checksum-message").html(template({
        filename: checksumElement.data("filename"),
        md5sum: checksumElement.data("md5sum"),
        sha1sum: checksumElement.data("sha1sum"),
        sha256sum: checksumElement.data("sha256sum")
      }));
      $('body').addClass("o-h");
    });
  };
})(jQuery);

var determinePackageNameBasedOnOS = function () {
  var userDefinedPackageName = window.location.hash.substr(1);
  var validPackageNames = ['zip', 'windows', 'osx', 'debian', 'redhat', 'ami', 'docker'];
  if (userDefinedPackageName !== "" && validPackageNames.includes(userDefinedPackageName)) {
    return userDefinedPackageName;
  }

  var userAgent = navigator.userAgent;
  var packageName = 'zip';
  if (userAgent.indexOf("Win") !== -1) packageName = "windows";
  if (userAgent.indexOf("Mac") !== -1) packageName = "osx";
  if (userAgent.indexOf("Debian") !== -1) packageName = "debian";
  if (userAgent.indexOf("Ubuntu") !== -1) packageName = "debian";
  if (userAgent.indexOf("RedHat") !== -1) packageName = "redhat";
  if (userAgent.indexOf("CentOS") !== -1) packageName = "redhat";

  return packageName
};

var switchDownloadType = function (currentInstallerType) {
  $(".release-type input." + currentInstallerType).attr('checked', true);
};

var displayAmiDropdown = function (currentOSPackageType) {
  if (currentOSPackageType === 'ami') {
    $('.select-dropdown').each(function () {
      var $this = $(this),
        numberOfOptions = $(this).children('option').length;

      $this.addClass('select-hidden');
      $this.wrap('

');
      $this.after('

');

      var $styledSelect = $this.next('div.select-styled');
      $styledSelect.text($this.children('option').eq(0).text());

      var $list = $('
', {
        'class': 'select-options'
      }).insertAfter($styledSelect);

      for (var i = 0; i < numberOfOptions; i++) {
        $('
', {
          text: $this.children('option').eq(i).text(),
          rel: $this.children('option').eq(i).val()
        }).appendTo($list);
      }

      var $listItems = $list.children('li');

      $styledSelect.click(function (e) {
        e.stopPropagation();
        $('div.select-styled.active').not(this).each(function () {
          $(this).removeClass('active').next('ul.select-options').hide();
        });
        $(this).toggleClass('active').next('ul.select-options').toggle();
      });

      $listItems.click(function (e) {
        e.stopPropagation();
        var previous_text = $styledSelect.text();
        $styledSelect.text($(this).text()).removeClass('active');
        $this.val($(this).attr('rel'));
        $list.hide();
        var previously_selected_row = "table ." + previous_text;
        var current_selected_row = "table ." + $styledSelect.text();

        $styledSelect.closest('.table-c').find(previously_selected_row).hide();
        $styledSelect.closest('.table-c').find(current_selected_row).show();
        //console.log($this.val());
      });

      $(document).click(function () {
        $styledSelect.removeClass('active');
        $list.hide();
      });
    });

    $('.table-c').each(function () {
      $(this).find('tr:gt(1)').each(function () {
        var $this = $(this);
        $this.hide();
      });
    });
  }
};

var showHelpLinksFor = (function ($) {
  return function (packageName) {
    var installer_type_to_help_link_type = {
      'debian': 'linux',
      'redhat': 'linux',
      'windows': 'windows',
      'zip': 'zip',
      'osx': 'osx'
    };
    var template = Handlebars.compile($("#downloads-help-links").html());

    $("#help-links").html(template({
      os: installer_type_to_help_link_type[packageName]
    }));
  };
})(jQuery);

Handlebars.registerHelper('size', function (array, operator, expectedSize, options) {
  'use strict';
  if (array == null || array == undefined) {
    return options.inverse(this);
  }

  switch (operator) {
    case 'lt':
      return array.length < expectedSize ? options.fn(this) : options.inverse(this);
    case 'lte':
      return array.length <= expectedSize ? options.fn(this) : options.inverse(this);
    case 'eq':
      return array.length === expectedSize ? options.fn(this) : options.inverse(this);
    case 'gt':
      return array.length > expectedSize ? options.fn(this) : options.inverse(this);
    case 'gte':
      return array.length >= expectedSize ? options.fn(this) : options.inverse(this);
    default:
      throw "Invalid operator " + operator + ".";
      break;
  }
});

(function showPopup() {
  var access_country;
  var COUNTRY_CODES_EU = [
    "AT", "BE", "BG", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT",
    "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "GB", "US"
  ]

  $.get("https://ipinfo.io", function (response) {
    access_country = response.country
  }, "jsonp");

  if ($.inArray(access_country, COUNTRY_CODES_EU) == -1) {
    $('.banner-fixed-bottom slide-in-bottom').hide();
  }
})();<commit_msg>bug fix in accessing country and displaying fixed banner popup based on country<commit_after>var showDownloadLinks = (function ($) {
  return function (options) {
    var typeOfInstallersToShow = options.typeOfInstallersToShow;

    var settingsForAllTypes = {
      stable: {
        download_info_url: 'https://download.gocd.org/releases.json',
        download_prefix: 'https://download.gocd.org/binaries/',
        version_to_show: function (release) {
          return release['go_version'];
        },
        cloud_info_url: 'https://download.gocd.org/cloud.json'
      },
      experimental: {
        download_info_url: 'https://download.gocd.org/experimental/releases.json',
        download_prefix: 'https://download.gocd.org/experimental/binaries/',
        version_to_show: function (release) {
          return release['go_full_version'];
        },
        cloud_info_url: 'https://download.gocd.org/cloud.json'
      }
    };

    var settings = settingsForAllTypes[typeOfInstallersToShow];

    var dateFilter = R.curry(function (timeInSecondsSinceEpoch) {
      return (new Date() - new Date(timeInSecondsSinceEpoch * 1000)) < 3600 * 24 * 366 * 1000;
    });

    var releasesLessThanAYearOld = R.filter(R.where({
      release_time: dateFilter
    }));

    var addURLToFiles = function (release) {
      var addDetailsFrom = R.curry(function (release, analyticsIDPrefix, o) {
        var afterAddingURL = R.assoc('url', settings.download_prefix + release['go_full_version'] + '/' + o["file"], o);
        var afterAddingFilename = R.assoc('filename', R.last(o["file"].split("/")), afterAddingURL, o);
        var afterAddingAnalyticsID = R.assoc('analytics_id', analyticsIDPrefix + "_" + release['go_full_version'], afterAddingFilename, o);
        return afterAddingAnalyticsID;
      });

      return R.evolve({
        win: {
          server: addDetailsFrom(release, 'Windows-Server'),
          agent: addDetailsFrom(release, 'Windows-Agent'),
          server32bit: addDetailsFrom(release, 'Windows-Server-32bit'),
          agent32bit: addDetailsFrom(release, 'Windows-Agent-32bit')
        },
        osx: {
          server: addDetailsFrom(release, 'Mac-Server'),
          agent: addDetailsFrom(release, 'Mac-Agent')
        },
        deb: {
          server: addDetailsFrom(release, 'LinuxDeb-Server'),
          agent: addDetailsFrom(release, 'LinuxDeb-Agent')
        },
        rpm: {
          server: addDetailsFrom(release, 'LinuxRpm-Server'),
          agent: addDetailsFrom(release, 'LinuxRpm-Agent')
        },
        generic: {
          server: addDetailsFrom(release, 'Package-Server'),
          agent: addDetailsFrom(release, 'Package-Agent')
        }
      }, release);
    };

    var addDisplayVersion = R.curry(function (release) {
      return R.assoc('display_version', settings.version_to_show(release), release);
    });

    var compareVersions = function (propertyToCompareOn) {
      return function (a, b) {
        var i, diff;

        var segmentsA = a[propertyToCompareOn].replace('-', '.').split('.');
        var segmentsB = b[propertyToCompareOn].replace('-', '.').split('.');

        var l = Math.min(segmentsA.length, segmentsB.length);

        for (i = 0; i < l; i++) {
          diff = parseInt(segmentsB[i], 10) - parseInt(segmentsA[i], 10);
          if (diff) {
            return diff;
          }
        }
        return segmentsA.length - segmentsB.length;
      }
    };

    var showReleases = function (releaseData, amiData) {
      var addInfo = function (latestRelease) {
        var notes = {
          win: 'GoCD server and agent installers for Windows are packaged with 64 bit JRE. Starting with GoCD release v18.12.0, GoCD server and agent windows installers will not be shipped with 32 bit JRE.',
          deb: 'Note: If you prefer to use the APT repository to install, please follow these instructions.',
          rpm: 'Note: If you prefer to use the YUM repository to install, please follow these instructions.'
        };

        for (var key in notes) {
          var installerInfo = R.assoc('info', notes[key], latestRelease[key]);
          latestRelease = R.assoc(key, installerInfo, latestRelease)
        }
        return latestRelease;
      };

      var releases = R.compose(releasesLessThanAYearOld, R.sort(compareVersions('go_full_version')), R.map(addURLToFiles), R.map(addDisplayVersion))(releaseData[0]);
      var amiReleases = R.compose(releasesLessThanAYearOld, R.sort(compareVersions('go_version')))(amiData[0]);

      var latest_cloud_release = R.head(amiReleases);
      var other_cloud_releases = R.tail(amiReleases);
      var latestRelease = addInfo(R.head(releases));
      var template = Handlebars.compile($("#download-revisions-template").html());

      $("#downloads").html(template({
        latest_release: latestRelease,
        all_other_releases: R.tail(releases),
        latest_version: releases[0].go_version,
        latest_cloud_release: latest_cloud_release,
        all_other_cloud_releases: other_cloud_releases
      }));

      // add additional padding if there are 32 bit and 64 bit installers to show
      $("#downloads #tab-windows .files:has(.download-files)").css("padding-top", "40px");
    };

    var showFailureMessage = function (error) {
      $("#downloads").html('
Sorry. Something went wrong and we could not list the download links. \
        Please report this issue.
');
      console.log("Error: " + error);
    };

    $("#downloads").html($(".loading-message-template").html());

    return $.when(downloadOrGetFromCache(settings.download_info_url), downloadOrGetFromCache(settings.cloud_info_url))
      .done(showReleases)
      .fail(showFailureMessage);
  };
})(jQuery);

var downloadOrGetFromCache = (function ($) {
  var storedJSON = {};

  return function (url) {
    var deferred = $.Deferred();

    if (storedJSON.hasOwnProperty(url)) {
      deferred.resolve([storedJSON[url], "success"]);
      return deferred.promise();
    }

    return $.getJSON(url).done(function (data) {
      storedJSON[url] = data;
    });
  };
})(jQuery);

var setupShowVerifyChecksumMessage = (function ($) {
  return function () {
    $("body").on('click', '#downloads .verify-checksum', function (evt) {
      var checksumElement = $(evt.currentTarget);
      var template = Handlebars.compile($("#verify-checksum-message-template").html());
      $("#verify-checksum-message").html(template({
        filename: checksumElement.data("filename"),
        md5sum: checksumElement.data("md5sum"),
        sha1sum: checksumElement.data("sha1sum"),
        sha256sum: checksumElement.data("sha256sum")
      }));
      $('body').addClass("o-h");
    });
  };
})(jQuery);

var determinePackageNameBasedOnOS = function () {
  var userDefinedPackageName = window.location.hash.substr(1);
  var validPackageNames = ['zip', 'windows', 'osx', 'debian', 'redhat', 'ami', 'docker'];
  if (userDefinedPackageName !== "" && validPackageNames.includes(userDefinedPackageName)) {
    return userDefinedPackageName;
  }

  var userAgent = navigator.userAgent;
  var packageName = 'zip';
  if (userAgent.indexOf("Win") !== -1) packageName = "windows";
  if (userAgent.indexOf("Mac") !== -1) packageName = "osx";
  if (userAgent.indexOf("Debian") !== -1) packageName = "debian";
  if (userAgent.indexOf("Ubuntu") !== -1) packageName = "debian";
  if (userAgent.indexOf("RedHat") !== -1) packageName = "redhat";
  if (userAgent.indexOf("CentOS") !== -1) packageName = "redhat";

  return packageName
};

var switchDownloadType = function (currentInstallerType) {
  $(".release-type input." + currentInstallerType).attr('checked', true);
};

var displayAmiDropdown = function (currentOSPackageType) {
  if (currentOSPackageType === 'ami') {
    $('.select-dropdown').each(function () {
      var $this = $(this),
        numberOfOptions = $(this).children('option').length;

      $this.addClass('select-hidden');
      $this.wrap('

');
      $this.after('

');

      var $styledSelect = $this.next('div.select-styled');
      $styledSelect.text($this.children('option').eq(0).text());

      var $list = $('
', {
        'class': 'select-options'
      }).insertAfter($styledSelect);

      for (var i = 0; i < numberOfOptions; i++) {
        $('
', {
          text: $this.children('option').eq(i).text(),
          rel: $this.children('option').eq(i).val()
        }).appendTo($list);
      }

      var $listItems = $list.children('li');

      $styledSelect.click(function (e) {
        e.stopPropagation();
        $('div.select-styled.active').not(this).each(function () {
          $(this).removeClass('active').next('ul.select-options').hide();
        });
        $(this).toggleClass('active').next('ul.select-options').toggle();
      });

      $listItems.click(function (e) {
        e.stopPropagation();
        var previous_text = $styledSelect.text();
        $styledSelect.text($(this).text()).removeClass('active');
        $this.val($(this).attr('rel'));
        $list.hide();
        var previously_selected_row = "table ." + previous_text;
        var current_selected_row = "table ." + $styledSelect.text();

        $styledSelect.closest('.table-c').find(previously_selected_row).hide();
        $styledSelect.closest('.table-c').find(current_selected_row).show();
        //console.log($this.val());
      });

      $(document).click(function () {
        $styledSelect.removeClass('active');
        $list.hide();
      });
    });

    $('.table-c').each(function () {
      $(this).find('tr:gt(1)').each(function () {
        var $this = $(this);
        $this.hide();
      });
    });
  }
};

var showHelpLinksFor = (function ($) {
  return function (packageName) {
    var installer_type_to_help_link_type = {
      'debian': 'linux',
      'redhat': 'linux',
      'windows': 'windows',
      'zip': 'zip',
      'osx': 'osx'
    };
    var template = Handlebars.compile($("#downloads-help-links").html());

    $("#help-links").html(template({
      os: installer_type_to_help_link_type[packageName]
    }));
  };
})(jQuery);

Handlebars.registerHelper('size', function (array, operator, expectedSize, options) {
  'use strict';
  if (array == null || array == undefined) {
    return options.inverse(this);
  }

  switch (operator) {
    case 'lt':
      return array.length < expectedSize ? options.fn(this) : options.inverse(this);
    case 'lte':
      return array.length <= expectedSize ? options.fn(this) : options.inverse(this);
    case 'eq':
      return array.length === expectedSize ? options.fn(this) : options.inverse(this);
    case 'gt':
      return array.length > expectedSize ? options.fn(this) : options.inverse(this);
    case 'gte':
      return array.length >= expectedSize ? options.fn(this) : options.inverse(this);
    default:
      throw "Invalid operator " + operator + ".";
      break;
  }
});

(function showPopup() {
  var access_country;
  var COUNTRY_CODES_EU = [
    "AT", "BE", "BG", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT",
    "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "GB", "US"
  ]

  $.get("https://ipinfo.io", function (response) {
    access_country = response.country
  }, "jsonp");

  if ($.inArray(access_country, COUNTRY_CODES_EU) == -1) {
    $('.banner-fixed-bottom').hide();
  }
})();<|endoftext|>


<commit_before>'use strict';

const version = 'v20160516-1';
const offlineResources = [
  '/',
  '/offline.html',
  '/offline.svg'
];

const ignoreFetch = [
  /https?:\/\/[^\/]*mixpanel[^\/]*\.com\//,
  /https?:\/\/[^\/]*mxpnl[^\/]*\.com\//,
  /https?:\/\/[^\/]*segment[^\/]*\.io\//,
  /https?:\/\/[^\/]*getclicky[^\/]*\.com\//,
  /https?:\/\/[^\/]*typekit[^\/]*\.net\//,
  /https?:\/\/[^\/]*sumome[^\/]*\.com\//,
  /https?:\/\/[^\/]*disqus[^\/]*\.com\//,
  /https?:\/\/[^\/]*google-analytics[^\/]*\.com\//,
  /https?:\/\/zenkaffe\.herokuapp\.com\//,
  /\/__rack\//,
];

//////////
// Install
//////////
function onInstall(event) {
  log('install event in progress.');

  event.waitUntil(cacheOfflineResources());
}

function cacheOfflineResources() {
  return caches
    .open(cacheKey('offline'))
    .then((cache) => {
      return cache.addAll(offlineResources);
    })
    .then(() => {
      log('installation complete!');
    });
}

////////
// Fetch
////////
function onFetch(event) {
  const request = event.request;

  if (shouldAlwaysFetch(request)) {
    console.log('shouldAlwaysFetch', request.url)
    return;
  }

  if (shouldFetchAndCache(request)) {
    console.log('shouldFetchAndCache', request.url)
    event.respondWith(networkedOrCached(request));
    return;
  }

  console.log('cachedOrNetworked', request.url)
  event.respondWith(cachedOrNetworked(request));
}

function networkedOrCached(request) {
  return networkedAndCache(request)
    .catch(() => { return cachedOrOffline(request) });
}

// Stash response in cache as side-effect of network request
function networkedAndCache(request) {
  return fetch(request)
    .then((response) => {
      var copy = response.clone();
      caches.open(cacheKey('resources'))
        .then((cache) => {
          cache.put(request, copy);
        });

      log("(network: cache write)", request.method, request.url);
      return response;
    });
}

function cachedOrNetworked(request) {
  return caches.match(request)
    .then((response) => {
      log(response ? '(cached)' : '(network: cache miss)', request.method, request.url);
      return response ||
        networkedAndCache(request)
          .catch(() => { return offlineResponse(request) });
    });
}

function networkedOrOffline(request) {
  return fetch(request)
    .then((response) => {
      log('(network)', request.method, request.url);
      return response;
    })
    .catch(() => {
      return offlineResponse(request);
    });
}

function cachedOrOffline(request) {
  return caches
    .match(request)
    .then((response) => {
      return response || offlineResponse(request);
    });
}

function offlineResponse(request) {
  log('(offline)', request.method, request.url);

  let url = new URL(request.url);
  let path = url.pathname;

  if (path.endsWith(".html") || path.endsWith("/") || !path.endsWith(".js")) {
    return caches.match('/offline.html');
  } else {
    return new Response('', { status: 503, statusText: 'Service Unavailable' });;
  }
}

///////////
// Activate
///////////
function onActivate(event) {
  log('activate event in progress.');
  event.waitUntil(removeOldCache());
}

function removeOldCache() {
  return caches
    .keys()
    .then((keys) => {
      return Promise.all( // We return a promise that settles when all outdated caches are deleted.
        keys
         .filter((key) => {
           return !key.startsWith(version); // Filter by keys that don't start with the latest version prefix.
         })
         .map((key) => {
           return caches.delete(key); // Return a promise that's fulfilled when each outdated cache is deleted.
         })
      );
    })
    .then(() => {
      log('removeOldCache completed.');
    });
}

function cacheKey() {
  return [version, ...arguments].join(':');
}

function log() {
  if (developmentMode()) {
    console.log("SW:", ...arguments);
  }
}

function shouldAlwaysFetch(request) {
  return __DEVELOPMENT__ ||
    request.method !== 'GET' ||
      ignoreFetch.some(regex => request.url.match(regex));
}

function shouldFetchAndCache(request) {
  return ~request.headers.get('Accept').indexOf('text/html');
}

function developmentMode() {
  return __DEVELOPMENT__ || __DEBUG__;
}

log("Hello from ServiceWorker land!", version);

self.addEventListener('install', onInstall);

self.addEventListener('fetch', onFetch);

self.addEventListener("activate", onActivate);
<commit_msg>Advance service worker cache version<commit_after>'use strict';

const version = 'v20160917-1';
const offlineResources = [
  '/',
  '/offline.html',
  '/offline.svg'
];

const ignoreFetch = [
  /https?:\/\/[^\/]*mixpanel[^\/]*\.com\//,
  /https?:\/\/[^\/]*mxpnl[^\/]*\.com\//,
  /https?:\/\/[^\/]*segment[^\/]*\.io\//,
  /https?:\/\/[^\/]*getclicky[^\/]*\.com\//,
  /https?:\/\/[^\/]*typekit[^\/]*\.net\//,
  /https?:\/\/[^\/]*sumome[^\/]*\.com\//,
  /https?:\/\/[^\/]*disqus[^\/]*\.com\//,
  /https?:\/\/[^\/]*google-analytics[^\/]*\.com\//,
  /https?:\/\/zenkaffe\.herokuapp\.com\//,
  /\/__rack\//,
];

//////////
// Install
//////////
function onInstall(event) {
  log('install event in progress.');

  event.waitUntil(cacheOfflineResources());
}

function cacheOfflineResources() {
  return caches
    .open(cacheKey('offline'))
    .then((cache) => {
      return cache.addAll(offlineResources);
    })
    .then(() => {
      log('installation complete!');
    });
}

////////
// Fetch
////////
function onFetch(event) {
  const request = event.request;

  if (shouldAlwaysFetch(request)) {
    console.log('shouldAlwaysFetch', request.url)
    return;
  }

  if (shouldFetchAndCache(request)) {
    console.log('shouldFetchAndCache', request.url)
    event.respondWith(networkedOrCached(request));
    return;
  }

  console.log('cachedOrNetworked', request.url)
  event.respondWith(cachedOrNetworked(request));
}

function networkedOrCached(request) {
  return networkedAndCache(request)
    .catch(() => { return cachedOrOffline(request) });
}

// Stash response in cache as side-effect of network request
function networkedAndCache(request) {
  return fetch(request)
    .then((response) => {
      var copy = response.clone();
      caches.open(cacheKey('resources'))
        .then((cache) => {
          cache.put(request, copy);
        });

      log("(network: cache write)", request.method, request.url);
      return response;
    });
}

function cachedOrNetworked(request) {
  return caches.match(request)
    .then((response) => {
      log(response ? '(cached)' : '(network: cache miss)', request.method, request.url);
      return response ||
        networkedAndCache(request)
          .catch(() => { return offlineResponse(request) });
    });
}

function networkedOrOffline(request) {
  return fetch(request)
    .then((response) => {
      log('(network)', request.method, request.url);
      return response;
    })
    .catch(() => {
      return offlineResponse(request);
    });
}

function cachedOrOffline(request) {
  return caches
    .match(request)
    .then((response) => {
      return response || offlineResponse(request);
    });
}

function offlineResponse(request) {
  log('(offline)', request.method, request.url);

  let url = new URL(request.url);
  let path = url.pathname;

  if (path.endsWith(".html") || path.endsWith("/") || !path.endsWith(".js")) {
    return caches.match('/offline.html');
  } else {
    return new Response('', { status: 503, statusText: 'Service Unavailable' });;
  }
}

///////////
// Activate
///////////
function onActivate(event) {
  log('activate event in progress.');
  event.waitUntil(removeOldCache());
}

function removeOldCache() {
  return caches
    .keys()
    .then((keys) => {
      return Promise.all( // We return a promise that settles when all outdated caches are deleted.
        keys
         .filter((key) => {
           return !key.startsWith(version); // Filter by keys that don't start with the latest version prefix.
         })
         .map((key) => {
           return caches.delete(key); // Return a promise that's fulfilled when each outdated cache is deleted.
         })
      );
    })
    .then(() => {
      log('removeOldCache completed.');
    });
}

function cacheKey() {
  return [version, ...arguments].join(':');
}

function log() {
  if (developmentMode()) {
    console.log("SW:", ...arguments);
  }
}

function shouldAlwaysFetch(request) {
  return __DEVELOPMENT__ ||
    request.method !== 'GET' ||
      ignoreFetch.some(regex => request.url.match(regex));
}

function shouldFetchAndCache(request) {
  return ~request.headers.get('Accept').indexOf('text/html');
}

function developmentMode() {
  return __DEVELOPMENT__ || __DEBUG__;
}

log("Hello from ServiceWorker land!", version);

self.addEventListener('install', onInstall);

self.addEventListener('fetch', onFetch);

self.addEventListener("activate", onActivate);
<|endoftext|>


<commit_before>/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2017 Zenesis Ltd

   License:
     MIT: https://opensource.org/licenses/MIT
     See the LICENSE file in the project's top-level directory for details.

   Authors:
     * John Spackman (john.spackman@zenesis.com, @johnspackman)

************************************************************************ */

const path = require("upath");
const process = require("process");
const express = require("express");
const http = require("http");
const fs = qx.tool.utils.Promisify.fs;

require("app-module-path").addPath(process.cwd() + "/node_modules");

require("./Compile");

/**
 * Handles compilation of the project by qxcompiler
 */
qx.Class.define("qx.tool.cli.commands.Serve", {
  extend: qx.tool.cli.commands.Compile,

  statics: {

    YARGS_BUILDER: {
      "listen-port": {
        alias: "p",
        describe: "The port for the web browser to listen on",
        type: "number",
        default: 8080
      },
      "show-startpage": {
        alias: "S",
        describe: "Show the startpage with the list of applications and additional information",
        type: "boolean",
        default: false
      },
      "rebuild-startpage": {
        alias: "R",
        describe: "Rebuild the startpage with the list of applications and additional information",
        type: "boolean",
        default: false
      }
    },

    getYargsCommand: function() {
      return {
        command   : "serve [configFile]",
        describe  : "runs a webserver to run the current application with continuous compilation, using compile.json",
        builder   : Object.assign(qx.tool.cli.commands.Compile.YARGS_BUILDER, qx.tool.cli.commands.Serve.YARGS_BUILDER),
        handler: function(argv) {
          return new qx.tool.cli.commands.Serve(argv)
            .process()
            .catch(e => {
              qx.tool.compiler.Console.error(e.stack || e.message);
              process.exit(1);
            });
        }
      };
    }
  },

  members: {
    /*
     * @Override
     */
    process: async function() {
      this.argv.watch = true;
      this.argv["machine-readable"] = false;
      this.argv["feedback"] = false;
      await this.base(arguments);
      // build website if it hasn't been built yet.
      const website = new qx.tool.utils.Website();
      if (!await fs.existsAsync(website.getTargetDir()) || this.argv.rebuildStartpage) {
        qx.tool.compiler.Console.info(">>> Building startpage...");
        await website.generateSite();
        await website.compileScss();
      }
      await this.runWebServer();
    },

    /**
     *
     * @returns
     */
    /* @ignore qx.tool.$$resourceDir */

    runWebServer: async function() {
      let makers = this.getMakers().filter(maker => maker.getApplications().some(app => app.isBrowserApp()));
      let apps = [];
      makers.forEach(maker => {
        maker.getApplications().forEach(app => {
          if (app.isBrowserApp()) {
            apps.push(app);
          }
        });
      });
      var config = this._getConfig();

      const app = express();
      const website = new qx.tool.utils.Website();
      if (((apps.length === 1) || apps[0].getWriteIndexHtmlToRoot()) && (this.argv.showStartpage === false)) {
        let target = makers[0].getTarget();
        app.use("/", express.static(target.getOutputDir()));
      } else {
        let s = await this.getAppQxPath();
        if (!await fs.existsAsync(path.join(s, "docs"))) {
          s = path.dirname(s);
        }
        app.use("/docs", express.static(path.join(s, "docs")));
        app.use("/apps", express.static(path.join(s, "apps")));
        app.use("/", express.static(website.getTargetDir()));
        var appsData = [];
        makers.forEach(maker => {
          let target = maker.getTarget();
          app.use("/" + target.getOutputDir(), express.static(target.getOutputDir()));
          appsData.push({
            target: {
              type: target.getType(),
              outputDir: "/" + target.getOutputDir()
            },
            apps: maker.getApplications()
              .filter(app => app.isBrowserApp())
              .map(app => ({
                name: app.getName(),
                type: app.getType(),
                title: app.getTitle() || app.getName(),
                outputPath: target.getProjectDir(app) // no trailing slash or link will break
              }))
          });
        });
        app.get("/serve.api/apps.json", (req, res) => {
          res.set("Content-Type", "application/json");
          res.send(JSON.stringify(appsData, null, 2));
        });
      }
      this.addListenerOnce("made", e => {
        let server = http.createServer(app);
        server.on("error", e => {
          if (e.code === "EADDRINUSE") {
            qx.tool.compiler.Console.print("qx.tool.cli.serve.webAddrInUse", config.serve.listenPort);
            process.exit(-1);
          } else {
            qx.tool.compiler.Console.log("Error when starting web server: " + e);
          }
        });
        server.listen(config.serve.listenPort, () =>
          qx.tool.compiler.Console.print("qx.tool.cli.serve.webStarted", "http://localhost:" + config.serve.listenPort));
      });
    }
  },

  defer: function(statics) {
    qx.tool.compiler.Console.addMessageIds({
      "qx.tool.cli.serve.webStarted": "Web server started, please browse to %1",
      "qx.tool.cli.serve.webAddrInUse": "Web server cannot start because port %1 is already in use"
    });
  }
});

<commit_msg>rework detection of default app<commit_after>/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2017 Zenesis Ltd

   License:
     MIT: https://opensource.org/licenses/MIT
     See the LICENSE file in the project's top-level directory for details.

   Authors:
     * John Spackman (john.spackman@zenesis.com, @johnspackman)

************************************************************************ */

const path = require("upath");
const process = require("process");
const express = require("express");
const http = require("http");
const fs = qx.tool.utils.Promisify.fs;

require("app-module-path").addPath(process.cwd() + "/node_modules");

require("./Compile");

/**
 * Handles compilation of the project by qxcompiler
 */
qx.Class.define("qx.tool.cli.commands.Serve", {
  extend: qx.tool.cli.commands.Compile,

  statics: {

    YARGS_BUILDER: {
      "listen-port": {
        alias: "p",
        describe: "The port for the web browser to listen on",
        type: "number",
        default: 8080
      },
      "show-startpage": {
        alias: "S",
        describe: "Show the startpage with the list of applications and additional information",
        type: "boolean",
        default: false
      },
      "rebuild-startpage": {
        alias: "R",
        describe: "Rebuild the startpage with the list of applications and additional information",
        type: "boolean",
        default: false
      }
    },

    getYargsCommand: function() {
      return {
        command   : "serve [configFile]",
        describe  : "runs a webserver to run the current application with continuous compilation, using compile.json",
        builder   : Object.assign(qx.tool.cli.commands.Compile.YARGS_BUILDER, qx.tool.cli.commands.Serve.YARGS_BUILDER),
        handler: function(argv) {
          return new qx.tool.cli.commands.Serve(argv)
            .process()
            .catch(e => {
              qx.tool.compiler.Console.error(e.stack || e.message);
              process.exit(1);
            });
        }
      };
    }
  },

  members: {
    /*
     * @Override
     */
    process: async function() {
      this.argv.watch = true;
      this.argv["machine-readable"] = false;
      this.argv["feedback"] = false;
      await this.base(arguments);
      // build website if it hasn't been built yet.
      const website = new qx.tool.utils.Website();
      if (!await fs.existsAsync(website.getTargetDir()) || this.argv.rebuildStartpage) {
        qx.tool.compiler.Console.info(">>> Building startpage...");
        await website.generateSite();
        await website.compileScss();
      }
      await this.runWebServer();
    },

    /**
     *
     * @returns
     */
    /* @ignore qx.tool.$$resourceDir */

    runWebServer: async function() {
      let makers = this.getMakers().filter(maker => maker.getApplications().some(app => app.isBrowserApp()));
      let apps = [];
      let defaultMaker = null;
      let firstMaker = null;
      makers.forEach(maker => {
        maker.getApplications().forEach(app => {
          if (app.isBrowserApp()) {
            apps.push(app);
            if (firstMaker === null) {
              firstMaker = maker;
            }
            if ((defaultMaker === null) && app.getWriteIndexHtmlToRoot()) {
              defaultMaker = maker;
            }
          }
        });
      });
      if (!defaultMaker && (apps.length === 1)) {
        defaultMaker = firstMaker;
      }
      var config = this._getConfig();

      const app = express();
      const website = new qx.tool.utils.Website();
      if (defaultMaker && (this.argv.showStartpage === false)) {
        app.use("/", express.static(defaultMaker.getTarget().getOutputDir()));
      } else {
        let s = await this.getAppQxPath();
        if (!await fs.existsAsync(path.join(s, "docs"))) {
          s = path.dirname(s);
        }
        app.use("/docs", express.static(path.join(s, "docs")));
        app.use("/apps", express.static(path.join(s, "apps")));
        app.use("/", express.static(website.getTargetDir()));
        var appsData = [];
        makers.forEach(maker => {
          let target = maker.getTarget();
          app.use("/" + target.getOutputDir(), express.static(target.getOutputDir()));
          appsData.push({
            target: {
              type: target.getType(),
              outputDir: "/" + target.getOutputDir()
            },
            apps: maker.getApplications()
              .filter(app => app.isBrowserApp())
              .map(app => ({
                name: app.getName(),
                type: app.getType(),
                title: app.getTitle() || app.getName(),
                outputPath: target.getProjectDir(app) // no trailing slash or link will break
              }))
          });
        });
        app.get("/serve.api/apps.json", (req, res) => {
          res.set("Content-Type", "application/json");
          res.send(JSON.stringify(appsData, null, 2));
        });
      }
      this.addListenerOnce("made", e => {
        let server = http.createServer(app);
        server.on("error", e => {
          if (e.code === "EADDRINUSE") {
            qx.tool.compiler.Console.print("qx.tool.cli.serve.webAddrInUse", config.serve.listenPort);
            process.exit(-1);
          } else {
            qx.tool.compiler.Console.log("Error when starting web server: " + e);
          }
        });
        server.listen(config.serve.listenPort, () =>
          qx.tool.compiler.Console.print("qx.tool.cli.serve.webStarted", "http://localhost:" + config.serve.listenPort));
      });
    }
  },

  defer: function(statics) {
    qx.tool.compiler.Console.addMessageIds({
      "qx.tool.cli.serve.webStarted": "Web server started, please browse to %1",
      "qx.tool.cli.serve.webAddrInUse": "Web server cannot start because port %1 is already in use"
    });
  }
});

<|endoftext|>