<commit_before>define(["js/core/EventDispatcher", "js/lib/parser", "underscore"], function (EventDispatcher, Parser, _) {

    /**
     * Returns false if path includes function
     * @param path
     */
    var pathToString = function (path) {
        var str = [];
        for (var i = 0; i < path.length; i++) {
            var el = path[i];
            if (el.type == TYPE_VAR) {
                str.push(el.name);
            } else {
                return false;
            }
        }
        return str.join(".");
    };

    var bindingsDestroyed = 0,
        undefined;

    var Bindable;
    var Binding = EventDispatcher.inherit("js.core.Binding",
        /** @lends Binding */
        {
            defaults: {
                event: 'change',
                path: null,
                twoWay: false
            },

            ctor: function (attributes) {
                if(!Bindable){
                    try {
                        Bindable = requirejs('js/core/Bindable');
                    } catch(e) {
                        Bindable = null;
                    }
                }
                this.callBase();
                this.$targets = [];
                this.$ = attributes;
                _.defaults(this.$,this.defaults);

                this.initialize();
            },

            transform: function (val) {
                return val;
            },

            transformBack: function (val) {
                return val;
            },

            initialize: function () {
                this._checkAttributes();
                this.$parameters = [];
                this.$events = [];
                this.$subBinding = null;

                if (!this.$.rootScope) {
                    this.$.rootScope = this;
                }
                var scope = this.$.scope;
                if(_.isString(this.$.path)){
                    this.$.path = Parser.parse(this.$.path,'path');
                }
                // split up first key
                this.$.key = this.$.path[0];
                var self = this;

                if(!this.$.parent){
                    // destroy yourself on target or scope destroy
                    scope.bind('destroy', this.destroy, this);

                    this.$.root = this;
                }

                if (this.$.key.type == TYPE_FNC) {
                    var fncName = this.$.key.name, parameters = this.$.key.parameter;

                    if (_.isFunction(scope[fncName])) {
                        var fnc = scope[fncName],
                            events = [];

                        fnc._attributes = this._getOnChangeAttributesForFnc(scope, fnc);

                        if (fnc._attributes && fnc._attributes.length > 0) {
                            this.$.scope.bind("change", this._changeCallback, this);
                            this.$events.push({eventType: "change", callback: this._changeCallback});
                        }

                        fnc._events = this._getEventsForFnc(scope, fnc);
                        if (fnc._events) {
                            events = fnc._events;
                        } else {
                            events = [];
                        }

                        var event;

                        for (var i = 0; i < events.length; i++) {
                            event = events[i];
                            scope.bind(event, this._callback, this);
                            this.$events.push({eventType: event, callback: this._callback});
                        }

                        // TODO: remove this closure
                        var cb = function () {
                            self._callback();
                        };

                        var para;
                        this.$parameters = [];
                        for (var j = 0; j < parameters.length; j++) {
                            para = parameters[j];
                            // if we have an array, it's a path
                            if(para instanceof Array) {
                                para = {
                                    path: para,
                                    type: TYPE_NORMAL,
                                    parent: null
                                };
                            }
                            if(_.isObject(para)){
                                para = this.$.bindingCreator.create(para, this.$.target, cb);
                            }
                            this.$parameters.push(para);

                        }
                        this.$.fnc = fnc;
                        this.$.fnc.trigger = function () {
                            self.triggerBinding();
                        };
                    }

                } else {
                    this.$.event = "change:" + this.$.key.name;
                    this.$events.push({eventType: this.$.event, callback: this._callback});
                    // on change of this key
                    scope.bind(this.$.event, this._callback, this);
                }

                if (this.$.twoWay === true) {
                    this.$.targetEvent = 'change:' + this.$.targetKey;
                    if(this.$.path.length === 1){
                        this.$.target.bind(this.$.targetEvent, this._revCallback, this);
                    }
                }

                if (!this.$.parent) {
                    this.addTarget(this.$.target, this.$.targetKey || this.$.callback);
                }

                this._createSubBinding();
            },

            _getOnChangeAttributesForFnc: function(scope, fnc) {
                var ret = [];
                if (fnc._attributes && fnc._attributes.length > 0) {

                    for (var x = 0; x < fnc._attributes.length; x++) {
                        var attribute = fnc._attributes[x];

                        var fncExtractor = /^(.+)\(\)$/;
                        var extract = fncExtractor.exec(attribute);

                        if (extract) {
                            var extendFunction = scope[extract[1]];
                            if (extendFunction) {
                                // copy all onChangeAttributes
                                ret = ret.concat(this._getOnChangeAttributesForFnc(scope, extendFunction));
                            }
                        } else {
                            ret.push(attribute);
                        }
                    }
                }

                return ret;

            },

            _getEventsForFnc: function(scope, fnc){
                var ret = [];
                if (fnc._events && fnc._events.length > 0) {

                    for (var x = 0; x < fnc._events.length; x++) {
                        var event = fnc._events[x];

                        var fncExtractor = /^(.+)\(\)$/;
                        var extract = fncExtractor.exec(event);

                        if (extract) {
                            var extendFunction = scope[extract[1]];
                            if (extendFunction) {
                                // copy all onChangeAttributes
                                ret = ret.concat(this._getEventsForFnc(scope, extendFunction));
                            }
                        } else {
                            if(!_.contains(ret,event)){
                                ret.push(event);
                            }
                        }
                    }
                }

                return ret;

            },

            _checkAttributes: function () {
                // check infrastructur
                if (!this.$.path) {
                    throw "No path defined!";
                }

                if (!this.$.scope) {
                    throw "No scope defined!";
                }

                if (this.$.twoWay) {
                    if (!this.$.target) {
                        throw "TwoWay binding, but no target defined!";
                    }
                    if (!this.$.target instanceof Bindable) {
                        throw "Target is not a Bindable!";
                    }

                    if (!this.$.targetKey) {
                        throw "TwoWay binding, but no target key defined!";
                    }

                }

                if(!this.$.bindingCreator){
                    this.$.bindingCreator = this;
                }

                if(this.$.transform){
                    this.transform = this.$.transform;
                }

                if (this.$.transformBack) {
                    this.transformBack = this.$.transformBack;
                }
            },
            _createSubBinding: function () {
                if (this.$.path.length > 1) {
                    var nScope;
                    if (this.$.fnc) {
                        nScope = this.getValue();
                    } else {
                        nScope = this.$.scope.$[this.$.key.name];
                    }
                    // if keys are left and has value && is bindable
                    // get value for first child
                    if(nScope instanceof Bindable){
                        // init new binding, which triggers this binding
                        this.$subBinding = new Binding({scope: nScope, path: this.$.path.slice(1), target: this.$.target, targetKey: this.$.targetKey, rootScope: this.$.rootScope, callback: this.$.callback, context: this.$.context, twoWay: this.$.twoWay, transform: this.$.transform, transformBack: this.$.transformBack, bindingCreator: this.$.bindingCreator, parent: this, root: this.$.root});
                    } else if(nScope instanceof Object){
                        // we have a object which is not bindable
                        this.$jsonObject = nScope;
                    } else if(_.isString(nScope)){
                        this.$jsonObject = nScope;
                    }

                }
            },
            _revCallback: function (e) {
                if (this.$.fnc) {
                    var params = this._getFncParameters();
                    params.unshift(e.$);
                    this.$.fnc.apply(this.$.scope, params);
                } else {
                    this.$.scope.set(pathToString(this.$.path), this.transformBack.call(this.$.scope, e.$, this.$originalValue));
                }
            },
            /**
             * This method is called, when the a change event of an function binding is triggered
             *
             * @param event
             * @private
             */
            _changeCallback: function (event) {

                if (!this.$) {
                    return;
                }

                for (var i = 0; i < this.$.fnc._attributes.length; i++) {
                    if (!_.isUndefined(event.$[this.$.fnc._attributes[i]])) {
                        this._callback();
                        return;
                    }
                }
            },
            /**
             * This method is called, when the value of the current binding changes.
             * It recreates the the subBinding and triggers the binding
             * @private
             */
            _callback: function () {

                if(!this.$){
                    return;
                }

                this.invalidateValueCache();

                // remove subBindings!
                if (this.$subBinding) {
                    this.$subBinding.destroy();
                    this.$subBinding = null;
                }

                // try to create subBinding
                this._createSubBinding();
                this.triggerBinding();
            },

            /**
             * Unbinds all events and destroys subBinding...
             */
            _innerDestroy: function () {
                // binding already destroyed?
                if(!this.$){
                    return;
                }
                var e;
                for (var j = 0; j < this.$events.length; j++) {
                    e = this.$events[j];
                    this.$.scope.unbind(e.eventType, e.callback, this);
                }

                this.$.scope.unbind('destroy', this.destroy, this);

                if (this.$.twoWay === true) {
                    this.$.target.unbind(this.$.targetEvent, this._revCallback, this);
                }
                if (this.$subBinding) {
                    this.$subBinding.destroy();
                    this.$subBinding = null;
                }

                // destroy parameter bindings
                for (var i = 0; i < this.$parameters.length; i++) {
                    var par = this.$parameters[i];
                    if (par instanceof Binding) {
                        par.destroy();
                    }
                }
                this.$parameters = null;
                this.$.scope = this.$.target = this.$.callback = null;
                this.$ = null;
                this.$targets = null;
                this.callBase();

                bindingsDestroyed++;
                if(bindingsDestroyed === 500){
                    if (typeof(CollectGarbage) == "function") {
                        CollectGarbage();
                    }
                    bindingsDestroyed = 0;
                }
            },
            /**
             * Returns an array with values of all function parameters
             * @return {Array}
             * @private
             */
            _getFncParameters: function () {
                var parameters = [];
                for (var i = 0; i < this.$parameters.length; i++) {
                    var para = this.$parameters[i];
                    if (para instanceof Binding) {
                        para = para.getValue();
                    }
                    parameters.push(para);
                }
                return parameters;
            },
            /**
             * Returns the transformed value of the binding or null, if the binding path is not present
             * @return {*}
             */
            getValue: function () {
                if (this.$subBinding) {
                    this.$subBinding.invalidateValueCache();
                    return this.$subBinding.getValue();
                } else {
                    if(this.$cachedValue !== undefined){
                        return this.$cachedValue;
                    }
                    this.$originalValue = null;
                    if (this.$.fnc && !this.$jsonObject) {
                        this.$originalValue = this.$.fnc.apply(this.$.scope, this._getFncParameters());
                    } else if (this.$.path.length === 1) {
                        this.$originalValue = this.$.scope.get(this.$.key.name);
                    } else if(this.$jsonObject) {
                        this.$originalValue = this.$.scope.get(this.$jsonObject, this.$.path.slice(1));
                    }
                    this.$cachedValue = this.transform.call(this.$.scope, this.$originalValue);
                    return this.$cachedValue;
                }

            },

            invalidateValueCache: function(){
                this.$cachedValue = undefined;
            },

            /**
             * Returns the value in the context of the surrounding bindings
             * @return {*}
             */
            getContextValue: function () {
                if (this.$.context && this.$.context.length > 1) {
                    return Binding.contextToString(this.$.context);
                } else {
                    return this.getValue();
                }
            },
            /**
             * This method triggers the binding and syncs the target with the scope
             */
            triggerBinding: function () {
                // get value
                var val = this.getContextValue();

                var target,
                    targets = this.$.root.getTargets();
                if(targets){
                    for(var i = 0; i < targets.length; i++){
                        target = targets[i];
                        if(target.key instanceof Function){
                            target.key.call(target.scope, val, this);
                        } else {
                            target.scope.set(target.key, val);
                        }
                    }
                }

            },
            toString: function () {
                return this.getValue();
            },

            getTargets: function(){
                return this.$targets;
            },

            /***
             *
             * @param {Bindable} targetScope
             * @param {String|Function} key
             */
            addTarget: function(targetScope, key){
                targetScope.bind('destroy', function(){
                    this.removeTarget(targetScope, key);
                },this);

                this.$targets.push({
                    scope: targetScope,
                    key: key
                });
            },
            /***
             *
             * @param {Bindable} targetScope
             * @param {String|Function} key
             */
            removeTarget: function(targetScope, key){
                var target;
                if(this.$targets){
                    for (var i = 0; i < this.$targets.length; i++) {
                        target = this.$targets[i];
                        if (target.key === key && target.scope === targetScope) {
                            this.$targets.splice(i,1);
                            break;
                        }
                    }
                    if(this.$targets.length === 0){
                        this.destroy();
                    }
                }
            },

            create: function(bindingDef, target, callback){
                var options = {
                    scope: this.$.scope,
                    target: target,
                    callback: callback,
                    path: bindingDef.path,
                    parent: bindingDef.parent,
                    twoWay : bindingDef.type === TYPE_TWOWAY, bindingCreator: this.$.bindingCreator};

                var fncEl;
                var fncScope;
                if(bindingDef.transform) {
                    fncEl = bindingDef.transform.pop();
                    fncScope = this.get(bindingDef.transform);
                    if(fncScope){
                        options.transform = fncScope[fncEl.name];
                    }
                }
                if(bindingDef.transformBack){
                    fncEl = bindingDef.transformBack.pop();
                    fncScope = this.get(bindingDef.transform);
                    if (fncScope) {
                        options.transformBack = fncScope[fncEl.name];
                    }
                }
                return new Binding(options);
            }
        });

    var TYPE_FNC = Binding.TYPE_FNC = "fnc";
    var TYPE_VAR = Binding.TYPE_VAR = "var";
    var TYPE_NORMAL = Binding.TYPE_NORMAL ="normal";
    var TYPE_STATIC = Binding.TYPE_STATIC ="static";
    var TYPE_TWOWAY = Binding.TYPE_TWOWAY ="twoWay";

    Binding.contextToString = function (context) {
        var str = "", el;
        for (var i = 0; i < context.length; i++) {
            el = context[i];
            if (el instanceof Binding) {
                el = el.getValue();
            }
            if (el !== null && typeof(el) !== "undefined") {
                str += el;
            }
        }
        return str;
    };

    return Binding;
});<commit_msg>fixed type annotation of bindable<commit_after>define(["js/core/EventDispatcher", "js/lib/parser", "underscore"], function (EventDispatcher, Parser, _) {

    /**
     * Returns false if path includes function
     * @param path
     */
    var pathToString = function (path) {
        var str = [];
        for (var i = 0; i < path.length; i++) {
            var el = path[i];
            if (el.type == TYPE_VAR) {
                str.push(el.name);
            } else {
                return false;
            }
        }
        return str.join(".");
    };

    var bindingsDestroyed = 0,
        undefined;

    var Bindable;
    var Binding = EventDispatcher.inherit("js.core.Binding",
        /** @lends Binding */
        {
            defaults: {
                event: 'change',
                path: null,
                twoWay: false
            },

            ctor: function (attributes) {
                if(!Bindable){
                    try {
                        Bindable = requirejs('js/core/Bindable');
                    } catch(e) {
                        Bindable = null;
                    }
                }
                this.callBase();
                this.$targets = [];
                this.$ = attributes;
                _.defaults(this.$,this.defaults);

                this.initialize();
            },

            transform: function (val) {
                return val;
            },

            transformBack: function (val) {
                return val;
            },

            initialize: function () {
                this._checkAttributes();
                this.$parameters = [];
                this.$events = [];
                this.$subBinding = null;

                if (!this.$.rootScope) {
                    this.$.rootScope = this;
                }
                var scope = this.$.scope;
                if(_.isString(this.$.path)){
                    this.$.path = Parser.parse(this.$.path,'path');
                }
                // split up first key
                this.$.key = this.$.path[0];
                var self = this;

                if(!this.$.parent){
                    // destroy yourself on target or scope destroy
                    scope.bind('destroy', this.destroy, this);

                    this.$.root = this;
                }

                if (this.$.key.type == TYPE_FNC) {
                    var fncName = this.$.key.name, parameters = this.$.key.parameter;

                    if (_.isFunction(scope[fncName])) {
                        var fnc = scope[fncName],
                            events = [];

                        fnc._attributes = this._getOnChangeAttributesForFnc(scope, fnc);

                        if (fnc._attributes && fnc._attributes.length > 0) {
                            this.$.scope.bind("change", this._changeCallback, this);
                            this.$events.push({eventType: "change", callback: this._changeCallback});
                        }

                        fnc._events = this._getEventsForFnc(scope, fnc);
                        if (fnc._events) {
                            events = fnc._events;
                        } else {
                            events = [];
                        }

                        var event;

                        for (var i = 0; i < events.length; i++) {
                            event = events[i];
                            scope.bind(event, this._callback, this);
                            this.$events.push({eventType: event, callback: this._callback});
                        }

                        // TODO: remove this closure
                        var cb = function () {
                            self._callback();
                        };

                        var para;
                        this.$parameters = [];
                        for (var j = 0; j < parameters.length; j++) {
                            para = parameters[j];
                            // if we have an array, it's a path
                            if(para instanceof Array) {
                                para = {
                                    path: para,
                                    type: TYPE_NORMAL,
                                    parent: null
                                };
                            }
                            if(_.isObject(para)){
                                para = this.$.bindingCreator.create(para, this.$.target, cb);
                            }
                            this.$parameters.push(para);

                        }
                        this.$.fnc = fnc;
                        this.$.fnc.trigger = function () {
                            self.triggerBinding();
                        };
                    }

                } else {
                    this.$.event = "change:" + this.$.key.name;
                    this.$events.push({eventType: this.$.event, callback: this._callback});
                    // on change of this key
                    scope.bind(this.$.event, this._callback, this);
                }

                if (this.$.twoWay === true) {
                    this.$.targetEvent = 'change:' + this.$.targetKey;
                    if(this.$.path.length === 1){
                        this.$.target.bind(this.$.targetEvent, this._revCallback, this);
                    }
                }

                if (!this.$.parent) {
                    this.addTarget(this.$.target, this.$.targetKey || this.$.callback);
                }

                this._createSubBinding();
            },

            _getOnChangeAttributesForFnc: function(scope, fnc) {
                var ret = [];
                if (fnc._attributes && fnc._attributes.length > 0) {

                    for (var x = 0; x < fnc._attributes.length; x++) {
                        var attribute = fnc._attributes[x];

                        var fncExtractor = /^(.+)\(\)$/;
                        var extract = fncExtractor.exec(attribute);

                        if (extract) {
                            var extendFunction = scope[extract[1]];
                            if (extendFunction) {
                                // copy all onChangeAttributes
                                ret = ret.concat(this._getOnChangeAttributesForFnc(scope, extendFunction));
                            }
                        } else {
                            ret.push(attribute);
                        }
                    }
                }

                return ret;

            },

            _getEventsForFnc: function(scope, fnc){
                var ret = [];
                if (fnc._events && fnc._events.length > 0) {

                    for (var x = 0; x < fnc._events.length; x++) {
                        var event = fnc._events[x];

                        var fncExtractor = /^(.+)\(\)$/;
                        var extract = fncExtractor.exec(event);

                        if (extract) {
                            var extendFunction = scope[extract[1]];
                            if (extendFunction) {
                                // copy all onChangeAttributes
                                ret = ret.concat(this._getEventsForFnc(scope, extendFunction));
                            }
                        } else {
                            if(!_.contains(ret,event)){
                                ret.push(event);
                            }
                        }
                    }
                }

                return ret;

            },

            _checkAttributes: function () {
                // check infrastructur
                if (!this.$.path) {
                    throw "No path defined!";
                }

                if (!this.$.scope) {
                    throw "No scope defined!";
                }

                if (this.$.twoWay) {
                    if (!this.$.target) {
                        throw "TwoWay binding, but no target defined!";
                    }
                    if (!this.$.target instanceof Bindable) {
                        throw "Target is not a Bindable!";
                    }

                    if (!this.$.targetKey) {
                        throw "TwoWay binding, but no target key defined!";
                    }

                }

                if(!this.$.bindingCreator){
                    this.$.bindingCreator = this;
                }

                if(this.$.transform){
                    this.transform = this.$.transform;
                }

                if (this.$.transformBack) {
                    this.transformBack = this.$.transformBack;
                }
            },
            _createSubBinding: function () {
                if (this.$.path.length > 1) {
                    var nScope;
                    if (this.$.fnc) {
                        nScope = this.getValue();
                    } else {
                        nScope = this.$.scope.$[this.$.key.name];
                    }
                    // if keys are left and has value && is bindable
                    // get value for first child
                    if(nScope instanceof Bindable){
                        // init new binding, which triggers this binding
                        this.$subBinding = new Binding({scope: nScope, path: this.$.path.slice(1), target: this.$.target, targetKey: this.$.targetKey, rootScope: this.$.rootScope, callback: this.$.callback, context: this.$.context, twoWay: this.$.twoWay, transform: this.$.transform, transformBack: this.$.transformBack, bindingCreator: this.$.bindingCreator, parent: this, root: this.$.root});
                    } else if(nScope instanceof Object){
                        // we have a object which is not bindable
                        this.$jsonObject = nScope;
                    } else if(_.isString(nScope)){
                        this.$jsonObject = nScope;
                    }

                }
            },
            _revCallback: function (e) {
                if (this.$.fnc) {
                    var params = this._getFncParameters();
                    params.unshift(e.$);
                    this.$.fnc.apply(this.$.scope, params);
                } else {
                    this.$.scope.set(pathToString(this.$.path), this.transformBack.call(this.$.scope, e.$, this.$originalValue));
                }
            },
            /**
             * This method is called, when the a change event of an function binding is triggered
             *
             * @param event
             * @private
             */
            _changeCallback: function (event) {

                if (!this.$) {
                    return;
                }

                for (var i = 0; i < this.$.fnc._attributes.length; i++) {
                    if (!_.isUndefined(event.$[this.$.fnc._attributes[i]])) {
                        this._callback();
                        return;
                    }
                }
            },
            /**
             * This method is called, when the value of the current binding changes.
             * It recreates the the subBinding and triggers the binding
             * @private
             */
            _callback: function () {

                if(!this.$){
                    return;
                }

                this.invalidateValueCache();

                // remove subBindings!
                if (this.$subBinding) {
                    this.$subBinding.destroy();
                    this.$subBinding = null;
                }

                // try to create subBinding
                this._createSubBinding();
                this.triggerBinding();
            },

            /**
             * Unbinds all events and destroys subBinding...
             */
            _innerDestroy: function () {
                // binding already destroyed?
                if(!this.$){
                    return;
                }
                var e;
                for (var j = 0; j < this.$events.length; j++) {
                    e = this.$events[j];
                    this.$.scope.unbind(e.eventType, e.callback, this);
                }

                this.$.scope.unbind('destroy', this.destroy, this);

                if (this.$.twoWay === true) {
                    this.$.target.unbind(this.$.targetEvent, this._revCallback, this);
                }
                if (this.$subBinding) {
                    this.$subBinding.destroy();
                    this.$subBinding = null;
                }

                // destroy parameter bindings
                for (var i = 0; i < this.$parameters.length; i++) {
                    var par = this.$parameters[i];
                    if (par instanceof Binding) {
                        par.destroy();
                    }
                }
                this.$parameters = null;
                this.$.scope = this.$.target = this.$.callback = null;
                this.$ = null;
                this.$targets = null;
                this.callBase();

                bindingsDestroyed++;
                if(bindingsDestroyed === 500){
                    if (typeof(CollectGarbage) == "function") {
                        CollectGarbage();
                    }
                    bindingsDestroyed = 0;
                }
            },
            /**
             * Returns an array with values of all function parameters
             * @return {Array}
             * @private
             */
            _getFncParameters: function () {
                var parameters = [];
                for (var i = 0; i < this.$parameters.length; i++) {
                    var para = this.$parameters[i];
                    if (para instanceof Binding) {
                        para = para.getValue();
                    }
                    parameters.push(para);
                }
                return parameters;
            },
            /**
             * Returns the transformed value of the binding or null, if the binding path is not present
             * @return {*}
             */
            getValue: function () {
                if (this.$subBinding) {
                    this.$subBinding.invalidateValueCache();
                    return this.$subBinding.getValue();
                } else {
                    if(this.$cachedValue !== undefined){
                        return this.$cachedValue;
                    }
                    this.$originalValue = null;
                    if (this.$.fnc && !this.$jsonObject) {
                        this.$originalValue = this.$.fnc.apply(this.$.scope, this._getFncParameters());
                    } else if (this.$.path.length === 1) {
                        this.$originalValue = this.$.scope.get(this.$.key.name);
                    } else if(this.$jsonObject) {
                        this.$originalValue = this.$.scope.get(this.$jsonObject, this.$.path.slice(1));
                    }
                    this.$cachedValue = this.transform.call(this.$.scope, this.$originalValue);
                    return this.$cachedValue;
                }

            },

            invalidateValueCache: function(){
                this.$cachedValue = undefined;
            },

            /**
             * Returns the value in the context of the surrounding bindings
             * @return {*}
             */
            getContextValue: function () {
                if (this.$.context && this.$.context.length > 1) {
                    return Binding.contextToString(this.$.context);
                } else {
                    return this.getValue();
                }
            },
            /**
             * This method triggers the binding and syncs the target with the scope
             */
            triggerBinding: function () {
                // get value
                var val = this.getContextValue();

                var target,
                    targets = this.$.root.getTargets();
                if(targets){
                    for(var i = 0; i < targets.length; i++){
                        target = targets[i];
                        if(target.key instanceof Function){
                            target.key.call(target.scope, val, this);
                        } else {
                            target.scope.set(target.key, val);
                        }
                    }
                }

            },
            toString: function () {
                return this.getValue();
            },

            getTargets: function(){
                return this.$targets;
            },

            /***
             *
             * @param {js.core.Bindable} targetScope
             * @param {String|Function} key
             */
            addTarget: function(targetScope, key){
                targetScope.bind('destroy', function(){
                    this.removeTarget(targetScope, key);
                },this);

                this.$targets.push({
                    scope: targetScope,
                    key: key
                });
            },
            /***
             *
             * @param {js.core.Bindable} targetScope
             * @param {String|Function} key
             */
            removeTarget: function(targetScope, key){
                var target;
                if(this.$targets){
                    for (var i = 0; i < this.$targets.length; i++) {
                        target = this.$targets[i];
                        if (target.key === key && target.scope === targetScope) {
                            this.$targets.splice(i,1);
                            break;
                        }
                    }
                    if(this.$targets.length === 0){
                        this.destroy();
                    }
                }
            },

            create: function(bindingDef, target, callback){
                var options = {
                    scope: this.$.scope,
                    target: target,
                    callback: callback,
                    path: bindingDef.path,
                    parent: bindingDef.parent,
                    twoWay : bindingDef.type === TYPE_TWOWAY, bindingCreator: this.$.bindingCreator};

                var fncEl;
                var fncScope;
                if(bindingDef.transform) {
                    fncEl = bindingDef.transform.pop();
                    fncScope = this.get(bindingDef.transform);
                    if(fncScope){
                        options.transform = fncScope[fncEl.name];
                    }
                }
                if(bindingDef.transformBack){
                    fncEl = bindingDef.transformBack.pop();
                    fncScope = this.get(bindingDef.transform);
                    if (fncScope) {
                        options.transformBack = fncScope[fncEl.name];
                    }
                }
                return new Binding(options);
            }
        });

    var TYPE_FNC = Binding.TYPE_FNC = "fnc";
    var TYPE_VAR = Binding.TYPE_VAR = "var";
    var TYPE_NORMAL = Binding.TYPE_NORMAL ="normal";
    var TYPE_STATIC = Binding.TYPE_STATIC ="static";
    var TYPE_TWOWAY = Binding.TYPE_TWOWAY ="twoWay";

    Binding.contextToString = function (context) {
        var str = "", el;
        for (var i = 0; i < context.length; i++) {
            el = context[i];
            if (el instanceof Binding) {
                el = el.getValue();
            }
            if (el !== null && typeof(el) !== "undefined") {
                str += el;
            }
        }
        return str;
    };

    return Binding;
});<|endoftext|>


<commit_before>define(["js/core/EventDispatcher", "js/lib/parser", "underscore"], function (EventDispatcher, Parser, _) {

    /**
     * Returns false if path includes function
     * @param path
     */
    var pathToString = function (path) {
        var str = [];
        for (var i = 0; i < path.length; i++) {
            var el = path[i];
            if (el.type == TYPE_VAR) {
                str.push(el.name);
            } else {
                return false;
            }
        }
        return str.join(".");
    };
    var Bindable;
    var Binding = EventDispatcher.inherit("js.core.Binding",
        /** @lends Binding */
        {
            defaults: {
                event: 'change',
                path: null,
                twoWay: false
            },

            ctor: function (attributes) {
                if(!Bindable){
                    try {
                        Bindable = requirejs('js/core/Bindable');
                    } catch(e) {
                        Bindable = null;
                    }
                }
                this.callBase();

                this.$ = attributes;
                _.defaults(this.$,this.defaults);

                this.initialize();
            },

            transform: function (val) {
                return val;
            },

            transformBack: function (val) {
                return val;
            },

            initialize: function () {
                this._checkAttributes();
                this.$parameters = [];
                this.$events = [];
                this.$subBinding = null;

                if (!this.$.rootScope) {
                    this.$.rootScope = this;
                }
                var scope = this.$.scope;
                if(_.isString(this.$.path)){
                    this.$.path = Parser.parse(this.$.path,'path');
                }
                // split up first key
                this.$.key = this.$.path[0];
                var self = this;

                if (this.$.key.type == TYPE_FNC) {
                    var fncName = this.$.key.name;
                    this.$parameters = this.$.key.parameter;

                    if (_.isFunction(scope[fncName])) {
                        var fnc = scope[fncName];
                        var events = [];
                        if (fnc._attributes && fnc._attributes.length > 0) {
                            this.$.scope.bind("change", this._changeCallback, this);
                            this.$events.push({eventType: "change", callback: this._changeCallback});
                        } else {
                            if (fnc._events) {
                                events = fnc._events;
                            } else {
                                events = [];
                            }

                            var event, path;
                            for (var i = 0; i < events.length; i++) {
                                event = events[i];
                                scope.bind(event, this._callback, this);
                                this.$events.push({eventType: event, callback: this._callback});
                            }
                        }

                        var cb = function () {
                            self.trigger();
                        };

                        var para;
                        for (var j = 0; j < this.$parameters.length; j++) {
                            para = this.$parameters[j];
                            if (_.isObject(para)) {
                                this.$parameters[j] = this.$.bindingCreator.create(para, this.$.target, cb);
                            }

                        }
                        this.$.fnc = fnc;
                        this.$.fnc.trigger = function () {
                            self.trigger();
                        };
                    }

                } else {
                    this.$.event = "change:" + this.$.key.name;
                    this.$events.push({eventType: this.$.event, callback: this._callback});
                    // on change of this key
                    scope.bind(this.$.event, this._callback, this);
                }

                if (this.$.twoWay === true && this.$.path.length === 1) {
                    this.$.targetEvent = 'change:' + this.$.targetKey;

                    this.$.target.bind(this.$.targetEvent, this._revCallback, this);
                }

                this._createSubBinding();
                scope.bind('destroy', function () {
                    self.destroy();
                });

                if (this.$.path.length === 1) {
                    this.trigger();
                }
            },
            _checkAttributes: function () {
                // check infrastructur
                if (!this.$.path) {
                    throw "No path defined!";
                }

                if (!this.$.scope) {
                    throw "No scope defined!"
                }

                if (this.$.twoWay) {
                    if (!this.$.target) {
                        throw "TwoWay binding, but no target defined!";
                    }
                    if (!this.$.target instanceof Bindable) {
                        throw "Target is not a Bindable!";
                    }

                    if (!this.$.targetKey) {
                        throw "TwoWay binding, but no target key defined!";
                    }

                }

                if(!this.$.bindingCreator){
                    this.$.bindingCreator = this;
                }

                if(this.$.transform){
                    this.transform = this.$.transform;
                }

                if (this.$.transformBack) {
                    this.transformBack = this.$.transformBack;
                }

            },
            _createSubBinding: function () {
                if (this.$.path.length > 1) {
                    var nScope;
                    if (this.$.fnc) {
                        nScope = this.getValue();
                    } else {
                        nScope = this.$.scope.$[this.$.key.name];
                    }
                    // if keys are left and has value && is bindable
                    // get value for first child
                    if (nScope) {
                        if(nScope instanceof Bindable){
                            // init new binding, which triggers this binding
                            this.$subBinding = new Binding({scope: nScope, path: this.$.path.slice(1), target: this.$.target, targetKey: this.$.targetKey, rootScope: this.$.rootScope, callback: this.$.callback, context: this.$.context, twoWay: this.$.twoWay, transform: this.$.transform, transformBack: this.$.transformBack, bindingCreator: this.$.bindingCreator});
                        } else {
                            // TODO: find next bindable var
                        }

                    }
                }
            },
            _revCallback: function (e) {
                if (this.$.fnc) {
                    var params = this._getFncParameters();
                    params.unshift(e.$);
                    this.$.fnc.apply(this.$.scope, params);
                } else {
                    this.$.scope.set(pathToString(this.$.path), this.transformBack(e.$));
                }
            },
            _changeCallback: function (event) {
                for (var i = 0; i < this.$.fnc._attributes.length; i++) {
                    if (!_.isUndefined(event.$[this.$.fnc._attributes[i]])) {
                        this.trigger();
                        return;
                    }
                }
            },
            _callback: function () {
                // remove subBindings!
                if (this.$subBinding) {
                    this.$subBinding.destroy();
                    this.$subBinding = null;
                }

                // try to create subBinding
                this._createSubBinding();

                this.trigger();
            },
            destroy: function () {
                var e;
                for (var j = 0; j < this.$events.length; j++) {
                    e = this.$events[j];
                    this.$.scope.unbind(e.eventType, e.callback);
                }

                if (this.$.twoWay === true) {
                    this.$.target.unbind(this.$.targetEvent, this._revCallback);
                }
                if (this.$subBinding) {
                    this.$subBinding.destroy();

                    delete this.$subBinding;
                }

                // destroy parameter bindings
                for (var i = 0; i < this.$parameters.length; i++) {
                    var par = this.$parameters[i];
                    if (par instanceof Binding) {
                        par.destroy();
                    }
                }
            },
            _getFncParameters: function () {
                var parameters = [];
                for (var i = 0; i < this.$parameters.length; i++) {
                    var para = this.$parameters[i];
                    if (para instanceof Binding) {
                        para = para.getValue();
                    }
                    parameters.push(para);
                }
                return parameters;
            },
            getValue: function () {
                if (this.$subBinding) {
                    return this.$subBinding.getValue();
                } else {
                    if (this.$.fnc) {
                        return this.$.fnc.apply(this.$.scope, this._getFncParameters());
                    } else if (this.$.path.length == 1) {
                        return this.$.scope.get(this.$.key.name);
                    } else {
                        return null;
                    }
                }
            },
            getContextValue: function () {
                if (this.$.context && this.$.context.length > 1) {
                    return Binding.contextToString(this.$.context);
                } else {
                    return this.getValue();
                }
            },
            // trigger
            trigger: function () {
                // get value
                var val = this.getContextValue();
                if (this.$.targetKey) {
                    this.$.target.set(this.$.targetKey, this.transform(val));
                } else if (this.$.callback) {
                    this.$.callback.call(this.$.target, this.transform(val));
                }

            },
            toString: function () {
                return this.getValue();
            },
            create: function(bindingDef, target, callback){
                var options = {scope: this.$.scope, target: target, callback: callback, path: bindingDef.path, twoWay : bindingDef.type === TYPE_TWOWAY, bindingCreator: this.$.bindingCreator};

                var fncEl;
                var fncScope;
                if(bindingDef.transform) {
                    fncEl = bindingDef.transform.pop();
                    fncScope = this.get(bindingDef.transform);
                    if(fncScope){
                        options.transform = fncScope[fncEl.name];
                    }
                }
                if(bindingDef.transformBack){
                    fncEl = bindingDef.transformBack.pop();
                    fncScope = this.get(bindingDef.transform);
                    if (fncScope) {
                        options.transformBack = fncScope[fncEl.name];
                    }
                }
                return new Binding(options);
            }
        });

    var TYPE_FNC = Binding.TYPE_FNC = "fnc";
    var TYPE_VAR = Binding.TYPE_VAR = "var";
    var TYPE_STATIC = Binding.TYPE_STATIC ="static";
    var TYPE_TWOWAY = Binding.TYPE_TWOWAY ="twoWay";

    Binding.contextToString = function (context) {
        var str = "", el;
        for (var i = 0; i < context.length; i++) {
            el = context[i];
            if (el instanceof Binding) {
                el = el.getValue();
            }
            if (el !== null && typeof(el) !== "undefined") {
                str += el;
            }
        }
        return str;
    };

    return Binding;
});<commit_msg>fixed binding parameters<commit_after>define(["js/core/EventDispatcher", "js/lib/parser", "underscore"], function (EventDispatcher, Parser, _) {

    /**
     * Returns false if path includes function
     * @param path
     */
    var pathToString = function (path) {
        var str = [];
        for (var i = 0; i < path.length; i++) {
            var el = path[i];
            if (el.type == TYPE_VAR) {
                str.push(el.name);
            } else {
                return false;
            }
        }
        return str.join(".");
    };
    var Bindable;
    var Binding = EventDispatcher.inherit("js.core.Binding",
        /** @lends Binding */
        {
            defaults: {
                event: 'change',
                path: null,
                twoWay: false
            },

            ctor: function (attributes) {
                if(!Bindable){
                    try {
                        Bindable = requirejs('js/core/Bindable');
                    } catch(e) {
                        Bindable = null;
                    }
                }
                this.callBase();

                this.$ = attributes;
                _.defaults(this.$,this.defaults);

                this.initialize();
            },

            transform: function (val) {
                return val;
            },

            transformBack: function (val) {
                return val;
            },

            initialize: function () {
                this._checkAttributes();
                this.$parameters = [];
                this.$events = [];
                this.$subBinding = null;

                if (!this.$.rootScope) {
                    this.$.rootScope = this;
                }
                var scope = this.$.scope;
                if(_.isString(this.$.path)){
                    this.$.path = Parser.parse(this.$.path,'path');
                }
                // split up first key
                this.$.key = this.$.path[0];
                var self = this;

                if (this.$.key.type == TYPE_FNC) {
                    var fncName = this.$.key.name, parameters = this.$.key.parameter;

                    if (_.isFunction(scope[fncName])) {
                        var fnc = scope[fncName];
                        var events = [];
                        if (fnc._attributes && fnc._attributes.length > 0) {
                            this.$.scope.bind("change", this._changeCallback, this);
                            this.$events.push({eventType: "change", callback: this._changeCallback});
                        } else {
                            if (fnc._events) {
                                events = fnc._events;
                            } else {
                                events = [];
                            }

                            var event, path;
                            for (var i = 0; i < events.length; i++) {
                                event = events[i];
                                scope.bind(event, this._callback, this);
                                this.$events.push({eventType: event, callback: this._callback});
                            }
                        }

                        var cb = function () {
                            self.trigger();
                        };

                        var para;
                        this.$parameters = [];
                        for (var j = 0; j < parameters.length; j++) {
                            para = parameters[j];
                            if(_.isObject(para)) {
                                para = this.$.bindingCreator.create(para, this.$.target, cb);
                            }
                            this.$parameters.push(para);

                        }
                        this.$.fnc = fnc;
                        this.$.fnc.trigger = function () {
                            self.trigger();
                        };
                    }

                } else {
                    this.$.event = "change:" + this.$.key.name;
                    this.$events.push({eventType: this.$.event, callback: this._callback});
                    // on change of this key
                    scope.bind(this.$.event, this._callback, this);
                }

                if (this.$.twoWay === true && this.$.path.length === 1) {
                    this.$.targetEvent = 'change:' + this.$.targetKey;

                    this.$.target.bind(this.$.targetEvent, this._revCallback, this);
                }

                this._createSubBinding();
                scope.bind('destroy', function () {
                    self.destroy();
                });

                if (this.$.path.length === 1) {
                    this.trigger();
                }
            },
            _checkAttributes: function () {
                // check infrastructur
                if (!this.$.path) {
                    throw "No path defined!";
                }

                if (!this.$.scope) {
                    throw "No scope defined!"
                }

                if (this.$.twoWay) {
                    if (!this.$.target) {
                        throw "TwoWay binding, but no target defined!";
                    }
                    if (!this.$.target instanceof Bindable) {
                        throw "Target is not a Bindable!";
                    }

                    if (!this.$.targetKey) {
                        throw "TwoWay binding, but no target key defined!";
                    }

                }

                if(!this.$.bindingCreator){
                    this.$.bindingCreator = this;
                }

                if(this.$.transform){
                    this.transform = this.$.transform;
                }

                if (this.$.transformBack) {
                    this.transformBack = this.$.transformBack;
                }

            },
            _createSubBinding: function () {
                if (this.$.path.length > 1) {
                    var nScope;
                    if (this.$.fnc) {
                        nScope = this.getValue();
                    } else {
                        nScope = this.$.scope.$[this.$.key.name];
                    }
                    // if keys are left and has value && is bindable
                    // get value for first child
                    if (nScope) {
                        if(nScope instanceof Bindable){
                            // init new binding, which triggers this binding
                            this.$subBinding = new Binding({scope: nScope, path: this.$.path.slice(1), target: this.$.target, targetKey: this.$.targetKey, rootScope: this.$.rootScope, callback: this.$.callback, context: this.$.context, twoWay: this.$.twoWay, transform: this.$.transform, transformBack: this.$.transformBack, bindingCreator: this.$.bindingCreator});
                        } else {
                            // TODO: find next bindable var
                        }

                    }
                }
            },
            _revCallback: function (e) {
                if (this.$.fnc) {
                    var params = this._getFncParameters();
                    params.unshift(e.$);
                    this.$.fnc.apply(this.$.scope, params);
                } else {
                    this.$.scope.set(pathToString(this.$.path), this.transformBack(e.$));
                }
            },
            _changeCallback: function (event) {
                for (var i = 0; i < this.$.fnc._attributes.length; i++) {
                    if (!_.isUndefined(event.$[this.$.fnc._attributes[i]])) {
                        this.trigger();
                        return;
                    }
                }
            },
            _callback: function () {
                // remove subBindings!
                if (this.$subBinding) {
                    this.$subBinding.destroy();
                    this.$subBinding = null;
                }

                // try to create subBinding
                this._createSubBinding();

                this.trigger();
            },
            destroy: function () {
                var e;
                for (var j = 0; j < this.$events.length; j++) {
                    e = this.$events[j];
                    this.$.scope.unbind(e.eventType, e.callback);
                }

                if (this.$.twoWay === true) {
                    this.$.target.unbind(this.$.targetEvent, this._revCallback);
                }
                if (this.$subBinding) {
                    this.$subBinding.destroy();

                    delete this.$subBinding;
                }

                // destroy parameter bindings
                for (var i = 0; i < this.$parameters.length; i++) {
                    var par = this.$parameters[i];
                    if (par instanceof Binding) {
                        par.destroy();
                    }
                }
            },
            _getFncParameters: function () {
                var parameters = [];
                for (var i = 0; i < this.$parameters.length; i++) {
                    var para = this.$parameters[i];
                    if (para instanceof Binding) {
                        para = para.getValue();
                    }
                    parameters.push(para);
                }
                return parameters;
            },
            getValue: function () {
                if (this.$subBinding) {
                    return this.$subBinding.getValue();
                } else {
                    if (this.$.fnc) {
                        return this.$.fnc.apply(this.$.scope, this._getFncParameters());
                    } else if (this.$.path.length == 1) {
                        return this.$.scope.get(this.$.key.name);
                    } else {
                        return null;
                    }
                }
            },
            getContextValue: function () {
                if (this.$.context && this.$.context.length > 1) {
                    return Binding.contextToString(this.$.context);
                } else {
                    return this.getValue();
                }
            },
            // trigger
            trigger: function () {
                // get value
                var val = this.getContextValue();
                if (this.$.targetKey) {
                    this.$.target.set(this.$.targetKey, this.transform(val));
                } else if (this.$.callback) {
                    this.$.callback.call(this.$.target, this.transform(val));
                }

            },
            toString: function () {
                return this.getValue();
            },
            create: function(bindingDef, target, callback){
                var options = {scope: this.$.scope, target: target, callback: callback, path: bindingDef.path, twoWay : bindingDef.type === TYPE_TWOWAY, bindingCreator: this.$.bindingCreator};

                var fncEl;
                var fncScope;
                if(bindingDef.transform) {
                    fncEl = bindingDef.transform.pop();
                    fncScope = this.get(bindingDef.transform);
                    if(fncScope){
                        options.transform = fncScope[fncEl.name];
                    }
                }
                if(bindingDef.transformBack){
                    fncEl = bindingDef.transformBack.pop();
                    fncScope = this.get(bindingDef.transform);
                    if (fncScope) {
                        options.transformBack = fncScope[fncEl.name];
                    }
                }
                return new Binding(options);
            }
        });

    var TYPE_FNC = Binding.TYPE_FNC = "fnc";
    var TYPE_VAR = Binding.TYPE_VAR = "var";
    var TYPE_STATIC = Binding.TYPE_STATIC ="static";
    var TYPE_TWOWAY = Binding.TYPE_TWOWAY ="twoWay";

    Binding.contextToString = function (context) {
        var str = "", el;
        for (var i = 0; i < context.length; i++) {
            el = context[i];
            if (el instanceof Binding) {
                el = el.getValue();
            }
            if (el !== null && typeof(el) !== "undefined") {
                str += el;
            }
        }
        return str;
    };

    return Binding;
});<|endoftext|>


<commit_before>var Disassembler = Disassembler || {};

(function() {
  'use strict';

  var diagram;

  function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
  }

  // An instruction
  var Instruction = function(instruction, address) {

    var toBytes = function(number) {
      var p = [];

      for (var i = Math.floor(number.length / 2); i-->0;) {
        p[i] = number.slice(i * 2, (i + 1) * 2);
      }

      return p;
    }

    if (instruction.length != 8 || !instruction.match(/[0-9a-fA-F]{8}/)) {
      throw "Invalid instruction '" + instruction + "'";
    }

    var bytes = toBytes(instruction);

    this.opcode = instruction;
    this.address = pad(address.toString(16), 8).toUpperCase();
    this.next = [parseInt(this.address, 16) + 1];

    switch (parseInt(bytes[0], 16)) {
    case 0:
      this.instruction = 'IUC';
      this.desc = 'No operation';
      break;
    case 1:
      this.instruction = 'HUC';
      this.desc = 'Terminate';
      break;
    case 2:
      var address = + bytes[1] + bytes[2] + bytes[3];
      this.instruction = 'BUC  ' + address;
      this.desc = 'Jump to ' + address;
      this.next = [parseInt(address, 16)];
      break;
    case 3:
      var address = + bytes[1] + bytes[2] + bytes[3];
      this.instruction = 'BIC  ' + address;
      this.desc = 'Jump to ' + address + ' if condition flag is set';
      this.next.push(parseInt(address, 16));
      break;
    case 4:
      this.instruction = 'SET0 ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Set outputs ' + bytes[1] + ' AND ' + bytes[2] + ' XOR ' + bytes[3];
      break;
    case 5:
      this.instruction = 'TSTI ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Test inputs ' + bytes[1] + ' AND ' + bytes[2] + ' XOR ' + bytes[3];
      break;
    default:
      throw "Invalid opcode '" + bytes[0] + "'";
    };
  };

  var code = $('#code');
  var errors = $('#errors');
  var output = $('#output');

  // Decode an array of strings, one instruction per string
  var decode = function(text) {
    var instructions = [];

    try { // Parse instruction
      var count = 0;

      for (var i = 0; i < text.length; i++) {
        var string = text[i].trim()

        if (string.length)
          instructions.push(new Instruction(string, count++));
      }

    } catch (err) {
      addError("At line " + i + ": " + err);
    }

    show(instructions);
  }

  var instructionsToChart = function(instructions) {
    var text = "";

    for (var i = 0; i < instructions.length; i++) {
      var instruction = instructions[i];

      if (instruction.next[1])
        text += "i" + i + "=>condition: " + instruction.instruction + "\n";
      else
        text += "i" + i + "=>operation: " + instruction.instruction + "\n";
    }

    instructions.forEach(function(instruction) {
      instruction.next.forEach(function(address) {
        if (address >= instructions.length)
          address = -1;
      });
    });

    for (var i = 0; i < instructions.length - 1; i++) {
      var instruction = instructions[i];

      if (instruction.next[1]) {
        if (instruction.next[0] !== -1)
          text += "i" + i + "(no)->i" + instruction.next[0] + "\n";
        if (instruction.next[1] !== -1)
          text += "i" + i + "(yes, right)->i" + instruction.next[1] + "\n";
      } else {
        if (instruction.next[0] !== -1)
          text += "i" + i + "->i" + instruction.next[0] + "\n";
      }
    }

    return text;
  }

  // Display an array of instructions
  var show = function(instructions) {
    instructions.forEach(function(e) {
      addInstruction(e);
    });

    if (instructions.length)
      $('#labels').show();
    else
      $('#labels').hide();

    // Draw flowchart
    if (diagram)
      diagram.clean();

    diagram = flowchart.parse(instructionsToChart(instructions));
    diagram.drawSVG('diagram');
  };

  var clearErrors = function() {
    errors.html('');
  };

  var addError = function(msg) {
    errors.append("
" + msg +
                  "×
");
  };

  var clearInstructions = function() {
    output.html('');
  };

  var addInstruction = function(instruction) {
    output.append("
" + instruction.address + "	" +
                  "" + instruction.opcode + "	" +
                  "" + instruction.instruction + "	" +
                  "" + instruction.desc + "	" +
                  "
");
  }

  // Update as the user types
  code.bind('input propertychange', function() {
    clearErrors();
    clearInstructions();
    decode(code.val().split("\n"));
  });

}).call(Disassembler);
<commit_msg>disassembler: Refactor chart generation<commit_after>var Disassembler = Disassembler || {};

(function() {
  'use strict';

  var diagram;

  function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
  }

  // An instruction
  var Instruction = function(instruction, address) {

    var toBytes = function(number) {
      var p = [];

      for (var i = Math.floor(number.length / 2); i-->0;) {
        p[i] = number.slice(i * 2, (i + 1) * 2);
      }

      return p;
    }

    if (instruction.length != 8 || !instruction.match(/[0-9a-fA-F]{8}/)) {
      throw "Invalid instruction '" + instruction + "'";
    }

    var bytes = toBytes(instruction);

    this.opcode = instruction;
    this.address = pad(address.toString(16), 8).toUpperCase();
    this.next = [parseInt(this.address, 16) + 1];

    switch (parseInt(bytes[0], 16)) {
    case 0:
      this.instruction = 'IUC';
      this.desc = 'No operation';
      break;
    case 1:
      this.instruction = 'HUC';
      this.desc = 'Terminate';
      break;
    case 2:
      var address = + bytes[1] + bytes[2] + bytes[3];
      this.instruction = 'BUC  ' + address;
      this.desc = 'Jump to ' + address;
      this.next = [parseInt(address, 16)];
      break;
    case 3:
      var address = + bytes[1] + bytes[2] + bytes[3];
      this.instruction = 'BIC  ' + address;
      this.desc = 'Jump to ' + address + ' if condition flag is set';
      this.next.push(parseInt(address, 16));
      break;
    case 4:
      this.instruction = 'SET0 ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Set outputs ' + bytes[1] + ' AND ' + bytes[2] + ' XOR ' + bytes[3];
      break;
    case 5:
      this.instruction = 'TSTI ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Test inputs ' + bytes[1] + ' AND ' + bytes[2] + ' XOR ' + bytes[3];
      break;
    default:
      throw "Invalid opcode '" + bytes[0] + "'";
    };
  };

  var code = $('#code');
  var errors = $('#errors');
  var output = $('#output');

  // Decode an array of strings, one instruction per string
  var decode = function(text) {
    var instructions = [];

    try { // Parse instruction
      var count = 0;

      for (var i = 0; i < text.length; i++) {
        var string = text[i].trim()

        if (string.length)
          instructions.push(new Instruction(string, count++));
      }

    } catch (err) {
      addError("At line " + i + ": " + err);
    }

    show(instructions);
  }

  var instructionsToChart = function(instructions) {
    var instructionDefinition = function(instruction, i) {
      if (instruction.next[1] !== undefined)
        return "i" + i + "=>condition: " + instruction.instruction + "\n";
      else {
        if (i === 0)
          return "i" + i + "=>start: " + instruction.instruction + "\n";
        else if (i === instructions.length - 1)
          return "i" + i + "=>end: " + instruction.instruction + "\n";
        else
          return "i" + i + "=>operation: " + instruction.instruction + "\n";
      }
    };

    var instructionLinks = function(instruction, i) {
      if (instruction.next[1] !== undefined) {
        var links = "";

        if (instruction.next[0] !== -1)
          links = "i" + i + "(no)->i" + instruction.next[0] + "\n";
        if (instruction.next[1] !== -1)
          links += "i" + i + "(yes, right)->i" + instruction.next[1] + "\n";

        return links
      } else {
        if (instruction.next[0] !== -1)
          return "i" + i + "->i" + instruction.next[0] + "\n";
        else
          return "";
      }
    }

    var definitions = "", links = "";

    for (var i = 0; i < instructions.length; i++) {
      if (instructions[i].next[0] >= instructions.length)
        instructions[i].next[0] = -1;

      if (instructions[i].next[1] >= instructions.length)
        instructions[i].next[1] = -1;

      definitions += instructionDefinition(instructions[i], i);
      links += instructionLinks(instructions[i], i);
    }

    return definitions + links;
  }

  // Display an array of instructions
  var show = function(instructions) {
    instructions.forEach(function(e) {
      addInstruction(e);
    });

    if (instructions.length)
      $('#labels').show();
    else
      $('#labels').hide();

    // Draw flowchart
    if (diagram)
      diagram.clean();

    diagram = flowchart.parse(instructionsToChart(instructions));
    diagram.drawSVG('diagram');
  };

  var clearErrors = function() {
    errors.html('');
  };

  var addError = function(msg) {
    errors.append("
" + msg +
                  "×
");
  };

  var clearInstructions = function() {
    output.html('');
  };

  var addInstruction = function(instruction) {
    output.append("
" + instruction.address + "	" +
                  "" + instruction.opcode + "	" +
                  "" + instruction.instruction + "	" +
                  "" + instruction.desc + "	" +
                  "
");
  }

  // Update as the user types
  code.bind('input propertychange', function() {
    clearErrors();
    clearInstructions();
    decode(code.val().split("\n"));
  });

}).call(Disassembler);
<|endoftext|>


<commit_before>//
// Dalliance Genome Explorer
// (c) Thomas Down 2006-2010
//
// feature-draw.js: new feature-tier renderer
//

"use strict";

if (typeof(require) !== 'undefined') {
    var utils = require('./utils');
    var shallowCopy = utils.shallowCopy;
    var pusho = utils.pusho;

    var tier = require('./tier');
    var DasTier = tier.DasTier;

    var g = require('./glyphs');
    var BoxGlyph = g.BoxGlyph;
    var GroupGlyph = g.GroupGlyph;
    var LineGraphGlyph = g.LineGraphGlyph;
    var LabelledGlyph = g.LabelledGlyph;
    var CrossGlyph = g.CrossGlyph;
    var ExGlyph = g.ExGlyph;
    var TriangleGlyph = g.TriangleGlyph;
    var DotGlyph = g.DotGlyph;
    var PaddedGlyph = g.PaddedGlyph;
    var AArrowGlyph = g.AArrowGlyph;
    var SpanGlyph = g.SpanGlyph;
    var LineGlyph = g.LineGlyph;
    var PrimersGlyph = g.PrimersGlyph;
    var ArrowGlyph = g.ArrowGlyph;
    var TooManyGlyph = g.TooManyGlyph;
    var TextGlyph = g.TextGlyph;
    var SequenceGlyph = g.SequenceGlyph;
    var AminoAcidGlyph = g.AminoAcidGlyph;
    var TranslatedGlyph = g.TranslatedGlyph;
    var PointGlyph = g.PointGlyph;
    var GridGlyph = g.GridGlyph;
    var StarGlyph = g.StarGlyph;
    var PlimsollGlyph = g.PlimsollGlyph;
    var OverlayLabelCanvas = g.OverlayLabelCanvas;

    var color = require('./color');
    var makeGradient = color.makeGradient;

    var spans = require('./spans');
    var Range = spans.Range;
    var union = spans.union;

    var das = require('./das');
    var DASFeature = das.DASFeature;
    var isDasBooleanTrue = das.isDasBooleanTrue;
    var isDasBooleanNotFalse = das.isDasBooleanNotFalse;

    var parseCigar = require('./cigar').parseCigar;

    var nf = require('./numformats');
    var formatQuantLabel = nf.formatQuantLabel;
}

var MIN_PADDING = 3;

function SubTier() {
    this.glyphs = [];
    this.height = 0;
    this.quant = null;
}

SubTier.prototype.indexFor = function(glyph) {
    var gmin = glyph.min();
    var lb = 0, ub = this.glyphs.length;
    while (ub > lb) {
        var mid = ((lb + ub)/2)|0;
        if (mid >= this.glyphs.length)
            return this.glyphs.length;
        var mg = this.glyphs[mid];
        if (gmin < mg.min()) {
            ub = mid;
        } else {
            lb = mid + 1;
        }
    }
    return ub;
}

SubTier.prototype.add = function(glyph) {
    var ind = this.indexFor(glyph);
    this.glyphs.splice(ind, 0, glyph);
    this.height = Math.max(this.height, glyph.height());
    if (glyph.quant && this.quant == null) {
        this.quant = glyph.quant;
    }
}

SubTier.prototype.hasSpaceFor = function(glyph) {
    var ind = this.indexFor(glyph);
    if (ind > 0 && this.glyphs[ind-1].max() >= glyph.min())
        return false;
    if (ind < this.glyphs.length && this.glyphs[ind].min() <= glyph.max())
        return false;

    return true;
}

DasTier.prototype.paintToContext = function(gc, oc, offset) {
    var subtiers = this.subtiers;
    var fpw = this.viewport.width|0;

    gc.save();
    for (var s = 0; s < subtiers.length; ++s) {
        var quant = null;
        var glyphs = subtiers[s].glyphs;
        for (var i = 0; i < glyphs.length; ++i) {
            var glyph = glyphs[i];
            if (glyph.min() < fpw-offset && glyph.max() > -offset) {
                var glyph = glyphs[i];
                glyph.draw(gc, oc);
                if (glyph.quant) {
                    quant = glyph.quant;
                }
            }
        }

	if (quant && quant.min < 0 && quant.max > 0 && this.dasSource.zeroLine) {
	    var ry = subtiers[0].height * (quant.max / (quant.max - quant.min))
	    gc.save();
	    gc.strokeStyle = this.dasSource.zeroLine;
	    gc.lineWidth = 0.5;
	    gc.beginPath();
	    gc.moveTo(-1000, ry);
	    gc.lineTo(fpw + 1000, ry);
	    gc.stroke();
	    gc.restore();
	}

        if (this.scaleVertical) {
            var scale = this.browser.scale;
            gc.translate(0, scale + this.padding);
            oc.translate(0, scale + this.padding);
        } else {
            gc.translate(0, subtiers[s].height + this.padding);
            oc.translate(0, subtiers[s].height + this.padding);
        }
    }
    gc.restore();

    if (quant && this.quantLeapThreshold && this.featureSource && this.browser.sourceAdapterIsCapable(this.featureSource, 'quantLeap')) {
        var ry = subtiers[0].height * (1.0 - ((this.quantLeapThreshold - quant.min) / (quant.max - quant.min)));

        gc.save();
        gc.strokeStyle = 'red';
        gc.lineWidth = 0.3;
        gc.beginPath();
        gc.moveTo(-1000, ry);
        gc.lineTo(fpw + 1000, ry);
        gc.stroke();
        gc.restore();
    }
}

DasTier.prototype.paintQuant = function() {
    if (!this.quantOverlay)
        return;

    var retina = this.browser.retina && window.devicePixelRatio > 1;

    var quant;
    if (this.subtiers && this.subtiers.length > 0)
        quant = this.subtiers[0].quant;

    if (quant) {
        var h = this.subtiers[0].height;
        var w = 50;
        this.quantOverlay.height = this.viewport.height;
        this.quantOverlay.width = retina ? w*2 : w;
        this.quantOverlay.style.height = '' + (retina ? this.quantOverlay.height/2 : this.quantOverlay.height) + 'px';
        this.quantOverlay.style.width = '' + w + 'px';
        this.quantOverlay.style.display = 'block';
        var ctx = this.quantOverlay.getContext('2d');
        if (retina)
            ctx.scale(2, 2);

        var numTics = 2;
        if (h > 40) {
            numTics = 1 + ((h/20) | 0);
        }
        var ticSpacing = (h + this.padding*2) / (numTics - 1);
        var ticInterval = (quant.max - quant.min) / (numTics - 1);

        ctx.fillStyle = 'white'
        ctx.globalAlpha = 0.6;
        if (this.browser.rulerLocation == 'right') {
            ctx.fillRect(w-30, 0, 30, h + this.padding*2);
        } else {
            ctx.fillRect(0, 0, 30, h + this.padding*2);
        }
        ctx.globalAlpha = 1.0;

        ctx.strokeStyle = 'black';
        ctx.lineWidth = 1;
        ctx.beginPath();

        if (this.browser.rulerLocation == 'right') {
            ctx.moveTo(w - 8, this.padding);
            ctx.lineTo(w, this.padding);
            ctx.lineTo(w, h + this.padding);
            ctx.lineTo(w - 8, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.moveTo(w, ty);
                ctx.lineTo(w - 5, ty);
            }
        } else {
            ctx.moveTo(8, this.padding);
            ctx.lineTo(0, this.padding);
            ctx.lineTo(0, h + this.padding);
            ctx.lineTo(8, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.moveTo(0, ty);
                ctx.lineTo(5, ty);
            }
        }
        ctx.stroke();

        ctx.fillStyle = 'black';

        if (this.browser.rulerLocation == 'right') {
            ctx.textAlign = 'right';
            ctx.fillText(formatQuantLabel(quant.max), w-9, 8);
            ctx.fillText(formatQuantLabel(quant.min), w-9, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.fillText(formatQuantLabel((1.0*quant.max) - (t*ticInterval)), w - 9, ty + 3);
            }
        } else {
            ctx.textAlign = 'left';
            ctx.fillText(formatQuantLabel(quant.max), 9, 8);
            ctx.fillText(formatQuantLabel(quant.min), 9, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.fillText(formatQuantLabel((1.0*quant.max) - (t*ticInterval)), 9, ty + 3);
            }
        }
    } else {
        this.quantOverlay.style.display = 'none';
    }
}

DasTier.prototype.styleForFeature = function(f) {
    var ssScale = this.browser.zoomForCurrentScale();

    if (!this.stylesheet) {
        return null;
    }

    var maybe = null;
    var ss = this.stylesheet.styles;
    for (var si = 0; si < ss.length; ++si) {
        var sh = ss[si];
        if (sh.zoom && sh.zoom != ssScale) {
            continue;
        }

        if (sh.orientation) {
            if (sh.orientation != f.orientation) {
                continue;
            }
        }

        var labelRE = sh._labelRE;
        if (!labelRE || !labelRE.test) {
            labelRE = new RegExp('^' + sh.label + '$');
            sh._labelRE = labelRE;
        }
        if (sh.label && !(labelRE.test(f.label))) {
            continue;
        }
        var methodRE = sh._methodRE;
        if (!methodRE || !methodRE.test) {
            methodRE = new RegExp('^' + sh.method + '$');
            sh._methodRE = methodRE;
        }
        if (sh.method && !(methodRE.test(f.method))) {
            continue;
        }
        if (sh.type) {
            if (sh.type == 'default') {
                if (!maybe) {
                    maybe = sh.style;
                }
                continue;
            } else {
                var typeRE = sh._typeRE;
                if (!typeRE || !typeRE.test) {
                    typeRE = new RegExp('^' + sh.type + '$');
                    sh._typeRE = typeRE;
                }
                if (!typeRE.test(f.type))
                    continue;
            }
        }
        return sh.style;
    }
    return maybe;
}

DasTier.prototype.quantMin = function(style) {
    if (this.forceMinDynamic) {
        return this.currentFeaturesMinScore || 0;
    } else if (typeof(this.forceMin) === 'number') {
        return this.forceMin;
    } else {
        return style.MIN || this.currentFeaturesMinScore || 0;
    }
}

DasTier.prototype.quantMax = function(style) {
    if (this.forceMaxDynamic) {
        return this.currentFeaturesMaxScore || 0;
    } else if (typeof(this.forceMax) === 'number') {
        return this.forceMax;
    } else {
        return style.MAX || this.currentFeaturesMaxScore || 0;
    }
}

if (typeof(module) !== 'undefined') {
    module.exports = {
        SubTier: SubTier
    };
}
<commit_msg>Cleanup.<commit_after>//
// Dalliance Genome Explorer
// (c) Thomas Down 2006-2010
//
// feature-draw.js: new feature-tier renderer
//

"use strict";

if (typeof(require) !== 'undefined') {
    var tier = require('./tier');
    var DasTier = tier.DasTier;

    var nf = require('./numformats');
    var formatQuantLabel = nf.formatQuantLabel;
}

function SubTier() {
    this.glyphs = [];
    this.height = 0;
    this.quant = null;
}

SubTier.prototype.indexFor = function(glyph) {
    var gmin = glyph.min();
    var lb = 0, ub = this.glyphs.length;
    while (ub > lb) {
        var mid = ((lb + ub)/2)|0;
        if (mid >= this.glyphs.length)
            return this.glyphs.length;
        var mg = this.glyphs[mid];
        if (gmin < mg.min()) {
            ub = mid;
        } else {
            lb = mid + 1;
        }
    }
    return ub;
}

SubTier.prototype.add = function(glyph) {
    var ind = this.indexFor(glyph);
    this.glyphs.splice(ind, 0, glyph);
    this.height = Math.max(this.height, glyph.height());
    if (glyph.quant && this.quant == null) {
        this.quant = glyph.quant;
    }
}

SubTier.prototype.hasSpaceFor = function(glyph) {
    var ind = this.indexFor(glyph);
    if (ind > 0 && this.glyphs[ind-1].max() >= glyph.min())
        return false;
    if (ind < this.glyphs.length && this.glyphs[ind].min() <= glyph.max())
        return false;

    return true;
}

DasTier.prototype.paintToContext = function(gc, oc, offset) {
    var subtiers = this.subtiers;
    var fpw = this.viewport.width|0;

    gc.save();
    for (var s = 0; s < subtiers.length; ++s) {
        var quant = null;
        var glyphs = subtiers[s].glyphs;
        for (var i = 0; i < glyphs.length; ++i) {
            var glyph = glyphs[i];
            if (glyph.min() < fpw-offset && glyph.max() > -offset) {
                var glyph = glyphs[i];
                glyph.draw(gc, oc);
                if (glyph.quant) {
                    quant = glyph.quant;
                }
            }
        }

	if (quant && quant.min < 0 && quant.max > 0 && this.dasSource.zeroLine) {
	    var ry = subtiers[0].height * (quant.max / (quant.max - quant.min))
	    gc.save();
	    gc.strokeStyle = this.dasSource.zeroLine;
	    gc.lineWidth = 0.5;
	    gc.beginPath();
	    gc.moveTo(-1000, ry);
	    gc.lineTo(fpw + 1000, ry);
	    gc.stroke();
	    gc.restore();
	}

        if (this.scaleVertical) {
            var scale = this.browser.scale;
            gc.translate(0, scale + this.padding);
            oc.translate(0, scale + this.padding);
        } else {
            gc.translate(0, subtiers[s].height + this.padding);
            oc.translate(0, subtiers[s].height + this.padding);
        }
    }
    gc.restore();

    if (quant && this.quantLeapThreshold && this.featureSource && this.browser.sourceAdapterIsCapable(this.featureSource, 'quantLeap')) {
        var ry = subtiers[0].height * (1.0 - ((this.quantLeapThreshold - quant.min) / (quant.max - quant.min)));

        gc.save();
        gc.strokeStyle = 'red';
        gc.lineWidth = 0.3;
        gc.beginPath();
        gc.moveTo(-1000, ry);
        gc.lineTo(fpw + 1000, ry);
        gc.stroke();
        gc.restore();
    }
}

DasTier.prototype.paintQuant = function() {
    if (!this.quantOverlay)
        return;

    var retina = this.browser.retina && window.devicePixelRatio > 1;

    var quant;
    if (this.subtiers && this.subtiers.length > 0)
        quant = this.subtiers[0].quant;

    if (quant) {
        var h = this.subtiers[0].height;
        var w = 50;
        this.quantOverlay.height = this.viewport.height;
        this.quantOverlay.width = retina ? w*2 : w;
        this.quantOverlay.style.height = '' + (retina ? this.quantOverlay.height/2 : this.quantOverlay.height) + 'px';
        this.quantOverlay.style.width = '' + w + 'px';
        this.quantOverlay.style.display = 'block';
        var ctx = this.quantOverlay.getContext('2d');
        if (retina)
            ctx.scale(2, 2);

        var numTics = 2;
        if (h > 40) {
            numTics = 1 + ((h/20) | 0);
        }
        var ticSpacing = (h + this.padding*2) / (numTics - 1);
        var ticInterval = (quant.max - quant.min) / (numTics - 1);

        ctx.fillStyle = 'white'
        ctx.globalAlpha = 0.6;
        if (this.browser.rulerLocation == 'right') {
            ctx.fillRect(w-30, 0, 30, h + this.padding*2);
        } else {
            ctx.fillRect(0, 0, 30, h + this.padding*2);
        }
        ctx.globalAlpha = 1.0;

        ctx.strokeStyle = 'black';
        ctx.lineWidth = 1;
        ctx.beginPath();

        if (this.browser.rulerLocation == 'right') {
            ctx.moveTo(w - 8, this.padding);
            ctx.lineTo(w, this.padding);
            ctx.lineTo(w, h + this.padding);
            ctx.lineTo(w - 8, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.moveTo(w, ty);
                ctx.lineTo(w - 5, ty);
            }
        } else {
            ctx.moveTo(8, this.padding);
            ctx.lineTo(0, this.padding);
            ctx.lineTo(0, h + this.padding);
            ctx.lineTo(8, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.moveTo(0, ty);
                ctx.lineTo(5, ty);
            }
        }
        ctx.stroke();

        ctx.fillStyle = 'black';

        if (this.browser.rulerLocation == 'right') {
            ctx.textAlign = 'right';
            ctx.fillText(formatQuantLabel(quant.max), w-9, 8);
            ctx.fillText(formatQuantLabel(quant.min), w-9, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.fillText(formatQuantLabel((1.0*quant.max) - (t*ticInterval)), w - 9, ty + 3);
            }
        } else {
            ctx.textAlign = 'left';
            ctx.fillText(formatQuantLabel(quant.max), 9, 8);
            ctx.fillText(formatQuantLabel(quant.min), 9, h + this.padding);
            for (var t = 1; t < numTics-1; ++t) {
                var ty = t*ticSpacing;
                ctx.fillText(formatQuantLabel((1.0*quant.max) - (t*ticInterval)), 9, ty + 3);
            }
        }
    } else {
        this.quantOverlay.style.display = 'none';
    }
}

DasTier.prototype.styleForFeature = function(f) {
    var ssScale = this.browser.zoomForCurrentScale();

    if (!this.stylesheet) {
        return null;
    }

    var maybe = null;
    var ss = this.stylesheet.styles;
    for (var si = 0; si < ss.length; ++si) {
        var sh = ss[si];
        if (sh.zoom && sh.zoom != ssScale) {
            continue;
        }

        if (sh.orientation) {
            if (sh.orientation != f.orientation) {
                continue;
            }
        }

        var labelRE = sh._labelRE;
        if (!labelRE || !labelRE.test) {
            labelRE = new RegExp('^' + sh.label + '$');
            sh._labelRE = labelRE;
        }
        if (sh.label && !(labelRE.test(f.label))) {
            continue;
        }
        var methodRE = sh._methodRE;
        if (!methodRE || !methodRE.test) {
            methodRE = new RegExp('^' + sh.method + '$');
            sh._methodRE = methodRE;
        }
        if (sh.method && !(methodRE.test(f.method))) {
            continue;
        }
        if (sh.type) {
            if (sh.type == 'default') {
                if (!maybe) {
                    maybe = sh.style;
                }
                continue;
            } else {
                var typeRE = sh._typeRE;
                if (!typeRE || !typeRE.test) {
                    typeRE = new RegExp('^' + sh.type + '$');
                    sh._typeRE = typeRE;
                }
                if (!typeRE.test(f.type))
                    continue;
            }
        }
        return sh.style;
    }
    return maybe;
}

DasTier.prototype.quantMin = function(style) {
    if (this.forceMinDynamic) {
        return this.currentFeaturesMinScore || 0;
    } else if (typeof(this.forceMin) === 'number') {
        return this.forceMin;
    } else {
        return style.MIN || this.currentFeaturesMinScore || 0;
    }
}

DasTier.prototype.quantMax = function(style) {
    if (this.forceMaxDynamic) {
        return this.currentFeaturesMaxScore || 0;
    } else if (typeof(this.forceMax) === 'number') {
        return this.forceMax;
    } else {
        return style.MAX || this.currentFeaturesMaxScore || 0;
    }
}

if (typeof(module) !== 'undefined') {
    module.exports = {
        SubTier: SubTier
    };
}
<|endoftext|>


<commit_before>/*
 * gallery location allay
 *
 * cernter: lat, lng
 * cSize: circle size(*30)
 * name: gallery name
 */
var gallery = {};
gallery['ESPACE LOUIS VUITTON'] = {
        latlng: [35.666566,139.709102],
        address:'Louis Vuitton Omotesando Bldg. 7F 5-7-5 Jingumae, Shibuya-ku, Tokyo',
        url: 'http://www.espacelouisvuittontokyo.com/en/'
};
gallery['ARCHI-DEPOT Museum'] = {
	latlng: [35.620988,139.748830],
	address: 'Terada soko, 2-6-10, Higashi Shinagawa, Tokyo',
	url:'http://archi-depot.com/'
};
gallery['Tokyo Metropolitan Teien Art Museum'] = {
	latlng: [35.635753,139.720453],
	address:'5−21-9, Shirokanedai, Minato-ku, Tokyo',
	url: 'http://www.teien-art-museum.ne.jp/en/'
};
gallery['Aoyama Meguro'] = {
	latlng: [35.6507662,139.6968979],
	address:'2-30-6 Kamimeguro Meguroku Tokyo',
	url: 'http://aoyamameguro.com/en'
};
gallery['Maison Hermes'] = {
	latlng: [35.6688001,139.7286596],
	address:'5-4-1 Ginza, Chuo-ku, Tokyo',
	url: 'http://goo.gl/iLFxCb'
};
gallery['Mori Art Museum'] = {
	latlng: [35.660556,139.729167],
	address:'Roppongi Hills Mori Tower, 6-10-1 Roppongi, Minato-ku, Tokyo',
	url: 'http://www.mori.art.museum/eng/'
};
gallery['The National Museum of Modern Art'] = {
	latlng: [35.690543,139.754693],
	address:'3-1 Kitanomaru Park, Chiyoda-ku, Tokyo, 1028322',
	url: 'http://www.momat.go.jp/english/'
};
gallery['Nezu Museum'] ={
	latlng: [35.662161,139.717566],
	address:'6-5-1 Minami Aoyama, Minato-ku, Tokyo',
	url: 'http://www.nezu-muse.or.jp/en/about/index.html'
};
gallery['SCAI THE BATHHOUSE'] = {
	latlng: [35.721775,139.770496],
	address:'6-1-23 Yanaka, Taito-Ku, Tokyo',
	url:'http://www.scaithebathhouse.com/'
};
gallery['Taka Ishii Gallery'] = {
	latlng: [35.664122,139.729426],
	address:'6-5-24 3F Roppongi Minato-ku Tokyo #106-0032',
	url: 'http://www.takaishiigallery.com/en/'
};
gallery['WAKO WORKS OF ART'] = {
 	latlng: [35.661867,139.731351],
	address:'Piramide Bldg. 3F, 6-6-9 Roppongi, Minato-ku, Tokyo',
	url: 'http://www.wako-art.jp/top.php'
};
gallery['Watarium Museum']= {
 	latlng: [35.670668,139.713372],
	address:'3-7-6 Jingumae, Shibuya-ku, Tokyo',
	url: 'http://www.watarium.co.jp/'
};

<commit_msg>fixed link bug<commit_after>/*
 * gallery location allay
 *
 * cernter: lat, lng
 * cSize: circle size(*30)
 * name: gallery name
 */
var gallery = {};
gallery['ESPACE LOUIS VUITTON'] = {
        latlng: [35.666566,139.709102],
        address:'Louis Vuitton Omotesando Bldg. 7F 5-7-5 Jingumae, Shibuya-ku, Tokyo',
        url: 'http://www.espacelouisvuittontokyo.com/en/'
};
gallery['ARCHI-DEPOT Museum'] = {
	latlng: [35.620988,139.748830],
	address: 'Terada soko, 2-6-10, Higashi Shinagawa, Tokyo',
	url:'http://archi-depot.com/'
};
gallery['Tokyo Metropolitan Teien Art Museum'] = {
	latlng: [35.635753,139.720453],
	address:'5−21-9, Shirokanedai, Minato-ku, Tokyo',
	url: 'http://www.teien-art-museum.ne.jp/en/'
};
gallery['Aoyama Meguro'] = {
	latlng: [35.6507662,139.6968979],
	address:'2-30-6 Kamimeguro Meguroku Tokyo',
	url: 'http://aoyamameguro.com/en'
};
gallery['Maison Hermes'] = {
	latlng: [35.6688001,139.7286596],
	address:'5-4-1 Ginza, Chuo-ku, Tokyo',
	url: 'http://www.maisonhermes.jp/ginza/le-forum/'
};
gallery['Mori Art Museum'] = {
	latlng: [35.660556,139.729167],
	address:'Roppongi Hills Mori Tower, 6-10-1 Roppongi, Minato-ku, Tokyo',
	url: 'http://www.mori.art.museum/eng/'
};
gallery['The National Museum of Modern Art'] = {
	latlng: [35.690543,139.754693],
	address:'3-1 Kitanomaru Park, Chiyoda-ku, Tokyo, 1028322',
	url: 'http://www.momat.go.jp/english/'
};
gallery['Nezu Museum'] ={
	latlng: [35.662161,139.717566],
	address:'6-5-1 Minami Aoyama, Minato-ku, Tokyo',
	url: 'http://www.nezu-muse.or.jp/en/about/index.html'
};
gallery['SCAI THE BATHHOUSE'] = {
	latlng: [35.721775,139.770496],
	address:'6-1-23 Yanaka, Taito-Ku, Tokyo',
	url:'http://www.scaithebathhouse.com/'
};
gallery['Taka Ishii Gallery'] = {
	latlng: [35.664122,139.729426],
	address:'6-5-24 3F Roppongi Minato-ku Tokyo #106-0032',
	url: 'http://www.takaishiigallery.com/en/'
};
gallery['WAKO WORKS OF ART'] = {
 	latlng: [35.661867,139.731351],
	address:'Piramide Bldg. 3F, 6-6-9 Roppongi, Minato-ku, Tokyo',
	url: 'http://www.wako-art.jp/top.php'
};
gallery['Watarium Museum']= {
 	latlng: [35.670668,139.713372],
	address:'3-7-6 Jingumae, Shibuya-ku, Tokyo',
	url: 'http://www.watarium.co.jp/'
};

<|endoftext|>