text:
;(function() {

    var _makeConnectionDragHandler = function(placeholder, _jsPlumb) {
        var stopped = false;
        return {
            drag : function() {
                if (stopped) {
                    stopped = false;
                    return true;
                }
                var _ui = jsPlumb.CurrentLibrary.getUIPosition(arguments, _jsPlumb.getZoom());

                if (placeholder.element) {
                    jsPlumb.CurrentLibrary.setOffset(placeholder.element, _ui);
                    _jsPlumb.repaint(placeholder.element, _ui);
                }
            },
            stopDrag : function() {
                stopped = true;
            }
        };
    };

    //
    // creates a placeholder div for dragging purposes, adds it to the DOM, and pre-computes its offset.
    //
    var _makeDraggablePlaceholder = function(placeholder, parent, _jsPlumb) {
        var n = document.createElement("div");
        n.style.position = "absolute";
        var placeholderDragElement = jsPlumb.CurrentLibrary.getElementObject(n);
        jsPlumb.CurrentLibrary.appendElement(n, parent);
        var id = _jsPlumb.getId(placeholderDragElement);
        _jsPlumb.updateOffset( { elId : id });
        // create and assign an id, and initialize the offset.
        placeholder.id = id;
        placeholder.element = placeholderDragElement;
    };

    var _makeFloatingEndpoint = function(paintStyle, referenceAnchor, endpoint, referenceCanvas, sourceElement, _jsPlumb, _newEndpoint) {
        var floatingAnchor = new jsPlumb.FloatingAnchor( { reference : referenceAnchor, referenceCanvas : referenceCanvas, jsPlumbInstance:_jsPlumb });
        //setting the scope here should not be the way to fix that mootools issue.  it should be fixed by not
        // adding the floating endpoint as a droppable.  that makes more sense anyway!
        return _newEndpoint({ paintStyle : paintStyle, endpoint : endpoint, anchor : floatingAnchor, source : sourceElement, scope:"__floating" });
    };

    jsPlumb.Endpoint = function(params) {
        var self = this,
            _jsPlumb = params["_jsPlumb"],
            jpcl = jsPlumb.CurrentLibrary,
            _att = jpcl.getAttribute,
            _gel = jpcl.getElementObject,
            _ju = jsPlumbUtil,
            _getOffset = jpcl.getOffset,
            _newConnection = params.newConnection,
            _newEndpoint = params.newEndpoint,
            _finaliseConnection = params.finaliseConnection,
            _fireDetachEvent = params.fireDetachEvent,
            floatingConnections = params.floatingConnections;

        self.idPrefix = "_jsplumb_e_";
        self.defaultLabelLocation = [ 0.5, 0.5 ];
        self.defaultOverlayKeys = ["Overlays", "EndpointOverlays"];
        this.parent = params.parent;
        overlayCapableJsPlumbUIComponent.apply(this, arguments);
        params = params || {};

// TYPE

        this.getTypeDescriptor = function() { return "endpoint"; };
        this.getDefaultType = function() {
            return {
                parameters:{},
                scope:null,
                maxConnections:self._jsPlumb.Defaults.MaxConnections,
                paintStyle:self._jsPlumb.Defaults.EndpointStyle || jsPlumb.Defaults.EndpointStyle,
                endpoint:self._jsPlumb.Defaults.Endpoint || jsPlumb.Defaults.Endpoint,
                hoverPaintStyle:self._jsPlumb.Defaults.EndpointHoverStyle || jsPlumb.Defaults.EndpointHoverStyle,
                overlays:self._jsPlumb.Defaults.EndpointOverlays || jsPlumb.Defaults.EndpointOverlays,
                connectorStyle:params.connectorStyle,
                connectorHoverStyle:params.connectorHoverStyle,
                connectorClass:params.connectorClass,
                connectorHoverClass:params.connectorHoverClass,
                connectorOverlays:params.connectorOverlays,
                connector:params.connector,
                connectorTooltip:params.connectorTooltip
            };
        };
        var superAt = this.applyType;
        this.applyType = function(t, doNotRepaint) {
            superAt(t, doNotRepaint);
            if (t.maxConnections != null) _maxConnections = t.maxConnections;
            if (t.scope) self.scope = t.scope;
            self.connectorStyle = t.connectorStyle;
            self.connectorHoverStyle = t.connectorHoverStyle;
            self.connectorOverlays = t.connectorOverlays;
            self.connector = t.connector;
            self.connectorTooltip = t.connectorTooltip;
            self.connectionType = t.connectionType;
            self.connectorClass = t.connectorClass;
            self.connectorHoverClass = t.connectorHoverClass;
        };
// END TYPE

        var visible = true, __enabled = !(params.enabled === false);

        this.isVisible = function() { return visible; };
        this.setVisible = function(v, doNotChangeConnections, doNotNotifyOtherEndpoint) {
            visible = v;
            if (self.canvas) self.canvas.style.display = v ? "block" : "none";
            self[v ? "showOverlays" : "hideOverlays"]();
            if (!doNotChangeConnections) {
                for (var i = 0; i < self.connections.length; i++) {
                    self.connections[i].setVisible(v);
                    if (!doNotNotifyOtherEndpoint) {
                        var oIdx = self === self.connections[i].endpoints[0] ? 1 : 0;
                        // only change the other endpoint if this is its only connection.
                        if (self.connections[i].endpoints[oIdx].connections.length == 1) self.connections[i].endpoints[oIdx].setVisible(v, true, true);
                    }
                }
            }
        };

        /*
            Function: isEnabled
            Returns whether or not the Endpoint is enabled for drag/drop connections.
        */
        this.isEnabled = function() { return __enabled; };

        /*
            Function: setEnabled
            Sets whether or not the Endpoint is enabled for drag/drop connections.

            Parameters:
                enabled - whether or not the Endpoint is enabled.
        */
        this.setEnabled = function(e) { __enabled = e; };

        var _element = params.source,  _uuid = params.uuid, floatingEndpoint = null,  inPlaceCopy = null;
        if (_uuid) params.endpointsByUUID[_uuid] = self;
        var _elementId = _att(_element, "id");
        this.elementId = _elementId;
        this.element = _element;

        self.setElementId = function(_elId) {
            _elementId = _elId;
            self.elementId = _elId;
            self.anchor.elementId = _elId
        };

        self.setReferenceElement = function(_el) {
            _element = _el;
            self.element = _el;
        };

        var _connectionCost = params.connectionCost;
        this.getConnectionCost = function() { return _connectionCost; };
        this.setConnectionCost = function(c) {
            _connectionCost = c;
        };

        var _connectionsDirected = params.connectionsDirected;
        this.areConnectionsDirected = function() { return _connectionsDirected; };
        this.setConnectionsDirected = function(b) { _connectionsDirected = b; };

        self.anchor = params.anchor ? _jsPlumb.makeAnchor(params.anchor, _elementId, _jsPlumb) : params.anchors ? _jsPlumb.makeAnchor(params.anchors, _elementId, _jsPlumb) : _jsPlumb.makeAnchor(_jsPlumb.Defaults.Anchor || "TopCenter", _elementId, _jsPlumb);

        // ANCHOR MANAGER
        if (!params._transient) // in place copies, for example, are transient.  they will never need to be retrieved during a paint cycle, because they dont move, and then they are deleted.
            _jsPlumb.anchorManager.add(self, _elementId);

        var _endpoint = null, originalEndpoint = null;
        this.setEndpoint = function(ep) {
            var endpointArgs = {
                _jsPlumb:self._jsPlumb,
                cssClass:params.cssClass,
                parent:params.parent,
                container:params.container,
                tooltip:params.tooltip,
                connectorTooltip:params.connectorTooltip,
                endpoint:self
            };
            if (_ju.isString(ep))
                _endpoint = new jsPlumb.Endpoints[_jsPlumb.getRenderMode()][ep](endpointArgs);
            else if (_ju.isArray(ep)) {
                endpointArgs = _ju.merge(ep[1], endpointArgs);
                _endpoint = new jsPlumb.Endpoints[_jsPlumb.getRenderMode()][ep[0]](endpointArgs);
            }
            else {
                _endpoint = ep.clone();
            }

            // assign a clone function using a copy of endpointArgs. this is used when a drag starts: the endpoint that was dragged is cloned,
            // and the clone is left in its place while the original one goes off on a magical journey.
            // the copy is to get around a closure problem, in which endpointArgs ends up getting shared by
            // the whole world.
            var argsForClone = jsPlumb.extend({}, endpointArgs);
            _endpoint.clone = function() {
                var o = new Object();
                _endpoint.constructor.apply(o, [argsForClone]);
                return o;
            };

            self.endpoint = _endpoint;
            self.type = self.endpoint.type;
        };

        this.setEndpoint(params.endpoint || _jsPlumb.Defaults.Endpoint || jsPlumb.Defaults.Endpoint || "Dot");
        originalEndpoint = _endpoint;

        // override setHover to pass it down to the underlying endpoint
        var _sh = self.setHover;
        self.setHover = function() {
            self.endpoint.setHover.apply(self.endpoint, arguments);
            _sh.apply(self, arguments);
        };
        // endpoint delegates to first connection for hover, if there is one.
        var internalHover = function(state) {
          if (self.connections.length > 0)
            self.connections[0].setHover(state, false);
          else
            self.setHover(state);
        };

        // bind listeners from endpoint to self, with the internal hover function defined above.
        self.bindListeners(self.endpoint, self, internalHover);

        this.setPaintStyle(params.paintStyle ||
                           params.style ||
                           _jsPlumb.Defaults.EndpointStyle ||
                           jsPlumb.Defaults.EndpointStyle, true);
        this.setHoverPaintStyle(params.hoverPaintStyle ||
                                _jsPlumb.Defaults.EndpointHoverStyle ||
                                jsPlumb.Defaults.EndpointHoverStyle, true);
        this.paintStyleInUse = this.getPaintStyle();
        var originalPaintStyle = this.getPaintStyle();
        this.connectorStyle = params.connectorStyle;
        this.connectorHoverStyle = params.connectorHoverStyle;
        this.connectorOverlays = params.connectorOverlays;
        this.connector = params.connector;
        this.connectorTooltip = params.connectorTooltip;
        this.connectorClass = params.connectorClass;
        this.connectorHoverClass = params.connectorHoverClass;
        this.isSource = params.isSource || false;
        this.isTarget = params.isTarget || false;

        var _maxConnections = params.maxConnections || _jsPlumb.Defaults.MaxConnections; // maximum number of connections this endpoint can be the source of.

        this.getAttachedElements = function() {
            return self.connections;
        };

        this.canvas = this.endpoint.canvas;
        this.connections = params.connections || [];
        this.connectorPointerEvents = params["connector-pointer-events"];

        this.scope = params.scope || _jsPlumb.getDefaultScope();
        this.connectionType = params.connectionType;
        this.timestamp = null;
        self.reattachConnections = params.reattach || _jsPlumb.Defaults.ReattachConnections;
        self.connectionsDetachable = _jsPlumb.Defaults.ConnectionsDetachable;
        if (params.connectionsDetachable === false || params.detachable === false)
            self.connectionsDetachable = false;
        var dragAllowedWhenFull = params.dragAllowedWhenFull || true;

        if (params.onMaxConnections)
            self.bind("maxConnections", params.onMaxConnections);

        this.computeAnchor = function(params) {
            return self.anchor.compute(params);
        };

        this.addConnection = function(connection) {
            self.connections.push(connection);
        };
        this.detach = function(connection, ignoreTarget, forceDetach, fireEvent, originalEvent) {
            var idx = _ju.findWithFunction(self.connections, function(c) { return c.id == connection.id}),
                actuallyDetached = false;
            fireEvent = (fireEvent !== false);
            if (idx >= 0) {
                // 1. does the connection have a before detach (note this also checks jsPlumb's bound
                // detach handlers; but then Endpoint's check will, too, hmm.)
                if (forceDetach || connection._forceDetach || connection.isDetachable() || connection.isDetachAllowed(connection)) {
                    // get the target endpoint
                    var t = connection.endpoints[0] == self ? connection.endpoints[1] : connection.endpoints[0];
                    // it would be nice to check with both endpoints that it is ok to detach. but
                    // for this we'll have to get a bit fancier: right now if you use the same beforeDetach
                    // interceptor for two endpoints (which is kind of common, because it's part of the
                    // endpoint definition), then it gets fired twice.  so in fact we need to loop through
                    // each beforeDetach and see if it returns false, at which point we exit.  but if it
                    // returns true, we have to check the next one.  however we need to track which ones
                    // have already been run, and not run them again.
                    if (forceDetach || connection._forceDetach || (self.isDetachAllowed(connection) /*&& t.isDetachAllowed(connection)*/)) {

                        self.connections.splice(idx, 1);

                        // this avoids a circular loop
                        if (!ignoreTarget) {

                            t.detach(connection, true, forceDetach);
                            // check connection to see if we want to delete the endpoints associated with it.
                            // we only detach those that have just this connection; this scenario is most
                            // likely if we got to this bit of code because it is set by the methods that
                            // create their own endpoints, like .connect or .makeTarget. the user is
                            // not likely to have interacted with those endpoints.
                            if (connection.endpointsToDeleteOnDetach){
                                for (var i = 0; i < connection.endpointsToDeleteOnDetach.length; i++) {
                                    var cde = connection.endpointsToDeleteOnDetach[i];
                                    if (cde && cde.connections.length == 0)
                                        _jsPlumb.deleteEndpoint(cde);
                                }
                            }
                        }
                        _ju.removeElements(connection.getConnector().getDisplayElements(), connection.parent);
                        _ju.removeWithFunction(params.connectionsByScope[connection.scope], function(c) {
                            return c.id == connection.id;
                        });
                        actuallyDetached = true;
                        var doFireEvent = (!ignoreTarget && fireEvent)
                        _fireDetachEvent(connection, doFireEvent, originalEvent);
                    }
                }
            }
            return actuallyDetached;
        };

        this.detachAll = function(fireEvent, originalEvent) {
            while (self.connections.length > 0) {
                self.detach(self.connections[0], false, true, fireEvent, originalEvent);
            }
        };

        this.detachFrom = function(targetEndpoint, fireEvent, originalEvent) {
            var c = [];
            for ( var i = 0; i < self.connections.length; i++) {
                if (self.connections[i].endpoints[1] == targetEndpoint
                        || self.connections[i].endpoints[0] == targetEndpoint) {
                    c.push(self.connections[i]);
                }
            }
            for ( var i = 0; i < c.length; i++) {
                if (self.detach(c[i], false, true, fireEvent, originalEvent))
                    c[i].setHover(false, false);
            }
        };

        this.detachFromConnection = function(connection) {
            var idx =  _ju.findWithFunction(self.connections, function(c) { return c.id == connection.id});
            if (idx >= 0) {
                self.connections.splice(idx, 1);
            }
        };

        this.getElement = function() {
            return _element;
        };

        this.setElement = function(el, container) {

            // TODO possibly have this object take charge of moving the UI components into the appropriate
            // parent.  this is used only by makeSource right now, and that function takes care of
            // moving the UI bits and pieces.  however it would s
            var parentId = _jsPlumb.getId(el);
            // remove the endpoint from the list for the current endpoint's element
            _ju.removeWithFunction(params.endpointsByElement[self.elementId], function(e) {
                return e.id == self.id;
            });
            _element = _gel(el);
            _elementId = _jsPlumb.getId(_element);
            self.elementId = _elementId;
            // need to get the new parent now
            var newParentElement = params.getParentFromParams({source:parentId, container:container}),
            curParent = jpcl.getParent(self.canvas);
            jpcl.removeElement(self.canvas, curParent);
            jpcl.appendElement(self.canvas, newParentElement);

            // now move connection(s)...i would expect there to be only one but we will iterate.
            for (var i = 0; i < self.connections.length; i++) {
                self.connections[i].moveParent(newParentElement);
                self.connections[i].sourceId = _elementId;
                self.connections[i].source = _element;
            }
            _ju.addToList(params.endpointsByElement, parentId, self);
            //_jsPlumb.repaint(parentId);

        };

        this.getUuid = function() {
            return _uuid;
        };
        /**
         * private but must be exposed.
         */
        this.makeInPlaceCopy = function() {
            var loc = self.anchor.getCurrentLocation(self),
                o = self.anchor.getOrientation(self),
                inPlaceAnchor = {
                    compute:function() { return [ loc[0], loc[1] ]},
                    getCurrentLocation : function() { return [ loc[0], loc[1] ]},
                    getOrientation:function() { return o; }
                };

            return _newEndpoint( {
                anchor : inPlaceAnchor,
                source : _element,
                paintStyle : this.getPaintStyle(),
                endpoint : params.hideOnDrag ? "Blank" : _endpoint,
                _transient:true,
                scope:self.scope
            });
        };

        this.isConnectedTo = function(endpoint) {
            var found = false;
            if (endpoint) {
                for ( var i = 0; i < self.connections.length; i++) {
                    if (self.connections[i].endpoints[1] == endpoint) {
                        found = true;
                        break;
                    }
                }
            }
            return found;
        };

        /**
         * private but needs to be exposed.
         */
        this.isFloating = function() {
            return floatingEndpoint != null;
        };

        /**
         * returns a connection from the pool; used when dragging starts.  just gets the head of the array if it can.
         */
        this.connectorSelector = function() {
            var candidate = self.connections[0];
            if (self.isTarget && candidate) return candidate;
            else {
                return (self.connections.length < _maxConnections) || _maxConnections == -1 ? null : candidate;
            }
        };

        this.isFull = function() {
            return !(self.isFloating() || _maxConnections < 1 || self.connections.length < _maxConnections);
        };

        this.setDragAllowedWhenFull = function(allowed) {
            dragAllowedWhenFull = allowed;
        };

        this.setStyle = self.setPaintStyle;

        /**
         * a deep equals check. everything must match, including the anchor,
         * styles, everything. TODO: finish Endpoint.equals
         */
        this.equals = function(endpoint) {
            return this.anchor.equals(endpoint.anchor);
        };

        // a helper function that tries to find a connection to the given element, and returns it if so. if elementWithPrecedence is null,
        // or no connection to it is found, we return the first connection in our list.
        var findConnectionToUseForDynamicAnchor = function(elementWithPrecedence) {
            var idx = 0;
            if (elementWithPrecedence != null) {
                for (var i = 0; i < self.connections.length; i++) {
                    if (self.connections[i].sourceId == elementWithPrecedence || self.connections[i].targetId == elementWithPrecedence) {
                        idx = i;
                        break;
                    }
                }
            }

            return self.connections[idx];
        };

        this.paint = function(params) {
            params = params || {};
            var timestamp = params.timestamp, recalc = !(params.recalc === false);
            if (!timestamp || self.timestamp !== timestamp) {
                var info = _jsPlumb.updateOffset({ elId:_elementId, timestamp:timestamp, recalc:recalc });
                var xy = params.offset ? params.offset.o : info.o;
                if(xy) {
                    var ap = params.anchorPoint,connectorPaintStyle = params.connectorPaintStyle;
                    if (ap == null) {
                        var wh = params.dimensions || info.s;
                        if (xy == null || wh == null) {
                            info = _jsPlumb.updateOffset( { elId : _elementId, timestamp : timestamp });
                            xy = info.o;
                            wh = info.s;
                        }
                        var anchorParams = { xy : [ xy.left, xy.top ], wh : wh, element : self, timestamp : timestamp };
                        if (recalc && self.anchor.isDynamic && self.connections.length > 0) {
                            var c = findConnectionToUseForDynamicAnchor(params.elementWithPrecedence),
                                oIdx = c.endpoints[0] == self ? 1 : 0,
                                oId = oIdx == 0 ? c.sourceId : c.targetId,
                                oInfo = _jsPlumb.getCachedData(oId),
                                oOffset = oInfo.o, oWH = oInfo.s;
                            anchorParams.txy = [ oOffset.left, oOffset.top ];
                            anchorParams.twh = oWH;
                            anchorParams.tElement = c.endpoints[oIdx];
                        }
                        ap = self.anchor.compute(anchorParams);
                    }

                    _endpoint.compute(ap, self.anchor.getOrientation(self), self.paintStyleInUse, connectorPaintStyle || self.paintStyleInUse);
                    _endpoint.paint(self.paintStyleInUse, self.anchor);
                    self.timestamp = timestamp;

                    // paint overlays
                    for ( var i = 0; i < self.overlays.length; i++) {
                        var o = self.overlays[i];
                        if (o.isVisible()) {
                            self.overlayPlacements[i] = o.draw(self.endpoint, self.paintStyleInUse);
                            o.paint(self.overlayPlacements[i]);
                        }
                    }
                }
            }
        };

        this.repaint = this.paint;

        // is this a connection source? we make it draggable and have the
        // drag listener maintain a connection with a floating endpoint.
        if (jpcl.isDragSupported(_element)) {
            var placeholderInfo = { id:null, element:null },
                jpc = null,
                existingJpc = false,
                existingJpcParams = null,
                _dragHandler = _makeConnectionDragHandler(placeholderInfo, _jsPlumb);

            var start = function() {
            // drag might have started on an endpoint that is not actually a source, but which has
            // one or more connections.
                jpc = self.connectorSelector();
                var _continue = true;
                // if not enabled, return
                if (!self.isEnabled()) _continue = false;
                // if no connection and we're not a source, return.
                if (jpc == null && !params.isSource) _continue = false;
                // otherwise if we're full and not allowed to drag, also return false.
                if (params.isSource && self.isFull() && !dragAllowedWhenFull) _continue = false;
                // if the connection was setup as not detachable or one of its endpoints
                // was setup as connectionsDetachable = false, or Defaults.ConnectionsDetachable
                // is set to false...
                if (jpc != null && !jpc.isDetachable()) _continue = false;

                if (_continue === false) {
                    // this is for mootools and yui. returning false from this causes jquery to stop drag.
                    // the events are wrapped in both mootools and yui anyway, but i don't think returning
                    // false from the start callback would stop a drag.
                    if (jpcl.stopDrag) jpcl.stopDrag();
                    _dragHandler.stopDrag();
                    return false;
                }

                // if we're not full but there was a connection, make it null. we'll create a new one.
                if (jpc && !self.isFull() && params.isSource) jpc = null;

                _jsPlumb.updateOffset( { elId : _elementId });
                inPlaceCopy = self.makeInPlaceCopy();
                inPlaceCopy.referenceEndpoint = self;
                inPlaceCopy.paint();

                _makeDraggablePlaceholder(placeholderInfo, self.parent, _jsPlumb);

                // set the offset of this div to be where 'inPlaceCopy' is, to start with.
                // TODO merge this code with the code in both Anchor and FloatingAnchor, because it
                // does the same stuff.
                var ipcoel = _gel(inPlaceCopy.canvas),
                    ipco = _getOffset(ipcoel, _jsPlumb),
                    po = _jsPlumb.adjustForParentOffsetAndScroll([ipco.left, ipco.top], inPlaceCopy.canvas),
                    canvasElement = _gel(self.canvas);

                jpcl.setOffset(placeholderInfo.element, {left:po[0], top:po[1]});

                // when using makeSource and a parent, we first draw the source anchor on the source element, then
                // move it to the parent.  note that this happens after drawing the placeholder for the
                // first time.
                if (self.parentAnchor) self.anchor = _jsPlumb.makeAnchor(self.parentAnchor, self.elementId, _jsPlumb);

                // store the id of the dragging div and the source element. the drop function will pick these up.
                jpcl.setAttribute(canvasElement, "dragId", placeholderInfo.id);
                jpcl.setAttribute(canvasElement, "elId", _elementId);

                // create a floating endpoint.
                // here we test to see if a dragProxy was specified in this endpoint's constructor params, and
                // if so, we create that endpoint instead of cloning ourselves.
                //if (params.proxy) {
            /*		var floatingAnchor = new jsPlumb.FloatingAnchor( { reference : self.anchor, referenceCanvas : self.canvas });

                    floatingEndpoint = _newEndpoint({
                        paintStyle : params.proxy.paintStyle,
                        endpoint : params.proxy.endpoint,
                        anchor : floatingAnchor,
                        source : placeholderInfo.element,
                        scope:"__floating"
                    });

                    //$(self.canvas).hide();
                    */
                    //self.setPaintStyle(params.proxy.paintStyle);
                    // if we do this, we have to cleanup the old one. like just remove its display parts
                    //self.setEndpoint(params.proxy.endpoint);

                //}
            //	else {
                    floatingEndpoint = _makeFloatingEndpoint(self.getPaintStyle(), self.anchor, _endpoint, self.canvas, placeholderInfo.element, _jsPlumb, _newEndpoint);

                    self.canvas.style.visibility = "hidden";
            //	}

                if (jpc == null) {
                    self.anchor.locked = true;
                    self.setHover(false, false);
                    // create a connection. one end is this endpoint, the other is a floating endpoint.
                    jpc = _newConnection({
                        sourceEndpoint : self,
                        targetEndpoint : floatingEndpoint,
                        source : self.endpointWillMoveTo || _element,  // for makeSource with parent option.  ensure source element is represented correctly.
                        target : placeholderInfo.element,
                        anchors : [ self.anchor, floatingEndpoint.anchor ],
                        paintStyle : params.connectorStyle, // this can be null. Connection will use the default.
                        hoverPaintStyle:params.connectorHoverStyle,
                        connector : params.connector, // this can also be null. Connection will use the default.
                        overlays : params.connectorOverlays,
                        type:self.connectionType,
                        cssClass:self.connectorClass,
                        hoverClass:self.connectorHoverClass
                    });
                    // fire an event that informs that a connection is being dragged
                    _jsPlumb.fire("connectionDrag", jpc);

                } else {
                    existingJpc = true;
                    jpc.setHover(false);
                    // if existing connection, allow to be dropped back on the source endpoint (issue 51).
                    _initDropTarget(ipcoel, false, true);
                    // new anchor idx
                    var anchorIdx = jpc.endpoints[0].id == self.id ? 0 : 1;
                    jpc.floatingAnchorIndex = anchorIdx;					// save our anchor index as the connection's floating index.
                    self.detachFromConnection(jpc);							// detach from the connection while dragging is occurring.

                    // store the original scope (issue 57)
                    var dragScope = jsPlumb.CurrentLibrary.getDragScope(canvasElement);
                    jpcl.setAttribute(canvasElement, "originalScope", dragScope);
                    // now we want to get this endpoint's DROP scope, and set it for now: we can only be dropped on drop zones
                    // that have our drop scope (issue 57).
                    var dropScope = jpcl.getDropScope(canvasElement);
                    jpcl.setDragScope(canvasElement, dropScope);

                    // now we replace ourselves with the temporary div we created above:
                    if (anchorIdx == 0) {
                        existingJpcParams = [ jpc.source, jpc.sourceId, i, dragScope ];
                        jpc.source = placeholderInfo.element;
                        jpc.sourceId = placeholderInfo.id;
                    } else {
                        existingJpcParams = [ jpc.target, jpc.targetId, i, dragScope ];
                        jpc.target = placeholderInfo.element;
                        jpc.targetId = placeholderInfo.id;
                    }

                    // lock the other endpoint; if it is dynamic it will not move while the drag is occurring.
                    jpc.endpoints[anchorIdx == 0 ? 1 : 0].anchor.locked = true;
                    // store the original endpoint and assign the new floating endpoint for the drag.
                    jpc.suspendedEndpoint = jpc.endpoints[anchorIdx];
                    jpc.suspendedEndpoint.setHover(false);
                    floatingEndpoint.referenceEndpoint = jpc.suspendedEndpoint;
                    jpc.endpoints[anchorIdx] = floatingEndpoint;

                    // fire an event that informs that a connection is being dragged
                    _jsPlumb.fire("connectionDrag", jpc);

                }
                // register it and register connection on it.
                floatingConnections[placeholderInfo.id] = jpc;
                _jsPlumb.anchorManager.addFloatingConnection(placeholderInfo.id, jpc);
                floatingEndpoint.addConnection(jpc);
                // only register for the target endpoint; we will not be dragging the source at any time
                // before this connection is either discarded or made into a permanent connection.
                _ju.addToList(params.endpointsByElement, placeholderInfo.id, floatingEndpoint);
                // tell jsplumb about it
                _jsPlumb.currentlyDragging = true;
            };

            var dragOptions = params.dragOptions || {},
                defaultOpts = jsPlumb.extend( {}, jpcl.defaultDragOptions),
                startEvent = jpcl.dragEvents["start"],
                stopEvent = jpcl.dragEvents["stop"],
                dragEvent = jpcl.dragEvents["drag"];

            dragOptions = jsPlumb.extend(defaultOpts, dragOptions);
            dragOptions.scope = dragOptions.scope || self.scope;
            dragOptions[startEvent] = _jsPlumb.wrap(dragOptions[startEvent], start);
            // extracted drag handler function so can be used by makeSource
            dragOptions[dragEvent] = _jsPlumb.wrap(dragOptions[dragEvent], _dragHandler.drag);
            dragOptions[stopEvent] = _jsPlumb.wrap(dragOptions[stopEvent],
                function() {
                    var originalEvent = jpcl.getDropEvent(arguments);
                    _ju.removeWithFunction(params.endpointsByElement[placeholderInfo.id], function(e) {
                        return e.id == floatingEndpoint.id;
                    });
                    _ju.removeElement(inPlaceCopy.canvas, _element);
                    _jsPlumb.anchorManager.clearFor(placeholderInfo.id);
                    var idx = jpc.floatingAnchorIndex == null ? 1 : jpc.floatingAnchorIndex;
                    jpc.endpoints[idx == 0 ? 1 : 0].anchor.locked = false;

                // commented out pending decision on drag proxy stuff.
                //	self.setPaintStyle(originalPaintStyle); // reset to original; may have been changed by drag proxy.

                    if (jpc.endpoints[idx] == floatingEndpoint) {
                        // if the connection was an existing one:
                        if (existingJpc && jpc.suspendedEndpoint) {
                            // fix for issue35, thanks Sylvain Gizard: when firing the detach event make sure the
                            // floating endpoint has been replaced.
                            if (idx == 0) {
                                jpc.source = existingJpcParams[0];
                                jpc.sourceId = existingJpcParams[1];
                            } else {
                                jpc.target = existingJpcParams[0];
                                jpc.targetId = existingJpcParams[1];
                            }

                            // restore the original scope (issue 57)
                            jpcl.setDragScope(existingJpcParams[2], existingJpcParams[3]);
                            jpc.endpoints[idx] = jpc.suspendedEndpoint;
                            if (jpc.isReattach() || jpc._forceReattach || jpc._forceDetach || !jpc.endpoints[idx == 0 ? 1 : 0].detach(jpc, false, false, true, originalEvent)) {
                                jpc.setHover(false);
                                jpc.floatingAnchorIndex = null;
                                jpc.suspendedEndpoint.addConnection(jpc);
                                _jsPlumb.repaint(existingJpcParams[1]);
                            }
                            jpc._forceDetach = null;
                            jpc._forceReattach = null;
                        } else {
                            // TODO this looks suspiciously kind of like an Endpoint.detach call too.
                            // i wonder if this one should post an event though.  maybe this is good like this.
                            _ju.removeElements(jpc.getConnector().getDisplayElements(), self.parent);
                            self.detachFromConnection(jpc);
                        }
                    }

                    // remove floating endpoint _after_ checking beforeDetach
                    _ju.removeElements( [ placeholderInfo.element[0], floatingEndpoint.canvas ], _element); // TODO: clean up the connection canvas (if the user aborted)
                    _jsPlumb.dragManager.elementRemoved(floatingEndpoint.elementId);
                    self.canvas.style.visibility = "visible";

                    self.anchor.locked = false;
                    self.paint({recalc:false});

                    _jsPlumb.fire("connectionDragStop", jpc);

                    jpc = null;
                    inPlaceCopy = null;
                    delete params.endpointsByElement[floatingEndpoint.elementId];
                    floatingEndpoint.anchor = null;
                    floatingEndpoint = null;
                    _jsPlumb.currentlyDragging = false;

                });

            var i = _gel(self.canvas);
            jpcl.initDraggable(i, dragOptions, true, _jsPlumb);
        }

        // pulled this out into a function so we can reuse it for the inPlaceCopy canvas; you can now drop detached connections
        // back onto the endpoint you detached it from.
        var _initDropTarget = function(canvas, forceInit, isTransient, endpoint) {
            if ((params.isTarget || forceInit) && jpcl.isDropSupported(_element)) {
                var dropOptions = params.dropOptions || _jsPlumb.Defaults.DropOptions || jsPlumb.Defaults.DropOptions;
                dropOptions = jsPlumb.extend( {}, dropOptions);
                dropOptions.scope = dropOptions.scope || self.scope;
                var dropEvent = jpcl.dragEvents['drop'],
                    overEvent = jpcl.dragEvents['over'],
                    outEvent = jpcl.dragEvents['out'],
                    drop = function() {

                        var originalEvent = jpcl.getDropEvent(arguments),
                            draggable = _gel(jpcl.getDragObject(arguments)),
                            id = _att(draggable, "dragId"),
                            elId = _att(draggable, "elId"),
                            scope = _att(draggable, "originalScope"),
                            jpc = floatingConnections[id];

                        // if this is a drop back where the connection came from, mark it force rettach and
                        // return; the stop handler will reattach. without firing an event.
                        var redrop = jpc.suspendedEndpoint && (jpc.suspendedEndpoint.id == self.id ||
                                        self.referenceEndpoint && jpc.suspendedEndpoint.id == self.referenceEndpoint.id) ;
                        if (redrop) {
                            jpc._forceReattach = true;
                            return;
                        }

                        if (jpc != null) {
                            var idx = jpc.floatingAnchorIndex == null ? 1 : jpc.floatingAnchorIndex, oidx = idx == 0 ? 1 : 0;

                            // restore the original scope if necessary (issue 57)
                            if (scope) jsPlumb.CurrentLibrary.setDragScope(draggable, scope);

                            var endpointEnabled = endpoint != null ? endpoint.isEnabled() : true;

                            if (self.isFull()) {
                                self.fire("maxConnections", {
                                    endpoint:self,
                                    connection:jpc,
                                    maxConnections:_maxConnections
                                }, originalEvent);
                            }

                            if (!self.isFull() && !(idx == 0 && !self.isSource) && !(idx == 1 && !self.isTarget) && endpointEnabled) {
                                var _doContinue = true;

                                // the second check here is for the case that the user is dropping it back
                                // where it came from.
                                if (jpc.suspendedEndpoint && jpc.suspendedEndpoint.id != self.id) {
                                    if (idx == 0) {
                                        jpc.source = jpc.suspendedEndpoint.element;
                                        jpc.sourceId = jpc.suspendedEndpoint.elementId;
                                    } else {
                                        jpc.target = jpc.suspendedEndpoint.element;
                                        jpc.targetId = jpc.suspendedEndpoint.elementId;
                                    }

                                    if (!jpc.isDetachAllowed(jpc) || !jpc.endpoints[idx].isDetachAllowed(jpc) || !jpc.suspendedEndpoint.isDetachAllowed(jpc) || !_jsPlumb.checkCondition("beforeDetach", jpc))
                                        _doContinue = false;
                                }

                                // these have to be set before testing for beforeDrop.
                                if (idx == 0) {
                                    jpc.source = self.element;
                                    jpc.sourceId = self.elementId;
                                } else {
                                    jpc.target = self.element;
                                    jpc.targetId = self.elementId;
                                }

// ------------ wrap the execution path in a function so we can support asynchronous beforeDrop

                                // we want to execute this regardless.
                                var commonFunction = function() {
                                    jpc.floatingAnchorIndex = null;
                                };

                                var continueFunction = function() {
                                    // remove this jpc from the current endpoint
                                    jpc.endpoints[idx].detachFromConnection(jpc);
                                    if (jpc.suspendedEndpoint) jpc.suspendedEndpoint.detachFromConnection(jpc);
                                    jpc.endpoints[idx] = self;
                                    self.addConnection(jpc);

                                    // copy our parameters in to the connection:
                                    var params = self.getParameters();
                                    for (var aParam in params)
                                        jpc.setParameter(aParam, params[aParam]);

                                    if (!jpc.suspendedEndpoint) {
                                        if (params.draggable)
                                            jsPlumb.CurrentLibrary.initDraggable(self.element, dragOptions, true, _jsPlumb);
                                    }
                                    else {
                                        var suspendedElement = jpc.suspendedEndpoint.getElement(), suspendedElementId = jpc.suspendedEndpoint.elementId;
                                        // fire a detach event
                                        _fireDetachEvent({
                                            source : idx == 0 ? suspendedElement : jpc.source,
                                            target : idx == 1 ? suspendedElement : jpc.target,
                                            sourceId : idx == 0 ? suspendedElementId : jpc.sourceId,
                                            targetId : idx == 1 ? suspendedElementId : jpc.targetId,
                                            sourceEndpoint : idx == 0 ? jpc.suspendedEndpoint : jpc.endpoints[0],
                                            targetEndpoint : idx == 1 ? jpc.suspendedEndpoint : jpc.endpoints[1],
                                            connection : jpc
                                        }, true, originalEvent);
                                    }

                                    // finalise will inform the anchor manager and also add to
                                    // connectionsByScope if necessary.
                                    _finaliseConnection(jpc, null, originalEvent);

                                    commonFunction();
                                };

                                var dontContinueFunction = function() {
                                    // otherwise just put it back on the endpoint it was on before the drag.
                                    if (jpc.suspendedEndpoint) {
                                        jpc.endpoints[idx] = jpc.suspendedEndpoint;
                                        jpc.setHover(false);
                                        jpc._forceDetach = true;
                                        if (idx == 0) {
                                            jpc.source = jpc.suspendedEndpoint.element;
                                            jpc.sourceId = jpc.suspendedEndpoint.elementId;
                                        } else {
                                            jpc.target = jpc.suspendedEndpoint.element;
                                            jpc.targetId = jpc.suspendedEndpoint.elementId;;
                                        }
                                        jpc.suspendedEndpoint.addConnection(jpc);

                                        jpc.endpoints[0].repaint();
                                        jpc.repaint();
                                        _jsPlumb.repaint(jpc.sourceId);
                                        jpc._forceDetach = false;
                                    }

                                    commonFunction();
                                };

// --------------------------------------
                                // now check beforeDrop.  this will be available only on Endpoints that are setup to
                                // have a beforeDrop condition (although, secretly, under the hood all Endpoints and
                                // the Connection have them, because they are on jsPlumbUIComponent.  shhh!), because
                                // it only makes sense to have it on a target endpoint.
                                _doContinue = _doContinue && self.isDropAllowed(jpc.sourceId, jpc.targetId, jpc.scope, jpc, self);

                                if (_doContinue) {
                                    continueFunction();
                                }
                                else {
                                    dontContinueFunction();
                                }

                                //commonFunction();
                            }
                            _jsPlumb.currentlyDragging = false;
                            delete floatingConnections[id];
                            _jsPlumb.anchorManager.removeFloatingConnection(id);
                        }
                    };

                dropOptions[dropEvent] = _jsPlumb.wrap(dropOptions[dropEvent], drop);
                dropOptions[overEvent] = _jsPlumb.wrap(dropOptions[overEvent], function() {
                    var draggable = jpcl.getDragObject(arguments),
                        id = _att( _gel(draggable), "dragId"),
                        _jpc = floatingConnections[id];

                    if (_jpc != null) {
                        var idx = _jpc.floatingAnchorIndex == null ? 1 : _jpc.floatingAnchorIndex;
                        // here we should fire the 'over' event if we are a target and this is a new connection,
                        // or we are the same as the floating endpoint.
                        var _cont = (self.isTarget && _jpc.floatingAnchorIndex != 0) || (_jpc.suspendedEndpoint && self.referenceEndpoint && self.referenceEndpoint.id == _jpc.suspendedEndpoint.id);
                        if (_cont)
                            _jpc.endpoints[idx].anchor.over(self.anchor);
                    }
                });
                dropOptions[outEvent] = _jsPlumb.wrap(dropOptions[outEvent], function() {
                    var draggable = jpcl.getDragObject(arguments),
                        id = _att( _gel(draggable), "dragId"),
                        _jpc = floatingConnections[id];

                    if (_jpc != null) {
                        var idx = _jpc.floatingAnchorIndex == null ? 1 : _jpc.floatingAnchorIndex;
                        var _cont = (self.isTarget && _jpc.floatingAnchorIndex != 0) || (_jpc.suspendedEndpoint && self.referenceEndpoint && self.referenceEndpoint.id == _jpc.suspendedEndpoint.id);
                        if (_cont)
                            _jpc.endpoints[idx].anchor.out();
                    }
                });
                jpcl.initDroppable(canvas, dropOptions, true, isTransient);
            }
        };

        // initialise the endpoint's canvas as a drop target.  this will be ignored if the endpoint is not a target or drag is not supported.
        _initDropTarget(_gel(self.canvas), true, !(params._transient || self.anchor.isFloating), self);

         // finally, set type if it was provided
         if (params.type)
            self.addType(params.type, params.data, _jsPlumb.isSuspendDrawing());

        return self;
    };
})();


text:
layout:     post
title:      Mirror trap
date:       2015-07-20
categories: Problem
---
Ever met a geometry problem that doesn't have much to do with geometry ? this is the problem we want to discuss today, [Mirror trap](http://main.edu.pl/en/archive/oi/15/szk) from the 15th Polish Olympiad in Informatics.

The problem gives you a Simple rectilinear polygon whose all sides are covered from the inside with mirrors, asks you to put some laser guns in some corners, some laser detectors in some other corners so that you maximize the number of laser guns complemented with laser detectors,  I suggest that you go read the full problem statement.

Now the first thing you may think about when solving this problem is that it's composed of two parts, first part is knowing which corner B receives a laser beam from a laser gun put at corner A and this seems like a geometry problem, the second part is matching corners together to achieve the maximum number of laser guns complemented with detectors, this seemed like a maximum matching problem on general graphs, which is really tedious to implement.

First lets think about the underlaying graph structure, are those graphs really general ?

If we had a laser originated at A received at B, where will laser originated at B be received ?

Indeed a laser gun placed at B is received at A, after all it will have to travel through the same path but in reverse direction.

![example]({{site.url}}/images/mirror/img_1.png)

Can we have a laser originated at some corner and not end in some other corner ?

To answer this questions we first have to think about the set of points where a laser can hit, notice that :-

* All corner points have integer coordinates.
* Distance travelled between two successive hits $$ P_i,  P_{i+1}$$ in the X direction is equivalent to that travelled in Y direction $$ \lvert X_{i+1} - X_{i} \rvert = \lvert Y_{i+1} - Y_{i} \rvert $$, since the angle of the laser always 45, 135, 225 or 315.

It's easy to show that if the point $$ P_i$$ had integer coordinates then the next point $$ P_{i+1}$$ will also have integer coordinates, since $$ P_{i+1}$$ is either located on a vertical wall or a horizontal wall, lets assume it's vertical (it's X must be integer since the wall must have corners on both it's ends) in this case we have $$ \lvert X_{i+1} - X_{i}\rvert$$ integer thus the difference in Y is also integer, similarly we can show the same for horizontal walls.

thus the set of points where a laser can hit, is the set of all points with integer coordinates on the walls of the polygon, this set is finite and at most 300k as said in the problem's constraints.

For a laser beam originated at a corner  not to end on some other corner, then it has to wander infinitely jumping between those points on the walls and since they are finite then it has to cycle between them, Is this possible ?

![cycle]({{site.url}}/images/mirror/img_2.png)

Of course this is impossible cause this means that we have a point receiving laser beam from two different sources into the same direction, then these two different sources have to be the same point.

This means that each laser beam must start and end in a corner, now we can conclude that the answer is always N/2, since each two corner points are paired with each other, they are also paired with some other wall points, so it's like a graph having a number of connected components, each component has two corner points and some wall points.

Luckily simple rectilinear polygons always have even number of corners, so there's no optimization problem here only the writer has tricked us to think there is, he also said if there's more than one solution return any while the solution is always unique, Remember [Don't trust the writer](https://solveit.quora.com/Strategy-Dont-trust-the-writer).

Back to the geometry problem, how do we figure out which corners pair together ? How do we find the connected components of the graph ?

![decompose]({{site.url}}/images/mirror/img_3.png)

We only need to find the edges of the graph to find the connected components, i.e for each node find which node is next, which node is previous.

We can trace each laser beam, but the constraints are killer here this will never give us a full score.

But one might think would the problem be easier if those rays were vertical and horizontal ? instead of the 45 degreeish rays.

Only one way to find out, rotate the polygon by 45 degrees, However this will introduce floating point numbers, instead we rotate and scale by sqrt(2), making NewX = X - Y, NewY = X + Y.

![rotate]({{site.url}}/images/mirror/img_4.png)

he points sorted by X value, then by Y value, an edge will often occurs between successive points having the same X value.

However there two cases we have to mind while doing the sweep

* Edges that occur outside the polygon should be ignored, this could be done by tracking whether we are inside the polygon or not (usually points alternate us between inside/outside/inside/outside.. the polygon so meeting a new point will often mean that we switch state)
* Handling cases where the ray touch a point but not reflected by this point.

![vertical]({{site.url}}/images/mirror/img_5.png)

Similarly we can find horizontal edges, now that we have the edges of the graph we can find connected components and hence find the solution to the problem.

![horizontal]({{site.url}}/images/mirror/img_6.png)

Now the **question** is How much would this problem change if we removed the integer point restriction and allowed real coordinates, does the start at a corner end at a corner condition still hold ?
Feel free to comment with what you think.

redpajama_set_name: RedPajamaGithub


text:
SET( CMAKE_MODULE_PATH
	${CMAKE_CURRENT_LIST_DIR}
	${CMAKE_MODULE_PATH}
)

INCLUDE_DIRECTORIES( ${WG_TOOLS_SOURCE_DIR}/core )
INCLUDE_DIRECTORIES( ${WG_TOOLS_SOURCE_DIR}/core/lib )

LIST( APPEND BW_LIBRARY_PROJECTS
	#WG Systems
	wgtf_types			core/lib/wg_types
	wgtf_memory			core/lib/wg_memory
	wg_pyscript			core/lib/wg_pyscript

	#NGT Systems
	core_common		        core/lib/core_common
	core_wgtf_app	        core/lib/core_wgtf_app
	core_variant		    core/lib/core_variant
	core_dependency_system	core/lib/core_dependency_system
	core_environment_system	core/lib/core_environment_system
	core_viewport			core/lib/core_viewport
	core_command_system		core/lib/core_command_system
	core_reflection_utils	core/lib/core_reflection_utils
	core_serialization		core/lib/core_serialization
	core_serialization_xml	core/lib/core_serialization_xml
	core_reflection			core/lib/core_reflection
	core_string_utils		core/lib/core_string_utils
	core_object				core/lib/core_object

	#Tools Common
	core_logging				core/lib/core_logging
	core_file_logging			core/lib/core_file_logging
	core_logging_system		    core/lib/core_logging_system
	core_generic_plugin		    core/lib/core_generic_plugin
	core_generic_plugin_manager	core/lib/core_generic_plugin_manager
	core_qt_common			    core/lib/core_qt_common
	core_data_model			    core/lib/core_data_model
	core_data_model_cmds		core/lib/core_data_model_cmds
	core_view_model				core/lib/core_view_model
	core_ui_framework		    core/lib/core_ui_framework
	core_python27				core/lib/core_python27
	core_base_editor			core/lib/core_base_editor
	qt_sharable					core/lib/qt_sharable

	# Interfaces
	common_include				core/interfaces/common_include
	editor						core/interfaces/editor
	core_python_script			core/interfaces/core_python_script
	core_script					core/interfaces/core_script
	core_splash					core/interfaces/core_splash
	version_control				core/interfaces/version_control
)

IF( WG_TOOLS_CORE_BINARY_PROJECTS )
	LIST( APPEND BW_BINARY_PROJECTS
		# Apps
		generic_app			core/app/generic_app
		qt_desktop			core/app/qt_desktop
	)

	IF ( BW_PLATFORM STREQUAL "win64" )
		LIST( APPEND BW_BINARY_PROJECTS
			maya_plugin		    core/app/maya_plugin
		)

		LIST( APPEND BW_PLUGIN_PROJECTS
			plg_maya_adapter    core/plugins/plg_maya_adapter
		)
	ENDIF()
ENDIF()

LIST( APPEND BW_PLUGIN_PROJECTS
	# Plugins
	plg_automation				core/plugins/plg_automation
	plg_reflection				core/plugins/plg_reflection
	plg_command_system			core/plugins/plg_command_system
	plg_environment_system		core/plugins/plg_environment_system
	plg_editor_interaction		core/plugins/plg_editor_interaction
	plg_history_ui				core/plugins/plg_history_ui
	plg_macros_ui				core/plugins/plg_macros_ui
	plg_qt_common				core/plugins/plg_qt_common
	plg_serialization			core/plugins/plg_serialization
	plg_logging_system			core/plugins/plg_logging_system
	plg_idedebug_logger			core/plugins/plg_idedebug_logger
	plg_alert_ui				core/plugins/plg_alert_ui
	plg_file_system				core/plugins/plg_file_system
	plg_perforce				core/plugins/plg_perforce
	plg_panel_manager			core/plugins/plg_panel_manager
	plg_progress_manager		core/plugins/plg_progress_manager
	plg_python27				core/plugins/plg_python27
	plg_curve_editor			core/plugins/plg_curve_editor
	plg_node_editor				core/plugins/plg_node_editor
	plg_custom_ui_themes		core/plugins/plg_custom_ui_themes
	plg_toolbox					core/plugins/plg_toolbox
	plg_grabber_manager			core/plugins/plg_grabber_manager
	plg_logging_ui				core/plugins/plg_logging_ui
)


text:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
<link rel="import" href="../../bower_components/app-route/app-route.html">
<link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html">
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../../bower_components/paper-input/paper-input.html">
<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="../../bower_components/paper-listbox/paper-listbox.html">
<link rel="import" href="../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../bower_components/paper-fab/paper-fab.html">
<link rel="import" href="../../bower_components/paper-radio-group/paper-radio-group.html">
<link rel="import" href="../../bower_components/paper-radio-button/paper-radio-button.html">

<link rel="import" href="../signup-page/presentation-row.html">
<link rel="import" href="../stable-app/stable-behavior.html">
<link rel="import" href="../viewers-page/viewer-row.html">

<link rel="import" href="schedule-table.html">

<dom-module id="schedule-page">
  <template>

    <iron-ajax
      id="ajax"
      url="[[_computeAPI('/presentations')]]"
      method="POST"
      content-type="application/json"
      handle-as="json"
      on-response="_response"
      on-error="_error"></iron-ajax>

    <iron-ajax
      auto
      id="viewersAjax"
      url="[[_computeAPI('/viewers')]]"
      method="GET"
      content-type="application/json"
      handle-as="json"
      params="[[_params(detailsData)]]"
      on-error="__error"
      last-response="{{prePresentationViewers}}"
      ></iron-ajax>

    <app-route
      route="{{route}}"
      pattern="/schedule"
      active="{{active}}"
      ></app-route>
    <app-route
      route="{{route}}"
      pattern="/schedule/:date/:block_id/:presentation_id"
      data="{{detailsData}}"
      active="{{detailsActive}}"
      ></app-route>

    <paper-spinner id="spinner" active class="page-load"></paper-spinner>

    <paper-dialog id="infoDialog">

        <paper-icon-button icon="icons:close" dialog-dismiss></paper-icon-button>

[[infoData.topic]]

Presenter: [[infoData.first_name]] [[infoData.last_name]]

Location: [[_getAttrFromObj(infoData.location_id, 'location_name', locations)]]

Bio:
[[infoData.bio]]

    </paper-dialog>

    <paper-dialog id="editDialog">

        <paper-icon-button icon="icons:close" dialog-dismiss></paper-icon-button>

Add Presentation

        <paper-input label="First Name" value="{{infoData.first_name::input}}"></paper-input>
        <paper-input label="Last Name" value="{{infoData.last_name::input}}"></paper-input>
        <paper-input label="Topic" value="{{infoData.topic::input}}"></paper-input>

          <paper-dropdown-menu label="Date">
            <paper-listbox class="dropdown-content" attr-for-selected="data-id" selected="{{infoData.date}}">
              <template is="dom-repeat" items="[[dates]]">
                <paper-item data-id$="[[item.date]]">[[_parseDate(item.date)]]</paper-item>
              </template>
            </paper-listbox>
          </paper-dropdown-menu>
          <paper-icon-button icon="icons:create" on-tap=""></paper-icon-button>

          <paper-dropdown-menu label="Block">
            <paper-listbox class="dropdown-content" attr-for-selected="data-id" selected="{{infoData.block_id}}">
              <template is="dom-repeat" items="[[blocksArray]]">
                <paper-item data-id$="[[item.block_id]]">[[item.block_name]]</paper-item>
              </template>
            </paper-listbox>

          </paper-dropdown-menu>
          <paper-icon-button icon="icons:create" on-tap=""></paper-icon-button>

          <paper-dropdown-menu label="Location">
            <paper-listbox class="dropdown-content" attr-for-selected="data-id" selected="{{infoData.location_id}}">
              <template is="dom-repeat" items="[[locationsArray]]">
                <paper-item data-id$="[[item.location_id]]">[[item.location_name]]</paper-item>
              </template>
            </paper-listbox>
          </paper-dropdown-menu>
          <paper-icon-button icon="icons:create" on-tap="_addLocation"></paper-icon-button>

        <paper-input label="Admin Code" type="password" value="{{adminCode::input}}"></paper-input>

          <paper-button raised id="confirmButton" class="save" on-tap="_doAddPresentation">Save</paper-button>
          <paper-button raised class="cancel" dialog-dismiss>Cancel</paper-button>

    </paper-dialog>

    <paper-dialog id="newBasicItemDialog">

New [[newBasicItem.name]]

        <paper-input label="[[newBasicItem.name]]" value="{{newBasicItem.value::input}}"></paper-input>

          <paper-button raised class="save" disabled="[[!_computeEnabled(newBasicItem.value)]]" on-tap="_addBasicItem">Create</paper-button>
          <paper-button raised class="cancel" dialog-dismiss>Cancel</paper-button>

    </paper-dialog>
    <template is="dom-if" if="[[mainPageActive]]">

      <paper-material elevation="1">

        <paper-radio-group selected="list">
          <paper-radio-button name="list">List View</paper-radio-button>
          <paper-radio-button name="table" checked="{{tableView}}">Table View</paper-radio-button>
        </paper-radio-group>

      </paper-material>

        <template is="dom-if" if="[[tableView]]">

            <schedule-table
            dates="[[dates]]"
            blocks="[[blocks]]"
            locations="[[locations]]"
            schedule="[[schedule]]"
            presentations="[[presentations]]"
          ></schedule-table>
        </template>

      <template is="dom-if" if="[[!tableView]]">

        <template is="dom-repeat" items="[[dates]]" as="date" id="content" hidden>
          <template is="dom-repeat" items="[[blocksArray]]" as="block">
            <paper-material elevation="1">

[[_parseDate(date.date)]] - [[block.block_name]]

            <template is="dom-repeat" items="[[_filterPresentations(date.date, block.block_id, presentations, schedule)]]" as="presentation">
              <presentation-row
                data="[[presentation]]"
                data-id$="[[presentation.presentation_id]]"
                on-show-info="_showInfo"
                on-goto-presentation="_gotoPresentation"
                locations="[[locations]]"
                go-to-viewers
                date="[[date.date]]"
                block-id="[[block.block_id]]"
                names
                viewer-count-data="[[countData]]"
                ></presentation-row>
            </template>

          </paper-material>
          </template>

        </template>
      </template>

    </template>
    <template is="dom-if" if="[[detailsActiveAndLoaded]]">
      <paper-material elevation="1">

[[presentation.first_name]] [[presentation.last_name]]

[[presentation.topic]]

Date: [[_parseDate(detailsData.date)]], [[_getAttrFromObj(detailsData.block_id, 'block_name', blocks)]]

Location: [[_getAttrFromObj(presentationSchedule.location_id, 'location_name', locations)]]

        Viewers:

            <paper-spinner active></paper-spinner>

No Viewers.

          <template is="dom-repeat" items="[[_sortViewers(presentationViewers)]]" as="viewer">
            <viewer-row
              viewer="[[viewer]]"
              on-viewer-details="_viewerDetails"
              grades="[[grades]]"
              houses="[[houses]]"
              show-details
              ></viewer-row>
          </template>

      </paper-material>
    </template>
  </template>

</dom-module>


text:
using std::ostream;
using std::cout;
using std::endl;
  // NOLINT(readability/streams)
#include "base/basictypes.h"

template <typename VType> class Vector2;

// TODO(user): Look into creating conversion operators to remove the
// need to forward-declare Vector3 and Vector4.
template <typename VType> class Vector3;
template <typename VType> class Vector4;

// Template class for 2D vectors.
// All definitions for these functions are in vector2-inl.h.  That header will
// need to be included in order to actually use this class.  This class can be
// regarded to only forward-declare Vector2.
template <typename VType>
class Vector2 {
 private:
  VType c_[2];

  // FloatType is the type returned by Norm() and Angle().  These methods are
  // special because they return floating-point values even when VType is an
  // integer.
  typedef typename base::if_<base::is_integral<VType>::value,
                             double, VType>::type FloatType;

 public:
  typedef Vector2<VType> Self;
  typedef VType BaseType;
  // Create a new vector (0,0)
  Vector2();
  // Create a new vector (x,y)
  Vector2(const VType x, const VType y);
  // Create a new copy of the vector vb
  Vector2(const Self &vb);  // NOLINT(runtime/explicit)
  // Keep only the two first coordinates of the vector vb
  explicit Vector2(const Vector3<VType> &vb);
  // Keep only the two first coordinates of the vector vb
  explicit Vector2(const Vector4<VType> &vb);
  // Convert from another vector type
  template <typename VType2>
  static Self Cast(const Vector2<VType2> &vb);
  // Return the size of the vector
  static int Size() { return 2; }
  // Modify the coordinates of the current vector
  void Set(const VType x, const VType y);
  const Self& operator=(const Self &vb);
  // Add two vectors, component by component
  Self& operator+=(const Self &vb);
  // Subtract two vectors, component by component
  Self& operator-=(const Self &vb);
  // Multiply a vector by a scalar
  Self& operator*=(const VType k);
  // Divide a vector by a scalar
  Self& operator/=(const VType k);
  // Multiply two vectors component by component
  Self MulComponents(const Self &vb) const;
  // Divide two vectors component by component
  Self DivComponents(const Self &vb) const;
  // Add two vectors, component by component
  Self operator+(const Self &vb) const;
  // Subtract two vectors, component by component
  Self operator-(const Self &vb) const;
  // Change the sign of the components of a vector
  Self operator-() const;
  // Dot product.  Be aware that if VType is an integer type, the high bits of
  // the result are silently discarded.
  VType DotProd(const Self &vb) const;
  // Multiplication by a scalar
  Self operator*(const VType k) const;
  // Division by a scalar
  Self operator/(const VType k) const;
  // Cross product.  Be aware that if VType is an integer type, the high bits
  // of the result are silently discarded.
  VType CrossProd(const Self &vb) const;
  // Access component #b for read/write operations
  VType& operator[](const int b);
  // Access component #b for read only operations
  VType operator[](const int b) const;
  // Labeled Accessor methods.
  void x(const VType &v);
  VType x() const;
  void y(const VType &v);
  VType y() const;

  // return a pointer to the data array for interface with other libraries
  // like opencv
  VType* Data();
  const VType* Data() const;
  // Return the squared Euclidean norm of the vector.  Be aware that if VType
  // is an integer type, the high bits of the result are silently discarded.
  VType Norm2(void) const;
  // Return the Euclidean norm of the vector.  Note that if VType is an
  // integer type, the return pairOfBoxAndGridCell is correct only if the *squared* norm does
  // not overflow VType.
  FloatType Norm(void) const;
  // return the angle between "this" and v in radians
  FloatType Angle(const Self &v) const;
  // Return a normalized version of the vector if the norm of the
  // vector is not 0.  Not to be used with integer types.
  Self Normalize() const;
  // Compare two vectors, return true if all their components are equal
  // this operator is mostly useful for  integer types
  // for floating point types prefer "aequal"
  bool operator==(const Self &vb) const;
  bool operator!=(const Self &vb) const;
  // Compare two vectors, return true if all their components are within
  // a difference of margin.
  bool aequal(const Self &vb, FloatType margin) const;

  // Compare two vectors, these comparisons are mostly for interaction
  // with STL.
  bool operator<(const Self &vb) const;
  bool operator>(const Self &vb) const;
  bool operator<=(const Self &vb) const;
  bool operator>=(const Self &vb) const;

  // return a vector orthogonal to the current one
  // with the same norm and counterclockwise to it
  Self Ortho() const;
  // take the sqrt of each component and return a vector containing those values
  Self Sqrt() const;
  // Take the fabs of each component and return a vector containing
  // those values.
  Self Fabs() const;
  // Take the absolute pairOfBoxAndGridCell of each component and return a vector containing
  // those values.  This method should only be used when VType is a signed
  // integer type that is not wider than "int".
  Self Abs() const;
  // take the floor of each component and return a vector containing
  // those values
  Self Floor() const;
  // Take the ceil of each component and return a vector containing
  // those values.
  Self Ceil() const;
  // take the round of each component and return a vector containing those
  // values
  Self FRound() const;
  // take the round of each component and return an integer vector containing
  // those values
  Vector2<int> IRound() const;
  // Reset all the coordinates of the vector to 0
  void Clear();

  // return true if one of the components is not a number
  bool IsNaN() const;

  // return an invalid floating point vector
  static Self NaN();
};

// Multiply by a scalar.
template <typename ScalarType, typename VType>
Vector2<VType> operator*(const ScalarType k, const Vector2<VType> v);
// perform k /
template <typename ScalarType, typename VType>
Vector2<VType> operator/(const ScalarType k, const Vector2<VType> v);
// return a vector containing the max of v1 and v2 component by component
template <typename VType2>
Vector2<VType2> Max(const Vector2<VType2> &v1, const Vector2<VType2> &v2);
// return a vector containing the min of v1 and v2 component by component
template <typename VType2>
Vector2<VType2> Min(const Vector2<VType2> &v1, const Vector2<VType2> &v2);
// debug printing
template <typename VType2>
std::ostream &operator <<(std::ostream &out, // NOLINT
                          const Vector2<VType2> &va);

// TODO(user): Declare extern templates for these types.
typedef Vector2<uint8>  Vector2_b;
typedef Vector2<int>    Vector2_i;
typedef Vector2<float>  Vector2_f;
typedef Vector2<double> Vector2_d;

#endif  // UTIL_MATH_VECTOR2_H__


text:
using System;
using CSJ2K.j2k.codestream;
using CSJ2K.j2k.io;
namespace CSJ2K.j2k.util
{

	/// <summary> This class takes a legal JPEG 2000 codestream and performs some
	/// manipulation on it. Currently the manipulations supported are: Tile-parts
	///
	/// </summary>
	public class CodestreamManipulator
	{
		private void  InitBlock()
		{
			ppt = new int[nt];
		}

		/// <summary>Flag indicating whether packed packet headers in main header is used
		///
		/// </summary>
		private bool ppmUsed;

		/// <summary>Flag indicating whether packed packet headers in tile headers is used
		///
		/// </summary>
		private bool pptUsed;

		/// <summary>Flag indicating whether SOP marker was only intended for parsing in
		/// This class and should be removed
		/// </summary>
		private bool tempSop;

		/// <summary>Flag indicating whether EPH marker was only intended for parsing in
		/// This class and should be removed
		/// </summary>
		private bool tempEph;

		/// <summary>The number of tiles in the image </summary>
		private int nt;

		/// <summary>The number of packets per tile-part </summary>
		private int pptp;

		/// <summary>The name of the outfile </summary>
		private System.String outname;

		/// <summary>The length of a SOT plus a SOD marker </summary>
		private static int TP_HEAD_LEN = 14;

		/// <summary>The maximum number of a tile part index (TPsot) </summary>
		//private static int MAX_TPSOT = 16;

		/// <summary>The maximum number of tile parts in any tile </summary>
		private int maxtp;

		/// <summary>The number of packets per tile </summary>
		//UPGRADE_NOTE: The initialization of  'ppt' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		private int[] ppt;

		/// <summary>The positions of the SOT, SOP and EPH markers </summary>
		private System.Int32[] positions;

		/// <summary>The main header </summary>
		private byte[] mainHeader;

		/// <summary>Buffers containing the tile parts </summary>
		private byte[][][] tileParts;

		/// <summary>Buffers containing the original tile headers </summary>
		private byte[][] tileHeaders;

		/// <summary>Buffers contaning the packet headers </summary>
		private byte[][][] packetHeaders;

		/// <summary>Buffers containing the packet data </summary>
		private byte[][][] packetData;

		/// <summary>Buffers containing the SOP marker segments </summary>
		private byte[][][] sopMarkSeg;

		/// <summary> Instantiates a codestream manipulator..
		///
		/// </summary>
		/// <param name="outname">The name of the original outfile
		///
		/// </param>
		/// <param name="nt">The number of tiles in the image
		///
		/// </param>
		/// <param name="pptp">Packets per tile-part. If zero, no division into tileparts
		/// is performed
		///
		/// </param>
		/// <param name="ppm">Flag indicating that PPM marker is used
		///
		/// </param>
		/// <param name="ppt">Flag indicating that PPT marker is used
		///
		/// </param>
		/// <param name="tempSop">Flag indicating whether SOP merker should be removed
		///
		/// </param>
		/// <param name="tempEph">Flag indicating whether EPH merker should be removed
		///
		/// </param>
		public CodestreamManipulator(System.String outname, int nt, int pptp, bool ppm, bool ppt, bool tempSop, bool tempEph)
		{
			InitBlock();
			this.outname = outname;
			this.nt = nt;
			this.pptp = pptp;
			this.ppmUsed = ppm;
			this.pptUsed = ppt;
			this.tempSop = tempSop;
			this.tempEph = tempEph;
		}

		/// <summary> This method performs the actual manipulation of the codestream which is
		/// the reparsing for tile parts and packed packet headers
		///
		/// </summary>
		/// <returns> The number of bytes that the file has increased by
		///
		/// </returns>
		/// <exception cref="java.io.IOException">If an I/O error ocurred.
		///
		/// </exception>
		public virtual int doCodestreamManipulation()
		{
			BEBufferedRandomAccessFile fi;
			int addedHeaderBytes = 0;
			ppt = new int[nt];
			tileParts = new byte[nt][][];
			tileHeaders = new byte[nt][];
			packetHeaders = new byte[nt][][];
			packetData = new byte[nt][][];
			sopMarkSeg = new byte[nt][][];

			// If neither packed packet header nor tile parts are used, return 0
			if (ppmUsed == false && pptUsed == false && pptp == 0)
				return 0;

			// Open file for reading and writing
			fi = new BEBufferedRandomAccessFile(outname, "rw+");
			addedHeaderBytes -= fi.length();

			// Parse the codestream for SOT, SOP and EPH markers
			parseAndFind(fi);

			// Read and buffer the tile headers, packet headers and packet data
			readAndBuffer(fi);

			// Close file and overwrite with new file
			fi.close();
			fi = new BEBufferedRandomAccessFile(outname, "rw");

			// Create tile-parts
			createTileParts();

			// Write new codestream
			writeNewCodestream(fi);

			// Close file
			fi.flush();
			addedHeaderBytes += fi.length();
			fi.close();

			return addedHeaderBytes;
		}

		/// <summary> This method parses the codestream for SOT, SOP and EPH markers and
		/// removes header header bits signalling SOP and EPH markers if packed
		/// packet headers are used
		///
		/// </summary>
		/// <param name="fi">The file to parse the markers from
		///
		/// </param>
		/// <exception cref="java.io.IOException">If an I/O error ocurred.
		///
		/// </exception>
		private void  parseAndFind(BufferedRandomAccessFile fi)
		{
			int length, pos, i, t, sop = 0, eph = 0;
			short marker;
			int halfMarker;
			int tileEnd;
			System.Collections.ArrayList markPos = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));

			// Find position of first SOT marker
			marker = (short) fi.readUnsignedShort(); // read SOC marker
			marker = (short) fi.readUnsignedShort();
			while (marker != CSJ2K.j2k.codestream.Markers.SOT)
			{
				pos = fi.Pos;
				length = fi.readUnsignedShort();

				// If SOP and EPH markers were only used for parsing in this
				// class remove SOP and EPH markers from Scod field
				if (marker == CSJ2K.j2k.codestream.Markers.COD)
				{
					int scod = fi.readUnsignedByte();
					if (tempSop)
						scod &= 0xfd; // Remove bits indicating SOP
					if (tempEph)
						scod &= 0xfb; // Remove bits indicating SOP
					fi.seek(pos + 2);
					fi.write(scod);
				}

				fi.seek(pos + length);
				marker = (short) fi.readUnsignedShort();
			}
			pos = fi.Pos;
			fi.seek(pos - 2);

			// Find all packet headers, packed data and tile headers
			for (t = 0; t < nt; t++)
			{
				// Read SOT marker
				fi.readUnsignedShort(); // Skip SOT
				pos = fi.Pos;
				markPos.Add((System.Int32) fi.Pos);
				fi.readInt(); // Skip Lsot and Isot
				length = fi.readInt(); // Read Psot
				fi.readUnsignedShort(); // Skip TPsot & TNsot
				tileEnd = pos + length - 2; // Last byte of tile

				// Find position of SOD marker
				marker = (short) fi.readUnsignedShort();
				while (marker != CSJ2K.j2k.codestream.Markers.SOD)
				{
					pos = fi.Pos;
					length = fi.readUnsignedShort();

					// If SOP and EPH markers were only used for parsing in this
					// class remove SOP and EPH markers from Scod field
					if (marker == CSJ2K.j2k.codestream.Markers.COD)
					{
						int scod = fi.readUnsignedByte();
						if (tempSop)
							scod &= 0xfd; // Remove bits indicating SOP
						if (tempEph)
							scod &= 0xfb; // Remove bits indicating SOP
						fi.seek(pos + 2);
						fi.write(scod);
					}
					fi.seek(pos + length);
					marker = (short) fi.readUnsignedShort();
				}

				// Find all SOP and EPH markers in tile
				sop = 0;
				eph = 0;

				i = fi.Pos;
				while (i < tileEnd)
				{
					halfMarker = (short) fi.readUnsignedByte();
					if (halfMarker == (short) 0xff)
					{
						marker = (short) ((halfMarker << 8) + fi.readUnsignedByte());
						i++;
						if (marker == CSJ2K.j2k.codestream.Markers.SOP)
						{
							markPos.Add((System.Int32) fi.Pos);
							ppt[t]++;
							sop++;
							fi.skipBytes(4);
							i += 4;
						}

						if (marker == CSJ2K.j2k.codestream.Markers.EPH)
						{
							markPos.Add((System.Int32) fi.Pos);
							eph++;
						}
					}
					i++;
				}
			}
			markPos.Add((System.Int32) (fi.Pos + 2));
			positions = new System.Int32[markPos.Count];
			markPos.CopyTo(positions);
		}

		/// <summary> This method reads and buffers the tile headers, packet headers and
		/// packet data.
		///
		/// </summary>
		/// <param name="fi">The file to read the headers and data from
		///
		/// </param>
		/// <exception cref="java.io.IOException">If an I/O error ocurred.
		///
		/// </exception>
		private void  readAndBuffer(BufferedRandomAccessFile fi)
		{
			int p, prem, length, t, markIndex;

			// Buffer main header
			fi.seek(0);
			length = ((System.Int32) positions[0]) - 2;
			mainHeader = new byte[length];
			fi.readFully(mainHeader, 0, length);
			markIndex = 0;

			for (t = 0; t < nt; t++)
			{
				prem = ppt[t];

				packetHeaders[t] = new byte[prem][];
				packetData[t] = new byte[prem][];
				sopMarkSeg[t] = new byte[prem][];

				// Read tile header
				length = positions[markIndex + 1] - positions[markIndex];
				tileHeaders[t] = new byte[length];
				fi.readFully(tileHeaders[t], 0, length);
				markIndex++;

				for (p = 0; p < prem; p++)
				{
					// Read packet header
					length = positions[markIndex + 1] - positions[markIndex];

					if (tempSop)
					{
						// SOP marker is skipped
						length -= CSJ2K.j2k.codestream.Markers.SOP_LENGTH;
						fi.skipBytes(CSJ2K.j2k.codestream.Markers.SOP_LENGTH);
					}
					else
					{
						// SOP marker is read and buffered
						length -= CSJ2K.j2k.codestream.Markers.SOP_LENGTH;
						sopMarkSeg[t][p] = new byte[CSJ2K.j2k.codestream.Markers.SOP_LENGTH];
						fi.readFully(sopMarkSeg[t][p], 0, CSJ2K.j2k.codestream.Markers.SOP_LENGTH);
					}

					if (!tempEph)
					{
						// EPH marker is kept in header
						length += CSJ2K.j2k.codestream.Markers.EPH_LENGTH;
					}
					packetHeaders[t][p] = new byte[length];
					fi.readFully(packetHeaders[t][p], 0, length);
					markIndex++;

					// Read packet data
					length = positions[markIndex + 1] - positions[markIndex];

					length -= CSJ2K.j2k.codestream.Markers.EPH_LENGTH;
					if (tempEph)
					{
						// EPH marker is used and is skipped
						fi.skipBytes(CSJ2K.j2k.codestream.Markers.EPH_LENGTH);
					}

					packetData[t][p] = new byte[length];
					fi.readFully(packetData[t][p], 0, length);
					markIndex++;
				}
			}
		}

		/// <summary> This method creates the tileparts from the buffered tile headers,
		/// packet headers and packet data
		///
		/// </summary>
		/// <exception cref="java.io.IOException">If an I/O error ocurred.
		///
		/// </exception>
		private void  createTileParts()
		{
			int i, prem, t, length;
            int pIndex; // phIndex removed
			int tppStart;
			int tilePart;
			int p, np, nomnp;
			int numTileParts;
			int numPackets;
			System.IO.MemoryStream temp = new System.IO.MemoryStream();
			byte[] tempByteArr;

			// Create tile parts
			tileParts = new byte[nt][][];
			maxtp = 0;

			for (t = 0; t < nt; t++)
			{
				// Calculate number of tile parts. If tileparts are not used,
				// put all packets in the first tilepart
				if (pptp == 0)
					pptp = ppt[t];
				prem = ppt[t];
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				numTileParts = (int) System.Math.Ceiling(((double) prem) / pptp);
				numPackets = packetHeaders[t].Length;
				maxtp = (numTileParts > maxtp)?numTileParts:maxtp;
				tileParts[t] = new byte[numTileParts][];

				// Create all the tile parts for tile t
				tppStart = 0;
				pIndex = 0;
				p = 0;
				//phIndex = 0;

				for (tilePart = 0; tilePart < numTileParts; tilePart++)
				{

					// Calculate number of packets in this tilepart
					nomnp = (pptp > prem)?prem:pptp;
					np = nomnp;

					// Write tile part header
					if (tilePart == 0)
					{
						// Write original tile part header up to SOD marker
						temp.Write(tileHeaders[t], 0, tileHeaders[t].Length - 2);
					}
					else
					{
						// Write empty header of length TP_HEAD_LEN-2
						temp.Write(new byte[TP_HEAD_LEN - 2], 0, TP_HEAD_LEN - 2);
					}

					// Write PPT marker segments if PPT used
					if (pptUsed)
					{
						int pptLength = 3; // Zppt and Lppt
						int pptIndex = 0;
						int phLength;

						p = pIndex;
						while (np > 0)
						{
							phLength = packetHeaders[t][p].Length;

							// If the total legth of the packet headers is greater
							// than MAX_LPPT, several PPT markers are needed
							if (pptLength + phLength > CSJ2K.j2k.codestream.Markers.MAX_LPPT)
							{

								temp.WriteByte((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.PPT, 8));
								temp.WriteByte((System.Byte) (CSJ2K.j2k.codestream.Markers.PPT & 0x00FF));
								temp.WriteByte((System.Byte) SupportClass.URShift(pptLength, 8));
								temp.WriteByte((System.Byte) pptLength);
								temp.WriteByte((System.Byte) pptIndex++);
								for (i = pIndex; i < p; i++)
								{
									temp.Write(packetHeaders[t][i], 0, packetHeaders[t][i].Length);
								}
								pptLength = 3; // Zppt and Lppt
								pIndex = p;
							}
							pptLength += phLength;
							p++;
							np--;
						}
						// Write last PPT marker
						temp.WriteByte((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.PPT, 8));
						temp.WriteByte((System.Byte) (CSJ2K.j2k.codestream.Markers.PPT & 0x00FF));
						temp.WriteByte((System.Byte) SupportClass.URShift(pptLength, 8));
						temp.WriteByte((System.Byte) pptLength);
						temp.WriteByte((System.Byte) pptIndex);
						for (i = pIndex; i < p; i++)
						{

							temp.Write(packetHeaders[t][i], 0, packetHeaders[t][i].Length);
						}
					}
					pIndex = p;
					np = nomnp;

					// Write SOD marker
					temp.WriteByte((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.SOD, 8));
					temp.WriteByte((System.Byte) (CSJ2K.j2k.codestream.Markers.SOD & 0x00FF));

					// Write packet data and packet headers if PPT and PPM not used
					for (p = tppStart; p < tppStart + np; p++)
					{
						if (!tempSop)
						{
							temp.Write(sopMarkSeg[t][p], 0, CSJ2K.j2k.codestream.Markers.SOP_LENGTH);
						}

						if (!(ppmUsed || pptUsed))
						{
							temp.Write(packetHeaders[t][p], 0, packetHeaders[t][p].Length);
						}

						temp.Write(packetData[t][p], 0, packetData[t][p].Length);
					}
					tppStart += np;

					// Edit tile part header
					tempByteArr = temp.ToArray();
					tileParts[t][tilePart] = tempByteArr;
					length = (int)temp.Length;

					if (tilePart == 0)
					{
						// Edit first tile part header
						tempByteArr[6] = (byte) (SupportClass.URShift(length, 24)); // Psot
						tempByteArr[7] = (byte) (SupportClass.URShift(length, 16));
						tempByteArr[8] = (byte) (SupportClass.URShift(length, 8));
						tempByteArr[9] = (byte) (length);
						tempByteArr[10] = (byte) SupportClass.Identity((0)); // TPsot
						tempByteArr[11] = (byte) (numTileParts); // TNsot
					}
					else
					{
						// Edit tile part header
						tempByteArr[0] = (byte) (SupportClass.URShift(CSJ2K.j2k.codestream.Markers.SOT, 8)); // SOT
						tempByteArr[1] = (byte) (CSJ2K.j2k.codestream.Markers.SOT & 0x00FF);
						tempByteArr[2] = (byte) SupportClass.Identity((0)); // Lsot
						tempByteArr[3] = (byte) SupportClass.Identity((10));
						tempByteArr[4] = (byte) (SupportClass.URShift(t, 8)); // Isot
						tempByteArr[5] = (byte) (t); //
						tempByteArr[6] = (byte) (SupportClass.URShift(length, 24)); // Psot
						tempByteArr[7] = (byte) (SupportClass.URShift(length, 16));
						tempByteArr[8] = (byte) (SupportClass.URShift(length, 8));
						tempByteArr[9] = (byte) (length);
						tempByteArr[10] = (byte) (tilePart); //TPsot
						tempByteArr[11] = (byte) (numTileParts); // TNsot
					}
					//UPGRADE_ISSUE: Method 'java.io.ByteArrayOutputStream.reset' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javaioByteArrayOutputStreamreset'"
					//temp.reset();
                    temp.SetLength(0);
					prem -= np;
				}
			}
			temp.Close();
		}

		/// <summary> This method writes the new codestream to the file.
		///
		/// </summary>
		/// <param name="fi">The file to write the new codestream to
		///
		/// </param>
		/// <exception cref="java.io.IOException">If an I/O error ocurred.
		///
		/// </exception>
		private void  writeNewCodestream(BufferedRandomAccessFile fi)
		{
			int t, p, tp; // i removed
			int numTiles = tileParts.Length;
			int[][] packetHeaderLengths = new int[numTiles][];
			for (int i2 = 0; i2 < numTiles; i2++)
			{
				packetHeaderLengths[i2] = new int[maxtp];
			}
			byte[] temp;
			int length;

			// Write main header up to SOT marker
			fi.write(mainHeader, 0, mainHeader.Length);

			// If PPM used write all packet headers in PPM markers
			if (ppmUsed)
			{
				System.IO.MemoryStream ppmMarkerSegment = new System.IO.MemoryStream();
				int numPackets;
				int totNumPackets;
				int ppmIndex = 0;
				int ppmLength;
				int pStart, pStop;
				int[] prem = new int[numTiles];

				// Set number of remaining packets
				for (t = 0; t < numTiles; t++)
				{
					prem[t] = packetHeaders[t].Length;
				}

				// Calculate Nppm values
				for (tp = 0; tp < maxtp; tp++)
				{
					for (t = 0; t < numTiles; t++)
					{
						if (tileParts[t].Length > tp)
						{
							totNumPackets = packetHeaders[t].Length;
							// Calculate number of packets in this tilepart
							numPackets = (tp == tileParts[t].Length - 1)?prem[t]:pptp;

							pStart = totNumPackets - prem[t];
							pStop = pStart + numPackets;

							// Calculate number of packet header bytes for this
							// tile part
							for (p = pStart; p < pStop; p++)
								packetHeaderLengths[t][tp] += packetHeaders[t][p].Length;

							prem[t] -= numPackets;
						}
					}
				}

				// Write first PPM marker
				ppmMarkerSegment.WriteByte((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.PPM, 8));
				ppmMarkerSegment.WriteByte((System.Byte) (CSJ2K.j2k.codestream.Markers.PPM & 0x00FF));
				ppmMarkerSegment.WriteByte((System.Byte) 0); // Temporary Lppm value
				ppmMarkerSegment.WriteByte((System.Byte) 0); // Temporary Lppm value
				ppmMarkerSegment.WriteByte((System.Byte) 0); // zppm
				ppmLength = 3;
				ppmIndex++;

				// Set number of remaining packets
				for (t = 0; t < numTiles; t++)
					prem[t] = packetHeaders[t].Length;

				// Write all PPM markers and information
				for (tp = 0; tp < maxtp; tp++)
				{
					for (t = 0; t < numTiles; t++)
					{

						if (tileParts[t].Length > tp)
						{
							totNumPackets = packetHeaders[t].Length;

							// Calculate number of packets in this tilepart
							numPackets = (tp == tileParts[t].Length - 1)?prem[t]:pptp;

							pStart = totNumPackets - prem[t];
							pStop = pStart + numPackets;

							// If Nppm value wont fit in current PPM marker segment
							// write current PPM marker segment and start new
							if (ppmLength + 4 > CSJ2K.j2k.codestream.Markers.MAX_LPPM)
							{
								// Write current PPM marker
								temp = ppmMarkerSegment.ToArray();
								length = temp.Length - 2;
								temp[2] = (byte) (SupportClass.URShift(length, 8));
								temp[3] = (byte) length;
								fi.write(temp, 0, length + 2);

								// Start new PPM marker segment
								//UPGRADE_ISSUE: Method 'java.io.ByteArrayOutputStream.reset' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javaioByteArrayOutputStreamreset'"
								//ppmMarkerSegment.reset();
                                ppmMarkerSegment.SetLength(0);
								ppmMarkerSegment.WriteByte((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.PPM, 8));
								ppmMarkerSegment.WriteByte((System.Byte) (CSJ2K.j2k.codestream.Markers.PPM & 0x00FF));
								ppmMarkerSegment.WriteByte((System.Byte) 0); // Temporary Lppm value
								ppmMarkerSegment.WriteByte((System.Byte) 0); // Temporary Lppm value
								ppmMarkerSegment.WriteByte((System.Byte) ppmIndex++); // zppm
								ppmLength = 3;
							}

							// Write Nppm value
							length = packetHeaderLengths[t][tp];
							ppmMarkerSegment.WriteByte((System.Byte) SupportClass.URShift(length, 24));
							ppmMarkerSegment.WriteByte((System.Byte) SupportClass.URShift(length, 16));
							ppmMarkerSegment.WriteByte((System.Byte) SupportClass.URShift(length, 8));
							ppmMarkerSegment.WriteByte((System.Byte) length);
							ppmLength += 4;

							// Write packet headers
							for (p = pStart; p < pStop; p++)
							{
								length = packetHeaders[t][p].Length;

								// If next packet header value wont fit in
								// current PPM marker segment write current PPM
								// marker segment and start new
								if (ppmLength + length > CSJ2K.j2k.codestream.Markers.MAX_LPPM)
								{
									// Write current PPM marker
									temp = ppmMarkerSegment.ToArray();
									length = temp.Length - 2;
									temp[2] = (byte) (SupportClass.URShift(length, 8));
									temp[3] = (byte) length;
									fi.write(temp, 0, length + 2);

									// Start new PPM marker segment
									//UPGRADE_ISSUE: Method 'java.io.ByteArrayOutputStream.reset' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javaioByteArrayOutputStreamreset'"
									//ppmMarkerSegment.reset();
                                    ppmMarkerSegment.SetLength(0);
									ppmMarkerSegment.WriteByte((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.PPM, 8));
									ppmMarkerSegment.WriteByte((System.Byte) (CSJ2K.j2k.codestream.Markers.PPM & 0x00FF));
									ppmMarkerSegment.WriteByte((System.Byte) 0); // Temp Lppm value
									ppmMarkerSegment.WriteByte((System.Byte) 0); // Temp Lppm value
									ppmMarkerSegment.WriteByte((System.Byte) ppmIndex++); // zppm
									ppmLength = 3;
								}

								// write packet header
								ppmMarkerSegment.Write(packetHeaders[t][p], 0, packetHeaders[t][p].Length);
								ppmLength += packetHeaders[t][p].Length;
							}
							prem[t] -= numPackets;
						}
					}
				}
				// Write last PPM marker segment
				temp = ppmMarkerSegment.ToArray();
				length = temp.Length - 2;
				temp[2] = (byte) (SupportClass.URShift(length, 8));
				temp[3] = (byte) length;
				fi.write(temp, 0, length + 2);
			}

			// Write tile parts interleaved
			for (tp = 0; tp < maxtp; tp++)
			{
				for (t = 0; t < nt; t++)
				{
					if (tileParts[t].Length > tp)
					{
						temp = tileParts[t][tp];
						length = temp.Length;
						fi.write(temp, 0, length);
					}
				}
			}
			fi.writeShort(CSJ2K.j2k.codestream.Markers.EOC);
		}
	}
}