text:
/*global Leap*/
var LeapElement = function(element) {
    this.element = element;
    this.cursor = null;
};

LeapElement.prototype = {
    isAttractor: function() {
        return this.element.getAttribute("leap-attractor") === "true" || (this.element.getAttribute("leap-attractor-x-padding") != null && !isNaN(this.element.getAttribute("leap-attractor-x-padding"))) || (this.element.getAttribute("leap-attractor-y-padding") != null && !isNaN(this.element.getAttribute("leap-attractor-y-padding")));
    },
    appendChild: function(element) {
        if (element instanceof HTMLElement) {
            return this.element.appendChild(element);
        } else {
            return this.element.appendChild(element.getElement());
        }
    },
    removeChild: function(element) {
        if (element instanceof HTMLElement) {
            return this.element.removeChild(element);
        } else {
            return this.element.removeChild(element.getElement());
        }
    },
    getID: function() {
        return this.element.id;
    },
    setStyle: function(style) {
        for (var key in style) {
            this.element.style[key] = style[key];
        }
    },
    getParent: function() {
        return this.element.parentNode;
    },
    getWidth: function() {
        return this.element.offsetWidth;
    },
    getHeight: function() {
        return this.element.offsetHeight;
    },
    getElement: function() {
        return this.element;
    },
    hasCursor: function() {
        return this.cursor !== null;
    },
    capture: function(cursor) {
        // console.log("Cursor Captured");
        this.cursor = cursor;
        this.cursor.capture(this);
    },
    release: function() {
        // console.log("Cursor Released");
        if (this.cursor) {
            this.cursor.release();
            this.cursor = null;
        }
    },
    getAttractorPadding: function() {
        return {
            x: parseInt(this.element.getAttribute("leap-attractor-x-padding"), 10) || 0,
            y: parseInt(this.element.getAttribute("leap-attractor-y-padding"), 10) || 0
        };
    },
    setAttribute: function(name, value){
        this.element.setAttribute(name, value);
    },
    getClickDelay: function() {
        return this.element.getAttribute("leap-click-delay");
    },
    hasMultitap: function() {
        return this.element.getAttribute("leap-enable-multitap") === "true";
    },
    isTappable: function() {
        return this.element.getAttribute("leap-disable-tap") !== "true";
    },
    isHoverable: function() {
        return this.element.getAttribute("leap-disable-hover") !== "true";
    },
    hasRelay: function() {
      return this.element.getAttribute("leap-relay") !== null;
    },
    getRelay: function() {
        var selector = this.element.getAttribute("leap-relay");
        return selector;
    },
    setXY: function(x, y) {
        this.setX(x);
        this.setY(y);
    },
    setX: function(x) {
        this.element.style.left = x + "px";
    },
    setY: function(y) {
        this.element.style.top = y + "px";
    },
    getX: function() {
        return this.element.getBoundingClientRect().left;
    },
    getY: function() {
        return this.element.getBoundingClientRect().top;
    },
    scroll:function(speed) {
        var yDiff = this.element.clientHeight > this.element.parentElement.clientHeight;
        var xDiff = this.element.clientWidth > this.element.parentElement.clientWidth;

        if(this.element === document.body) {
            if(yDiff > 0 && yDiff > xDiff) {
                this.scrollY(speed);
            }else if(xDiff >0) {
                this.scrollX(speed);
            }
        }else {
            if(this.element.scrollHeight > this.element.clientHeight) {
                this.scrollY(speed);
            }else if (this.element.scrollWidth > this.element.clientWidth) {
                this.scrollX(speed);
            }
        }
    },
    scrollX: function(speed) {
        this.element.scrollLeft += speed;
    },
    scrollY: function(speed) {
        this.element.scrollTop += speed;
    },
    addClass: function(classname) {
        var cn = this.element.className;
        //test for existance
        if (cn && cn.indexOf(classname) !== -1) {
            return;
        }
        //add a space if the element already has class
        if (cn !== '') {
            classname = ' ' + classname;
        }
        this.element.className = cn + classname;
    },
    removeClass: function(classname) {
        var cn = this.element.className;
        var rxp = new RegExp("\\s?\\b" + classname + "\\b", "g");
        cn = cn.replace(rxp, '');
        this.element.className = cn;
    },
    fireEvent: function(event) {
        this.element.dispatchEvent(event);
    }
};

var LeapManagerUtils = (function() {
    var elementsCache = {};
    var ELEMENT_ID_PREFIX = "leap_element_";
    var elementCount = 0;
    var queryCache = {};

    return {
        getLeapElement: function(domElement) {
            if(domElement == null) return null;
            if (!domElement.id) domElement.id = ELEMENT_ID_PREFIX + elementCount++;
            if (!elementsCache[domElement.id]) {
                elementsCache[domElement.id] = new LeapElement(domElement);
            }
            return elementsCache[domElement.id];
        },
        isElementVisible: function(element) {
            while (element !== document.body.parentNode) {
                if ('0' === LeapManagerUtils.getStyle(element, "opacity") || 'none' === LeapManagerUtils.getStyle(element, "display") || 'hidden' === LeapManagerUtils.getStyle(element, "visibility")) {
                    return false;
                }
                element = element.parentNode;
            }
            return true;
        },
        getStyle: function(el, style) {
            if (window.getComputedStyle) {
                return document.defaultView.getComputedStyle(el)[style];
            }
            if (el.currentStyle) {
                return el.currentStyle[style];
            }
        },
        extend: function(a, b) {
            for (var i in b) {
                a[i] = b[i];
            }
        },
        extendIf: function(a, b) {
            for (var i in b) {
                if (b[i] instanceof Object && b[i].constructor === Object) {
                    if (a[i] === undefined || a[i] === null) a[i] = {};
                    LeapManagerUtils.extendIf(a[i], b[i]);
                } else {
                    if (a[i] === undefined || a[i] === null) a[i] = b[i];
                }
            }
        },
        exists: function(obj){
            return obj !== undefined && obj !== null;
        },
        bind: function(func, scope, args) {
            return function() {
                if (!args) args = [];
                args = Array.prototype.slice.call(arguments).concat(args);
                func.apply(scope, args);
            };
        },
        map: function(value, srcLow, srcHigh, resultLow, resultHigh) {
            return (value === srcLow) ? resultLow : (value - srcLow) * (resultHigh - resultLow) / (srcHigh - srcLow) + resultLow;
        },
        error: function(error) {
            console.log(error);
        },
        testStructure: function(obj, structure){
            var value;
            for (var i = 0; i < structure.length; i++) {
                value = structure[i];
                if(typeof(value) === "string") {
                    if(!LeapManagerUtils.exists(obj[value])) {
                        return false;
                    }else{
                        obj = obj[value];
                    }
                }
            }
            return true;
        },
        createStructure: function(obj, structure){
            var structureExists = true,
            value;
            for (var i = 0; i < structure.length; i++) {
                value = structure[i];
                if(typeof(value) === "string") {
                    if(!LeapManagerUtils.exists(obj[value])) {
                        obj = obj[value] = {};
                        structureExists = false;
                    }
                }
            }
            return structureExists;
        },
        distance: function(a, b) {
            var xs, ys;
            xs = b.x - a.x;
            xs = xs * xs;

            ys = b.y - a.y;
            ys = ys * ys;

            return Math.sqrt( xs + ys );
        },
        getQueryAll: function(id, selector) {
            if(!LeapManagerUtils.exists(queryCache[id])) {
                queryCache[id] = document.querySelectorAll(selector);
            }
            return queryCache[id];
        },
        getQuery: function(id, selector) {
            if(!LeapManagerUtils.exists(queryCache[id])) {
                queryCache[id] = document.querySelector(selector);
            }
            return queryCache[id];
        }
    };
})();

var Cursor = function(config) {
    var TIMER_CURSOR_CLASS = "leap-timer-cursor";
    if(!config) {
        LeapManagerUtils.error('Cursor#constructor: You must specify a config object.');
        return null;
    }
    if (!config.source) {
        LeapManagerUtils.error('Cursor#constructor: You must specify a `source`.');
        return null;
    }
    if (!config.id) {
        LeapManagerUtils.error('Cursor#constructor: You must specify a `id`.');
        return null;
    }
    if (!config.icon) {
        LeapManagerUtils.error('Cursor#constructor: You must specify a `icon`.');
        return null;
    }
    LeapManagerUtils.extendIf(config, this.defaultConfig);
    this.source = config.source;
    this.id = config.id;
    this.type = config.type;
    this.icon = config.icon;
    this.easing = config.easing;
    this.clickDelay = config.clickDelay;
    this.multitapEnabled = config.multitapEnabled;

    //Cursor that created this virtual cursor
    this.virtualParent = config.virtualParent || null;
    if(this.virtualParent) {
        this.type = "virtual";
        this.setElement(this.virtualParent.getElement());
        this.virtualParent.addVirtual(this);
    }

    //Virtual Cursors attached to this cursor
    this.virtualCursors = [];

    if (this.clickDelay === 0 || isNaN(this.clickDelay)) this.clickDelay = null;
    this.onTapUpdate = LeapManagerUtils.bind(this._onTapUpdate, this);
    if (this.clickDelay) this.icon.addClass(TIMER_CURSOR_CLASS);
    if (this.icon instanceof HTMLElement) this.icon = new LeapElement(this.icon);
    if (config.position) {
        this.update(config.position.x, config.position.y);
        var halfWidth = (this.icon.getWidth() / 2);
        var halfHeight = (this.icon.getHeight() / 2);
        this.icon.setX((config.position.x * window.innerWidth) + halfWidth);
        this.icon.setY((config.position.y * window.innerHeight) + halfHeight);
    }
};

Cursor.prototype = {
    //Position
    x: 0,
    y: 0,
    z: 0,
    //Speed
    X: 0,
    Y: 0,
    Z: 0,
    //Velocity
    vX: 0,
    vY: 0,
    vZ: 0,
    enabled: true,
    captureHost: null,
    attractor: null,
    element: null,
    isTimerRunning: false,
    type: "real",
    startTime: null,
    animiationIntervalID: null,
    state: "up",
    currentClickDelay: 0,
    defaultConfig: {
        multitapEnabled: false,
        clickDelay: 0,
        easing: 0.3
    },
    _tapCapable: true,
    _startPoint: null,
    onAdded: function() {},
    onRemoved: function() {},
    setManager: function(manager){
        this.manager = manager;
    },
    //Enabled
    setEnabled: function(value) {
        this.enabled = value;
    },
    isEnabled: function() {
        return this.enabled;
    },
    //Element
    setElement: function(element) {
        this.element = element;
    },
    getElement: function(element) {
        return this.element;
    },
    hasElement: function() {
        return this.element !== null;
    },
    //Callbacks from Manager for Element Interactions
    onElementOver: function(element) {
        this.setElement(element);
        this.currentClickDelay = this.element.getClickDelay() || this.clickDelay;
        if (element.isHoverable()) {
            element.addClass("hover");
        }
        if (this._tapCapable && this.manager.isHoverTapEnabled() && this.currentClickDelay && element.isTappable()) {
            this.startTimer();
        }
    },
    onElementDown: function(element) {
        element.addClass("leap-down");
        this.icon.addClass("cursor-down");
        this.state = "down";
    },
    onElementMove: function(element) {},
    onElementUp: function(element) {
        this.state = "up";
        element.removeClass("leap-down");
        this.icon.removeClass("cursor-down");
    },
    onElementOut: function(element) {
        if (element.isHoverable()) {
            element.removeClass("hover");
        }
        if (this.manager.isHoverTapEnabled() && this.currentClickDelay && element.isTappable()) {
            this.stopTimer();
        }
        this.setElement(null);
    },
    isDown:function() {
        return this.state === "down";
    },
    disableTap: function() {
        if(this.element) {
            if (this.element.isHoverable()) {
                this.element.removeClass("hover");
            }

            if (this.currentClickDelay && this.element.isTappable()) {
                this.stopTimer();
            }
        }
        this._tapCapable = false;
    },
    restartTap: function() {
        this._tapCapable = true;
    },
    //Attractor
    setAttractor: function(attractor) {
        this.attractor = attractor;
    },
    hasAttractor: function() {
        return this.attractor !== null;
    },
    //Capture  & Release
    capture: function(host) {
        this.captureHost = host;
        this.setAttractor(null);
    },
    isCaptured: function() {
        return this.captureHost != null;
    },
    release: function() {
        this.captureHost = null;
    },
    //Position
    update: function(x, y, z) {
        this.setPositionX(x);
        this.setPositionY(y);
        this.setPositionZ(z);
    },
    setPositionX: function(value) {
        this.X = value - this.x;
        this.x = value;
    },
    setPositionY: function(value) {
        this.Y = value - this.y;
        this.y = value;
    },
    setPositionZ: function(value) {
        this.Z = value - this.z;
        this.z = value;
    },
    //Speed
    getX: function() {
        return this.x;
    },
    getY: function() {
        return this.y;
    },
    getZ: function() {
        return this.z;
    },
    //Velocity
    setVelocityXYZ: function(x, y, z) {
        this.setVelocityX(x);
        this.setVelocityY(y);
        this.setVelocityZ(z);
    },
    setVelocityX: function(value) {
        this.vX = value;
    },
    setVelocityY: function(value) {
        this.vY = value;
    },
    setVelocityZ: function(value) {
        this.vZ = value;
    },
    getVelocityX: function() {
        return this.vX;
    },
    getVelocityY: function() {
        return this.vY;
    },
    getVelocityZ: function() {
        return this.vZ;
    },
    //Easing
    getEasing: function() {
        return this.easing;
    },
    fireEvent: function(event) {
        if (this.element) {
            this.element.fireEvent.apply(this.element, [event]);
        }
    },
    startTimer: function() {
        // console.log("startTimer");
        if (this.animiationIntervalID) this.stopTimer();
        this.startTime = new Date();
        var me = this;
        this.animiationIntervalID = setInterval(
            function() {
                me.onTapUpdate();
            }, 1000 / 30
        );
        this.onTimerStart();
    },
    stopTimer: function() {
        clearInterval(this.animiationIntervalID);
        this.startTime = null;
        this.onTimerStop();
    },
    isVirtual: function() {
        return this.type === "virtual";
    },
    addVirtual: function(virtualCursor) {
        this.virtualCursors.push(virtualCursor);
    },
    _onTapUpdate: function() {
        // console.log("_onTapUpdate");
        if (!this.startTime) {
            this.stopTimer();
            return;
        }
        var now = new Date();
        var time = now - this.startTime;
        this.onTimerUpdate(time);
        if (time >= this.currentClickDelay) {
            this.stopTimer();
            this.onTimerComplete();
        }
    },
    onTimerStart: function() {
        // console.log("onTimerStart");
        this.icon.setStyle({
            "transitionDuration": this.currentClickDelay / 1000 + "s"
        });
        this.icon.addClass("active-timer");
    },
    onTimerStop: function() {
        // console.log("onTimerStop");
        this.icon.setStyle({
            "transitionDuration": "0s"
        });
        this.icon.removeClass("active-timer");
    },
    onTimerUpdate: function(time) {},
    onTimerComplete: function() {
        if (this.element) {
            this.dispatchDown();
            this.dispatchUp();
            this.dispatchClick();
            this.dispatchTap();

            if (this.multitapEnabled || this.element.hasMultitap()) {
                var me = this;
                setTimeout(function() {
                    me.startTimer();
                }, 100);
            } else {
                this.release();
            }
        } else {
            this.release();
        }
    },
    dispatchOver: function(element) {
        if(element) this.setElement(element);
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("MouseEvent");
            mouseEvent.initMouseEvent("mouseover", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);
            this.onElementOver(this.element);
        }
    },
    dispatchMove: function(element) {
        if(element) this.setElement(element);
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("MouseEvent");
            mouseEvent.initMouseEvent("mousemove", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);
            this.onElementMove(this.element);
            if(this.manager.isPressDownEnabled() && this.element.isTappable()) {
                if(!this.isDown() && this.getZ() < this.manager.getPressThreshold()) {
                    this.dispatchDown(element);
                }else if(this.isDown() && this.getZ() > this.manager.getPressThreshold()) {
                    this.dispatchUp(element);
                }
            }
        }
    },
    dispatchOut: function(element) {
        if(element) this.setElement(element);
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("MouseEvent");
            mouseEvent.initMouseEvent("mouseout", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);

            //if(this.isDown()) this.dispatchUp(element, false);
            this.onElementOut(this.element);
        }
    },
    dispatchDown: function(element) {
        if(element) this.setElement(element);
        this._startPoint = {x:this.icon.getX(), y: this.icon.getY()};
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("MouseEvent");
            mouseEvent.initMouseEvent("mousedown", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);
            this.onElementDown(this.element);
        }
    },
    dispatchUp: function(element, dispatchClick) {
        if(!LeapManagerUtils.exists(dispatchClick)) dispatchClick = true;
        if(element) this.setElement(element);
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("MouseEvent");
            mouseEvent.initMouseEvent("mouseup", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);
            this.onElementUp(this.element);

            var distance = LeapManagerUtils.distance(this._startPoint, {x:this.icon.getX(), y: this.icon.getY()});
            if(dispatchClick && distance > 0 && distance < 100) {
                this.dispatchClick();
                this.dispatchTap();
            }
        }
    },
    dispatchClick: function(element) {
        if(element) this.setElement(element);
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("MouseEvent");
            mouseEvent.initMouseEvent("click", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);
        }
    },
    dispatchTap: function(element) {
        if(element) this.setElement(element);
        if(this.hasElement()) {
            var mouseEvent = document.createEvent("UIEvent");
            mouseEvent.initUIEvent("tap", true, false, window, 1, this.icon.getX(), this.icon.getY(), this.icon.getX(), this.icon.getY(), false, false, false, false, 0, this.element);
            this.element.fireEvent(mouseEvent);
        }
    }
};

var CursorManager = function(config) {
    this.globalInteractiveSelector = '.leap-interactive';
    this.cursorContainerClass = 'leap-cursor-container';
    this.leapCursorClass = 'leap-cursor';

    this.interactiveSelector = config.interactiveSelector || null;
    this.untappableSelector = config.untappableSelector || null;
    this.pressThreshold = config.pressThreshold || 0;
    this.enableHoverTap = config.enableHoverTap === true;
    this.enablePressDown = config.enablePressDown === true;
    this.greedySelector = config.greedySelector || null;

    if (!this.cursorContainer) {
        this.cursorContainer = new LeapElement(document.createElement('div'));
        var root = config.root || document.body;
        root.appendChild(this.cursorContainer.element);
        this.cursorContainer.addClass(this.cursorContainerClass);
        this.cursorContainer.setStyle({
            zIndex: 100000,
            position: "fixed",
            top: "0px",
            left: "0px"
        });
    }
};

CursorManager.prototype = {
    cursorContainer: null,
    elementLookup: {},
    mouseEvent: null,
    interactiveSelector: "",
    cursorLookup: {},
    isHoverTapEnabled:function(){
        return this.enableHoverTap === true;
    },
    isPressDownEnabled: function() {
        return this.enablePressDown === true;
    },
    getPressThreshold: function() {
        return this.pressThreshold || 0;
    },
    get: function(source, id, type) {
        if(type == null) type = "real";
        LeapManagerUtils.createStructure(this.cursorLookup, [type, source]);
        return this.cursorLookup[type][source][id];
    },
    add: function(cursor) {
        var type = cursor.type || "real";
        var source = cursor.source || "default";
        var id = cursor.id || 0;
        LeapManagerUtils.createStructure(this.cursorLookup, [type, source]);

        if(!LeapManagerUtils.exists(this.cursorLookup[type][source][id])) {
            this.cursorLookup[type][source][id] = cursor;
            this.cursorContainer.appendChild(cursor.icon);
            cursor.icon.addClass(this.leapCursorClass);
            cursor.setManager(this);
            cursor.onAdded();
            return cursor;
        }else {
            return this.cursorLookup[type][source][id];
        }
    },
    remove: function(cursor) {
        var type = cursor.type || "real";
        var source = cursor.source || "default";
        var id = cursor.id || 0;

        if(!cursor.isVirtual() && LeapManagerUtils.testStructure(this.elementLookup, [cursor.source, cursor.id])) {
            var element = this.elementLookup[cursor.source][cursor.id];
             if (element && element.isAttractor()) {
                cursor.setAttractor(null);
                //Release Cursor
                if (element.hasCursor()) element.release();
            }
            if(element) {
                this.cursorOut(cursor, element, {x:cursor.icon.getX(), y:cursor.icon.getY()});
            }
            this.elementLookup[cursor.source][cursor.id] = null;
        }

        var virtualCursor;
        for (var i = 0; i < cursor.virtualCursors.length; i++) {
            virtualCursor = cursor.virtualCursors[i];
            this.removeVirtualCursor(virtualCursor);
        }
        cursor.virtualCursors = [];
        cursor.setManager(null);
        cursor.onRemoved();
        if(LeapManagerUtils.exists(cursor.icon.getParent())) this.cursorContainer.removeChild(cursor.icon);
        if(LeapManagerUtils.testStructure(this.cursorLookup, [type, source])) {
            this.cursorLookup[type][source][cursor.id] = null;
            delete this.cursorLookup[type][source][cursor.id];
        }
        return true;
    },
    pruneCursors: function(source, activeIDs, type) {
        if(!LeapManagerUtils.exists(type)) type = "real";
        if(LeapManagerUtils.testStructure(this.cursorLookup, [type, source])) {
            var cursor,
                cursorIndex,
                remove = [];
            for(cursorIndex in this.cursorLookup[type][source]){
                cursor = this.cursorLookup[type][source][cursorIndex];
                if(cursor instanceof Cursor) {
                    if(activeIDs.indexOf(cursor.id) === - 1) {
                        remove.push(cursor);
                    }
                }
            }

            for (var i = 0; i < remove.length; i++) {
                this.remove(remove[i]);
            }
        }
    },
    update: function() {
        var windowPoint, destinationPoint, xDiff, yDiff, xRatio, yRatio, halfWidth, halfHeight, minPull = 0.1,
            maxPull = 1,
            bounds, originalElement, element, i, cursor,
            typeIndex, sourceIndex, cursorIndex;
        for(typeIndex in this.cursorLookup){
            for(sourceIndex in this.cursorLookup[typeIndex]){
                for(cursorIndex in this.cursorLookup[typeIndex][sourceIndex]){
                    cursor = this.cursorLookup[typeIndex][sourceIndex][cursorIndex];
                    if(cursor instanceof Cursor) {
                        //Virtual Cursors just get moved, but are not used in detection.
                        if(cursor.isVirtual()) {
                            cursor.icon.setX(cursor.icon.getX() + cursor.getVelocityX());
                            cursor.icon.setY(cursor.icon.getY() + cursor.getVelocityY());
                            continue;
                        }

                        if (!this.elementLookup[cursor.source]) this.elementLookup[cursor.source] = {};
                        if (!this.elementLookup[cursor.source][cursor.id]) this.elementLookup[cursor.source][cursor.id] = null;
                        windowPoint = {
                            x: Math.round(cursor.getX() * window.innerWidth),
                            y: Math.round(cursor.getY() * window.innerHeight)
                        };
                        element = this.elementLookup[cursor.source][cursor.id];
                        //Cursor Is Not enabled, check for an object under it
                        if (!cursor.isEnabled()) {
                            if (element) {
                                if (element.isAttractor()) {
                                    cursor.setAttractor(null);
                                    //Release Cursor
                                    if (element.hasCursor()) element.release();
                                }
                                this.cursorOut(cursor, element);
                                this.elementLookup[cursor.source][cursor.id] = null;
                            }
                            continue;
                        }
                        halfWidth = (cursor.icon.getWidth() / 2);
                        halfHeight = (cursor.icon.getHeight() / 2);
                        if (!cursor.isCaptured()) {
                            if (cursor.attractor) {
                                bounds = cursor.attractor.element.getBoundingClientRect();
                                destinationPoint = {
                                    x: Math.round((bounds.left + (bounds.width / 2)) - halfWidth),
                                    y: Math.round((bounds.top + (bounds.height / 2)) - halfHeight)
                                };
                                xDiff = destinationPoint.x - cursor.icon.getX();
                                yDiff = destinationPoint.y - cursor.icon.getY();
                                xRatio = Math.abs(xDiff / (bounds.width / 2));
                                yRatio = Math.abs(yDiff / (bounds.height / 2));
                                if (xRatio > 1) xRatio = 1;
                                if (yRatio > 1) yRatio = 1;
                                xRatio = Math.abs(1 - xRatio);
                                yRatio = Math.abs(1 - yRatio);
                                cursor.setVelocityXYZ(
                                xDiff * Math.max(minPull, Math.min(maxPull, xRatio)), yDiff * Math.max(minPull, Math.min(maxPull, yRatio)), 0);
                                if (Math.abs(cursor.getVelocityX()) <= 0.1 && Math.abs(cursor.getVelocityY()) <= 0.1) {
                                    cursor.setVelocityXYZ(0, 0, 0);
                                    cursor.icon.setX(destinationPoint.x);
                                    cursor.icon.setY(destinationPoint.y);
                                    cursor.attractor.capture(cursor);
                                }
                            } else {
                                xDiff = (windowPoint.x - halfWidth) - cursor.icon.getX();
                                yDiff = (windowPoint.y - halfHeight) - cursor.icon.getY();
                                cursor.setVelocityXYZ(xDiff * cursor.getEasing(), yDiff * cursor.getEasing());
                            }
                        }
                        cursor.icon.setX(cursor.icon.getX() + cursor.getVelocityX());
                        cursor.icon.setY(cursor.icon.getY() + cursor.getVelocityY());
                        element = this.getCollidingElements(windowPoint);
                        originalElement = this.elementLookup[cursor.source][cursor.id];
                        if (element) {
                            if (originalElement == null) {
                                this.elementLookup[cursor.source][cursor.id] = element;
                                if (element.isAttractor() && !element.hasCursor() && cursor.attractor == null && cursor.captureHost == null) {
                                    cursor.setAttractor(element);
                                }
                                this.cursorOver(cursor, element);
                            }
                            this.cursorMove(cursor, element);
                        }
                        if (originalElement && originalElement !== element) {
                            if (originalElement.isAttractor()) {
                                cursor.setAttractor(null);
                                if (originalElement.hasCursor()) originalElement.release(cursor);
                            }
                            this.cursorOut(cursor, originalElement);
                            this.elementLookup[cursor.source][cursor.id] = element;
                            if (element) {
                                this.cursorOver(cursor, element);
                                if (element.isAttractor() && cursor.attractor == null && cursor.captureHost == null) {
                                    if (!(element.hasCursor())) cursor.setAttractor(element);
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    cursorOver: function(cursor, element) {
        cursor.dispatchOver(element);
    },
    cursorMove: function(cursor, element) {
       cursor.dispatchMove(element);
    },
    cursorOut: function(cursor, element) {
        cursor.dispatchOut(element);
    },
    cursorDown: function(cursor, element) {
        cursor.dispatchDown(element);
    },
    cursorUp: function(cursor, element) {
        cursor.dispatchUp(element);
    },

    getCollidingElements: function(point) {
        var selector = this.globalInteractiveSelector;
        if(typeof(this.interactiveSelector) === "string" && this.interactiveSelector.length >0) {
            selector += ", " + this.interactiveSelector;
        }

        var interactiveElements = LeapManagerUtils.getQueryAll("interactiveElements", selector) || [],
            horizontalPadding, verticalPadding, i, element, bounds, withinXBounds, withinYBounds;

        for (i = interactiveElements.length-1; i >= 0; i--) {
            element = interactiveElements[i];
            if (!LeapManagerUtils.isElementVisible(element)) continue;
            bounds = element.getBoundingClientRect();
            element = LeapManagerUtils.getLeapElement(element);
            if(element) {
                horizontalPadding = element.isAttractor() ? element.getAttractorPadding().x : 0;
                verticalPadding = element.isAttractor() ? element.getAttractorPadding().y : 0;
                // console.log(point.x + " : " + (bounds.left - horizontalPadding) + " : " + (bounds.left + bounds.width + horizontalPadding));
                // console.log(point.y + " : " + (bounds.top - verticalPadding) + " : " + (bounds.top + bounds.height + verticalPadding));
                withinXBounds = point.x > (bounds.left - horizontalPadding) && point.x < (bounds.left + bounds.width + horizontalPadding);
                withinYBounds = point.y > (bounds.top - verticalPadding) && point.y < (bounds.top + bounds.height + verticalPadding);
                if (withinXBounds && withinYBounds) {
                    if(element.hasRelay()) {
                        element = LeapManagerUtils.getLeapElement(LeapManagerUtils.getQuery(element.getID() + "-relay", element.getRelay()));
                    }

                    if(element) {
                        if(element.isTappable() && typeof(this.untappableSelector) === "string" && this.untappableSelector.length >0) {
                            var untappableElements = LeapManagerUtils.getQueryAll("untappableElements", this.untappableSelector) || [];
                            for (i = 0; i < untappableElements.length; i++) {
                                if(untappableElements[i] === element.getElement()) {
                                    element.setAttribute("leap-disable-tap", "true");
                                    break;
                                }
                            }
                        }
                        return element;
                    }
                }
            }
        }

        if(this.greedySelector !== null) {
            element = LeapManagerUtils.getLeapElement(LeapManagerUtils.getQuery("greedySelector", this.greedySelector));
            if(element.hasRelay()) {
                element = LeapManagerUtils.getLeapElement(LeapManagerUtils.getQuery(element.getID() + "-relay", element.getRelay()));
            }
            return element;
        }else {
            return null;
        }

    },
    getVirtualCursor: function (source, id) {
        return this.get(source, id, "virtual");
    },
    addVirtualCursor: function (cursor) {
        return this.add(cursor);
    },
    removeVirtualCursor: function(cursor) {
        return this.remove(cursor);
    }
};

var MouseSimulator = (function() {
    var MOUSE_CURSOR_CLASS = "leap-mouse-cursor";
    return {
        cursorManager: null,
        mouseCursor: null,
        init: function(cursorManager, cursorConfig) {
            this.cursorManager = cursorManager;
            var icon = new LeapElement(document.createElement('div'));
            icon.addClass(MOUSE_CURSOR_CLASS);
            var cfg = {
                source: "mouse",
                id: 1,
                icon: icon
            };
            LeapManagerUtils.extendIf(cfg, cursorConfig);
            this.mouseCursor = new Cursor(cfg);
            this.enable();
        },
        enable: function() {
            this._onMouseMove = LeapManagerUtils.bind(this.onMouseMove, this);
            this._onMouseClick = LeapManagerUtils.bind(this.onMouseClick, this);
            document.addEventListener('mousemove', this._onMouseMove);
            document.addEventListener('click', this._onMouseClick);
            this.cursorManager.add(this.mouseCursor);
        },
        disable: function() {
            if (!this.mouseCursor) return;
            document.removeEventListener('mousemove', this._onMouseMove);
            document.removeEventListener('click', this._onMouseClick);
            this.cursorManager.remove(this.mouseCursor);
            this.mouseCursor = null;
        },
        update: function(x, y, z) {
            this.mouseCursor.update(x, y, z);
        },
        onMouseMove: function(event) {
            event = event || window.e;
            var x = 0,
                y = 0,
                z = 0;
            if (event.pageX || event.pageY) {
                x = event.pageX;
                y = event.pageY;
            } else {
                x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                y = event.clientY + document.body.scollTop + document.documentElement.scrollTop;
            }
            x /= window.innerWidth;
            y /= window.innerHeight;
            z = this.currentZ;
            this.update(x, y, z);
        },
        onMouseClick: function(event) {}
    };
})();

var DualSwipe = function(firstGesture, secondGesture, direction) {
    this.firstGesture = firstGesture;
    this.secondGesture = secondGesture;
    this.direction = direction;
    this.type = "dual-swipe";
    this.state = "stop";
};

var LeapManager = (function() {
    'use strict';
    var LEAP_POINTABLE_CURSOR_CLASS = "leap-pointable-cursor";
    var LEAP_POINTABLE_VIRTUAL_CURSOR_CLASS = "leap-pointable-virtual-cursor";
    var LEAP_POINTABLE_VIRTUAL_SCROLLER_CURSOR_CLASS = "leap-pointable-virtual-scroller-cursor";
    var LEAP_SOURCE = "leap";
    var defaultConfig = {
        maxCursors: 1,
        enableTouchScrolling: false,
        enableScrollbarScrolling: true,
        enableHoverTap: true,
        enablePressDown: false,
        pressThreshold: 0,
        simulateWithMouse: false,
        enableInBackground: false,
        cacheQueries: true,
        enableMetaGestures: true,
        enableDefaultMetaGestureActions: true,
        metaGestureMaxDelay: 1200,
        greedySelector: null,
        root: null,
        gestureCallback: null,
        gestureScope: null,
        interactiveSelector: null,
        enableSenchaTouch: false,
        boundary: {
            top: 350,
            left: -100,
            right: 100,
            bottom: 150
        },
        touchScrollingConfig: {
            scrollVector: {x:0, y:1, z:0},
            scrollMaxSpeed: 7,
            scrollMinSpeed: 2,
            scrollMaxDuration: 6
        },
        scrollbarScrollingConfig: {
            resetDelay: 1000,
            scrollMaxSpeed: 7,
            scrollMinSpeed: 2,
            scrollMaxDuration: 6
        },
        cursorConfig: {
            multitapEnabled: false,
            clickDelay: 1000
        },
        mouseCursorConfig: {
            multitapEnabled: false,
            clickDelay: 1000
        },
        loopConfig: {
            enableGestures: true
        }
    };
    return {
        cursorManager: null,
        gestureHistory: {},
        init: function(config) {
            LeapManagerUtils.extendIf(config, defaultConfig);
            this.boundary = config.boundary;
            this.maxCursors = config.maxCursors;
            this.simulateWithMouse = config.simulateWithMouse;
            this.gestureCallback = config.gestureCallback;
            this.gestureScope = config.gestureScope;
            this.cursorConfig = config.cursorConfig;

            this.enableTouchScrolling = config.enableTouchScrolling;
            this.touchScrollingConfig = config.touchScrollingConfig;

            this.enableScrollbarScrolling = config.enableScrollbarScrolling;
            this.scrollbarScrollingConfig = config.scrollbarScrollingConfig;

            this.enableMetaGestures = config.enableMetaGestures;
            this.enableDefaultMetaGestureActions = config.enableDefaultMetaGestureActions;
            this.metaGestureMaxDelay = config.metaGestureMaxDelay || 500;

            //Sencha Touch Switch
            if (config.enableSenchaTouch) {
                if (config.interactiveSelector == null) {
                    config.interactiveSelector = "";
                } else {
                    config.interactiveSelector += ",";
                }
                config.interactiveSelector += ["a", ".x-tab", ".x-button", ".x-video-ghost", ".x-scroll-scroller", ".x-list-item"].join(",");
                config.untappableSelector = [".x-scroll-scroller"].join(", ");
            }
            this.cursorManager = new CursorManager({
                root: config.root,
                interactiveSelector: config.interactiveSelector,
                untappableSelector: config.untappableSelector,
                enableHoverTap: config.enableHoverTap,
                enablePressDown: config.enablePressDown,
                pressThreshold: config.pressThreshold,
                greedySelector: config.greedySelector
            });
            if (this.simulateWithMouse) MouseSimulator.init(this.cursorManager, config.mouseCursorConfig || {});
            //Active Tab/Window Checking
            var me = this;
            me.isActiveWindow = true;
            if (!config.enableInBackground) {
                window.addEventListener('blur', function() {
                    me.isActiveWindow = false;
                });
                window.addEventListener('focus', function() {
                    me.isActiveWindow = true;
                });
            }
            var callback = function(frame) {
                    me.onLoop(frame);
                };
            if(Leap !== null) Leap.loop(config.loopConfig, callback);
        },
        onLoop: function(frame) {
            if (!this.isActiveWindow) return;
            this.cursorManager.update();
            this.updatePointables(frame);
            this.updateGestures(frame);
        },
        updatePointables: function(frame) {
            var pointable, pointableIndex, cursor, posX, posY, posZ, cursorIndex, currentCursors = [];
            if (frame && frame.pointables) {
                for (pointableIndex = 0; pointableIndex < frame.pointables.length && pointableIndex < this.maxCursors; pointableIndex++) {
                    pointable = frame.pointables[pointableIndex];
                    if (pointable) {
                        posX = LeapManagerUtils.map(pointable.tipPosition[0], this.boundary.left, this.boundary.right, 0, 1);
                        posY = LeapManagerUtils.map(pointable.tipPosition[1], this.boundary.bottom, this.boundary.top, 1, 0);
                        posZ = pointable.tipPosition[2];
                        cursor = this.getCursor(pointable.id, {
                            x: posX,
                            y: posY,
                            z: posZ
                        });
                        currentCursors.push(cursor.id);
                        cursor.update(posX, posY, posZ);
                    }
                }
            }

            this.cursorManager.pruneCursors(LEAP_SOURCE, currentCursors);
        },
        getCursor: function(id, position) {
            var cursor = this.cursorManager.get(LEAP_SOURCE, id);
            if (cursor) return cursor;

            var icon = new LeapElement(document.createElement('div'));
            icon.addClass(LEAP_POINTABLE_CURSOR_CLASS);
            var cfg = {
                source: LEAP_SOURCE,
                id: id,
                position: position,
                icon: icon
            };
            LeapManagerUtils.extend(cfg, this.cursorConfig);
            cursor = new Cursor(cfg);
            this.cursorManager.add(cursor);
            return cursor;
        },
        updateGestures: function(frame) {
            var me = this,
                cursor;

            if (frame.gestures.length > 0) {
                frame.gestures.forEach(function(gesture) {
                    if (gesture.pointableIds && gesture.pointableIds.length > 0) {
                        gesture.pointableIds.forEach(function(pointableId) {
                            cursor = me.cursorManager.get(LEAP_SOURCE, pointableId);
                            if (cursor instanceof Cursor) {

                                //Per Element Gesture Events
                                if (cursor.hasElement()) {
                                    var evt = document.createEvent("Event");
                                    evt.initEvent("leap-"+gesture.type, true, true);
                                    evt.state = gesture.state;
                                    evt.gesture = gesture;
                                    cursor.element.fireEvent(evt);

                                    evt = document.createEvent("Event");
                                    evt.initEvent("leap-"+gesture.type+"-"+gesture.state, true, true);
                                    evt.state = gesture.state;
                                    evt.gesture = gesture;
                                    cursor.element.fireEvent(evt);
                                }

                                //Catch-All Gesture Callback
                                if (me.gestureCallback) {
                                    me.gestureCallback.call(me.gestureScope || me, gesture);
                                }

                                //Scrolling Simulation
                                if((me.enableTouchScrolling || me.enableScrollbarScrolling) && gesture.type === "circle") {
                                    var position = {
                                        x: LeapManagerUtils.map(gesture.center[0], me.boundary.left, me.boundary.right, 0, 1),
                                        y: LeapManagerUtils.map(gesture.center[1], me.boundary.bottom, me.boundary.top, 1, 0),
                                        z: 0
                                    };

                                    var speed;
                                    var virtualSource = 'leap-scroller';
                                    var virtualCursor = me.cursorManager.getVirtualCursor(virtualSource, gesture.id);

                                    if(me.enableTouchScrolling) {
                                        if (gesture.state === "start") {
                                            cursor.disableTap();
                                            if(virtualCursor) {
                                                me.removeVirtualCursor(virtualCursor);
                                            }

                                            var icon = new LeapElement(document.createElement('div'));
                                            icon.addClass(LEAP_POINTABLE_CURSOR_CLASS);
                                            icon.addClass(LEAP_POINTABLE_VIRTUAL_CURSOR_CLASS);
                                            icon.addClass(LEAP_POINTABLE_VIRTUAL_SCROLLER_CURSOR_CLASS);
                                            var cfg = {
                                                source: virtualSource,
                                                id: gesture.id,
                                                position: position,
                                                icon: icon
                                            };

                                            cfg.virtualParent = cursor;
                                            virtualCursor = new Cursor(cfg);
                                            virtualCursor.onAdded = function() {
                                                this.dispatchDown();
                                            };
                                            virtualCursor.onRemoved = function() {
                                                this.setVelocityXYZ(0,0,0);
                                                this.dispatchUp();
                                            };

                                            me.cursorManager.addVirtualCursor(virtualCursor);

                                        } else if (gesture.state === "stop" && virtualCursor) {
                                            cursor.restartTap();
                                            me.cursorManager.removeVirtualCursor(virtualCursor);
                                        } else if(virtualCursor) {

                                            speed = LeapManagerUtils.map(
                                                gesture.duration/1000000,
                                                0, me.touchScrollingConfig.scrollMaxDuration,
                                                me.touchScrollingConfig.scrollMinSpeed, me.touchScrollingConfig.scrollMaxSpeed);

                                            if(gesture.normal[2] > 0) {
                                                virtualCursor.setVelocityXYZ(
                                                    speed * me.touchScrollingConfig.scrollVector.x,
                                                    speed * me.touchScrollingConfig.scrollVector.y,
                                                    speed * me.touchScrollingConfig.scrollVector.z
                                                );
                                            }else{
                                                virtualCursor.setVelocityXYZ(
                                                    speed * -me.touchScrollingConfig.scrollVector.x,
                                                    speed * -me.touchScrollingConfig.scrollVector.y,
                                                    speed * -me.touchScrollingConfig.scrollVector.z
                                                );
                                            }

                                            virtualCursor.dispatchMove();
                                        }
                                    } else if(me.enableScrollbarScrolling) {
                                        if (gesture.state === "start") {
                                            if(LeapManagerUtils.exists(cursor._lastElementTime)) {
                                                var timeDiff = new Date() - cursor._lastElementTime;
                                                if(timeDiff > me.scrollbarScrollingConfig.resetDelay) {
                                                    cursor._scrollElement = cursor.getElement();
                                                }
                                            }
                                            cursor._lastElementTime = new Date();

                                            if(cursor.getElement() && !LeapManagerUtils.exists(cursor._scrollElement)) {
                                                cursor._scrollElement = cursor.getElement();
                                            }

                                            if(LeapManagerUtils.exists(cursor._scrollElement)){
                                                cursor.disableTap();
                                            }
                                        } else if (gesture.state === "update") {
                                            if(LeapManagerUtils.exists(cursor._scrollElement)) {
                                                cursor._lastElementTime = new Date();
                                                speed = LeapManagerUtils.map(
                                                    gesture.duration/1000000,
                                                    0, me.scrollbarScrollingConfig.scrollMaxDuration,
                                                    me.scrollbarScrollingConfig.scrollMinSpeed, me.scrollbarScrollingConfig.scrollMaxSpeed);

                                                if(gesture.normal[2] > 0) {
                                                    cursor._scrollElement.scroll(-speed);
                                                } else {
                                                    cursor._scrollElement.scroll(speed);
                                                }
                                            }
                                        }else if(gesture.state === "end") {
                                            cursor.restartTap();
                                        }
                                    }
                                }
                            }
                        });
                    }

                    //Swipe MetaGesture Testing
                    if(me.enableMetaGestures && gesture.state === "stop" && gesture.type === "swipe") {
                        if(!(me.gestureHistory[gesture.type] instanceof Array)) me.gestureHistory[gesture.type] = [];
                        gesture.timestamp = new Date().getTime();

                        var i,
                            largest = 0,
                            largestIndex =0,
                            timeDiff = 0,
                            currentGesture,
                            ignoreZGestures = true,
                            previousGesture;
                        for (i = 0; i < (ignoreZGestures ? 2 : 3); i++) {
                            if(Math.abs(gesture.direction[i]) > largest) {
                                largest = Math.abs(gesture.direction[i]);
                                largestIndex = i;
                            }
                        }

                        if(largestIndex === 0) {
                            gesture._direction = gesture.direction[0] > 0 ? "right" : "left";
                        } else if(largestIndex === 1) {
                            gesture._direction = gesture.direction[1] > 0 ? "up" : "down";
                        }else {
                            gesture._direction = gesture.direction[2] > 0 ? "backward" : "forward";
                        }

                        me.gestureHistory[gesture.type].push(gesture);

                        if(me.gestureHistory[gesture.type].length === 2) {
                            previousGesture = me.gestureHistory[gesture.type][0];
                            if(gesture._direction === previousGesture._direction) {
                                timeDiff = gesture.timestamp - previousGesture.timestamp;
                                console.log(timeDiff);
                                if(timeDiff < me.metaGestureMaxDelay) {
                                    var dualSwipe = new DualSwipe(gesture, previousGesture, gesture._direction);

                                    //Catch-All Gesture Callback
                                    if (me.gestureCallback) {
                                        me.gestureCallback.call(me.gestureScope || me, dualSwipe);
                                    }

                                    //MetaEvents are fired on the Body
                                    var evt = document.createEvent("Event");
                                    evt.initEvent("leap-"+dualSwipe.type, true, true);
                                    evt.state = gesture.state;
                                    evt.gesture = dualSwipe;
                                    document.body.dispatchEvent(evt);

                                    //Default Actions
                                    if(me.enableDefaultMetaGestureActions) {
                                        switch(dualSwipe.direction) {
                                            case "left":
                                                history.back();
                                                break;
                                            case "right":
                                                history.forward();
                                                break;
                                            case "up":
                                                break;
                                            case "down":
                                                break;
                                        }
                                    }
                                }
                            }
                        }

                        while(me.gestureHistory[gesture.type].length > 1) {
                            me.gestureHistory[gesture.type].shift();
                        }
                    }
                });
            }
        }
    };
})();


text:
package seedu.address.logic.parser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import seedu.address.commons.util.CollectionUtil;
import seedu.address.commons.util.SubstringRange;
import seedu.address.model.ReadOnlyModel;

/**
 * A utility class that uses a {@link CommandLineScanner} to parse a string, breaking it down into its
 * individual {@link CommandLineParser.Argument} and {@link CommandLineParser.Flag}
 */
public class CommandLineParser {

    private static String MSG_ARG_NOT_PROVIDED = "Required argument not provided: %s";
    private static String MSG_FLAG_NOT_PROVIDED = "Required flag not provided: %s%s";
    private static String MSG_EXPECTED_KEYWORD = "Expected keyword: %s";
    private static String MSG_TOO_MANY_ARGS = "Too many arguments";
    private static String MSG_FLAG_MULTIPLE = "%s specified multiple times";

    private final List<ArgumentParser> arguments = new ArrayList<>();
    private final Map<String, FlagParser> flags = new HashMap<>();

    public CommandLineParser addArgument(ArgumentParser argument) {
        arguments.add(argument);
        return this;
    }

    public CommandLineParser addArgument(String keyword) {
        Parser<Object> parser = str -> {
            if (str.equals(keyword)) {
                return new Object(); // dummy object
            } else {
                SubstringRange range = new SubstringRange(0, str.length());
                throw new ParseException(String.format(MSG_EXPECTED_KEYWORD, keyword), range);
            }
        };
        arguments.add(new Argument<Object>(keyword, parser));
        return this;
    }

    public CommandLineParser putFlag(FlagParser flag) {
        flags.put(flag.getPrefix(), flag);
        return this;
    }

    private Collection<String> getPrefixesForFlags() {
        return flags.values().stream().map(flag -> flag.getPrefix()).collect(Collectors.toList());
    }

    private void reset() {
        // Reset all argument parsers
        for (ArgumentParser argument : arguments) {
            argument.reset();
        }

        // Reset all flag parsers
        for (FlagParser flag : flags.values()) {
            flag.reset();
        }
    }

    public void parse(String str) throws ParseException {
        reset();

        final CommandLineScanner scanner = new CommandLineScanner(str, getPrefixesForFlags());

        // Parse arguments
        for (ArgumentParser argument : arguments) {
            argument.parse(scanner);
        }

        if (!flags.isEmpty()) {
            // Parse flags
            Optional<CommandLineScanner.Flag> scannerFlag;
            while ((scannerFlag = scanner.nextFlag()).isPresent()) {
                FlagParser flag = flags.get(scannerFlag.get().prefix);
                assert flag != null; // CommandLineScanner should only return flags it recognizes
                flag.parseFlag(scannerFlag.get());
            }

            // Any non-optional flags that are not specified?
            for (FlagParser flag : flags.values()) {
                if (!flag.isOptional() && !flag.isPresent()) {
                    throw new ParseException(String.format(MSG_FLAG_NOT_PROVIDED, flag.getPrefix(), flag.getName()));
                }
            }
        } else {
            // Do we have any extra arguments that should not be there?
            scanner.skipWhitespace();
            if (!scanner.getRemainingInput().isEmpty()) {
                SubstringRange range = new SubstringRange(scanner.getInputPosition(), scanner.getInput().length());
                throw new ParseException(MSG_TOO_MANY_ARGS, range);
            }
        }
    }

    public List<String> autocomplete(ReadOnlyModel model, String str, int pos) {
        reset();

        final CommandLineScanner scanner = new CommandLineScanner(str, getPrefixesForFlags());

        // Autocomplete arguments
        for (ArgumentParser argument : arguments) {
            final List<String> candidates = argument.autocomplete(model, scanner, pos);
            if (scanner.getInputPosition() >= pos) {
                return candidates;
            }
        }

        // Autocomplete flags
        try {
            Optional<CommandLineScanner.Flag> scannerFlag;
            while ((scannerFlag = scanner.nextFlag()).isPresent()) {
                final FlagParser flag = flags.get(scannerFlag.get().prefix);
                final List<String> candidates = flag.autocomplete(model, scannerFlag.get(), pos);
                if (scanner.getInputPosition() >= pos) {
                    return candidates;
                }
            }
        } catch (ParseException e) {
            // The CommandLineScanner found an unrecognized flag prefix and so can't continue any more.
            return Collections.emptyList();
        }

        return Collections.emptyList();
    }

    public interface ArgumentParser {
        /** Name of the argument. */
        String getName();

        /** Resets the parser */
        default void reset() {}

        /**
         * Scans and parses in input from the provided {@link CommandLineScanner}.
         * @throws ParseException of there was an error parsing the input. The input position of the
         * CommandLineScanner must NOT be modified in this case.
         */
        void parse(CommandLineScanner scanner) throws ParseException;

        /**
         * Autocompletes the input from the provided {@link CommandLineScanner}, with the "caret position"
         * at pos.
         * @return the list of autocomplete suggestions if pos is within the range of the input handled by
         * this argument.
         */
        List<String> autocomplete(ReadOnlyModel model, CommandLineScanner scanner, int pos);
    }

    /**
     * An command line argument parser for a single argument of type T.
     */
    public static class Argument<T> implements ArgumentParser {
        private final String name;
        private Parser<? extends T> parser;
        private boolean present;
        private T value;
        private SubstringRange range;

        public Argument(String name, Parser<? extends T> parser) {
            assert !CollectionUtil.isAnyNull(name, parser);
            this.name = name;
            this.parser = parser;
        }

        @Override
        public String getName() {
            return name;
        }

        public void setParser(Parser<? extends T> parser) {
            assert parser != null;
            this.parser = parser;
        }

        public boolean isPresent() {
            return present;
        }

        public void set(T value, SubstringRange range) {
            assert !CollectionUtil.isAnyNull(value, range);
            this.value = value;
            this.range = range;
            present = true;
        }

        @Override
        public void reset() {
            present = false;
            value = null;
            range = null;
        }

        public T getValue() {
            assert present;
            return value;
        }

        public SubstringRange getRange() {
            assert present;
            return range;
        }

        /**
         * Parses the provided {@link CommandLineScanner.Argument}.
         */
        public void parse(CommandLineScanner.Argument arg) throws ParseException {
            final T value;
            try {
                value = parser.parse(arg.value);
            } catch (ParseException e) {
                final ParseExceptionBuilder builder = new ParseExceptionBuilder(e);
                builder.prependMessage(getName() + ": ");
                if (arg.quoted) {
                    builder.clearRanges()
                            .addRange(arg.range);
                } else {
                    builder.indentRanges(arg.range.getStart());
                }
                throw builder.build();
            }
            set(value, arg.range);
        }

        @Override
        public void parse(CommandLineScanner scanner) throws ParseException {
            Optional<CommandLineScanner.Argument> arg = scanner.peekNextArgument();
            if (!arg.isPresent()) {
                SubstringRange range = new SubstringRange(scanner.getInputPosition(), scanner.getInput().length());
                throw new ParseException(String.format(MSG_ARG_NOT_PROVIDED, name), range);
            }
            parse(arg.get());
            scanner.nextArgument();
        }

        /**
         * Autocompletes the input from the provided {@link CommandLineScanner.Argument}, with the
         * "caret position" at pos.
         */
        public List<String> autocomplete(ReadOnlyModel model, CommandLineScanner.Argument arg, int pos) {
            if (arg.quoted) {
                // TODO: we don't support quoted arguments yet because autocompleting them will be tricky
                // (e.g. need to requote the arguments)
                return Collections.emptyList();
            } else if (arg.range.contains(pos)) {
                return parser.autocomplete(model, arg.value, pos - arg.range.getStart());
            } else if (pos > arg.range.getEnd()) {
                // Attempt to parse this argument, in case other arguments/flags need this argument as
                // context for autocompletion
                try {
                    parse(arg);
                } catch (ParseException e) {
                    // This is okay as the validity of this argument may not be required for a successful
                    // autocomplete.
                }
            }
            return Collections.emptyList();
        }

        @Override
        public List<String> autocomplete(ReadOnlyModel model, CommandLineScanner scanner, int pos) {
            Optional<CommandLineScanner.Argument> arg = scanner.nextArgument();
            if (!arg.isPresent() && pos <= scanner.getInputPosition()) {
                // Caret position is within the blank space between the arguments and the flags sections
                return parser.autocomplete(model, "", 0);
            } else if (arg.isPresent()) {
                // Caret position is within the argument
                return autocomplete(model, arg.get(), pos);
            } else {
                // Caret is within the "flags" section
                return Collections.emptyList();
            }
        }
    }

    /**
     * A command line argument parser for parsing a rest argument of type T.
     */
    public static class RestArgument<T> extends Argument<T> {
        public RestArgument(String name, Parser<? extends T> parser) {
            super(name, parser);
        }

        @Override
        public void parse(CommandLineScanner scanner) throws ParseException {
            final CommandLineScanner.Argument restArgument = scanner.peekNextRestArgument();
            parse(restArgument);
            scanner.nextRestArgument();
        }

        @Override
        public List<String> autocomplete(ReadOnlyModel model, CommandLineScanner scanner, int pos) {
            return autocomplete(model, scanner.nextRestArgument(), pos);
        }
    }

    /**
     * A command line argument parser for parsing a variable number of arguments of type T.
     */
    public static class ListArgument<T> implements ArgumentParser {
        private final String name;
        private Parser<? extends T> parser;
        private final ArrayList<Argument<T>> arguments = new ArrayList<>();
        private SubstringRange range;

        public ListArgument(String name, Parser<? extends T> parser) {
            assert !CollectionUtil.isAnyNull(name, parser);
            this.name = name;
            this.parser = parser;
        }

        @Override
        public String getName() {
            return name;
        }

        public void setParser(Parser<? extends T> parser) {
            assert parser != null;
            this.parser = parser;
        }

        @Override
        public void reset() {
            arguments.clear();
            range = null;
        }

        public List<T> getValues() {
            return arguments.stream()
                            .map(arg -> arg.getValue())
                            .collect(Collectors.toList());
        }

        public SubstringRange getRange() {
            assert range != null;
            return range;
        }

        @Override
        public void parse(CommandLineScanner scanner) throws ParseException {
            scanner.skipWhitespace();
            range = new SubstringRange(scanner.getInputPosition(), scanner.getInputPosition());
            while (scanner.peekNextArgument().isPresent()) {
                final Argument<T> argument = new Argument<>(name + "[" + arguments.size() + "]", parser);
                argument.parse(scanner);
                arguments.add(argument);
                range = new SubstringRange(range.getStart(), scanner.getInputPosition());
            }
        }

        @Override
        public List<String> autocomplete(ReadOnlyModel model, CommandLineScanner scanner, int pos) {
            while (scanner.nextArgument().isPresent()) {
                final Argument<T> argument = new Argument<>(name + "[" + arguments.size() + "]", parser);
                final List<String> candidates = argument.autocomplete(model, scanner, pos);
                if (scanner.getInputPosition() >= pos) {
                    return candidates;
                }
            }
            return Collections.emptyList();
        }

    }

    public interface FlagParser {
        /** Returns the flag prefix */
        String getPrefix();

        /** Returns the flag name */
        String getName();

        /** Resets the flag parsing state */
        default void reset() {}

        /** Returns true if the flag is optional */
        boolean isOptional();

        /** Returns true if the flag has a value */
        boolean isPresent();

        /** Parses the {@link CommandLineScanner.Flag} */
        void parseFlag(CommandLineScanner.Flag flag) throws ParseException;

        /**
         * Autocompletes the {@link CommandLineScanner.Flag}, with the "caret position" at pos.
         * pos is guaranteed to be within the range of the flag.
         */
        List<String> autocomplete(ReadOnlyModel model, CommandLineScanner.Flag flag, int pos);
    }

    private abstract static class BaseFlag<T> implements FlagParser {

        private final String prefix;
        private final String name;
        private Parser<? extends T> parser;
        protected T value;
        protected boolean present;
        protected SubstringRange range;

        protected BaseFlag(String prefix, String name, Parser<? extends T> parser) {
            assert !CollectionUtil.isAnyNull(prefix, name, parser);
            this.prefix = prefix;
            this.name = name;
            this.parser = parser;
        }

        @Override
        public String getPrefix() {
            return prefix;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public boolean isPresent() {
            return present;
        }

        public void setParser(Parser<? extends T> parser) {
            assert parser != null;
            this.parser = parser;
        }

        @Override
        public void reset() {
            present = false;
        }

        @Override
        public void parseFlag(CommandLineScanner.Flag flag) throws ParseException {
            assert flag.prefix.equals(prefix);
            if (present) {
                throw new ParseException(String.format(MSG_FLAG_MULTIPLE, prefix), flag.range);
            }
            try {
                value = parser.parse(flag.value);
            } catch (ParseException e) {
                final ParseExceptionBuilder builder = new ParseExceptionBuilder(e);
                builder.prependMessage(getName() + ": ");
                if (flag.quoted) {
                    builder.clearRanges().addRange(flag.range);
                } else {
                    builder.indentRanges(flag.range.getStart());
                }
                throw builder.build();
            }
            present = true;
            range = flag.range;
        }

        @Override
        public List<String> autocomplete(ReadOnlyModel model, CommandLineScanner.Flag flag, int pos) {
            if (flag.quoted) {
                // TODO: we don't support quoted arguments yet because autocompleting them will be tricky
                // (e.g. need to requote the arguments)
                return Collections.emptyList();
            }
            return parser.autocomplete(model, flag.value, pos - flag.range.getStart());
        }
    }

    public static class Flag<T> extends BaseFlag<T> {

        public Flag(String prefix, String name, Parser<? extends T> parser) {
            super(prefix, name, parser);
        }

        public T getValue() {
            assert present;
            return value;
        }

        public SubstringRange getRange() {
            assert present;
            return range;
        }

        @Override
        public boolean isOptional() {
            return false;
        }

    }

    public static class OptionalFlag<T> extends BaseFlag<T> {

        public OptionalFlag(String prefix, String name, Parser<? extends T> parser) {
            super(prefix, name, parser);
        }

        public Optional<T> getValue() {
            return isPresent() ? Optional.of(value) : Optional.empty();
        }

        public Optional<SubstringRange> getRange() {
            return isPresent() ? Optional.of(range) : Optional.empty();
        }

        @Override
        public boolean isOptional() {
            return true;
        }

    }

}

redpajama_set_name: RedPajamaGithub


text:
<?php
if (!class_exists('EmployeesAdminManager')) {
	class EmployeesAdminManager extends AbstractModuleManager{

		public function initializeUserClasses(){

		}

		public function initializeFieldMappings(){

		}

		public function initializeDatabaseErrorMappings(){
			$this->addDatabaseErrorMapping('CONSTRAINT `Fk_User_Employee` FOREIGN KEY',"Can not delete Employee, please delete the User for this employee first.");
			$this->addDatabaseErrorMapping("Duplicate entry|for key 'employee'","A duplicate entry found");
		}

		public function setupModuleClassDefinitions(){
			$this->addModelClass('Employee');
			$this->addModelClass('EmploymentStatus');
		}

	}
}

if (!class_exists('Employee')) {
	class Employee extends ICEHRM_Record {

		public function getAdminAccess(){
			return array("get","element","save","delete");
		}

		public function getManagerAccess(){
			return array("get","element","save");
		}

		public function getUserAccess(){
			return array("get");
		}

		public function getUserOnlyMeAccess(){
			return array("element","save");
		}

		public function getUserOnlyMeAccessField(){
			return "id";
		}

		var $_table = 'Employees';
	}
}

if (!class_exists('EmploymentStatus')) {
	class EmploymentStatus extends ICEHRM_Record {

		var $_table = 'EmploymentStatus';

		public function getAdminAccess(){
			return array("get","element","save","delete");
		}

		public function getManagerAccess(){
			return array("get","element","save");
		}

		public function getUserAccess(){
			return array();
		}
	}
}


text:
package net.wasdev.gameon.room.engine.parser;

public class Verb extends Node {
    public final String name;

    public Verb(String name) {
        this.name = name.trim().toUpperCase();
        if (name.contains(":") || name.contains("/")) {
            throw new RuntimeException("Forbidden characters : or / found in verb name");
        }
    }

    public Type getType() {
        return Type.VERB;
    }

    public String getKey() {
        return "/V:" + name;
    }
}


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.databox.models;

import com.azure.core.annotation.Immutable;
import com.azure.core.util.logging.ClientLogger;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

/** Capacity of the sku. */
@Immutable
public final class SkuCapacity {
    @JsonIgnore private final ClientLogger logger = new ClientLogger(SkuCapacity.class);

    /*
     * Usable capacity in TB.
     */
    @JsonProperty(value = "usable", access = JsonProperty.Access.WRITE_ONLY)
    private String usable;

    /*
     * Maximum capacity in TB.
     */
    @JsonProperty(value = "maximum", access = JsonProperty.Access.WRITE_ONLY)
    private String maximum;

    /**
     * Get the usable property: Usable capacity in TB.
     *
     * @return the usable value.
     */
    public String usable() {
        return this.usable;
    }

    /**
     * Get the maximum property: Maximum capacity in TB.
     *
     * @return the maximum value.
     */
    public String maximum() {
        return this.maximum;
    }

    /**
     * Validates the instance.
     *
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
    }
}


text:
package java.io;

/**
 * The DataInput interface provides
 * for reading bytes from a binary stream and
 * reconstructing from them data in any of
 * the Java primitive types. There is also
 * a
 * facility for reconstructing a String
 * from data in
 * modified UTF-8
 * format.
 *

 * It is generally true of all the reading
 * routines in this interface that if end of
 * file is reached before the desired number
 * of bytes has been read, an EOFException
 * (which is a kind of IOException)
 * is thrown. If any byte cannot be read for
 * any reason other than end of file, an IOException
 * other than EOFException is
 * thrown. In particular, an IOException
 * may be thrown if the input stream has been
 * closed.
 *
 *
Modified UTF-8

 *

 * Implementations of the DataInput and DataOutput interfaces represent
 * Unicode strings in a format that is a slight modification of UTF-8.
 * (For information regarding the standard UTF-8 format, see section
 * 3.9 Unicode Encoding Forms of The Unicode Standard, Version
 * 4.0).
 * Note that in the following tables, the most significant bit appears in the
 * far left-hand column.
 *

 * All characters in the range '\u0001' to
 * '\u007F' are represented by a single byte:
 *
 *

 *

 *

 *
 *       Bit Values
 *

 *

 *       Byte 1
 *
 *

 *

 *             0
 *             bits 6-0
 *

 *

 *
 *

 *

 *

 *
 *

 * The null character '\u0000' and characters in the
 * range '\u0080' to '\u07FF' are
 * represented by a pair of bytes:
 *
 *

 *

 *

 *
 *       Bit Values
 *

 *

 *       Byte 1
 *
 *

 *

 *             1
 *             1
 *             0
 *             bits 10-6
 *

 *

 *
 *

 *

 *       Byte 2
 *
 *

 *

 *             1
 *             0
 *             bits 5-0
 *

 *

 *
 *

 *

 *

 *
 *

 * char values in the range '\u0800' to
 * '\uFFFF' are represented by three bytes:
 *
 *

 *

 *

 *
 *       Bit Values
 *

 *

 *       Byte 1
 *
 *

 *

 *             1
 *             1
 *             1
 *             0
 *             bits 15-12
 *

 *

 *
 *

 *

 *       Byte 2
 *
 *

 *

 *             1
 *             0
 *             bits 11-6
 *

 *

 *
 *

 *

 *       Byte 3
 *
 *

 *

 *             1
 *             0
 *             bits 5-0
 *

 *

 *
 *

 *

 *

 *
 *

 * The differences between this format and the
 * standard UTF-8 format are the following:
 *

 *
The null byte '\u0000' is encoded in 2-byte format
 *     rather than 1-byte, so that the encoded strings never have
 *     embedded nulls.
 *
Only the 1-byte, 2-byte, and 3-byte formats are used.
 *
Supplementary characters
 *     are represented in the form of surrogate pairs.
 *

 * @author  Frank Yellin
 * @version 1.25, 04/10/06
 * @see     java.io.DataInputStream
 * @see     java.io.DataOutput
 * @since   JDK1.0
 */
public
interface DataInput {
    /**
     * Reads some bytes from an input
     * stream and stores them into the buffer
     * array b. The number of bytes
     * read is equal
     * to the length of b.
     *

     * This method blocks until one of the
     * following conditions occurs:

     *

     *
b.length
     * bytes of input data are available, in which
     * case a normal return is made.
     *
     *
End of
     * file is detected, in which case an EOFException
     * is thrown.
     *
     *
An I/O error occurs, in
     * which case an IOException other
     * than EOFException is thrown.
     *

     *

     * If b is null,
     * a NullPointerException is thrown.
     * If b.length is zero, then
     * no bytes are read. Otherwise, the first
     * byte read is stored into element b[0],
     * the next one into b[1], and
     * so on.
     * If an exception is thrown from
     * this method, then it may be that some but
     * not all bytes of b have been
     * updated with data from the input stream.
     *
     * @param     b   the buffer into which the data is read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    void readFully(byte b[]) throws IOException;

    /**
     *
     * Reads len
     * bytes from
     * an input stream.
     *

     * This method
     * blocks until one of the following conditions
     * occurs:

     *

     *
len bytes
     * of input data are available, in which case
     * a normal return is made.
     *
     *
End of file
     * is detected, in which case an EOFException
     * is thrown.
     *
     *
An I/O error occurs, in
     * which case an IOException other
     * than EOFException is thrown.
     *

     *

     * If b is null,
     * a NullPointerException is thrown.
     * If off is negative, or len
     * is negative, or off+len is
     * greater than the length of the array b,
     * then an IndexOutOfBoundsException
     * is thrown.
     * If len is zero,
     * then no bytes are read. Otherwise, the first
     * byte read is stored into element b[off],
     * the next one into b[off+1],
     * and so on. The number of bytes read is,
     * at most, equal to len.
     *
     * @param     b   the buffer into which the data is read.
     * @param off  an int specifying the offset into the data.
     * @param len  an int specifying the number of bytes to read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    void readFully(byte b[], int off, int len) throws IOException;

    /**
     * Makes an attempt to skip over
     * n bytes
     * of data from the input
     * stream, discarding the skipped bytes. However,
     * it may skip
     * over some smaller number of
     * bytes, possibly zero. This may result from
     * any of a
     * number of conditions; reaching
     * end of file before n bytes
     * have been skipped is
     * only one possibility.
     * This method never throws an EOFException.
     * The actual
     * number of bytes skipped is returned.
     *
     * @param      n   the number of bytes to be skipped.
     * @return     the number of bytes actually skipped.
     * @exception  IOException   if an I/O error occurs.
     */
    int skipBytes(int n) throws IOException;

    /**
     * Reads one input byte and returns
     * true if that byte is nonzero,
     * false if that byte is zero.
     * This method is suitable for reading
     * the byte written by the writeBoolean
     * method of interface DataOutput.
     *
     * @return     the boolean value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    boolean readBoolean() throws IOException;

    /**
     * Reads and returns one input byte.
     * The byte is treated as a signed value in
     * the range -128 through 127,
     * inclusive.
     * This method is suitable for
     * reading the byte written by the writeByte
     * method of interface DataOutput.
     *
     * @return     the 8-bit value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    byte readByte() throws IOException;

    /**
     * Reads one input byte, zero-extends
     * it to type int, and returns
     * the result, which is therefore in the range
     * 0
     * through 255.
     * This method is suitable for reading
     * the byte written by the writeByte
     * method of interface DataOutput
     * if the argument to writeByte
     * was intended to be a value in the range
     * 0 through 255.
     *
     * @return     the unsigned 8-bit value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    int readUnsignedByte() throws IOException;

    /**
     * Reads two input bytes and returns
     * a short value. Let a
     * be the first byte read and b
     * be the second byte. The value
     * returned
     * is:
     *

(short)((a << 8) | (b & 0xff))
     *

     * This method
     * is suitable for reading the bytes written
     * by the writeShort method of
     * interface DataOutput.
     *
     * @return     the 16-bit value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    short readShort() throws IOException;

    /**
     * Reads two input bytes and returns
     * an int value in the range 0
     * through 65535. Let a
     * be the first byte read and
     * b
     * be the second byte. The value returned is:
     *

(((a & 0xff) << 8) | (b & 0xff))
     *

     * This method is suitable for reading the bytes
     * written by the writeShort method
     * of interface DataOutput  if
     * the argument to writeShort
     * was intended to be a value in the range
     * 0 through 65535.
     *
     * @return     the unsigned 16-bit value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    int readUnsignedShort() throws IOException;

    /**
     * Reads two input bytes and returns a char value.
     * Let a
     * be the first byte read and b
     * be the second byte. The value
     * returned is:
     *

(char)((a << 8) | (b & 0xff))
     *

     * This method
     * is suitable for reading bytes written by
     * the writeChar method of interface
     * DataOutput.
     *
     * @return     the char value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    char readChar() throws IOException;

    /**
     * Reads four input bytes and returns an
     * int value. Let a-d
     * be the first through fourth bytes read. The value returned is:
     *

     *
     * (((a & 0xff) << 24) | ((b & 0xff) << 16) |
     *  ((c & 0xff) << 8) | (d & 0xff))
     *

     * This method is suitable
     * for reading bytes written by the writeInt
     * method of interface DataOutput.
     *
     * @return     the int value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    int readInt() throws IOException;

    /**
     * Reads eight input bytes and returns
     * a long value. Let a-h
     * be the first through eighth bytes read.
     * The value returned is:
     *

     * (((long)(a & 0xff) << 56) |
     *  ((long)(b & 0xff) << 48) |
     *  ((long)(c & 0xff) << 40) |
     *  ((long)(d & 0xff) << 32) |
     *  ((long)(e & 0xff) << 24) |
     *  ((long)(f & 0xff) << 16) |
     *  ((long)(g & 0xff) <<  8) |
     *  ((long)(h & 0xff)))
     *

     *

     * This method is suitable
     * for reading bytes written by the writeLong
     * method of interface DataOutput.
     *
     * @return     the long value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    long readLong() throws IOException;

    /**
     * Reads four input bytes and returns
     * a float value. It does this
     * by first constructing an int
     * value in exactly the manner
     * of the readInt
     * method, then converting this int
     * value to a float in
     * exactly the manner of the method Float.intBitsToFloat.
     * This method is suitable for reading
     * bytes written by the writeFloat
     * method of interface DataOutput.
     *
     * @return     the float value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    float readFloat() throws IOException;

    /**
     * Reads eight input bytes and returns
     * a double value. It does this
     * by first constructing a long
     * value in exactly the manner
     * of the readlong
     * method, then converting this long
     * value to a double in exactly
     * the manner of the method Double.longBitsToDouble.
     * This method is suitable for reading
     * bytes written by the writeDouble
     * method of interface DataOutput.
     *
     * @return     the double value read.
     * @exception  EOFException  if this stream reaches the end before reading
     *               all the bytes.
     * @exception  IOException   if an I/O error occurs.
     */
    double readDouble() throws IOException;

    /**
     * Reads the next line of text from the input stream.
     * It reads successive bytes, converting
     * each byte separately into a character,
     * until it encounters a line terminator or
     * end of
     * file; the characters read are then
     * returned as a String. Note
     * that because this
     * method processes bytes,
     * it does not support input of the full Unicode
     * character set.
     *

     * If end of file is encountered
     * before even one byte can be read, then null
     * is returned. Otherwise, each byte that is
     * read is converted to type char
     * by zero-extension. If the character '\n'
     * is encountered, it is discarded and reading
     * ceases. If the character '\r'
     * is encountered, it is discarded and, if
     * the following byte converts  to the
     * character '\n', then that is
     * discarded also; reading then ceases. If
     * end of file is encountered before either
     * of the characters '\n' and
     * '\r' is encountered, reading
     * ceases. Once reading has ceased, a String
     * is returned that contains all the characters
     * read and not discarded, taken in order.
     * Note that every character in this string
     * will have a value less than \u0100,
     * that is, (char)256.
     *
     * @return the next line of text from the input stream,
     *         or null if the end of file is
     *         encountered before a byte can be read.
     * @exception  IOException  if an I/O error occurs.
     */
    String readLine() throws IOException;

    /**
     * Reads in a string that has been encoded using a
     * modified UTF-8
     * format.
     * The general contract of readUTF
     * is that it reads a representation of a Unicode
     * character string encoded in modified
     * UTF-8 format; this string of characters
     * is then returned as a String.
     *

     * First, two bytes are read and used to
     * construct an unsigned 16-bit integer in
     * exactly the manner of the readUnsignedShort
     * method . This integer value is called the
     * UTF length and specifies the number
     * of additional bytes to be read. These bytes
     * are then converted to characters by considering
     * them in groups. The length of each group
     * is computed from the value of the first
     * byte of the group. The byte following a
     * group, if any, is the first byte of the
     * next group.
     *

     * If the first byte of a group
     * matches the bit pattern 0xxxxxxx
     * (where x means "may be 0
     * or 1"), then the group consists
     * of just that byte. The byte is zero-extended
     * to form a character.
     *

     * If the first byte
     * of a group matches the bit pattern 110xxxxx,
     * then the group consists of that byte a
     * and a second byte b. If there
     * is no byte b (because byte
     * a was the last of the bytes
     * to be read), or if byte b does
     * not match the bit pattern 10xxxxxx,
     * then a UTFDataFormatException
     * is thrown. Otherwise, the group is converted
     * to the character:

     *
(char)(((a& 0x1F) << 6) | (b & 0x3F))
     *

     * If the first byte of a group
     * matches the bit pattern 1110xxxx,
     * then the group consists of that byte a
     * and two more bytes b and c.
     * If there is no byte c (because
     * byte a was one of the last
     * two of the bytes to be read), or either
     * byte b or byte c
     * does not match the bit pattern 10xxxxxx,
     * then a UTFDataFormatException
     * is thrown. Otherwise, the group is converted
     * to the character:

     *

     * (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F))
     *

     * If the first byte of a group matches the
     * pattern 1111xxxx or the pattern
     * 10xxxxxx, then a UTFDataFormatException
     * is thrown.
     *

     * If end of file is encountered
     * at any time during this entire process,
     * then an EOFException is thrown.
     *

     * After every group has been converted to
     * a character by this process, the characters
     * are gathered, in the same order in which
     * their corresponding groups were read from
     * the input stream, to form a String,
     * which is returned.
     *

     * The writeUTF
     * method of interface DataOutput
     * may be used to write data that is suitable
     * for reading by this method.
     * @return     a Unicode string.
     * @exception  EOFException            if this stream reaches the end
     *               before reading all the bytes.
     * @exception  IOException             if an I/O error occurs.
     * @exception  UTFDataFormatException  if the bytes do not represent a
     *               valid modified UTF-8 encoding of a string.
     */
    String readUTF() throws IOException;
}