[
  {
    "path": ".bowerrc",
    "content": "{\n    \"directory\" : \"bower_components\"\n}"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.tmp\n.sass-cache\nnode_modules\nnode-webkit\nbower_components\nbuild\ndist\ntmp"
  },
  {
    "path": "Gruntfile.js",
    "content": "var exec = require('child_process').exec;\n\nmodule.exports = function (grunt) {\n    require('load-grunt-tasks')(grunt);\n\n    var pgk = grunt.file.readJSON('package.json');\n\n    var cfg = {\n        build: 'build',\n        dist: 'dist',\n        tmp: 'tmp',\n        macBundleId: 'com.quasado.gravit',\n        macSignIdentity: '1269B5CE3B0DCC676DA70011A618EB6FA95F8F50'\n    };\n\n    grunt.initConfig({\n        cfg: cfg,\n        pkg: pgk,\n\n        watch: {\n            compass: {\n                files: ['style/{,*/}*.{scss,sass}'],\n                tasks: ['compass']\n            },\n            livereload: {\n                options: {\n                    livereload: '<%= connect.options.livereload %>'\n                },\n                files: [\n                    'src/*.html',\n                    '<%= cfg.tmp %>/{,*/}*.css',\n                    '{<%= cfg.tmp %>,src/{,*/}*.js,test/{,*/}*.js',\n                    'assets/image/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'\n                ]\n            }\n        },\n        connect: {\n            options: {\n                port: 8999,\n                livereload: 35728,\n                hostname: 'localhost'\n            },\n            livereload: {\n                options: {\n                    open: true,\n                    base: [\n                        '<%= cfg.tmp %>',\n                        'assets',\n                        'src',\n                        '.'\n                    ]\n                }\n            },\n            test: {\n                options: {\n                    base: [\n                        '<%= cfg.tmp %>',\n                        'assets',\n                        'test',\n                        'src',\n                        '.'\n                    ]\n                }\n            }\n        },\n        clean: {\n            dev: '<%= cfg.tmp %>',\n            build: '<%= cfg.build %>',\n            dist: '<%= cfg.dist %>'\n        },\n        mocha: {\n            all: {\n                options: {\n                    run: true,\n                    urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']\n                }\n            }\n        },\n        compass: {\n            options: {\n                sassDir: 'style',\n                cssDir: '<%= cfg.tmp %>',\n                generatedImagesDir: '<%= cfg.tmp %>/image/generated',\n                imagesDir: 'assets/image/images',\n                javascriptsDir: 'src',\n                fontsDir: '<%= cfg.tmp %>/font',\n                httpImagesPath: '/image',\n                httpGeneratedImagesPath: '/image/generated',\n                httpFontsPath: '/font',\n                relativeAssets: false\n            },\n            dev: {\n                options: {\n                    debugInfo: true\n                }\n            },\n            build: {\n                options: {\n                    debugInfo: false,\n                    generatedImagesDir: '<%= cfg.build %>/source/image/generated'\n                }\n            }\n        },\n        concat: {\n            build: {\n                files: {\n                    '<%= cfg.build %>/browser/gravit-shell.js': ['shell/browser/*.js'],\n                    '<%= cfg.build %>/chrome/gravit-shell.js': ['shell/chrome/*.js', '!shell/chrome/background.js'],\n                    '<%= cfg.build %>/system/gravit-shell.js': ['shell/system/*.js']\n                }\n            }\n        },\n        uglify: {\n            build: {\n                files: {\n                    '<%= cfg.build %>/browser/gravit-shell.js': ['<%= cfg.build %>/browser/gravit-shell.js'],\n                    '<%= cfg.build %>/chrome/gravit-shell.js': ['<%= cfg.build %>/chrome/gravit-shell.js'],\n                    '<%= cfg.build %>/system/gravit-shell.js': ['<%= cfg.build %>/system/gravit-shell.js']\n                }\n            }\n        },\n        copy: {\n            dev: {\n                files: [\n                    {\n                        expand: true,\n                        dot: true,\n                        cwd: 'bower_components/font-awesome/fonts',\n                        dest: '<%= cfg.tmp %>/font/',\n                        src: '{,*/}*.*'\n                    }\n                ]\n            },\n            preBuild: {\n                files: [\n                    // Source Assets\n                    {\n                        expand: true,\n                        dot: true,\n                        cwd: 'bower_components/font-awesome/fonts',\n                        dest: '<%= cfg.build %>/source/font/',\n                        src: '{,*/}*.*'\n                    },\n                    {\n                        expand: true,\n                        dot: true,\n                        cwd: 'assets/cursor',\n                        dest: '<%= cfg.build %>/source/cursor/',\n                        src: '{,*/}*.*'\n                    },\n                    {\n                        expand: true,\n                        dot: true,\n                        cwd: 'assets/font',\n                        dest: '<%= cfg.build %>/source/font/',\n                        src: '{,*/}*.*'\n                    },\n\n                    // Chrome Assets\n                    {\n                        expand: true,\n                        dot: true,\n                        cwd: 'bower_components/jquery/dist/',\n                        dest: '<%= cfg.build %>/chrome/',\n                        src: 'jquery.min.js'\n                    },\n\n                    // System assets\n                    {\n                        expand: true,\n                        dot: true,\n                        cwd: 'bower_components/jquery/dist/',\n                        dest: '<%= cfg.build %>/system/',\n                        src: 'jquery.min.js'\n                    }\n                ]\n            },\n            postBuild: {\n                files: [\n                    // Copy some files for mac binary\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/system/',\n                        dest: '<%= cfg.build %>/system-binaries/Gravit/osx/Gravit.app/Contents/',\n                        src: ['Info.plist']\n                    },\n                    {\n                        expand: true,\n                        cwd: 'shell/system/',\n                        dest: '<%= cfg.build %>/system-binaries/Gravit/osx/Gravit.app/Contents/Resources/',\n                        src: ['doc.icns']\n                    }\n                ]\n            },\n            build: {\n                files: [\n                    // Browser\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/source/',\n                        dest: '<%= cfg.build %>/browser/',\n                        src: '{,*/}*.*'\n                    },\n                    {\n                        expand: true,\n                        cwd: 'assets/icon/',\n                        dest: '<%= cfg.build %>/browser/icon',\n                        src: ['**']\n                    },\n                    {\n                        expand: true,\n                        cwd: 'shell/browser/',\n                        dest: '<%= cfg.build %>/browser/',\n                        src: ['index.html']\n                    },\n\n                    // Infinity\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/source/',\n                        dest: '<%= cfg.build %>/infinity/',\n                        src: ['cursor/*.*', 'infinity-**.js']\n                    },\n\n                    // Chrome\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/chrome/',\n                        dest: '<%= cfg.build %>/chrome/',\n                        src: ['**']\n                    },\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/source/',\n                        dest: '<%= cfg.build %>/chrome/',\n                        src: ['**']\n                    },\n                    {\n                        expand: true,\n                        cwd: 'shell/chrome/',\n                        dest: '<%= cfg.build %>/chrome/',\n                        src: ['index.html', 'manifest.json', 'background.js']\n                    },\n                    {\n                        expand: true,\n                        cwd: 'assets/icon/',\n                        dest: '<%= cfg.build %>/chrome/icon',\n                        src: ['**']\n                    },\n\n                    // System\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/source/',\n                        dest: '<%= cfg.build %>/system/',\n                        src: ['**']\n                    },\n                    {\n                        expand: true,\n                        cwd: 'shell/system/',\n                        dest: '<%= cfg.build %>/system/',\n                        src: ['index.html', 'package.json', 'Info.plist']\n                    }\n                ]\n            },\n            dist: {\n                files: [\n                    // Browser\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/browser/',\n                        dest: '<%= cfg.dist %>/browser/',\n                        src: ['**']\n                    },\n\n                    // Infinity\n                    {\n                        expand: true,\n                        cwd: '<%= cfg.build %>/infinity/',\n                        dest: '<%= cfg.dist %>/infinity/',\n                        src: ['**']\n                    }\n                ]\n            }\n        },\n        replace: {\n            build: {\n                src: ['<%= cfg.build %>/system/package.json', '<%= cfg.build %>/system/Info.plist', '<%= cfg.build %>/chrome/manifest.json'],\n                overwrite: true,\n                replacements: [\n                    {\n                        from: '%name%',\n                        to: '<%= pkg.name %>'\n                    },\n                    {\n                        from: '%description%',\n                        to: '<%= pkg.description %>'\n                    },\n                    {\n                        from: '%version%',\n                        to: '<%= pkg.version %>'\n                    },\n                    {\n                        from: '%mac-bundle-id%',\n                        to: '<%= cfg.macBundleId %>'\n                    }\n                ]\n            }\n        },\n        useminPrepare: {\n            options: {\n                dest: '<%= cfg.build %>/source'\n            },\n            html: 'src/index.html'\n        },\n        usemin: {\n            options: {\n                dirs: ['<%= cfg.build %>/source']\n            },\n            html: ['<%= cfg.build %>/source/{,*/}*.html'],\n            css: ['<%= cfg.build %>/source/{,*/}*.css']\n        },\n        nodewebkit: {\n            options: {\n                version: '0.10.1',\n                platforms: ['win', 'osx', 'linux64'],\n                cacheDir: './node-webkit',\n                buildDir: '<%= cfg.build %>/system-binaries',\n                macIcns: 'shell/system/appicon.icns',\n                macZip: false,\n                winIco: 'shell/system/appicon.ico'\n            },\n            src: '<%= cfg.build %>/system/**/*'\n        }\n    });\n\n    // Private tasks\n    grunt.registerTask('_dist_osx', function () {\n        var done = this.async();\n\n        var gravitAppDir = cfg.build + '/system-binaries/Gravit/osx/Gravit.app';\n\n        var commands = [\n            // sign\n            'codesign --deep -f -v -s ' + cfg.macSignIdentity + ' -i ' + cfg.macBundleId + ' \"' + gravitAppDir + '/Contents/Frameworks/node-webkit Helper.app\"',\n            'codesign --deep -f -v -s ' + cfg.macSignIdentity + ' -i ' + cfg.macBundleId + ' \"' + gravitAppDir + '/Contents/Frameworks/node-webkit Helper EH.app\"',\n            'codesign --deep -f -v -s ' + cfg.macSignIdentity + ' -i ' + cfg.macBundleId + ' \"' + gravitAppDir + '/Contents/Frameworks/node-webkit Helper NP.app\"',\n            'codesign --deep -f -v -s ' + cfg.macSignIdentity + ' -i ' + cfg.macBundleId + ' \"' + gravitAppDir + '\"',\n\n            // verify\n            'spctl --assess -vvvv \"' + gravitAppDir + '/Contents/Frameworks/node-webkit Helper.app\"',\n            'spctl --assess -vvvv \"' + gravitAppDir + '/Contents/Frameworks/node-webkit Helper EH.app\"',\n            'spctl --assess -vvvv \"' + gravitAppDir + '/Contents/Frameworks/node-webkit Helper NP.app\"',\n            'spctl --assess -vvvv \"' + gravitAppDir + '\"',\n\n            // package\n            'test -f ./dist/gravit-osx.dmg && rm ./dist/gravit-osx.dmg',\n            'mkdir ./dist',\n            './node_modules/appdmg/bin/appdmg ./shell/system/package/osx/dmg.json ' + cfg.dist + '/gravit-osx.dmg'\n        ];\n\n        console.log('Sign & Package for OS-X');\n\n        var index = 0;\n\n        var _exec = function () {\n            exec(commands[index], function (error, stdout, stderr) {\n                if (stdout) console.log(stdout);\n                if (stderr) console.log(stderr);\n                if (error !== null) {\n                    console.log('exec error: ' + error);\n                }\n\n                if (++index < commands.length) {\n                    _exec();\n                } else {\n                    done();\n                }\n            });\n        }\n\n        _exec();\n    })\n\n    grunt.registerTask('_dist_win', function () {\n        // TODO : Build installer\n        var done = this.async();\n\n        exec('zip -r -X ../../../../' + cfg.dist + '/gravit-windows.zip *', {cwd: cfg.build + '/system-binaries/Gravit/win'}, function (error, stdout, stderr) {\n            if (stdout) console.log(stdout);\n            if (stderr) console.log(stderr);\n            if (error !== null) {\n                console.log('exec error: ' + error);\n            }\n            done();\n        });\n    })\n\n    grunt.registerTask('_dist_linux', function () {\n        var done = this.async();\n\n        exec('zip -r -X ../../../../' + cfg.dist + '/gravit-linux64.zip *', {cwd: cfg.build + '/system-binaries/Gravit/linux64'}, function (error, stdout, stderr) {\n            if (stdout) console.log(stdout);\n            if (stderr) console.log(stderr);\n            if (error !== null) {\n                console.log('exec error: ' + error);\n            }\n            done();\n        });\n    })\n\n    grunt.registerTask('_dist_chrome', function () {\n        var done = this.async();\n\n        exec('zip -r -X ../../' + cfg.dist + '/gravit-chrome.zip *', {cwd: cfg.build + '/chrome'}, function (error, stdout, stderr) {\n            if (stdout) console.log(stdout);\n            if (stderr) console.log(stderr);\n            if (error !== null) {\n                console.log('exec error: ' + error);\n            }\n            done();\n        });\n    })\n\n    // Public tasks\n    grunt.registerTask('dev', function (target) {\n        grunt.task.run([\n            'clean:dev',\n            'compass:dev',\n            'copy:dev',\n            'connect:livereload',\n            'watch'\n        ]);\n    });\n\n    grunt.registerTask('test', function (target) {\n        grunt.task.run([\n            'clean:dev',\n            'compass:dev',\n            'copy:dev',\n            'connect:test',\n            'mocha'\n        ]);\n    });\n\n    grunt.registerTask('build', function (target) {\n        grunt.task.run([\n            'clean:build',\n            'useminPrepare',\n            'compass:build',\n            'concat',\n            'cssmin',\n            'uglify',\n            'usemin',\n            'copy:preBuild',\n            'copy:build',\n            'replace:build',\n            'nodewebkit',\n            'copy:postBuild'\n        ]);\n    });\n\n    grunt.registerTask('dist', function (target) {\n        grunt.task.run([\n            'test',\n            'build',\n            'clean:dist',\n            'copy:dist',\n            '_dist_osx',\n            '_dist_linux',\n            '_dist_win',\n            '_dist_chrome'\n        ]);\n    });\n\n\n    // By default we'll run the development task\n    grunt.registerTask('default', [\n        'dev'\n    ]);\n};"
  },
  {
    "path": "LICENSE",
    "content": "Gravit - The versatile, cross-platform design tool\nCopyright (C) 2012-2014 Quasado GmbH, Quasado e.K.\n\nThe name Gravit and the Gravit Logo as well as all related logos are\nexclusive trademarks of Quasado GmbH, Quasado e.K. and may not be used\nwithout prior written permission.\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nIn addition to the GPL, complete source code means all the source code for\nall modules it contains made available as non-obfuscated source code."
  },
  {
    "path": "README.md",
    "content": "## Introduction\n\nGravit is a design tool for Mac, Windows, Linux, ChromeOS and the Browser made\nin the spirit for Freehand and Fireworks. It is completely written in HTML5,\nJavascript and CSS3. Gravit consists of the core engine called \"Infinity\", the\nactual Application and the core Module called \"Gravit\".\n\nWe'd like to encourage everyone in getting involved with this project. You can\ndevelop new features or take a ticket and fix it. Or if you're a UX/Designer, you\ncould help designing new icons or improving the UI. To get started contributing,\nread the [GitHub Guide](https://guides.github.com/activities/contributing-to-open-source/)\n\n## Prerequisites\n\n* NodeJS + NPM\n* Grunt Client\n* Bower\n* SASS + Compass\n\n## Quick Start\n\nInstall all prerequisites and make sure they're available on your path.\n\nThen run `npm install` to install all nodejs dependencies\nThen run `bower install` to install all client javascript libraries\n\nFinally run `grunt`. You can then open Gravit in your\nwebbrowser at http://127.0.0.1:8999/.\n\nWe recommend using Chrome as this is the browser also used for the standalone\nversion.\n\n## Quick Overview\n\n+ assets - contains all relevant assets like fonts, images, etc.\n+ shell - contains platform-specific code for standalone version\n+ src - contains all source code\n  + application - contains the application framework\n  + development - contains the development addon automatically loaded when developing\n  + gravit - contains the core module that is loaded by the application and provides all UI of Gravit\n  + infinity - contains the core rendering engine as well as core classes used everywhere else\n  + infinity-editor - contains editors, tools, guides and more based on infinity\n+ style - contains all styling files for the application\n+ test - contains all test files\n\n## Community\n\nIssues are being tracked here on GitHub.\n\n## License\n\n`Gravit`'s code in this repo uses the GPL license, see our `LICENSE` file for detailed information.\nThe name Gravit and the Gravit Logo as well as all related logos are exclusive trademarks of\nQuasado GmbH, Quasado e.K. and may not be used without prior written permission.\n\n`Gravit`'s code is also available as a commercial license. For more information, contact us."
  },
  {
    "path": "bower.json",
    "content": "{\n    \"name\": \"gravit\",\n    \"version\": \"0.0.1\",\n    \"dependencies\": {\n        \"jquery\": \"~2.1.1\",\n        \"mousetrap\": \"latest\",\n        \"font-awesome\": \"latest\",\n        \"jqtree\": \"latest\",\n        \"opentype.js\": \"git://github.com/nodebox/opentype.js.git#latest\",\n        \"pako\": \"latest\",\n        \"rangy\": \"latest\",\n        \"color-thief\": \"latest\",\n        \"uri.js\": \"latest\",\n        \"Blob.js\": \"git://github.com/eligrey/Blob.js.git#latest\",\n        \"canvas-toBlob.js\": \"git://github.com/eligrey/canvas-toBlob.js.git#latest\"\n    },\n    \"devDependencies\": {},\n    \"private\": true\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"Gravit\",\n    \"description\" : \"Gravit, the versatile Design Tool\",\n    \"author\" : \"Quasado\",\n    \"version\": \"0.0.3.1\",\n    \"private\": true,\n    \"devDependencies\": {\n        \"grunt\": \"~0.4.1\",\n        \"grunt-contrib-copy\": \"~0.5.0\",\n        \"grunt-contrib-concat\": \"~0.3.0\",\n        \"grunt-contrib-uglify\": \"~0.2.0\",\n        \"grunt-contrib-compass\": \"~0.5.0\",\n        \"grunt-contrib-jshint\": \"~0.6.3\",\n        \"grunt-contrib-cssmin\": \"~0.6.0\",\n        \"grunt-contrib-connect\": \"~0.5.0\",\n        \"grunt-contrib-clean\": \"~0.5.0\",\n        \"grunt-contrib-htmlmin\": \"~0.1.3\",\n        \"grunt-bower-install\": \"~0.5.0\",\n        \"grunt-contrib-imagemin\": \"~0.2.0\",\n        \"grunt-contrib-watch\": \"~0.5.2\",\n        \"grunt-rev\": \"~0.1.0\",\n        \"grunt-autoprefixer\": \"~0.2.0\",\n        \"grunt-usemin\": \"~0.1.10\",\n        \"grunt-mocha\": \"~0.4.0\",\n        \"grunt-svgmin\": \"~0.2.0\",\n        \"grunt-concurrent\": \"~0.3.0\",\n        \"grunt-text-replace\": \"~0.3.12\",\n        \"grunt-node-webkit-builder\": \"0.2.0\",\n        \"load-grunt-tasks\": \"~0.1.0\",\n        \"time-grunt\": \"~0.1.1\",\n        \"appdmg\": \"^0.2.0\"\n    }\n}"
  },
  {
    "path": "shell/browser/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title>Gravit</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\n    <meta name=\"apple-mobile-web-app-capable\" content=\"yes\"/>\n    <meta name=\"apple-mobile-web-app-title\" content=\"Gravit\">\n    <link rel=\"shortcut icon\" href=\"icon/icon_16x16.ico\" type=\"image/x-icon\"/>\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"icon/icon_144x144.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114×114\" href=\"icon/icon_114x114.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"72×72\" href=\"icon/icon_72x72.png\">\n    <link rel=\"apple-touch-icon-precomposed\" href=\"icon/icon_57x57.png\">\n    <link rel=\"stylesheet\" href=\"gravit.css\">\n</head>\n<body>\n<script src=\"http://code.jquery.com/jquery-2.1.1.min.js\"></script>\n<script src=\"infinity-libraries.js\"></script>\n<script src=\"infinity-core.js\"></script>\n<script src=\"infinity-editor.js\"></script>\n<script src=\"gravit.js\"></script>\n<script src=\"gravit-shell.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "shell/browser/shell.js",
    "content": "(function (_) {\n    /**\n     * The browser shell\n     * @class GBrowserShell\n     * @extends GShell\n     * @constructor\n     */\n    function GBrowserShell() {\n        this._menuBar = new GMenuBar();\n        this._clipboardMimeTypes = {};\n    };\n    IFObject.inherit(GBrowserShell, GShell);\n\n    /**\n     * @type {GMenuBar}\n     * @private\n     */\n    GBrowserShell.prototype._menuBar = null;\n\n    /**\n     * @type {*}\n     * @private\n     */\n    GBrowserShell.prototype._clipboardMimeTypes = null;\n\n    /** @override */\n    GBrowserShell.prototype.isDevelopment = function () {\n        return document.location.hostname === 'localhost' || document.location.hostname === '127.0.0.1';\n    };\n\n    /** @override */\n    GBrowserShell.prototype.prepare = function () {\n        // Append our menu bar element as first child of header\n        var menuElement = this._menuBar._htmlElement;\n        menuElement\n            .css('height', '100%')\n            .prependTo($('#header'));\n    };\n\n    /** @override */\n    GBrowserShell.prototype.addMenu = function (parentMenu, title, callback) {\n        parentMenu = parentMenu || this._menuBar.getMenu();\n        var item = new GMenuItem(GMenuItem.Type.Menu);\n        item.setCaption(title);\n        parentMenu.addItem(item);\n\n        if (callback) {\n            item.getMenu().addEventListener(GMenu.OpenEvent, callback);\n        }\n\n        return item.getMenu();\n    };\n\n    /** @override */\n    GBrowserShell.prototype.addMenuSeparator = function (parentMenu) {\n        var item = new GMenuItem(GMenuItem.Type.Divider);\n        parentMenu.addItem(item);\n        return item;\n    };\n\n    /** @override */\n    GBrowserShell.prototype.addMenuItem = function (parentMenu, title, checkable, shortcut, callback) {\n        var item = new GMenuItem(GMenuItem.Type.Item);\n        if (callback) {\n            item.addEventListener(GMenuItem.ActivateEvent, callback);\n        }\n\n        if (shortcut) {\n            gApp.registerShortcut(shortcut, function () {\n                callback();\n            }.bind(this));\n\n            item.setShortcutHint(shortcut);\n        }\n\n        this.updateMenuItem(item, title, true, false);\n        parentMenu.addItem(item);\n        return item;\n    };\n\n    /** @override */\n    GBrowserShell.prototype.updateMenuItem = function (item, title, enabled, checked) {\n        item.setCaption(title);\n        item.setEnabled(enabled);\n        item.setChecked(checked);\n    };\n\n    /** @override */\n    GBrowserShell.prototype.removeMenuItem = function (parentMenu, child) {\n        parentMenu.removeItem(parentMenu.indexOf(child));\n    };\n\n    /** @override */\n    GBrowserShell.prototype.getClipboardMimeTypes = function () {\n        return this._clipboardMimeTypes ? Object.keys(this._clipboardMimeTypes) : null;\n    };\n\n    /** @override */\n    GBrowserShell.prototype.getClipboardContent = function (mimeType) {\n        if (this._clipboardMimeTypes && this._clipboardMimeTypes.hasOwnProperty(mimeType)) {\n            return this._clipboardMimeTypes[mimeType];\n        }\n        return null;\n    };\n\n    /** @override */\n    GBrowserShell.prototype.setClipboardContent = function (mimeType, content) {\n        this._clipboardMimeTypes[mimeType] = content;\n    };\n\n    _.gShell = new GBrowserShell;\n\n    $(document).ready(function () {\n        gShellReady();\n    });\n\n    $(window).load(function () {\n        gShellFinished();\n    });\n})(this);\n"
  },
  {
    "path": "shell/chrome/background.js",
    "content": "// TODO : Load/Store window state\nchrome.app.runtime.onLaunched.addListener(function() {\n    chrome.app.window.create('index.html', {\n        'bounds': {\n            'width': 1024,\n            'height': 768\n        }\n    });\n});"
  },
  {
    "path": "shell/chrome/filestorage.js",
    "content": "(function (_) {\n    /**\n     * The file storage class for chrome\n     * @constructor\n     */\n    function GFileStorage() {\n        this._urlEntryMap = {};\n    };\n    IFObject.inherit(GFileStorage, GStorage);\n\n    /**\n     * @type {*}\n     * @private\n     */\n    GFileStorage.prototype._urlEntryMap = null;\n\n    /** @override */\n    GFileStorage.prototype.isAvailable = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.isSaving = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.isPrompting = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.getProtocol = function () {\n        return 'file';\n    };\n\n    /** @override */\n    GFileStorage.prototype.getExtensions = function () {\n        return null;\n    };\n\n    /** @override */\n    GFileStorage.prototype.getName = function () {\n        // TODO : I18N\n        return 'File';\n    };\n\n    /** @override */\n    GFileStorage.prototype.openResourcePrompt = function (reference, extensions, done) {\n        chrome.fileSystem.chooseEntry(\n            {\n                type: 'openWritableFile',\n                acceptsAllTypes: !extensions,\n                accepts: [\n                    {\n                        extensions: extensions\n                    },\n                ]\n            },\n            function (entry) {\n                if (entry) {\n                    this._addEntryMapping(entry, done);\n                }\n            }.bind(this));\n    };\n\n    /** @override */\n    GFileStorage.prototype.saveResourcePrompt = function (reference, proposedName, extension, done) {\n        chrome.fileSystem.chooseEntry(\n            {\n                type: 'saveFile',\n                suggestedName: proposedName,\n                acceptsAllTypes: !extension,\n                accepts: [\n                    {\n                        extensions: [extension]\n                    },\n                ]\n            },\n            function (entry) {\n                if (entry) {\n                    this._addEntryMapping(entry, done);\n                }\n            }.bind(this));\n    };\n\n    /** @override */\n    GFileStorage.prototype.load = function (url, binary, done) {\n        if (!this._urlEntryMap.hasOwnProperty(url)) {\n            throw new Error('No file-entry for url ' + url);\n        }\n\n        var entry = this._urlEntryMap[url].entry;\n        var name = this._extractFileName(url);\n\n        entry.file(function (file) {\n            var reader = new FileReader();\n\n            reader.onerror = function (e) {\n                console.log('read_error on ' + url);\n                console.log(e);\n            }\n            reader.onloadend = function (e) {\n                done(e.target.result, name);\n            };\n\n            if (binary) {\n                reader.readAsArrayBuffer(file);\n            } else {\n                reader.readAsText(file);\n            }\n        });\n    };\n\n    /** @override */\n    GFileStorage.prototype.save = function (url, data, binary, done) {\n        if (!this._urlEntryMap.hasOwnProperty(url)) {\n            throw new Error('No file-entry for url ' + url);\n        }\n\n        var entry = this._urlEntryMap[url].entry;\n        var name = this._extractFileName(url);\n\n        entry.createWriter(function (writer) {\n            writer.onerror = function (e) {\n                console.log('write_error on ' + url);\n                console.log(e);\n            }\n            writer.onwriteend = function (e) {\n                if (done) {\n                    done(name);\n                }\n            };\n            writer.write(new Blob([data], {type: binary ? 'text/plain' : 'text/plain'}));\n        }, function (e) {\n            console.log('create_writer_error on ' + url);\n        });\n    };\n\n    /** @override */\n    GFileStorage.prototype.releaseUrl = function (url) {\n        if (this._urlEntryMap.hasOwnProperty(url)) {\n            if (--this._urlEntryMap[url].usage === 0) {\n                delete this._urlEntryMap[url];\n            }\n        }\n    };\n\n    /** @override */\n    GFileStorage.prototype.resolveUrl = function (url, resolved) {\n        // Our file:/// protocol is understandable by the browser\n        // so just use the source url\n        resolved(url);\n    };\n\n    /**\n     * @private\n     */\n    GFileStorage.prototype._extractFileName = function (path) {\n        var lastSlash = path.lastIndexOf('/');\n        if (lastSlash < 0) {\n            lastSlash = path.lastIndexOf('\\\\');\n        }\n        if (lastSlash >= 0) {\n            var lastDot = path.lastIndexOf('.');\n            if (lastDot > 0) {\n                return path.substr(lastSlash + 1, lastDot - lastSlash - 1);\n            } else {\n                return path.substr(lastSlash + 1);\n            }\n        }\n    };\n\n    /** @private */\n    GFileStorage.prototype._addEntryMapping = function (entry, done) {\n        chrome.fileSystem.getDisplayPath(entry, function (path) {\n            var url = this.getProtocol() + '://' + ifUtil.replaceAll(path, '\\\\', '/');\n\n            if (!this._urlEntryMap.hasOwnProperty(url)) {\n                this._urlEntryMap[url] = {\n                    usage: 1,\n                    entry: entry\n                };\n            } else {\n                this._urlEntryMap[url].usage++;\n            }\n\n            done(url);\n        }.bind(this));\n    };\n\n    _.GFileStorage = GFileStorage;\n})(this);\n"
  },
  {
    "path": "shell/chrome/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title>Gravit</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\n    <meta name=\"apple-mobile-web-app-capable\" content=\"yes\"/>\n    <meta name=\"apple-mobile-web-app-title\" content=\"Gravit\">\n    <link rel=\"shortcut icon\" href=\"icon/icon_16x16.ico\" type=\"image/x-icon\"/>\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"icon/icon_144x144.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114×114\" href=\"icon/icon_114x114.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"72×72\" href=\"icon/icon_72x72.png\">\n    <link rel=\"apple-touch-icon-precomposed\" href=\"icon/icon_57x57.png\">\n    <link rel=\"stylesheet\" href=\"gravit.css\">\n</head>\n<body>\n<script src=\"jquery.min.js\"></script>\n<script src=\"infinity-libraries.js\"></script>\n<script src=\"infinity-core.js\"></script>\n<script src=\"infinity-editor.js\"></script>\n<script src=\"gravit.js\"></script>\n<script src=\"gravit-shell.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "shell/chrome/manifest.json",
    "content": "{\n    \"name\": \"%name%\",\n    \"description\": \"%description%\",\n    \"version\": \"%version%\",\n    \"manifest_version\": 2,\n    \"minimum_chrome_version\": \"36\",\n    \"app\": {\n        \"background\": {\n            \"scripts\": [\"background.js\"]\n        }\n    },\n    \"icons\": {\n        \"16\": \"icon/icon_16x16.png\",\n        \"128\": \"icon/icon_128x128.png\"\n    },\n    \"permissions\": [\n        \"clipboardRead\",\n        \"clipboardWrite\",\n        {\n            \"fileSystem\": [\"write\", \"retainEntries\", \"directory\"]\n        },\n        \"storage\"\n    ]\n}"
  },
  {
    "path": "shell/chrome/shell.js",
    "content": "(function (_) {\n    /**\n     * The chrome shell\n     * @class GChromeShell\n     * @extends GShell\n     * @constructor\n     */\n    function GChromeShell() {\n        this._menuBar = new GMenuBar();\n        this._clipboardMimeTypes = {};\n    };\n    IFObject.inherit(GChromeShell, GShell);\n\n    /**\n     * @type {GMenuBar}\n     * @private\n     */\n    GChromeShell.prototype._menuBar = null;\n\n    /**\n     * @type {*}\n     * @private\n     */\n    GChromeShell.prototype._clipboardMimeTypes = null;\n\n    /** @override */\n    GChromeShell.prototype.isDevelopment = function () {\n        return document.location.hostname === 'localhost' || document.location.hostname === '127.0.0.1';\n    };\n\n    /** @override */\n    GChromeShell.prototype.prepare = function () {\n        // Append our menu bar element as first child of header\n        var menuElement = this._menuBar._htmlElement;\n        menuElement\n            .css('height', '100%')\n            .prependTo($('#header'));\n    };\n\n    /** @override */\n    GChromeShell.prototype.addMenu = function (parentMenu, title, callback) {\n        parentMenu = parentMenu || this._menuBar.getMenu();\n        var item = new GMenuItem(GMenuItem.Type.Menu);\n        item.setCaption(title);\n        parentMenu.addItem(item);\n\n        if (callback) {\n            item.getMenu().addEventListener(GMenu.OpenEvent, callback);\n        }\n\n        return item.getMenu();\n    };\n\n    /** @override */\n    GChromeShell.prototype.addMenuSeparator = function (parentMenu) {\n        var item = new GMenuItem(GMenuItem.Type.Divider);\n        parentMenu.addItem(item);\n        return item;\n    };\n\n    /** @override */\n    GChromeShell.prototype.addMenuItem = function (parentMenu, title, checkable, shortcut, callback) {\n        var item = new GMenuItem(GMenuItem.Type.Item);\n        if (callback) {\n            item.addEventListener(GMenuItem.ActivateEvent, callback);\n        }\n\n        if (shortcut) {\n            gApp.registerShortcut(shortcut, function () {\n                callback();\n            }.bind(this));\n\n            item.setShortcutHint(shortcut);\n        }\n\n        this.updateMenuItem(item, title, true, false);\n        parentMenu.addItem(item);\n        return item;\n    };\n\n    /** @override */\n    GChromeShell.prototype.updateMenuItem = function (item, title, enabled, checked) {\n        item.setCaption(title);\n        item.setEnabled(enabled);\n        item.setChecked(checked);\n    };\n\n    /** @override */\n    GChromeShell.prototype.removeMenuItem = function (parentMenu, child) {\n        parentMenu.removeItem(parentMenu.indexOf(child));\n    };\n\n    /** @override */\n    GChromeShell.prototype.getClipboardMimeTypes = function () {\n        return this._clipboardMimeTypes ? Object.keys(this._clipboardMimeTypes) : null;\n    };\n\n    /** @override */\n    GChromeShell.prototype.getClipboardContent = function (mimeType) {\n        if (this._clipboardMimeTypes && this._clipboardMimeTypes.hasOwnProperty(mimeType)) {\n            return this._clipboardMimeTypes[mimeType];\n        }\n        return null;\n    };\n\n    /** @override */\n    GChromeShell.prototype.setClipboardContent = function (mimeType, content) {\n        this._clipboardMimeTypes[mimeType] = content;\n    };\n\n    _.gShell = new GChromeShell;\n\n    $(document).ready(function () {\n        gShellReady();\n    });\n\n    $(window).load(function () {\n        gravit.storages.push(new GFileStorage());\n        gShellFinished();\n    });\n})(this);\n"
  },
  {
    "path": "shell/system/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleName</key>\n\t<string>Gravit</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>%name%</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.graphics-design</string>\n\t<key>CFBundleDocumentTypes</key>\n    <array>\n    \t<dict>\n    \t\t<key>CFBundleTypeExtensions</key>\n    \t\t<array>\n    \t\t\t<string>gravit</string>\n    \t\t</array>\n    \t\t<key>CFBundleTypeIconFile</key>\n    \t\t<string>doc.icns</string>\n    \t\t<key>CFBundleTypeName</key>\n    \t\t<string>Gravit Design</string>\n    \t\t<key>CFBundleTypeOSTypes</key>\n    \t\t<array>\n    \t\t\t<string>????</string>\n    \t\t</array>\n    \t\t<key>CFBundleTypeRole</key>\n    \t\t<string>Editor</string>\n    \t</dict>\n    </array>\n    <key>CFBundleExecutable</key>\n\t<string>node-webkit</string>\n\t<key>CFBundleIconFile</key>\n\t<string>nw.icns</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>%mac-bundle-id%</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>Version 0.0.1</string>\n\t<key>CFBundleVersion</key>\n\t<string>%version%</string>\n\t<key>LSFileQuarantineEnabled</key>\n\t<true/>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>10.6.0</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticGraphicsSwitching</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "shell/system/filestorage.js",
    "content": "(function (_) {\n    var fs = require('fs');\n\n    /**\n     * The file storage class for the system\n     * @constructor\n     */\n    function GFileStorage() {\n        this._fileInput = $('<input/>')\n            .css('display', 'none')\n            .attr('type', 'file')\n            .on('change', function (evt) {\n                var files = this._fileInput[0].files;\n                if (files && files.length > 0) {\n                    var file = this._fileInput[0].files[0];\n                    var location = ifUtil.replaceAll(file.path, '\\\\', '/');\n\n                    if (this._fileInputMode === 'open_resource') {\n                        this._fileInputCallback(this.getProtocol() + '://' + location);\n                    } else if (this._fileInputMode === 'save_resource') {\n                        var extension = this._fileInput.attr('data-extension');\n                        if (extension && !location.match(\"\\\\.\" + extension + \"$\")) {\n                            location += \".\" + extension;\n                        }\n                        this._fileInputCallback(this.getProtocol() + '://' + location);\n                    } else if (this._fileInputMode === 'open_directory' || this._fileInputMode === 'save_directory') {\n                        // Make sure location ends with a slash\n                        if (location.charAt(location.length - 1) !== '/') {\n                            location += '/';\n                        }\n                        this._fileInputCallback(this.getProtocol() + '://' + location);\n                    }\n                }\n            }.bind(this))\n            .appendTo($('body'));\n    };\n    IFObject.inherit(GFileStorage, GStorage);\n\n    /**\n     * @type {String}\n     * @private\n     */\n    GFileStorage.prototype._fileInputMode = null;\n\n    /**\n     * @type {Function}\n     * @private\n     */\n    GFileStorage.prototype._fileInputCallback = null;\n\n    /** @override */\n    GFileStorage.prototype.isAvailable = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.isSaving = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.isPrompting = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.isDirectory = function () {\n        return true;\n    };\n\n    /** @override */\n    GFileStorage.prototype.getProtocol = function () {\n        return 'file';\n    };\n\n    /** @override */\n    GFileStorage.prototype.getExtensions = function () {\n        return null;\n    };\n\n    /** @override */\n    GFileStorage.prototype.getName = function () {\n        // TODO : I18N\n        return 'File';\n    };\n\n    /** @override */\n    GFileStorage.prototype.openResourcePrompt = function (reference, extensions, done) {\n        var filter = \"*.*\";\n        if (extensions) {\n            filter = \"\";\n            for (var i = 0; i < extensions.length; ++i) {\n                if (i > 0) {\n                    filter += \",\";\n                }\n                filter += \".\" + extensions[i];\n            }\n        }\n\n        this._fileInputMode = 'open_resource';\n        this._fileInputCallback = done;\n        this._prepareInput(reference);\n        this._fileInput\n            .attr('accept', filter ? filter : '')\n            .trigger('click');\n    };\n\n    /** @override */\n    GFileStorage.prototype.saveResourcePrompt = function (reference, proposedName, extension, done) {\n        this._fileInputMode = 'save_resource';\n        this._fileInputCallback = done;\n        this._prepareInput(reference);\n        this._fileInput\n            .attr('accept', extension ? '.' + extension : '')\n            .attr('nwsaveas', proposedName ? proposedName + (extension ? '.' + extension : '') : '')\n            .attr('data-extension', extension)\n            .trigger('click');\n    };\n\n    /** @override */\n    GFileStorage.prototype.openDirectoryPrompt = function (reference, done) {\n        this._fileInputMode = 'open_directory';\n        this._fileInputCallback = done;\n        this._prepareInput(reference);\n        this._fileInput\n            .attr('nwdirectory', '')\n            .trigger('click');\n    };\n\n    /** @override */\n    GFileStorage.prototype.saveDirectoryPrompt = function (reference, done) {\n        this._fileInputMode = 'save_directory';\n        this._fileInputCallback = done;\n        this._prepareInput(reference);\n        this._fileInput\n            .attr('nwdirectory', '')\n            .trigger('click');\n    };\n\n    /** @override */\n    GFileStorage.prototype.load = function (url, binary, done) {\n        var location = new URI(url).path();\n        var buffer = fs.readFileSync(location, binary ? null : 'utf8');\n\n        if (buffer) {\n            if (binary) {\n                var ab = new ArrayBuffer(buffer.length);\n                var view = new Uint8Array(ab);\n                for (var i = 0; i < buffer.length; ++i) {\n                    view[i] = buffer[i];\n                }\n                buffer = ab;\n            }\n\n            done(buffer, this._extractFileName(location));\n        }\n    };\n\n    /** @override */\n    GFileStorage.prototype.save = function (url, data, binary, done) {\n        var location = new URI(url).path();\n\n        if (binary) {\n            data = new Buffer(new Uint8Array(data));\n        }\n\n        fs.writeFileSync(location, data, binary ? null : 'utf8');\n\n        if (done) {\n            done(this._extractFileName(location));\n        }\n    };\n\n    /** @override */\n    GFileStorage.prototype.resolveUrl = function (url, resolved) {\n        // Our file:/// protocol is understandable by the browser\n        // so just use the source url\n        resolved(url);\n    };\n\n    /** @private */\n    GFileStorage.prototype._prepareInput = function (reference) {\n        var workingDir = null;\n        if (reference && reference !== '') {\n            var directory = new URI(reference).directory();\n            if (directory && directory !== '') {\n                if (ifSystem.operatingSystem === IFSystem.OperatingSystem.Windows) {\n                    directory = ifUtil.replaceAll(directory, '/', '\\\\');\n                }\n                workingDir = directory;\n            }\n        }\n\n        this._fileInput\n            .removeAttr('accept')\n            .removeAttr('nwsaveas')\n            .removeAttr('nwdirectory')\n            .removeAttr('nwworkingdir')\n            .removeAttr('data-extension')\n            .val('');\n\n        if (workingDir && workingDir !== '') {\n            this._fileInput\n                .attr('nwworkingdir', workingDir);\n        } else {\n            this._fileInput\n                .removeAttr('nwworkingdir');\n        }\n    };\n\n    /**\n     * @private\n     */\n    GFileStorage.prototype._extractFileName = function (path) {\n        var lastSlash = path.lastIndexOf('/');\n        if (lastSlash < 0) {\n            lastSlash = path.lastIndexOf('\\\\');\n        }\n        if (lastSlash >= 0) {\n            var lastDot = path.lastIndexOf('.');\n            if (lastDot > 0) {\n                return path.substr(lastSlash + 1, lastDot - lastSlash - 1);\n            } else {\n                return path.substr(lastSlash + 1);\n            }\n        }\n    };\n\n    _.GFileStorage = GFileStorage;\n})(this);\n"
  },
  {
    "path": "shell/system/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title>Gravit</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\n    <link rel=\"stylesheet\" href=\"gravit.css\">\n</head>\n<body>\n<script src=\"jquery.min.js\"></script>\n<script src=\"infinity-libraries.js\"></script>\n<script src=\"infinity-core.js\"></script>\n<script src=\"infinity-editor.js\"></script>\n<script src=\"gravit.js\"></script>\n<script src=\"gravit-shell.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "shell/system/package/osx/dmg.json",
    "content": "{\n    \"title\": \"Gravit\",\n    \"icon\": \"../../appicon.icns\",\n    \"background\": \"background.tiff\",\n    \"icon-size\": 120,\n    \"contents\": [\n        { \"x\": 284, \"y\": 20, \"type\": \"file\", \"path\": \"../../../../build/system-binaries/Gravit/osx/Gravit.app\" },\n        { \"x\": 483, \"y\": 20, \"type\": \"link\", \"path\": \"/Applications\" }\n    ]\n}"
  },
  {
    "path": "shell/system/package.json",
    "content": "{\n    \"name\": \"%name%\",\n    \"description\": \"%description%\",\n    \"version\": \"%version%\",\n    \"main\": \"index.html\",\n    \"window\": {\n        \"toolbar\": false,\n        \"resizable\": true,\n        \"show_in_taskbar\": true,\n        \"frame\": true,\n        \"width\": 1024,\n        \"height\": 786,\n        \"show\": true\n    }\n}"
  },
  {
    "path": "shell/system/shell.js",
    "content": "(function (_) {\n    var gui = require('nw.gui');\n\n    gui.App.on('open', function (cmdline) {\n        if (cmdline && cmdline.length > 0) {\n            gApp.openDocument('file://' + cmdline);\n        }\n    });\n\n    /**\n     * The system shell\n     * @class GSystemShell\n     * @extends GShell\n     * @constructor\n     */\n    function GSystemShell() {\n        this._menuBar = new gui.Menu({ type: \"menubar\" });\n\n        if (process.platform === 'darwin') {\n            this._menuBar.createMacBuiltin(\"Gravit\", {\n                hideEdit: true,\n                hideWindow: true\n            });\n        }\n\n        this._clipboardMimeTypes = {};\n    };\n    IFObject.inherit(GSystemShell, GShell);\n\n    /**\n     * @type {gui.Menu}\n     * @private\n     */\n    GSystemShell.prototype._menuBar = null;\n\n    /**\n     * @type {*}\n     * @private\n     */\n    GSystemShell.prototype._clipboardMimeTypes = null;\n\n    /** @override */\n    GSystemShell.prototype.isDevelopment = function () {\n        var argv = gui.App.argv;\n        return argv.indexOf('-dev') >= 0;\n    };\n\n    /** @override */\n    GSystemShell.prototype.start = function () {\n        var win = gui.Window.get();\n        win.menu = _.gShell._menuBar;\n        win.show();\n        win.focus();\n\n        var hasOpenedDocuments = false;\n        var argv = gui.App.argv;\n        if (argv && argv.length) {\n            for (var i = 0; i < argv.length; ++i) {\n                if (argv[i].charAt(0) !== '-') {\n                    gApp.openDocument('file://' + argv[i]);\n                    hasOpenedDocuments = true;\n                }\n            }\n        }\n\n        if (!hasOpenedDocuments) {\n            GShell.prototype.start.call(this);\n        }\n    };\n\n    /** @override */\n    GSystemShell.prototype.addMenu = function (parentMenu, title, callback) {\n        parentMenu = parentMenu || this._menuBar;\n        var item = new gui.MenuItem({\n            label: title,\n            submenu: new gui.Menu()\n        });\n        parentMenu.append(item);\n\n        //if (callback) {\n        //    item.getMenu().addEventListener(GMenu.OpenEvent, callback);\n        //}\n\n        return item.submenu;\n    };\n\n    /** @override */\n    GSystemShell.prototype.addMenuSeparator = function (parentMenu) {\n        var item = new gui.MenuItem({ type: 'separator' });\n        parentMenu.append(item);\n        return item;\n    };\n\n    /** @override */\n    GSystemShell.prototype.addMenuItem = function (parentMenu, title, checkable, shortcut, callback) {\n        var shortcut = shortcut ? this._shortcutToShellShortcut(shortcut) : null;\n\n        var item = new gui.MenuItem({\n            type: checkable ? 'checkbox' : 'normal',\n            label: title,\n            key: shortcut ? shortcut.key : null,\n            modifiers: shortcut ? shortcut.modifiers : null,\n            click: callback\n        });\n\n        parentMenu.append(item);\n        return item;\n    };\n\n    /** @override */\n    GSystemShell.prototype.updateMenuItem = function (item, title, enabled, checked) {\n        item.label = title;\n        item.enabled = enabled;\n        item.checked = checked;\n    };\n\n    /** @override */\n    GSystemShell.prototype.removeMenuItem = function (parentMenu, child) {\n        parentMenu.remove(child);\n    };\n\n    /** @override */\n    GSystemShell.prototype.getClipboardMimeTypes = function () {\n        return this._clipboardMimeTypes ? Object.keys(this._clipboardMimeTypes) : null;\n    };\n\n    /** @override */\n    GSystemShell.prototype.getClipboardContent = function (mimeType) {\n        if (this._clipboardMimeTypes && this._clipboardMimeTypes.hasOwnProperty(mimeType)) {\n            return this._clipboardMimeTypes[mimeType];\n        }\n        return null;\n    };\n\n    /** @override */\n    GSystemShell.prototype.setClipboardContent = function (mimeType, content) {\n        this._clipboardMimeTypes[mimeType] = content;\n    };\n\n    /**\n     * Convert internal key into a shell-compatible key\n     * @param {Array<*>} shortcut\n     * @returns {{key: String, modifiers: String}}\n     */\n    GSystemShell.prototype._shortcutToShellShortcut = function (shortcut) {\n        var result = {\n            key: null,\n            modifiers: ''\n        };\n\n        for (var i = 0; i < shortcut.length; ++i) {\n            var key = shortcut[i];\n\n            if (typeof key == 'number') {\n                // we want a system-translated key here\n                var key = ifKey.transformKey(key);\n                switch (key) {\n                    // Modifiers\n                    case IFKey.Constant.CONTROL:\n                        result.modifiers = result.modifiers + (result.modifiers ? '-' : '') + 'ctrl';\n                        break;\n                    case IFKey.Constant.SHIFT:\n                        result.modifiers = result.modifiers + (result.modifiers ? '-' : '') + 'shift';\n                        break;\n                    case IFKey.Constant.ALT:\n                        result.modifiers = result.modifiers + (result.modifiers ? '-' : '') + 'alt';\n                        break;\n                    case IFKey.Constant.COMMAND:\n                        result.modifiers = result.modifiers + (result.modifiers ? '-' : '') + 'cmd';\n                        break;\n\n                    // Regular Keys\n                    case IFKey.Constant.SPACE:\n                        // TODO\n                        result.key = \" \";\n                        break;\n                    case IFKey.Constant.ENTER:\n                        // TODO\n                        result.key = \"\\r\";\n                        break;\n                    case IFKey.Constant.TAB:\n                        // TODO\n                        result.key = \"\\t\";\n                        break;\n                    case IFKey.Constant.BACKSPACE:\n                        // TODO\n                        result.key = \"\\b\";\n                        break;\n\n                    case IFKey.Constant.LEFT:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF702);\n                        } else {\n                            result.key = \"LEFT\";\n                        }\n                        break;\n                    case IFKey.Constant.UP:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF700);\n                        } else {\n                            result.key = \"UP\";\n                        }\n                        break;\n                    case IFKey.Constant.RIGHT:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF703);\n                        } else {\n                            result.key = \"RIGHT\";\n                        }\n                        break;\n                    case IFKey.Constant.DOWN:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF701);\n                        } else {\n                            result.key = \"DOWN\";\n                        }\n                        break;\n                    case IFKey.Constant.PAGE_UP:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF72C);\n                        } else {\n                            result.key = \"PAGEUP\";\n                        }\n                        break;\n                    case IFKey.Constant.PAGE_DOWN:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF72D);\n                        } else {\n                            result.key = \"PAGEDOWN\";\n                        }\n                        break;\n                    case IFKey.Constant.HOME:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF729);\n                        } else {\n                            result.key = \"HOME\";\n                        }\n                        break;\n                    case IFKey.Constant.END:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF72B);\n                        } else {\n                            result.key = \"END\";\n                        }\n                        break;\n                    case IFKey.Constant.INSERT:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF727);\n                        } else {\n                            result.key = \"INSERT\";\n                        }\n                        break;\n                    case IFKey.Constant.DELETE:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF728);\n                        } else {\n                            result.key = \"DELETE\";\n                        }\n                        break;\n                    case IFKey.Constant.F1:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF704);\n                        } else {\n                            result.key = \"F1\";\n                        }\n                        break;\n                    case IFKey.Constant.F2:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF705);\n                        } else {\n                            result.key = \"F2\";\n                        }\n                        break;\n                    case IFKey.Constant.F3:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF706);\n                        } else {\n                            result.key = \"F3\";\n                        }\n                        break;\n                    case IFKey.Constant.F4:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF707);\n                        } else {\n                            result.key = \"F4\";\n                        }\n                        break;\n                    case IFKey.Constant.F5:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF708);\n                        } else {\n                            result.key = \"F5\";\n                        }\n                        break;\n                    case IFKey.Constant.F6:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF709);\n                        } else {\n                            result.key = \"F6\";\n                        }\n                        break;\n                    case IFKey.Constant.F7:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF70A);\n                        } else {\n                            result.key = \"F7\";\n                        }\n                        break;\n                    case IFKey.Constant.F8:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF70B);\n                        } else {\n                            result.key = \"F8\";\n                        }\n                        break;\n                    case IFKey.Constant.F9:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF70C);\n                        } else {\n                            result.key = \"F9\";\n                        }\n                        break;\n                    case IFKey.Constant.F10:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF70D);\n                        } else {\n                            result.key = \"F10\";\n                        }\n                        break;\n                    case IFKey.Constant.F11:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF70E);\n                        } else {\n                            result.key = \"F11\";\n                        }\n                        break;\n                    case IFKey.Constant.F12:\n                        if (process.platform === 'darwin') {\n                            result.key = String.fromCharCode(0xF70F);\n                        } else {\n                            result.key = \"F12\";\n                        }\n                        break;\n                    default:\n                        throw new Error(\"Unknown key code\");\n                }\n            } else {\n                result.key = key.toLowerCase();\n            }\n        }\n\n        if (result.modifiers === '') {\n            result.modifiers = null;\n        }\n\n        return result.key !== null ? result : null;\n    };\n\n    _.gShell = new GSystemShell;\n\n    $(document).ready(function () {\n        // Open dev console if desired\n        var argv = gui.App.argv;\n        if (_.gShell.isDevelopment() || argv.indexOf('-console') >= 0) {\n            win.showDevTools();\n        }\n\n        gShellReady();\n    });\n\n    $(window).load(function () {\n        gravit.storages.push(new GFileStorage());\n        gShellFinished();\n    });\n})(this);\n"
  },
  {
    "path": "shell/system/winstate.js",
    "content": "/**\n * Cross-platform window state preservation.\n * Yes this code is quite complicated, but this is the best I came up with for\n * current state of node-webkit Window API (v0.7.3 and later).\n *\n * Known issues:\n * - Unmaximization not always sets the window (x, y) in the lastly used coordinates.\n * - Unmaximization animation sometimes looks wierd.\n * - Extra height added to window, at least in linux x64 gnome-shell env. It seems that\n *   when we read height then it returns it with window frame, but if we resize window\n *   then it applies dimensions only to internal document without external frame.\n *   Need to test in other environments with different visual themes.\n *\n * Change log:\n * 2013-12-01\n * - Workaround of extra height in gnome-shell added.\n *\n * 2014-03-22\n * - Repared workaround (from 2013-12-01) behaviour when use frameless window.\n *   Now it works correctly.\n */\n\nvar gui = require('nw.gui');\nvar win = gui.Window.get();\nvar winState;\nvar currWinMode;\nvar resizeTimeout;\nvar isMaximizationEvent = false;\n\n// extra height added in linux x64 gnome-shell env, use it as workaround\nvar deltaHeight = (function () {\n    // use deltaHeight only in windows with frame enabled\n    if (gui.App.manifest.window.frame) return true; else return 'disabled';\n})();\n\n\nfunction initWindowState() {\n    winState = JSON.parse(localStorage.windowState || 'null');\n\n    if (winState) {\n        currWinMode = winState.mode;\n        if (currWinMode === 'maximized') {\n            win.maximize();\n        } else {\n            restoreWindowState();\n        }\n    } else {\n        currWinMode = 'normal';\n        if (deltaHeight !== 'disabled') deltaHeight = 0;\n        dumpWindowState();\n    }\n}\n\nfunction dumpWindowState() {\n    if (!winState) {\n        winState = {};\n    }\n\n    // we don't want to save minimized state, only maximized or normal\n    if (currWinMode === 'maximized') {\n        winState.mode = 'maximized';\n    } else {\n        winState.mode = 'normal';\n    }\n\n    // when window is maximized you want to preserve normal\n    // window dimensions to restore them later (even between sessions)\n    if (currWinMode === 'normal') {\n        winState.x = win.x;\n        winState.y = win.y;\n        winState.width = win.width;\n        winState.height = win.height;\n\n        // save delta only of it is not zero\n        if (deltaHeight !== 'disabled' && deltaHeight !== 0 && currWinMode !== 'maximized') {\n            winState.deltaHeight = deltaHeight;\n        }\n    }\n}\n\nfunction restoreWindowState() {\n    console.log('restore_window_state');\n    // deltaHeight already saved, so just restore it and adjust window height\n    if (deltaHeight !== 'disabled' && typeof winState.deltaHeight !== 'undefined') {\n        deltaHeight = winState.deltaHeight\n        winState.height = winState.height - deltaHeight\n    }\n\n    win.resizeTo(winState.width, winState.height);\n    win.moveTo(winState.x, winState.y);\n}\n\nfunction saveWindowState() {\n    dumpWindowState();\n    localStorage.windowState = JSON.stringify(winState);\n}\n\ninitWindowState();\n\nwin.on('maximize', function () {\n    isMaximizationEvent = true;\n    currWinMode = 'maximized';\n});\n\nwin.on('unmaximize', function () {\n    currWinMode = 'normal';\n    restoreWindowState();\n});\n\nwin.on('minimize', function () {\n    currWinMode = 'minimized';\n});\n\nwin.on('restore', function () {\n    currWinMode = 'normal';\n});\n\nwin.window.addEventListener('resize', function () {\n    // resize event is fired many times on one resize action,\n    // this hack with setTiemout forces it to fire only once\n    clearTimeout(resizeTimeout);\n    resizeTimeout = setTimeout(function () {\n\n        // on MacOS you can resize maximized window, so it's no longer maximized\n        if (isMaximizationEvent) {\n            // first resize after maximization event should be ignored\n            isMaximizationEvent = false;\n        } else {\n            if (currWinMode === 'maximized') {\n                currWinMode = 'normal';\n            }\n        }\n\n        // there is no deltaHeight yet, calculate it and adjust window size\n        if (deltaHeight !== 'disabled' && deltaHeight === false) {\n            deltaHeight = win.height - winState.height;\n\n            // set correct size\n            if (deltaHeight !== 0) {\n                win.resizeTo(winState.width, win.height - deltaHeight);\n            }\n        }\n\n        dumpWindowState();\n\n    }, 500);\n}, false);\n\nwin.on('close', function () {\n    saveWindowState();\n    this.close(true);\n});"
  },
  {
    "path": "src/application/application.js",
    "content": "(function (_) {\n    /**\n     * The global application class\n     * @class GApplication\n     * @extends GEventTarget\n     * @constructor\n     * @version 1.0\n     */\n    function GApplication() {\n        this._actions = [];\n        this._toolManager = new IFToolManager();\n        this._documents = [];\n        this._windowMenuMap = [];\n\n        document.addEventListener(\"touchstart\", this._touchHandler, true);\n        document.addEventListener(\"touchmove\", this._touchHandler, true);\n        document.addEventListener(\"touchend\", this._touchHandler, true);\n        document.addEventListener(\"touchcancel\", this._touchHandler, true);\n\n        // This is a hack to focus our active window\n        // whenever a key is hit down (in capture phase) and\n        // if not an editable element is active!\n        document.addEventListener('keydown', function (evt) {\n            var activeWindow = this._windows.getActiveWindow();\n            if (activeWindow && (!document.activeElement || !$(document.activeElement).is(\":editable\"))) {\n                activeWindow.getView().focus();\n            }\n        }.bind(this), false);\n\n        // Prevent context-menu globally except for editable elements\n        document.addEventListener('contextmenu', function (evt) {\n            if (!$(evt.target).is(':editable')) {\n                evt.preventDefault();\n                return false;\n            } else {\n                // Stop propagation to let browser handle the event\n                evt.stopPropagation();\n                return true;\n            }\n        }, true);\n    };\n    IFObject.inherit(GApplication, GEventTarget);\n\n    // Constants for pre-defined action categories\n    GApplication.CATEGORY_FILE = new IFLocale.Key(GApplication, \"category.file\");\n    GApplication.CATEGORY_EDIT = new IFLocale.Key(GApplication, \"category.edit\");\n    GApplication.CATEGORY_MODIFY = new IFLocale.Key(GApplication, \"category.modify\");\n    GApplication.CATEGORY_MODIFY_ARRANGE = new IFLocale.Key(GApplication, \"category.modify.arrange\");\n    GApplication.CATEGORY_MODIFY_ALIGN = new IFLocale.Key(GApplication, \"category.modify.align\");\n    GApplication.CATEGORY_MODIFY_TRANSFORM = new IFLocale.Key(GApplication, \"category.modify.transform\");\n    GApplication.CATEGORY_MODIFY_PAGE = new IFLocale.Key(GApplication, \"category.modify.page\");\n    GApplication.CATEGORY_MODIFY_LAYER = new IFLocale.Key(GApplication, \"category.modify.layer\");\n    GApplication.CATEGORY_VIEW = new IFLocale.Key(GApplication, \"category.view\");\n    GApplication.CATEGORY_VIEW_MAGNIFICATION = new IFLocale.Key(GApplication, \"category.view.magnification\");\n    GApplication.CATEGORY_WINDOW = new IFLocale.Key(GApplication, \"category.window\");\n    GApplication.CATEGORY_HELP = new IFLocale.Key(GApplication, \"category.help\");\n\n    // Constants for pre-defined tool categories\n    GApplication.TOOL_CATEGORY_SELECT = new IFLocale.Key(GApplication, \"tool-category.select\");\n    GApplication.TOOL_CATEGORY_IMAGE = new IFLocale.Key(GApplication, \"tool-category.image\");\n    GApplication.TOOL_CATEGORY_VECTOR = new IFLocale.Key(GApplication, \"tool-category.vector\");\n    GApplication.TOOL_CATEGORY_OTHER = new IFLocale.Key(GApplication, \"tool-category.other\");\n    GApplication.TOOL_CATEGORY_COLOR = new IFLocale.Key(GApplication, \"tool-category.color\");\n    GApplication.TOOL_CATEGORY_VIEW = new IFLocale.Key(GApplication, \"tool-category.view\");\n\n    /**\n     * Visual parts of the application\n     */\n    GApplication.Part = {\n        Header: {\n            id: \"header\"\n        },\n        Toolbar: {\n            id: \"toolbar\"\n        },\n        Panels: {\n            id: \"panels\"\n        },\n        Sidebars: {\n            id: \"sidebars\"\n        },\n        Windows: {\n            id: \"windows\"\n        },\n        Palettes: {\n            id: \"palettes\"\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GApplication.DocumentEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event whenever a document event occurrs\n     * @class GApplication.DocumentEvent\n     * @extends GEvent\n     * @constructor\n     */\n    GApplication.DocumentEvent = function (type, document) {\n        this.type = type;\n        this.document = document;\n    };\n    IFObject.inherit(GApplication.DocumentEvent, GEvent);\n\n    /**\n     * Enumeration of view event types\n     * @enum\n     */\n    GApplication.DocumentEvent.Type = {\n        Added: 0,\n        Removed: 1,\n        Deactivated: 10,\n        Activated: 11,\n        UrlUpdated: 12\n    };\n\n    /**\n     * @type {GApplication.DocumentEvent.Type}\n     */\n    GApplication.DocumentEvent.prototype.type = null;\n\n    /**\n     * The affected document\n     * @type {GDocument}\n     */\n    GApplication.DocumentEvent.prototype.document = null;\n\n    /** @override */\n    GApplication.DocumentEvent.prototype.toString = function () {\n        return \"[Object GApplication.DocumentEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GApplication Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    GApplication.prototype._initialized = false;\n\n    /**\n     * @type {IFToolManager}\n     * @private\n     */\n    GApplication.prototype._toolManager = null;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    GApplication.prototype._documentUntitledCount = 0;\n\n    /**\n     * @type {Array<GDocument>}\n     * @private\n     */\n    GApplication.prototype._documents = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GApplication.prototype._activeDocument = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GApplication.prototype._view = null;\n\n    /**\n     * @type {GHeader}\n     * @private\n     */\n    GApplication.prototype._header = null;\n\n    /**\n     * @type {GToolbar}\n     * @private\n     */\n    GApplication.prototype._toolbar = null;\n\n    /**\n     * @type {GPanels}\n     * @private\n     */\n    GApplication.prototype._panels = null;\n\n    /**\n     * @type {GSidebars}\n     * @private\n     */\n    GApplication.prototype._sidebars = null;\n\n    /**\n     * @type {GWindows}\n     * @private\n     */\n    GApplication.prototype._windows = null;\n\n    /**\n     * @type {GPalettes}\n     * @private\n     */\n    GApplication.prototype._palettes = null;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    GApplication.prototype._resizeTimerId = null;\n\n\n    /**\n     * Array of registered actions\n     * @type {Array<GAction>}\n     * @private\n     */\n    GApplication.prototype._actions = null;\n\n    /**\n     * Application window shell menu\n     * @type {*}\n     * @private\n     */\n    GApplication.prototype._windowMenu = null;\n\n    /**\n     * @type {Array<{window: GWindow, item: *}>}\n     * @private\n     */\n    GApplication.prototype._windowMenuMap = null;\n\n    /**\n     * @returns {IFToolManager}\n     */\n    GApplication.prototype.getToolManager = function () {\n        return this._toolManager;\n    };\n\n    /**\n     * Returns a list of all opened documents\n     * @return {Array<GDocument>}\n     */\n    GApplication.prototype.getDocuments = function () {\n        return this._documents;\n    };\n\n    /**\n     * Returns the currently active document\n     * @return {GDocument}\n     */\n    GApplication.prototype.getActiveDocument = function () {\n        return this._activeDocument ? this._activeDocument : null;\n    };\n\n    /**\n     * Return access to the header\n     * @returns {GHeader}\n     */\n    GApplication.prototype.getHeader = function () {\n        return this._header;\n    };\n\n    /**\n     * Return access to the toolbar\n     * @returns {GToolbar}\n     */\n    GApplication.prototype.getToolbar = function () {\n        return this._toolbar;\n    };\n\n    /**\n     * Return access to the panels\n     * @returns {GPanels}\n     */\n    GApplication.prototype.getPanels = function () {\n        return this._panels;\n    };\n\n    /**\n     * Return access to the sidebars\n     * @returns {GSidebars}\n     */\n    GApplication.prototype.getSidebars = function () {\n        return this._sidebars;\n    };\n\n    /**\n     * Return access to the window container\n     * @returns {GWindows}\n     */\n    GApplication.prototype.getWindows = function () {\n        return this._windows;\n    };\n\n    /**\n     * Return access to the palettes container\n     * @returns {GPalettes}\n     */\n    GApplication.prototype.getPalettes = function () {\n        return this._palettes;\n    };\n\n    /**\n     * Checks if a given part is visible or not\n     * @param {GApplication.Part} part the part to check for\n     * @returns {boolean} true if part is visible, false if not\n     */\n    GApplication.prototype.isPartVisible = function (part) {\n        return this.getPart(part).css('display') !== 'none';\n    };\n\n    /**\n     * Make a given part visible or not\n     * @param {GApplication.Part} part the part\n     * @param visible whether to make the part visible or not\n     */\n    GApplication.prototype.setPartVisible = function (part, visible) {\n        if (visible != this.isPartVisible(part)) {\n            this.getPart(part).css('display', (visible ? 'block' : 'none'));\n            this.relayout();\n        }\n    };\n\n    /**\n     * Return reference to a given part\n     * @param {GApplication.Part} part\n     * @returns {JQuery}\n     */\n    GApplication.prototype.getPart = function (part) {\n        return this._view.find('#' + part.id);\n    };\n\n    /**\n     * Get a list of all registered actions\n     * @return {Array<GAction>} list of registered actions\n     */\n    GApplication.prototype.getActions = function () {\n        return this._actions;\n    };\n\n    /**\n     * Get an action instance by it's given id\n     * @param {String} id\n     */\n    GApplication.prototype.getAction = function (id) {\n        for (var i = 0; i < this._actions.length; ++i) {\n            if (this._actions[i].getId() === id) {\n                return this._actions[i];\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Returns the storage for a given url by it's protocol\n     * @param {String} url\n     * @return {GStorage}\n     */\n    GApplication.prototype.getStorage = function (url) {\n        var protocol = new URI(url).protocol();\n        if (protocol && protocol.length) {\n            for (var i = 0; i < gravit.storages.length; ++i) {\n                if (gravit.storages[i].getProtocol() === protocol) {\n                    return gravit.storages[i];\n                }\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Tries to find the best matching storage for the given parameters\n     * @param {Boolean} prompt if true, the storage must support prompting\n     * @param {Boolean} save if true, the storage must support saving\n     * @param {String} [extension] if set, the storage must support the given\n     * extension (ignored if directory is true), defaults to null which ignores this\n     * @param {Boolean} [directory] if true, the storage must support directories,\n     * defaults to false\n     * @param {GStorage} [preferredStorage] if provided, will prefer this storage\n     * when it fills all requirements. Defaults to null.\n     */\n    GApplication.prototype.getMatchingStorage = function (prompt, save, extension, directory, preferredStorage) {\n        var storages = [];\n\n        // Put preferred storage on top if any\n        if (preferredStorage) {\n            storages.push(preferredStorage);\n        }\n\n        // Add all storages to check\n        for (var i = 0; i < gravit.storages.length; ++i) {\n            var storage = gravit.storages[i];\n            if (storage !== preferredStorage) {\n                storages.push(storage);\n            }\n        }\n\n        // Now iterate and find the best candidate if any\n        for (var i = 0; i < storages.length; ++i) {\n            var storage = storages[i];\n\n            if (prompt && !storage.isPrompting()) {\n                continue;\n            }\n\n            if (save && !storage.isSaving()) {\n                continue;\n            }\n\n            if (extension && extension !== '') {\n                var extensions = storage.getExtensions();\n                if (extensions && extensions.length && extensions.indexOf(extension) < 0) {\n                    continue;\n                }\n            }\n\n            if (directory && !storage.isDirectory()) {\n                continue;\n            }\n\n            return storage;\n        }\n\n        return null;\n    };\n\n    /**\n     * Create a new document and add it\n     */\n    GApplication.prototype.createNewDocument = function () {\n        // Create scene, add it and call add page to insert a default page\n        var scene = new IFScene();\n        scene.setProperty('unit', IFLength.Unit.PX);\n        var document = this.addDocument(scene);\n        document.createNewPage(true/*no-undo*/);\n    };\n\n    /**\n     * Add a new document and open up a window for it\n     * and mark the view as being active\n     * @param {IFScene} scene the scene to add the document from it\n     * @param {String} [temporaryTitle] optional temporary title to be used\n     * for the document if no url is assigned, defaults to null to use\n     * the default naming scheme\n     */\n    GApplication.prototype.addDocument = function (scene, temporaryTitle) {\n        // TODO : I18N\n        var document = new GDocument(scene, null, temporaryTitle ? temporaryTitle : 'Untitled-' + (++this._documentUntitledCount).toString());\n        this._addDocument(document);\n        return document;\n    };\n\n    /**\n     * Open a document and open up a window for it\n     * and mark the view as being active\n     * @param {String} url the url to open the document from\n     */\n    GApplication.prototype.openDocument = function (url) {\n        // Iterate all documents first and look if the given\n        // url is already opened and if so, activate the\n        // document's last view\n        var documentAlreadyOpened = false;\n        for (var i = 0; i < this._documents.length; ++i) {\n            var document = this._documents[i];\n            if (document.getUrl() === url) {\n                this.activateDocument(document);\n                documentAlreadyOpened = true;\n            }\n        }\n\n        if (!documentAlreadyOpened) {\n            var storage = this.getStorage(url);\n            if (storage) {\n                storage.load(url, true, function (data, name) {\n                    var _readDocument = function (source) {\n                        var scene = new IFScene();\n                        var document = new GDocument(scene, url, name);\n                        try {\n                            var blob = JSON.parse(source);\n                            if (!scene.restore(blob)) {\n                                throw new Error('Failure.');\n                            }\n                        } catch (e) {\n                            document.close();\n                            scene = null;\n                            document = null;\n                            console.log(e);\n                            alert('An error has ocurred while trying to open the document.');\n                        }\n\n                        if (document) {\n                            this._addDocument(document);\n                        }\n                    }.bind(this);\n\n\n                    var uint8Array = new Uint8Array(data);\n\n                    // Test for gzip\n                    if (uint8Array[0] === 0x1F && uint8Array[1] === 0x8B && uint8Array[2] === 0x08) {\n                        var source = pako.ungzip(uint8Array, { to: 'string' });\n                        _readDocument(source);\n                    } else {\n                        // Assume plain string\n                        var f = new FileReader();\n                        f.onload = function (e) {\n                            _readDocument(e.target.result);\n                        }\n                        f.readAsText(new Blob([data]));\n                    }\n                }.bind(this));\n            }\n        }\n    };\n\n    /**\n     * Prompt to open a document\n     * @param {GStorage} storage\n     */\n    GApplication.prototype.openDocumentFrom = function (storage) {\n        var url = gApp.getActiveDocument() ? gApp.getActiveDocument().getUrl() : null;\n        storage.openResourcePrompt(url && url !== '' ? url : null, ['gravit'], function (url) {\n            gApp.openDocument(url);\n        });\n    };\n\n    /**\n     * Prompt to save a document under a new target\n     * @param {GStorage} storage\n     * @param {GDocument} [document] the document to save as, if\n     * not provided takes the currently active one\n     */\n    GApplication.prototype.saveDocumentAs = function (storage, document) {\n        var document = document || this.getActiveDocument();\n\n        if (document) {\n            // TODO : Set first parameter 'reference'\n            storage.saveResourcePrompt(null, document.getTitle(), 'gravit', function (url) {\n                document.setUrl(url)\n                document.save();\n\n                // Update all view window menu items\n                var windows = document.getWindows();\n                for (var i = 0; i < windows.length; ++i) {\n                    this._updateWindowMenuItem(windows[i]);\n                }\n\n                // Trigger event\n                if (this.hasEventListeners(GApplication.DocumentEvent)) {\n                    this.trigger(new GApplication.DocumentEvent(GApplication.DocumentEvent.Type.UrlUpdated, this));\n                }\n            }.bind(this));\n        }\n    };\n\n    /**\n     * Mark a given document as being the active one and activates\n     * the first window for the document as well\n     * @param {GDocument} document may be null to only deactivate the current one\n     * @param {boolean} [noWindowActivation] optional param that, if set, avoids\n     * activating the corresponding window when the document gets activated\n     */\n    GApplication.prototype.activateDocument = function (document, noWindowActivation) {\n        if (document != this._activeDocument) {\n            // Deactivate previous one if any\n            if (this._activeDocument) {\n                if (this._activeDocument) {\n                    this._activeDocument.deactivate();\n\n                    if (this.hasEventListeners(GApplication.DocumentEvent)) {\n                        this.trigger(new GApplication.DocumentEvent(GApplication.DocumentEvent.Type.Deactivated, this._activeDocument));\n                    }\n                }\n\n                this._activeDocument = null;\n            }\n\n            // Activate new one if any\n            if (document) {\n                // Activate lastly activated window of document\n                if (!noWindowActivation) {\n                    this._windows.activateWindow(document.getActiveWindow());\n                }\n\n                document.activate();\n\n                // Now assign the active document\n                this._activeDocument = document;\n\n                if (this.hasEventListeners(GApplication.DocumentEvent)) {\n                    this.trigger(new GApplication.DocumentEvent(GApplication.DocumentEvent.Type.Activated, document));\n                }\n            }\n        }\n    };\n\n    /**\n     * Closes and removes a document and all of it's views\n     * @param {GDocument} document\n     */\n    GApplication.prototype.closeDocument = function (document) {\n        if (document._windows.length) {\n            // Document has windows so remove them first which\n            // will then trigger this function again\n            while (document._windows.length > 0) {\n                this._windows.closeWindow(document._windows[0]);\n            }\n        } else {\n            // Remove active document if this is the active one\n            if (document === this.getActiveDocument()) {\n                this.activateDocument(null);\n            }\n\n            // Release document\n            document.release();\n\n            // Remove and trigger event\n            this._documents.splice(this._documents.indexOf(document), 1);\n\n            if (this.hasEventListeners(GApplication.DocumentEvent)) {\n                this.trigger(new GApplication.DocumentEvent(GApplication.DocumentEvent.Type.Removed, document));\n            }\n        }\n    };\n\n    /**\n     * Checks whether a given action can be executed or not\n     * @param {String} id id of the action to check\n     * @param {*} [args] optional args to be supplied to the action\n     * @return {Boolean}\n     */\n    GApplication.prototype.canExecuteAction = function (id, args) {\n        var actionInstance = this.getAction(id);\n\n        if (actionInstance) {\n            return actionInstance.isAvailable() && actionInstance.isEnabled.apply(actionInstance, args);\n        }\n\n        return false;\n    };\n\n    /**\n     * Execute a given action\n     * @param {String} id id of the action to execute\n     * @param {*} [args] optional args to be supplied to the action\n     * @return {*} the result of the action if any\n     */\n    GApplication.prototype.executeAction = function (id, args) {\n        var actionInstance = this.getAction(id);\n\n        if (!actionInstance) {\n            throw new Error(\"Unable to execute action '\" + id + \"' - not registered.\");\n        }\n\n        if (actionInstance.isAvailable() && actionInstance.isEnabled.apply(actionInstance, args)) {\n            var result = actionInstance.execute.apply(actionInstance, args);\n            if (typeof result !== 'undefined') {\n                return result;\n            }\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Called to initialize the application\n     */\n    GApplication.prototype.init = function () {\n        var body = $('body');\n\n        // Iterate modules and let each one initialize\n        for (var i = 0; i < gravit.modules.length; ++i) {\n            var module = gravit.modules[i];\n            console.log(\"Init module <\" + module.toString() + \">\");\n            module.init();\n        }\n\n        this._view = $(\"<div></div>\")\n            .attr('id', 'workspace')\n            .css('display', 'none')\n            .prependTo(body);\n\n        // Windows-Part\n        var windowsPart = $(\"<div></div>\")\n            .attr('id', GApplication.Part.Windows.id)\n            .appendTo(this._view);\n\n        this._windows = new GWindows(windowsPart);\n\n        // Header-Part\n        var headerPart = $(\"<div></div>\")\n            .attr('id', GApplication.Part.Header.id)\n            .appendTo(this._view);\n\n        this._header = new GHeader(headerPart);\n\n        // Toolbar-Part\n        var toolbarPart = $(\"<div></div>\")\n            .attr('id', GApplication.Part.Toolbar.id)\n            .appendTo(this._view);\n\n        this._toolbar = new GToolbar(toolbarPart);\n\n        // Panels-Part\n        var panelsPart = $(\"<div></div>\")\n            .attr('id', GApplication.Part.Panels.id)\n            .appendTo(this._view);\n\n        this._panels = new GPanels(panelsPart);\n\n        // Sidebars-Part\n        var sidebarsPart = $(\"<div></div>\")\n            .attr('id', GApplication.Part.Sidebars.id)\n            .appendTo(this._view);\n\n        this._sidebars = new GSidebars(sidebarsPart);\n\n        // Palettes-Part\n        var palettesPart = $(\"<div></div>\")\n            .attr('id', GApplication.Part.Palettes.id)\n            .appendTo(this._view);\n\n        this._palettes = new GPalettes(palettesPart);\n\n        // Append the corresponding hardware class to our body\n        switch (ifSystem.hardware) {\n            case IFSystem.Hardware.Desktop:\n                body.addClass('g-desktop');\n                break;\n            case IFSystem.Hardware.Tablet:\n                body.addClass('g-touch');\n                body.addClass('g-tablet');\n                break;\n            case IFSystem.Hardware.Phone:\n                body.addClass('g-touch');\n                body.addClass('g-phone');\n                break;\n        }\n\n        // Subscribe to window resize to relayout\n        $(window).resize(function () {\n            if (this._resizeTimerId != null) {\n                clearTimeout(this._resizeTimerId);\n                this._resizeTimerId = null;\n            }\n\n            this._windows.relayout();\n\n            this._resizeTimerId = setTimeout(function () {\n                this.relayout();\n                this._resizeTimerId = null;\n            }.bind(this), 200);\n        }.bind(this));\n\n        // TODO : Order our available palettes by group\n        // TODO : Order our available tools by group\n\n        // -- Register Actions\n        this._actions = gravit.actions.slice();\n        this._createMainMenu();\n\n        // Add all available tools to toolmanager and register\n        // their activation character(s) if any as shortcuts\n        if (gravit.tools) {\n            var _createToolActivateAction = function (instance) {\n                return function () {\n                    this._toolManager.activateTool(instance);\n                }.bind(this);\n            }.bind(this);\n\n            for (var i = 0; i < gravit.tools.length; ++i) {\n                var tool = gravit.tools[i];\n\n                // Register tool instance\n                this._toolManager.addTool(tool.instance);\n\n                // Register activation characters\n                if (tool.keys && tool.keys.length > 0) {\n                    var action = _createToolActivateAction(tool.instance);\n                    for (var c = 0; c < tool.keys.length; ++c) {\n                        this.registerShortcut([tool.keys[c]], action);\n                    }\n                }\n            }\n        }\n\n        this._header.init();\n        this._toolbar.init();\n        this._panels.init();\n        this._sidebars.init();\n        this._windows.init();\n        this._palettes.init();\n\n        // Hide sidebars by default - TODO : Load & save view configuration here\n        this.setPartVisible(GApplication.Part.Sidebars, false);\n\n        // Make workspace visible & make initial layout\n        this._view.css('display', '');\n\n        // Mark initialized\n        this._initialized = true;\n\n        // Subscribe to window events\n        this._windows.addEventListener(GWindows.WindowEvent, this._windowEvent, this);\n    };\n\n    /**\n     * Called to relayout the application\n     */\n    GApplication.prototype.relayout = function () {\n        if (!this._initialized) {\n            // ignore\n            return;\n        }\n\n        setTimeout(function () {\n            var topOffset = 0;\n            var leftOffset = 0;\n            var rightOffset = 0;\n            var bottomOffset = 0;\n\n            var headerPart = this.getPart(GApplication.Part.Header);\n            topOffset += this.isPartVisible(GApplication.Part.Header) ? headerPart.outerHeight() : 0;\n\n            var toolbarPart = this.getPart(GApplication.Part.Toolbar);\n            toolbarPart.css('top', topOffset.toString() + 'px');\n            toolbarPart.height(this._view.height() - topOffset);\n            leftOffset += this.isPartVisible(GApplication.Part.Toolbar) ? toolbarPart.outerWidth() : 0;\n\n            var sidebarsPart = this.getPart(GApplication.Part.Sidebars);\n            sidebarsPart.css('top', topOffset.toString() + 'px');\n            sidebarsPart.css('left', leftOffset.toString() + 'px');\n            sidebarsPart.height(this._view.height() - topOffset);\n            leftOffset += this.isPartVisible(GApplication.Part.Sidebars) ? sidebarsPart.outerWidth() : 0;\n\n            var palettesPart = this.getPart(GApplication.Part.Palettes);\n            palettesPart.css('top', topOffset.toString() + 'px');\n            palettesPart.height(this._view.height() - topOffset);\n            rightOffset += this.isPartVisible(GApplication.Part.Palettes) ? palettesPart.outerWidth() : 0;\n\n            var panelsPart = this.getPart(GApplication.Part.Panels);\n            panelsPart.css('left', leftOffset.toString() + 'px');\n            panelsPart.css('width', (this._view.width() - leftOffset - rightOffset).toString() + 'px');\n            bottomOffset += this.isPartVisible(GApplication.Part.Panels) ? panelsPart.outerHeight() : 0;\n\n            this._header.relayout();\n            this._toolbar.relayout();\n            this._panels.relayout();\n            this._sidebars.relayout();\n            this._windows.relayout([leftOffset, topOffset, rightOffset, bottomOffset]);\n            this._palettes.relayout();\n        }.bind(this), 0);\n    };\n\n    /**\n     * Register a shortcut that'll execute a given function\n     * @param {Array<*>} shortcut the shortcut for the action\n     * @param {Function} action an action to be executed when the\n     * shortcut is called\n     */\n    GApplication.prototype.registerShortcut = function (shortcut, action) {\n        Mousetrap.bind(this._shortcutToMouseTrapShortcut(shortcut), function () {\n            action();\n            return false;\n        }.bind(this));\n    };\n\n    /**\n     * Add a new document\n     * @param {GDocument} document\n     * @private\n     */\n    GApplication.prototype._addDocument = function (document) {\n        // Send an event\n        if (this.hasEventListeners(GApplication.DocumentEvent)) {\n            this.trigger(new GApplication.DocumentEvent(GApplication.DocumentEvent.Type.Added, document));\n        }\n\n        // Add a window for the document making it activated by default\n        this._windows.addWindow(document);\n    };\n\n    /**\n     * Create the main menu based on actions\n     * @param {Array<GAction>} actions\n     * @private\n     */\n    GApplication.prototype._createMainMenu = function () {\n        // Create our menu structure based on actions\n        // TODO : Order given actions by category & group\n\n        var itemToGroupArray = [];\n        var treeRoot = {\n            items: []\n        };\n\n        var _getGroupForItem = function (item) {\n            for (var i = 0; i < itemToGroupArray.length; ++i) {\n                if (itemToGroupArray[i].item === item) {\n                    return itemToGroupArray[i].group;\n                }\n            }\n        };\n\n        var _addItemGroupAndDivider = function (menu, item, group) {\n            if (menu.items.length > 0) {\n                var lastGroup = _getGroupForItem(menu.items[menu.items.length - 1]);\n                if (lastGroup !== group) {\n                    menu.items.push({\n                        type: 'divider'\n                    });\n                }\n            }\n            itemToGroupArray.push({\n                item: item,\n                group: group\n            });\n        };\n\n        for (var i = 0; i < this._actions.length; ++i) {\n            var action = this._actions[i];\n\n            if (!action.isAvailable()) {\n                continue;\n            }\n\n            var category = ifLocale.get(action.getCategory());\n            var group = action.getGroup();\n            var categories = category ? category.split('/') : null;\n            var groups = group ? [\"\"].concat(group.split('/')) : null;\n\n            if (groups && categories && categories.length !== groups.length - 1) {\n                throw new Error(\"Number of categories different thant number of groups.\");\n            }\n\n            // Build up our structure by iterating our categories\n            var currentTree = treeRoot;\n            if (categories) {\n                for (var k = 0; k < categories.length; ++k) {\n                    var category = categories[k];\n                    var group = groups ? groups[k] : null;\n\n                    var item = null;\n                    for (var l = 0; l < currentTree.items.length; ++l) {\n                        if (category == currentTree.items[l].caption) {\n                            item = currentTree.items[l];\n                        }\n                    }\n\n                    if (!item) {\n                        item = {\n                            type: 'menu',\n                            caption: category,\n                            items: [],\n                            windowMenu: GApplication.CATEGORY_WINDOW === action.getCategory() &&\n                                currentTree === treeRoot\n                        };\n                        _addItemGroupAndDivider(currentTree, item, group);\n\n                        currentTree.items.push(item);\n                    }\n                    currentTree = item;\n                }\n            }\n\n            // Add our action item now\n            var actionItem = {\n                type: 'item',\n                action: action\n            };\n            _addItemGroupAndDivider(currentTree, actionItem, groups ? groups[groups.length - 1] : null);\n\n            currentTree.items.push(actionItem);\n        }\n\n        var _createMenuItem = function (item, parentMenu) {\n            if (item.type === 'menu') {\n                item.menu = _createMenu(item, parentMenu);\n            } else if (item.type === 'divider') {\n                item.separator = gShell.addMenuSeparator(parentMenu);\n            } else if (item.type === 'item') {\n                item.item = gShell.addMenuItem(parentMenu, ifLocale.get(item.action.getTitle()), item.action.isCheckable(), item.action.getShortcut(),\n                    function () {\n                        this.executeAction(item.action.getId());\n                    }.bind(this));\n            }\n        }.bind(this);\n\n        // Initiate our menu structure now using our shell\n        var _createMenu = function (tree, parentMenu) {\n            var menu = gShell.addMenu(parentMenu, tree.caption, function () {\n                for (var i = 0; i < tree.items.length; ++i) {\n                    var item = tree.items[i];\n                    if (item.type === 'item') {\n                        gShell.updateMenuItem(item.item, ifLocale.get(item.action.getTitle()),\n                            item.action.isEnabled(), item.action.isCheckable() ? item.action.isChecked() : false);\n                    }\n                }\n            });\n\n            for (var i = 0; i < tree.items.length; ++i) {\n                _createMenuItem(tree.items[i], menu);\n            }\n\n            return menu;\n        };\n\n        for (var i = 0; i < treeRoot.items.length; ++i) {\n            var item = treeRoot.items[i];\n            var menu = _createMenu(treeRoot.items[i], null);\n\n            // Save window menu\n            if (item.windowMenu) {\n                this._windowMenu = menu;\n\n                // Make sure to append an ending divider for windows\n                gShell.addMenuSeparator(this._windowMenu);\n            }\n        }\n    };\n\n    /**\n     * @param {GWindows.WindowEvent} evt\n     * @private\n     */\n    GApplication.prototype._windowEvent = function (evt) {\n        switch (evt.type) {\n            case GWindows.WindowEvent.Type.Added:\n                this._addWindowMenuItem(evt.window);\n                break;\n            case GWindows.WindowEvent.Type.Removed:\n                this._removeWindowMenuItem(evt.window);\n                break;\n            case GWindows.WindowEvent.Type.Activated:\n                this._updateWindowMenuItem(evt.window);\n                this._toolManager.setView(evt.window.getView());\n                break;\n            case GWindows.WindowEvent.Type.Deactivated:\n                this._updateWindowMenuItem(evt.window);\n                this._toolManager.setView(null);\n                break;\n            default:\n                break;\n        }\n    };\n\n    /**\n     * @param {GWindow} window\n     * @private\n     */\n    GApplication.prototype._addWindowMenuItem = function (window) {\n        this._windowMenuMap.push({\n            window: window,\n            item: gShell.addMenuItem(this._windowMenu, window.getTitle(), true, null, function () {\n                this._windows.activateWindow(window);\n            }.bind(this))\n        });\n        this._updateWindowMenuItem(window);\n    };\n\n    /**\n     * @param {GWindow} window\n     * @private\n     */\n    GApplication.prototype._removeWindowMenuItem = function (window) {\n        for (var i = 0; i < this._windowMenuMap.length; ++i) {\n            var map = this._windowMenuMap[i];\n            if (map.window === window) {\n                gShell.removeMenuItem(this._windowMenu, map.item);\n                this._windowMenuMap.splice(i, 1);\n                break;\n            }\n        }\n        this._updateTitle();\n    };\n\n    /**\n     * @param {GWindow} window\n     * @private\n     */\n    GApplication.prototype._updateWindowMenuItem = function (window) {\n        for (var i = 0; i < this._windowMenuMap.length; ++i) {\n            var map = this._windowMenuMap[i];\n            if (map.window === window) {\n                gShell.updateMenuItem(map.item, map.window.getTitle(), true, map.window === this._windows.getActiveWindow());\n                break;\n            }\n        }\n        this._updateTitle();\n    };\n\n    GApplication.prototype._updateTitle = function () {\n        var title = 'Gravit';\n        var window = this.getWindows().getActiveWindow();\n        if (window) {\n            title += ' - ' + window.getTitle();\n        }\n        document.title = title;\n    }\n\n    /**\n     * Handle touch events by converting them into mouse events and stopping\n     * every further propagation to guarantee mouse events not being fired twice\n     * @private\n     */\n    GApplication.prototype._touchHandler = function (event) {\n        // allow default multi-touch gestures to work\n        if (event.touches.length > 1) {\n            return;\n        }\n\n        function dispatchEventFromTouch(eventType, touch) {\n            var simulatedEvent = document.createEvent(\"MouseEvent\");\n            simulatedEvent.initMouseEvent(eventType, true, true, window, 1,\n                touch.screenX, touch.screenY,\n                touch.clientX, touch.clientY, false,\n                false, false, false, 0/*left*/, null);\n\n            touch.target.dispatchEvent(simulatedEvent);\n        };\n\n        var touch = event.changedTouches[0];\n        switch (event.type) {\n            case \"touchstart\":\n                dispatchEventFromTouch(\"mousedown\", touch);\n                break;\n            case \"touchmove\":\n                dispatchEventFromTouch(\"mousemove\", touch);\n                break;\n            case \"touchend\":\n                dispatchEventFromTouch(\"mouseup\", touch);\n                dispatchEventFromTouch(\"click\", touch);\n                break;\n            default:\n                return;\n        }\n\n        // Prevent any further processing\n        event.preventDefault();\n        event.stopPropagation();\n    };\n\n    /**\n     * Convert internal key into a mousetrap-compatible key\n     * @param {Array<*>} shortcut\n     * @returns {String}\n     */\n    GApplication.prototype._shortcutToMouseTrapShortcut = function (shortcut) {\n        var result = \"\";\n        for (var i = 0; i < shortcut.length; ++i) {\n            if (i > 0) {\n                result += \"+\";\n            }\n\n            var key = shortcut[i];\n            if (typeof key == 'number') {\n                switch (key) {\n                    case IFKey.Constant.META:\n                        result += \"meta\";\n                        break;\n                    case IFKey.Constant.OPTION:\n                        result += \"option\";\n                        break;\n                    case IFKey.Constant.REMOVE:\n                        result += \"del\";\n                        break;\n                    case IFKey.Constant.SPACE:\n                        result += \"space\";\n                        break;\n                    case IFKey.Constant.ENTER:\n                        result += \"enter\";\n                        break;\n                    case IFKey.Constant.TAB:\n                        result += \"tab\";\n                        break;\n                    case IFKey.Constant.BACKSPACE:\n                        result += \"backspace\";\n                        break;\n                    case IFKey.Constant.CONTROL:\n                        result += \"ctrl\";\n                        break;\n                    case IFKey.Constant.SHIFT:\n                        result += \"shift\";\n                        break;\n                    case IFKey.Constant.ALT:\n                        result += \"alt\";\n                        break;\n                    case IFKey.Constant.LEFT:\n                        result += \"left\";\n                        break;\n                    case IFKey.Constant.UP:\n                        result += \"up\";\n                        break;\n                    case IFKey.Constant.RIGHT:\n                        result += \"right\";\n                        break;\n                    case IFKey.Constant.DOWN:\n                        result += \"down\";\n                        break;\n                    case IFKey.Constant.PAGE_UP:\n                        result += \"pageup\";\n                        break;\n                    case IFKey.Constant.PAGE_DOWN:\n                        result += \"pagedown\";\n                        break;\n                    case IFKey.Constant.HOME:\n                        result += \"home\";\n                        break;\n                    case IFKey.Constant.END:\n                        result += \"end\";\n                        break;\n                    case IFKey.Constant.INSERT:\n                        result += \"ins\";\n                        break;\n                    case IFKey.Constant.DELETE:\n                        result += \"del\";\n                        break;\n                    case IFKey.Constant.COMMAND:\n                        result += \"meta\";\n                        break;\n                    case IFKey.Constant.F1:\n                        result += \"f1\";\n                        break;\n                    case IFKey.Constant.F2:\n                        result += \"f2\";\n                        break;\n                    case IFKey.Constant.F3:\n                        result += \"f3\";\n                        break;\n                    case IFKey.Constant.F4:\n                        result += \"f4\";\n                        break;\n                    case IFKey.Constant.F5:\n                        result += \"f5\";\n                        break;\n                    case IFKey.Constant.F6:\n                        result += \"f6\";\n                        break;\n                    case IFKey.Constant.F7:\n                        result += \"f7\";\n                        break;\n                    case IFKey.Constant.F8:\n                        result += \"f8\";\n                        break;\n                    case IFKey.Constant.F9:\n                        result += \"f9\";\n                        break;\n                    case IFKey.Constant.F10:\n                        result += \"f10\";\n                        break;\n                    case IFKey.Constant.F11:\n                        result += \"f11\";\n                        break;\n                    case IFKey.Constant.F12:\n                        result += \"f12\";\n                        break;\n                    default:\n                        throw new Error(\"Unknown key code\");\n                }\n            } else {\n                result += key.toLowerCase();\n            }\n        }\n        return result;\n    };\n\n    _.GApplication = GApplication;\n})(this);\n"
  },
  {
    "path": "src/application/bootstrap.js",
    "content": "var gravit = {\n    /**\n     * Array<GModule>\n     */\n    modules: [],\n\n    /**\n     * Array<GStorage>\n     */\n    storages: [],\n\n    /**\n     * Array<GExporter>\n     */\n    exporters: [],\n\n    /**\n     * Array<GAction>\n     */\n    actions: [],\n\n    /**\n     * Array<GPalette>\n     */\n    palettes: [],\n\n    /**\n     * Array<GSidebar>\n     */\n    sidebars: [],\n\n    /**\n     * Array<GPanel>\n     */\n    panels: [],\n\n    /**\n     * Array<{{instance: IFTool, title: String|IFLocale.Key, group: String, keys: Array<String>}, icon: String}>\n     */\n    tools: [],\n\n    /**\n     * Array<GColorMatcher>\n     */\n    colorMatchers: [],\n\n    /**\n     * Array<GProperties>\n     */\n    properties: [],\n\n    /**\n     * Array<GStyleEntry>\n     */\n    styleEntries: [],\n\n    /**\n     * Array<GTransformer>\n     */\n    transformers: []\n};\n\nvar gLoaderCode = '<div style=\"position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; background: rgb(213, 223, 0);\">\\n    <style type=\"text/css\">\\n        .spinner {\\n            width: 120px;\\n            height: 120px;\\n            position: absolute;\\n            top: 50%;\\n            left: 50%;\\n            margin: -80px 0 0 -60px;\\n            text-align: center;\\n            -webkit-animation: rotate 2.0s infinite linear;\\n            animation: rotate 2.0s infinite linear;\\n        }\\n\\n        .spinner-dot1, .spinner-dot2 {\\n            width: 60%;\\n            height: 60%;\\n            display: inline-block;\\n            position: absolute;\\n            top: 0;\\n            background-color: rgb(229, 71, 97);\\n            border-radius: 100%;\\n            -webkit-animation: bounce 2.0s infinite ease-in-out;\\n            animation: bounce 2.0s infinite ease-in-out;\\n        }\\n\\n        .spinner-dot1 {\\n            top: auto;\\n            bottom: 0px;\\n            -webkit-animation-delay: -1.0s;\\n            animation-delay: -1.0s;\\n        }\\n\\n        @-webkit-keyframes rotate { 100% { -webkit-transform: rotate(360deg) }}\\n        @keyframes rotate { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg) }}\\n\\n        @-webkit-keyframes bounce {\\n            0%, 100% { -webkit-transform: scale(0.0) }\\n            50% { -webkit-transform: scale(1.0) }\\n        }\\n\\n        @keyframes bounce {\\n            0%, 100% {\\n                transform: scale(0.0);\\n                -webkit-transform: scale(0.0);\\n            } 50% {\\n                  transform: scale(1.0);\\n                  -webkit-transform: scale(1.0);\\n              }\\n        }\\n    </style>\\n    <div class=\"spinner\">\\n        <div class=\"spinner-dot1\"></div>\\n        <div class=\"spinner-dot2\"></div>\\n    </div>\\n</div>';\n\n/**\n * @type {GShell}\n */\nvar gShell = null;\n\n/**\n * @type {GApplication}\n */\nvar gApp = null;\n\nvar __loader = null;\n\n// Those functions need to be called from within the shell\nfunction gShellReady() {\n    gApp = new GApplication();\n}\n\nfunction gShellFinished() {\n    gApp.init();\n    gShell.prepare();\n    gApp.relayout();\n\n    // Run shell start with a slight delay\n    setTimeout(function () {\n        gShell.start();\n        __loader.remove();\n    }, 2500);\n}\n\n// Bootstrapping when the DOM is ready\n$(document).ready(function () {\n    if (!gShell) {\n        throw new Error(\"Shell needs to be initialized, first.\");\n    }\n\n    // Add Gravit Loader\n    __loader = $(gLoaderCode)\n        .appendTo($('body'));\n\n    //\n    // -- FONTS --\n    //\n\n    //\n    // TODO : Remove / handle default fonts somewhere else!?\n    //\n\n    // Open Sans\n    ifFont.addType('Open Sans', IFFont.Style.Normal, IFFont.Weight.Light, 'font/OpenSans-Light.ttf', IFFont.Category.Serif);\n    ifFont.addType('Open Sans', IFFont.Style.Italic, IFFont.Weight.Light, 'font/OpenSans-LightItalic.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Normal, IFFont.Weight.Regular, 'font/OpenSans-Regular.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Italic, IFFont.Weight.Regular, 'font/OpenSans-Italic.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Normal, IFFont.Weight.SemiBold, 'font/OpenSans-Semibold.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Italic, IFFont.Weight.SemiBold, 'font/OpenSans-SemiboldItalic.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Normal, IFFont.Weight.Bold, 'font/OpenSans-Bold.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Italic, IFFont.Weight.Bold, 'font/OpenSans-BoldItalic.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Normal, IFFont.Weight.ExtraBold, 'font/OpenSans-ExtraBold.ttf');\n    ifFont.addType('Open Sans', IFFont.Style.Italic, IFFont.Weight.ExtraBold, 'font/OpenSans-ExtraBoldItalic.ttf');\n\n    // Source Sans Pro\n    ifFont.addType('Source Sans Pro', IFFont.Style.Normal, IFFont.Weight.ExtraLight, 'font/SourceSansPro-ExtraLight.ttf', IFFont.Category.Serif);\n    ifFont.addType('Source Sans Pro', IFFont.Style.Italic, IFFont.Weight.ExtraLight, 'font/SourceSansPro-ExtraLightIt.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Normal, IFFont.Weight.Light, 'font/SourceSansPro-Light.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Italic, IFFont.Weight.Light, 'font/SourceSansPro-LightIt.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Normal, IFFont.Weight.Regular, 'font/SourceSansPro-Regular.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Italic, IFFont.Weight.Regular, 'font/SourceSansPro-It.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Normal, IFFont.Weight.SemiBold, 'font/SourceSansPro-Semibold.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Italic, IFFont.Weight.SemiBold, 'font/SourceSansPro-SemiboldIt.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Normal, IFFont.Weight.Bold, 'font/SourceSansPro-Bold.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Italic, IFFont.Weight.Bold, 'font/SourceSansPro-BoldIt.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Normal, IFFont.Weight.Heavy, 'font/SourceSansPro-Black.ttf');\n    ifFont.addType('Source Sans Pro', IFFont.Style.Italic, IFFont.Weight.Heavy, 'font/SourceSansPro-BlackIt.ttf');\n\n\n    // Source Code Pro\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.ExtraLight, 'font/SourceCodePro-ExtraLight.ttf', IFFont.Category.Monospace);\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.Light, 'font/SourceCodePro-Light.ttf');\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.Regular, 'font/SourceCodePro-Regular.ttf');\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.Medium, 'font/SourceCodePro-Medium.ttf');\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.SemiBold, 'font/SourceCodePro-Semibold.ttf');\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.Bold, 'font/SourceCodePro-Bold.ttf');\n    ifFont.addType('Source Code Pro', IFFont.Style.Normal, IFFont.Weight.Heavy, 'font/SourceCodePro-Black.ttf');\n\n    // FontAwesome\n    ifFont.addType('FontAwesome', IFFont.Style.Normal, IFFont.Weight.Regular, gShell.isDevelopment() ? '../bower_components/font-awesome/fonts/FontAwesome-webfont.ttf' : 'font/FontAwesome-webfont.ttf', IFFont.Category.Iconic);\n});\n\n$(window).load(function () {\n    rangy.init();\n});"
  },
  {
    "path": "src/application/component/autoedit.js",
    "content": "(function ($) {\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // Selector for the content, if not provided\n                // takes this element as content\n                selector: null\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n                $(this)\n                    .data('gautoedit', {\n                        options: options,\n                        input: null\n                    })\n                    .on('dblclick', function (evt) {\n                        methods.open.call(self);\n                    });\n            });\n        },\n\n        // Open the editor\n        open: function () {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('gautoedit');\n\n            if (data.input) {\n                methods.close.call(this);\n            }\n\n            var container = $this.find(data.options.selector);\n\n            if (container.length === 0) {\n                if (data.options.selector) {\n                    return;\n                }\n\n                container = $this;\n            }\n\n            var offset = container.offset();\n\n            data.value = container.text();\n\n            data.input = $('<input>')\n                .css({\n                    'position': 'absolute',\n                    'left': offset.left + 'px',\n                    'top': offset.top + 'px',\n                    'width': container.outerWidth() + 'px',\n                    'height': container.outerHeight() + 'px'\n                })\n                .val(data.value)\n                .on('blur', function (evt) {\n                    methods.submit.call(self);\n                })\n                .on('keyup', function (evt) {\n                    if (evt.keyCode === 13) {\n                        methods.submit.call(self);\n                    } else if (evt.keyCode === 27) {\n                        methods.close.call(self);\n                    }\n                })\n                .appendTo($('body'))\n                .focus()\n                .select();\n        },\n\n        // Submit editor contents and close it\n        submit: function () {\n            var $this = $(this);\n            var data = $this.data('gautoedit');\n\n            // save input value\n            var inputVal = data.input ? data.input.val() : null;\n\n            // close first\n            methods.close.call(this);\n\n            if (inputVal) {\n                if (data.value !== inputVal) {\n                    $this.trigger('submitvalue', inputVal);\n                }\n            }\n        },\n\n        // Close the editor\n        close: function () {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('gautoedit');\n\n            if (data.input) {\n                data.input.remove();\n                data.input = null;\n                data.value = null;\n            }\n        },\n    };\n\n    /**\n     * Adds the capability to edit some text\n     */\n    $.fn.gAutoEdit = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/blendmode.js",
    "content": "(function ($) {\n\n    var blendModes = [\n        {\n            type: IFPaintCanvas.BlendMode.Normal,\n            // TODO : I18N\n            name: 'Normal'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Multiply,\n            // TODO : I18N\n            name: 'Multiply'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Screen,\n            // TODO : I18N\n            name: 'Screen'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Overlay,\n            // TODO : I18N\n            name: 'Overlay'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Darken,\n            // TODO : I18N\n            name: 'Darken'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Lighten,\n            // TODO : I18N\n            name: 'Lighten'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.ColorDodge,\n            // TODO : I18N\n            name: 'Color Dodge'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.ColorBurn,\n            // TODO : I18N\n            name: 'Color Burn'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.HardLight,\n            // TODO : I18N\n            name: 'Hard Light'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.SoftLight,\n            // TODO : I18N\n            name: 'Soft Light'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Difference,\n            // TODO : I18N\n            name: 'Difference'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Exclusion,\n            // TODO : I18N\n            name: 'Exclusion'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Hue,\n            // TODO : I18N\n            name: 'Hue'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Saturation,\n            // TODO : I18N\n            name: 'Saturation'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Color,\n            // TODO : I18N\n            name: 'Color'\n        },\n        {\n            type: IFPaintCanvas.BlendMode.Luminosity,\n            // TODO : I18N\n            name: 'Luminosity'\n        }\n    ];\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n            }, options);\n\n            return this.each(function () {\n                var $this = $(this);\n                if ($this.is(\"select\")) {\n                    // If the last item is an optgroup, use that as a target\n                    var target = $this;\n                    var lastElement = $this.find(':last');\n                    if (lastElement.is('optgroup')) {\n                        target = lastElement;\n                    }\n\n                    // Append corner types\n                    for (var i = 0; i < blendModes.length; ++i) {\n                        target.append($('<option></option>')\n                            .attr('value', blendModes[i].type)\n                            .text(blendModes[i].name));\n                    }\n                }\n            });\n        }\n    };\n\n    /**\n     * Adds a translated list of options to a selection that\n     * represents the IFPaintCanvas.BlendMode choices\n     * TODO : Replace select with visual selector with icons\n     */\n    $.fn.gBlendMode = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/colorbutton.js",
    "content": "(function ($) {\n\n    var COLORPANEL = null;\n\n    function getColorPanel() {\n        if (!COLORPANEL) {\n            COLORPANEL = $('<div></div>')\n                .css('padding', '5px')\n                .gColorPanel()\n                .gOverlay();\n        }\n        return COLORPANEL;\n    }\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // Whether to behave as button or not, which, in the latter case,\n                // means that the target element will only react on clicking but\n                // not behave like a button with icon and background color\n                transient: false,\n                // Whether to automatically open the color chooser on click\n                // or wait for a manual call to the open function\n                autoOpen: true,\n                // Whether to allow clearing the color or not\n                allowClear: false,\n                // Whether to immediately close after color has changed or not\n                immediateClose: false,\n                // Scene to be used for swatches\n                scene: null\n                // see options of gPatternTarget\n            }, options);\n\n            // always overwrite types to allow colors, only\n            options.types = [IFPattern.Type.Color];\n\n            return this.each(function () {\n                var self = this;\n                var $this = $(this);\n\n                $this\n                    .addClass('g-input')\n                    .css('min-width', '20px')\n                    .data('g-colorbutton', {\n                        options: options,\n                        scene: options.scene,\n                        panelCloseListener: function (evt) {\n                            var data = $this.data('g-colorbutton');\n                            var colorPanel = getColorPanel();\n                            colorPanel.gColorPanel('scene', null);\n                            colorPanel.off('colorchange', data.panelChangeListener);\n                            colorPanel.off('close', data.panelCloseListener);\n                        },\n                        panelChangeListener: function (evt, color) {\n                            if (options.immediateClose) {\n                                methods.close.call(self);\n                            }\n\n                            methods.value.call(self, color);\n                            $this.trigger('colorchange', color);\n                        }\n                    })\n                    .gPatternTarget(options)\n                    .on('patternchange', function (evt, color) {\n                        methods.value.call(self, color);\n                    });\n\n                if (!options.transient) {\n                    $this\n                        .addClass('g-cursor-pipette');\n                }\n\n                if (options.autoOpen) {\n                    $this\n                        .on('click', function () {\n                            methods.open.call(self);\n                        })\n                }\n            });\n        },\n\n        open: function () {\n            var $this = $(this);\n            var data = $this.data('g-colorbutton');\n            var colorPanel = getColorPanel();\n            colorPanel.gOverlay('close', this);\n            colorPanel.gColorPanel('scene', data.scene);\n            colorPanel.gColorPanel('value', methods.value.call(this));\n            colorPanel.gColorPanel('allowClear', data.options.allowClear);\n            colorPanel.on('colorchange', data.panelChangeListener);\n            colorPanel.on('close', data.panelCloseListener);\n            colorPanel.gOverlay('open', this);\n            return this;\n        },\n\n        close: function () {\n            var colorPanel = getColorPanel();\n            colorPanel.gOverlay('close', this);\n            return this;\n        },\n\n        scene: function (value) {\n            var $this = $(this);\n            var data = $this.data('g-colorbutton');\n\n            if (!arguments.length) {\n                return data.scene;\n            } else {\n                data.scene = value;\n                return this;\n            }\n        },\n\n        value: function (value) {\n            var $this = $(this);\n            var data = $this.data('g-colorbutton');\n\n            if (!arguments.length) {\n                return $this.gPatternTarget('value');\n            } else {\n                $this.gPatternTarget('value', value);\n\n                if (!data.options.transient) {\n                    $this.css('background', IFPattern.asCSSBackground(value));\n                }\n\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Block to transform buttons to color buttons\n     */\n    $.fn.gColorButton = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/colorpanel.js",
    "content": "(function ($) {\n    /** @enum */\n    var ViewType = {\n        Palette: 'palette',\n        Swatches: 'swatches',\n        Trends: 'trends',\n        Image: 'image'\n    };\n\n    /**\n     * @private\n     */\n    ColorModes = [\n        {\n            type: IFColor.Type.RGB,\n            name: 'RGB',\n            components: [\n                {\n                    label: 'R',\n                    min: 0,\n                    max: 255,\n                    unit: ' ',\n                    stops: function (components) {\n                        var rgba = components;\n                        return [\n                            new IFColor(IFColor.Type.RGB, [0, rgba[1], rgba[2], 100]),\n                            new IFColor(IFColor.Type.RGB, [255, rgba[1], rgba[2], 100]),\n                        ];\n                    }\n                },\n                {\n                    label: 'G',\n                    min: 0,\n                    max: 255,\n                    unit: ' ',\n                    stops: function (components) {\n                        var rgba = components;\n                        return [\n                            new IFColor(IFColor.Type.RGB, [rgba[0], 0, rgba[2], 100]),\n                            new IFColor(IFColor.Type.RGB, [rgba[0], 255, rgba[2], 100]),\n                        ];\n                    }\n                },\n                {\n                    label: 'B',\n                    min: 0,\n                    max: 255,\n                    unit: ' ',\n                    stops: function (components) {\n                        var rgba = components;\n                        return [\n                            new IFColor(IFColor.Type.RGB, [rgba[0], rgba[1], 0, 100]),\n                            new IFColor(IFColor.Type.RGB, [rgba[0], rgba[1], 255, 100]),\n                        ];\n                    }\n                },\n                {\n                    label: 'A',\n                    min: 0,\n                    max: 100,\n                    unit: '%'\n                }\n            ],\n            makeColor: function (components) {\n                return new IFColor(IFColor.Type.RGB, components);\n            }\n        },\n        {\n            type: IFColor.Type.HSL,\n            name: 'HSL',\n            components: [\n                {\n                    label: 'H',\n                    min: 0,\n                    max: 360,\n                    unit: '° ',\n                    stops: function (components) {\n                        var hsla = components;\n                        var result = [];\n                        var steps = 60;\n                        for (var i = 0; i <= 360; i += steps) {\n                            result.push(new IFColor(IFColor.Type.HSL, [i, hsla[1], hsla[2], 100]));\n                        }\n                        return result;\n                    }\n                },\n                {\n                    label: 'S',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        var hsla = components;\n                        return [\n                            new IFColor(IFColor.Type.HSL, [hsla[0], 0, hsla[2], 100]),\n                            new IFColor(IFColor.Type.HSL, [hsla[0], 100, hsla[2], 100]),\n                        ];\n                    }\n                },\n                {\n                    label: 'L',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        var hsla = components;\n                        return [\n                            new IFColor(IFColor.Type.HSL, [hsla[0], hsla[1], 0, 100]),\n                            new IFColor(IFColor.Type.HSL, [hsla[0], hsla[1], 100, 100]),\n                        ];\n                    }\n                },\n                {\n                    label: 'A',\n                    min: 0,\n                    max: 100,\n                    unit: '%'\n                }\n            ],\n            makeColor: function (components) {\n                return new IFColor(IFColor.Type.HSL, components);\n            }\n        },\n        {\n            type: IFColor.Type.Tone,\n            name: 'Tone',\n            components: [\n                {\n                    label: 'T',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        return [IFColor.parseCSSColor('white'), IFColor.parseCSSColor('black')];\n                    }\n                },\n                {\n                    label: 'A',\n                    min: 0,\n                    max: 100,\n                    unit: '%'\n                }\n            ],\n            makeColor: function (components) {\n                return new IFColor(IFColor.Type.Tone, components);\n            }\n        },\n\n        {\n            type: IFColor.Type.CMYK,\n            name: 'CMYK',\n            components: [\n                {\n                    label: 'C',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        var cmyk = components;\n                        return [\n                            new IFColor(IFColor.Type.CMYK, [0, cmyk[1], cmyk[2], cmyk[3]]),\n                            new IFColor(IFColor.Type.CMYK, [100, cmyk[1], cmyk[2], cmyk[3]]),\n                        ];\n                    }\n                },\n                {\n                    label: 'M',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        var cmyk = components;\n                        return [\n                            new IFColor(IFColor.Type.CMYK, [cmyk[0], 0, cmyk[2], cmyk[3]]),\n                            new IFColor(IFColor.Type.CMYK, [cmyk[0], 100, cmyk[2], cmyk[3]]),\n                        ];\n                    }\n                },\n                {\n                    label: 'Y',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        var cmyk = components;\n                        return [\n                            new IFColor(IFColor.Type.CMYK, [cmyk[0], cmyk[1], 0, cmyk[3]]),\n                            new IFColor(IFColor.Type.CMYK, [cmyk[0], cmyk[1], 100, cmyk[3]]),\n                        ];\n                    }\n                },\n                {\n                    label: 'K',\n                    min: 0,\n                    max: 100,\n                    unit: '%',\n                    stops: function (components) {\n                        var cmyk = components;\n                        return [\n                            new IFColor(IFColor.Type.CMYK, [cmyk[0], cmyk[1], cmyk[2], 0]),\n                            new IFColor(IFColor.Type.CMYK, [cmyk[0], cmyk[1], cmyk[2], 100]),\n                        ];\n                    }\n                }\n            ],\n            makeColor: function (components) {\n                return new IFColor(IFColor.Type.CMYK, components);\n            }\n        }\n    ];\n\n    var MAX_SWATCHES_PER_ROW = 21;\n\n    // 21 per row\n    var PALETTE = [\n        '000000', '001F3F', 'DDDDDD', '000000', '003300', '006600', '009900', '00CC00', '00FF00', '330000', '333300', '336600', '339900', '33CC00', '33FF00', '660000', '663300', '666600', '669900', '66CC00', '66FF00',\n        '333333', '0074D9', 'CCCCCC', '000033', '003333', '006633', '009933', '00CC33', '00FF33', '330033', '333333', '336633', '339933', '33CC33', '33FF33', '660033', '663333', '666633', '669933', '66CC33', '66FF33',\n        '666666', '7FDBFF', 'BBBBBB', '000066', '003366', '006666', '009966', '00CC66', '00FF66', '330066', '333366', '336666', '339966', '33CC66', '33FF66', '660066', '663366', '666666', '669966', '66CC66', '66FF66',\n        '999999', '39CCCC', 'AAAAAA', '000099', '003399', '006699', '009999', '00CC99', '00FF99', '330099', '333399', '336699', '339999', '33CC99', '33FF99', '660099', '663399', '666699', '669999', '66CC99', '66FF99',\n        'CCCCCC', '3D9970', '999999', '0000CC', '0033CC', '0066CC', '0099CC', '00CCCC', '00FFCC', '3300CC', '3333CC', '3366CC', '3399CC', '33CCCC', '33FFCC', '6600CC', '6633CC', '6666CC', '6699CC', '66CCCC', '66FFCC',\n        'FFFFFF', '2ECC40', '888888', '0000FF', '0033FF', '0066FF', '0099FF', '00CCFF', '00FFFF', '3300FF', '3333FF', '3366FF', '3399FF', '33CCFF', '33FFFF', '6600FF', '6633FF', '6666FF', '6699FF', '66CCFF', '66FFFF',\n        'FF0000', '01FF70', '777777', '990000', '993300', '996600', '999900', '99CC00', '99FF00', 'CC0000', 'CC3300', 'CC6600', 'CC9900', 'CCCC00', 'CCFF00', 'FF0000', 'FF3300', 'FF6600', 'FF9900', 'FFCC00', 'FFFF00',\n        '00FF00', 'FFDC00', '666666', '990033', '993333', '996633', '999933', '99CC33', '99FF33', 'CC0033', 'CC3333', 'CC6633', 'CC9933', 'CCCC33', 'CCFF33', 'FF0033', 'FF3333', 'FF6633', 'FF9933', 'FFCC33', 'FFFF33',\n        '0000FF', 'FF851B', '555555', '990066', '993366', '996666', '999966', '99CC66', '99FF66', 'CC0066', 'CC3366', 'CC6666', 'CC9966', 'CCCC66', 'CCFF66', 'FF0066', 'FF3366', 'FF6666', 'FF9966', 'FFCC66', 'FFFF66',\n        'FFFF00', 'FF4136', '444444', '990099', '993399', '996699', '999999', '99CC99', '99FF99', 'CC0099', 'CC3399', 'CC6699', 'CC9999', 'CCCC99', 'CCFF99', 'FF0099', 'FF3399', 'FF6699', 'FF9999', 'FFCC99', 'FFFF99',\n        '00FFFF', '85144B', '333333', '9900CC', '9933CC', '9966CC', '9999CC', '99CCCC', '99FFCC', 'CC00CC', 'CC33CC', 'CC66CC', 'CC99CC', 'CCCCCC', 'CCFFCC', 'FF00CC', 'FF33CC', 'FF66CC', 'FF99CC', 'FFCCCC', 'FFFFCC',\n        'FF00FF', 'B10DC9', '222222', '9900FF', '9933FF', '9966FF', '9999FF', '99CCFF', '99FFFF', 'CC00FF', 'CC33FF', 'CC66FF', 'CC99FF', 'CCCCFF', 'CCFFFF', 'FF00FF', 'FF33FF', 'FF66FF', 'FF99FF', 'FFCCFF', 'FFFFFF'];\n\n    function createPaletteView($this) {\n        var view = $('<table></table>');\n\n        var parent = $('<tr></tr>').appendTo(view);\n\n        var col = 0;\n        for (var i = 0; i < PALETTE.length; ++i) {\n            var color = '#' + PALETTE[i];\n\n            $('<td></td>')\n                .addClass('swatch')\n                .css('background', color)\n                .attr('data-color', color)\n                .on('click', function () {\n                    var color = IFColor.parseCSSColor($(this).attr('data-color'));\n                    assignValue($this, color, false);\n                    $this.trigger('colorchange', color);\n                })\n                .appendTo(parent);\n\n            if (++col === MAX_SWATCHES_PER_ROW) {\n                col = 0;\n                parent = $('<tr></tr>').appendTo(view);\n            }\n        }\n\n        return view;\n    };\n\n    function createSwatchesView($this) {\n        var data = $this.data('gcolorpanel');\n\n        return $('<div></div>')\n            .gSwatchPanel({\n                nullSwatch: $('<span></span>')\n                    .addClass('fa fa-plus-circle'),\n                // TODO : I18N\n                nullName: 'Add current color as new swatch',\n                types: [IFPattern.Type.Color],\n                allowSelect: false\n            })\n            .on('swatchchange', function (evt, swatch) {\n                if (!swatch) {\n                    if (!data.scene || !data.color) {\n                        return; // leave here, no color or scene\n                    }\n\n                    // Make sure there's no such color, yet\n                    var swatches = data.scene.getSwatchCollection();\n                    for (var node = swatches.getFirstChild(); node !== null; node = node.getNext()) {\n                        if (node instanceof IFSwatch && node.getPatternType() === IFPattern.Type.Color) {\n                            if (IFColor.equals(data.color, node.getProperty('pat'))) {\n                                return; // leave here, colors are equal\n                            }\n                        }\n                    }\n\n                    // Ask for a name\n                    var name = prompt('Enter a name for the new swatch:', data.color.asString());\n                    if (name === null) {\n                        return; // leave here, user has canceled\n                    }\n                    if (name.trim() === '') {\n                        name = data.color.asString();\n                    }\n\n                    // Add current color as swatch\n                    var editor = IFEditor.getEditor(data.scene);\n\n                    if (editor) {\n                        editor.beginTransaction();\n                    }\n\n                    try {\n                        var swatch = new IFSwatch();\n                        swatch.setProperties(['name', 'pat'], [name, data.color]);\n                        swatches.appendChild(swatch);\n                    } finally {\n                        if (editor) {\n                            editor.commitTransaction('Add Swatch');\n                        }\n                    }\n                } else {\n                    var color = swatch.getProperty('pat');\n                    assignValue($this, color, false);\n                    $this.trigger('colorchange', color);\n                }\n            });\n    }\n\n    function createTrendsView($this) {\n        var _addTrend = function (index, view) {\n            var label = null;\n            switch (index) {\n                // Tint\n                case 1:\n                    // TODO : I18N\n                    label = 'Tint';\n                    break;\n                // Shade\n                case 2:\n                    label = 'Shade';\n                    break;\n                // Tone\n                case 3:\n                    label = 'Tone';\n                    break;\n            }\n\n\n            $('<div></div>')\n                .addClass('color-trend-label')\n                .text(label)\n                .appendTo(view);\n\n            var container = $('<div></div>')\n                .addClass('color-trend color-trend-' + index.toString())\n                .append($('<div></div>')\n                    .addClass('color-palette')\n                    .append($('<div></div>')\n                        .addClass('color-preview')))\n                .append($('<div></div>')\n                    .addClass('color-trend-value')\n                    .append($('<input>')\n                        .attr('type', 'text')\n                        .on('input', function (evt) {\n                            var val = $(this).val();\n                            var color = updateTrendValue($this, index, val);\n                        })))\n                .appendTo(view);\n\n            var preview = container.find('.color-preview');\n            for (var i = 1; i <= 10; ++i) {\n                $('<div>&nbsp;</div>')\n                    .addClass('g-input color-trend-box-' + (i === 10 ? 'current' : i.toString()))\n                    .css('width', '10%')\n                    .on('click', function (evt) {\n                        var color = IFColor.parseColor($(this).attr('data-color'));\n                        if (color) {\n                            assignValue($this, color, false);\n                            $this.trigger('colorchange', color);\n                        }\n                    })\n                    .appendTo(preview);\n            }\n        }.bind(this);\n\n        var view = $('<div></div>');\n\n        _addTrend(1, view);\n        _addTrend(2, view);\n        _addTrend(3, view);\n\n        return view;\n    }\n\n    function colorForTrendAndValue($this, trend, value) {\n        var sourceColor = $this.data('gcolorpanel').color;\n        if (!sourceColor) {\n            return null;\n        }\n\n        // Calculate a new color\n        switch (trend) {\n            // Tint\n            case 1:\n                return sourceColor.withTint(value);\n\n            // Shade\n            case 2:\n                return sourceColor.withShade(value);\n\n            // Tone\n            case 3:\n                return sourceColor.withTone(value);\n\n            default:\n                throw new Error('Unknown trend: ' + trend);\n        }\n    };\n\n    function updateTrendValue($this, trend, value) {\n        if (typeof value === 'string') {\n            value = parseInt(value);\n            if (isNaN(value)) {\n                value = 50;\n            }\n        }\n        if (value < 0) {\n            value = 0;\n        } else if (value > 100) {\n            value = 100;\n        }\n\n\n        var trendsView = $this.find('[data-view=\"trends\"]');\n        var container = trendsView.find('.color-trend-' + trend.toString());\n\n        var newColor = colorForTrendAndValue($this, trend, value);\n\n        container.find('.color-trend-box-current')\n            .attr('data-color', newColor ? newColor.asString() : '')\n            .css('background', IFPattern.asCSSBackground(newColor));\n\n        container.find('.color-trend-value > input')\n            .val(value);\n\n        return newColor;\n    }\n\n    function updateTrends($this) {\n        var trendsView = $this.find('[data-view=\"trends\"]');\n\n        for (var i = 1; i <= 3; ++i) {\n            var container = trendsView.find('.color-trend-' + i.toString());\n            for (var k = 1; k <= 9; ++k) {\n                var newColor = colorForTrendAndValue($this, i, k * 10);\n\n                // Assign to color box\n                container\n                    .find('.color-trend-box-' + k.toString())\n                    .attr('data-color', newColor ? newColor.asString() : '')\n                    .css('background', IFPattern.asCSSBackground(newColor));\n\n                // If this is 50% then assign to current trend box\n                // and update it's text input\n                if (k === 5) {\n                    updateTrendValue($this, i, 50);\n                }\n            }\n        }\n    }\n\n    function cvColorThiefColor(color) {\n        return new IFColor(IFColor.Type.RGB, [color[0], color[1], color[2], 100]);\n    }\n\n    function createImageView($this) {\n        return $('<div></div>')\n            .append($('<div></div>')\n                .addClass('image-panel')\n                .text('Drag an image here')\n                .on('dragenter', function () {\n                    $(this).css('background', 'maroon');\n                    return false;\n                })\n                .on('dragleave', function () {\n                    $(this).css('background', '');\n                    return false;\n                })\n                .on('dragover', function () {\n                    return false;\n                })\n                .on('drop', function (event) {\n                    var imagePanel = $(this);\n                    imagePanel.css('background', '');\n\n                    var palettePanel = imagePanel.closest('[data-view]').find('.image-palette');\n                    palettePanel.empty();\n\n                    var _addPaletteColor = function (color) {\n                        $('<div></div>')\n                            .css('background', IFPattern.asCSSBackground(color))\n                            .on('click', function () {\n                                assignValue($this, color, false);\n                                $this.trigger('colorchange', color);\n                            }.bind(this))\n                            .appendTo(palettePanel);\n                    }.bind(this);\n\n                    var files = event.originalEvent.dataTransfer.files;\n                    var fileCount = files.length;\n                    var imageType = /image.*/;\n\n                    for (var i = 0; i < fileCount; i++) {\n                        var file = files[i];\n\n                        if (file.type.match(imageType)) {\n                            var reader = new FileReader();\n                            reader.onload = function (event) {\n                                var image = new Image();\n                                image.src = event.target.result;\n                                image.onload = function () {\n                                    var colorThief = new ColorThief();\n                                    var mainColor = cvColorThiefColor(colorThief.getColor(image));\n                                    _addPaletteColor(mainColor);\n\n                                    var palette = colorThief.getPalette(image, 8);\n                                    for (var i = 0; i < palette.length; ++i) {\n                                        var convertedColor = cvColorThiefColor(palette[i]);\n\n                                        // Take care to avoid duplications with dominant color\n                                        if (!IFColor.equals(convertedColor, mainColor)) {\n                                            _addPaletteColor(convertedColor);\n                                        }\n                                    }\n                                }.bind(this);\n\n                                imagePanel\n                                    .css('background-image', 'url(' + event.target.result + ')')\n                                    .text('');\n                            }.bind(this);\n                            reader.readAsDataURL(file);\n                            break;\n                        }\n                    }\n\n                    return false;\n                }))\n            .append($('<div></div>')\n                .addClass('image-palette'));\n    }\n\n    function createView($this, viewType) {\n        var view = null;\n\n        if (viewType === ViewType.Palette) {\n            view = createPaletteView($this);\n        } else if (viewType === ViewType.Swatches) {\n            view = createSwatchesView($this);\n        } else if (viewType === ViewType.Trends) {\n            view = createTrendsView($this);\n        } else if (viewType === ViewType.Image) {\n            view = createImageView($this);\n        } else {\n            throw new Error('Unknown color view: ' + viewType);\n        }\n\n        if (view) {\n            view\n                .attr('data-view', viewType)\n                .css('display', 'none')\n                .appendTo($this.find('.color-view'));\n        }\n    }\n\n    function updateMatches($this) {\n        var data = $this.data('gcolorpanel');\n        var palettePanel = $this.find('.matcher-palette');\n        palettePanel.empty();\n\n        if (data.matcher && data.color) {\n            var _addMatchColor = function (color, width) {\n                $('<div></div>')\n                    .css('width', width.toString() + '%')\n                    .css('background', IFPattern.asCSSBackground(color))\n                    .on('click', function () {\n                        assignValue($this, color, false);\n                        $this.trigger('colorchange', color);\n                    }.bind(this))\n                    .appendTo(palettePanel);\n            }.bind(this);\n\n            var matches = data.matcher.match(data.color);\n            if (matches && matches.length > 0) {\n                var len = Math.min(matches.length, 8);\n                var width = 100 / len;\n                for (var i = 0; i < len; ++i) {\n                    // Convert match color to same type as curent color if any\n                    var match = data.color ? matches[i].toType(data.color.getType()) : matches[i];\n                    _addMatchColor(match, width);\n                }\n            }\n        }\n    };\n\n    function activateMatcher($this, matcher) {\n        var data = $this.data('gcolorpanel');\n        data.matcher = matcher;\n\n        updateMatches($this);\n    };\n\n    function activateColorMode($this, colorMode) {\n        var data = $this.data('gcolorpanel');\n\n        if (!data.colorMode || colorMode !== data.colorMode.type.key) {\n            for (var i = 0; i < ColorModes.length; ++i) {\n                var modeInfo = ColorModes[i];\n                if (modeInfo.type.key === colorMode) {\n                    data.colorMode = modeInfo;\n\n                    // Activate sliders\n                    for (var i = 0; i < 4; ++i) {\n                        var componentPanel = $this.find('.color-component-' + i.toString());\n\n                        if (i >= modeInfo.components.length) {\n                            componentPanel.css('visibility', 'hidden');\n                        } else {\n                            componentPanel.css('visibility', '');\n\n                            var component = modeInfo.components[i];\n                            var range = componentPanel.find('input[type=\"range\"]');\n                            var label = componentPanel.find('.color-label');\n                            var unit = componentPanel.find('.color-unit');\n\n                            label.text(component.label);\n                            unit.text(component.unit);\n                            unit.css('display', component.unit != '' ? '' : 'none');\n\n                            range.attr('min', component.min);\n                            range.attr('max', component.max);\n                        }\n                    }\n\n                    updateToComponents($this);\n                    updateFromComponents($this);\n\n                    break;\n                }\n            }\n        }\n        $this.find('.color-mode-select').val(data.colorMode ? data.colorMode.type.key : IFColor.Type.RGB.key);\n    }\n\n    function updateFromComponents($this) {\n        var data = $this.data('gcolorpanel');\n\n        // Collect component values / correct them for current mode\n        var components = [];\n        for (var i = 0; i < data.colorMode.components.length; ++i) {\n            var component = data.colorMode.components[i];\n            var componentEl = $this.find('.color-component-' + i.toString());\n            var textInput = componentEl.find('input[type=\"text\"]');\n            var rangeInput = componentEl.find('input[type=\"range\"]');\n            var value = parseInt(textInput.val());\n\n            if (isNaN(value) || value < component.min) {\n                value = component.min;\n            } else if (value > component.max) {\n                value = component.max;\n            }\n\n            // Push value\n            components.push(value);\n\n            // Update inputs with correct value\n            textInput.val(value);\n            rangeInput.val(value);\n        }\n\n        var color = data.colorMode.makeColor(components);\n        assignValue($this, color);\n        return color;\n    }\n\n    function updateToComponents($this) {\n        var data = $this.data('gcolorpanel');\n\n        var color = data.color ? data.color : IFColor.TRANSPARENT_WHITE;\n\n        // Get the components in the right format\n        var components = null;\n        if (data.colorMode.type === IFColor.Type.RGB) {\n            components = color.asRGB();\n        } else if (data.colorMode.type === IFColor.Type.HSL) {\n            components = color.asHSL();\n        } else if (data.colorMode.type === IFColor.Type.Tone) {\n            components = color.asTone();\n        } else if (data.colorMode.type === IFColor.Type.CMYK) {\n            components = color.asCMYK();\n        } else {\n            throw new Error('Unknown mode.');\n        }\n\n        if (components) {\n            for (var i = 0; i < data.colorMode.components.length; ++i) {\n                var component = data.colorMode.components[i];\n                var componentEl = $this.find('.color-component-' + i.toString());\n                var textInput = componentEl.find('input[type=\"text\"]');\n                var rangeInput = componentEl.find('input[type=\"range\"]');\n                var val = Math.min(component.max, Math.max(component.min, components[i])).toFixed(0);\n\n                var stopsFunc = data.colorMode.components[i].stops;\n                var stops = stopsFunc ? stopsFunc(components) : null;\n\n                if (stops) {\n                    if (stops.length === 1) {\n                        rangeInput.css('background', stops[0].asCSSString());\n                    } else {\n                        var cssStops = '';\n                        for (var s = 0; s < stops.length; ++s) {\n                            if (cssStops !== '') {\n                                cssStops += ',';\n                            }\n                            cssStops += stops[s].asCSSString();\n                        }\n                        rangeInput.css('background', 'linear-gradient(90deg, ' + cssStops + ')');\n                    }\n                } else {\n                    rangeInput.css('background', '');\n                }\n\n                textInput.val(val);\n                rangeInput.val(val);\n            }\n        }\n    }\n\n    function assignValue($this, value, overwritePrevious) {\n        var data = $this.data('gcolorpanel');\n\n        value = typeof value === 'string' ? IFColor.parseColor(value) : value;\n\n        data.color = value;\n\n        if (overwritePrevious) {\n            data.previousColor = value;\n        }\n\n        $this.find('input[type=\"color\"]').val(value ? value.asHTMLHexString() : '');\n        $this.find('.previous-color').css('background', IFPattern.asCSSBackground(data.previousColor));\n        $this.find('.current-color').css('background', IFPattern.asCSSBackground(data.color));\n        $this.find('.color-input').val(data.color ? data.color.asHTMLHexString() : '');\n\n        // Show color difference\n        var colorDiff = '&ndash;';\n        if (data.previousColor && data.color) {\n            var diff = data.color.difference(data.previousColor);\n            colorDiff = '&Delta;&nbsp;' + (diff < 0 ? ifUtil.formatNumber(diff, 2) : diff.toFixed(0));\n        }\n        $this.find('.color-difference').html(colorDiff);\n\n\n        activateColorMode($this, value ? value.getType().key : IFColor.Type.RGB.key);\n        updateMatches($this);\n        updateToComponents($this);\n        updateTrends($this);\n    }\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // The default view\n                defaultView: ViewType.Palette\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n\n                var data = {\n                    options: options,\n                    allowClear: false,\n                    scene: null\n                };\n\n                var $this = $(this)\n                    .data('gcolorpanel', data);\n\n                $this\n                    .addClass('g-color-panel')\n                    .append($('<input>')\n                        .attr('type', 'color')\n                        .css({\n                            'position': 'absolute',\n                            'visibility': 'hidden'\n                        })\n                        .on('change', function () {\n                            var color = IFColor.parseCSSColor($(this).val());\n                            assignValue($this, color, false);\n                            $this.trigger('colorchange', color);\n                        }))\n                    .append($('<div></div>')\n                        .addClass('toolbar')\n                        .append($('<div></div>')\n                            .addClass('section-start')\n                            .append($('<button></button>')\n                                .attr('data-action', 'clear')\n                                // TODO : I18N\n                                .attr('title', 'Clear Color')\n                                .css('display', 'none')\n                                .append($('<span></span>')\n                                    .addClass('fa fa-ban'))\n                                .on('click', function () {\n                                    assignValue($this, null, false);\n                                    $this.trigger('colorchange', null);\n                                }))\n                            .append($('<button></button>')\n                                .attr('data-action', 'system-color')\n                                // TODO : I18N\n                                .attr('title', 'System')\n                                .append($('<span></span>')\n                                    .addClass('fa fa-cog'))\n                                .on('click', function () {\n                                    $this.find('input[type=\"color\"]').trigger('click');\n                                })))\n                        .append($('<div></div>')\n                            .addClass('section-center')\n                            .append($('<button></button>')\n                                .attr('data-activate-view', ViewType.Palette)\n                                // TODO : I18N\n                                .attr('title', 'Palette')\n                                .append($('<span></span>')\n                                    .addClass('fa fa-th')))\n                            .append($('<button></button>')\n                                .attr('data-activate-view', ViewType.Swatches)\n                                // TODO : I18N\n                                .attr('title', 'Swatches')\n                                .css('display', 'none') // of by default\n                                .append($('<span></span>')\n                                    .addClass('fa fa-bars')))\n                            .append($('<button></button>')\n                                .attr('data-activate-view', ViewType.Trends)\n                                // TODO : I18N\n                                .attr('title', 'Trends')\n                                .append($('<span></span>')\n                                    .addClass('fa fa-sliders')))\n                            .append($('<button></button>')\n                                .attr('data-activate-view', ViewType.Image)\n                                // TODO : I18N\n                                .attr('title', 'From Image')\n                                .append($('<span></span>')\n                                    .addClass('fa fa-image'))))\n                        .append($('<div></div>')\n                            .addClass('section-end')\n                            .append($('<select></select>')\n                                .addClass('color-mode-select')\n                                .on('change', function () {\n                                    activateColorMode($this, $(this).val());\n                                }))))\n                    .append($('<div></div>')\n                        .addClass('color-view'))\n                    .append($('<div></div>')\n                        .addClass('color-components'))\n                    .append($('<hr/>'))\n                    .append($('<div></div>')\n                        .addClass('color')\n                        .append($('<div></div>')\n                            .append($('<div>&nbsp;</div>')\n                                .addClass('previous-color g-input')\n                                .on('click', function () {\n                                    if (data.previousColor) {\n                                        assignValue($this, data.previousColor, false);\n                                        $this.trigger('colorchange', data.previousColor);\n                                    }\n                                }))\n                            .append($('<div>&nbsp;</div>')\n                                .addClass('current-color g-input'))\n                            .append($('<div></div>')\n                                .addClass('color-difference g-input')\n                                // TODO : I18N\n                                .attr('title', 'Color Difference (CIEDE2000)'))\n                            .append($('<input>')\n                                .addClass('color-input')\n                                .on('change', function () {\n                                    var color = IFColor.parseCSSColor($(this).val());\n                                    if (color) {\n                                        assignValue($this, color, false);\n                                        $this.trigger('colorchange', color);\n                                    }\n                                })))\n                        .append($('<div></div>')\n                            .append($('<select></select>')\n                                .addClass('matcher-select')\n                                .on('change', function () {\n                                    activateMatcher($this, $(this).find(':selected').data('matcher'));\n                                }))))\n                    .append($('<div></div>')\n                        .addClass('matcher-palette'));\n\n                $this.find('[data-activate-view]').each(function (index, element) {\n                    var $element = $(element);\n                    $element\n                        .on('click', function (evt) {\n                            methods.view.call(self, $element.attr('data-activate-view'));\n                        });\n                });\n\n                // Initiate components\n                var components = $this.find('.color-components');\n                var _addComponent = function (index) {\n                    $('<div></div>')\n                        .addClass('color-component color-component-' + index.toString())\n                        .append($('<div></div>')\n                            .addClass('color-label')\n                            .on('click', function () {\n                                var input = $this.find('.color-component-' + index.toString() + ' input[type=\"text\"]');\n                                if (input.val() == data.colorMode.components[index].max) {\n                                    input.val(data.colorMode.components[index].min);\n                                } else {\n                                    input.val(data.colorMode.components[index].max);\n                                }\n\n                                var color = updateFromComponents($this);\n                                $this.trigger('colorchange', color);\n                            }.bind(this)))\n                        .append($('<div></div>')\n                            .addClass('color-range')\n                            .append($('<input>')\n                                .attr('type', 'range')\n                                .attr('tabIndex', '-1')\n                                .on('input', function (evt) {\n                                    $this.find('.color-component-' + index.toString() + ' input[type=\"text\"]').val($(evt.target).val());\n                                    var color = updateFromComponents($this);\n                                    $this.trigger('colorchange', color);\n                                }.bind(this))))\n                        .append($('<div></div>')\n                            .addClass('color-value')\n                            .append($('<input>')\n                                .attr('type', 'text')\n                                .on('input', function () {\n                                    var color = updateFromComponents($this);\n                                    $this.trigger('colorchange', color);\n                                })))\n                        .append($('<div></div>')\n                            .addClass('color-unit'))\n                        .appendTo(components);\n                }.bind(this);\n\n                for (var i = 0; i < 4; ++i) {\n                    _addComponent(i);\n                }\n\n                // Init color modes\n                var colorModeSelect = $this.find('.color-mode-select');\n                for (var i = 0; i < ColorModes.length; ++i) {\n                    var modeInfo = ColorModes[i];\n                    $('<option></option>')\n                        .attr('value', modeInfo.type.key)\n                        .text(modeInfo.name)\n                        .appendTo(colorModeSelect);\n\n                    if (!data.colorMode) {\n                        activateColorMode($this, modeInfo.type.key);\n                    }\n                }\n\n                // Initiate matchers\n                var matcherSelect = $this.find('.matcher-select');\n                var matcherGroup = matcherSelect;\n                var lastCategory = null;\n                for (var i = 0; i < gravit.colorMatchers.length; ++i) {\n                    var matcher = gravit.colorMatchers[i];\n                    var category = ifLocale.get(matcher.getCategory());\n\n                    // Add to selector\n                    if (!lastCategory || category !== lastCategory) {\n                        matcherGroup = $('<optgroup></optgroup>')\n                            .attr('label', category)\n                            .appendTo(matcherSelect);\n                        lastCategory = category;\n                    }\n\n                    $('<option></option>')\n                        .data('matcher', matcher)\n                        .text(ifLocale.get(matcher.getTitle()))\n                        .appendTo(matcherGroup);\n\n                    if (!data.matcher) {\n                        activateMatcher($this, matcher);\n                    }\n                }\n\n                // Init views\n                for (var view in ViewType) {\n                    if (ViewType.hasOwnProperty(view)) {\n                        createView($this, ViewType[view]);\n                    }\n                }\n\n                // Set default view\n                methods.view.call(self, options.defaultView);\n            });\n        },\n\n        view: function (value) {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('gcolorpanel');\n\n            if (!arguments.length) {\n                return data.view;\n            } else {\n                if (value !== data.view) {\n                    data.view = value;\n\n                    $this.find('[data-activate-view]').each(function (index, element) {\n                        var $element = $(element);\n                        $element.toggleClass('g-active', $element.attr('data-activate-view') === value);\n                    });\n\n                    $this.find('.color-view > *').each(function (index, element) {\n                        var $element = $(element);\n                        $element.css('display', $element.attr('data-view') === value ? '' : 'none');\n                    });\n                }\n                return this;\n            }\n        },\n\n        allowClear: function (value) {\n            var $this = $(this);\n            if (!arguments.length) {\n                return $this.data('gcolorpanel').allowClear;\n            } else {\n                // TODO : Detach & Attach listeners & Change active view if swatches & value=null\n                $this.data('gcolorpanel').allowClear = value;\n                $this.find('[data-action=\"clear\"]')\n                    .css('display', value ? '' : 'none');\n                return this;\n            }\n        },\n\n        scene: function (value) {\n            var $this = $(this);\n            var data = $this.data('gcolorpanel');\n\n            if (!arguments.length) {\n                return data.scene;\n            } else {\n                var oldScene = data.scene;\n                data.scene = value;\n\n                // Update swatches\n                var swatchView = $this.find('[data-view=\"' + ViewType.Swatches + '\"]');\n                if (oldScene) {\n                    swatchView.gSwatchPanel('detach');\n                }\n\n                if (data.scene) {\n                    swatchView.gSwatchPanel('attach', data.scene.getSwatchCollection());\n                }\n\n                $this.find('[data-activate-view=\"' + ViewType.Swatches + '\"]')\n                    .css('display', data.scene ? '' : 'none');\n\n                return this;\n            }\n        },\n\n        value: function (value) {\n            var $this = $(this);\n            if (!arguments.length) {\n                return $this.data('gcolorpanel').color;\n            } else {\n                var data = $this.data('gcolorpanel');\n                assignValue($this, value, true);\n\n                if (data.scene && (!data.color || data.color.getType() === IFColor.Type.Black || data.color.getType() === IFColor.Type.White || data.color.getType() === IFColor.Type.Registration)) {\n                    var clspace = data.scene.getProperty('clspace');\n                    if (clspace) {\n                        for (var i = 0; i < ColorModes.length; ++i) {\n                            if (ColorModes[i].type.space === clspace) {\n                                activateColorMode($this, ColorModes[i].type.key);\n                                break;\n                            }\n                        }\n                    }\n                }\n\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Block to transform divs to color panels\n     */\n    $.fn.gColorPanel = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}\n    (jQuery)\n    )\n;\n"
  },
  {
    "path": "src/application/component/cornertype.js",
    "content": "(function ($) {\n\n    var cornerTypes = [\n        {\n            type: IFPathBase.CornerType.Rounded,\n            // TODO : I18N\n            name: 'Rounded'\n        },\n        {\n            type: IFPathBase.CornerType.InverseRounded,\n            // TODO : I18N\n            name: 'Inverse Rounded'\n        },\n        {\n            type: IFPathBase.CornerType.Bevel,\n            // TODO : I18N\n            name: 'Beveled'\n        },\n        {\n            type: IFPathBase.CornerType.Inset,\n            // TODO : I18N\n            name: 'Inset'\n        },\n        {\n            type: IFPathBase.CornerType.Fancy,\n            // TODO : I18N\n            name: 'Fancy'\n        }\n    ];\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n            }, options);\n\n            return this.each(function () {\n                var $this = $(this);\n                if ($this.is(\"select\")) {\n                    // If the last item is an optgroup, use that as a target\n                    var target = $this;\n                    var lastElement = $this.find(':last');\n                    if (lastElement.is('optgroup')) {\n                        target = lastElement;\n                    }\n\n                    // Append corner types\n                    for (var i = 0; i < cornerTypes.length; ++i) {\n                        target.append($('<option></option>')\n                            .attr('value', cornerTypes[i].type)\n                            .text(cornerTypes[i].name));\n                    }\n                }\n            });\n        }\n    };\n\n    /**\n     * Adds a translated list of options to a selection that\n     * represents the IFBasePath.CornerType choices\n     * TODO : Replace select with visual selector with icons\n     */\n    $.fn.gCornerType = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/gradienteditor.js",
    "content": "(function ($) {\n\n    function updateStop($this, $stop) {\n        $stop.css('left', $stop.data('stop-position') + '%');\n        $stop.find('.stop-color').css('background', $stop.data('stop-color').asCSSString());\n        $stop.gColorButton('value', $stop.data('stop-color'));\n\n        updateGradient($this);\n    }\n\n    function updateGradient($this) {\n        var stops = $this.gGradientEditor('value');\n        var cssStops = [];\n\n        for (var i = 0; i < stops.length; ++i) {\n            var stop = stops[i];\n            cssStops.push('' + stop.color.asCSSString() + ' ' + stop.position + '%');\n        }\n\n        $this.find('.gradient').css('background', 'linear-gradient(90deg, ' + cssStops.join(\", \") + ')');\n\n        $this.gPatternTarget('value', new IFGradient(stops));\n    }\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // An attached scene used for swatch handling\n                // when coosing a color\n                scene: null\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n\n                var data = {\n                    options: options\n                };\n\n                var $this = $(this)\n                    .addClass('g-gradient-editor')\n                    .data('ggradienteditor', data)\n                    .gPatternTarget({\n                        types: [IFPattern.Type.Color, IFPattern.Type.Gradient]\n                    })\n                    .on('patterndrop', function (evt, pattern, mouseEvent) {\n                        if (pattern && pattern instanceof IFColor) {\n                            var $stops = $(this).find('.stops');\n                            var stopsWidth = $stops.width();\n                            var relativePos = mouseEvent.pageX - $stops.offset().left;\n                            var percentPos = relativePos <= 0 ? 0 :\n                                relativePos >= stopsWidth ? 100 : (relativePos / stopsWidth * 100);\n                            methods.insertStop.call(self, percentPos, pattern);\n                            $this.trigger('change');\n                        } else if (pattern instanceof IFGradient) {\n                            methods.value.call(self, pattern.getStops());\n                            $this.trigger('change');\n                        }\n                    });\n\n                var container = $('<div></div>')\n                    .addClass('container')\n                    .appendTo($this);\n\n                container\n                    .append($('<div></div>')\n                        .addClass('editor')\n                        .append($('<div></div>')\n                            .addClass('gradient g-input')\n                            .css('background', 'transparent'))\n                        .append($('<div></div>')\n                            .addClass('stops')\n                            .on('mousedown', function (evt) {\n                                // Prevents any accident drag'n'drop actions\n                                evt.preventDefault();\n                                evt.stopPropagation();\n                            })\n                            .on('dblclick', function (evt) {\n                                var $stops = $(evt.target);\n                                if ($stops.hasClass('stops')) {\n                                    // Calculate insert position\n                                    // TODO : Calculate gradient color at given position and set it\n                                    var stopsWidth = $stops.width();\n                                    var relativePos = evt.pageX - $stops.offset().left;\n                                    var percentPos = relativePos <= 0 ? 0 :\n                                        relativePos >= stopsWidth ? 100 : (relativePos / stopsWidth * 100);\n\n                                    var finalPosition = methods.insertStop.call(self, percentPos, IFColor.parseCSSColor('black'));\n                                    $this.trigger('change');\n\n                                    $stops.find('> .stop').each(function (index, element) {\n                                        var $stop = $(element);\n                                        if ($stop.data('stop-position') === finalPosition) {\n                                            $stop.gColorButton('open');\n                                            return false;\n                                        }\n                                    });\n                                }\n                            })));\n            });\n        },\n\n        value: function (value) {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('ggradienteditor');\n            var $stops = $this.find('.stops > .stop');\n\n            if (!arguments.length) {\n                var stops = [];\n                $stops.each(function (index, element) {\n                    var $stop = $(element);\n                    if ($stop.data('stop-delete') === false) {\n                        stops.push({\n                            position: $stop.data('stop-position'),\n                            color: $stop.data('stop-color')\n                        });\n                    }\n                });\n\n                stops.sort(function (a, b) {\n                    return a.position > b.position;\n                });\n\n                return stops;\n            } else {\n                // Shortcut: If stops lengths are equal,\n                // do a simple stop-update instead of clearing\n                if (value && value.length === $stops.length) {\n                    $stops.each(function (index, element) {\n                        var $stop = $(element);\n                        $stop\n                            .data('stop-position', value[index].position)\n                            .data('stop-color', value[index].color)\n                            .data('stop-delete', false);\n\n                        updateStop($this, $stop);\n                    });\n                } else {\n                    // Clear stops and add all again\n                    $this.find('.stops').empty();\n\n                    // Insert all stops now if any\n                    if (value) {\n                        for (var i = 0; i < value.length; ++i) {\n                            methods.insertStop.call(self, value[i].position, value[i].color);\n                        }\n                    }\n                }\n\n                return this;\n            }\n        },\n\n        insertStop: function (position, color) {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('ggradienteditor');\n            var $stops = $this.find('.stops');\n\n            // Normalize position\n            position = Math.round(position);\n            position = position < 0 ? 0 : position > 100 ? 100 : position;\n\n            var hasChanged = false;\n\n            // Insert stop widget\n            var $stop = $('<div></div>')\n                .addClass('stop')\n                .data('stop-position', position)\n                .data('stop-color', color)\n                .data('stop-delete', false)\n                .gColorButton({\n                    drag: false,\n                    transient: true,\n                    autoOpen: false,\n                    scene: data.options.scene\n                })\n                .append($('<div></div>')\n                    .addClass('stop-color'))\n                .on('colorchange', function (evt, color) {\n                    if (color) {\n                        $stop.data('stop-color', color);\n                        updateStop($this, $stop);\n                        $this.trigger('change');\n                    }\n                })\n                .on('click', function (evt) {\n                    if (!hasChanged) {\n                        $(this).gColorButton('open');\n                    }\n                })\n                .on('mousedown', function (evt) {\n                    hasChanged = false;\n\n                    // Implement dragging stuff\n                    var stopsOffset = $stops.offset();\n                    var moveMinX = stopsOffset.left;\n                    var moveMaxX = moveMinX + $stops.width();\n                    var moveMaxY = stopsOffset.top + $stops.outerHeight();\n                    var stopWidth = $stop.outerWidth();\n                    var startPosX = $stop.offset().left + stopWidth - evt.pageX;\n                    var startPosY = $stop.offset().top - evt.pageY;\n\n                    var $document = $(document);\n\n                    var docMouseMove = function (evt) {\n                        var left = evt.pageX + startPosX - (stopWidth / 2);\n                        var top = evt.pageY + startPosY;\n\n                        // Ensure to not move outside our range horizontally\n                        if (left <= moveMinX) {\n                            left = moveMinX;\n                        } else if (left >= moveMaxX) {\n                            left = moveMaxX;\n                        }\n\n                        if (top > moveMaxY) {\n                            // Moved outside area so get rid of our stop\n                            $stop\n                                .css('display', 'none')\n                                .data('stop-delete', true);\n                        } else {\n                            $stop\n                                .css('display', '')\n                                .data('stop-delete', false);\n                        }\n\n                        // Calculate percentage for stop\n                        var relativePos = left - moveMinX;\n                        var relativeMoveArea = (moveMaxX - moveMinX);\n                        var percentPos = relativePos <= 0 ? 0 :\n                            relativePos >= relativeMoveArea ? 100 : (relativePos / relativeMoveArea * 100);\n\n                        $stop.data('stop-position', percentPos);\n                        updateStop($this, $stop);\n                        hasChanged = true;\n                    };\n\n                    var docMouseUp = function (evt) {\n                        // Clear the document listeners\n                        $document\n                            .off(\"mousemove\", docMouseMove)\n                            .off(\"mouseup\", docMouseUp);\n\n                        // Delete the stop if marked and we\n                        // still have at least two steps left\n                        var triggerChange = true;\n                        if ($stop.data('stop-delete') === true) {\n                            if ($stops.find('> .stop').length > 2) {\n                                $stop.remove();\n                                hasChanged = true;\n                            } else {\n                                $stop.data('stop-delete', false);\n                                hasChanged = true;\n                                triggerChange = false;\n                            }\n                        }\n\n                        if (hasChanged && triggerChange) {\n                            $this.trigger('change');\n                        }\n                    };\n\n                    $document\n                        .on(\"mousemove\", docMouseMove)\n                        .on(\"mouseup\", docMouseUp);\n                })\n                .appendTo($stops);\n\n            updateStop($this, $stop);\n\n            return position;\n        }\n    };\n\n    /**\n     * Initiates a gradient editor on a given div\n     */\n    $.fn.gGradientEditor = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n})(jQuery);"
  },
  {
    "path": "src/application/component/menu.js",
    "content": "(function (_) {\n    /**\n     * A menu implementation\n     * @param {GMenuItem|GMenuBar} parent parent if not a standalone menu\n     * @class GMenu\n     * @extends GEventTarget\n     * @constructor\n     * @version 1.0\n     */\n    function GMenu(parent) {\n        this._parent = parent;\n        this._htmlElement = $(\"<ul></ul>\").addClass('g-menu');\n        this._htmlElement.on(\"mouseover\", this._mouseOver.bind(this));\n        this._htmlElement.on(\"mouseout\", this._mouseOut.bind(this));\n    };\n\n    IFObject.inherit(GMenu, GEventTarget);\n\n    /**\n     * A position a menu can be opened at\n     * @enum\n     */\n    GMenu.Position = {\n        Left_Top: 0,\n        Center: 1,\n        Right_Bottom: 2\n    };\n\n    /**\n     * Global, active menu\n     * @type {GMenu}\n     * @private\n     */\n    GMenu._activeMenu = null;\n\n    /**\n     * Array of tracked mouse locations\n     * @type {Array<{{x:Number, y: Number}}>}\n     * @private\n     */\n    GMenu._activeMenuMouseLocations = null;\n\n    /**\n     * Get the globally, active menu\n     * @returns {GMenu}\n     */\n    GMenu.getActiveMenu = function () {\n        return GMenu._activeMenu;\n    };\n\n    /**\n     * Assign the globally, active menu, closing any active one, first\n     * @param {GMenu} menu if null, only closes\n     */\n    GMenu.setActiveMenu = function (menu, noCloseCall) {\n        // Close any active menu, first\n        if (this._activeMenu) {\n            if (!noCloseCall) {\n                this._activeMenu.close();\n            }\n\n            this._activeMenu = null;\n\n            // Remove global menu listeners\n            document.removeEventListener(\"mousemove\", GMenu._activeMenuMouseMoveListener);\n            document.removeEventListener(\"mousedown\", GMenu._activeMenuMouseUpDownListener);\n            document.removeEventListener(\"mouseup\", GMenu._activeMenuMouseUpDownListener);\n            document.removeEventListener(\"keyup\", GMenu._activeMenuKeyDownListener);\n        }\n\n        this._activeMenu = menu;\n\n        // Assign a new, active menu if any\n        if (this._activeMenu) {\n            // Register menu listeners\n            document.addEventListener(\"mousemove\", GMenu._activeMenuMouseMoveListener);\n            document.addEventListener(\"mousedown\", GMenu._activeMenuMouseUpDownListener);\n            // Mouse down close listener needs slight timeout to not hit the 'click' event and\n            // immediately close any active menu after mouse up\n            setTimeout(function () {\n                document.addEventListener(\"mouseup\", GMenu._activeMenuMouseUpDownListener);\n            }, 250);\n            document.addEventListener(\"keyup\", GMenu._activeMenuKeyDownListener);\n        }\n    };\n\n    /**\n     * Method listening on document mouse move for tracking\n     * the last mouse locations\n     * @param evt\n     * @private\n     */\n    GMenu._activeMenuMouseMoveListener = function (evt) {\n        if (!GMenu._activeMenuMouseLocations) {\n            GMenu._activeMenuMouseLocations = [];\n        }\n\n        GMenu._activeMenuMouseLocations.push({\n            x: evt.pageX,\n            y: evt.pageY\n        });\n\n        if (GMenu._activeMenuMouseLocations.length > 3) {\n            GMenu._activeMenuMouseLocations.shift();\n        }\n    };\n\n    /**\n     * Method listening on document mouse down/up and simply\n     * closes the active menu if any\n     * @param evt\n     * @private\n     */\n    GMenu._activeMenuMouseUpDownListener = function (evt) {\n        GMenu.setActiveMenu(null);\n    };\n\n    /**\n     * Method listening on document key event and closes\n     * the active menu if any when the ESC is hit\n     * @param evt\n     * @private\n     */\n    GMenu._activeMenuKeyDownListener = function (evt) {\n        if (evt.keyCode == 27) {\n            GMenu.setActiveMenu(null);\n        }\n    };\n\n    /**\n     * Creates a menu out of the registered actions\n     * @param {Array<GAction>} actions array of actions to create a menu of\n     * @param {GMenu} targetMenu the menu to create the action structure into\n     */\n    GMenu.createActionMenu = function (actions, targetMenu) {\n        // TODO : Order given actions by category & group\n\n        var itemToGroupArray = [];\n\n        var _getGroupForItem = function (item) {\n            for (var i = 0; i < itemToGroupArray.length; ++i) {\n                if (itemToGroupArray[i].item === item) {\n                    return itemToGroupArray[i].group;\n                }\n            }\n        };\n\n        var _addItemGroupAndDivider = function (menu, item, group) {\n            if (menu.getItemCount() > 0) {\n                var lastGroup = _getGroupForItem(menu.getItem(menu.getItemCount() - 1));\n                if (lastGroup !== group) {\n                    menu.addItem(new GMenuItem(GMenuItem.Type.Divider));\n                }\n            }\n            itemToGroupArray.push({\n                item: item,\n                group: group\n            });\n        };\n\n        for (var i = 0; i < actions.length; ++i) {\n            var action = actions[i];\n\n            if (!action.isAvailable()) {\n                continue;\n            }\n\n            var category = ifLocale.get(action.getCategory());\n            var group = action.getGroup();\n            var categories = category ? category.split('/') : null;\n            var groups = group ? [\"\"].concat(group.split('/')) : null;\n\n            if (groups && categories && categories.length !== groups.length - 1) {\n                throw new Error(\"Number of categories different thant number of groups.\");\n            }\n\n            // Build up our structure by iterating our categories\n            var currentMenu = targetMenu;\n            if (categories) {\n                for (var k = 0; k < categories.length; ++k) {\n                    var category = categories[k];\n                    var group = groups ? groups[k] : null;\n                    var item = currentMenu.findItem(category);\n                    if (!item) {\n                        item = new GMenuItem(GMenuItem.Type.Menu);\n                        item.setCaption(category);\n                        _addItemGroupAndDivider(currentMenu, item, group);\n\n                        currentMenu.addItem(item);\n                    }\n                    currentMenu = item.getMenu();\n                }\n            }\n\n            // Add our action item now\n            var actionItem = new GMenuItem();\n            actionItem.setAction(action);\n            _addItemGroupAndDivider(currentMenu, actionItem, groups ? groups[groups.length - 1] : null);\n\n            currentMenu.addItem(actionItem);\n        }\n    };\n\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenu.OpenEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a (standalone) menu is opened\n     * @class GMenu.OpenEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    GMenu.OpenEvent = function () {\n    };\n    IFObject.inherit(GMenu.OpenEvent, GEvent);\n\n    /** @override */\n    GMenu.OpenEvent.prototype.toString = function () {\n        return \"[Object GMenu.OpenEvent]\";\n    };\n\n    GMenu.OPEN_EVENT = new GMenu.OpenEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenu.CloseEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a (standalone) menu is closed\n     * @class GMenu.CloseEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    GMenu.CloseEvent = function () {\n    };\n    IFObject.inherit(GMenu.CloseEvent, GEvent);\n\n    /** @override */\n    GMenu.CloseEvent.prototype.toString = function () {\n        return \"[Object GMenu.CloseEvent]\";\n    };\n\n    GMenu.CLOSE_EVENT = new GMenu.CloseEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenu Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @type {GMenuItem|GMenuBar}\n     * @private\n     */\n    GMenu.prototype._parent = null;\n\n    /**\n     * @type {HTMLDivElement}\n     * @private\n     */\n    GMenu.prototype._htmlElement = null;\n\n    /**\n     * @type {Array<GMenuItem>}\n     * @private\n     */\n    GMenu.prototype._items = null;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    GMenu.prototype._hovered = false;\n\n    /**\n     * @returns {GMenuItem|GMenuBar}\n     */\n    GMenu.prototype.getParent = function () {\n        return this._parent;\n    };\n\n    /**\n     * Checks and returns whether the mouse is currently\n     * over this menu including sub menus if desired\n     * @param {boolean} recursive if true, considers\n     * also any sub-menu hovering as effective, otherwise\n     * only takes into account this menu\n     */\n    GMenu.prototype.isHovered = function (recursive) {\n        if (this._hovered) {\n            return true;\n        }\n        else if (!recursive) {\n            return false;\n        } else {\n            for (var i = 0; i < this.getItemCount(); ++i) {\n                var item = this.getItem(i);\n                if (item instanceof GMenuItem && item.getType() === GMenuItem.Type.Menu) {\n                    if (item.getMenu().isHovered(true)) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        }\n    };\n\n    /**\n     * Checks whether this menu is a root menu or not which\n     * is the case if the parent is either null or anything\n     * else than another GMenuItem\n     * @returns {boolean}\n     */\n    GMenu.prototype.isRootMenu = function () {\n        return !this._parent || !(this._parent instanceof GMenuItem);\n    };\n\n    /**\n     * Checks if this is a sub-menu or not\n     * @returns {boolean}\n     */\n    GMenu.prototype.isSubMenu = function () {\n        if (this._parent && this._parent instanceof GMenuItem) {\n            return !this._parent.isRootItem();\n        }\n        return false;\n    };\n\n    /**\n     * Creates and appends a divider and returns it\n     * @returns {GMenuItem}\n     */\n    GMenu.prototype.createAddDivider = function () {\n        return this.createInsertDivider(this.getItemCount());\n    };\n\n    /**\n     * Creates and inserts a divider and returns it\n     * @param index\n     * @returns {GMenuItem}\n     */\n    GMenu.prototype.createInsertDivider = function (index) {\n        var newItem = new GMenuItem(GMenuItem.Type.Divider);\n        this.insertItem(index, newItem);\n        return newItem;\n    };\n\n    /**\n     * Creates and appends a menu item and returns it\n     * @param caption\n     * @param activate\n     * @param enter\n     * @param leave\n     * @returns {GMenuItem}\n     */\n    GMenu.prototype.createAddItem = function (caption, activate, enter, leave) {\n        return this.createInsertItem(this.getItemCount(), caption, activate, enter, leave);\n    };\n\n    /**\n     * Creates and inserts a menu item and returns it\n     * @param index\n     * @param caption\n     * @param activate\n     * @param enter\n     * @param leave\n     * @returns {GMenuItem}\n     */\n    GMenu.prototype.createInsertItem = function (index, caption, activate, enter, leave) {\n        var newItem = new GMenuItem();\n        newItem.setCaption(caption);\n\n        if (activate) {\n            newItem.addEventListener(GMenuItem.ActivateEvent, activate);\n        }\n\n        if (enter) {\n            newItem.addEventListener(GMenuItem.EnterEvent, enter);\n        }\n\n        if (leave) {\n            newItem.addEventListener(GMenuItem.LeaveEvent, leave);\n        }\n\n        this.insertItem(index, newItem);\n\n        return newItem;\n    };\n\n    /**\n     * Add a menu item to this menu\n     * @param {GMenuItem} item\n     * @returns {Number} index of newly inserted item\n     * @version 1.0\n     */\n    GMenu.prototype.addItem = function (item) {\n        return this.insertItem(this.getItemCount(), item);\n    };\n\n    /**\n     * Insert a menu item into this menu\n     * @param {Number} index the index to insert before, if equal\n     * to length, inserts at end\n     * @param {GMenuItem} item\n     * @returns {Number} index of newly inserted item\n     * @version 1.0\n     */\n    GMenu.prototype.insertItem = function (index, item) {\n        if (this._items == null) {\n            this._items = [];\n        }\n\n        if (index + 1 < this._items.length) {\n            this._items.splice(index, 0, item);\n            this._items[index + 1]._htmlElement.before(item._htmlElement);\n        } else {\n            this._items.push(item);\n            this._htmlElement.append(item._htmlElement);\n        }\n\n        item._parent = this;\n    };\n\n    /**\n     * Remove an item at a given index\n     * @param {Number} index\n     * @version 1.0\n     */\n    GMenu.prototype.removeItem = function (index) {\n        if (index >= 0 && index < this.getItemCount()) {\n            this._items[index]._parent = null;\n            this._items[index]._htmlElement.detach();\n            this._items.splice(index, 1);\n        }\n    };\n\n    /**\n     * Removes all items of this menu\n     */\n    GMenu.prototype.clearItems = function () {\n        if (this._items) {\n            for (var i = 0; i < this._items.length; ++i) {\n                this._items[i]._parent = null;\n                this._items[i]._htmlElement.detach();\n            }\n            this._items = [];\n        }\n    };\n\n    /**\n     * Get a menu item by it's index\n     * @param {Number} index the index to look for\n     * @return {GMenuItem} the menu item or null if index is invalid\n     */\n    GMenu.prototype.getItem = function (index) {\n        if (index >= 0 && index < this.getItemCount()) {\n            return this._items[index];\n        }\n        return null;\n    };\n\n    /**\n     * @returns {Number} the number of items in this menu\n     * @version 1.0\n     */\n    GMenu.prototype.getItemCount = function () {\n        return this._items ? this._items.length : 0;\n    };\n\n    /**\n     * Get the index for an item\n     * @param {GMenuItem} item the item to get an index for\n     * @return {Number} index of the item or -1 if not found\n     * @version 1.0\n     */\n    GMenu.prototype.indexOf = function (item) {\n        return this._items ? this._items.indexOf(item) : -1;\n    };\n\n    /**\n     * Find a menu item by its caption\n     * @param {String} caption the caption to find\n     * @return {GMenuItem} the menu item or null if not found\n     */\n    GMenu.prototype.findItem = function (caption) {\n        for (var i = 0; i < this.getItemCount(); ++i) {\n            var item = this.getItem(i);\n            if (caption == item.getCaption()) {\n                return item;\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Called to update the status of all direct children of this menu\n     * @version 1.0\n     */\n    GMenu.prototype.update = function () {\n        for (var i = 0; i < this.getItemCount(); ++i) {\n            var item = this.getItem(i);\n            item.update();\n        }\n    };\n\n    /**\n     * Returns whether this menu is open or not\n     * @return {Boolean}\n     */\n    GMenu.prototype.isOpen = function () {\n        return !!this._htmlElement.parent().length;\n    };\n\n    /**\n     * Open the menu at a given reference which can be\n     * either an absolute point or a jquery html element\n     * @param {JQuery|{{x: Number, y: Number}}} reference the reference element or point to open at\n     * @param {GMenu.Position|Number} horzPosition the horizontal position to open at\n     * @param {GMenu.Position|Number} vertPosition the vertical position to open at\n     */\n    GMenu.prototype.open = function (reference, horzPosition, vertPosition) {\n        horzPosition = typeof horzPosition === 'number' ? horzPosition : GMenu.Position.Center;\n        vertPosition = typeof vertPosition === 'number' ? vertPosition : GMenu.Position.Center;\n\n        if (!this.isOpen()) {\n            // Do an initial update on the menu\n            this.update();\n\n            // Attach it to the DOM\n            this._htmlElement.appendTo($(\"body\"));\n\n            // If this is not a sub-menu, then mark this\n            // as being the global active menu\n            if (!this.isSubMenu()) {\n                GMenu.setActiveMenu(this);\n            }\n\n            // Send open event\n            this.trigger(GMenu.OPEN_EVENT);\n        }\n\n        if (this._htmlElement.parent().is(\"body\")) {\n            // Gather our menu's extents\n            var menuWidth = this._htmlElement.outerWidth();\n            var menuHeight = this._htmlElement.outerHeight();\n\n            // Gather window's extents\n            var windowWidth = $(window).width();\n            var windowHeight = $(window).height();\n\n            // Try to figure show rectangle\n            var rect = {x: 0, y: 0, width: 0, height: 0};\n            if (typeof reference.x === 'number' && typeof reference.y === 'number') {\n                rect.x = reference.x;\n                rect.y = reference.y;\n            } else {\n                var refOffset = reference.offset();\n                rect.x = refOffset.left;\n                rect.y = refOffset.top;\n                rect.width = reference.outerWidth();\n                rect.height = reference.outerHeight();\n            }\n\n            // Now find the right x,y position according to rect and position\n            var x = 0;\n            switch (horzPosition) {\n                case GMenu.Position.Left_Top:\n                    x = rect.x - menuWidth;\n                    break;\n                case GMenu.Position.Center:\n                    x = rect.x;\n                    break;\n                case GMenu.Position.Right_Bottom:\n                    x = rect.x + rect.width;\n                    break;\n            }\n\n            var y = 0;\n            switch (vertPosition) {\n                case GMenu.Position.Left_Top:\n                    y = rect.y - menuHeight;\n                    break;\n                case GMenu.Position.Center:\n                    y = rect.y;\n                    break;\n                case GMenu.Position.Right_Bottom:\n                    y = rect.y + rect.height;\n                    break;\n            }\n\n            // Correct position to not float outside visible area\n            if (x < 0) {\n                x = 0;\n            }\n            if (x + menuWidth >= windowWidth) {\n                x = windowWidth - menuWidth;\n            }\n            if (y < 0) {\n                y = 0;\n            }\n            if (y + menuHeight >= windowHeight) {\n                y = windowHeight - menuHeight;\n            }\n\n            // Finally position our menu and set the position classes\n            this._htmlElement.css('left', x);\n            this._htmlElement.css('top', y);\n\n            switch (horzPosition) {\n                case GMenu.Position.Left_Top:\n                    this._htmlElement.addClass('g-menu-left');\n                    break;\n                case GMenu.Position.Right_Bottom:\n                    this._htmlElement.addClass('g-menu-right');\n                    break;\n            }\n\n            switch (vertPosition) {\n                case GMenu.Position.Left_Top:\n                    this._htmlElement.addClass('g-menu-top');\n                    break;\n                case GMenu.Position.Right_Bottom:\n                    this._htmlElement.addClass('g-menu-bottom');\n                    break;\n            }\n        }\n    };\n\n    /**\n     * Close the menu if it is opened and closeable\n     */\n    GMenu.prototype.close = function () {\n        if (this.isOpen() && this._htmlElement.parent().is(\"body\")) {\n            this.closeMenus();\n\n            // Remove our orientation classes\n            this._htmlElement.removeClass('g-menu-left g-menu-right g-menu-top g-menu-bottom');\n\n            // Simply detach our element\n            this._htmlElement.detach();\n\n            // If this is the active menu, remove it now\n            if (this === GMenu._activeMenu) {\n                GMenu.setActiveMenu(null, true);\n            }\n\n            // Send close event\n            this.trigger(GMenu.CLOSE_EVENT);\n        }\n    };\n\n    /**\n     * Close all sub menus\n     */\n    GMenu.prototype.closeMenus = function () {\n        for (var i = 0; i < this.getItemCount(); ++i) {\n            var item = this.getItem(i);\n            if (item instanceof GMenuItem && item.getType() === GMenuItem.Type.Menu) {\n                item.getMenu().close();\n            }\n        }\n    };\n\n    GMenu.prototype._mouseOver = function (evt) {\n        this._hovered = true;\n    };\n\n    GMenu.prototype._mouseOut = function (evt) {\n        this._hovered = false;\n\n        if (this.isSubMenu()) {\n            setTimeout(function () {\n                if (!this.isHovered(true)) {\n                    this.closeMenus();\n                }\n            }.bind(this), 150);\n        }\n    };\n\n    _.GMenu = GMenu;\n})(this);\n"
  },
  {
    "path": "src/application/component/menubar.js",
    "content": "(function (_) {\n    /**\n     * A menu representing a menu bar\n     * @param {GMenu} [menu] optional menu to use as base\n     * @class GMenuBar\n     * @constructor\n     * @version 1.0\n     */\n    function GMenuBar(menu) {\n        this._menu = menu ? menu : new GMenu(this);\n        this._menu._parent = this;\n        this._menu._htmlElement.addClass('g-menu-root');\n        this._htmlElement = $(\"<nav></nav>\")\n            .addClass(\"g-menu-bar\")\n            .append(this._menu._htmlElement);\n    };\n\n    /**\n     * @type {GMenu}\n     * @private\n     */\n    GMenuBar.prototype._menu = null;\n\n    /**\n     * Return the menu for the menu bar\n     * @version 1.0\n     */\n    GMenuBar.prototype.getMenu = function () {\n        return this._menu;\n    };\n\n    /**\n     * This returns whether any menu on the menubar\n     * is opened which means the bar is active\n     * @return {Boolean}\n     */\n    GMenuBar.prototype.isActive = function () {\n        var activeMenu = GMenu.getActiveMenu();\n        if (activeMenu && activeMenu._parent && activeMenu._parent instanceof GMenuItem) {\n            return activeMenu._parent.getMenuBar() === this;\n        }\n        return false;\n    };\n\n    /** @override */\n    GMenuBar.prototype.toString = function () {\n        return \"[Object GMenuBar]\";\n    };\n\n    _.GMenuBar = GMenuBar;\n})(this);"
  },
  {
    "path": "src/application/component/menubutton.js",
    "content": "(function ($) {\n\n    var DEF_ACTION_CARET_CSS = {\n        'margin': '0px 1px',\n        'transform': 'rotate(-45deg)',\n        'position': 'absolute',\n        'bottom': '3px',\n        'font-size': '10px'\n    };\n\n    var NO_DEF_ACTION_CARET_CSS = {\n        'margin-left': '3px'\n    };\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // The menu to be shown\n                menu: null,\n                // A default action to be fired. If this is provided,\n                // the menu will be shown with some delay, otherwise the\n                // defaultAction gets fired\n                defaultAction: null,\n                // Whether to show a dropdown arrow indicator or not\n                arrow: true\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n                var timeout = null;\n\n                var $this = $(this)\n                    .data('gmenubutton', {\n                        options: options\n                    })\n                    .on('mousedown', function (evt) {\n                        evt.stopPropagation(); //!! prevent menu closing !!\n                        if (!options.defaultAction) {\n                            methods.open.call(self);\n                        } else {\n                            timeout = setTimeout(function () {\n                                methods.open.call(self);\n                                timeout = null;\n                            }.bind(this), 250);\n                        }\n                    })\n                    .on('mouseup', function (evt) {\n                        evt.stopPropagation(); //!! prevent menu closing !!\n                        if (timeout !== null) {\n                            clearTimeout(timeout);\n                            timeout = null;\n                        }\n\n                        if (!options.menu.isOpen() && options.defaultAction) {\n                            options.defaultAction();\n                        }\n                    });\n\n                if (options.arrow) {\n                    $this\n                        .append($('<span></span>')\n                            .addClass('fa fa-caret-down')\n                            .css(options.defaultAction ? DEF_ACTION_CARET_CSS : NO_DEF_ACTION_CARET_CSS));\n                }\n            });\n        },\n\n        // Open the menu\n        open: function () {\n            var $this = $(this);\n            var menu = $this.data('gmenubutton').options.menu;\n            if (!menu.isOpen()) {\n                menu.open($this, GMenu.Position.Center, GMenu.Position.Right_Bottom);\n            }\n        },\n\n        // Close the menu\n        close: function () {\n            var menu = $this.data('gmenubutton').options.menu;\n            if (menu.isOpen()) {\n                menu.close();\n            }\n        }\n    };\n\n    /**\n     * Converts a given button into a button with a menu\n     */\n    $.fn.gMenuButton = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/menuitem.js",
    "content": "(function (_) {\n    /**\n     * A menu item\n     * @param {Number} type the type of the menu item.\n     * Defaults to GMenuItem.Type.Item\n     * @class GMenuItem\n     * @extends GEventTarget\n     * @constructor\n     * @see GMenuItem.Type\n     * @version 1.0\n     */\n    function GMenuItem(type) {\n        this._htmlElement = $(\"<li></li>\").addClass('g-menu-item');\n\n        this._type = type ? type : GMenuItem.Type.Item;\n\n        if (this._type === GMenuItem.Type.Divider) {\n            this._htmlElement.addClass('g-menu-item-divider');\n        } else {\n            this._htmlElement\n                .append($('<span></span>')\n                    .addClass('g-menu-item-icon')\n                    .css('display', 'none'))\n                .append($('<span></span>')\n                    .addClass('g-menu-item-caption'))\n                .append($('<span></span>')\n                    .addClass('g-menu-item-shortcut')\n                    .css('display', 'none'))\n                .append($('<span></span>')\n                    .addClass('g-menu-item-tail'));\n\n            if (this._type === GMenuItem.Type.Menu) {\n                this._htmlElement.addClass('g-menu-item-menu');\n                this.setMenu(new GMenu(this));\n            }\n        }\n\n        this._htmlElement.on(\"mouseover\", this._mouseOver.bind(this));\n        this._htmlElement.on(\"mouseout\", this._mouseOut.bind(this));\n        this._htmlElement.on(\"mousedown\", this._mouseDown.bind(this));\n        this._htmlElement.on(\"mouseup\", this._mouseUp.bind(this));\n    }\n\n    IFObject.inherit(GMenuItem, GEventTarget);\n\n    /**\n     * The type of a menu item\n     * @type {{}}\n     * @version 1.0\n     */\n    GMenuItem.Type = {\n        /**\n         * A regular item which can be checked and clicked / executed\n         * @type {Number}\n         * @version 1.0\n         */\n        Item: 0,\n        /**\n         * An item representing a submenu item, can not be checked or executed\n         * @type {Number}\n         * @version 1.0\n         */\n        Menu: 1,\n\n        /**\n         * A divider item, can not be checked or executed or captioned\n         * @type {Number}\n         * @version 1.0\n         */\n        Divider: 2\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenuItem.EnterEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a menu item is entered\n     * @class GMenuItem.EnterEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    GMenuItem.EnterEvent = function () {\n    };\n    IFObject.inherit(GMenuItem.EnterEvent, GEvent);\n\n    /** @override */\n    GMenuItem.EnterEvent.prototype.toString = function () {\n        return \"[Object GMenuItem.EnterEvent]\";\n    };\n\n    GMenuItem.ENTER_EVENT = new GMenuItem.EnterEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenuItem.LeaveEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a menu item is left\n     * @class GMenuItem.LeaveEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    GMenuItem.LeaveEvent = function () {\n    };\n    IFObject.inherit(GMenuItem.LeaveEvent, GEvent);\n\n    /** @override */\n    GMenuItem.LeaveEvent.prototype.toString = function () {\n        return \"[Object GMenuItem.LeaveEvent]\";\n    };\n\n    GMenuItem.LEAVE_EVENT = new GMenuItem.LeaveEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenuItem.ActivateEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a menu item was activated\n     * @class GMenuItem.ActivateEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    GMenuItem.ActivateEvent = function () {\n    };\n    IFObject.inherit(GMenuItem.ActivateEvent, GEvent);\n\n    /** @override */\n    GMenuItem.ActivateEvent.prototype.toString = function () {\n        return \"[Object GMenuItem.ActivateEvent]\";\n    };\n\n    GMenuItem.ACTIVATE_EVENT = new GMenuItem.ActivateEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenuItem.UpdateEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a menu item should be updated (before it is shown)\n     * @class GMenuItem.UpdateEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    GMenuItem.UpdateEvent = function () {\n    };\n    IFObject.inherit(GMenuItem.UpdateEvent, GEvent);\n\n    /** @override */\n    GMenuItem.UpdateEvent.prototype.toString = function () {\n        return \"[Object GMenuItem.UpdateEvent]\";\n    };\n\n    GMenuItem.UPDATE_EVENT = new GMenuItem.UpdateEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GMenuItem Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {GMenu}\n     * @private\n     */\n    GMenuItem.prototype._parent = null;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    GMenuItem.prototype._type = null;\n    /**\n     * @type {GMenu}\n     * @private\n     */\n    GMenuItem.prototype._menu = null;\n\n    /**\n     * @type {String|JQuery}\n     * @private\n     */\n    GMenuItem.prototype._icon = null;\n\n    /**\n     * @type {IFLocale.Key|String}\n     * @private\n     */\n    GMenuItem.prototype._caption = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    GMenuItem.prototype._shortcutHint = null;\n\n    /**\n     * @type {GAction}\n     * @private\n     */\n    GMenuItem.prototype._action = null;\n\n    /**\n     * @return {GMenu}\n     * @version 1.0\n     */\n    GMenuItem.prototype.getParent = function () {\n        return this._parent;\n    };\n\n    /**\n     * @returns {Number} the item's type\n     * @see GMenuItem.Type\n     * @version 1.0\n     */\n    GMenuItem.prototype.getType = function () {\n        return this._type;\n    };\n\n    /**\n     * @returns {Stringg|JQuery} the item's icon\n     */\n    GMenuItem.prototype.getIcon = function () {\n        return this._icon;\n    };\n\n    /**\n     * Assign the item's icon which may be an icon class\n     * or a JQuery Html-Element\n     * @param {Stringg|JQuery} icon the icon or null for none\n     */\n    GMenuItem.prototype.setIcon = function (icon) {\n        if (icon !== this._icon) {\n            this._icon = icon;\n            var iconElement = this._htmlElement.find('.g-menu-item-icon');\n            iconElement.empty();\n            if (this._icon) {\n                if (typeof this._icon === 'string') {\n                    iconElement.append($('<i></i>')\n                        .addClass(icon));\n                } else {\n                    iconElement.append(this._icon);\n                }\n                iconElement.css('display', '');\n            } else {\n                iconElement.css('display', 'none');\n            }\n        }\n    };\n\n    /**\n     * @returns {IFLocale.Key|String} the item's caption\n     * @version 1.0\n     */\n    GMenuItem.prototype.getCaption = function () {\n        return this._caption;\n    };\n\n    /**\n     * Assigns the item's the caption\n     * @param {IFLocale.Key|String} caption\n     * @version 1.0\n     */\n    GMenuItem.prototype.setCaption = function (caption) {\n        if (caption !== this._caption) {\n            this._caption = caption;\n            var captionElement = this._htmlElement.find('.g-menu-item-caption');\n            captionElement.empty();\n\n            if (!this._caption || this._caption instanceof IFLocale.Key || typeof this._caption === 'string') {\n                captionElement.text(this._caption ? ifLocale.get(this._caption) : \"\");\n            } else {\n                captionElement.append(this._caption);\n            }\n        }\n    };\n\n    /**\n     * @returns {Array<*>} the item's shortcut hint\n     */\n    GMenuItem.prototype.getShortcutHint = function () {\n        return this._shortcutHint;\n    };\n\n    /**\n     * Assigns the item's shortcut hint\n     * @param {Array<*>} hint the shortcut hint\n     * @version 1.0\n     */\n    GMenuItem.prototype.setShortcutHint = function (hint) {\n        this._shortcutHint = hint;\n        var shortcutElement = this._htmlElement.find('.g-menu-item-shortcut');\n        if (this._shortcutHint && this._shortcutHint.length > 0) {\n            shortcutElement.text(ifKey.shortcutToString(hint));\n            shortcutElement.css('display', '');\n        } else {\n            shortcutElement.empty();\n            shortcutElement.css('display', 'none');\n        }\n    };\n\n    /**\n     * @returns {GAction} the item's action\n     */\n    GMenuItem.prototype.getAction = function () {\n        return this._action;\n    };\n\n    /**\n     * Assign an action to this menu item or remove it\n     * @param {GAction} action\n     */\n    GMenuItem.prototype.setAction = function (action) {\n        if (action !== this._action) {\n            if (this._action) {\n                // Remove shortcut if any was set\n                var shortcut = action.getShortcut();\n                if (shortcut && shortcut === this.getShortcutHint()) {\n                    this.setShortcutHint(null);\n                }\n            }\n\n            this._action = action;\n\n            if (this._action) {\n                // Check if there's a shortcut for the item and set if any\n                var shortcut = action.getShortcut();\n                if (shortcut) {\n                    this.setShortcutHint(shortcut);\n                }\n\n                this.setCaption(this._action.getTitle());\n                this.setEnabled(this._action.isEnabled() === true);\n            }\n        }\n    };\n\n    /**\n     * @returns {Boolean} whether the item is checked or not\n     * @version 1.0\n     */\n    GMenuItem.prototype.isChecked = function () {\n        return this._htmlElement.hasClass('g-menu-item-checked');\n    };\n\n    /**\n     * Assign whether the item is checked or not (no effect if not checkable)\n     * @param {Boolean} checked\n     * @version 1.0\n     */\n    GMenuItem.prototype.setChecked = function (checked) {\n        if (checked != this.isChecked()) {\n            if (checked) {\n                this._htmlElement.addClass(\"g-menu-item-checked\");\n            } else {\n                this._htmlElement.removeClass(\"g-menu-item-checked\");\n            }\n        }\n    };\n\n    /**\n     * @returns {Boolean} whether the item is enabled or not\n     * @version 1.0\n     */\n    GMenuItem.prototype.isEnabled = function () {\n        return !this._htmlElement.hasClass('g-disabled');\n    };\n\n    /**\n     * Assign whether the item is enabled or not\n     * @param {Boolean} enabled\n     * @version 1.0\n     */\n    GMenuItem.prototype.setEnabled = function (enabled) {\n        if (enabled != this.isEnabled()) {\n            if (enabled) {\n                this._htmlElement.removeClass(\"g-disabled\");\n            } else {\n                this._htmlElement.addClass(\"g-disabled\");\n            }\n        }\n    };\n\n    /**\n     * Checks and returns whether this item is a root item or not\n     * @return {boolean}\n     */\n    GMenuItem.prototype.isRootItem = function () {\n        return this._parent && this._parent instanceof GMenu &&\n            this._parent._parent != null && !(this._parent._parent instanceof GMenuItem);\n    };\n\n    /**\n     * Checks and returns whether this item is a a root item of a menubar or not\n     * @return {boolean}\n     */\n    GMenuItem.prototype.isRootMenuBarItem = function () {\n        return this.isRootItem() && this._parent._parent instanceof GMenuBar;\n    };\n\n    /**\n     * This will go up and return the menu bar or null if there's none\n     * @return {GMenuBar}\n     */\n    GMenuItem.prototype.getMenuBar = function () {\n        if (this.isRootMenuBarItem()) {\n            return this._parent._parent;\n        }\n        return null;\n    };\n\n    /**\n     * @return {GMenu} the submenu of this item if supported\n     * @version 1.0\n     */\n    GMenuItem.prototype.getMenu = function () {\n        return this._menu;\n    };\n\n    /**\n     * Assign the submenu for this item if it is a menu item\n     * @param {GMenu} menu\n     */\n    GMenuItem.prototype.setMenu = function (menu) {\n        if (menu && menu !== this._menu && this._type === GMenuItem.Type.Menu) {\n            this._menu = menu;\n            this._menu._parent = this;\n            this._menu.addEventListener(GMenu.OPEN_EVENT, this._menuOpen.bind(this));\n            this._menu.addEventListener(GMenu.CLOSE_EVENT, this._menuClose.bind(this));\n        }\n    };\n\n    /**\n     * Called before the menu item is shown to update it's status\n     * @version 1.0\n     */\n    GMenuItem.prototype.update = function () {\n        // If we have an action, it may have changed so update here\n        if (this._action) {\n            this.setCaption(this._action.getTitle());\n            this.setEnabled(this._action.isEnabled());\n            this.setChecked(this._action.isChecked());\n        }\n\n        if (this.hasEventListeners(GMenuItem.UpdateEvent)) {\n            this.trigger(GMenuItem.UPDATE_EVENT);\n        }\n    };\n\n    /** @override */\n    GMenuItem.prototype.toString = function () {\n        return \"[Object GMenuItem]\";\n    };\n\n    GMenuItem.prototype._mouseOver = function (evt) {\n        // Close all sub-menus of our parent\n        if (this._parent && this._parent instanceof GMenu && !this.isRootItem()) {\n            this._parent.closeMenus();\n        }\n\n        if (!this.isEnabled()) {\n            return;\n        }\n\n        // Check whether to open sub-menu on hover which is the case if\n        // a) We're on Desktop-Device\n        // b) Are a Sub-Menu Item\n        // c) Are not a Root-Item\n        //      - or -\n        //    Are a root item and part of a menu-bar which' menu is opened\n        if (this._type == GMenuItem.Type.Menu &&\n            ifSystem.hardware === IFSystem.Hardware.Desktop &&\n            (!this.isRootItem() || (this.isRootMenuBarItem() && this.getMenuBar().isActive()))) {\n            this._openMenu();\n        }\n\n        // Handle events for others than dividers\n        if (this._type != GMenuItem.Type.Divider) {\n            this._htmlElement.addClass(\"g-hover\");\n\n            if (this.hasEventListeners(GMenuItem.EnterEvent)) {\n                this.trigger(GMenuItem.ENTER_EVENT);\n            }\n        }\n    };\n\n    GMenuItem.prototype._mouseOut = function (evt) {\n        if (!this.isEnabled()) {\n            return;\n        }\n\n        if (this._type != GMenuItem.Type.Divider) {\n            this._htmlElement.removeClass(\"g-hover\");\n\n            if (this.hasEventListeners(GMenuItem.LeaveEvent)) {\n                this.trigger(GMenuItem.LEAVE_EVENT);\n            }\n        }\n    };\n\n    GMenuItem.prototype._mouseDown = function (evt) {\n        if (!this.isEnabled()) {\n            return;\n        }\n\n        if (evt.button == GUIMouseEvent.BUTTON_LEFT) {\n            // Stop propagation and default handling to not run into our global menu handlers\n            evt.stopPropagation();\n            evt.preventDefault();\n\n            // Open Sub-Menu if we're a Sub-Item and on Root or not on Desktop which doesn't have mouse-over\n            if (this._type === GMenuItem.Type.Menu && (this.isRootItem() || ifSystem.hardware !== IFSystem.Hardware.Desktop)) {\n                // Toggle our menu\n                if (this._htmlElement.hasClass('g-active')) {\n                    this.getMenu().close();\n                } else {\n                    this._openMenu();\n                }\n            }\n        }\n    };\n\n    GMenuItem.prototype._mouseUp = function (evt) {\n        // Stop propagation and default handling to not run into our global menu handlers\n        evt.stopPropagation();\n        evt.preventDefault();\n\n        if (!this.isRootMenuBarItem()) {\n            // Simulate a virtual 'mouse-out', first as that'll never occurr\n            // otherwise as we're removing the menu from the DOM\n            this._mouseOut(evt);\n\n            // Reset the active menu closing everything\n            GMenu.setActiveMenu(null);\n        }\n\n        if (this._type == GMenuItem.Type.Item) {\n            if (this._action && this._action.isAvailable() && this._action.isEnabled()) {\n                this._action.execute();\n            }\n\n            if (this.isEnabled() && this.hasEventListeners(GMenuItem.ActivateEvent)) {\n                this.trigger(GMenuItem.ACTIVATE_EVENT);\n            }\n        }\n    };\n\n    GMenuItem.prototype._openMenu = function () {\n        this.getMenu().open(this._htmlElement,\n            this.isRootItem() ? GMenu.Position.Center : GMenu.Position.Right_Bottom,\n            this.isRootItem() ? GMenu.Position.Right_Bottom : GMenu.Position.Center);\n    };\n\n    GMenuItem.prototype._menuOpen = function () {\n        this._htmlElement.addClass('g-active');\n\n        if (this.isRootItem()) {\n            this._parent._parent._htmlElement.addClass('g-active');\n        }\n    };\n\n    GMenuItem.prototype._menuClose = function () {\n        this._htmlElement.removeClass('g-active');\n\n        if (this.isRootItem()) {\n            this._parent._parent._htmlElement.removeClass('g-active');\n        }\n    };\n\n    _.GMenuItem = GMenuItem;\n})(this);"
  },
  {
    "path": "src/application/component/overlay.js",
    "content": "(function ($) {\n    var openOverlayStack = [];\n\n    document.addEventListener('keydown', function (evt) {\n        if (openOverlayStack.length > 0) {\n            if (evt.keyCode === 27) {\n                openOverlayStack[openOverlayStack.length - 1].gOverlay('close');\n            }\n        }\n    });\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // Whether to release on close or just detach\n                releaseOnClose: false\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n\n                var $this = $(this)\n                    .data('goverlay', {\n                        releaseOnClose: options.releaseOnClose\n                    });\n\n                var overlay = $('<div></div>')\n                    .addClass('g-modal-background')\n                    .on('click', function (evt) {\n                        if ($(evt.target).hasClass('g-modal-background')) {\n                            methods.close.call(self);\n                        }\n                    });\n\n                var container = $('<div></div>')\n                    .addClass('g-overlay')\n                    .css('position', 'absolute')\n                    .append($this)\n                    .appendTo(overlay);\n            });\n        },\n\n        open: function (target) {\n            var $this = $(this);\n            var data = $this.data('goverlay');\n\n            $this.parents('.g-modal-background').appendTo($('body'));\n\n            var $window = $(window);\n            var windowWidth = $window.width();\n            var windowHeight = $window.height();\n            var container = $this.parents('.g-overlay');\n            var containerWidth = container.outerWidth();\n            var containerHeight = container.outerHeight();\n            var $target = $(target);\n            var offset = $target.offset();\n            var top = offset.top;\n            var left = offset.left;\n            var right = offset.left + $target.outerWidth();\n            var bottom = offset.top +  + $target.outerHeight();\n\n            // By default we try to position at left-bottom\n            // but need to check whether we run out of window\n            // and eventually adjust positioning\n            var x = left;\n            var y = bottom;\n\n            if (x + containerWidth > windowWidth) {\n                x = right - containerWidth;\n            }\n            if (x + containerWidth > windowWidth) {\n                x = windowWidth - containerWidth;\n            }\n\n            if (y + containerHeight > windowHeight) {\n                y = top - containerHeight;\n            }\n            if (y + containerHeight > windowHeight) {\n                y = windowHeight - containerHeight;\n            }\n\n            if (y < 0) {\n                y = 0;\n            }\n            if (x < 0) {\n                x = 0;\n            }\n\n            container\n                .css('left', x + 'px')\n                .css('top', y + 'px');\n\n            openOverlayStack.push($this);\n\n            return this;\n        },\n\n        close: function () {\n            var $this = $(this);\n            var data = $this.data('goverlay');\n\n            $this.trigger('close');\n\n            if (data.releaseOnClose) {\n                $this.parents('.g-modal-background').remove();\n            } else {\n                $this.parents('.g-modal-background').detach();\n            }\n\n            openOverlayStack.pop();\n\n            return this;\n        }\n    };\n\n    /**\n     * Block to create an overlay\n     */\n    $.fn.gOverlay = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/panel.js",
    "content": "(function ($) {\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // The title of the panel\n                title: '',\n                // The content of the panel\n                content: '',\n                // The controls for the panel if any\n                controls: null\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n\n                var $this = $(this)\n                    .empty()\n                    .addClass('g-panel')\n                    .data('gpanel', {\n                        options: options,\n                        expanded: true\n                    })\n                    .append($('<div></div>')\n                        .addClass('header')\n                        .append($('<div></div>')\n                            .addClass('title')\n                            .append($('<i></i>')\n                                .addClass('fa fa-angle-down'))\n                            .append($('<span></span>')\n                                .text(options.title))\n                            .on('click', function () {\n                                methods.toggle.call(self);\n                            }))\n                        .append($('<div></div>')\n                            .addClass('controls')\n                            .append(options.controls)))\n                    .append($('<div></div>')\n                        .addClass('content')\n                        .append(options.content));\n            });\n        },\n\n        toggle: function () {\n            var $this = $(this);\n            var data = $this.data('gpanel');\n            methods.expanded.call(this, !data.expanded);\n        },\n\n        expanded: function (value) {\n            var $this = $(this);\n            var data = $this.data('gpanel');\n\n            if (!arguments.length) {\n                return data.expanded;\n            } else {\n                if (value !== data.expanded) {\n                    data.expanded = value;\n                    $this.find('.content').css('display', data.expanded ? '' : 'none');\n                    $this.find('.controls').css('visibility', data.expanded ? '' : 'hidden');\n                    $this.find('.header i.fa')\n                        .toggleClass('fa-angle-down', data.expanded)\n                        .toggleClass('fa-angle-right', !data.expanded);\n                }\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Block convert a div into a panel with a title and content\n     */\n    $.fn.gPanel = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/patterntarget.js",
    "content": "(function ($) {\n\n    var previewBoxSize = 20;\n\n    var dragImage = $('<div></div>')\n        .css({\n            'position': 'absolute',\n            'left': '0px',\n            'top': '0px',\n            'width': previewBoxSize + 'px',\n            'height': previewBoxSize + 'px',\n            'z-index': '-1'\n        })\n        .appendTo($('body'));\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // Pattern can be dragged away\n                allowDrag: true,\n                // Pattern can be dropped in\n                allowDrop: true,\n                // Specifies the allowed types of patterns,\n                // null or zero length means accepting all\n                types: null\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n                var $this = $(this);\n\n                $this\n                    .data('gpatterntarget', {\n                        options: options,\n                        pattern: null\n                    });\n\n                if (options.allowDrag) {\n                    $this\n                        .attr('draggable', 'true')\n                        .on('dragstart', function (evt) {\n                            var event = evt.originalEvent;\n\n                            var pattern = $this.data('gpatterntarget').pattern;\n                            if (!pattern) {\n                                // No dragging without a pattern\n                                event.preventDefault();\n                                return;\n                            }\n                            event.stopPropagation();\n\n                            $this.trigger('patterndrag', pattern);\n\n                            // Create an invisible div with the pattern as background\n                            dragImage.css('background', IFPattern.asCSSBackground(pattern));\n\n                            // Setup our allowDrag-event now\n                            event.dataTransfer.effectAllowed = 'move';\n                            event.dataTransfer.setData(IFPattern.MIME_TYPE, IFPattern.asString(pattern));\n                            event.dataTransfer.setDragImage(dragImage[0], previewBoxSize / 2, previewBoxSize / 2);\n                            event.dataTransfer.sourceElement = this;\n                        })\n                        .on('dragend', function (evt) {\n                            var event = evt.originalEvent;\n                            event.stopPropagation();\n                        });\n                }\n\n                if (options.allowDrop) {\n                    $this\n                        .on('dragover', function (evt) {\n                            var event = evt.originalEvent;\n                            event.preventDefault();\n                            event.stopPropagation();\n                            evt.originalEvent.dataTransfer.dropEffect = 'move';\n                        })\n                        .on('drop', function (evt) {\n                            var event = evt.originalEvent;\n\n                            var source = event.dataTransfer.getData(IFPattern.MIME_TYPE);\n                            if (source) {\n                                source = IFPattern.parsePattern(source);\n                                if (source && (!options.types || options.types.length === 0 || options.types.indexOf(source.getPatternType()) >= 0)) {\n                                    var myPattern = $this.data('gpatterntarget').pattern;\n                                    if (!IFPattern.equals(source, myPattern)) {\n                                        methods.value.call(self, source);\n                                        $this.trigger('patternchange', source);\n                                    }\n\n                                    // allowDrop will always fire\n                                    $this.trigger('patterndrop', [source, event]);\n                                }\n                            }\n\n                            return false;\n                        });\n                }\n            });\n        },\n\n        value: function (value) {\n            var $this = $(this);\n            var data = $this.data('gpatterntarget');\n\n            if (!arguments.length) {\n                return data.pattern;\n            } else {\n                value = typeof value === 'string' ? IFPattern.parsePattern(value) : value;\n                data.pattern = value;\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Block to transform target into a pattern target which holds a pattern value\n     * and optionally supports allowDrag'n'allowDrop (out and in)\n     */\n    $.fn.gPatternTarget = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/pivot.js",
    "content": "(function ($) {\n\n    var methods = {\n        init: function (options) {\n            return this.each(function () {\n                var self = this;\n                var $this = $(this)\n                    .data('gpivot', {\n                        value: null\n                    })\n                    .addClass('g-pivot');\n\n                var _addSide = function (side) {\n                    $('<div></div>')\n                        .addClass('side')\n                        .attr('data-side', side)\n                        .on('click', function (evt) {\n                            methods.value.call(self, side);\n                            $this.trigger('pivotchange', side);\n                        })\n                        .appendTo($this);\n                };\n\n                // Add borderline\n                $('<div></div>')\n                    .addClass('borderline')\n                    .appendTo($this);\n\n                // Add button for each side\n                for (var side in IFRect.Side) {\n                    if (IFRect.Side.hasOwnProperty(side)) {\n                        var value = IFRect.Side[side];\n                        if (typeof value === 'string') {\n                            _addSide(value);\n                        }\n                    }\n                }\n            });\n        },\n\n        // = IFRect.Side\n        value: function (value) {\n            var $this = $(this);\n            var data = $this.data('gpivot');\n\n            if (!arguments.length) {\n                return data.value;\n            } else {\n                data.value = value;\n                $this.find('div[data-side]').each(function (index, element) {\n                    var $element = $(element);\n                    $element.toggleClass('g-active', $element.attr('data-side') === value);\n                });\n\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Converts a div into a pivot chooser panel\n     */\n    $.fn.gPivot = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/stylepanel.js",
    "content": "(function ($) {\n\n    function updateSelectedStyle($this, style) {\n        $this.find('.style-block').each(function (index, element) {\n            var $element = $(element);\n            $element\n                .toggleClass('selected', $element.data('style') === style);\n        });\n    };\n\n    function updatePlaceholder($this) {\n        var data = $this.data('gstylepanel');\n\n        if (data.options.placeholder) {\n            var placeholder = $this.find('.placeholder');\n            var blocks = $this.find('> .style-block');\n            if (blocks.length === 0) {\n                if (placeholder.length === 0) {\n                    placeholder = $('<div></div>')\n                        .addClass('placeholder')\n                        .text(data.options.placeholder)\n                        .appendTo($this);\n                }\n            } else {\n                if (placeholder.length > 0) {\n                    placeholder.remove();\n                }\n            }\n        }\n    }\n\n    function afterInsertEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gstylepanel').container;\n        if (evt.node instanceof IFStyle && evt.node.getParent() === container) {\n            methods.insertStyle.call(this, evt.node);\n        }\n    };\n\n    function beforeRemoveEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gstylepanel').container;\n        if (evt.node instanceof IFStyle && evt.node.getParent() === container) {\n            methods.removeStyle.call(this, evt.node);\n        }\n    };\n\n    function afterPropertiesChangeEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gstylepanel').container;\n        if (evt.node.getParent() === container) {\n            methods.updateStyle.call(this, evt.node);\n        }\n    };\n\n    function styleChangeEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gstylepanel').container;\n        if (evt.style.getParent() === container) {\n            methods.updateStyle.call(this, evt.style);\n        }\n    };\n\n    /** @type {IFStyle} */\n    var dragStyle = null;\n\n    function canDrop($this, target) {\n        var data = $this.data('gstylepanel');\n        if (dragStyle) {\n            var targetStyle = $(target).data('style');\n\n            if (targetStyle && (targetStyle !== dragStyle || ifPlatform.modifiers.shiftKey)) {\n                if (dragStyle.getParent() === targetStyle.getParent()) {\n                    return data.options.allowReorder;\n                } else {\n                    return data.options.allowDrop;\n                }\n            }\n        }\n\n        return false;\n    };\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // Whether to allow dragging of styles\n                allowDrag: true,\n                // Whether to allow dropping of styles\n                allowDrop: false,\n                // Whether to allow re-order of styles or not\n                allowReorder: true,\n                // Allow editing the style name or not\n                allowNameEdit: false,\n                // The html code or Jquery for the null style, if set to null,\n                // no null style will be provided for choosing\n                nullStyle: null,\n                // The name of the null style if any\n                nullName: null,\n                // The placeholder text if there's no content\n                placeholder: null,\n                // The width of the style preview\n                previewWidth: 30,\n                // The height of the style preview\n                previewHeight: 30\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n\n                var $this = $(this)\n                    .addClass('g-style-panel')\n                    .data('gstylepanel', {\n                        selected: null,\n                        options: options\n                    });\n\n                if (options.nullStyle) {\n                    $('<div></div>')\n                        .addClass('style-block style-null')\n                        .data('style', null)\n                        .attr('title', options.nullName ? options.nullName : '')\n                        .append($('<div></div>')\n                            .addClass('style-content')\n                            .append($('<div></div>')\n                                .addClass('style-preview')\n                                .append($('<div></div>')\n                                    .css({\n                                        'display': 'inline-block',\n                                        'width': options.previewWidth + 'px',\n                                        'height': options.previewHeight + 'px',\n                                        'line-height': options.previewHeight + 'px'\n                                    })\n                                    .append(options.nullStyle)))\n                            .append($('<div></div>')\n                                .addClass('style-name')\n                                .text(options.nullName ? options.nullName : '')))\n                        .on('click', function () {\n                            $this.data('gstylepanel').selected = null;\n                            updateSelectedStyle($this, null);\n                            $this.trigger('stylechange', null);\n                        })\n                        .appendTo($this);\n                }\n\n                updatePlaceholder($this);\n            });\n        },\n\n        insertStyle: function (style, index) {\n            var $this = $(this);\n            var data = $this.data('gstylepanel');\n            var self = this;\n\n            var insertBefore = null;\n\n            if (typeof index === 'number') {\n                if (data.options.nullStyle) {\n                    index += 1;\n                }\n                insertBefore = $this.children('.style-block').eq(index);\n            } else {\n                if (style.getNext()) {\n                    $this.find('.style-block').each(function (index, element) {\n                        var $element = $(element);\n                        if ($element.data('style') === style.getNext()) {\n                            insertBefore = $element;\n                            return false;\n                        }\n                    });\n                }\n            }\n\n            var block = $('<div></div>')\n                .addClass('style-block')\n                .data('style', style)\n                .append($('<div></div>')\n                    .addClass('style-content')\n                    .append($('<div></div>')\n                        .addClass('style-preview')\n                        .append($('<img>')))\n                    .append($('<div></div>')\n                        .addClass('style-name')))\n                .on('mousedown', function () {\n                    $this.data('gstylepanel').selected = style;\n                    updateSelectedStyle($this, style);\n                })\n                .on('click', function () {\n                    $this.trigger('stylechange', style);\n                });\n\n            if (data.options.allowNameEdit && style instanceof IFSharedStyle) {\n                block\n                    .gAutoEdit({\n                        selector: '.style-name'\n                    })\n                    .on('submitvalue', function (evt, value) {\n                        if (value && value.trim() !== '') {\n                            // TODO : I18N\n                            IFEditor.tryRunTransaction(style, function () {\n                                style.setProperty('name', value);\n                            }, 'Rename Style');\n                        }\n                    });\n            }\n\n            if (data.options.allowDrag || data.options.allowReorder) {\n                block\n                    .attr('draggable', 'true')\n                    .on('dragstart', function (evt) {\n                        var event = evt.originalEvent;\n                        event.stopPropagation();\n\n                        dragStyle = $(this).data('style');\n\n                        if (data.options.allowDrag) {\n                            $this.trigger('styledragstart', style);\n\n                            // Setup our drag-event now\n                            event.dataTransfer.effectAllowed = 'move';\n                            event.dataTransfer.setData(IFNode.MIME_TYPE, IFNode.serialize(style));\n                            event.dataTransfer.setDragImage(block.find('.style-preview > img')[0], data.options.previewWidth / 2, data.options.previewHeight / 2);\n                        }\n                    })\n                    .on('dragend', function (evt) {\n                        var event = evt.originalEvent;\n                        event.stopPropagation();\n\n                        dragStyle = null;\n\n                        if (data.options.allowDrag) {\n                            var offset = $this.offset();\n                            var width = $this.outerWidth();\n                            var height = $this.outerHeight();\n                            var x = event.pageX;\n                            var y = event.pageY;\n\n                            if (x <= offset.left || x >= offset.left + width ||\n                                y <= offset.top || y >= offset.top + height) {\n                                $this.trigger('styledragaway', style);\n                            } else {\n                                $this.trigger('styledragend', style);\n                            }\n                        }\n                    });\n            }\n\n            if (data.options.allowDrop || data.options.allowReorder) {\n                block\n                    .on('dragenter', function (evt) {\n                        if (canDrop($this, this)) {\n                            $(this).addClass('drop');\n                        }\n                    })\n                    .on('dragleave', function (evt) {\n                        if (canDrop($this, this)) {\n                            $(this).removeClass('drop');\n                        }\n                    })\n                    .on('dragover', function (evt) {\n                        var event = evt.originalEvent;\n                        if (canDrop($this, this)) {\n                            event.preventDefault();\n                            event.stopPropagation();\n                            event.dataTransfer.dropEffect = 'move';\n                        }\n                    })\n                    .on('drop', function (evt) {\n                        $(this).removeClass('drop');\n                        var targetStyle = $(this).data('style');\n\n                        if (data.options.allowReorder && dragStyle) {\n                            if (data.container && dragStyle.getParent() === data.container) {\n                                var parent = dragStyle.getParent();\n                                var sourceIndex = parent.getIndexOfChild(dragStyle);\n                                var targetIndex = parent.getIndexOfChild(targetStyle);\n\n                                // TODO : I18N\n                                IFEditor.tryRunTransaction(parent, function () {\n                                    if (ifPlatform.modifiers.shiftKey) {\n                                        // Clone style\n                                        var styleClone = dragStyle.clone();\n                                        styleClone.setProperty('name', styleClone.getProperty('name') + '-copy');\n                                        parent.insertChild(styleClone, sourceIndex < targetIndex ? targetStyle.getNext() : targetStyle);\n                                    } else {\n                                        parent.removeChild(dragStyle);\n                                        parent.insertChild(dragStyle, sourceIndex < targetIndex ? targetStyle.getNext() : targetStyle);\n                                    }\n                                }, ifPlatform.modifiers.shiftKey ? 'Duplicate Style' : 'Move Style');\n                            }\n\n                            $this.trigger('stylemove', [dragStyle, targetStyle]);\n                        } else if (data.options.allowDrop) {\n                            $this.trigger('styledrop', [dragStyle, targetStyle, ]);\n                        }\n                    });\n            }\n\n            if (insertBefore && insertBefore.length > 0) {\n                block.insertBefore(insertBefore);\n            } else {\n                block.appendTo($this);\n            }\n\n            updatePlaceholder($this);\n\n            methods.updateStyle.call(this, style);\n        },\n\n        updateStyle: function (style) {\n            var $this = $(this);\n            var data = $this.data('gstylepanel');\n\n            $this.find('.style-block').each(function (index, element) {\n                var $element = $(element);\n                if ($element.data('style') === style) {\n                    $element\n                        .find('.style-preview > img')\n                        .attr('src', style.createPreviewImage(data.options.previewWidth, data.options.previewHeight));\n\n                    var name = '';\n                    if (style instanceof IFSharedStyle) {\n                        name = style.getProperty('name');\n                    }\n\n                    $element.attr('title', name);\n                    $element.find('.style-name').text(name);\n                    return false;\n                }\n            });\n        },\n\n        removeStyle: function (style) {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('gstylepanel');\n\n            $this.find('.style-block').each(function (index, element) {\n                var $element = $(element);\n                if ($element.data('style') === style) {\n                    $element.remove();\n\n                    if (style === data.selected) {\n                        data.selected = null;\n                        $this.trigger('stylechange', null);\n                    }\n\n                    updatePlaceholder($this);\n                    return false;\n                }\n            });\n        },\n\n        clear: function () {\n            var $this = $(this);\n            var data = $this.data('gstylepanel');\n            var remove = [];\n\n            $this.find('.style-block').each(function (index, block) {\n                var $block = $(block);\n                if (!$block.hasClass('style-null')) {\n                    remove.push($block);\n                }\n            });\n\n            for (var i = 0; i < remove.length; ++i) {\n                remove[i].remove();\n            }\n\n            updatePlaceholder($this);\n        },\n\n        attach: function (container) {\n            var $this = $(this);\n            var data = $this.data('gstylepanel');\n\n            methods.detach.call(this);\n\n            data.container = container;\n\n            if (container) {\n                for (var child = container.getFirstChild(); child !== null; child = child.getNext()) {\n                    if (child instanceof IFStyle) {\n                        methods.insertStyle.call(this, child);\n                    }\n                }\n\n                // Subscribe to container\n                var scene = container.getScene();\n                if (scene) {\n                    data.afterInsertHandler = afterInsertEvent.bind(this);\n                    data.beforeRemoveHandler = beforeRemoveEvent.bind(this);\n                    data.styleChangeHandler = styleChangeEvent.bind(this);\n                    data.afterPropertiesChangeHandler = afterPropertiesChangeEvent.bind(this);\n                    scene.addEventListener(IFNode.AfterInsertEvent, data.afterInsertHandler);\n                    scene.addEventListener(IFNode.BeforeRemoveEvent, data.beforeRemoveHandler);\n                    scene.addEventListener(IFNode.AfterPropertiesChangeEvent, data.afterPropertiesChangeHandler);\n                    scene.addEventListener(IFStyle.StyleChangeEvent, data.styleChangeHandler);\n                }\n            }\n            return this;\n        },\n\n        detach: function () {\n            var $this = $(this);\n            var data = $this.data('gstylepanel');\n            var container = data.container;\n\n            if (container) {\n                // Unsubscribe from container\n                var scene = container.getScene();\n                if (scene) {\n                    scene.removeEventListener(IFNode.AfterInsertEvent, data.afterInsertHandler);\n                    scene.removeEventListener(IFNode.BeforeRemoveEvent, data.beforeRemoveHandler);\n                    scene.removeEventListener(IFNode.AfterPropertiesChangeEvent, data.afterPropertiesChangeHandler);\n                    scene.removeEventListener(IFStyle.StyleChangeEvent, data.styleChangeHandler);\n                }\n            }\n\n            data.container = null;\n            data.afterInsertHandler = null;\n            data.beforeRemoveHandler = null;\n            data.afterPropertiesChangeHandler = null;\n            data.styleChangeHandler = null;\n\n            methods.clear.call(this);\n\n            return this;\n        },\n\n        // Assigns or returns the selected style\n        value: function (value) {\n            var $this = $(this);\n            if (!arguments.length) {\n                return $this.data('gstylepanel').selected;\n            } else {\n                $this.data('gstylepanel').selected = value;\n                updateSelectedStyle($this, value);\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Block to transform divs to style panels\n     */\n    $.fn.gStylePanel = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/swatchpanel.js",
    "content": "(function ($) {\n\n    function updateSelectedSwatch($this, swatch) {\n        if ($this.data('gswatchpanel').options.allowSelect) {\n            $this.find('.swatch-block').each(function (index, element) {\n                var $element = $(element);\n                $element\n                    .toggleClass('selected', $element.data('swatch') === swatch);\n            });\n        }\n    };\n\n    function updatePlaceholder($this) {\n        var data = $this.data('gswatchpanel');\n\n        if (data.options.placeholder) {\n            var placeholder = $this.find('.placeholder');\n            var blocks = $this.find('> .swatch-block');\n            if (blocks.length === 0) {\n                if (placeholder.length === 0) {\n                    placeholder = $('<div></div>')\n                        .addClass('placeholder')\n                        .text(data.options.placeholder)\n                        .appendTo($this);\n                }\n            } else {\n                if (placeholder.length > 0) {\n                    placeholder.remove();\n                }\n            }\n        }\n    }\n\n    function afterInsertEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gswatchpanel').container;\n        if (evt.node instanceof IFSwatch && evt.node.getParent() === container) {\n            methods.insertSwatch.call(this, evt.node);\n        }\n    };\n\n    function beforeRemoveEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gswatchpanel').container;\n        if (evt.node instanceof IFSwatch && evt.node.getParent() === container) {\n            methods.removeSwatch.call(this, evt.node);\n        }\n    };\n\n    function afterPropertiesChangeEvent(evt) {\n        var $this = $(this);\n        var container = $this.data('gswatchpanel').container;\n        if (evt.node.getParent() === container) {\n            methods.updateSwatch.call(this, evt.node);\n        }\n    };\n\n    /** @type {IFSwatch} */\n    var dragSwatch = null;\n\n    function canDrop($this, target) {\n        var data = $this.data('gswatchpanel');\n        if (dragSwatch) {\n            var targetSwatch = $(target).data('swatch');\n\n            if (targetSwatch && targetSwatch !== dragSwatch) {\n                if (dragSwatch.getParent() === targetSwatch.getParent()) {\n                    return data.options.allowReorder;\n                } else {\n                    return data.options.allowDrop;\n                }\n            }\n        }\n\n        return false;\n    };\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n                // Types of swatches to be shown, if null or empty,\n                // all types will be shown\n                types: null,\n                // Whether to allow dragging of swatches\n                allowDrag: true,\n                // Whether to allow dropping of swatches\n                allowDrop: false,\n                // Whether to allow re-order of swatches or not\n                allowReorder: true,\n                // Whether to allow selecting or not\n                allowSelect: true,\n                // Allow editing the swatch name or not\n                allowNameEdit: false,\n                // The html code or Jquery for the null swatch, if set to null,\n                // no null swatch will be provided for choosing\n                nullSwatch: null,\n                // The name of the null swatch if any\n                nullName: null,\n                // The placeholder text if there's no content\n                placeholder: null,\n                // The width of the swatch preview\n                previewWidth: 20,\n                // The height of the swatch preview\n                previewHeight: 20\n            }, options);\n\n            return this.each(function () {\n                var self = this;\n                var $this = $(this)\n                    .addClass('g-swatch-panel')\n                    .data('gswatchpanel', {\n                        selected: null,\n                        options: options\n                    })\n                    .on('dragover', function (evt) {\n                        var event = evt.originalEvent;\n                        event.preventDefault();\n                        event.stopPropagation();\n                        event.dataTransfer.dropEffect = 'move';\n                    })\n                    .on('drop', function (evt) {\n                        var data = $this.data('gswatchpanel');\n\n                        var event = evt.originalEvent;\n                        event.stopPropagation();\n\n                        if (dragSwatch || !data.container || !data.container.getScene()) {\n                            dragSwatch = null;\n                            return;\n                        }\n\n                        var scene = data.container.getScene();\n                        var sourcePattern = event.dataTransfer.getData(IFPattern.MIME_TYPE);\n                        if (sourcePattern) {\n                            var pattern = IFPattern.parsePattern(sourcePattern);\n                            if (pattern) {\n                                // Make sure there's no such swatch, yet\n                                var swatches = scene.getSwatchCollection();\n                                for (var node = swatches.getFirstChild(); node !== null; node = node.getNext()) {\n                                    if (node instanceof IFSwatch) {\n                                        if (IFPattern.equals(pattern, node.getProperty('pat'))) {\n                                            return; // leave here, patterns are equal\n                                        }\n                                    }\n                                }\n\n                                // Ask for a name\n                                // TODO : I18N\n                                var sourceName = pattern instanceof IFColor ? pattern.asString() : 'pattern';\n                                var name = prompt('Enter a name for the new swatch:', sourceName);\n                                if (name === null) {\n                                    return; // leave here, user has canceled\n                                }\n                                if (name.trim() === '') {\n                                    name = sourceName;\n                                }\n\n                                // Add pattern as swatch\n                                // TODO : I18N\n                                IFEditor.tryRunTransaction(scene, function () {\n                                    var swatch = new IFSwatch();\n                                    swatch.setProperties(['name', 'pat'], [name, pattern]);\n                                    swatches.appendChild(swatch);\n                                }, 'Add Swatch');\n                            }\n                        }\n                    });\n\n                if (options.nullSwatch) {\n                    $('<div></div>')\n                        .addClass('swatch-block swatch-null')\n                        .data('swatch', null)\n                        .attr('title', options.nullName ? options.nullName : '')\n                        .append($('<div></div>')\n                            .addClass('swatch-content')\n                            .append($('<div></div>')\n                                .addClass('swatch-preview')\n                                .append($('<div></div>')\n                                    .css({\n                                        'width': options.previewWidth + 'px',\n                                        'height': options.previewHeight + 'px',\n                                        'line-height': options.previewHeight + 'px'\n                                    })\n                                    .append(options.nullSwatch)))\n                            .append($('<div></div>')\n                                .addClass('swatch-name')\n                                .text(options.nullName ? options.nullName : '')))\n                        .on('click', function () {\n                            $this.data('gswatchpanel').selected = null;\n                            updateSelectedSwatch($this, null);\n                            $this.trigger('swatchchange', null);\n                        })\n                        .appendTo($this);\n                }\n\n                updatePlaceholder($this);\n            });\n        },\n\n        insertSwatch: function (swatch, index) {\n            var $this = $(this);\n            var data = $this.data('gswatchpanel');\n            var self = this;\n\n            // don't add if type is not right\n            var types = data.options.types;\n            if (types !== null && types.length > 0 && types.indexOf(swatch.getPatternType()) < 0) {\n                return;\n            }\n\n            var insertBefore = null;\n\n            if (typeof index === 'number') {\n                if (data.options.nullSwatch) {\n                    index += 1;\n                }\n                insertBefore = $this.children('.swatch-block').eq(index);\n            } else {\n                if (swatch.getNext()) {\n                    $this.find('.swatch-block').each(function (index, element) {\n                        var $element = $(element);\n                        if ($element.data('swatch') === swatch.getNext()) {\n                            insertBefore = $element;\n                            return false;\n                        }\n                    });\n                }\n            }\n\n            var block = $('<div></div>')\n                .addClass('swatch-block')\n                .data('swatch', swatch)\n                .append($('<div></div>')\n                    .addClass('swatch-content')\n                    .append($('<div></div>')\n                        .addClass('swatch-preview')\n                        .append($('<div></div>')\n                            .css({\n                                'width': data.options.previewWidth + 'px',\n                                'height': data.options.previewHeight + 'px'\n                            })))\n                    .append($('<div></div>')\n                        .addClass('swatch-name')))\n                .on('mousedown', function () {\n                    $this.data('gswatchpanel').selected = swatch;\n                    updateSelectedSwatch($this, swatch);\n                })\n                .on('click', function () {\n                    $this.trigger('swatchchange', swatch);\n                });\n\n            if (data.options.allowNameEdit) {\n                block\n                    .gAutoEdit({\n                        selector: '.swatch-name'\n                    })\n                    .on('submitvalue', function (evt, value) {\n                        if (value && value.trim() !== '') {\n                            // TODO : I18N\n                            IFEditor.tryRunTransaction(swatch, function () {\n                                swatch.setProperty('name', value);\n                            }, 'Rename Swatch');\n                        }\n                    });\n            }\n\n            if (data.options.allowDrag || data.options.allowReorder) {\n                block\n                    .attr('draggable', 'true')\n                    .on('dragstart', function (evt) {\n                        var event = evt.originalEvent;\n                        event.stopPropagation();\n\n                        dragSwatch = $(this).data('swatch');\n                        var pattern = dragSwatch.getProperty('pat');\n                        if (!pattern) {\n                            event.preventDefault();\n                            return;\n                        }\n\n                        if (data.options.allowDrag) {\n                            $this.trigger('swatchdragstart', dragSwatch);\n\n                            // Setup our drag-event now\n                            event.dataTransfer.effectAllowed = 'move';\n                            event.dataTransfer.setData(IFPattern.MIME_TYPE, IFPattern.asString(pattern));\n                            event.dataTransfer.setDragImage(block.find('.swatch-preview > div')[0], data.options.previewWidth / 2, data.options.previewHeight / 2);\n                        }\n                    })\n                    .on('dragend', function (evt) {\n                        var event = evt.originalEvent;\n                        event.stopPropagation();\n\n                        dragSwatch = null;\n\n                        if (data.options.allowDrag) {\n                            var offset = $this.offset();\n                            var width = $this.outerWidth();\n                            var height = $this.outerHeight();\n                            var x = event.pageX;\n                            var y = event.pageY;\n\n                            if (x <= offset.left || x >= offset.left + width ||\n                                y <= offset.top || y >= offset.top + height) {\n                                $this.trigger('swatchdragaway', swatch);\n                            } else {\n                                $this.trigger('swatchdragend', swatch);\n                            }\n                        }\n                    });\n            }\n\n            if (data.options.allowDrop || data.options.allowReorder) {\n                block\n                    .on('dragenter', function (evt) {\n                        if (canDrop($this, this)) {\n                            $(this).addClass('drop');\n                        }\n                    })\n                    .on('dragleave', function (evt) {\n                        if (canDrop($this, this)) {\n                            $(this).removeClass('drop');\n                        }\n                    })\n                    .on('dragover', function (evt) {\n                        var event = evt.originalEvent;\n                        if (canDrop($this, this)) {\n                            event.preventDefault();\n                            event.stopPropagation();\n                            event.dataTransfer.dropEffect = 'move';\n                        }\n                    })\n                    .on('drop', function (evt) {\n                        $(this).removeClass('drop');\n                        var targetSwatch = $(this).data('swatch');\n\n                        if (dragSwatch) {\n                            if (data.options.allowReorder) {\n                                if (data.container && dragSwatch.getParent() === data.container) {\n                                    var parent = dragSwatch.getParent();\n                                    var sourceIndex = parent.getIndexOfChild(dragSwatch);\n                                    var targetIndex = parent.getIndexOfChild(targetSwatch);\n\n                                    IFEditor.tryRunTransaction(parent, function () {\n                                        parent.removeChild(dragSwatch);\n                                        parent.insertChild(dragSwatch, sourceIndex < targetIndex ? targetSwatch.getNext() : targetSwatch);\n                                    }, 'Move Swatch');\n                                }\n\n                                $this.trigger('swatchmove', [dragSwatch, targetSwatch]);\n                            } else if (data.options.allowDrop) {\n                                $this.trigger('swatchdrop', [dragSwatch, targetSwatch]);\n                            }\n                        }\n                    });\n            }\n\n            if (insertBefore && insertBefore.length > 0) {\n                block.insertBefore(insertBefore);\n            } else {\n                block.appendTo($this);\n            }\n\n            updatePlaceholder($this);\n\n            methods.updateSwatch.call(this, swatch);\n        },\n\n        updateSwatch: function (swatch) {\n            var $this = $(this);\n            var data = $this.data('gswatchpanel');\n\n            $this.find('.swatch-block').each(function (index, element) {\n                var $element = $(element);\n                if ($element.data('swatch') === swatch) {\n                    $element\n                        .find('.swatch-preview > div')\n                        .css('background', IFPattern.asCSSBackground(swatch.getProperty('pat')));\n\n                    var name = swatch.getProperty('name');\n\n                    $element.attr('title', name);\n                    $element.find('.swatch-name').text(name);\n                    return false;\n                }\n            });\n        },\n\n        removeSwatch: function (swatch) {\n            var self = this;\n            var $this = $(this);\n            var data = $this.data('gswatchpanel');\n\n            $this.find('.swatch-block').each(function (index, element) {\n                var $element = $(element);\n                if ($element.data('swatch') === swatch) {\n                    $element.remove();\n\n                    if (swatch === data.selected) {\n                        data.selected = null;\n                        $this.trigger('swatchchange', null);\n                    }\n\n                    updatePlaceholder($this);\n                    return false;\n                }\n            });\n        },\n\n        clear: function () {\n            var $this = $(this);\n            var data = $this.data('gswatchpanel');\n            var remove = [];\n\n            $this.find('.swatch-block').each(function (index, block) {\n                var $block = $(block);\n                if (!$block.hasClass('swatch-null')) {\n                    remove.push($block);\n                }\n            });\n\n            for (var i = 0; i < remove.length; ++i) {\n                remove[i].remove();\n            }\n\n            updatePlaceholder($this);\n        },\n\n        attach: function (container) {\n            var $this = $(this);\n            var data = $this.data('gswatchpanel');\n\n            methods.detach.call(this);\n\n            data.container = container;\n\n            if (container) {\n                for (var child = container.getFirstChild(); child !== null; child = child.getNext()) {\n                    if (child instanceof IFSwatch) {\n                        methods.insertSwatch.call(this, child);\n                    }\n                }\n\n                // Subscribe to container\n                var scene = container.getScene();\n                if (scene) {\n                    data.afterInsertHandler = afterInsertEvent.bind(this);\n                    data.beforeRemoveHandler = beforeRemoveEvent.bind(this);\n                    data.afterPropertiesChangeHandler = afterPropertiesChangeEvent.bind(this);\n                    scene.addEventListener(IFNode.AfterInsertEvent, data.afterInsertHandler);\n                    scene.addEventListener(IFNode.BeforeRemoveEvent, data.beforeRemoveHandler);\n                    scene.addEventListener(IFNode.AfterPropertiesChangeEvent, data.afterPropertiesChangeHandler);\n                }\n            }\n            return this;\n        },\n\n        detach: function () {\n            var $this = $(this);\n            var data = $this.data('gswatchpanel');\n            var container = data.container;\n\n            if (container) {\n                // Unsubscribe from container\n                var scene = container.getScene();\n                if (scene) {\n                    scene.removeEventListener(IFNode.AfterInsertEvent, data.afterInsertHandler);\n                    scene.removeEventListener(IFNode.BeforeRemoveEvent, data.beforeRemoveHandler);\n                    scene.removeEventListener(IFNode.AfterPropertiesChangeEvent, data.afterPropertiesChangeHandler);\n                }\n            }\n\n            data.container = null;\n            data.afterInsertHandler = null;\n            data.beforeRemoveHandler = null;\n            data.afterPropertiesChangeHandler = null;\n\n            methods.clear.call(this);\n\n            return this;\n        },\n\n        // Assigns or returns the selected swatch\n        value: function (value) {\n            var $this = $(this);\n            if (!arguments.length) {\n                return $this.data('gswatchpanel').selected;\n            } else {\n                $this.data('gswatchpanel').selected = value;\n                updateSelectedSwatch($this, value);\n                return this;\n            }\n        }\n    };\n\n    /**\n     * Block to transform divs to swatch panels\n     */\n    $.fn.gSwatchPanel = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/component/unit.js",
    "content": "(function ($) {\n\n    var units = [\n        {\n            unit: IFLength.Unit.PX,\n            // TODO : I18N\n            name: 'Pixels'\n        },\n        {\n            unit: IFLength.Unit.MM,\n            // TODO : I18N\n            name: 'Millimeters'\n        },\n        {\n            unit: IFLength.Unit.CM,\n            // TODO : I18N\n            name: 'Centimeters'\n        },\n        {\n            unit: IFLength.Unit.IN,\n            // TODO : I18N\n            name: 'Inches'\n        },\n        {\n            unit: IFLength.Unit.PC,\n            // TODO : I18N\n            name: 'Picas'\n        },\n        {\n            unit: IFLength.Unit.PT,\n            // TODO : I18N\n            name: 'Points'\n        }\n    ];\n\n    var methods = {\n        init: function (options) {\n            options = $.extend({\n            }, options);\n\n            return this.each(function () {\n                var $this = $(this);\n                if ($this.is(\"select\")) {\n                    for (var i = 0; i < units.length; ++i) {\n                        $this.append($('<option></option>')\n                            .attr('value', units[i].unit)\n                            .text(units[i].name));\n                    }\n                }\n            });\n        }\n    };\n\n    /**\n     * Adds a translated list of units to a selection that\n     * represents the IFLength.Unit choices\n     */\n    $.fn.gUnit = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.myPlugin');\n        }\n    }\n\n}(jQuery));"
  },
  {
    "path": "src/application/document.js",
    "content": "(function (_) {\n    /**\n     * An instance of an opened document\n     * @class GDocument\n     * @extends GEventTarget\n     * @constructor\n     */\n    function GDocument(scene, url, title) {\n        this.setUrl(url);\n        this._scene = scene;\n        this._editor = new IFEditor(scene);\n        this._windows = [];\n        this._activeWindow = null;\n        // TODO : I18N\n        this._title = title;\n\n        // Provide an url resolver to our scene\n        this._scene.addEventListener(IFScene.ResolveUrlEvent, this._resolveUrl, this);\n    };\n    IFObject.inherit(GDocument, GEventTarget);\n\n    /**\n     * The underlying scene\n     * @type {IFScene}\n     * @private\n     */\n    GDocument.prototype._scene = null;\n\n    /**\n     * The underlying url, may be null\n     * @type {String}\n     * @private\n     */\n    GDocument.prototype._url = null;\n\n    /**\n     * The underlying editor working on the document\n     * @type {IFSceneEditor}\n     * @private\n     */\n    GDocument.prototype._editor = null;\n\n    /**\n     * The windows attached to the document\n     * @type {Array<GWindow>}\n     * @private\n     */\n    GDocument.prototype._windows = null;\n\n    /**\n     * The currently active window of this document\n     * @type {GWindow}\n     * @private\n     */\n    GDocument.prototype._activeWindow = null;\n\n    /**\n     * The title of the document\n     * @type {String}\n     * @private\n     */\n    GDocument.prototype._title = null;\n\n    /**\n     * Returns the scene this document is working on\n     * @returns {IFScene}\n     */\n    GDocument.prototype.getScene = function () {\n        return this._scene;\n    };\n\n    /**\n     * Return the underlying storage if any\n     * @returns {GStorage}\n     */\n    GDocument.prototype.getStorage = function () {\n        return this._storage;\n    };\n\n    /**\n     * Returns the url this document is working on if any\n     * @returns {String}\n     */\n    GDocument.prototype.getUrl = function () {\n        return this._url;\n    };\n\n    /**\n     * Assigns an url this document is working on\n     * @param {String} url\n     */\n    GDocument.prototype.setUrl = function (url) {\n        if (url !== this._url) {\n            if (this._storage) {\n                this._storage.releaseUrl(this._url);\n            }\n\n            this._url = url;\n            this._storage = url ? gApp.getStorage(url) : null;\n        }\n    };\n\n    /**\n     * Return the underlying editor\n     * @returns {IFSceneEditor}\n     */\n    GDocument.prototype.getEditor = function () {\n        return this._editor;\n    };\n\n    /**\n     * Returns a list of all windows attached to this document\n     * @return {Array<GWindow>}\n     */\n    GDocument.prototype.getWindows = function () {\n        return this._windows;\n    };\n\n    /**\n     * Returns the currently active window of this document\n     * @return {GWindow}\n     */\n    GDocument.prototype.getActiveWindow = function () {\n        return this._activeWindow;\n    };\n\n    /**\n     * Returns the title for the document\n     * @return {String}\n     */\n    GDocument.prototype.getTitle = function () {\n        return this._title;\n    };\n\n    /**\n     * Returns whether this document is saveable which\n     * is the case if it has an underyling, valid url\n     * and when it's internal editor's undo list has\n     * modifications.\n     * @return {Boolean}\n     */\n    GDocument.prototype.isSaveable = function () {\n        return !!this._storage;\n    };\n\n    /**\n     * Saves the document if it has an underlying url\n     */\n    GDocument.prototype.save = function () {\n        // TODO : Reset undo list/set save point\n        if (this._url) {\n            var input = IFNode.serialize(this._scene);\n            var output = pako.gzip(input, {level:9});\n            this._storage.save(this._url, output.buffer, true, function (name) {\n                this._title = name;\n            }.bind(this));\n        }\n    };\n\n    /**\n     * Create and returns a new page\n     * @param {Boolean} [noUndo] if set, no undo takes place for adding the page\n     * @return {IFPage}\n     */\n    GDocument.prototype.createNewPage = function (noUndo) {\n        var scene = this._scene;\n        var insertPos = this._scene.getPageInsertPosition();\n\n        // Create page\n        var page = new IFPage();\n        page.setProperties([\n            'name',\n            'x',\n            'y',\n            'w',\n            'h',\n            'cls'\n        ], [\n            'Page ' + (scene.queryCount('> page') + 1).toString(),\n            insertPos.getX(),\n            insertPos.getY(),\n            800,\n            600,\n            IFColor.WHITE\n        ]);\n\n        // Add default layer\n        var layer = new IFLayer();\n        // TODO : I18N\n        layer.setProperties(['name'], ['Background']);\n        page.appendChild(layer);\n\n        var addPageFunc = function () {\n            scene.appendChild(page);\n            scene.setActiveLayer(layer);\n        }\n\n        if (!noUndo) {\n            // TODO : I18N\n            IFEditor.tryRunTransaction(scene, addPageFunc, 'Add new Page');\n        } else {\n            addPageFunc();\n        }\n\n        return page;\n    };\n\n    /**\n     * Called before this document gets activated\n     */\n    GDocument.prototype.activate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called before this document gets deactivated\n     */\n    GDocument.prototype.deactivate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called when this document gets released\n     */\n    GDocument.prototype.release = function () {\n        this._editor.release();\n\n        this._scene.removeEventListener(IFScene.ResolveUrlEvent, this._resolveUrl, this);\n\n        if (this._storage) {\n            this._storage.releaseUrl(this._url);\n        }\n    };\n\n    /**\n     * @param {IFScene.ResolveUrlEvent} evt\n     * @private\n     */\n    GDocument.prototype._resolveUrl = function (evt) {\n        var uri = new URI(evt.url);\n        if (uri.protocol().length === 0) {\n            // make absolute to ourself first\n            uri = uri.absoluteTo(this._url);\n        }\n\n        if (uri.protocol().length > 0) {\n            var storage = gApp.getStorage(uri.protocol() + ':');\n            if (storage) {\n                storage.resolveUrl(uri.toString(), evt.resolved);\n            }\n        }\n    };\n\n    _.GDocument = GDocument;\n})(this);\n"
  },
  {
    "path": "src/application/extension/action.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for an action\n     * @class GAction\n     * @extends IFObject\n     * @constructor\n     */\n    function GAction() {\n    };\n    IFObject.inherit(GAction, IFObject);\n\n    /**\n     * Get the id of the action\n     * @return {String}\n     * @version 1.0\n     */\n    GAction.prototype.getId = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /**\n     * Get the title of the action\n     * @return {IFLocale.Key|String}\n     * @version 1.0\n     */\n    GAction.prototype.getTitle = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /**\n     * Get the category of the action,\n     * returns null by default\n     * @return {IFLocale.Key|String}\n     * @version 1.0\n     */\n    GAction.prototype.getCategory = function () {\n        return null;\n    };\n\n    /**\n     * Get the group of the action\n     * @return {String}\n     * @version 1.0\n     */\n    GAction.prototype.getGroup = function () {\n        return null;\n    };\n\n    /**\n     * Get the default shortcut of the action\n     * @return {Array<Number>}\n     * @version 1.0\n     */\n    GAction.prototype.getShortcut = function () {\n        return null;\n    };\n\n    /**\n     * Get the enabled status of the action\n     * @return {Boolean} true if enabled, false if not\n     * @version 1.0\n     */\n    GAction.prototype.isEnabled = function () {\n        // Enabled by default\n        return true;\n    };\n\n    /**\n     * Whether this action is checkable or not\n     * @return {Boolean} true if checkable, false if not\n     */\n    GAction.prototype.isCheckable = function () {\n        // Not checkable by default\n        return false;\n    };\n\n    /**\n     * Get the checked status of the action\n     * @return {Boolean} true if checked, false if not\n     * @version 1.0\n     */\n    GAction.prototype.isChecked = function () {\n        // Not checked by default\n        return false;\n    };\n\n    /**\n     * Called to check if the action is available or not\n     * @return {Boolean} true if available, false if not\n     */\n    GAction.prototype.isAvailable = function () {\n        // Available by default\n        return true;\n    };\n\n    /**\n     * Execute the action\n     * @version 1.0\n     */\n    GAction.prototype.execute = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /** @override */\n    GAction.prototype.toString = function () {\n        return \"[Object GAction]\";\n    };\n\n    _.GAction = GAction;\n})(this);"
  },
  {
    "path": "src/application/extension/colormatcher.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for a color matcher\n     * @class GColorMatcher\n     * @constructor\n     */\n    function GColorMatcher() {\n    };\n\n    GColorMatcher.CATEGORY_HARMONY = new IFLocale.Key(GColorMatcher, \"category.harmony\");\n    GColorMatcher.CATEGORY_PALETTE = new IFLocale.Key(GColorMatcher, \"category.palette\");\n\n    /**\n     * Get the title of the matcher\n     * @return {String|IFLocale.Key}\n     */\n    GColorMatcher.prototype.getTitle = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /**\n     * Get the category of the matcher\n     * @return {String|IFLocale.Key}\n     */\n    GColorMatcher.prototype.getCategory = function () {\n        return null;\n    };\n\n    /**\n     * Called to match and return an array of matching\n     * colors. Note that more than eight colors will be cut off.\n     * Returning null or empty array will ignore the call.\n     * @param {IFColor} referenceColor a reference color\n     * used for matching\n     * @return {Array<IFColor>}\n     */\n    GColorMatcher.prototype.match = function (referenceColor) {\n        throw new Error(\"Not Supported\");\n    };\n\n    /** @override */\n    GColorMatcher.prototype.toString = function () {\n        return \"[Object GColorMatcher]\";\n    };\n\n    _.GColorMatcher = GColorMatcher;\n})(this);"
  },
  {
    "path": "src/application/extension/exporter.js",
    "content": "(function (_) {\n    /**\n     * The base for an exporter\n     * @class GExporter\n     * @constructor\n     */\n    function GExporter() {\n    };\n\n    /**\n     * @param {String} size ?|({Number}[{Unit|x|w|h}])[@?|({Number}[{Unit|x}])]\n     * @return {{width: Number|IFLength, height: Number|IFLength}}\n     */\n    GExporter.parseSize = function (size) {\n        var width = null;\n        var height = null;\n\n        var wh = size.split('@');\n\n        var _parseValue = function (value) {\n            if (value === '?') {\n                return null;\n            }\n\n            var number = ifUtil.parseNumber(value);\n            if (typeof number != \"number\") {\n                return null;\n            }\n\n            var unitStr = value.substr(number.toString().length);\n            if (unitStr && unitStr.length > 0) {\n                unitStr = unitStr.trim().toLowerCase();\n                if (unitStr === 'x') {\n                    return number;\n                }\n            }\n\n            return IFLength.parseLength(value);\n        }\n\n        var width = null;\n        var height = null;\n\n        switch (wh[0].charAt(wh[0].length - 1)) {\n            case 'w':\n            case 'W':\n                width = _parseValue(wh[0].substr(0, wh[0].length - 1));\n                break;\n            case 'h':\n            case 'H':\n                height = _parseValue(wh[0].substr(0, wh[0].length - 1));\n                break;\n            default:\n                width = _parseValue(wh[0]);\n                if (wh.length > 1) {\n                    height = _parseValue(wh[1]);\n                }\n        }\n\n        return {\n            width: width,\n            height: height\n        }\n    };\n\n    /**\n     * Returns whether this exporter only exports a whole scene\n     * or can also export individual parts of it\n     */\n    GExporter.prototype.isStandalone = function () {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * The name of the exporter\n     */\n    GExporter.prototype.getName = function () {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * The extensions this export filter produces like ['png', 'jpg'].\n     * Ensure to always return extensions in lower-case only!\n     * @return {Array<String>} the extension\n     */\n    GExporter.prototype.getExtensions = function () {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Called to let the exporter export a part. This will never be\n     * called when the exporter is standalone only\n     * @param {IFElement} part the part to be exported\n     * @param {String} size desired see. See GExporter.parseSize\n     * @param {GStorage} storage the storage to be used for storing\n     * @param {String} url the url to store the part within the storage\n     * @param {String} extension the extension to be used, this is one\n     * of the extensions supplied by this exporter\n     */\n    GExporter.prototype.exportPart = function (part, size, storage, url, extension) {\n        throw new Error('Not Supported.');\n    };\n\n    _.GExporter = GExporter;\n})(this);\n"
  },
  {
    "path": "src/application/extension/module.js",
    "content": "(function (_) {\n    /**\n     * The base for a module\n     * @class GModule\n     * @constructor\n     * @version 1.0\n     */\n    function GModule() {\n    };\n\n    /**\n     * Called whenever the module should initialize itself now\n     */\n    GModule.prototype.init = function () {\n        // NO-OP\n    };\n\n    _.GModule = GModule;\n})(this);\n"
  },
  {
    "path": "src/application/extension/palette.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for an palette\n     * @class GPalette\n     * @extends GView\n     * @constructor\n     */\n    function GPalette() {\n        GView.call(this);\n    };\n    IFObject.inherit(GPalette, GView);\n\n    /**\n     * Get the default group of the palette, null for none\n     * @return {String}\n     */\n    GPalette.prototype.getGroup = function () {\n        return null;\n    };\n\n    /**\n     * Whether the palette is enabled or. Note that this\n     * will only disable the palette's panel so if the\n     * palette provides a custom menu, the enabled status\n     * of those needs to be manually managed by the palette.\n     * @return {Boolean}\n     */\n    GPalette.prototype.isEnabled = function () {\n        return true;\n    };\n\n    /**\n     * Called to let the palette initialize on a given panel\n     * and within a given menu if any\n     * @param {JQuery} htmlElement the panel to put the palette into\n     * @param {JQuery} controls the controls to add controls into\n     */\n    GPalette.prototype.init = function (htmlElement, controls) {\n        gApp.addEventListener(GApplication.DocumentEvent, this._documentEvent, this);\n    };\n\n    /** @override */\n    GPalette.prototype.toString = function () {\n        return \"[Object GPalette]\";\n    };\n\n    _.GPalette = GPalette;\n})(this);"
  },
  {
    "path": "src/application/extension/panel.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for an panel\n     * @class GPanel\n     * @extends GView\n     * @constructor\n     */\n    function GPanel() {\n        GView.call(this);\n    };\n    IFObject.inherit(GPanel, GView);\n\n    /**\n     * Get the title of the panel\n     * @return {String|IFLocale.Key}\n     */\n    GPanel.prototype.getTitle = function () {\n        return null;\n    };\n\n    /**\n     * Called to let the panel initialize on a given panel\n     * @param {JQuery} htmlElement the panel to put the panel into\n     */\n    GPanel.prototype.init = function (htmlElement) {\n        gApp.addEventListener(GApplication.DocumentEvent, this._documentEvent, this);\n    };\n\n    /**\n     * Called whenever the panel gets activated\n     */\n    GPanel.prototype.activate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called whenever the panel gets deactivated\n     */\n    GPanel.prototype.deactivate = function () {\n        // NO-OP\n    };\n\n    /** @override */\n    GPanel.prototype.toString = function () {\n        return \"[Object GPanel]\";\n    };\n\n    _.GPanel = GPanel;\n})(this);"
  },
  {
    "path": "src/application/extension/properties.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for property panels\n     * @class GProperties\n     * @extends GEventTarget\n     * @constructor\n     */\n    function GProperties() {\n    };\n\n    /**\n     * Called to return the category of the panel\n     * @return {String|IFLocale.Key}\n     */\n    GProperties.prototype.getCategory = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to initialize the properties panel\n     * @param {JQuery} panel the panel to init on\n     */\n    GProperties.prototype.init = function (panel) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to update\n     * @param {GDocument} document the document to work on\n     * @param {Array<IFElement>} elements array of elements, contains at least one\n     * @return {Boolean} true if this properties panel is available, false if not\n     */\n    GProperties.prototype.update = function (document, elements) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /** @override */\n    GProperties.prototype.toString = function () {\n        return \"[Object GProperties]\";\n    };\n\n    _.GProperties = GProperties;\n})(this);"
  },
  {
    "path": "src/application/extension/sidebar.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for an sidebar\n     * @class GSidebar\n     * @extends GView\n     * @constructor\n     */\n    function GSidebar() {\n        GView.call(this);\n    };\n    IFObject.inherit(GSidebar, GView);\n\n    /**\n     * Get the icon code of the sidebar\n     * @return {String|JQuery}\n     */\n    GSidebar.prototype.getIcon = function () {\n        return null;\n    };\n\n    /**\n     * Called to let the sidebar initialize on a given panel\n     * @param {JQuery} htmlElement the panel to put the sidebar into\n     */\n    GSidebar.prototype.init = function (htmlElement) {\n        gApp.addEventListener(GApplication.DocumentEvent, this._documentEvent, this);\n    };\n\n    /**\n     * Called whenever the sidebar gets activated\n     */\n    GSidebar.prototype.activate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called whenever the sidebar gets deactivated\n     */\n    GSidebar.prototype.deactivate = function () {\n        // NO-OP\n    };\n\n    /** @override */\n    GSidebar.prototype.toString = function () {\n        return \"[Object GSidebar]\";\n    };\n\n    _.GSidebar = GSidebar;\n})(this);"
  },
  {
    "path": "src/application/extension/storage.js",
    "content": "(function (_) {\n    /**\n     * The storage base class\n     * @constructor\n     */\n    function GStorage() {\n    };\n\n    /**\n     * Returns whether this storage is available at all or not\n     * @return {Boolean}\n     */\n    GStorage.prototype.isAvailable = function () {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Returns whether this storage can also save urls or not (load only)\n     * @return {Boolean}\n     */\n    GStorage.prototype.isSaving = function () {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Returns whether this storage supports prompting\n     * @return {Boolean}\n     */\n    GStorage.prototype.isPrompting = function () {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Returns whether this storage supports directories\n     * @return {Boolean}\n     */\n    GStorage.prototype.isDirectory = function () {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Get the unique protocol of this storage\n     * @return {String}\n     */\n    GStorage.prototype.getProtocol = function () {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * The extensions this storage  supports like ['pdf', 'ps'].\n     * Return null or empty array to support all. Ensure to always\n     * return extensions in lower-case only!\n     * @return {Array<String>} array of extensions\n     */\n    GStorage.prototype.getExtensions = function () {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Get the human readable name of this storage\n     * @return {String|IFLocale.Key}\n     */\n    GStorage.prototype.getName = function () {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Prompt for opening a resource\n     * @param {String} reference a reference url to set i.e.\n     * the current working directory from, defaults to null\n     * @param {Array<String>} extensions array of extensions to limit\n     * the selection to, can be null for all\n     * @param {Function} done called with the resource url\n     */\n    GStorage.prototype.openResourcePrompt = function (reference, extensions, done) {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Prompt for saving to a resources\n     * @param {String} reference a reference url to set i.e.\n     * the current working directory from, defaults to null\n     * @param {String} proposedName the proposed default name,\n     * maybe null for none\n     * @param {String} extension the desired extension to be\n     * used for the url resource, can be null\n     * @param {Function} done called with the resource url\n     */\n    GStorage.prototype.saveResourcePrompt = function (reference, proposedName, extension, done) {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Prompt for opening a directory\n     * @param {String} reference a reference url to set i.e.\n     * the current working directory from, defaults to null\n     * @param {Function} done called with the directory url\n     */\n    GStorage.prototype.openDirectoryPrompt = function (reference, done) {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Prompt for saving to a directory\n     * @param {String} reference a reference url to set i.e.\n     * the current working directory from, defaults to null\n     * @param {Function} done called with the directory url\n     */\n    GStorage.prototype.saveDirectoryPrompt = function (reference, done) {\n        throw new Error('Not supported.');\n    };\n\n    /**\n     * Load from an url\n     * @param {String} url the url to load from\n     * @param {Boolean} binary if true, the data is read as binary,\n     * otherwise it is read as String\n     * @param {Function} callback called with the data restored which\n     * is either an ArrayBuffer for binary or a String and the name\n     * @return {String}\n     */\n    GStorage.prototype.load = function (url, binary, done) {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Save data to an url\n     * @param {String} url the url to save to\n     * @param {ArrayBuffer|String} data the data to store. If\n     * binary is set to true, an ArrayBuffer is expected, otherwise a string\n     * @param {Boolean} binary whether the data is binary or not\n     * @param {Function} callback called when data was stored with the name\n     */\n    GStorage.prototype.save = function (url, data, binary, done) {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Release an url that has previously been gathered via open- or\n     * save-prompt. After this call, neither load nor save should be\n     * used on the url any longer.\n     * @param {String} url the url to be released\n     */\n    GStorage.prototype.releaseUrl = function (url) {\n        // NO-OP by default\n    };\n\n    /**\n     * Resolve an url in the format of this storage in a real-world\n     * url that is understandable and reachable. If the url may require\n     * some authentication this can be done here and when done, the\n     * callback function should be fired.\n     * @param {String} url the url in this storage format to resolve\n     * @param {Function} resolved callback retrieving the final url\n     */\n    GStorage.prototype.resolveUrl = function (url, resolved) {\n        throw new Error('Not Supported.');\n    };\n\n    _.GStorage = GStorage;\n})(this);\n"
  },
  {
    "path": "src/application/extension/styleentry.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for style entry handlers\n     * @class GStyleEntry\n     * @constructor\n     */\n    function GStyleEntry() {\n    };\n\n    /**\n     * Should return the entry class this one handles\n     * @return {IFStyleEntry}\n     */\n    GStyleEntry.prototype.getEntryClass = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Should return the name of the entry class\n     * @return {String|IFLocale.Key}\n     */\n    GStyleEntry.prototype.getEntryName = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to create the contents\n     * @param {IFScene} scene the active scene\n     * @param {Function} assign callback to assign properties\n     * @param {Function} revert callback to revert properties\n     * @return {JQuery} the contents\n     */\n    GStyleEntry.prototype.createContent = function (scene, assign, revert) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to update the created content with the values of a given entry\n     * @param {JQuery} content\n     * @param {IFStyleEntry} entry\n     */\n    GStyleEntry.prototype.updateProperties = function (content, entry) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to assign the values of the content to the given entry\n     * @param {JQuery} content\n     * @param {IFStyleEntry} entry\n     */\n    GStyleEntry.prototype.assignProperties = function (content, entry) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /** @override */\n    GStyleEntry.prototype.toString = function () {\n        return \"[Object GStyleEntry]\";\n    };\n\n    _.GStyleEntry = GStyleEntry;\n})(this);"
  },
  {
    "path": "src/application/extension/transformer.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for transformer panels\n     * @class GTransformer\n     * @extends GEventTarget\n     * @constructor\n     */\n    function GTransformer() {\n    };\n\n    /**\n     * Called to return the category of the panel\n     * @return {String|IFLocale.Key}\n     */\n    GTransformer.prototype.getCategory = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to initialize the transform panel\n     * @param {JQuery} panel the panel to init on\n     */\n    GTransformer.prototype.init = function (panel) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to update\n     * @param {GDocument} document the document to work on\n     * @param {Array<IFElement>} elements array of transformable elements, contains at least one\n     * @return {Boolean} true if this transform panel is available, false if not\n     */\n    GTransformer.prototype.update = function (document, elements) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /** @override */\n    GTransformer.prototype.toString = function () {\n        return \"[Object GTransformer]\";\n    };\n\n    _.GTransformer = GTransformer;\n})(this);"
  },
  {
    "path": "src/application/extension/view.js",
    "content": "(function (_) {\n\n    /**\n     * Base class for a view\n     * @class GView\n     * @extends GEventTarget\n     * @constructor\n     */\n    function GView() {\n    };\n    IFObject.inherit(GView, GEventTarget);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GView.UpdateEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event whenever the view requires an update like changed\n     * title or enabled status\n     * @class GView.UpdateEvent\n     * @extends GEvent\n     * @constructor\n     */\n    GView.UpdateEvent = function () {\n    };\n    IFObject.inherit(GView.UpdateEvent, GEvent);\n\n    /** @override */\n    GView.UpdateEvent.prototype.toString = function () {\n        return \"[Object GView.UpdateEvent]\";\n    };\n\n    GView.UPDATE_EVENT = new GView.UpdateEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GView.DocumentState Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A class that keeps a Palette-State for each document\n     * @class GView.DocumentState\n     * @constructor\n     */\n    GView.DocumentState = function (document) {\n        this.document = document;\n    };\n\n    /**\n     * @type {GDocument}\n     */\n    GView.DocumentState.prototype.document = null;\n\n    /**\n     * Called whenever this state gets activated\n     */\n    GView.DocumentState.prototype.activate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called whenever this state gets deactivated\n     */\n    GView.DocumentState.prototype.deactivate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called when this state gets initialized\n     */\n    GView.DocumentState.prototype.init = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called when this state gets released\n     */\n    GView.DocumentState.prototype.release = function () {\n        // NO-OP\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GView Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {Array<GView.DocumentState>}\n     * @private\n     */\n    GView.prototype._documentStates = null;\n\n    /**\n     * Get the unique id of the view.\n     */\n    GView.prototype.getId = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /**\n     * Get the title of the view\n     * @return {String|IFLocale.Key}\n     */\n    GView.prototype.getTitle = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /**\n     * Should create a new state for a given document if desired.\n     * @param {GDocument} document\n     * @return {GView.DocumentState}\n     * @private\n     */\n    GView.prototype._createDocumentState = function (document) {\n        return null;\n    };\n\n    /**\n     * Called whenever a given document state should be activated\n     * @param {GView.DocumentState} state\n     * @private\n     */\n    GView.prototype._activateDocumentState = function (state) {\n        // NO-OP\n    };\n\n    /**\n     * Called whenever a given document state should be deactivated\n     * @param {GView.DocumentState} state\n     * @private\n     */\n    GView.prototype._deactivateDocumentState = function (state) {\n        // NO-OP\n    };\n\n    /**\n     * @param {GApplication.DocumentEvent} event\n     * @private\n     */\n    GView.prototype._documentEvent = function (event) {\n        switch (event.type) {\n            case GApplication.DocumentEvent.Type.Added:\n                // Initiate a new state and add it\n                var state = this._createDocumentState(event.document);\n                if (state) {\n                    state.init();\n                    if (!this._documentStates) {\n                        this._documentStates = [];\n                    }\n\n                    this._documentStates.push(state);\n\n                    this.trigger(GView.UPDATE_EVENT);\n                }\n                break;\n            case GApplication.DocumentEvent.Type.Removed:\n                // Find and release state\n                var state = this._findDocumentState(event.document);\n                if (state) {\n                    state.release();\n                    this._documentStates.splice(this._documentStates.indexOf(state), 1);\n\n                    if (this._documentStates.length === 0) {\n                        this._documentStates = null;\n                    }\n\n                    this.trigger(GView.UPDATE_EVENT);\n                }\n                break;\n            case GApplication.DocumentEvent.Type.Activated:\n                // Find and activate state\n                var state = this._findDocumentState(event.document);\n                if (state) {\n                    state.activate();\n                    this._activateDocumentState(state);\n\n                    this.trigger(GView.UPDATE_EVENT);\n                }\n                break;\n            case GApplication.DocumentEvent.Type.Deactivated:\n                // Find and deactivate state\n                var state = this._findDocumentState(event.document);\n                if (state) {\n                    state.deactivate();\n                    this._deactivateDocumentState(state);\n\n                    this.trigger(GView.UPDATE_EVENT);\n                }\n                break;\n\n            default:\n                break;\n        }\n    };\n\n    /**\n     * @param {GDocument} document\n     * @return {GView.DocumentState}\n     * @private\n     */\n    GView.prototype._findDocumentState = function (document) {\n        if (!this._documentStates) {\n            return null;\n        }\n\n        for (var i = 0; i < this._documentStates.length; ++i) {\n            if (this._documentStates[i].document === document) {\n                return this._documentStates[i];\n            }\n        }\n    };\n\n    /** @override */\n    GView.prototype.toString = function () {\n        return \"[Object GView]\";\n    };\n\n    _.GView = GView;\n})(this);"
  },
  {
    "path": "src/application/i18n/i18n_de.js",
    "content": ""
  },
  {
    "path": "src/application/i18n/i18n_en.js",
    "content": "// Extensions\nifLocale.setValues(GColorMatcher, IFLocale.Language.English, [\"category.harmony\", \"category.palette\"], [\"Harmony\", \"Palette\"]);\n\n// Root\nifLocale.setValues(GApplication, IFLocale.Language.English, [\n    // Actions\n    \"category.window\",\n    \"category.file\",\n    \"category.edit\",\n    \"category.modify\", \"category.modify.arrange\", \"category.modify.align\", \"category.modify.transform\", \"category.modify.page\", \"category.modify.layer\",\n    \"category.arrange\", \"category.arrange.transform\",\n    \"category.view\", \"category.view.magnification\",\n    \"category.help\",\n    // Tools\n    \"tool-category.select\",\n    \"tool-category.image\",\n    \"tool-category.vector\",\n    \"tool-category.other\",\n    \"tool-category.color\",\n    \"tool-category.view\"],\n    [\n        // Actions\n        \"Window\",\n        \"File\",\n        \"Edit\",\n        \"Modify\", \"Modify/Arrange\", \"Modify/Align\", \"Modify/Transform\", \"Modify/Page\", \"Modify/Layer\",\n        \"Arrange\", \"Arrange/Transform\",\n        \"View\",\n        \"View/Magnification\",\n        \"Help\",\n        // Tools\n        \"Select\",\n        \"Image\",\n        \"Vector\",\n        \"Other\",\n        \"Color\",\n        \"View\"]);"
  },
  {
    "path": "src/application/shell.js",
    "content": "(function (_) {\n    /**\n     * The global shell class\n     * @class GShell\n     * @extends GEventTarget\n     * @constructor\n     */\n    function GShell() {\n    };\n    IFObject.inherit(GShell, GEventTarget);\n\n    /**\n     * Called to check whether shell is in development mode or not\n     * @return {Boolean}\n     */\n    GShell.prototype.isDevelopment = function () {\n        return false;\n    };\n\n    /**\n     * Called to let the shell prepare itself. This is called\n     * *after* the app has been initialized.\n     */\n    GShell.prototype.prepare = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called to let the shell start. This is the last\n     * point in the startup sequence and by default\n     * this will simply create a new document\n     */\n    GShell.prototype.start = function () {\n        gApp.createNewDocument();\n    };\n\n    /**\n     * Called whenever a menu shall be added\n     * @param {*} parentMenu parent menu, may be null to add to the root\n     * @param {String} title the title of the menu item\n     * @param {Function} [callback] called whenever the menu opens to\n     * prepare for any item updates before showing it\n     * @return {*} a shell-specific menu instance\n     */\n    GShell.prototype.addMenu = function (parentMenu, title, callback) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called whenever a menu separator shall be added\n     * @param {*} parentMenu parent menu to add the separator, may not be null\n     * @return {*} a shell-specific menu separator instance\n     */\n    GShell.prototype.addMenuSeparator = function (parentMenu) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called whenever a menu item shall be added\n     * @param {*} parentMenu parent menu to add the item, may not be null\n     * @param {String} title the title of the item\n     * @param {Boolean} checkable whether the item is a checkable one or not\n     * @param {Array<*>} shortcut the shortcut for the item\n     * @param {Function} [callback] called whenever the item is activated\n     * @return {*} a shell-specific menu item instance\n     */\n    GShell.prototype.addMenuItem = function (parentMenu, title, checkable, shortcut, callback) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called whenever a menu item shall be updated\n     * @param {*} item the shell-specific menu item instance to update\n     * @param {String} title the title of the item\n     * @param {Boolean} enabled whether the item is enabled or not\n     * @param {Boolean} checked whether the item is checked or not\n     */\n    GShell.prototype.updateMenuItem = function (item, title, enabled, checked) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called whenever a menu item shall be removed\n     * @param {*} parentMenu the parent menu to remove a child from\n     * @param {*} child the child to be removed\n     */\n    GShell.prototype.removeMenuItem = function (parentMenu, child) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to return all available mime-types from the clipboard\n     * @return {Array<String>} a list of mime-types available on clipboard\n     * or null if there's nothing\n     */\n    GShell.prototype.getClipboardMimeTypes = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to return clipboard contents of a given mime-type\n     * @return {*} the clipboard contents of the given mime-type\n     * or null if there's none\n     */\n    GShell.prototype.getClipboardContent = function (mimeType) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to push something into the clipboard\n     * @param {String} mimeType the mime-type of the contents\n     * @param {*} content the contents to push into clipboard\n     */\n    GShell.prototype.setClipboardContent = function (mimeType, content) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    _.GShell = GShell;\n    _.gShell = null; // initialized by client\n})(this);\n"
  },
  {
    "path": "src/application/util/ciede2000.js",
    "content": "(function (_) {\n    /**\n     * @author Markus Näsman\n     * @copyright 2012 (c) Markus Näsman <markus at botten dot org >\n     * @license Copyright (c) 2012, Markus Näsman\n     * All rights reserved.\n     * Redistribution and use in source and binary forms, with or without\n     * modification, are permitted provided that the following conditions are met:\n     *    * Redistributions of source code must retain the above copyright\n     *      notice, this list of conditions and the following disclaimer.\n     *    * Redistributions in binary form must reproduce the above copyright\n     *      notice, this list of conditions and the following disclaimer in the\n     *      documentation and/or other materials provided with the distribution.\n     *    * Neither the name of the <organization> nor the\n     *      names of its contributors may be used to endorse or promote products\n     *      derived from this software without specific prior written permission.\n     *\n     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n     * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n     * DISCLAIMED. IN NO EVENT SHALL MARKUS NÄSMAN BE LIABLE FOR ANY\n     * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n     * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n     * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n     */\n\n    /**\n     * EXPORTS\n     */\n    _.ciede2000 = ciede2000;\n\n    /**\n     * IMPORTS\n     */\n    var sqrt = Math.sqrt;\n    var pow = Math.pow;\n    var cos = Math.cos;\n    var atan2 = Math.atan2;\n    var sin = Math.sin;\n    var abs = Math.abs;\n    var exp = Math.exp;\n    var PI = Math.PI;\n\n    /**\n     * Returns diff between c1 and c2 using the CIEDE2000 algorithm\n     * @param {labcolor} c1    Should have fields L,a,b\n     * @param {labcolor} c2    Should have fields L,a,b\n     * @return {float}   Difference between c1 and c2\n     */\n    function ciede2000(c1, c2) {\n        /**\n         * Implemented as in \"The CIEDE2000 Color-Difference Formula:\n         * Implementation Notes, Supplementary Test Data, and Mathematical Observations\"\n         * by Gaurav Sharma, Wencheng Wu and Edul N. Dalal.\n         */\n\n        // Get L,a,b values for color 1\n        var L1 = c1.L;\n        var a1 = c1.a;\n        var b1 = c1.b;\n\n        // Get L,a,b values for color 2\n        var L2 = c2.L;\n        var a2 = c2.a;\n        var b2 = c2.b;\n\n        // Weight factors\n        var kL = 1;\n        var kC = 1;\n        var kH = 1;\n\n        /**\n         * Step 1: Calculate C1p, C2p, h1p, h2p\n         */\n        var C1 = sqrt(pow(a1, 2) + pow(b1, 2)) //(2)\n        var C2 = sqrt(pow(a2, 2) + pow(b2, 2)) //(2)\n\n        var a_C1_C2 = (C1 + C2) / 2.0;             //(3)\n\n        var G = 0.5 * (1 - sqrt(pow(a_C1_C2, 7.0) /\n            (pow(a_C1_C2, 7.0) + pow(25.0, 7.0)))); //(4)\n\n        var a1p = (1.0 + G) * a1; //(5)\n        var a2p = (1.0 + G) * a2; //(5)\n\n        var C1p = sqrt(pow(a1p, 2) + pow(b1, 2)); //(6)\n        var C2p = sqrt(pow(a2p, 2) + pow(b2, 2)); //(6)\n\n        var hp_f = function (x, y) //(7)\n        {\n            if (x == 0 && y == 0) return 0;\n            else {\n                var tmphp = degrees(atan2(x, y));\n                if (tmphp >= 0) return tmphp\n                else           return tmphp + 360;\n            }\n        }\n\n        var h1p = hp_f(b1, a1p); //(7)\n        var h2p = hp_f(b2, a2p); //(7)\n\n        /**\n         * Step 2: Calculate dLp, dCp, dHp\n         */\n        var dLp = L2 - L1; //(8)\n        var dCp = C2p - C1p; //(9)\n\n        var dhp_f = function (C1, C2, h1p, h2p) //(10)\n        {\n            if (C1 * C2 == 0)               return 0;\n            else if (abs(h2p - h1p) <= 180) return h2p - h1p;\n            else if ((h2p - h1p) > 180)     return (h2p - h1p) - 360;\n            else if ((h2p - h1p) < -180)    return (h2p - h1p) + 360;\n            else                         throw(new Error());\n        }\n        var dhp = dhp_f(C1, C2, h1p, h2p); //(10)\n        var dHp = 2 * sqrt(C1p * C2p) * sin(radians(dhp) / 2.0); //(11)\n\n        /**\n         * Step 3: Calculate CIEDE2000 Color-Difference\n         */\n        var a_L = (L1 + L2) / 2.0; //(12)\n        var a_Cp = (C1p + C2p) / 2.0; //(13)\n\n        var a_hp_f = function (C1, C2, h1p, h2p) { //(14)\n            if (C1 * C2 == 0)                                      return h1p + h2p\n            else if (abs(h1p - h2p) <= 180)                         return (h1p + h2p) / 2.0;\n            else if ((abs(h1p - h2p) > 180) && ((h1p + h2p) < 360))  return (h1p + h2p + 360) / 2.0;\n            else if ((abs(h1p - h2p) > 180) && ((h1p + h2p) >= 360)) return (h1p + h2p - 360) / 2.0;\n            else                                                throw(new Error());\n        }\n        var a_hp = a_hp_f(C1, C2, h1p, h2p); //(14)\n        var T = 1 - 0.17 * cos(radians(a_hp - 30)) + 0.24 * cos(radians(2 * a_hp)) +\n            0.32 * cos(radians(3 * a_hp + 6)) - 0.20 * cos(radians(4 * a_hp - 63)); //(15)\n        var d_ro = 30 * exp(-(pow((a_hp - 275) / 25, 2))); //(16)\n        var RC = sqrt((pow(a_Cp, 7.0)) / (pow(a_Cp, 7.0) + pow(25.0, 7.0)));//(17)\n        var SL = 1 + ((0.015 * pow(a_L - 50, 2)) /\n            sqrt(20 + pow(a_L - 50, 2.0)));//(18)\n        var SC = 1 + 0.045 * a_Cp;//(19)\n        var SH = 1 + 0.015 * a_Cp * T;//(20)\n        var RT = -2 * RC * sin(radians(2 * d_ro));//(21)\n        var dE = sqrt(pow(dLp / (SL * kL), 2) + pow(dCp / (SC * kC), 2) +\n            pow(dHp / (SH * kH), 2) + RT * (dCp / (SC * kC)) *\n            (dHp / (SH * kH))); //(22)\n        return dE;\n    }\n\n    /**\n     * INTERNAL FUNCTIONS\n     */\n    function degrees(n) {\n        return n * (180 / PI);\n    }\n\n    function radians(n) {\n        return n * (PI / 180);\n    }\n\n}(this));\n"
  },
  {
    "path": "src/application/util/image.js",
    "content": "(function (_) {\n\n    /**\n     * Converts a given image or url into a canvas\n     * @param {String|Image|HTMLImageelement} imageOrUrl\n     * @param {Function} done the callback function called when done with the\n     * only parameter being the canvas with the painted image contents\n     */\n    _.image2Canvas = function (imageOrUrl, done) {\n        if (typeof imageOrUrl === 'string' && imageOrUrl.substr(0, 5) !== 'data:') {\n            var image = new Image();\n            image.src = imageOrUrl;\n            image.onload = function () {\n                _.image2Canvas(image, done);\n            }\n        } else {\n            var canvas = document.createElement(\"canvas\");\n            canvas.width = imageOrUrl.naturalWidth;\n            canvas.height = imageOrUrl.naturalHeight;\n\n            var ctx = canvas.getContext(\"2d\");\n            ctx.drawImage(imageOrUrl, 0, 0);\n\n            done(canvas);\n        }\n    };\n\n    /**\n     * Converts a given image or url into a base64-encoded png image data url (png)\n     * @param {String|Image|HTMLImageelement} imageOrUrl\n     * @param {Function} done the callback function called when done with the\n     * only parameter being the data url string\n     */\n    _.image2Base64 = function (imageOrUrl, done) {\n        _.image2Canvas(imageOrUrl, function (canvas) {\n            done(canvas.toDataURL('image/png'));\n        });\n    };\n\n    /**\n     * Converts a given image or url into an array buffer (png)\n     * @param {String|Image|HTMLImageelement} imageOrUrl\n     * @param {Function} done the callback function called when done with the\n     * only parameter being the ArrayBuffer\n     */\n    _.image2ArrayBuffer = function (imageOrUrl, done) {\n        _.image2Canvas(imageOrUrl, function (canvas) {\n            canvas.toBlob(function (blob) {\n                var reader = new FileReader();\n                reader.onload = function (event) {\n                    done(event.target.result);\n                };\n                reader.readAsArrayBuffer(blob);\n            });\n        });\n    };\n\n}(this));"
  },
  {
    "path": "src/application/util/selectors.js",
    "content": "(function ($) {\n\n    /**\n     * Selector that selects all editable elements including all input\n     * elements and also content editable elements and the such\n     * @param obj\n     * @returns {boolean}\n     */\n    $.expr[':'].editable = function(obj){\n        var $this = $(obj);\n        return $this.is(':input') || $this.attr('contenteditable') === 'true' || obj.isContentEditable;\n    };\n\n}(jQuery));"
  },
  {
    "path": "src/application/workspace/header.js",
    "content": "(function (_) {\n    /**\n     * The global idebar class\n     * @class GHeader\n     * @constructor\n     * @version 1.0\n     */\n    function GHeader(htmlElement) {\n        this._htmlElement = htmlElement;\n    };\n\n    /**\n     * @type {HTMLDivElement}\n     * @private\n     */\n    GHeader.prototype._htmlElement = null;\n\n    /**\n     * Called from the workspace to initialize\n     */\n    GHeader.prototype.init = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called from the workspace to relayout\n     */\n    GHeader.prototype.relayout = function () {\n        // NO-OP\n    };\n\n    _.GHeader = GHeader;\n})(this);\n"
  },
  {
    "path": "src/application/workspace/palettes.js",
    "content": "(function (_) {\n    /**\n     * The global palettes class\n     * @class GPalettes\n     * @constructor\n     */\n    function GPalettes(htmlElement) {\n        this._htmlElement = htmlElement;\n        this._palettesInfo = [];\n        this._groupsInfo = [];\n    };\n\n    /**\n     * @type {HTMLDivElement}\n     * @private\n     */\n    GPalettes.prototype._htmlElement = null;\n\n    /**\n     * @type {Array<{{palette: GPalette, panel: JQuery}}>}\n     * @private\n     */\n    GPalettes.prototype._palettesInfo = null;\n\n    /**\n     * @type {Array<{{expanded: Boolean, visible: Boolean, activePalette: String, palettes: []}}>}\n     * @private\n     */\n    GPalettes.prototype._groupsInfo = null;\n\n    /**\n     * Group an array of palettes together\n     * @param {Array<GPalette>} palettes\n     */\n    GPalettes.prototype.groupPalettes = function (palettes) {\n        // Detach palettes, first\n        for (var i = 0; i < palettes.length; ++i) {\n            this._detachPaletteFromGroup(palettes[i].getId());\n        }\n\n        // Initiate a new group for them\n        var group = this._addGroupInfo();\n\n        // Attach palettes to the group\n        for (var i = 0; i < palettes.length; ++i) {\n            this._attachPaletteToGroup(group, palettes[i].getId());\n        }\n    };\n\n    /**\n     * Returns whether a given palette is active or not. Note that this\n     * will also return false if the palette's group is not visible\n     * or not expanded\n     * @param {String} paletteId\n     * @return {Boolean}\n     */\n    GPalettes.prototype.isPaletteActive = function (paletteId) {\n        var groupInfo = this._getGroupInfoForPalette(paletteId);\n        if (groupInfo) {\n            return groupInfo.activePalette === paletteId && groupInfo.visible && groupInfo.expanded;\n        }\n        return false;\n    };\n\n    /**\n     * Assigns whether a given palette is active or not within it's group.\n     * Note that when the palette should be activated then the system\n     * will ensure that a) the sidebar is visible b) the palette is visible\n     * and c) the palette's group is expanded\n     * @param {String} paletteId\n     * @param {Boolean} active whether to activate or deactivate\n     */\n    GPalettes.prototype.setPaletteActive = function (paletteId, active) {\n        var groupInfo = this._getGroupInfoForPalette(paletteId);\n\n        if (groupInfo && (groupInfo.activePalette !== paletteId || !active || !groupInfo.visible || !groupInfo.expanded)) {\n            if (!active) {\n                // Simply hide our group and be done w/ it\n                this._setGroupVisible(groupInfo, false);\n            } else {\n                var paletteInfo = this._getPaletteInfo(paletteId);\n\n                // Assign active palette\n                groupInfo.activePalette = paletteId;\n\n                // Iterate each tab and mark active/non-active\n                groupInfo.container.find('.palette-group-tabs > button').each(function () {\n                    var el = $(this);\n                    if (el.attr('data-palette-id') === paletteId) {\n                        el.addClass('g-active');\n                    } else {\n                        el.removeClass('g-active');\n                    }\n                });\n\n                // Iterate each panel and mark visible/hidden\n                groupInfo.container.find('.palette-group-panels > div').each(function () {\n                    var el = $(this);\n                    if (el.attr('data-palette-id') === paletteId) {\n                        el.css('display', '');\n                    } else {\n                        el.css('display', 'none');\n                    }\n                });\n\n                // Empty and re-assign controls\n                var controls = groupInfo.container.find('.palette-group-controls');\n                controls.children().detach();\n                controls.append(paletteInfo.controls);\n\n                // Group needs to be visible and expanded\n                this._setGroupVisible(groupInfo, true);\n                this._setGroupExpanded(groupInfo, true);\n            }\n        }\n    };\n\n    /**\n     * Returns whether a given palette is enabled or not.\n     * @param {String} paletteId\n     * @return {Boolean}\n     */\n    GPalettes.prototype.isPaletteEnabled = function (paletteId) {\n        var paletteInfo = this._getPaletteInfo(paletteId);\n        if (paletteInfo) {\n            return paletteInfo.panel.find('.panel-disabled-overlay').length == 0;\n        }\n        return false;\n    };\n\n    /**\n     * Enable or disable a palette\n     * @param {String} paletteId\n     * @param {Boolean} enabled\n     */\n    GPalettes.prototype.setPaletteEnabled = function (paletteId, enabled) {\n        var paletteInfo = this._getPaletteInfo(paletteId);\n        if (paletteInfo) {\n            var overlay = paletteInfo.panel.find('.panel-disabled-overlay');\n\n            if (enabled && overlay.length > 0) {\n                overlay.remove();\n            } else if (!enabled && overlay.length === 0) {\n                overlay = $('<div></div>')\n                    .addClass('panel-disabled-overlay')\n                    .appendTo(paletteInfo.panel);\n            }\n        }\n    };\n\n    /**\n     * Called from the workspace to initialize\n     */\n    GPalettes.prototype.init = function () {\n        /** Array<Array<GPalette>> */\n        var grouppedPalettes = [];\n\n        // Add all palettes first and collect their grouping\n        var lastGroup = null;\n        var lastPalettes = null;\n        for (var i = 0; i < gravit.palettes.length; ++i) {\n            var palette = gravit.palettes[i];\n\n            this._addPaletteInfo(palette);\n\n            var group = palette.getGroup();\n            if (!group) {\n                group = palette.getId();\n            }\n\n            if (!lastGroup || lastGroup !== group) {\n                if (lastPalettes) {\n                    grouppedPalettes.push(lastPalettes);\n                }\n                lastPalettes = [];\n                lastGroup = group;\n            }\n\n            lastPalettes.push(palette);\n        }\n\n        if (lastPalettes) {\n            grouppedPalettes.push(lastPalettes);\n        }\n\n        // Group palettes now which'll create our groups\n        for (var i = 0; i < grouppedPalettes.length; ++i) {\n            this.groupPalettes(grouppedPalettes[i]);\n\n            // Active first palette by default\n            this.setPaletteActive(grouppedPalettes[i][0].getId(), true);\n\n            // Update enabled status if palettes\n            for (var k = 0; k < grouppedPalettes[i].length; ++k) {\n                var palette = grouppedPalettes[i][k];\n                this.setPaletteEnabled(palette.getId(), palette.isEnabled());\n            }\n        }\n    };\n\n    /**\n     * Called from the workspace to relayout\n     */\n    GPalettes.prototype.relayout = function () {\n        // NO-OP\n    };\n    GPalettes.prototype._addPaletteInfo = function (palette) {\n        // Create panel\n        var panel = $('<div></div>')\n            .attr('data-palette-id', palette.getId())\n            .addClass('palette-panel')\n            .addClass('palette-' + palette.getId())\n            .css('display', 'none');\n\n        var controls = $('<div></div>');\n\n        // Let palette init itself on panel\n        palette.init(panel, controls);\n\n        //\n        // Initiate our palette info object and add it to our array\n        //\n        var paletteInfo = {\n            palette: palette,\n            panel: panel,\n            controls: controls\n        };\n        this._palettesInfo.push(paletteInfo);\n\n        // Add update listener to palette\n        palette.addEventListener(GView.UpdateEvent, function () {\n            this.setPaletteEnabled(palette.getId(), palette.isEnabled());\n            // TODO : Update title, shortcut, etc.\n        }.bind(this));\n\n        return paletteInfo;\n    };\n\n    GPalettes.prototype._getPaletteInfo = function (paletteId) {\n        for (var i = 0; i < this._palettesInfo.length; ++i) {\n            if (this._palettesInfo[i].palette.getId() === paletteId) {\n                return this._palettesInfo[i];\n            }\n        }\n        return null;\n    };\n\n    GPalettes.prototype._detachPaletteFromGroup = function (paletteId) {\n        var group = this._getGroupInfoForPalette(paletteId);\n        var paletteInfo = this._getPaletteInfo(paletteId);\n\n        if (group && paletteInfo) {\n            // Remove Tab & Panel\n            group.container.find('.palette-group-tabs > button[data-palette-id=\"' + paletteId + '\"]').remove();\n\n            // Important: only detach, not remove our panel as it will be re-used!!\n            group.container.find('.palette-group-panels > div[data-palette-id=\"' + paletteId + '\"]').detach();\n\n            // Remove from palettes\n            group.palettes.slice(group.palettes.indexOf(paletteId));\n        }\n    };\n\n    GPalettes.prototype._attachPaletteToGroup = function (groupInfo, paletteId) {\n        var paletteInfo = this._getPaletteInfo(paletteId);\n\n        if (paletteInfo) {\n            var tabsContainer = groupInfo.container.find('.palette-group-tabs');\n            var panelsContainer = groupInfo.container.find('.palette-group-panels');\n\n            // Add Tab & Panel\n            tabsContainer.append($('<button></button>')\n                .attr('data-palette-id', paletteInfo.palette.getId())\n                .text(ifLocale.get(paletteInfo.palette.getTitle()))\n                .on('click', function () {\n                    // If palette already is active, change collapse state instead\n                    if (this.isPaletteActive(paletteInfo.palette.getId())) {\n                        this._setGroupExpanded(groupInfo, !groupInfo.expanded);\n                    } else {\n                        this.setPaletteActive(paletteInfo.palette.getId(), true);\n                    }\n                }.bind(this)));\n\n            panelsContainer.append(paletteInfo.panel);\n\n            // Add to palettes\n            groupInfo.palettes.push(paletteId);\n        }\n    };\n\n    GPalettes.prototype._addGroupInfo = function () {\n        var groupInfo = {\n            expanded: true,\n            visible: true,\n            activePalette: null,\n            palettes: []\n        };\n\n        groupInfo.container = $('<div></div>')\n            .addClass('palette-group')\n            .append($('<div></div>')\n                .addClass('palette-group-header')\n                .append($('<div></div>')\n                    .addClass('palette-group-collapse')\n                    .append($('<button></button>')\n                        .append($('<span></span>')\n                            .addClass('fa fa-angle-double-down fa-fw'))\n                        .on('click', function () {\n                            this._setGroupExpanded(groupInfo, !groupInfo.expanded);\n                        }.bind(this))))\n                .append($('<div></div>')\n                    .addClass('palette-group-tabs'))\n                .append($('<div></div>')\n                    .addClass('palette-group-controls')))\n            .append($('<div></div>')\n                .addClass('palette-group-panels'))\n            .appendTo(this._htmlElement);\n\n        this._groupsInfo.push(groupInfo);\n\n        return groupInfo;\n    };\n\n    GPalettes.prototype._getGroupInfoForPalette = function (paletteId) {\n        for (var i = 0; i < this._groupsInfo.length; ++i) {\n            if (this._groupsInfo[i].palettes.indexOf(paletteId) >= 0) {\n                return this._groupsInfo[i];\n            }\n        }\n        return null;\n    };\n\n    GPalettes.prototype._setGroupExpanded = function (groupInfo, expanded) {\n        if (expanded !== groupInfo.expanded) {\n            groupInfo.expanded = expanded;\n\n            var buttonSpan = groupInfo.container.find('.palette-group-collapse > button > span');\n\n            if (groupInfo.expanded) {\n                groupInfo.container.css('height', '');\n                groupInfo.container.removeClass('collapsed-palette');\n                buttonSpan.attr('class', 'fa  fa-angle-double-down fa-fw');\n            } else {\n                var header = groupInfo.container.find('.palette-group-header');\n                groupInfo.container.height(header.outerHeight());\n                groupInfo.container.addClass('collapsed-palette');\n                buttonSpan.attr('class', 'fa  fa-angle-double-right fa-fw');\n            }\n        }\n    };\n\n    GPalettes.prototype._setGroupVisible = function (groupInfo, visible) {\n        if (visible !== groupInfo.visible) {\n            groupInfo.visible = visible;\n\n            if (groupInfo.visible) {\n                groupInfo.container.css('display', '');\n            } else {\n                groupInfo.container.css('display', 'none');\n            }\n        }\n    };\n\n    _.GPalettes = GPalettes;\n})(this);"
  },
  {
    "path": "src/application/workspace/panels.js",
    "content": "(function (_) {\n    /**\n     * The global panels class\n     * @class GPanels\n     * @constructor\n     */\n    function GPanels(htmlElement) {\n        this._htmlElement = htmlElement;\n    };\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPanels.prototype._htmlElement = null;\n\n    /**\n     * @type {Array<{{container: JQuery, panel: GPanel}}>}\n     * @private\n     */\n    GPanels.prototype._panels = null;\n\n    /**\n     * @type {String}\n     * @private\n     */\n    GPanels.prototype._activePanel = null;\n\n    /**\n     * @returns {String} the id of the active panel or null for none\n     */\n    GPanels.prototype.getActivePanel = function () {\n        return this._activePanel;\n    };\n\n    /**\n     * Set an active panel\n     * @param {String} panelId\n     */\n    GPanels.prototype.setActivePanel = function (panelId) {\n        if (panelId !== this._activePanel) {\n            for (var i = 0; i < this._panels.length; ++i) {\n                var panel = this._panels[i];\n                var id = panel.panel.getId();\n\n                if (id === panelId) {\n                    panel.container.css('display', '');\n                    panel.tab.addClass('g-active');\n                    panel.panel.activate();\n                } else {\n                    panel.container.css('display', 'none');\n                    panel.tab.removeClass('g-active');\n                    if (id === this._activePanel) {\n                        panel.panel.deactivate();\n                    }\n                }\n            }\n\n            this._activePanel = panelId;\n        }\n    };\n\n    /**\n     * Called from the workspace to initialize\n     */\n    GPanels.prototype.init = function () {\n        this._panels = [];\n\n        var panelsTabs = $('<div></div>')\n            .addClass('panels-tabs')\n            .appendTo(this._htmlElement);\n\n        var panelsFrame = $('<div></div>')\n            .addClass('panels-frame')\n            .appendTo(this._htmlElement);\n\n        if (gravit.panels) {\n            for (var i = 0; i < gravit.panels.length; ++i) {\n                var panel = gravit.panels[i];\n\n                var tab = $('<button></button>')\n                    .addClass('panel-tab')\n                    .attr('data-panel-id', panel.getId())\n                    .text(ifLocale.get(panel.getTitle()))\n                    .on('click', function (evt) {\n                        this.setActivePanel($(evt.target).attr('data-panel-id'));\n                    }.bind(this))\n                    .appendTo(panelsTabs);\n\n                var container = $('<div></div>')\n                    .addClass('panel-container panel-' + panel.getId())\n                    .css('display', 'none')\n                    .appendTo(panelsFrame);\n\n                panel.init(container);\n\n                this._panels.push({\n                    tab: tab,\n                    container: container,\n                    panel: panel\n                });\n\n                // Activate the first panel found\n                if (!this._activePanel) {\n                    this.setActivePanel(panel.getId());\n                }\n            }\n        }\n    };\n\n    /**\n     * Called from the workspace to relayout\n     */\n    GPanels.prototype.relayout = function () {\n        // NO-OP\n    };\n\n    _.GPanels = GPanels;\n})(this);"
  },
  {
    "path": "src/application/workspace/sidebars.js",
    "content": "(function (_) {\n    /**\n     * The global sidebars class\n     * @class GSidebars\n     * @constructor\n     */\n    function GSidebars(htmlElement) {\n        this._htmlElement = htmlElement;\n    };\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GSidebars.prototype._htmlElement = null;\n\n    /**\n     * @type {Array<{{container: JQuery, sidebar: GSidebar}}>}\n     * @private\n     */\n    GSidebars.prototype._sidebars = null;\n\n    /**\n     * @type {String}\n     * @private\n     */\n    GSidebars.prototype._activeSidebar = null;\n\n    /**\n     * @returns {String} the id of the active sidebar or null for none\n     */\n    GSidebars.prototype.getActiveSidebar = function () {\n        return this._activeSidebar;\n    };\n\n    /**\n     * Set an active sidebar\n     * @param {String} sidebarId\n     */\n    GSidebars.prototype.setActiveSidebar = function (sidebarId) {\n        if (sidebarId !== this._activeSidebar) {\n            for (var i = 0; i < this._sidebars.length; ++i) {\n                var sidebar = this._sidebars[i];\n                var id = sidebar.sidebar.getId();\n\n                if (id === sidebarId) {\n                    sidebar.container.css('display', '');\n                    sidebar.sidebar.activate();\n                } else {\n                    sidebar.container.css('display', 'none');\n                    if (id === this._activeSidebar) {\n                        sidebar.sidebar.deactivate();\n                    }\n                }\n            }\n\n            this._activeSidebar = sidebarId;\n        }\n    };\n\n    /**\n     * Called from the workspace to initialize\n     */\n    GSidebars.prototype.init = function () {\n        this._sidebars = [];\n\n        if (gravit.sidebars) {\n            for (var i = 0; i < gravit.sidebars.length; ++i) {\n                var sidebar = gravit.sidebars[i];\n\n                var container = $('<div></div>')\n                    .addClass('sidebar-container sidebar-' + sidebar.getId())\n                    .css('display', 'none')\n                    .appendTo(this._htmlElement);\n\n                sidebar.init(container);\n\n                this._sidebars.push({\n                    container: container,\n                    sidebar: sidebar\n                });\n            }\n        }\n    };\n\n    /**\n     * Called from the workspace to relayout\n     */\n    GSidebars.prototype.relayout = function () {\n        // NO-OP\n    };\n\n    _.GSidebars = GSidebars;\n})(this);"
  },
  {
    "path": "src/application/workspace/toolbar.js",
    "content": "(function (_) {\n    /**\n     * The global toolbar class\n     * @class GToolbar\n     * @constructor\n     */\n    function GToolbar(htmlElement) {\n        this._htmlElement = htmlElement;\n\n        htmlElement\n            .append($('<div></div>')\n                .addClass('section sidebars'))\n            .append($('<div></div>')\n                .addClass('section toolpanel'));\n    };\n\n    /**\n     * @type {HTMLDivElement}\n     * @private\n     */\n    GToolbar.prototype._htmlElement = null;\n\n    /**\n     * @type {Array<{{group: String, tools: Array}}>}\n     * @private\n     */\n    GToolbar.prototype._groupedTools = null;\n\n    /**\n     * Called from the workspace to initialize\n     */\n    GToolbar.prototype.init = function () {\n        // Add sidebars\n        if (gravit.sidebars && gravit.sidebars.length > 0) {\n            var sidebarsSection = this._htmlElement.find('.sidebars');\n\n            for (var i = 0; i < gravit.sidebars.length; ++i) {\n                var sidebar = gravit.sidebars[i];\n\n                $('<button></button>')\n                    .append($(sidebar.getIcon()))\n                    .attr('title', ifLocale.get(sidebar.getTitle()))\n                    .attr('data-sidebar-id', sidebar.getId())\n                    .on('click', function () {\n                        var btn = $(this);\n                        var isActive = btn.hasClass('g-active');\n\n                        sidebarsSection.find('button').each(function (index, element) {\n                            $(element).removeClass('g-active');\n                        });\n\n                        if (isActive) {\n                            gApp.getSidebars().setActiveSidebar(null);\n                            gApp.setPartVisible(GApplication.Part.Sidebars, false);\n                        } else {\n                            gApp.getSidebars().setActiveSidebar(btn.attr('data-sidebar-id'));\n                            gApp.setPartVisible(GApplication.Part.Sidebars, true);\n                            btn.addClass('g-active');\n                        }\n                    })\n                    .appendTo(sidebarsSection);\n            }\n        }\n\n        // Init and add tools\n        var toolpanel = this._htmlElement.find('.toolpanel');\n\n        // Group tools together, first\n        this._groupedTools = [];\n        for (var i = 0; i < gravit.tools.length; ++i) {\n            var tool = gravit.tools[i];\n            var foundGroup = false;\n            for (var k = 0; k < this._groupedTools.length; ++k) {\n                if (this._groupedTools[k].group === tool.group) {\n                    this._groupedTools[k].tools.push(tool);\n                    foundGroup = true;\n                }\n            }\n\n            if (!foundGroup) {\n                this._groupedTools.push({\n                    group: tool.group,\n                    tools: [tool]\n                });\n            }\n        }\n\n\n        // Append all tool groups as buttons now\n        var lastCategory = null;\n        for (var i = 0; i < this._groupedTools.length; ++i) {\n            var group = this._groupedTools[i].group;\n            var tools = this._groupedTools[i].tools;\n            var mainTool = tools[0];\n\n            var category = ifLocale.get(mainTool.category);\n            if (category != lastCategory) {\n                // Add a divider, first\n                $(\"<div></div>\")\n                    .addClass('divider')\n                    .text(category)\n                    .appendTo(toolpanel);\n                lastCategory = category;\n\n                // Do some custom handling for known categories\n                if (mainTool.category === GApplication.TOOL_CATEGORY_VIEW) {\n                    $('<div></div>')\n                        .addClass('zoom')\n                        .append($('<button></button>')\n                            .on('click', function () {\n                                gApp.executeAction(GZoomOutAction.ID);\n                            })\n                            .append($('<span></span>')\n                                .addClass('fa fa-minus')))\n                        .append($('<input>')\n                            .css('border', 'none')\n                            .on('click', function () {\n                                $(this).select();\n                            })\n                            .on('change', function () {\n                                var zoomLevel = ifUtil.parseNumber($(this).val());\n                                if (!isNaN(zoomLevel) && zoomLevel !== 0) {\n                                    var view = gApp.getWindows().getActiveWindow().getView();\n                                    var centerPoint = view.getViewTransform().mapPoint(new IFPoint(view.getWidth() / 2.0, view.getHeight() / 2.0));\n                                    view.zoomAtCenter(centerPoint, zoomLevel);\n                                }\n                            }))\n                        .append($('<button></button>')\n                            .on('click', function () {\n                                gApp.executeAction(GZoomInAction.ID);\n                            })\n                            .append($('<span></span>')\n                                .addClass('fa fa-plus')))\n                        .appendTo(toolpanel);\n                }\n            }\n\n            // Append our group button now\n            var button = $(\"<button></button>\")\n                .attr('data-group', group)\n                .appendTo(toolpanel);\n\n            // Add menu logic if there're multiple tools on the group\n            if (tools.length > 1) {\n                // TODO\n            }\n\n            // Assign the main tool to the group button\n            this._updateGroupTool(mainTool.instance);\n        }\n\n        // Subscribe to some events\n        gApp.getToolManager().addEventListener(IFToolManager.ToolChangedEvent, this._toolChanged, this);\n        gApp.getWindows().addEventListener(GWindows.WindowEvent, this._windowEvent, this);\n\n        this._updateZoomFromWindow();\n    };\n\n    /**\n     * Called from the workspace to relayout\n     */\n    GToolbar.prototype.relayout = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called whenever the active tool has been changed\n     * @param event\n     * @private\n     */\n    GToolbar.prototype._toolChanged = function (event) {\n        if (event.previousTool) {\n            this._updateGroupTool(event.previousTool);\n        }\n\n        if (event.newTool) {\n            this._updateGroupTool(event.newTool);\n        }\n    };\n\n    /**\n     * @param {IFWindows.WindowEvent} evt\n     * @private\n     */\n    GToolbar.prototype._windowEvent = function (evt) {\n        if (evt.type === GWindows.WindowEvent.Type.Activated) {\n            evt.window.getView().addEventListener(IFView.TransformEvent, this._updateZoomFromWindow, this);\n        } else if (evt.type === GWindows.WindowEvent.Type.Deactivated && evt.window) {\n            evt.window.getView().removeEventListener(IFView.TransformEvent, this._updateZoomFromWindow, this);\n        }\n\n        this._updateZoomFromWindow();\n    };\n\n    /** @private */\n    GToolbar.prototype._updateZoomFromWindow = function () {\n        var zoom = this._htmlElement.find('.toolpanel > .zoom');\n        var window = gApp.getWindows().getActiveWindow();\n\n        zoom\n            .find('*').prop('disabled', !window);\n\n        if (window) {\n            zoom\n                .find('input').val(ifUtil.formatNumber(window.getView().getZoom()) + 'x');\n        }\n    };\n\n    /** @orivate */\n    GToolbar.prototype._updateGroupTool = function (toolInstance) {\n        var toolInfo = this._getToolInfo(toolInstance);\n\n        // Collect all group tools\n        var groupTools = [];\n        for (var i = 0; i < this._groupedTools.length; ++i) {\n            if (this._groupedTools[i].group === toolInfo.group) {\n                groupTools = this._groupedTools[i].tools.slice();\n            }\n        }\n\n        var groupButton = this._htmlElement\n            .find('.toolpanel button[data-group=\"' + toolInfo.group + '\"]');\n\n        groupButton\n            .empty()\n            .toggleClass('g-active', toolInstance == gApp.getToolManager().getActiveTool())\n            .attr('title', this._getToolTitle(toolInfo))\n            .append($(toolInfo.icon).attr('width', '18px').attr('height', '18px'))\n            .off('mousedown')\n            .on('mousedown', function (evt) {\n                gApp.getToolManager().activateTool(toolInstance);\n\n                if (groupTools.length > 1) {\n                    var overlayTimeout = setTimeout(function () {\n                        var panel = $('<div></div>')\n                            .gOverlay({\n                                releaseOnClose: true\n                            });\n\n                        var _addSubToolButton = function (toolInfo) {\n                            $(\"<button></button>\")\n                                .addClass('toolbar-tool-button')\n                                .append($('<span></span>')\n                                    .addClass('fa fa-check fa-fw')\n                                    .css('visibility', toolInfo.instance !== gApp.getToolManager().getActiveTool() ? 'hidden' : ''))\n                                .append($(toolInfo.icon).attr('width', '18px').attr('height', '18px'))\n                                .append($('<span></span>')\n                                    .html('&nbsp;' + this._getToolTitle(toolInfo)))\n                                .on('mouseenter', function () {\n                                    $(this).addClass('g-hover');\n                                })\n                                .on('mouseleave', function () {\n                                    $(this).removeClass('g-hover');\n                                })\n                                .on('mouseup', function () {\n                                    gApp.getToolManager().activateTool(toolInfo.instance);\n                                    panel.gOverlay('close');\n                                })\n                                .on('click', function () {\n                                    if (gApp.getToolManager().getActiveTool() !== toolInfo.instance) {\n                                        gApp.getToolManager().activateTool(toolInfo.instance);\n                                        panel.gOverlay('close');\n                                    }\n                                })\n                                .appendTo(panel);\n                        }.bind(this);\n\n                        for (var i = 0; i < groupTools.length; ++i) {\n                            _addSubToolButton(groupTools[i]);\n                        }\n\n                        panel.gOverlay('open', groupButton);\n                    }.bind(this), 250);\n\n                    groupButton\n                        .off('mouseup')\n                        .on('mouseup', function (evt) {\n                            clearTimeout(overlayTimeout);\n                            overlayTimeout = null;\n                        })\n                }\n            }.bind(this));\n\n        if (groupTools.length > 1) {\n            groupButton.append($('<span></span>')\n                .addClass('fa fa-caret-down'));\n        }\n    };\n\n    /** @private */\n    GToolbar.prototype._getToolTitle = function (toolInfo) {\n        var title = ifLocale.get(toolInfo.title);\n\n        if (toolInfo.keys && toolInfo.keys.length > 0) {\n            for (var i = 0; i < toolInfo.keys.length; ++i) {\n                if (i == 0) {\n                    title += \" (\";\n                } else {\n                    title += \", \";\n                }\n                title += toolInfo.keys[i];\n            }\n            title += \")\";\n        }\n\n        return title;\n    };\n\n    /** @private */\n    GToolbar.prototype._getToolInfo = function (toolInstance) {\n        for (var i = 0; i < gravit.tools.length; ++i) {\n            if (gravit.tools[i].instance === toolInstance) {\n                return gravit.tools[i];\n            }\n        }\n        return null;\n    };\n\n    _.GToolbar = GToolbar;\n})(this);\n"
  },
  {
    "path": "src/application/workspace/window.js",
    "content": "(function (_) {\n    /**\n     * An instance of an opened window\n     * @class GWindow\n     * @extends GEventTarget\n     * @constructor\n     * @version 1.0\n     */\n    function GWindow(document) {\n        this._container = $('<div></div>');\n        this._document = document;\n        this._view = new IFEditorView(this._document.getEditor());\n        this._view.setViewMargin([GWindow.VIEW_MARGIN, GWindow.VIEW_MARGIN, GWindow.VIEW_MARGIN, GWindow.VIEW_MARGIN]);\n        this._container.append(this._view._htmlElement);\n\n        // Add \"hack\" to focus the view on clicking\n        this._container.on('mousedown', function (e) {\n            this._view.focus();\n        }.bind(this));\n\n        // Catch the context menu event to show our own\n        var contextMenu = this._createContextMenu();\n        this._container.on(\"contextmenu\", function (evt) {\n            var toolManager = gApp.getToolManager();\n            var tool = toolManager.getActiveTool();\n            if (tool && tool.catchesContextMenu()) {\n                return;\n            }\n\n            this._contextMenuClientPosition = new IFPoint(evt.clientX, evt.clientY);\n            contextMenu.open({x: evt.pageX, y: evt.pageY});\n            return true;\n        }.bind(this));\n\n    };\n    IFObject.inherit(GWindow, GEventTarget);\n\n    /**\n     * Constant defining the additional margin for the view\n     * @type {number}\n     */\n    GWindow.VIEW_MARGIN = 10;\n\n    /**\n     * The view container\n     * @type {JQuery}\n     * @private\n     */\n    GWindow.prototype._container = null;\n\n    /**\n     * The underlying document\n     * @type {GDocument}\n     * @private\n     */\n    GWindow.prototype._document = null;\n\n    /**\n     * The underlying view\n     * @type {IFEditorView}\n     * @private\n     */\n    GWindow.prototype._view = null;\n\n    /**\n     * The current clientX/clientY position triggered\n     * by the contextmenu DOM-Event\n     * @type {IFPoint}\n     * @private\n     */\n    GWindow.prototype._contextMenuClientPosition = null;\n\n    /**\n     * Returns the document this window is bound to\n     * @return {GDocument}\n     */\n    GWindow.prototype.getDocument = function () {\n        return this._document;\n    };\n\n    /**\n     * Returns the underlying editor view this window is bound to\n     * @return {IFEditorView}\n     */\n    GWindow.prototype.getView = function () {\n        return this._view;\n    };\n\n    /**\n     * Returns the title for this window\n     * @return {String}\n     */\n    GWindow.prototype.getTitle = function () {\n        var result = this._document.getTitle();\n\n        var index = this._document._windows.indexOf(this);\n        if (index > 0) {\n            result += ':' + index.toString();\n        }\n\n        return result;\n    };\n\n    /**\n     * Called before this document gets activated\n     */\n    GWindow.prototype.activate = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called before this document gets deactivated\n     */\n    GWindow.prototype.deactivate = function () {\n        // Always finish inline editing of editor if any\n        // when a view gets deactivated\n        this._document.getEditor().closeInlineEditor();\n    };\n\n    /**\n     * Called when this window gets released\n     */\n    GWindow.prototype.release = function () {\n        this._view.release();\n    };\n\n    /**\n     * Creates the context menu for the view\n     * @returns {GMenu}\n     * @private\n     */\n    GWindow.prototype._createContextMenu = function () {\n        var menu = new GMenu();\n\n        // Add select menu item to select shapes underneath\n        var selectItem = new GMenuItem(GMenuItem.Type.Menu);\n        // TODO : I18N\n        selectItem.setCaption('Select');\n        selectItem.addEventListener(GMenuItem.UpdateEvent, function () {\n            // Clear out any previous items and disable our item by default\n            selectItem.getMenu().clearItems();\n            selectItem.setEnabled(false);\n\n            // Gather all element hits underneath cursor and update our menu\n            var elementHits = this._document.getScene().hitTest(this._contextMenuClientPosition, this._view.getWorldTransform(), function (hit) {\n                return true;\n            }.bind(this), true, -1, this._document.getScene().getProperty('pickDist'), true);\n\n            if (elementHits && elementHits.length > 0) {\n                selectItem.setEnabled(true);\n\n                // Add each hit as a menu item\n                for (var i = 0; i < elementHits.length; ++i) {\n                    var self = this;\n                    var element = elementHits[i].element;\n                    var name = element instanceof IFBlock ? element.getLabel() : element.getNodeNameTranslated();\n\n                    selectItem.getMenu().createAddItem(\n                        (i + 1).toString() + '. ' + name,\n                        function () {\n                            this.element.removeFlag(IFNode.Flag.Highlighted);\n                            self._document.getEditor().updateSelection(ifPlatform.modifiers.shiftKey, [this.element]);\n                        },\n                        function () {\n                            this.element.setFlag(IFNode.Flag.Highlighted);\n                        },\n                        function () {\n                            this.element.removeFlag(IFNode.Flag.Highlighted);\n                        }\n                    ).element = element;\n                }\n            }\n        }.bind(this));\n        menu.addItem(selectItem);\n\n        // TODO : Add more actions\n\n        // Finally return our context menu instance\n        return menu;\n    };\n\n    _.GWindow = GWindow;\n})(this);\n"
  },
  {
    "path": "src/application/workspace/windows.js",
    "content": "(function (_) {\n    /**\n     * The global window container class\n     * @class GWindows\n     * @extends GEventTarget\n     * @constructor\n     */\n    function GWindows(htmlElement) {\n        this._htmlElement = htmlElement;\n        this._windows = [];\n    };\n    IFObject.inherit(GWindows, GEventTarget);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GWindows.WindowEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever a window event occurrs\n     * @class GWindows.WindowEvent\n     * @extends GEvent\n     * @constructor\n     */\n    GWindows.WindowEvent = function (type, window) {\n        this.type = type;\n        this.window = window;\n    };\n    IFObject.inherit(GWindows.WindowEvent, GEvent);\n\n    /**\n     * Enumeration of window event types\n     * @enum\n     */\n    GWindows.WindowEvent.Type = {\n        Added: 0,\n        Removed: 1,\n        Deactivated: 10,\n        Activated: 11\n    };\n\n    /**\n     * @type {GWindows.WindowEvent.Type}\n     */\n    GWindows.WindowEvent.prototype.type = null;\n\n    /**\n     * The affected window\n     * @type {GWindow}\n     */\n    GWindows.WindowEvent.prototype.window = null;\n\n    /** @override */\n    GWindows.WindowEvent.prototype.toString = function () {\n        return \"[Object GWindows.WindowEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GWindows Class\n    // -----------------------------------------------------------------------------------------------------------------      \n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GWindows.prototype._htmlElement = null;\n\n    /**\n     * @type {Array<GWindow>}\n     * @private\n     */\n    GWindows.prototype._windows = null;\n\n    /**\n     * @type {GWindow}\n     * @private\n     */\n    GWindows.prototype._activeWindow = null;\n\n    /**\n     * @type {Array<Number>}\n     * @private\n     */\n    GWindows.prototype._viewOffset = null;\n\n    /**\n     * Returns a list of all opened windows\n     * @return {Array<GWindow>}\n     */\n    GWindows.prototype.getWindows = function () {\n        return this._windows;\n    };\n\n    /**\n     * Returns the currently active window\n     * @return {GWindow}\n     */\n    GWindows.prototype.getActiveWindow = function () {\n        return this._activeWindow;\n    };\n\n    /**\n     * Mark a given window as being the active one\n     * @param {GWindow} window may be null to only deactivate the current one\n     */\n    GWindows.prototype.activateWindow = function (window) {\n        if (window != this._activeWindow) {\n\n            // If we have an active window, clear that one out, first\n            if (this._activeWindow) {\n                // Notify the window\n                this._activeWindow.deactivate();\n\n                // Mark deactivated on document\n                this._activeWindow.getDocument()._activeWindow = null;\n\n                // Detach it's container\n                this._activeWindow._container.detach();\n            }\n\n            // Check to activate the document properly if it was changed\n            if (window === null) {\n                gApp.activateDocument(null, true);\n            } else if ((window && this._activeWindow && window.getDocument() !== this._activeWindow.getDocument()) || !this._activeWindow) {\n                gApp.activateDocument(window.getDocument(), true);\n            }\n\n            var previousActiveWindow = this._activeWindow;\n            this._activeWindow = window;\n\n            // Send deactivation event after document change if we had an active window\n            if (this._activeWindow && this.hasEventListeners(GWindows.WindowEvent)) {\n                this.trigger(new GWindows.WindowEvent(GWindows.WindowEvent.Type.Deactivated, previousActiveWindow));\n            }\n\n            // Activate the new window if we have any\n            if (window) {\n                // Notify the window\n                this._activeWindow.activate();\n\n                // Mark as active on document\n                window.getDocument()._activeWindow = window;\n\n                // Attach container and relayout it\n                this._htmlElement.append(window._container);\n                this._relayoutWindow(window);\n                window.getView().focus();\n\n                // Send out an event\n                if (this.hasEventListeners(GWindows.WindowEvent)) {\n                    this.trigger(new GWindows.WindowEvent(GWindows.WindowEvent.Type.Activated, window));\n                }\n            }\n        }\n    };\n\n    /**\n     * Add a new window for a given document\n     * @param {GDocument|GWindow} source the source to add a window from\n     * which can either be a document or a window. If it is a window, the\n     * newly added window will be an exact clone of the source\n     * @return {GWindow}\n     */\n    GWindows.prototype.addWindow = function (source) {\n        var document = source instanceof GWindow ? source.getDocument() : source;\n        var window = this._addWindow(document);\n\n        // If we have a source, copy it's settings\n        if (source instanceof GWindow) {\n            var sourceView = source.getView();\n            // TODO : Serialize/deserialize window settings instead\n            window.getView().transform(sourceView.getScrollX(), sourceView.getScrollY(), sourceView.getZoom());\n        } else {\n            // Otherwise let view zoom the active page\n            window.getView().zoomActivePage();\n        }\n\n        return window;\n    };\n\n    /**\n     * Closes and removes a window. If the window to be closed\n     * is the last window available for a document, then the\n     * document will be closed as well\n     * @param {GWindow} window\n     */\n    GWindows.prototype.closeWindow = function (window) {\n        var document = window.getDocument();\n\n        // If window is the active one, try to activate a previous one, first\n        if (window === this._activeWindow) {\n            var windowIndex = this._windows.indexOf(window);\n\n            if (windowIndex > 0) {\n                this.activateWindow(this._windows[windowIndex - 1]);\n            } else if (windowIndex + 1 < this._windows.length) {\n                this.activateWindow(this._windows[windowIndex + 1]);\n            } else {\n                this.activateWindow(null);\n            }\n        }\n\n        // Remove from the document's windows\n        document._windows.splice(document._windows.indexOf(window), 1);\n\n        // Remove from our windows\n        this._windows.splice(this._windows.indexOf(window), 1);\n\n        // Remove the window's container once and forever\n        window._container.remove();\n\n        // Send out an event\n        if (this.hasEventListeners(GWindows.WindowEvent)) {\n            this.trigger(new GWindows.WindowEvent(GWindows.WindowEvent.Type.Removed, window));\n        }\n\n        // Release window\n        window.release();\n\n        // If this was the only window for the document left,\n        // then remove/close our document now\n        if (document._windows.length === 0) {\n            gApp.closeDocument(document);\n        }\n    };\n\n    /**\n     * Called from the workspace to initialize\n     */\n    GWindows.prototype.init = function () {\n        // TODO\n    };\n\n    /**\n     * Called from the workspace to relayout\n     */\n    GWindows.prototype.relayout = function (viewOffset) {\n        this._viewOffset = viewOffset ? viewOffset : this._viewOffset;\n        if (this._activeWindow) {\n            this._relayoutWindow(this._activeWindow);\n        }\n    };\n\n    /**\n     * Relayouts a given window to the current settings\n     * @param {GWindow} window\n     * @private\n     */\n    GWindows.prototype._relayoutWindow = function (window) {\n        // TODO : Take care on ruler spacing\n        var myWidth = this._htmlElement.width();\n        var myHeight = this._htmlElement.height();\n        window._container.width(myWidth);\n        window._container.height(myHeight);\n        window.getView().setViewOffset(this._viewOffset);\n        var oldW = window.getView().getWidth();\n        var oldH = window.getView().getHeight();\n        window.getView().resize(myWidth, myHeight);\n        if (oldW != null && oldH != null && (oldW != myWidth || oldH != myHeight)) {\n            window.getView().scrollBy((oldW - myWidth) / 2, (oldH - myHeight) / 2);\n        }\n    };\n\n    /**\n     * Internal adding of a new window\n     * @param {GDocument} document\n     * @returns {GWindow}\n     * @private\n     */\n    GWindows.prototype._addWindow = function (document) {\n        var window = new GWindow(document);\n\n        // Add and trigger\n        document._windows.push(window);\n        this._windows.push(window);\n\n        // Send out an event\n        if (this.hasEventListeners(GWindows.WindowEvent)) {\n            this.trigger(new GWindows.WindowEvent(GWindows.WindowEvent.Type.Added, window));\n        }\n\n        // Mark the window being active\n        this.activateWindow(window);\n\n        // Return the new window\n        return window;\n    };\n\n    _.GWindows = GWindows;\n})(this);\n"
  },
  {
    "path": "src/development/bootstrap.js",
    "content": "var gDevelopment = {\n    tests : []\n};"
  },
  {
    "path": "src/development/development.js",
    "content": "(function (_) {\n    /**\n     * Gravit Development Module\n     * @class GDevelopmentModule\n     * @constructor\n     * @extends GModule\n     */\n    function GDevelopmentModule() {\n    }\n    IFObject.inherit(GDevelopmentModule, GModule);\n\n    /** @override */\n    GDevelopmentModule.prototype.init = function () {\n        var testActions = [];\n        for (var i = 0; i < _.gDevelopment.tests.length; ++i) {\n            testActions.push(new TestAction(_.gDevelopment.tests[i]));\n        }\n\n        // Register test actions\n        gravit.actions = gravit.actions.concat(testActions);\n    };\n\n    /** @override */\n    GDevelopmentModule.prototype.toString = function () {\n        return '[Module Gravit Development]';\n    };\n\n    gravit.modules.push(new GDevelopmentModule());\n})(this);\n"
  },
  {
    "path": "src/development/test/clone_scene.js",
    "content": "(function () {\n    gDevelopment.tests.push({\n        title: 'Clone Scene',\n        test: function () {\n            var sceneCode = IFNode.serialize(gApp.getActiveDocument().getScene());\n            var blob = JSON.parse(sceneCode);\n            var scene = new IFScene();\n            if (!scene.restore(blob)) {\n                throw new Error('Failure.');\n            }\n\n            gApp.addDocument(scene, 'Cloned Scene');\n        }\n    });\n})();\n"
  },
  {
    "path": "src/development/test/create_multiple_pages.js",
    "content": "(function () {\n    gDevelopment.tests.push({\n        title: 'Create Multiple Pages',\n        test: function () {\n            gApp.executeAction(GNewAction.ID);\n            var document = gApp.getActiveDocument();\n            var scene = document.getScene();\n            scene.removeChild(scene.getActivePage());\n\n            var masterPage = new IFPage();\n            var insertPos = scene.getPageInsertPosition();\n            var insertSize = new IFPoint(800, 600);\n\n            masterPage.setProperties([\n                'name',\n                'x',\n                'y',\n                'w',\n                'h'\n            ], [\n                'Master-Page',\n                insertPos.getX() + 100,\n                insertPos.getY() + 100,\n                insertSize.getX(),\n                insertSize.getY()\n            ]);\n\n            var layer = new IFLayer();\n            layer.setFlag(IFNode.Flag.Active);\n            masterPage.appendChild(layer);\n\n            var rectangle = new IFRectangle();\n            var style = new IFInlineStyle();\n            var fillPaint = new IFFillPaint();\n            fillPaint.setProperty('pat', IFColor.parseCSSColor('rgba(255, 0, 0, 0.75)'));\n            style.appendChild(fillPaint);\n            rectangle.getStyleSet().appendChild(style);\n            rectangle.setProperty('trf', new IFTransform(insertSize.getX() / 2, 0, 0, 50, 100 + insertSize.getX() / 2, 100 + 50));\n            layer.appendChild(rectangle);\n\n\n            var slice = new IFSlice();\n            slice.setProperty('trf', new IFTransform(50, 0, 0, 50, 100 + 50 / 2, 100 + 50));\n            layer.appendChild(slice);\n\n            scene.appendChild(masterPage);\n\n            for (var i = 0; i < 10; ++i) {\n                var page = new IFPage();\n                insertPos = scene.getPageInsertPosition();\n\n                page.setProperties([\n                    'name',\n                    'x',\n                    'y',\n                    'w',\n                    'h',\n                    'msref'\n                ], [\n                    'Page-' + i,\n                    insertPos.getX(),\n                    insertPos.getY(),\n                    insertSize.getX(),\n                    insertSize.getY(),\n                    masterPage.getReferenceId()\n                ]);\n\n                var text = new IFText();\n                text.fromHtml('<p style=\"font-size:72px\">Page Number ' + i + '</p>');\n\n                var style = new IFInlineStyle();\n                text.getStyleSet().appendChild(style);\n                style.appendChild(new IFFillPaint());\n\n                var textPaintBBox = text.getPaintBBox();\n                text.setProperties(['trf'], [new IFTransform(1, 0, 0, 1,\n                    insertPos.getX() + (insertSize.getX() - textPaintBBox.getWidth()) / 2,\n                    insertPos.getY() + (insertSize.getY() - textPaintBBox.getHeight()) / 2)]);\n\n                var layer = new IFLayer();\n                layer.setFlag(IFNode.Flag.Active);\n                layer.appendChild(text);\n\n                page.appendChild(layer);\n\n                scene.appendChild(page);\n\n                if (i === 0) {\n                    page.setFlag(IFNode.Flag.Active);\n                }\n            }\n        }\n    });\n})();\n"
  },
  {
    "path": "src/development/test/create_rect_grid_page.js",
    "content": "(function () {\n    gDevelopment.tests.push({\n        title: 'Create Rectangular Grid on Page',\n        test: function test() {\n            var RECT_SIZE = 50;\n            var RECT_SPACE = 10;\n\n            gApp.executeAction(GNewAction.ID);\n            var document = gApp.getActiveDocument();\n            var scene = document.getScene();\n            var page = scene.getActivePage();\n            var layer = scene.getActiveLayer();\n\n            var start = new Date().getTime();\n\n            var numberOfRects = 0;\n            for (var x = 0; x + RECT_SIZE < page.getProperty('w'); x += RECT_SIZE + RECT_SPACE) {\n                for (var y = 0; y + RECT_SIZE < page.getProperty('h'); y += RECT_SIZE + RECT_SPACE) {\n                    var rectangle = new IFRectangle();\n                    var style = new IFInlineStyle();\n                    style.appendChild(new IFStrokePaint());\n                    rectangle.getStyleSet().appendChild(style);\n\n                    rectangle.setProperty('trf', new IFTransform(RECT_SIZE / 2, 0, 0, RECT_SIZE / 2, x + RECT_SIZE / 2, y + RECT_SIZE / 2));\n\n                    layer.appendChild(rectangle);\n\n                    numberOfRects++;\n                }\n            }\n\n            var end = new Date().getTime() - start;\n            alert('Created ' + numberOfRects.toString() + ' Rectangles in ' + (end > 1000 ? ((end / 1000).toString() + 'sec') : (end.toString() + 'ms')));\n        }\n    });\n})();\n"
  },
  {
    "path": "src/development/test/deserialize_scene.js",
    "content": "(function () {\n    gDevelopment.tests.push({\n        title: 'Deserialize Scene',\n        test: function () {\n            var str = prompt('Enter JSON String');\n            if (str && str !== '') {\n                var blob = JSON.parse(str);\n                var scene = new IFScene();\n                if (!scene.restore(blob)) {\n                    throw new Error('Failure.');\n                }\n\n                gApp.addDocument(scene, 'From-String');\n            }\n        }\n    });\n})();\n"
  },
  {
    "path": "src/development/test/serialize_scene.js",
    "content": "(function () {\n    gDevelopment.tests.push({\n        title: 'Serialize Scene',\n        test: function () {\n            prompt('JSON-String:', IFNode.serialize(gApp.getActiveDocument().getScene()));\n        }\n    });\n})();\n"
  },
  {
    "path": "src/development/testaction.js",
    "content": "(function (_) {\n    function TestAction(test) {\n        this._test = test;\n    };\n    IFObject.inherit(TestAction, GAction);\n\n    /**\n     * @override\n     */\n    TestAction.prototype.getId = function() {\n        return this._test.category + '.' + this._test.title;\n    };\n\n    /**\n     * @override\n     */\n    TestAction.prototype.getTitle = function () {\n        return this._test.title;\n    };\n\n    /**\n     * @override\n     */\n    TestAction.prototype.getCategory = function () {\n        return ifLocale.get(GApplication.CATEGORY_FILE) + '/Development/Test';\n    };\n\n    /**\n     * @override\n     */\n    TestAction.prototype.execute = function () {\n        return this._test.test();\n    };\n\n    /** @override */\n    TestAction.prototype.toString = function () {\n        return \"[Object TestAction]\";\n    };\n\n    _.TestAction = TestAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/addlayeraction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for inserting a layer\n     * @class GAddLayerAction\n     * @extends GAction\n     * @constructor\n     */\n    function GAddLayerAction() {\n    };\n    IFObject.inherit(GAddLayerAction, GAction);\n\n    GAddLayerAction.ID = 'modify.add-layer';\n    GAddLayerAction.TITLE = new IFLocale.Key(GAddLayerAction, \"title\");\n\n    /**\n     * @override\n     */\n    GAddLayerAction.prototype.getId = function () {\n        return GAddLayerAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GAddLayerAction.prototype.getTitle = function () {\n        return GAddLayerAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GAddLayerAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_LAYER;\n    };\n\n    /**\n     * @override\n     */\n    GAddLayerAction.prototype.getGroup = function () {\n        return \"structure/modify\";\n    };\n\n    /**\n     * @override\n     */\n    GAddLayerAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GAddLayerAction.prototype.execute = function () {\n        var scene = gApp.getActiveDocument().getScene();\n        var activePage = scene.getActivePage();\n\n        // TODO : I18N\n        IFEditor.tryRunTransaction(activePage, function () {\n            var layer = new IFLayer();\n            layer.setProperty('name', 'Layer ' + scene.queryCount('layer').toString());\n            activePage.appendChild(layer);\n            scene.setActiveLayer(layer);\n        }, ifLocale.get(this.getTitle()));\n    };\n\n    /** @override */\n    GAddLayerAction.prototype.toString = function () {\n        return \"[Object GAddLayerAction]\";\n    };\n\n    _.GAddLayerAction = GAddLayerAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/addpageaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for adding a new page\n     * @class GAddPageAction\n     * @extends GAction\n     * @constructor\n     */\n    function GAddPageAction() {\n    };\n    IFObject.inherit(GAddPageAction, GAction);\n\n    GAddPageAction.ID = 'modify.add-page';\n    GAddPageAction.TITLE = new IFLocale.Key(GAddPageAction, \"title\");\n\n    /**\n     * @override\n     */\n    GAddPageAction.prototype.getId = function () {\n        return GAddPageAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GAddPageAction.prototype.getTitle = function () {\n        return GAddPageAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GAddPageAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_PAGE;\n    };\n\n    /**\n     * @override\n     */\n    GAddPageAction.prototype.getGroup = function () {\n        return \"structure/modify\";\n    };\n\n    /**\n     * @override\n     */\n    GAddPageAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GAddPageAction.prototype.execute = function () {\n        gApp.getActiveDocument().createNewPage();\n    };\n\n    /** @override */\n    GAddPageAction.prototype.toString = function () {\n        return \"[Object GAddPageAction]\";\n    };\n\n    _.GAddPageAction = GAddPageAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/alignaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for aligning\n     * @class GAlignAction\n     * @extends GAction\n     * @constructor\n     */\n    function GAlignAction(type) {\n        this._type = type;\n        this._title = new IFLocale.Key(GAlignAction, 'title.' + type);\n    };\n    IFObject.inherit(GAlignAction, GAction);\n\n    /** @enum */\n    GAlignAction.Type = {\n        AlignLeft: 'align-left',\n        AlignCenter: 'align-center',\n        AlignRight: 'align-right',\n        AlignTop: 'align-top',\n        AlignMiddle: 'align-middle',\n        AlignBottom: 'align-bottom',\n        AlignJustifyHorizontal: 'align-justify-horizontal',\n        AlignJustifyVertical: 'align-justify-vertical'\n    };\n\n    GAlignAction.ID = 'arrange.align';\n\n    /** @type {GAlignAction.Type} */\n    GAlignAction.prototype._type = null;\n\n    /** @type {IFLocale.Key} */\n    GAlignAction.prototype._title = null;\n\n    /**\n     * @override\n     */\n    GAlignAction.prototype.getId = function () {\n        return GAlignAction.ID + '.' + this._type;\n    };\n\n    /**\n     * @override\n     */\n    GAlignAction.prototype.getTitle = function () {\n        return this._title;\n    };\n\n    /**\n     * @override\n     */\n    GAlignAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_ALIGN;\n    };\n\n    /**\n     * @override\n     */\n    GAlignAction.prototype.getGroup = function () {\n        var result = '';\n\n        switch (this._type) {\n            case GAlignAction.Type.AlignLeft:\n            case GAlignAction.Type.AlignCenter:\n            case GAlignAction.Type.AlignRight:\n            case GAlignAction.Type.AlignJustifyHorizontal:\n                result = 'horizontal';\n                break;\n            case GAlignAction.Type.AlignTop:\n            case GAlignAction.Type.AlignMiddle:\n            case GAlignAction.Type.AlignBottom:\n            case GAlignAction.Type.AlignJustifyVertical:\n                result = 'vertical';\n                break;\n        }\n\n        return 'arrange/align-' + result;\n    };\n\n    /**\n     * @override\n     */\n    GAlignAction.prototype.getShortcut = function () {\n        return null;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @param {Boolean} [compound] if provided, aligns the whole element's bbox,\n     * otherwise if false (default), aligns each element individually\n     * @param {Boolean} [geometry] if provided, specifies whether to\n     * use geometry box for alignment, otherwise use paint box. Defaults\n     * to false.\n     * @param {IFRect} [referenceBox] a reference box to align to, if not\n     * given uses the element's total bbox\n     * @override\n     */\n    GAlignAction.prototype.isEnabled = function (elements, compound, geometry, referenceBox) {\n        elements = elements || (gApp.getActiveDocument() ? gApp.getActiveDocument().getEditor().getSelection() : null);\n        if (elements) {\n            return referenceBox ? elements.length > 0 : elements.length > 1;\n        }\n        return false;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @param {Boolean} [compound] if provided, aligns the whole element's bbox,\n     * otherwise if false (default), aligns each element individually\n     * @param {Boolean} [geometry] if provided, specifies whether to\n     * use geometry box for alignment, otherwise use paint box. Defaults\n     * to false.\n     * @param {IFRect} [referenceBox] a reference box to align to, if not\n     * given uses the element's total bbox\n     * @override\n     */\n    GAlignAction.prototype.execute = function (elements, compound, geometry, referenceBox) {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n\n        if (!elements) {\n            elements = document.getEditor().getSelection();\n        }\n\n        var tmpElements = elements;\n        var elements = [];\n\n        var elementsBBox = null;\n        for (var i = 0; i < tmpElements.length; ++i) {\n            var element = tmpElements[i];\n            if (element.hasMixin(IFElement.Transform)) {\n                var bbox = geometry ? element.getGeometryBBox() : element.getPaintBBox();\n                if (!bbox || bbox.isEmpty()) {\n                    continue;\n                }\n\n                elementsBBox = !elementsBBox ? bbox : elementsBBox.united(bbox);\n\n                elements.push({\n                    bbox: bbox,\n                    element: element\n                });\n            }\n        }\n\n        if (!referenceBox) {\n            for (var i = 0; i < elements.length; ++i) {\n                var bbox = elements[i].element.getPaintBBox();\n                if (bbox && !bbox.isEmpty()) {\n                    referenceBox = referenceBox ? referenceBox.united(bbox) : bbox;\n                }\n            }\n        }\n\n        if (!referenceBox || referenceBox.isEmpty()) {\n            return;\n        }\n\n        IFEditor.tryRunTransaction(scene, function () {\n            for (var i = 0; i < elements.length; ++i) {\n                var bbox = compound ? elementsBBox : elements[i].bbox;\n                var element = elements[i].element;\n\n                switch (this._type) {\n                    case GAlignAction.Type.AlignLeft:\n                        if (referenceBox.getX() !== bbox.getX()) {\n                            element.transform(new IFTransform(1, 0, 0, 1, referenceBox.getX() - bbox.getX(), 0));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignCenter:\n                        var center = referenceBox.getX() + referenceBox.getWidth() / 2;\n                        if (center !== bbox.getX() + bbox.getWidth() / 2) {\n                            element.transform(new IFTransform(1, 0, 0, 1, center - bbox.getX() - bbox.getWidth() / 2, 0));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignRight:\n                        var right = referenceBox.getX() + referenceBox.getWidth();\n                        if (right !== bbox.getX() + bbox.getWidth()) {\n                            element.transform(new IFTransform(1, 0, 0, 1, right - bbox.getWidth() - bbox.getX(), 0));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignTop:\n                        if (referenceBox.getY() !== bbox.getY()) {\n                            element.transform(new IFTransform(1, 0, 0, 1, 0, referenceBox.getY() - bbox.getY()));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignMiddle:\n                        var center = referenceBox.getY() + referenceBox.getHeight() / 2;\n                        if (center !== bbox.getY() + bbox.getHeight() / 2) {\n                            element.transform(new IFTransform(1, 0, 0, 1, 0, center - bbox.getY() - bbox.getHeight() / 2));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignBottom:\n                        var bottom = referenceBox.getY() + referenceBox.getHeight();\n                        if (bottom !== bbox.getY() + bbox.getHeight()) {\n                            element.transform(new IFTransform(1, 0, 0, 1, 0, bottom - bbox.getHeight() - bbox.getY()));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignJustifyHorizontal:\n                        if (referenceBox.getX() !== bbox.getX() || bbox.getWidth() !== referenceBox) {\n                            element.transform(\n                                new IFTransform(1, 0, 0, 1, 0, 0)\n                                    .translated(-bbox.getX(), -bbox.getY())\n                                    .scaled(referenceBox.getWidth() / bbox.getWidth(), 1)\n                                    .translated(bbox.getX(), bbox.getY())\n                                    .translated(referenceBox.getX() - bbox.getX(), 0));\n                        }\n                        break;\n\n                    case GAlignAction.Type.AlignJustifyVertical:\n                        if (referenceBox.getY() !== bbox.getY() || bbox.getHeight() !== referenceBox) {\n                            element.transform(\n                                new IFTransform(1, 0, 0, 1, 0, 0)\n                                    .translated(-bbox.getX(), -bbox.getY())\n                                    .scaled(1, referenceBox.getHeight() / bbox.getHeight())\n                                    .translated(bbox.getX(), bbox.getY())\n                                    .translated(0, referenceBox.getY() - bbox.getY()));\n                        }\n                        break;\n                }\n            }\n        }.bind(this), ifLocale.get(this.getTitle()));\n    };\n\n    /** @override */\n    GAlignAction.prototype.toString = function () {\n        return \"[Object GAlignAction]\";\n    };\n\n    _.GAlignAction = GAlignAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/arrangeaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for ordering\n     * @class GArrangeAction\n     * @extends GAction\n     * @constructor\n     */\n    function GArrangeAction(type) {\n        this._type = type;\n        this._title = new IFLocale.Key(GArrangeAction, 'title.' + type);\n    };\n    IFObject.inherit(GArrangeAction, GAction);\n\n    /** @enum */\n    GArrangeAction.Type = {\n        SendToFront: 'send-front',\n        BringForward: 'bring-forward',\n        SendBackward: 'send-backward',\n        SendToBack: 'send-back'\n    };\n\n    GArrangeAction.ID = 'arrange.order';\n\n    /** @type {GArrangeAction.Type} */\n    GArrangeAction.prototype._type = null;\n\n    /** @type {IFLocale.Key} */\n    GArrangeAction.prototype._title = null;\n\n    /**\n     * @override\n     */\n    GArrangeAction.prototype.getId = function () {\n        return GArrangeAction.ID + '.' + this._type;\n    };\n\n    /**\n     * @override\n     */\n    GArrangeAction.prototype.getTitle = function () {\n        return this._title;\n    };\n\n    /**\n     * @override\n     */\n    GArrangeAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_ARRANGE;\n    };\n\n    /**\n     * @override\n     */\n    GArrangeAction.prototype.getGroup = function () {\n        return \"arrange/arrange\";\n    };\n\n    /**\n     * @override\n     */\n    GArrangeAction.prototype.getShortcut = function () {\n        switch (this._type) {\n            case GArrangeAction.Type.SendToFront:\n                return [IFKey.Constant.SHIFT, IFKey.Constant.META, IFKey.Constant.UP];\n            case GArrangeAction.Type.BringForward:\n                return [IFKey.Constant.META, IFKey.Constant.UP];\n            case GArrangeAction.Type.SendBackward:\n                return [IFKey.Constant.META, IFKey.Constant.DOWN];\n            case GArrangeAction.Type.SendToBack:\n                return [IFKey.Constant.SHIFT, IFKey.Constant.META, IFKey.Constant.DOWN];\n        }\n        return null;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @override\n     */\n    GArrangeAction.prototype.isEnabled = function (elements) {\n        elements = elements || (gApp.getActiveDocument() ? gApp.getActiveDocument().getEditor().getSelection() : null);\n        return elements && elements.length > 0;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @override\n     */\n    GArrangeAction.prototype.execute = function (elements) {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n        var selection = null;\n\n        if (!elements) {\n            selection = document.getEditor().getSelection().slice();\n            elements = selection;\n        }\n\n        elements = IFNode.order(elements, true/*reverse*/);\n\n        // TODO : I18N\n        IFEditor.tryRunTransaction(scene, function () {\n            for (var i = 0; i < elements.length; ++i) {\n                var element = elements[i];\n                var parent = element.getParent();\n\n                switch (this._type) {\n                    case GArrangeAction.Type.SendToFront:\n                        if (element.getNext() !== null) {\n                            parent.removeChild(element);\n                            parent.appendChild(element);\n                        }\n                        break;\n                    case GArrangeAction.Type.BringForward:\n                        if (element.getNext() !== null) {\n                            var posElement = element.getNext() ? element.getNext().getNext() : null;\n                            parent.removeChild(element);\n                            parent.insertChild(element, posElement);\n                        }\n                        break;\n                    case GArrangeAction.Type.SendBackward:\n                        if (element.getPrevious() !== null) {\n                            var posElement = element.getPrevious() ? element.getPrevious() : parent.getFirstChild();\n                            parent.removeChild(element);\n                            parent.insertChild(element, posElement);\n                        }\n                        break;\n                    case GArrangeAction.Type.SendToBack:\n                        if (element.getPrevious() !== null) {\n                            parent.removeChild(element);\n                            parent.insertChild(element, parent.getFirstChild());\n                        }\n                        break;\n                }\n            }\n        }.bind(this), ifLocale.get(this.getTitle()));\n\n        if (selection) {\n            document.getEditor().updateSelection(false, selection);\n        }\n    };\n\n    /** @override */\n    GArrangeAction.prototype.toString = function () {\n        return \"[Object GArrangeAction]\";\n    };\n\n    _.GArrangeAction = GArrangeAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/cloneaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for cloning the selection from the current document\n     * @class GCloneAction\n     * @extends GAction\n     * @constructor\n     */\n    function GCloneAction() {\n    };\n    IFObject.inherit(GCloneAction, GAction);\n\n    GCloneAction.ID = 'edit.clone';\n    GCloneAction.TITLE = new IFLocale.Key(GCloneAction, \"title\");\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.getId = function () {\n        return GCloneAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.getTitle = function () {\n        return GCloneAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.getGroup = function () {\n        return \"selection\";\n    };\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.META, 'D'];\n    };\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        return document && document.getEditor().getSelection() != null;\n    };\n\n    /**\n     * @override\n     */\n    GCloneAction.prototype.execute = function () {\n        var editor = gApp.getActiveDocument().getEditor();\n\n        editor.beginTransaction();\n        try {\n            editor.cloneSelection();\n        } finally {\n            editor.commitTransaction(ifLocale.get(this.getTitle()));\n        }\n    };\n\n    /** @override */\n    GCloneAction.prototype.toString = function () {\n        return \"[Object GCloneAction]\";\n    };\n\n    _.GCloneAction = GCloneAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/closeaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action closing a document\n     * @class GCloseAction\n     * @extends GAction\n     * @constructor\n     */\n    function GCloseAction() {\n    };\n    IFObject.inherit(GCloseAction, GAction);\n\n    GCloseAction.ID = \"file.close\";\n    GCloseAction.TITLE = new IFLocale.Key(GCloseAction, \"title\");\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.getId = function () {\n        return GCloseAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.getTitle = function () {\n        return GCloseAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.getGroup = function () {\n        return \"close\";\n    };\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'Q'];\n    };\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.isEnabled = function () {\n        return !!gApp.getWindows().getActiveWindow();\n    };\n\n    /**\n     * @override\n     */\n    GCloseAction.prototype.execute = function () {\n        gApp.getWindows().closeWindow(gApp.getWindows().getActiveWindow());\n    };\n\n    /** @override */\n    GCloseAction.prototype.toString = function () {\n        return \"[Object GCloseAction]\";\n    };\n\n    _.GCloseAction = GCloseAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/closeallaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action closing all documents\n     * @class GCloseAllAction\n     * @extends GAction\n     * @constructor\n     */\n    function GCloseAllAction() {\n    };\n    IFObject.inherit(GCloseAllAction, GAction);\n\n    GCloseAllAction.ID = 'file.close-all';\n    GCloseAllAction.TITLE = new IFLocale.Key(GCloseAllAction, \"title\");\n\n    /**\n     * @override\n     */\n    GCloseAllAction.prototype.getId = function () {\n        return GCloseAllAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GCloseAllAction.prototype.getTitle = function () {\n        return GCloseAllAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GCloseAllAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GCloseAllAction.prototype.getGroup = function () {\n        return \"close\";\n    };\n\n    /**\n     * @override\n     */\n    GCloseAllAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GCloseAllAction.prototype.execute = function () {\n        while (!!gApp.getActiveDocument()) {\n            gApp.closeDocument(gApp.getActiveDocument());\n        }\n    };\n\n    /** @override */\n    GCloseAllAction.prototype.toString = function () {\n        return \"[Object GCloseAllAction]\";\n    };\n\n    _.GCloseAllAction = GCloseAllAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/copyaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for copying the current selection to the clipboard\n     * @class GCopyAction\n     * @extends GAction\n     * @constructor\n     */\n    function GCopyAction() {\n    };\n    IFObject.inherit(GCopyAction, GAction);\n\n    GCopyAction.ID = 'edit.copy';\n    GCopyAction.TITLE = new IFLocale.Key(GCopyAction, \"title\");\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.getId = function () {\n        return GCopyAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.getTitle = function () {\n        return GCopyAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.getGroup = function () {\n        return \"ccp\";\n    };\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'C'];\n    };\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.isEnabled = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            return true;\n        }\n\n        if (gApp.getActiveDocument() && !!gApp.getActiveDocument().getEditor().getSelection()) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('copy');\n        } else {\n            // TODO : Support multiple clipboards internally\n            // TODO : Support copy into system clipboard with\n            // intern format, rasterized and as svg format\n\n            // Make sure to serialize ordered\n            var selection = IFNode.order(gApp.getActiveDocument().getEditor().getSelectionCopy());\n            var serializedSelection = IFNode.serialize(selection);\n            gShell.setClipboardContent(IFNode.MIME_TYPE, serializedSelection);\n        }\n    };\n\n    /** @override */\n    GCopyAction.prototype.toString = function () {\n        return \"[Object GCopyAction]\";\n    };\n\n    _.GCopyAction = GCopyAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/copyattributesaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for copying the current selection's attributes to the clipboard\n     * @class GCopyAttributesAction\n     * @extends GAction\n     * @constructor\n     */\n    function GCopyAttributesAction() {\n    };\n    IFObject.inherit(GCopyAttributesAction, GAction);\n\n    GCopyAttributesAction.ID = 'edit.copy-attributes';\n    GCopyAttributesAction.TITLE = new IFLocale.Key(GCopyAttributesAction, \"title\");\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.getId = function () {\n        return GCopyAttributesAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.getTitle = function () {\n        return GCopyAttributesAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.getGroup = function () {\n        return \"ccp_special\";\n    };\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.F4];\n    };\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.isEnabled = function () {\n        return false;\n        /*\n        var document = gApp.getActiveDocument();\n        if (document) {\n            var selection = document.getEditor().getSelection();\n            if (selection) {\n                for (var i = 0; i < selection.length; ++i) {\n                    if (selection[i].hasMixin(IFElement.Attributes)) {\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;*/\n    };\n\n    /**\n     * @override\n     */\n    GCopyAttributesAction.prototype.execute = function () {\n        var selection = gApp.getActiveDocument().getEditor().getSelection();\n        for (var i = 0; i < selection.length; ++i) {\n            if (selection[i].hasMixin(IFElement.Attributes)) {\n                var attributes = selection[i].getAttributes();\n                if (attributes && attributes.hasMixin(IFNode.Container) && attributes.getFirstChild()) {\n                    var serializedAttributes = IFNode.serialize(attributes);\n                    gShell.setClipboardContent(IFAttribute.MIME_TYPE, serializedAttributes);\n                    break;\n                }\n            }\n        }\n    };\n\n    /** @override */\n    GCopyAttributesAction.prototype.toString = function () {\n        return \"[Object GCopyAttributesAction]\";\n    };\n\n    _.GCopyAttributesAction = GCopyAttributesAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/cutaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for cutting the current selection to the clipboard\n     * @class GCutAction\n     * @extends GAction\n     * @constructor\n     */\n    function GCutAction() {\n    };\n    IFObject.inherit(GCutAction, GAction);\n\n    GCutAction.ID = 'edit.cut';\n    GCutAction.TITLE = new IFLocale.Key(GCutAction, \"title\");\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.getId = function () {\n        return GCutAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.getTitle = function () {\n        return GCutAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.getGroup = function () {\n        return \"ccp\";\n    };\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'X'];\n    };\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.isEnabled = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            return true;\n        }\n\n        if (gApp.getActiveDocument() && !!gApp.getActiveDocument().getEditor().getSelection()) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GCutAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('cut');\n        } else {\n            var editor = gApp.getActiveDocument().getEditor();\n\n            // Run copy action, first\n            gApp.executeAction(GCopyAction.ID);\n\n            // Delete selection now\n            editor.beginTransaction();\n            try {\n                editor.deleteSelection(true);\n            } finally {\n                // TODO : I18N\n                editor.commitTransaction('Cut Selection');\n            }\n        }\n    };\n\n    /** @override */\n    GCutAction.prototype.toString = function () {\n        return \"[Object GCutAction]\";\n    };\n\n    _.GCutAction = GCutAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/deleteaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for deleting the selection from the current document\n     * @class GDeleteAction\n     * @extends GAction\n     * @constructor\n     */\n    function GDeleteAction() {\n    };\n    IFObject.inherit(GDeleteAction, GAction);\n\n    GDeleteAction.ID = 'edit.delete';\n    GDeleteAction.TITLE = new IFLocale.Key(GDeleteAction, \"title\");\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.getId = function () {\n        return GDeleteAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.getTitle = function () {\n        return GDeleteAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.getGroup = function () {\n        return \"ccp\";\n    };\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.REMOVE];\n    };\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n\n        if (document) {\n            var selection = document.getEditor().getSelection();\n            if (selection) {\n                for (var i = 0; i < selection.length; ++i) {\n                    if (selection[i] instanceof IFItem) {\n                        return true;\n                    }\n                }\n            }\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteAction.prototype.execute = function () {\n        var editor = gApp.getActiveDocument().getEditor();\n        editor.deleteSelection();\n    };\n\n    /** @override */\n    GDeleteAction.prototype.toString = function () {\n        return \"[Object GDeleteAction]\";\n    };\n\n    _.GDeleteAction = GDeleteAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/deletelayeraction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for deleting a layer\n     * @class GDeleteLayerAction\n     * @extends GAction\n     * @constructor\n     */\n    function GDeleteLayerAction() {\n    };\n    IFObject.inherit(GDeleteLayerAction, GAction);\n\n    GDeleteLayerAction.ID = 'modify.delete-layer';\n    GDeleteLayerAction.TITLE = new IFLocale.Key(GDeleteLayerAction, \"title\");\n\n    /**\n     * @override\n     */\n    GDeleteLayerAction.prototype.getId = function () {\n        return GDeleteLayerAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteLayerAction.prototype.getTitle = function () {\n        return GDeleteLayerAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteLayerAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_LAYER;\n    };\n\n    /**\n     * @override\n     */\n    GDeleteLayerAction.prototype.getGroup = function () {\n        return \"structure/modify\";\n    };\n\n    /**\n     * @param {IFLayer} [layer] the layer to be removed, if null takes the active one\n     * @override\n     */\n    GDeleteLayerAction.prototype.isEnabled = function (layer) {\n        if (!layer) {\n            layer = gApp.getActiveDocument() ? gApp.getActiveDocument().getScene().getActiveLayer() : null;\n        }\n\n        return !!layer;\n    };\n\n    /**\n     * @param {IFLayer} [layer] the layer to be removed, if null takes the active one\n     * @override\n     */\n    GDeleteLayerAction.prototype.execute = function (layer) {\n        var layer = layer || gApp.getActiveDocument().getScene().getActiveLayer();\n        var scene = layer.getScene();\n\n        if (!scene) {\n            throw new Error('No scene on layer.');\n        }\n\n        // Figure other layer either previous or next one or parent\n        var otherLayer = null;\n\n        for (var node = layer.getPrevious(); node !== null; node = node.getPrevious()) {\n            if (node instanceof IFLayer) {\n                otherLayer = node;\n                break;\n            }\n        }\n\n        if (!otherLayer) {\n            for (var node = layer.getNext(); node !== null; node = node.getNext()) {\n                if (node instanceof IFLayer) {\n                    otherLayer = node;\n                    break;\n                }\n            }\n        }\n\n        if (!otherLayer && layer.getParent() instanceof IFLayer) {\n            otherLayer = layer.getParent();\n        }\n\n        // If there's no other layer, stop here as we need at least one layer in the scene\n        if (!otherLayer) {\n            // TODO : I18N\n            alert('Unable to delete - the page needs to contain at least one layer.');\n            return;\n        }\n\n        // If layer is active, de-activate it first and activate the other one\n        if (layer.hasFlag(IFNode.Flag.Active)) {\n            scene.setActiveLayer(otherLayer);\n        }\n\n        // Finally we can remove the layer\n        // TODO : I18N\n        IFEditor.tryRunTransaction(scene, function () {\n            layer.getParent().removeChild(layer);\n        }, ifLocale.get(this.getTitle()));\n    };\n\n    /** @override */\n    GDeleteLayerAction.prototype.toString = function () {\n        return \"[Object GDeleteLayerAction]\";\n    };\n\n    _.GDeleteLayerAction = GDeleteLayerAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/deletepageaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for deleting the active page\n     * @class GDeletePageAction\n     * @extends GAction\n     * @constructor\n     */\n    function GDeletePageAction() {\n    };\n    IFObject.inherit(GDeletePageAction, GAction);\n\n    GDeletePageAction.ID = 'modify.delete-page';\n    GDeletePageAction.TITLE = new IFLocale.Key(GDeletePageAction, \"title\");\n\n    /**\n     * @override\n     */\n    GDeletePageAction.prototype.getId = function () {\n        return GDeletePageAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GDeletePageAction.prototype.getTitle = function () {\n        return GDeletePageAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GDeletePageAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_PAGE;\n    };\n\n    /**\n     * @override\n     */\n    GDeletePageAction.prototype.getGroup = function () {\n        return \"structure/modify\";\n    };\n\n    /**\n     * @param {IFPage} [page] the page to be removed, if null takes the active one\n     * @override\n     */\n    GDeletePageAction.prototype.isEnabled = function (page) {\n        if (!page) {\n            page = gApp.getActiveDocument() ? gApp.getActiveDocument().getScene().getActivePage() : null;\n        }\n\n        return !!page;\n    };\n\n    /**\n     * @param {IFPage} [page] the page to be removed, if null takes the active one\n     * @override\n     */\n    GDeletePageAction.prototype.execute = function (page) {\n        var page = page || gApp.getActiveDocument().getScene().getActivePage();\n        var scene = page.getScene();\n\n        if (!scene) {\n            throw new Error('No scene on page.');\n        }\n\n        // Figure other page either previous or next one\n        var otherPage = null;\n\n        for (var node = page.getPrevious(); node !== null; node = node.getPrevious()) {\n            if (node instanceof IFPage) {\n                otherPage = node;\n                break;\n            }\n        }\n\n        if (!otherPage) {\n            for (var node = page.getNext(); node !== null; node = node.getNext()) {\n                if (node instanceof IFPage) {\n                    otherPage = node;\n                    break;\n                }\n            }\n        }\n\n        // If there's no other page, stop here as we need at least one page in the scene\n        if (!otherPage) {\n            // TODO : I18N\n            alert('Unable to delete - the document needs to contain at least one page.');\n            return;\n        }\n\n        // If page is active, de-activate it first and activate the other one\n        if (page.hasFlag(IFNode.Flag.Active)) {\n            scene.setActivePage(otherPage);\n        }\n\n        // Finally we can remove the page\n        // TODO : I18N\n        IFEditor.tryRunTransaction(scene, function () {\n            page.getParent().removeChild(page);\n        }, ifLocale.get(this.getTitle()));\n    };\n\n    /** @override */\n    GDeletePageAction.prototype.toString = function () {\n        return \"[Object GDeletePageAction]\";\n    };\n\n    _.GDeletePageAction = GDeletePageAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/distributeaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for distributing\n     * @class GDistributeAction\n     * @extends GAction\n     * @constructor\n     */\n    function GDistributeAction(type) {\n        this._type = type;\n        this._title = new IFLocale.Key(GDistributeAction, 'title.' + type);\n    };\n    IFObject.inherit(GDistributeAction, GAction);\n\n    /** @enum */\n    GDistributeAction.Type = {\n        Horizontal: 'horizontal',\n        Vertical: 'vertical'\n    };\n\n    GDistributeAction.ID = 'arrange.distribute';\n\n    /** @type {GDistributeAction.Type} */\n    GDistributeAction.prototype._type = null;\n\n    /** @type {IFLocale.Key} */\n    GDistributeAction.prototype._title = null;\n\n    /**\n     * @override\n     */\n    GDistributeAction.prototype.getId = function () {\n        return GDistributeAction.ID + '.' + this._type;\n    };\n\n    /**\n     * @override\n     */\n    GDistributeAction.prototype.getTitle = function () {\n        return this._title;\n    };\n\n    /**\n     * @override\n     */\n    GDistributeAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_ALIGN;\n    };\n\n    /**\n     * @override\n     */\n    GDistributeAction.prototype.getGroup = function () {\n        return 'arrange/align-distribute';\n    };\n\n    /**\n     * @override\n     */\n    GDistributeAction.prototype.getShortcut = function () {\n        return null;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @param {Boolean} [geometry] if provided, specifies whether to\n     * use geometry box for distributing, otherwise use paint box. Defaults\n     * to false.\n     * @param {IFRect} [referenceBox] a reference box to dstribute within, if not\n     * given uses the element's total bbox\n     * @param {Number} [spacing] a fixed spacing value. If not provided or zero then\n     * spacing will be calculated automatically using the given box\n     * @override\n     */\n    GDistributeAction.prototype.isEnabled = function (elements, geometry, referenceBox, spacing) {\n        elements = elements || (gApp.getActiveDocument() ? gApp.getActiveDocument().getEditor().getSelection() : null);\n        if (elements) {\n            return referenceBox ? elements.length > 1 : elements.length > 2;\n        }\n        return false;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @param {Boolean} [geometry] if provided, specifies whether to\n     * use geometry box for distributing, otherwise use paint box. Defaults\n     * to false.\n     * @param {IFRect} [referenceBox] a reference box to dstribute within, if not\n     * given uses the element's total bbox\n     * @param {Number} [spacing] a fixed spacing value. If not provided or zero then\n     * spacing will be calculated automatically using the given box\n     * @override\n     */\n    GDistributeAction.prototype.execute = function (elements, geometry, referenceBox, spacing) {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n\n        if (!elements) {\n            elements = document.getEditor().getSelection();\n        }\n\n        var tmpElements = elements;\n        var elements = [];\n\n        for (var i = 0; i < tmpElements.length; ++i) {\n            var element = tmpElements[i];\n            if (element.hasMixin(IFElement.Transform)) {\n                var bbox = geometry ? element.getGeometryBBox() : element.getPaintBBox();\n                if (!bbox || bbox.isEmpty()) {\n                    continue;\n                }\n\n                elements.push({\n                    bbox: bbox,\n                    element: element\n                });\n            }\n        }\n\n        if (!referenceBox) {\n            for (var i = 0; i < elements.length; ++i) {\n                var bbox = elements[i].element.getPaintBBox();\n                if (bbox && !bbox.isEmpty()) {\n                    referenceBox = referenceBox ? referenceBox.united(bbox) : bbox;\n                }\n            }\n        }\n\n        if (!referenceBox || referenceBox.isEmpty()) {\n            return;\n        }\n\n        if (this._type === GDistributeAction.Type.Horizontal) {\n            elements.sort(function (e1, e2) {\n                return e1.bbox.getX() > e2.bbox.getX();\n            });\n\n            if (!spacing) {\n                var elementsTotal = 0;\n                for (var i = 0; i < elements.length; ++i) {\n                    elementsTotal += elements[i].bbox.getWidth();\n                }\n                spacing = (referenceBox.getWidth() - elementsTotal) / (elements.length - 1);\n            }\n\n            IFEditor.tryRunTransaction(scene, function () {\n                var position = referenceBox.getX();\n\n                for (var i = 0; i < elements.length; ++i) {\n                    if (position !== elements[i].bbox.getX()) {\n                        elements[i].element.transform(new IFTransform(1, 0, 0, 1, position - elements[i].bbox.getX(), 0));\n                    }\n                    position += elements[i].bbox.getWidth() + spacing;\n                }\n            }.bind(this), ifLocale.get(this.getTitle()));\n        } else if (this._type === GDistributeAction.Type.Vertical) {\n            elements.sort(function (e1, e2) {\n                return e1.bbox.getY() > e2.bbox.getY();\n            });\n\n            if (!spacing) {\n                var elementsTotal = 0;\n                for (var i = 0; i < elements.length; ++i) {\n                    elementsTotal += elements[i].bbox.getHeight();\n                }\n                spacing = (referenceBox.getHeight() - elementsTotal) / (elements.length - 1);\n            }\n\n            IFEditor.tryRunTransaction(scene, function () {\n                var position = referenceBox.getY();\n\n                for (var i = 0; i < elements.length; ++i) {\n                    if (position !== elements[i].bbox.getY()) {\n                        elements[i].element.transform(new IFTransform(1, 0, 0, 1, 0, position - elements[i].bbox.getY()));\n                    }\n                    position += elements[i].bbox.getHeight() + spacing;\n                }\n            }.bind(this), ifLocale.get(this.getTitle()));\n        }\n    };\n\n    /** @override */\n    GDistributeAction.prototype.toString = function () {\n        return \"[Object GDistributeAction]\";\n    };\n\n    _.GDistributeAction = GDistributeAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/duplicateaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for cloning the selection from the current document\n     * @class GDuplicateAction\n     * @extends GAction\n     * @constructor\n     */\n    function GDuplicateAction() {\n    };\n    IFObject.inherit(GDuplicateAction, GAction);\n\n    GDuplicateAction.ID = 'edit.duplicate';\n    GDuplicateAction.TITLE = new IFLocale.Key(GDuplicateAction, \"title\");\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.getId = function () {\n        return GDuplicateAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.getTitle = function () {\n        return GDuplicateAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.getGroup = function () {\n        return \"selection\";\n    };\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'D'];\n    };\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        return document && document.getEditor().getSelection() != null;\n    };\n\n    /**\n     * @override\n     */\n    GDuplicateAction.prototype.execute = function () {\n        var editor = gApp.getActiveDocument().getEditor();\n\n        editor.beginTransaction();\n        try {\n            editor.cloneSelection(true, true);\n        } finally {\n            editor.commitTransaction(ifLocale.get(this.getTitle()));\n        }\n    };\n\n    /** @override */\n    GDuplicateAction.prototype.toString = function () {\n        return \"[Object GDuplicateAction]\";\n    };\n\n    _.GDuplicateAction = GDuplicateAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/fitallaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for fitting everything into the current view\n     * @class GFitAllAction\n     * @extends GAction\n     * @constructor\n     */\n    function GFitAllAction() {\n    };\n    IFObject.inherit(GFitAllAction, GAction);\n\n    GFitAllAction.ID = 'view.zoom.fit.all';\n    GFitAllAction.TITLE = new IFLocale.Key(GFitAllAction, \"title\");\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.getId = function () {\n        return GFitAllAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.getTitle = function () {\n        return GFitAllAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.getGroup = function () {\n        return \"zoom\";\n    };\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'O'];\n    };\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        var paintBBox = document ? document.getScene().getPaintBBox() : null;\n        return (paintBBox && !paintBBox.isEmpty());\n    };\n\n    /**\n     * @override\n     */\n    GFitAllAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        if (document.getScene().getProperty('singlePage')) {\n            var currentPage = document.getScene().getActivePage();\n            document.getActiveWindow().getView().zoomAll(currentPage.getPaintBBox(), false);\n        } else {\n            document.getActiveWindow().getView().zoomAll(document.getScene().getPaintBBox(), false);\n        }\n    };\n\n    /** @override */\n    GFitAllAction.prototype.toString = function () {\n        return \"[Object GFitAllAction]\";\n    };\n\n    _.GFitAllAction = GFitAllAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/fitcurrentlayeraction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for fitting the current layer into the current view\n     * @class GFitCurrentLayerAction\n     * @extends GAction\n     * @constructor\n     */\n    function GFitCurrentLayerAction() {\n    };\n    IFObject.inherit(GFitCurrentLayerAction, GAction);\n\n    GFitCurrentLayerAction.ID = 'view.zoom.fit-current-layer';\n    GFitCurrentLayerAction.TITLE = new IFLocale.Key(GFitCurrentLayerAction, \"title\");\n\n    /**\n     * @override\n     */\n    GFitCurrentLayerAction.prototype.getId = function () {\n        return GFitCurrentLayerAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentLayerAction.prototype.getTitle = function () {\n        return GFitCurrentLayerAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentLayerAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentLayerAction.prototype.getGroup = function () {\n        return \"zoom\";\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentLayerAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        var activeLayer = document ? document.getScene().getActiveLayer() : null;\n\n        return (activeLayer && activeLayer.getPaintBBox() && !activeLayer.getPaintBBox().isEmpty());\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentLayerAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        var activeLayer = document.getScene().getActiveLayer();\n        document.getActiveWindow().getView().zoomAll(activeLayer.getPaintBBox(), false);\n    };\n\n    /** @override */\n    GFitCurrentLayerAction.prototype.toString = function () {\n        return \"[Object GFitCurrentLayerAction]\";\n    };\n\n    _.GFitCurrentLayerAction = GFitCurrentLayerAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/fitcurrentpageaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for fitting the current page into the current view\n     * @class GFitCurrentPageAction\n     * @extends GAction\n     * @constructor\n     */\n    function GFitCurrentPageAction() {\n    };\n    IFObject.inherit(GFitCurrentPageAction, GAction);\n\n    GFitCurrentPageAction.ID = 'view.zoom.fit-current-page';\n    GFitCurrentPageAction.TITLE = new IFLocale.Key(GFitCurrentPageAction, \"title\");\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.getId = function () {\n        return GFitCurrentPageAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.getTitle = function () {\n        return GFitCurrentPageAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.getGroup = function () {\n        return \"zoom\";\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, IFKey.Constant.SHIFT, 'W'];\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        var currentPage = document ? document.getScene().getActivePage() : null;\n\n        return (currentPage && currentPage.getPaintBBox() && !currentPage.getPaintBBox().isEmpty());\n    };\n\n    /**\n     * @override\n     */\n    GFitCurrentPageAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        var currentPage = document.getScene().getActivePage();\n        document.getActiveWindow().getView().zoomAll(currentPage.getPaintBBox(), false);\n    };\n\n    /** @override */\n    GFitCurrentPageAction.prototype.toString = function () {\n        return \"[Object GFitCurrentPageAction]\";\n    };\n\n    _.GFitCurrentPageAction = GFitCurrentPageAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/fitselectionaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for fitting the selection into the current view\n     * @class GFitSelectionAction\n     * @extends GAction\n     * @constructor\n     */\n    function GFitSelectionAction() {\n    };\n    IFObject.inherit(GFitSelectionAction, GAction);\n\n    GFitSelectionAction.ID = 'view.zoom.fit-selection';\n    GFitSelectionAction.TITLE = new IFLocale.Key(GFitSelectionAction, \"title\");\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.getId = function () {\n        return GFitSelectionAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.getTitle = function () {\n        return GFitSelectionAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.getGroup = function () {\n        return \"zoom\";\n    };\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, IFKey.Constant.OPTION, 'O'];\n    };\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        var editor = document ? document.getEditor() : null;\n        return editor && editor.hasSelection();\n    };\n\n    /**\n     * @override\n     */\n    GFitSelectionAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        var editor = document ? document.getEditor() : null;\n        var selection = editor.getSelection();\n        var selBBox = null;\n\n        for (var i = 0; i < selection.length; ++i) {\n            var bbox = selection[i].getPaintBBox();\n            if (bbox && !bbox.isEmpty()) {\n                selBBox = selBBox ? selBBox.united(bbox) : bbox;\n            }\n        }\n\n        if (selBBox && !selBBox.isEmpty()) {\n            document.getActiveWindow().getView().zoomAll(selBBox, false);\n        }\n    };\n\n    /** @override */\n    GFitSelectionAction.prototype.toString = function () {\n        return \"[Object GFitSelectionAction]\";\n    };\n\n    _.GFitSelectionAction = GFitSelectionAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/groupaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for grouping the selection together\n     * @class GGroupAction\n     * @extends GAction\n     * @constructor\n     */\n    function GGroupAction() {\n    };\n    IFObject.inherit(GGroupAction, GAction);\n\n    GGroupAction.ID = 'modify.group';\n    GGroupAction.TITLE = new IFLocale.Key(GGroupAction, \"title\");\n\n    /**\n     * @override\n     */\n    GGroupAction.prototype.getId = function () {\n        return GGroupAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GGroupAction.prototype.getTitle = function () {\n        return GGroupAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GGroupAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY;\n    };\n\n    /**\n     * @override\n     */\n    GGroupAction.prototype.getGroup = function () {\n        return \"structure-group\";\n    };\n\n    /**\n     * @override\n     */\n    GGroupAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'G'];\n    };\n\n    /**\n     * @override\n     */\n    GGroupAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        if (document) {\n            var selection = document.getEditor().getSelection();\n            return selection && selection.length > 1;\n        }\n        return false;\n    };\n\n    /** @override */\n    GGroupAction.prototype.execute = function () {\n        var editor = gApp.getActiveDocument().getEditor();\n        var selection = editor.getSelection();\n\n        editor.beginTransaction();\n        try {\n            // Create our group (= shapeSet)\n            var group = new IFShapeSet();\n\n            // Collect all items to be added to the group\n            var itemsToGroup = [];\n            for (var i = 0; i < selection.length; ++i) {\n                var item = selection[i];\n                if (item.validateInsertion(group)) {\n                    itemsToGroup.push(item);\n                }\n            }\n\n            if (itemsToGroup.length > 0) {\n                // Add items to group\n                for (var i = 0; i < itemsToGroup.length; ++i) {\n                    var item = itemsToGroup[i];\n                    item.getParent().removeChild(item);\n                    group.appendChild(item);\n                }\n\n                // Insert group\n                editor.insertElements([group], true, true);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Group');\n        }\n    };\n\n    /** @override */\n    GGroupAction.prototype.toString = function () {\n        return \"[Object GGroupAction]\";\n    };\n\n    _.GGroupAction = GGroupAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/invertselectionaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for inverting the current selection\n     * @class GInvertSelectionAction\n     * @extends GAction\n     * @constructor\n     */\n    function GInvertSelectionAction() {\n    };\n    IFObject.inherit(GInvertSelectionAction, GAction);\n\n    GInvertSelectionAction.ID = 'edit.invert-selection';\n    GInvertSelectionAction.TITLE = new IFLocale.Key(GInvertSelectionAction, \"title\");\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.getId = function () {\n        return GInvertSelectionAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.getTitle = function () {\n        return GInvertSelectionAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.getGroup = function () {\n        return \"select\";\n    };\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.META, 'A'];\n    };\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GInvertSelectionAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n\n        var source = null;\n        if (scene.getProperty('singlePage')) {\n            source = scene.getActivePage();\n        } else {\n            source = scene;\n        }\n\n        var selection = [];\n        source.accept(function (node) {\n            if (node instanceof IFItem && node.getParent() instanceof IFLayer && !node.hasFlag(IFNode.Flag.Selected)) {\n                selection.push(node);\n            }\n        });\n\n        document.getEditor().updateSelection(false, selection);\n    };\n\n    /** @override */\n    GInvertSelectionAction.prototype.toString = function () {\n        return \"[Object GInvertSelectionAction]\";\n    };\n\n    _.GInvertSelectionAction = GInvertSelectionAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/layertypeaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for setting the type of the active layer\n     * @class GLayerTypeAction\n     * @extends GAction\n     * @constructor\n     */\n    function GLayerTypeAction(layerType) {\n        this._layerType = layerType;\n    };\n    IFObject.inherit(GLayerTypeAction, GAction);\n\n    GLayerTypeAction.ID = 'modify.layer-type';\n    GLayerTypeAction.TITLE = new IFLocale.Key(GLayerTypeAction, 'title');\n\n    /**\n     * @type {IFLayer.Type}\n     * @private\n     */\n    GLayerTypeAction.prototype._layerType = null;\n\n    /**\n     * @override\n     */\n    GLayerTypeAction.prototype.getId = function () {\n        return GLayerTypeAction.ID + '.' + this._layerType;\n    };\n\n    /**\n     * @override\n     */\n    GLayerTypeAction.prototype.getTitle = function () {\n        return ifLocale.get(GLayerTypeAction.TITLE).replace('%name%',\n            ifLocale.get(IFLayer.TypeName[this._layerType]));\n    };\n\n    /**\n     * @override\n     */\n    GLayerTypeAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_LAYER;\n    };\n\n    /** @override */\n    GLayerTypeAction.prototype.getGroup = function () {\n        return \"structure/type\";\n    };\n\n    /** @override */\n    GLayerTypeAction.prototype.isCheckable = function () {\n        return true;\n    };\n\n    /**\n     * @override\n     */\n    GLayerTypeAction.prototype.isChecked = function () {\n        var activeLayer = gApp.getActiveDocument() ? gApp.getActiveDocument().getScene().getActiveLayer() : null;\n        if (activeLayer) {\n            return activeLayer.getProperty('tp') === this._layerType;\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GLayerTypeAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GLayerTypeAction.prototype.execute = function () {\n        var activeLayer = gApp.getActiveDocument() ? gApp.getActiveDocument().getScene().getActiveLayer() : null;\n        if (activeLayer) {\n            activeLayer.setProperty('tp', this._layerType);\n        }\n    };\n\n    /** @override */\n    GLayerTypeAction.prototype.toString = function () {\n        return \"[Object GLayerTypeAction]\";\n    };\n\n    _.GLayerTypeAction = GLayerTypeAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/magnificationaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for setting a specific magnfication on current view\n     * @class GMagnificationAction\n     * @extends GAction\n     * @constructor\n     */\n    function GMagnificationAction(magnification, shortcut) {\n        this._magnification = magnification;\n        this._shortcut = shortcut;\n    };\n    IFObject.inherit(GMagnificationAction, GAction);\n\n    GMagnificationAction.ID = 'view.magnification';\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    GMagnificationAction.prototype._magnification = null;\n\n    /**\n     * @type {Array<Number>}\n     * @private\n     */\n    GMagnificationAction.prototype._shortcut = null;\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.getId = function () {\n        return GMagnificationAction.ID + '.' + this._magnification.toString();\n    };\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.getTitle = function () {\n        return this._magnification.toString() + '%';\n    };\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW_MAGNIFICATION;\n    };\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.getGroup = function () {\n        return \"zoom/magnification-level\";\n    };\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.getShortcut = function () {\n        return this._shortcut;\n    };\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.isEnabled = function () {\n        return !!gApp.getWindows().getActiveWindow();\n    };\n\n    /**\n     * @override\n     */\n    GMagnificationAction.prototype.execute = function () {\n        var view = gApp.getWindows().getActiveWindow().getView();\n        var newZoom = this._magnification / 100.0;\n        var scene = view.getScene();\n        var zoomPoint = null;\n        if (scene.getProperty('singlePage')) {\n            var pageBBox = scene.getActivePage().getGeometryBBox();\n            if (pageBBox && !pageBBox.isEmpty()) {\n                zoomPoint = pageBBox.getSide(IFRect.Side.CENTER);\n            }\n        }\n        if (!zoomPoint) {\n            zoomPoint = view.getViewTransform().mapPoint(new IFPoint(view.getWidth() / 2.0, view.getHeight() / 2.0));\n        }\n        view.zoomAt(zoomPoint, newZoom);\n    };\n\n    /** @override */\n    GMagnificationAction.prototype.toString = function () {\n        return \"[Object GMagnificationAction]\";\n    };\n\n    _.GMagnificationAction = GMagnificationAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/newaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action creating a new document\n     * @class GNewAction\n     * @extends GAction\n     * @constructor\n     */\n    function GNewAction() {\n    };\n    IFObject.inherit(GNewAction, GAction);\n\n    GNewAction.ID = 'file.new';\n    GNewAction.TITLE = new IFLocale.Key(GNewAction, \"title\");\n\n    /**\n     * @override\n     */\n    GNewAction.prototype.getId = function () {\n        return GNewAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GNewAction.prototype.getTitle = function () {\n        return GNewAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GNewAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GNewAction.prototype.getGroup = function () {\n        return \"file\";\n    };\n\n    /**\n     * @override\n     */\n    GNewAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'N'];\n    };\n\n    /**\n     * @override\n     */\n    GNewAction.prototype.execute = function () {\n        gApp.createNewDocument();\n    };\n\n    /** @override */\n    GNewAction.prototype.toString = function () {\n        return \"[Object GNewAction]\";\n    };\n\n    _.GNewAction = GNewAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/newwindowaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for cloning the current view\n     * @class GNewWindowAction\n     * @extends GAction\n     * @constructor\n     */\n    function GNewWindowAction() {\n    };\n    IFObject.inherit(GNewWindowAction, GAction);\n\n    GNewWindowAction.ID = 'view.clone';\n    GNewWindowAction.TITLE = new IFLocale.Key(GNewWindowAction, \"title\");\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.getId = function () {\n        return GNewWindowAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.getTitle = function () {\n        return GNewWindowAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_WINDOW;\n    };\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.getGroup = function () {\n        return \"view\";\n    };\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, IFKey.Constant.OPTION, 'N'];\n    };\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.isEnabled = function () {\n        return !!gApp.getWindows().getActiveWindow();\n    };\n\n    /**\n     * @override\n     */\n    GNewWindowAction.prototype.execute = function () {\n        gApp.getWindows().addWindow(gApp.getWindows().getActiveWindow());\n    };\n\n    /** @override */\n    GNewWindowAction.prototype.toString = function () {\n        return \"[Object GNewWindowAction]\";\n    };\n\n    _.GNewWindowAction = GNewWindowAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/openaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action opening a document via the system storage\n     * @class GOpenAction\n     * @extends GAction\n     * @constructor\n     */\n    function GOpenAction() {\n    };\n    IFObject.inherit(GOpenAction, GAction);\n\n    GOpenAction.ID = 'file.open';\n    GOpenAction.TITLE = new IFLocale.Key(GOpenAction, \"title\");\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.getId = function () {\n        return GOpenAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.getTitle = function () {\n        return GOpenAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.getGroup = function () {\n        return 'file';\n    };\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'O'];\n    };\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.isEnabled = function () {\n        return !!this._getViableStorage();\n    };\n\n    /**\n     * @override\n     */\n    GOpenAction.prototype.execute = function () {\n        gApp.openDocumentFrom(this._getViableStorage());\n    };\n\n    /**\n     * @returns {GStorage}\n     * @private\n     */\n    GOpenAction.prototype._getViableStorage = function () {\n        for (var i = 0; i < gravit.storages.length; ++i) {\n            var storage = gravit.storages[i];\n            if (storage.isAvailable() && storage.isPrompting()) {\n                var extensions = storage.getExtensions();\n                if (!extensions || extensions.isEmpty() || extensions.indexOf('gravit') >= 0) {\n                    return storage;\n                }\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    GOpenAction.prototype.toString = function () {\n        return \"[Object GOpenAction]\";\n    };\n\n    _.GOpenAction = GOpenAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/originalviewaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for reseting the current view to the original view\n     * @class GOriginalViewAction\n     * @extends GAction\n     * @constructor\n     */\n    function GOriginalViewAction() {\n    };\n    IFObject.inherit(GOriginalViewAction, GAction);\n\n    GOriginalViewAction.ID = 'view.zoom.original';\n    GOriginalViewAction.TITLE = new IFLocale.Key(GOriginalViewAction, \"title\");\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.getId = function () {\n        return GOriginalViewAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.getTitle = function () {\n        return GOriginalViewAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.getGroup = function () {\n        return \"zoom\";\n    };\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, '0'];\n    };\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GOriginalViewAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        var paintBBox = document.getScene().getPaintBBox();\n        document.getActiveWindow().getView().zoomAtCenter(paintBBox && !paintBBox.isEmpty() ? paintBBox.getSide(IFRect.Side.CENTER) : new IFPoint(0, 0), 1.0);\n    };\n\n    /** @override */\n    GOriginalViewAction.prototype.toString = function () {\n        return \"[Object GOriginalViewAction]\";\n    };\n\n    _.GOriginalViewAction = GOriginalViewAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/paintmodeaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for changing paint mode in the current view\n     * @class GPaintModeAction\n     * @extends GAction\n     * @constructor\n     */\n    function GPaintModeAction(paintMode) {\n        this._paintMode = paintMode;\n    };\n    IFObject.inherit(GPaintModeAction, GAction);\n\n    GPaintModeAction.ID = 'view.page.decoration';\n    GPaintModeAction.TITLE = new IFLocale.Key(GPaintModeAction, 'title');\n\n    /**\n     * @type {IFScenePaintConfiguration.PaintMode}\n     * @private\n     */\n    GPaintModeAction.prototype._paintMode = null;\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.getId = function () {\n        return GPaintModeAction.ID + '.' + this._paintMode;\n    };\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.getTitle = function () {\n        return ifLocale.get(GPaintModeAction.TITLE).replace('%name%',\n            ifLocale.get(IFScenePaintConfiguration.PaintModeName[this._paintMode]));\n    };\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.getGroup = function () {\n        return \"paint-mode\";\n    };\n\n    /** @override */\n    GPaintModeAction.prototype.isCheckable = function () {\n        return true;\n    };\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.isChecked = function () {\n        var window = gApp.getWindows().getActiveWindow();\n        if (window) {\n            return window.getView().getViewConfiguration().paintMode === this._paintMode;\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.isEnabled = function () {\n        return !!gApp.getWindows().getActiveWindow();\n    };\n\n    /**\n     * @override\n     */\n    GPaintModeAction.prototype.execute = function () {\n        var view = gApp.getWindows().getActiveWindow().getView();\n        view.getViewConfiguration().paintMode = this._paintMode;\n        view.invalidate();\n    };\n\n    /** @override */\n    GPaintModeAction.prototype.toString = function () {\n        return \"[Object GPaintModeAction]\";\n    };\n\n    _.GPaintModeAction = GPaintModeAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/pasteaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for pasting clipboard contents into the center of active page\n     * @class GPasteAction\n     * @extends GAction\n     * @constructor\n     */\n    function GPasteAction() {\n    };\n    IFObject.inherit(GPasteAction, GAction);\n\n    GPasteAction.ID = 'edit.paste';\n    GPasteAction.TITLE = new IFLocale.Key(GPasteAction, \"title\");\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.getId = function () {\n        return GPasteAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.getTitle = function () {\n        return GPasteAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.getGroup = function () {\n        return \"ccp\";\n    };\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'V'];\n    };\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.isEnabled = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            return true;\n        }\n\n        var cpMimeTypes = gShell.getClipboardMimeTypes();\n        if (cpMimeTypes && cpMimeTypes.indexOf(IFNode.MIME_TYPE) >= 0) {\n            return !!gApp.getActiveDocument();\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('paste');\n        } else {\n            // TODO : Support pasting other formats like raster images\n            var nodes = IFNode.deserialize(gShell.getClipboardContent(IFNode.MIME_TYPE));\n            if (nodes && nodes.length > 0) {\n                var elements = [];\n                var editor = gApp.getActiveDocument().getEditor();\n                var page = gApp.getActiveDocument().getScene().querySingle('page:active');\n                var pageCntr = page.getGeometryBBox().getSide(IFRect.Side.CENTER);\n                for (var i = 0; i < nodes.length; ++i) {\n                    if (nodes[i] instanceof IFElement) {\n                        var element = nodes[i];\n                        var bbox = element.getGeometryBBox();\n                        var elemCntr = bbox ? bbox.getSide(IFRect.Side.CENTER) : new IFPoint(0,0);\n\n                        element.transform(new IFTransform(1, 0, 0, 1,\n                            -elemCntr.getX() + pageCntr.getX(), -elemCntr.getY() + pageCntr.getY()));\n\n                        elements.push(element);\n                    }\n                }\n\n                if (elements.length > 0) {\n                    editor.beginTransaction();\n                    try {\n                        editor.insertElements(elements, true, true);\n                    } finally {\n                        // TODO : I18N\n                        editor.commitTransaction('Paste');\n                    }\n                }\n            }\n        }\n    };\n\n    /** @override */\n    GPasteAction.prototype.toString = function () {\n        return \"[Object GPasteAction]\";\n    };\n\n    _.GPasteAction = GPasteAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/pasteattributesaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for pasting clipboard contents as attributes\n     * @class GPasteAttributesAction\n     * @extends GAction\n     * @constructor\n     */\n    function GPasteAttributesAction() {\n    };\n    IFObject.inherit(GPasteAttributesAction, GAction);\n\n    GPasteAttributesAction.ID = 'edit.paste-attributes';\n    GPasteAttributesAction.TITLE = new IFLocale.Key(GPasteAttributesAction, \"title\");\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.getId = function () {\n        return GPasteAttributesAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.getTitle = function () {\n        return GPasteAttributesAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.getGroup = function () {\n        return \"ccp_special\";\n    };\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.F4];\n    };\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.isEnabled = function () {\n        return false;\n        /*\n        var cpMimeTypes = gShell.getClipboardMimeTypes();\n        if (cpMimeTypes && cpMimeTypes.indexOf(IFAttribute.MIME_TYPE) >= 0) {\n            var document = gApp.getActiveDocument();\n            if (document) {\n                var selection = document.getEditor().getSelection();\n                if (selection) {\n                    for (var i = 0; i < selection.length; ++i) {\n                        if (selection[i].hasMixin(IFElement.Attributes)) {\n                            return true;\n                        }\n                    }\n                }\n            }\n        }\n        return false;\n        */\n    };\n\n    /**\n     * @override\n     */\n    GPasteAttributesAction.prototype.execute = function () {\n        var attributes = IFNode.deserialize(gShell.getClipboardContent(IFAttribute.MIME_TYPE));\n        if (attributes) {\n            var editor = gApp.getActiveDocument().getEditor();\n            var selection = editor.getSelection();\n\n            editor.beginTransaction();\n            try {\n                for (var i = 0; i < selection.length; ++i) {\n                    var target = selection[i];\n                    if (target.hasMixin(IFElement.Attributes)) {\n                        target.getAttributes().assignAttributesFrom(attributes);\n                    }\n                }\n            } finally {\n                // TODO : I18N\n                editor.commitTransaction('Paste Attributes');\n            }\n        }\n    };\n\n    /** @override */\n    GPasteAttributesAction.prototype.toString = function () {\n        return \"[Object GPasteAttributesAction]\";\n    };\n\n    _.GPasteAttributesAction = GPasteAttributesAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/pasteinplaceaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for pasting clipboard contents onto the positions relative to the active page top left\n     * @class GPasteInPlaceAction\n     * @extends GPasteAction\n     * @constructor\n     */\n    function GPasteInPlaceAction() {\n    };\n    IFObject.inherit(GPasteInPlaceAction, GPasteAction);\n\n    GPasteInPlaceAction.ID = 'edit.paste-in-place';\n    GPasteInPlaceAction.TITLE = new IFLocale.Key(GPasteInPlaceAction, \"title\");\n\n    /**\n     * @override\n     */\n    GPasteInPlaceAction.prototype.getId = function () {\n        return GPasteInPlaceAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GPasteInPlaceAction.prototype.getTitle = function () {\n        return GPasteInPlaceAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GPasteInPlaceAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('paste');\n        } else {\n            // TODO : Support pasting other formats like raster images\n            var nodes = IFNode.deserialize(gShell.getClipboardContent(IFNode.MIME_TYPE));\n            if (nodes && nodes.length > 0) {\n                var elements = [];\n                var page = gApp.getActiveDocument().getScene().querySingle('page:active');\n                for (var i = 0; i < nodes.length; ++i) {\n                    if (nodes[i] instanceof IFElement) {\n                        var element = nodes[i];\n                        element.transform(\n                            new IFTransform(1, 0, 0, 1, page.getProperty('x'), page.getProperty('y')));\n                        elements.push(element);\n                    }\n                }\n\n                if (elements.length > 0) {\n                    var editor = gApp.getActiveDocument().getEditor();\n                    editor.beginTransaction();\n                    try {\n                        editor.insertElements(elements, true, true);\n                    } finally {\n                        // TODO : I18N\n                        editor.commitTransaction('Paste');\n                    }\n                }\n            }\n        }\n    };\n\n    /** @override */\n    GPasteInPlaceAction.prototype.toString = function () {\n        return \"[Object GPasteInPlaceAction]\";\n    };\n\n    _.GPasteInPlaceAction = GPasteInPlaceAction;\n})(this);\n"
  },
  {
    "path": "src/gravit/action/pasteinsideaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for pasting clipboard contents into selection\n     * @class GPasteInsideAction\n     * @extends GAction\n     * @constructor\n     */\n    function GPasteInsideAction() {\n    };\n    IFObject.inherit(GPasteInsideAction, GAction);\n\n    GPasteInsideAction.ID = 'edit.paste-inside';\n    GPasteInsideAction.TITLE = new IFLocale.Key(GPasteInsideAction, \"title\");\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.getId = function () {\n        return GPasteInsideAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.getTitle = function () {\n        return GPasteInsideAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.getGroup = function () {\n        return \"ccp\";\n    };\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.META, 'V'];\n    };\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.isEnabled = function () {\n        var cpMimeTypes = gShell.getClipboardMimeTypes();\n        if (cpMimeTypes && cpMimeTypes.indexOf(IFNode.MIME_TYPE) >= 0) {\n            var document = gApp.getActiveDocument();\n            if (document) {\n                var selection = document.getEditor().getSelection();\n                if (selection) {\n                    for (var i = 0; i < selection.length; ++i) {\n                        if (selection[i].hasMixin(IFNode.Container)) {\n                            return true;\n                        }\n                    }\n                }\n            }\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GPasteInsideAction.prototype.execute = function () {\n        var nodes = IFNode.deserialize(gShell.getClipboardContent(IFNode.MIME_TYPE));\n        if (nodes && nodes.length > 0) {\n            var elements = [];\n            for (var i = 0; i < nodes.length; ++i) {\n                if (nodes[i] instanceof IFElement) {\n                    elements.push(nodes[i]);\n                }\n            }\n\n            if (elements.length > 0) {\n                var editor = gApp.getActiveDocument().getEditor();\n                var selection = editor.getSelection();\n                var newSelection = [];\n\n                editor.beginTransaction();\n                try {\n                    for (var i = 0; i < selection.length; ++i) {\n                        var target = selection[i];\n                        if (!target.hasMixin(IFNode.Container)) {\n                            continue;\n                        }\n\n                        var insertGroup = [];\n                        for (var k = 0; k < elements.length; ++k) {\n                            if (elements[k].validateInsertion(target)) {\n                                insertGroup.push(elements[k].clone());\n                            }\n                        }\n\n                        var groupBBox = IFElement.prototype.getGroupGeometryBBox(insertGroup);\n                        var groupCntr = groupBBox ? groupBBox.getSide(IFRect.Side.CENTER) : new IFPoint(0,0);\n                        var targBBox = target instanceof IFElement ? target.getGeometryBBox() : null;\n                        var targCntr = targBBox ? targBBox.getSide(IFRect.Side.CENTER) : new IFPoint(0,0);\n                        for (var k = 0; k < insertGroup.length; ++k) {\n                            insertGroup[k].transform(new IFTransform(1, 0, 0, 1,\n                                -groupCntr.getX() + targCntr.getX(), -groupCntr.getY() + targCntr.getY()));\n                            target.appendChild(insertGroup[k]);\n                            newSelection.push(insertGroup[k]);\n\n                        }\n                    }\n\n                    editor.updateSelection(false, newSelection);\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Paste Inside');\n                }\n            }\n        }\n    };\n\n    /** @override */\n    GPasteInsideAction.prototype.toString = function () {\n        return \"[Object GPasteInsideAction]\";\n    };\n\n    _.GPasteInsideAction = GPasteInsideAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/pixelpreviewaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for switching between pixel-mode and vector mode\n     * @class GPixelPreviewAction\n     * @extends GAction\n     * @constructor\n     */\n    function GPixelPreviewAction() {\n    };\n    IFObject.inherit(GPixelPreviewAction, GAction);\n\n    GPixelPreviewAction.ID = 'view.pixel-preview';\n    GPixelPreviewAction.TITLE = new IFLocale.Key(GPixelPreviewAction, 'title');\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.getId = function () {\n        return GPixelPreviewAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.getTitle = function () {\n        return GPixelPreviewAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.getGroup = function () {\n        return \"render\";\n    };\n\n    /** @override */\n    GPixelPreviewAction.prototype.isCheckable = function () {\n        return true;\n    };\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.isChecked = function () {\n        var window = gApp.getWindows().getActiveWindow();\n        if (window) {\n            return window.getView().getViewConfiguration().pixelMode;\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.isEnabled = function () {\n        return !!gApp.getWindows().getActiveWindow();\n    };\n\n    /**\n     * @override\n     */\n    GPixelPreviewAction.prototype.execute = function () {\n        var view = gApp.getWindows().getActiveWindow().getView();\n        view.getViewConfiguration().pixelMode = !view.getViewConfiguration().pixelMode;\n        view.invalidate();\n    };\n\n    /** @override */\n    GPixelPreviewAction.prototype.toString = function () {\n        return \"[Object GPixelPreviewAction]\";\n    };\n\n    _.GPixelPreviewAction = GPixelPreviewAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/placeimageaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for placing an image\n     * @class GPlaceImageAction\n     * @extends GAction\n     * @constructor\n     */\n    function GPlaceImageAction() {\n    };\n    IFObject.inherit(GPlaceImageAction, GAction);\n\n    GPlaceImageAction.ID = 'file.place-image';\n    GPlaceImageAction.TITLE = new IFLocale.Key(GPlaceImageAction, \"title\");\n\n    /**\n     * @override\n     */\n    GPlaceImageAction.prototype.getId = function () {\n        return GPlaceImageAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GPlaceImageAction.prototype.getTitle = function () {\n        return GPlaceImageAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GPlaceImageAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GPlaceImageAction.prototype.getGroup = function () {\n        return \"insert\";\n    };\n\n    /**\n     * @override\n     */\n    GPlaceImageAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        if (document && document.isSaveable()) {\n            return true;\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GPlaceImageAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        document.getStorage().openResourcePrompt(document.getUrl(), ['jpg', 'jpeg', 'png', 'gif'], function (url) {\n            var uri = new URI(url);\n\n            alert('uri: ' + uri.toString());\n            alert('make_relative_to: ' + document.getUrl());\n\n            // make url relative to document\n            url = uri.relativeTo(document.getUrl()).toString();\n\n            // extract a name for the picture\n            var filename = uri.filename();\n            var suffix = uri.suffix();\n            var name = suffix.length > 0 ? filename.substr(0, filename.length - suffix.length - 1) : filename;\n\n            var imagePos = document.getScene().getActivePage().getGeometryBBox().getSide(IFRect.Side.TOP_LEFT);\n            var image = new IFImage();\n            image.setProperties(['name', 'url', 'transform'], [name, url, new IFTransform(1, 0, 0, 1, imagePos.getX(), imagePos.getY())]);\n            image.transform();\n            document.getEditor().insertElements([image]);\n        });\n    };\n\n    /** @override */\n    GPlaceImageAction.prototype.toString = function () {\n        return \"[Object GPlaceImageAction]\";\n    };\n\n    _.GPlaceImageAction = GPlaceImageAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/redoaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for redo on the current document\n     * @class GRedoAction\n     * @extends GAction\n     * @constructor\n     */\n    function GRedoAction() {\n    };\n    IFObject.inherit(GRedoAction, GAction);\n\n    GRedoAction.ID = 'edit.redo';\n    GRedoAction.TITLE = new IFLocale.Key(GRedoAction, \"title\");\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.getId = function () {\n        return GRedoAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.getTitle = function () {\n        var result = ifLocale.get(GRedoAction.TITLE);\n        var document = gApp.getActiveDocument();\n        if (document && document.getEditor().hasRedoState()) {\n            result += \" \" + document.getEditor().getRedoStateName();\n        }\n        return result;\n    };\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.getGroup = function () {\n        return \"undo_redo\";\n    };\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.META, 'z'];\n    };\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.isEnabled = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            return true;\n        }\n\n        if (gApp.getActiveDocument() && gApp.getActiveDocument().getEditor().hasRedoState()) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GRedoAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('redo');\n        } else {\n            gApp.getActiveDocument().getEditor().redoState();\n        }\n    };\n\n    /** @override */\n    GRedoAction.prototype.toString = function () {\n        return \"[Object GRedoAction]\";\n    };\n\n    _.GRedoAction = GRedoAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/saveaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action saving a document\n     * @class GSaveAction\n     * @extends GAction\n     * @constructor\n     */\n    function GSaveAction() {\n    };\n    IFObject.inherit(GSaveAction, GAction);\n\n    GSaveAction.ID = 'file.save';\n    GSaveAction.TITLE = new IFLocale.Key(GSaveAction, \"title\");\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.getId = function () {\n        return GSaveAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.getTitle = function () {\n        return GSaveAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.getGroup = function () {\n        return \"file\";\n    };\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'S'];\n    };\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        return document && document.isSaveable();\n    };\n\n    /**\n     * @override\n     */\n    GSaveAction.prototype.execute = function () {\n        gApp.getActiveDocument().save();\n    };\n\n    /** @override */\n    GSaveAction.prototype.toString = function () {\n        return \"[Object GSaveAction]\";\n    };\n\n    _.GSaveAction = GSaveAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/saveallaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action saving all documents\n     * @class GSaveAllAction\n     * @extends GAction\n     * @constructor\n     */\n    function GSaveAllAction() {\n    };\n    IFObject.inherit(GSaveAllAction, GAction);\n\n    GSaveAllAction.ID = 'file.save-all';\n    GSaveAllAction.TITLE = new IFLocale.Key(GSaveAllAction, \"title\");\n\n    /**\n     * @override\n     */\n    GSaveAllAction.prototype.getId = function () {\n        return GSaveAllAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAllAction.prototype.getTitle = function () {\n        return GSaveAllAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAllAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAllAction.prototype.getGroup = function () {\n        return \"file\";\n    };\n\n    /**\n     * @override\n     */\n    GSaveAllAction.prototype.isEnabled = function () {\n        var documents = gApp.getDocuments();\n        for (var i = 0; i < documents.length; ++i) {\n            if (documents[i].isSaveable()) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAllAction.prototype.execute = function () {\n        var documents = gApp.getDocuments();\n        for (var i = 0; i < documents.length; ++i) {\n            if (documents[i].isSaveable()) {\n                documents[i].save();\n            }\n        }\n    };\n\n    /** @override */\n    GSaveAllAction.prototype.toString = function () {\n        return \"[Object GSaveAllAction]\";\n    };\n\n    _.GSaveAllAction = GSaveAllAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/saveasaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action saving a document filed under a name\n     * @class GSaveAsAction\n     * @extends GAction\n     * @constructor\n     */\n    function GSaveAsAction() {\n    };\n    IFObject.inherit(GSaveAsAction, GAction);\n\n    GSaveAsAction.ID = 'file.save-as';\n    GSaveAsAction.TITLE = new IFLocale.Key(GSaveAsAction, \"title\");\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.getId = function () {\n        return GSaveAsAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.getTitle = function () {\n        return GSaveAsAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_FILE;\n    };\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.getGroup = function () {\n        return 'file';\n    };\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.META, 'S'];\n    };\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.isEnabled = function () {\n        return !!this._getViableStorage() && !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GSaveAsAction.prototype.execute = function () {\n        gApp.saveDocumentAs(this._getViableStorage(), gApp.getActiveDocument());\n    };\n\n    /**\n     * @returns {GStorage}\n     * @private\n     */\n    GSaveAsAction.prototype._getViableStorage = function () {\n        for (var i = 0; i < gravit.storages.length; ++i) {\n            var storage = gravit.storages[i];\n            if (storage.isAvailable() && storage.isPrompting() && storage.isSaving()) {\n                var extensions = storage.getExtensions();\n                if (!extensions || extensions.isEmpty() || extensions.indexOf('gravit') >= 0) {\n                    return storage;\n                }\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    GSaveAsAction.prototype.toString = function () {\n        return \"[Object GSaveAsAction]\";\n    };\n\n    _.GSaveAsAction = GSaveAsAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/selectallaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for selecting everything\n     * @class GSelectAllAction\n     * @extends GAction\n     * @constructor\n     */\n    function GSelectAllAction() {\n    };\n    IFObject.inherit(GSelectAllAction, GAction);\n\n    GSelectAllAction.ID = 'edit.select-all';\n    GSelectAllAction.TITLE = new IFLocale.Key(GSelectAllAction, \"title\");\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.getId = function () {\n        return GSelectAllAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.getTitle = function () {\n        return GSelectAllAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.getGroup = function () {\n        return \"select\";\n    };\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'A'];\n    };\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.isEnabled = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            return true;\n        }\n\n        if (gApp.getActiveDocument()) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GSelectAllAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('selectAll');\n        } else {\n            var editor = gApp.getActiveDocument().getEditor();\n            var scene = gApp.getActiveDocument().getScene();\n\n            var source = null;\n            if (scene.getProperty('singlePage')) {\n                source = scene.getActivePage();\n            } else {\n                source = scene;\n            }\n\n            var selection = [];\n            source.accept(function (node) {\n                if (node instanceof IFItem && node.getParent() instanceof IFLayer) {\n                    selection.push(node);\n                }\n            });\n\n            editor.updateSelection(false, selection);\n        }\n    };\n\n    /** @override */\n    GSelectAllAction.prototype.toString = function () {\n        return \"[Object GSelectAllAction]\";\n    };\n\n    _.GSelectAllAction = GSelectAllAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/showallpagesaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for switching between single and multi page view\n     * @class GShowAllPagesAction\n     * @extends GAction\n     * @constructor\n     */\n    function GShowAllPagesAction() {\n    };\n    IFObject.inherit(GShowAllPagesAction, GAction);\n\n    GShowAllPagesAction.ID = 'view.show-all-pages';\n    GShowAllPagesAction.TITLE = new IFLocale.Key(GShowAllPagesAction, 'title');\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.getId = function () {\n        return GShowAllPagesAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.getTitle = function () {\n        return GShowAllPagesAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.getGroup = function () {\n        return \"render\";\n    };\n\n    /** @override */\n    GShowAllPagesAction.prototype.isCheckable = function () {\n        return true;\n    };\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.isChecked = function () {\n        var document = gApp.getActiveDocument();\n        if (document) {\n            return !document.getScene().getProperty('singlePage');\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /**\n     * @override\n     */\n    GShowAllPagesAction.prototype.execute = function () {\n        var scene = gApp.getActiveDocument().getScene();\n        scene.setProperty('singlePage', !scene.getProperty('singlePage'));\n    };\n\n    /** @override */\n    GShowAllPagesAction.prototype.toString = function () {\n        return \"[Object GShowAllPagesAction]\";\n    };\n\n    _.GShowAllPagesAction = GShowAllPagesAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/showgridaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for showing / hiding the grid\n     * @class GShowGridAction\n     * @extends GAction\n     * @constructor\n     */\n    function GShowGridAction() {\n    };\n    IFObject.inherit(GShowGridAction, GAction);\n\n    GShowGridAction.ID = 'view.show-grid';\n    GShowGridAction.TITLE = new IFLocale.Key(GShowGridAction, \"title\");\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.getId = function () {\n        return GShowGridAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.getTitle = function () {\n        return GShowGridAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.getGroup = function () {\n        return \"show\";\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, IFKey.Constant.OPTION, 'G'];\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.isEnabled = function () {\n        return !!gApp.getWindows().getActiveWindow();\n    };\n\n    /** @override */\n    GShowGridAction.prototype.isCheckable = function () {\n        return true;\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.isChecked = function () {\n        var window = gApp.getWindows().getActiveWindow();\n        if (window) {\n            return window.getView().getViewConfiguration().gridVisible === true;\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GShowGridAction.prototype.execute = function () {\n        var view = gApp.getWindows().getActiveWindow().getView();\n        view.getViewConfiguration().gridVisible = !view.getViewConfiguration().gridVisible;\n        view.invalidate();\n    };\n\n    /** @override */\n    GShowGridAction.prototype.toString = function () {\n        return \"[Object GShowGridAction]\";\n    };\n\n    _.GShowGridAction = GShowGridAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/showrulersaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for showing / hiding the rulers\n     * @class GShowRulersAction\n     * @extends GAction\n     * @constructor\n     */\n    function GShowRulersAction() {\n    };\n    IFObject.inherit(GShowRulersAction, GAction);\n\n    GShowRulersAction.ID = 'view.show-rulers';\n    GShowRulersAction.TITLE = new IFLocale.Key(GShowRulersAction, \"title\");\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.getId = function () {\n        return GShowRulersAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.getTitle = function () {\n        return GShowRulersAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW;\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.getGroup = function () {\n        return \"show\";\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, IFKey.Constant.OPTION, 'R'];\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.isEnabled = function () {\n        // TODO\n        return false;\n    };\n\n    /** @override */\n    GShowRulersAction.prototype.isCheckable = function () {\n        return true;\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.isChecked = function () {\n        // TODO\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GShowRulersAction.prototype.execute = function () {\n        // TODO\n        return false;\n    };\n\n    /** @override */\n    GShowRulersAction.prototype.toString = function () {\n        return \"[Object GShowRulersAction]\";\n    };\n\n    _.GShowRulersAction = GShowRulersAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/slicefromselection.js",
    "content": "(function (_) {\n\n    /**\n     * Action for creating a slice on selection\n     * @class GSliceFromSelectionAction\n     * @extends GAction\n     * @constructor\n     */\n    function GSliceFromSelectionAction() {\n    };\n    IFObject.inherit(GSliceFromSelectionAction, GAction);\n\n    GSliceFromSelectionAction.ID = 'modify.slice-from-selection';\n    GSliceFromSelectionAction.TITLE = new IFLocale.Key(GSliceFromSelectionAction, \"title\");\n\n    /**\n     * @override\n     */\n    GSliceFromSelectionAction.prototype.getId = function () {\n        return GSliceFromSelectionAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GSliceFromSelectionAction.prototype.getTitle = function () {\n        return GSliceFromSelectionAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GSliceFromSelectionAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY;\n    };\n\n    /**\n     * @override\n     */\n    GSliceFromSelectionAction.prototype.getGroup = function () {\n        return \"structure-slice\";\n    };\n\n    /**\n     * @override\n     */\n    GSliceFromSelectionAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        if (document) {\n            return document.getEditor().hasSelection();\n        }\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GSliceFromSelectionAction.prototype.execute = function () {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n        var editor = document.getEditor();\n        var selBBox = document.getEditor().getSelectionBBox(false);\n        if (selBBox && !selBBox.isEmpty()) {\n            IFEditor.tryRunTransaction(scene, function () {\n                var slice = new IFSlice();\n                slice.setProperty('trf',\n                    new IFTransform(selBBox.getWidth() / 2, 0, 0, selBBox.getHeight() / 2,\n                        selBBox.getX() + selBBox.getWidth() / 2, selBBox.getY() + selBBox.getHeight() / 2));\n                scene.getActiveLayer().appendChild(slice);\n                editor.updateSelection(false, [slice]);\n            }, ifLocale.get(this.getTitle()));\n        }\n    };\n\n    /** @override */\n    GSliceFromSelectionAction.prototype.toString = function () {\n        return \"[Object GSliceFromSelectionAction]\";\n    };\n\n    _.GSliceFromSelectionAction = GSliceFromSelectionAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/snapunitaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for snapping to units\n     * @class GSnapUnitAction\n     * @extends GAction\n     * @constructor\n     */\n    function GSnapUnitAction(type) {\n        this._type = type;\n        this._title = new IFLocale.Key(GSnapUnitAction, 'title.' + type);\n    };\n    IFObject.inherit(GSnapUnitAction, GAction);\n\n    /** @enum */\n    GSnapUnitAction.Type = {\n        FullUnit: 'full',\n        HalfUnit: 'half'\n    };\n\n    GSnapUnitAction.ID = 'arrange.snap-unit';\n\n    /** @type {GSnapUnitAction.Type} */\n    GSnapUnitAction.prototype._type = null;\n\n    /** @type {IFLocale.Key} */\n    GSnapUnitAction.prototype._title = null;\n\n    /**\n     * @override\n     */\n    GSnapUnitAction.prototype.getId = function () {\n        return GSnapUnitAction.ID + '.' + this._type;\n    };\n\n    /**\n     * @override\n     */\n    GSnapUnitAction.prototype.getTitle = function () {\n        return this._title;\n    };\n\n    /**\n     * @override\n     */\n    GSnapUnitAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_ALIGN;\n    };\n\n    /**\n     * @override\n     */\n    GSnapUnitAction.prototype.getGroup = function () {\n        return 'arrange/snap-unit';\n    };\n\n    /**\n     * @override\n     */\n    GSnapUnitAction.prototype.getShortcut = function () {\n        return null;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @override\n     */\n    GSnapUnitAction.prototype.isEnabled = function (elements) {\n        elements = elements || (gApp.getActiveDocument() ? gApp.getActiveDocument().getEditor().getSelection() : null);\n        return elements && elements.length > 0;\n        return false;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @override\n     */\n    GSnapUnitAction.prototype.execute = function (elements) {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n\n        if (!elements) {\n            elements = document.getEditor().getSelection();\n        }\n\n        // TODO : I18N\n        IFEditor.tryRunTransaction(scene, function () {\n            for (var i = 0; i < elements.length; ++i) {\n                var element = elements[i];\n                if (!element.hasMixin(IFElement.Transform)) {\n                    continue;\n                }\n\n                var bbox = element.getGeometryBBox();\n                if (!bbox || bbox.isEmpty()) {\n                    continue;\n                }\n\n                var x = ifMath.round(bbox.getX(), true);\n                var y = ifMath.round(bbox.getY(), true);\n                var w = ifMath.round(bbox.getWidth(), true);\n                var h = ifMath.round(bbox.getHeight(), true);\n\n                if (this._type === GSnapUnitAction.Type.HalfUnit) {\n                    x += 0.5;\n                    y += 0.5;\n                    w += 0.5;\n                    h += 0.5;\n                }\n\n                var transform = new IFTransform()\n                    .translated(-bbox.getX(), -bbox.getY())\n                    .scaled(w / bbox.getWidth(), h / bbox.getHeight())\n                    .translated(bbox.getX(), bbox.getY())\n                    .translated(x - bbox.getX(), y - bbox.getY());\n\n                element.transform(transform);\n            }\n        }.bind(this), ifLocale.get(this.getTitle()));\n    };\n\n    /** @override */\n    GSnapUnitAction.prototype.toString = function () {\n        return \"[Object GSnapUnitAction]\";\n    };\n\n    _.GSnapUnitAction = GSnapUnitAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/transformaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for transforming\n     * @class GTransformAction\n     * @extends GAction\n     * @constructor\n     */\n    function GTransformAction(type) {\n        this._type = type;\n        this._title = new IFLocale.Key(GTransformAction, 'title.' + type);\n    };\n    IFObject.inherit(GTransformAction, GAction);\n\n    /** @enum */\n    GTransformAction.Type = {\n        Rotate45Left: 'rotate-45-left',\n        Rotate90Left: 'rotate-90-left',\n        Rotate180Left: 'rotate-180-left',\n        Rotate45Right: 'rotate-45-right',\n        Rotate90Right: 'rotate-90-right',\n        Rotate180Right: 'rotate-180-right',\n        FlipVertical: 'flip-vertical',\n        FlipHorizontal: 'flip-horizontal'\n    };\n\n    GTransformAction.ID = 'arrange.transform';\n\n    /** @type {GTransformAction.Type} */\n    GTransformAction.prototype._type = null;\n\n    /** @type {IFLocale.Key} */\n    GTransformAction.prototype._title = null;\n\n    /**\n     * @override\n     */\n    GTransformAction.prototype.getId = function () {\n        return GTransformAction.ID + '.' + this._type;\n    };\n\n    /**\n     * @override\n     */\n    GTransformAction.prototype.getTitle = function () {\n        return this._title;\n    };\n\n    /**\n     * @override\n     */\n    GTransformAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY_TRANSFORM;\n    };\n\n    /**\n     * @override\n     */\n    GTransformAction.prototype.getGroup = function () {\n        var result = '';\n\n        switch (this._type) {\n            case GTransformAction.Type.Rotate45Left:\n            case GTransformAction.Type.Rotate90Left:\n            case GTransformAction.Type.Rotate180Left:\n                result = 'rotate-left';\n                break;\n            case GTransformAction.Type.Rotate45Right:\n            case GTransformAction.Type.Rotate90Right:\n            case GTransformAction.Type.Rotate180Right:\n                result = 'rotate-right';\n                break;\n            case GTransformAction.Type.FlipVertical:\n            case GTransformAction.Type.FlipHorizontal:\n                result = 'flip';\n                break;\n        }\n\n        return 'arrange/transform-' + result;\n    };\n\n    /**\n     * @override\n     */\n    GTransformAction.prototype.getShortcut = function () {\n        return null;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @override\n     */\n    GTransformAction.prototype.isEnabled = function (elements) {\n        elements = elements || (gApp.getActiveDocument() ? gApp.getActiveDocument().getEditor().getSelection() : null);\n        return elements && elements.length > 0;\n    };\n\n    /**\n     * @param {Array<IFElement>} [elements] optional elements, if not given\n     * uses the selection\n     * @override\n     */\n    GTransformAction.prototype.execute = function (elements) {\n        var document = gApp.getActiveDocument();\n        var scene = document.getScene();\n\n        if (!elements) {\n            elements = document.getEditor().getSelection();\n        }\n\n        IFEditor.tryRunTransaction(scene, function () {\n            for (var i = 0; i < elements.length; ++i) {\n                var element = elements[i];\n                var bbox = element.getGeometryBBox();\n\n                if (element.hasMixin(IFElement.Transform) && bbox && !bbox.isEmpty()) {\n                    var center = bbox.getSide(IFRect.Side.CENTER);\n                    var rotation = 0;\n                    var scaleX = 1;\n                    var scaleY = 1;\n\n                    switch (this._type) {\n                        case GTransformAction.Type.Rotate45Left:\n                            rotation = -45;\n                            break;\n\n                        case GTransformAction.Type.Rotate90Left:\n                            rotation = -90;\n                            break;\n\n                        case GTransformAction.Type.Rotate180Left:\n                            rotation = -180;\n                            break;\n\n                        case GTransformAction.Type.Rotate45Right:\n                            rotation = 45;\n                            break;\n\n                        case GTransformAction.Type.Rotate90Right:\n                            rotation = 90;\n                            break;\n\n                        case GTransformAction.Type.Rotate180Right:\n                            rotation = 180;\n                            break;\n\n                        case GTransformAction.Type.FlipVertical:\n                            scaleY = -1;\n                            break;\n\n                        case GTransformAction.Type.FlipHorizontal:\n                            scaleX = -1;\n                            break;\n                    }\n\n                    var transform = new IFTransform()\n                        .translated(-center.getX(), -center.getY())\n                        .scaled(scaleX, scaleY)\n                        .rotated(ifMath.toRadians(rotation))\n                        .translated(center.getX(), center.getY());\n\n                    element.transform(transform);\n                }\n            }\n        }.bind(this), ifLocale.get(this.getTitle()));\n    };\n\n    /** @override */\n    GTransformAction.prototype.toString = function () {\n        return \"[Object GTransformAction]\";\n    };\n\n    _.GTransformAction = GTransformAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/undoaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for undo on the current document\n     * @class GUndoAction\n     * @extends GAction\n     * @constructor\n     */\n    function GUndoAction() {\n    };\n    IFObject.inherit(GUndoAction, GAction);\n\n    GUndoAction.ID = 'edit.undo';\n    GUndoAction.TITLE = new IFLocale.Key(GUndoAction, \"title\");\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.getId = function () {\n        return GUndoAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.getTitle = function () {\n        var result = ifLocale.get(GUndoAction.TITLE);\n        var document = gApp.getActiveDocument();\n        if (document && document.getEditor().hasUndoState()) {\n            result += \" \" + document.getEditor().getUndoStateName();\n        }\n        return result;\n    };\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_EDIT;\n    };\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.getGroup = function () {\n        return \"undo_redo\";\n    };\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, 'z'];\n    };\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.isEnabled = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            return true;\n\n        }\n\n        if (gApp.getActiveDocument() && gApp.getActiveDocument().getEditor().hasUndoState()) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * @override\n     */\n    GUndoAction.prototype.execute = function () {\n        if (document.activeElement && $(document.activeElement).is(\":editable\")) {\n            document.execCommand('undo');\n        } else {\n        gApp.getActiveDocument().getEditor().undoState();\n        }/**/\n    };\n\n    /** @override */\n    GUndoAction.prototype.toString = function () {\n        return \"[Object GUndoAction]\";\n    };\n\n    _.GUndoAction = GUndoAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/ungroupaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for ungrouping the selection\n     * @class GUngroupAction\n     * @extends GAction\n     * @constructor\n     */\n    function GUngroupAction() {\n    };\n    IFObject.inherit(GUngroupAction, GAction);\n\n    GUngroupAction.ID = 'modify.ungroup';\n    GUngroupAction.TITLE = new IFLocale.Key(GUngroupAction, \"title\");\n\n    /**\n     * @override\n     */\n    GUngroupAction.prototype.getId = function () {\n        return GUngroupAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GUngroupAction.prototype.getTitle = function () {\n        return GUngroupAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GUngroupAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_MODIFY;\n    };\n\n    /**\n     * @override\n     */\n    GUngroupAction.prototype.getGroup = function () {\n        return \"structure-group\";\n    };\n\n    /**\n     * @override\n     */\n    GUngroupAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.SHIFT, IFKey.Constant.META, 'G'];\n    };\n\n    /**\n     * @override\n     */\n    GUngroupAction.prototype.isEnabled = function () {\n        var document = gApp.getActiveDocument();\n        if (document) {\n            var selection = document.getEditor().getSelection();\n            if (selection) {\n                for (var i = 0; i < selection.length; ++i) {\n                    if (selection[i] instanceof IFShapeSet) {\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    };\n\n    /** @override */\n    GUngroupAction.prototype.execute = function () {\n        var editor = gApp.getActiveDocument().getEditor();\n        var selection = editor.getSelection();\n\n        editor.beginTransaction();\n        try {\n            var newSelection = [];\n\n            for (var i = 0; i < selection.length; ++i) {\n                var item = selection[i];\n                if (item instanceof IFShapeSet) {\n                    var groupParent = item.getParent();\n                    var groupNext = item.getNext();\n                    var groupChildren = item.getChildren();\n\n                    // Remove the group, first\n                    groupParent.removeChild(item);\n\n                    // Now move all sub-items of group before the group\n                    for (var j = 0; j < groupChildren.length; ++j) {\n                        var child = groupChildren[j];\n                        item.removeChild(child);\n                        groupParent.insertChild(child, groupNext);\n                        newSelection.push(child);\n                    }\n                }\n            }\n\n            // Update selection if any\n            if (newSelection.length > 0) {\n                editor.updateSelection(false, newSelection);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Ungroup');\n        }\n    };\n\n    /** @override */\n    GUngroupAction.prototype.toString = function () {\n        return \"[Object GUngroupAction]\";\n    };\n\n    _.GUngroupAction = GUngroupAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/zoominaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for zooming into the current view\n     * @class GZoomInAction\n     * @extends GAction\n     * @constructor\n     */\n    function GZoomInAction() {\n    };\n    IFObject.inherit(GZoomInAction, GAction);\n\n    GZoomInAction.ID = 'view.zoom.in';\n    GZoomInAction.TITLE = new IFLocale.Key(GZoomInAction, \"title\");\n    GZoomInAction.ZOOM_STEP = 2.0;\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.getId = function () {\n        return GZoomInAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.getTitle = function () {\n        return GZoomInAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW_MAGNIFICATION;\n    };\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.getGroup = function () {\n        return \"zoom/magnification\";\n    };\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, '+'];\n    };\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.isEnabled = function () {\n        var window = gApp.getWindows().getActiveWindow();\n        var view = window ? window.getView() : null;\n        return view && view.getZoom() < IFView.options.maxZoomFactor;\n    };\n\n    /**\n     * @override\n     */\n    GZoomInAction.prototype.execute = function () {\n        var view = gApp.getWindows().getActiveWindow().getView();\n        var newZoom = view.getZoom() * GZoomInAction.ZOOM_STEP;\n        var scene = view.getScene();\n        var zoomPoint = null;\n        if (scene.getProperty('singlePage')) {\n            var pageBBox = scene.getActivePage().getGeometryBBox();\n            if (pageBBox && !pageBBox.isEmpty()) {\n                zoomPoint = pageBBox.getSide(IFRect.Side.CENTER);\n            }\n        }\n        if (!zoomPoint) {\n            zoomPoint = view.getViewTransform().mapPoint(new IFPoint(view.getWidth() / 2.0, view.getHeight() / 2.0));\n        }\n        view.zoomAt(zoomPoint, newZoom);\n    };\n\n    /** @override */\n    GZoomInAction.prototype.toString = function () {\n        return \"[Object GZoomInAction]\";\n    };\n\n    _.GZoomInAction = GZoomInAction;\n})(this);"
  },
  {
    "path": "src/gravit/action/zoomoutaction.js",
    "content": "(function (_) {\n\n    /**\n     * Action for zooming out of the current view\n     * @class GZoomOutAction\n     * @extends GAction\n     * @constructor\n     */\n    function GZoomOutAction() {\n    };\n    IFObject.inherit(GZoomOutAction, GAction);\n\n    GZoomOutAction.ID = 'zoom.out';\n    GZoomOutAction.TITLE = new IFLocale.Key(GZoomOutAction, \"title\");\n    GZoomOutAction.ZOOM_STEP = 2.0;\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.getId = function () {\n        return GZoomOutAction.ID;\n    };\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.getTitle = function () {\n        return GZoomOutAction.TITLE;\n    };\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.getCategory = function () {\n        return GApplication.CATEGORY_VIEW_MAGNIFICATION;\n    };\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.getGroup = function () {\n        return \"zoom/magnification\";\n    };\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.getShortcut = function () {\n        return [IFKey.Constant.META, '-'];\n    };\n\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.isEnabled = function () {\n        var window = gApp.getWindows().getActiveWindow();\n        var view = window ? window.getView() : null;\n        return view && view.getZoom() > IFView.options.minZoomFactor;\n    };\n\n    /**\n     * @override\n     */\n    GZoomOutAction.prototype.execute = function () {\n        var view = gApp.getWindows().getActiveWindow().getView();\n        var newZoom = view.getZoom() / GZoomOutAction.ZOOM_STEP;\n        var scene = view.getScene();\n        var zoomPoint = null;\n        if (scene.getProperty('singlePage')) {\n            var pageBBox = scene.getActivePage().getGeometryBBox();\n            if (pageBBox && !pageBBox.isEmpty()) {\n                zoomPoint = pageBBox.getSide(IFRect.Side.CENTER);\n            }\n        }\n        if (!zoomPoint) {\n            zoomPoint = view.getViewTransform().mapPoint(new IFPoint(view.getWidth() / 2.0, view.getHeight() / 2.0));\n        }\n        view.zoomAt(zoomPoint, newZoom);\n    };\n\n    /** @override */\n    GZoomOutAction.prototype.toString = function () {\n        return \"[Object GZoomOutAction]\";\n    };\n\n    _.GZoomOutAction = GZoomOutAction;\n})(this);"
  },
  {
    "path": "src/gravit/colormatcher/analogousmatcher.js",
    "content": "(function (_) {\n\n    /**\n     * Analogous Color Matcher\n     * @class GAnalogousMatcher\n     * @extends GColorMatcher\n     * @constructor\n     */\n    function GAnalogousMatcher() {\n    };\n    IFObject.inherit(GAnalogousMatcher, GColorMatcher);\n\n    GAnalogousMatcher.TITLE = new IFLocale.Key(GAnalogousMatcher, \"title\");\n\n    /** @override */\n    GAnalogousMatcher.prototype.getTitle = function () {\n        return GAnalogousMatcher.TITLE;\n    };\n\n    /** @override */\n    GAnalogousMatcher.prototype.getCategory = function () {\n        return GColorMatcher.CATEGORY_HARMONY;\n    };\n\n    /** @override */\n    GAnalogousMatcher.prototype.match = function (referenceColor) {\n        var result = [];\n        var hslLeft = referenceColor.asHSL();\n        var hslRight = hslLeft.slice();\n        var step = 180.0 / 8;\n        for (var i = 3; i >= 0; --i) {\n            hslRight[0] = ifMath.normalizeAngleDegrees(hslRight[0] + step);\n            result[i] = (new IFColor(IFColor.Type.HSL, hslRight));\n        }\n        for (var i = 0; i < 4; ++i) {\n            hslLeft[0] = ifMath.normalizeAngleDegrees(hslLeft[0] - step);\n            result.push(new IFColor(IFColor.Type.HSL, hslLeft));\n        }\n        return result;\n    };\n\n    /** @override */\n    GAnalogousMatcher.prototype.toString = function () {\n        return \"[Object GAnalogousMatcher]\";\n    };\n\n    _.GAnalogousMatcher = GAnalogousMatcher;\n})(this);"
  },
  {
    "path": "src/gravit/colormatcher/complementarymatcher.js",
    "content": "(function (_) {\n\n    /**\n     * Complementary Color Matcher\n     * @class GComplementaryMatcher\n     * @extends GColorMatcher\n     * @constructor\n     */\n    function GComplementaryMatcher() {\n    };\n    IFObject.inherit(GComplementaryMatcher, GColorMatcher);\n\n    GComplementaryMatcher.TITLE = new IFLocale.Key(GComplementaryMatcher, \"title\");\n\n    /** @override */\n    GComplementaryMatcher.prototype.getTitle = function () {\n        return GComplementaryMatcher.TITLE;\n    };\n\n    /** @override */\n    GComplementaryMatcher.prototype.getCategory = function () {\n        return GColorMatcher.CATEGORY_HARMONY;\n    };\n\n    /** @override */\n    GComplementaryMatcher.prototype.match = function (referenceColor) {\n        var hsl = referenceColor.asHSL();\n        hsl[0] = ifMath.normalizeAngleDegrees(hsl[0] + 180);\n        return [new IFColor(IFColor.Type.HSL, hsl)];\n    };\n\n    /** @override */\n    GComplementaryMatcher.prototype.toString = function () {\n        return \"[Object GComplementaryMatcher]\";\n    };\n\n    _.GComplementaryMatcher = GComplementaryMatcher;\n})(this);"
  },
  {
    "path": "src/gravit/exporter/imagexporter.js",
    "content": "(function (_) {\n    /**\n     * The image exporter\n     * @class GImageExporter\n     * @extends GExporter\n     * @constructor\n     */\n    function GImageExporter() {\n        GExporter.call(this);\n    };\n    IFObject.inherit(GImageExporter, GExporter);\n\n    /** @override */\n    GImageExporter.prototype.isStandalone = function () {\n        return false;\n    };\n\n    /** @override */\n    GImageExporter.prototype.getName = function () {\n        return 'Raster Image';\n    };\n\n    /** @override */\n    GImageExporter.prototype.getExtensions = function () {\n        return ['png', 'jpg'];\n    };\n\n    /** @override */\n    GImageExporter.prototype.exportPart = function (part, size, storage, url, extension) {\n        var size = GExporter.parseSize(size);\n        var bitmap = part.toBitmap(size.width, size.height ? size.height : size.width, 2);\n        if (bitmap) {\n            // Store bitmap now\n            bitmap.toImageBuffer(this._getImageTypeByExt(extension), function (buffer) {\n                storage.save(url, buffer, true);\n            });\n        }\n    };\n\n    /**\n     * @param {String} ext\n     * @returns {IFBitmap.ImageType}\n     * @private\n     */\n    GImageExporter.prototype._getImageTypeByExt = function (extension) {\n        if (extension === 'png') {\n            return IFBitmap.ImageType.PNG;\n        } else if (extension === 'jpg') {\n            return IFBitmap.ImageType.JPEG;\n        } else {\n            throw new Error('Unknown image extension - ' + extension);\n        }\n    };\n\n    _.GImageExporter = GImageExporter;\n})(this);\n"
  },
  {
    "path": "src/gravit/gravit.js",
    "content": "(function (_) {\n    /**\n     * Gravit Core Module\n     * @class GravitModule\n     * @constructor\n     * @extends GModule\n     */\n    function GravitModule() {\n    }\n\n    IFObject.inherit(GravitModule, GModule);\n\n    /** @override */\n    GravitModule.prototype.init = function () {\n        // Register default exporters\n        gravit.exporters.push(\n            new GImageExporter()\n        );\n\n        // Register default palettes\n        gravit.palettes.push(\n            new GExportPalette(),\n            new GStylePalette()\n        );\n\n        // Register default panels\n        gravit.panels.push(\n            new GPropertiesPanel(),\n            new GTransformPanel()\n        );\n\n        // Register default sidebars\n        gravit.sidebars.push(\n            new GPagesLayersSidebar(),\n            new GStylesSwatchesSidebar()\n        );\n\n        // Register default tools\n        // TODO : I18N\n        gravit.tools.push(\n            {\n                instance: new IFPointerTool(),\n                title: 'Pointer',\n                category: GApplication.TOOL_CATEGORY_SELECT,\n                group: 'select',\n                keys: ['V', '0'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M3.5,18.5v18l5-7h9L3.5,18.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFLassoTool(),\n                title: 'Lasso',\n                category: GApplication.TOOL_CATEGORY_SELECT,\n                group: 'select',\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M18.5,27c-3.7,0-4.7,2.9-5.5,5.2c-0.7,2-1.2,3.2-2.5,3.2c-0.8,0-1.5-0.3-2.1-0.8\\n\\tc-0.4-0.4-0.7-0.9-0.9-1.5c0.6-0.4,1-1,1-1.7c0-0.2,0-0.4-0.1-0.6c0.8-0.5,1.7-1.2,2.5-2c3.5-3.5,4.6-7.6,2.7-9.5\\n\\tc-0.6-0.6-1.5-0.9-2.4-0.9c-2.1,0-4.7,1.3-7,3.6c-3.5,3.5-4.6,7.6-2.7,9.5c0.6,0.6,1.5,0.9,2.4,0.9c0.3,0,0.6,0,0.9-0.1\\n\\tc0.3,0.6,1,1.1,1.8,1.1c0,0,0,0,0,0c0.3,0.7,0.6,1.4,1.2,1.9c0.7,0.7,1.7,1.1,2.8,1.1c2.2,0,2.8-2,3.5-4c0.8-2.3,1.6-4.6,4.5-4.6\\n\\tC18.5,28,18.5,27,18.5,27z M2.1,30.9c-0.9-0.9-0.6-2.4-0.4-3.2c0.5-1.6,1.5-3.4,3.1-4.9c2-2,4.5-3.3,6.3-3.3c0.7,0,1.3,0.2,1.7,0.6\\n\\tc0.4,0.4,0.6,1,0.6,1.7c0,1.9-1.3,4.3-3.3,6.3c-0.7,0.7-1.5,1.4-2.3,1.9c-0.4-0.3-0.8-0.5-1.4-0.5c-1.1,0-2,0.9-2,1.9\\n\\tc-0.2,0-0.4,0.1-0.7,0.1C3.1,31.5,2.5,31.3,2.1,30.9z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFSubSelectTool(),\n                title: 'Subselect',\n                category: GApplication.TOOL_CATEGORY_SELECT,\n                group: 'select2',\n                keys: ['A', '1'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M3.5,18.5v18l5-7h9L3.5,18.5z M7.5,27.5l-3,4.5V20.5l9,7H7.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFPageTool(),\n                title: 'Page',\n                category: GApplication.TOOL_CATEGORY_SELECT,\n                group: 'select3',\n                keys: ['D'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M15.5,18.5v10h-1v-9h-7v3h-3v10h3v1h-4v-12l3-3H15.5z M8.5,25.5v11l3.5-4h5.5L8.5,25.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFLayerTool(),\n                title: 'Layer',\n                category: GApplication.TOOL_CATEGORY_SELECT,\n                group: 'select3',\n                keys: ['L'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"-2.5 -.5 18 18\" width=\"18px\" height=\"18px\">\\n<path stroke=\"none\" d=\"M0.5,8.5 L0.5,10.5 L4.5,10.5 L4.5,8.5 L0.5,8.5 Z M10.5,8.5 L10.5,10.5 L12.5,10.5 L12.5,8.5 L10.5,8.5 Z M9.5,8.5 L9.5,9.5 L10.5,9.5 L10.5,8.5 L9.5,8.5 Z M0.5,0.5 L0.5,2.5 L12.5,2.5 L12.5,0.5 L0.5,0.5 Z M0.5,4.5 L0.5,6.5 L12.5,6.5 L12.5,4.5 L0.5,4.5 Z M5.5,7.5 L5.5,18.5 L9,14.5 L14.5,14.5 L5.5,7.5 Z\"></path>\\n</svg>'\n            },\n            {\n                instance: new IFTransformTool(),\n                title: 'Transform',\n                category: GApplication.TOOL_CATEGORY_SELECT,\n                group: 'transform',\n                keys: ['Q'],\n                // todo : get a real svg icon here\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M17.5,32.5H12l-3.5,4v-11L17.5,32.5z M3.5,18.5h-3v3h1v-2h2V18.5z M15.5,18.5v1h2v2h1v-3H15.5z M1.5,35.5v-2h-1v3h3v-1H1.5z M6.4,33.5H3.5v-12h12v7h1v-8h-14v14h3.9V33.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFLineTool(),\n                title: 'Line',\n                category: GApplication.TOOL_CATEGORY_VECTOR,\n                group: 'line',\n                keys: ['N'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<rect stroke=\"none\" x=\"9\" y=\"15.3\" transform=\"matrix(0.7069 0.7074 -0.7074 0.7069 22.2372 1.3418)\" width=\"1\" height=\"24.5\"/>\\n</svg>'\n            },\n            {\n                instance: new IFPenTool(),\n                title: 'Pen',\n                category: GApplication.TOOL_CATEGORY_VECTOR,\n                group: 'path',\n                keys: ['P'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M9.2,21.3l0.7,0.7l-6.5,3.6c0,0-0.5,3.1-1.4,5.7c-0.8,2.2-2.1,3.6-1.4,4.3c0,0,0,0,0.7,0.7\\n\\tc0.7,0.7,2.1-0.6,4.3-1.4c2.5-0.9,5.6-1.4,5.6-1.4l3.7-6.4l0.7,0.7l2.9-2.1l-7.1-7.1L9.2,21.3z M4.2,26.4l6.5-3.6l3.6,3.6l-3.7,6.4\\n\\tc-4.8,0.5-8.5,2.8-8.5,2.8l3.2-3.2c0.8,0.5,1.8,0.3,2.4-0.3c0.8-0.8,0.8-2,0-2.8c-0.8-0.8-2-0.8-2.8,0c-0.7,0.7-0.8,1.7-0.4,2.5\\n\\tl-3.2,3.2C1.4,34.9,3.7,31.2,4.2,26.4z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFBezigonTool(),\n                title: 'Bezigon',\n                category: GApplication.TOOL_CATEGORY_VECTOR,\n                group: 'path',\n                keys: ['B', '8'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path d=\"M7.8,29.3c-1.8-1.7,4.4-10.8,4.4-10.8l1.3,1.2c-1.3,1.5-2.5,3.6-3.1,4.7c-1,1.8-1.1,2.7-1.1,2.7l6-5.7l3.1,3\\n\\tC18.5,24.5,9.5,30.7,7.8,29.3z M18.5,33c0,0.8-0.7,1.5-1.5,1.5c-0.7,0-1.2-0.4-1.4-1H7.5v3h-7v-7h3v-8.1c-0.6-0.2-1-0.8-1-1.4\\n\\tc0-0.8,0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5c0,0.7-0.4,1.2-1,1.4v8.1h3v3h8.1c0.2-0.6,0.8-1,1.4-1C17.8,31.5,18.5,32.2,18.5,33z\\n\\t M6.5,30.5h-5v5h5V30.5z\" stroke=\"none\"/>\\n</svg>'\n            },\n            {\n                instance: new IFRectangleTool(),\n                title: 'Rectangle',\n                category: GApplication.TOOL_CATEGORY_VECTOR,\n                group: 'shape',\n                keys: ['R'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M17.5,20.5v14h-16v-14H17.5 M18.5,19.5h-18v16h18v-15V19.5L18.5,19.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFEllipseTool(),\n                title: 'Ellipse',\n                category: GApplication.TOOL_CATEGORY_VECTOR,\n                group: 'shape2',\n                keys: ['E', '3'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<ellipse style=\"fill:none; stroke: inherit\" cx=\"9.5\" cy=\"27.5\" rx=\"8.5\" ry=\"7.5\"/>\\n</svg>'\n            },\n            {\n                instance: new IFPolygonTool(),\n                title: 'Polygon',\n                category: GApplication.TOOL_CATEGORY_VECTOR,\n                group: 'shape2',\n                keys: ['G'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M13.4,20.5l3.9,7l-3.9,7H5.6l-3.9-7l3.9-7H13.4 M14,19.5H5l-4.5,8l4.5,8h9l4.5-8L14,19.5L14,19.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFTextTool(),\n                title: 'Text',\n                category: GApplication.TOOL_CATEGORY_OTHER,\n                group: 'text',\n                keys: ['T'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\">\\n<text style=\"stroke:none; fill: inherit; font-family: Arial; font-size: 18px; text-anchor: middle\" x=\"9\" y=\"15\">T</text>\\n</svg>'\n            },\n            {\n                instance: new IFSliceTool(),\n                title: 'Slice',\n                category: GApplication.TOOL_CATEGORY_OTHER,\n                group: 'slice',\n                keys: ['K'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M14.8,19.3L2.6,33.4c-0.2,0.3-0.1,0.7,0.1,0.9c0.2,0.2,0.6,0.3,0.9,0.1c0,0,7.9-4.9,8-5.1l6.4-7.4l0,0 c0.8-0.9,0.5-2.2-0.3-2.9C16.9,18.3,15.6,18.3,14.8,19.3z M17,21l-6.3,7.4l-1.1-0.9l6.4-7.4c0.4-0.5,1-0.2,1-0.1 C17.2,20.2,17.2,20.7,17,21z M15.5,27.5v9h-15v-13v0h8v1h-7v11h13v-8H15.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFZoomTool(),\n                title: 'Zoom',\n                category: GApplication.TOOL_CATEGORY_VIEW,\n                group: 'zoom',\n                keys: ['Z'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M17.9,34L15,31.2c1-1.3,1.5-2.9,1.5-4.7c0-4.4-3.6-8.1-8-8.1c-4.4,0-8.1,3.6-8.1,8.1c0,4.4,3.6,8,8.1,8\\n\\tc1.8,0,3.4-0.6,4.7-1.5l2.8,2.8c0.7,0.7,1.7,0.8,2.2,0.3C18.7,35.7,18.6,34.7,17.9,34z M1.6,26.5c0-3.8,3.1-6.9,6.9-6.9s7,3.1,7,6.9\\n\\ts-3.1,7-7,7S1.6,30.3,1.6,26.5z\"/>\\n</svg>'\n            },\n            {\n                instance: new IFHandTool(),\n                title: 'Hand',\n                category: GApplication.TOOL_CATEGORY_VIEW,\n                group: 'hand',\n                keys: ['H'],\n                icon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0.5 18.5 18 18\">\\n<path stroke=\"none\" d=\"M13.7,22.6C10.3,19,7.9,19,7,19.2l-0.4-0.4c-0.1,0-0.5-0.3-1.1-0.3c-0.4,0-0.7,0.1-1,0.4\\n\\tC4.2,19,4.1,19.2,4,19.4c-0.6-0.3-1.3-0.3-1.8,0.2c-0.3,0.3-0.5,0.7-0.5,1.1c0,0.1,0,0.3,0.1,0.4c-0.2,0.1-0.5,0.2-0.7,0.4\\n\\tc-0.9,0.7-0.5,1.7-0.2,2.3c2.7,2.6,5.6,5.8,6.1,7c-0.5-0.2-1.4-0.9-1.9-1.4c-1.7-1.4-2.8-2.2-3.6-1.7c-0.6,0.3-0.7,0.8-0.8,1.1\\n\\tc-0.4,1.5,3.4,5.2,3.6,5.4c1.2,1.3,8.9,2.4,8.9,2.4c0.1,0,0.2,0,0.3-0.1l4.8-3.3c0.1-0.1,0.2-0.2,0.2-0.4\\n\\tC18.5,32.5,18.7,27.8,13.7,22.6z M13.1,35.5L13.1,35.5c-2.9-0.4-7.4-1.3-8.1-2.1c0,0-0.1-0.1-0.2-0.2c-2.6-2.7-3.6-4.1-3.1-4.6\\n\\tc0.1-0.1,0.2-0.1,0.4-0.1c0.5,0,1.4,0.7,2.1,1.3L4.4,30c1,0.8,2.1,1.6,2.8,1.6c0.2,0,0.4-0.1,0.5-0.2c0.1-0.1,0.1-0.2,0.1-0.3\\n\\tc0-1.3-3.2-5.1-6.3-8c-0.2-0.3-0.3-0.7,0-1C1.8,22,2,21.9,2.2,21.9c0.2,0,0.3,0.1,0.4,0.1l4.5,4.3c0.2,0.1,0.4,0.1,0.6,0\\n\\tc0.1-0.1,0.1-0.1,0.1-0.2c0-0.1-0.1-0.3-0.1-0.3l-4.5-4.3c0,0-0.5-0.4-0.5-0.9c0-0.2,0.1-0.3,0.2-0.4c0.1-0.1,0.3-0.2,0.4-0.2\\n\\tc0.4,0,0.9,0.4,1.1,0.7L9,25.2c0.2,0.1,0.4,0.1,0.6,0c0.1-0.1,0.1-0.1,0.1-0.2c0-0.1-0.1-0.3-0.1-0.3l-4.6-4.4\\n\\tc-0.1-0.1-0.1-0.4,0.1-0.6c0.1-0.1,0.3-0.2,0.5-0.2c0.2,0,0.4,0.1,0.4,0.2h0l5,4.3c0.2,0.1,0.4,0.1,0.6,0c0.1-0.1,0.1-0.2,0.1-0.3\\n\\tc0-0.1-0.1-0.2-0.1-0.3L7.8,20l0.5,0.1c1,0.2,2.6,0.9,4.7,3.1c4,4.2,4.5,8.1,4.5,9.2l0,0.1L13.1,35.5z\"/>\\n</svg>'\n            }\n        );\n\n        // Register default color matcher\n        gravit.colorMatchers.push(\n            new GAnalogousMatcher(),\n            new GComplementaryMatcher()\n        );\n\n        // Register default properties\n        gravit.properties.push(\n            new GInfoProperties(),\n            new GDocumentProperties(),\n            new GPolygonProperties(),\n            new GPathProperties(),\n            new GRectangleProperties(),\n            new GEllipseProperties(),\n            new GTextProperties(),\n            new GImageProperties(),\n            new GSliceProperties(),\n            new GPageProperties()\n        );\n\n        // Register default style entries\n        gravit.styleEntries.push(\n            new GFillPaintEntry(),\n            new GStrokePaintEntry(),\n            new GBlurFilterEntry(),\n            new GOffsetVEffectEntry(),\n            new GShadowEffectEntry()\n        );\n\n        // Register default transformers\n        gravit.transformers.push(\n            new GAlignTransformer(),\n            new GAdjustTransformer()\n        );\n\n        // Register default actions\n        gravit.actions.push(\n            // File\n            new GNewAction(),\n            new GOpenAction(),\n\n            new GSaveAction(),\n            new GSaveAsAction(),\n            new GSaveAllAction(),\n\n            new GPlaceImageAction(),\n\n            new GCloseAction(),\n            new GCloseAllAction(),\n\n            // Edit\n            new GUndoAction(),\n            new GRedoAction(),\n\n            new GCutAction(),\n            new GCopyAction(),\n            new GPasteAction(),\n            new GPasteInPlaceAction(),\n            new GPasteInsideAction(),\n            new GDeleteAction(),\n\n            new GCopyAttributesAction(),\n            new GPasteAttributesAction(),\n\n            new GDuplicateAction(),\n            new GCloneAction(),\n\n            new GSelectAllAction(),\n            new GInvertSelectionAction(),\n\n            // Modify\n            new GArrangeAction(GArrangeAction.Type.SendToFront),\n            new GArrangeAction(GArrangeAction.Type.BringForward),\n            new GArrangeAction(GArrangeAction.Type.SendBackward),\n            new GArrangeAction(GArrangeAction.Type.SendToBack),\n\n            new GAlignAction(GAlignAction.Type.AlignLeft),\n            new GAlignAction(GAlignAction.Type.AlignCenter),\n            new GAlignAction(GAlignAction.Type.AlignRight),\n            new GAlignAction(GAlignAction.Type.AlignJustifyHorizontal),\n            new GAlignAction(GAlignAction.Type.AlignTop),\n            new GAlignAction(GAlignAction.Type.AlignMiddle),\n            new GAlignAction(GAlignAction.Type.AlignBottom),\n            new GAlignAction(GAlignAction.Type.AlignJustifyVertical),\n\n            new GDistributeAction(GDistributeAction.Type.Horizontal),\n            new GDistributeAction(GDistributeAction.Type.Vertical),\n\n            new GSnapUnitAction(GSnapUnitAction.Type.FullUnit),\n            new GSnapUnitAction(GSnapUnitAction.Type.HalfUnit),\n\n            new GTransformAction(GTransformAction.Type.Rotate45Left),\n            new GTransformAction(GTransformAction.Type.Rotate90Left),\n            new GTransformAction(GTransformAction.Type.Rotate180Left),\n            new GTransformAction(GTransformAction.Type.Rotate45Right),\n            new GTransformAction(GTransformAction.Type.Rotate90Right),\n            new GTransformAction(GTransformAction.Type.Rotate180Right),\n            new GTransformAction(GTransformAction.Type.FlipVertical),\n            new GTransformAction(GTransformAction.Type.FlipHorizontal),\n\n            new GGroupAction(),\n            new GUngroupAction(),\n\n            new GSliceFromSelectionAction(),\n\n            new GAddPageAction(),\n            new GDeletePageAction(),\n\n            new GAddLayerAction(),\n            new GDeleteLayerAction(),\n\n            new GLayerTypeAction(IFLayer.Type.Output),\n            new GLayerTypeAction(IFLayer.Type.Draft),\n            new GLayerTypeAction(IFLayer.Type.Guide),\n\n\n            // View\n            new GOriginalViewAction(),\n            new GFitSelectionAction(),\n            new GFitCurrentPageAction(),\n            new GFitCurrentLayerAction(),\n            new GFitAllAction(),\n            new GMagnificationAction(6, null),\n            new GMagnificationAction(12, null),\n            new GMagnificationAction(25, null),\n            new GMagnificationAction(50, [IFKey.Constant.META, '5']),\n            new GMagnificationAction(100, [IFKey.Constant.META, '1']),\n            new GMagnificationAction(200, [IFKey.Constant.META, '2']),\n            new GMagnificationAction(400, [IFKey.Constant.META, '4']),\n            new GMagnificationAction(800, [IFKey.Constant.META, '8']),\n            new GZoomInAction(),\n            new GZoomOutAction(),\n\n            new GPaintModeAction(IFScenePaintConfiguration.PaintMode.Full),\n            new GPaintModeAction(IFScenePaintConfiguration.PaintMode.Fast),\n            new GPaintModeAction(IFScenePaintConfiguration.PaintMode.Outline),\n            new GPaintModeAction(IFScenePaintConfiguration.PaintMode.Output),\n\n            new GPixelPreviewAction(),\n            new GShowAllPagesAction(),\n\n            new GShowGridAction(),\n            new GShowRulersAction(),\n\n            // Window\n            new GNewWindowAction()\n        );\n    };\n\n    /** @override */\n    GravitModule.prototype.toString = function () {\n        return '[Module Gravit]';\n    };\n\n    gravit.modules.push(new GravitModule());\n})(this);\n"
  },
  {
    "path": "src/gravit/i18n/i18n_de.js",
    "content": ""
  },
  {
    "path": "src/gravit/i18n/i18n_en.js",
    "content": "// Action\nifLocale.setValues(GAddLayerAction, IFLocale.Language.English, [\"title\"], [\"Add Layer\"]);\nifLocale.setValues(GAddPageAction, IFLocale.Language.English, [\"title\"], [\"Add Page\"]);\nifLocale.setValues(GAlignAction, IFLocale.Language.English, [\"title.align-left\", \"title.align-center\", \"title.align-right\", \"title.align-top\", \"title.align-middle\", \"title.align-bottom\", \"title.align-justify-horizontal\", \"title.align-justify-vertical\"], [\"Align Left\", \"Align Center\", \"Align Right\", \"Align Top\", \"Align Middle\", \"Align Bottom\", \"Justify Horizontal\", \"Justify Vertical\"]);\nifLocale.setValues(GCloneAction, IFLocale.Language.English, [\"title\"], [\"Clone\"]);\nifLocale.setValues(GCloseAction, IFLocale.Language.English, [\"title\"], [\"Close\"]);\nifLocale.setValues(GCloseAllAction, IFLocale.Language.English, [\"title\"], [\"Close All\"]);\nifLocale.setValues(GCopyAction, IFLocale.Language.English, [\"title\"], [\"Copy\"]);\nifLocale.setValues(GCopyAttributesAction, IFLocale.Language.English, [\"title\"], [\"Copy Attributes\"]);\nifLocale.setValues(GCutAction, IFLocale.Language.English, [\"title\"], [\"Cut\"]);\nifLocale.setValues(GDeleteAction, IFLocale.Language.English, [\"title\"], [\"Delete\"]);\nifLocale.setValues(GDeleteLayerAction, IFLocale.Language.English, [\"title\"], [\"Delete Layer\"]);\nifLocale.setValues(GDeletePageAction, IFLocale.Language.English, [\"title\"], [\"Delete Page\"]);\nifLocale.setValues(GDistributeAction, IFLocale.Language.English, [\"title.horizontal\", \"title.vertical\"], [\"Distribute Horizontally\", \"Distribute Vertically\"]);\nifLocale.setValues(GDuplicateAction, IFLocale.Language.English, [\"title\"], [\"Duplicate\"]);\nifLocale.setValues(GFitAllAction, IFLocale.Language.English, [\"title\"], [\"Fit All\"]);\nifLocale.setValues(GFitCurrentLayerAction, IFLocale.Language.English, [\"title\"], [\"Fit Layer\"]);\nifLocale.setValues(GFitCurrentPageAction, IFLocale.Language.English, [\"title\"], [\"Fit Page\"]);\nifLocale.setValues(GFitSelectionAction, IFLocale.Language.English, [\"title\"], [\"Fit Selection\"]);\nifLocale.setValues(GGroupAction, IFLocale.Language.English, [\"title\"], [\"Group Selection\"]);\nifLocale.setValues(GPlaceImageAction, IFLocale.Language.English, [\"title\"], [\"Place Image...\"]);\nifLocale.setValues(GInvertSelectionAction, IFLocale.Language.English, [\"title\"], [\"Invert Selection\"]);\nifLocale.setValues(GLayerTypeAction, IFLocale.Language.English, [\"title\"], [\"%name% Layer\"]);\nifLocale.setValues(GNewAction, IFLocale.Language.English, [\"title\"], [\"New...\"]);\nifLocale.setValues(GNewWindowAction, IFLocale.Language.English, [\"title\"], [\"New Window\"]);\nifLocale.setValues(GOpenAction, IFLocale.Language.English, [\"title\"], [\"Open...\"]);\nifLocale.setValues(GArrangeAction, IFLocale.Language.English, [\"title.send-front\", \"title.bring-forward\", \"title.send-backward\", \"title.send-back\"], [\"Send To Front\", \"Bring Forward\", \"Send Backward\", \"Send To Back\"]);\nifLocale.setValues(GOriginalViewAction, IFLocale.Language.English, [\"title\"], [\"Original-View\"]);\nifLocale.setValues(GPaintModeAction, IFLocale.Language.English, [\"title\"], [\"%name% View\"]);\nifLocale.setValues(GPasteAction, IFLocale.Language.English, [\"title\"], [\"Paste\"]);\nifLocale.setValues(GPasteInPlaceAction, IFLocale.Language.English, [\"title\"], [\"Paste In Place\"]);\nifLocale.setValues(GPasteInsideAction, IFLocale.Language.English, [\"title\"], [\"Paste Inside Selection\"]);\nifLocale.setValues(GPasteAttributesAction, IFLocale.Language.English, [\"title\"], [\"Paste Attributes\"]);\nifLocale.setValues(GPixelPreviewAction, IFLocale.Language.English, [\"title\"], [\"Pixel Preview\"]);\nifLocale.setValues(GRedoAction, IFLocale.Language.English, [\"title\"], [\"Redo\"]);\nifLocale.setValues(GSaveAction, IFLocale.Language.English, [\"title\"], [\"Save\"]);\nifLocale.setValues(GSaveAllAction, IFLocale.Language.English, [\"title\"], [\"Save All\"]);\nifLocale.setValues(GSaveAsAction, IFLocale.Language.English, [\"title\"], [\"Save As...\"]);\nifLocale.setValues(GShowRulersAction, IFLocale.Language.English, [\"title\"], [\"Show Rulers\"]);\nifLocale.setValues(GSelectAllAction, IFLocale.Language.English, [\"title\"], [\"Select All\"]);\nifLocale.setValues(GShowAllPagesAction, IFLocale.Language.English, [\"title\"], [\"All Pages visible\"]);\nifLocale.setValues(GShowGridAction, IFLocale.Language.English, [\"title\"], [\"Show Grid\"]);\nifLocale.setValues(GSliceFromSelectionAction, IFLocale.Language.English, [\"title\"], [\"Create Slice from Selection\"]);\nifLocale.setValues(GSnapUnitAction, IFLocale.Language.English, [\"title.full\", \"title.half\"], [\"Snap to full units\", \"Snap to half units\"]);\nifLocale.setValues(GTransformAction, IFLocale.Language.English, [\"title.rotate-45-left\", \"title.rotate-90-left\", \"title.rotate-180-left\", \"title.rotate-45-right\", \"title.rotate-90-right\", \"title.rotate-180-right\", \"title.flip-vertical\", \"title.flip-horizontal\"], [\"Rotate 45° Left\", \"Rotate 90° Left\", \"Rotate 180° Left\", \"Rotate 45° Right\", \"Rotate 90° Right\", \"Rotate 180° Right\", \"Flip Vertical\", \"Flip Horizontal\"]);\nifLocale.setValues(GUndoAction, IFLocale.Language.English, [\"title\"], [\"Undo\"]);\nifLocale.setValues(GUngroupAction, IFLocale.Language.English, [\"title\"], [\"Ungroup Selection\"]);\nifLocale.setValues(GZoomInAction, IFLocale.Language.English, [\"title\"], [\"Zoom in\"]);\nifLocale.setValues(GZoomOutAction, IFLocale.Language.English, [\"title\"], [\"Zoom out\"]);\n\n// Color\nifLocale.setValues(GAnalogousMatcher, IFLocale.Language.English, [\"title\"], [\"Analogous\"]);\nifLocale.setValues(GComplementaryMatcher, IFLocale.Language.English, [\"title\"], [\"Complementary\"]);\n\n// Palette\nifLocale.setValues(GExportPalette, IFLocale.Language.English, [\"title\"], [\"Export\"]);\nifLocale.setValues(GStylePalette, IFLocale.Language.English, [\"title\"], [\"Style\"]);\n\n// Panel\nifLocale.setValues(GPropertiesPanel, IFLocale.Language.English, [\"title\"], [\"Properties\"]);\nifLocale.setValues(GTransformPanel, IFLocale.Language.English, [\"title\"], [\"Transform\"]);\n\n// Sidebar\nifLocale.setValues(GStylesSwatchesSidebar, IFLocale.Language.English, [\"title\"], [\"Styles & Swatches\"]);\nifLocale.setValues(GPagesLayersSidebar, IFLocale.Language.English, [\"title\"], [\"Pages & Layers\"]);"
  },
  {
    "path": "src/gravit/palette/exportpalette.js",
    "content": "(function (_) {\n\n    /**\n     * Export Palette\n     * @class GExportPalette\n     * @extends GPalette\n     * @constructor\n     */\n    function GExportPalette() {\n        GPalette.call(this);\n        this._extensions = [];\n    }\n\n    IFObject.inherit(GExportPalette, GPalette);\n\n    GExportPalette.ID = \"export\";\n    GExportPalette.TITLE = new IFLocale.Key(GExportPalette, \"title\");\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GExportPalette.prototype._htmlElement = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GExportPalette.prototype._controls = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GExportPalette.prototype._document = null;\n\n    /**\n     * @type {IFElement}\n     * @private\n     */\n    GExportPalette.prototype._element = null;\n\n    /**\n     * @type {Array<{{extension: String, exporter: GExporter}}>}\n     * @private\n     */\n    GExportPalette.prototype._extensions = null;\n\n    /** @override */\n    GExportPalette.prototype.getId = function () {\n        return GExportPalette.ID;\n    };\n\n    /** @override */\n    GExportPalette.prototype.getTitle = function () {\n        return GExportPalette.TITLE;\n    };\n\n    /** @override */\n    GExportPalette.prototype.getGroup = function () {\n        return \"export\";\n    };\n\n    /** @override */\n    GExportPalette.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /** @override */\n    GExportPalette.prototype.init = function (htmlElement, controls) {\n        GPalette.prototype.init.call(this, htmlElement, controls);\n\n        // Init our extensions / exporters\n        for (var k = 0; k < gravit.exporters.length; ++k) {\n            var exporter = gravit.exporters[k];\n            if (!exporter.isStandalone()) {\n                var extensions = exporter.getExtensions();\n                for (var n = 0; n < extensions.length; ++n) {\n                    this._extensions.push({\n                        extension: extensions[n].toLowerCase(),\n                        exporter: exporter\n                    });\n                }\n            }\n        }\n\n        this._htmlElement = htmlElement;\n        this._controls = controls;\n\n        $('<button></button>')\n            .attr('data-action', 'add')\n            // TODO : I18N\n            .attr('title', 'Add Export')\n            .on('click', function () {\n                var exportVal = this._element.getProperty('export', true);\n\n                if (!exportVal) {\n                    exportVal = [];\n                } else {\n                    exportVal = exportVal.slice(); // clone!!\n                }\n\n                exportVal.push({\n                    'sz': '1x',\n                    'sf': '',\n                    'ex': gravit.exporters[0].getExtensions()[0]\n                });\n\n                this._element.setProperty('export', exportVal, true);\n            }.bind(this))\n            .append($('<span></span>')\n                .addClass('fa fa-plus'))\n            .appendTo(controls);\n    };\n\n    /** @override */\n    GExportPalette.prototype._documentEvent = function (event) {\n        if (event.type === GApplication.DocumentEvent.Type.Activated) {\n            this._document = event.document;\n            var scene = this._document.getScene();\n            var editor = this._document.getEditor();\n\n            scene.addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            editor.addEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n\n            this._updateFromSelection();\n\n            this.trigger(GPalette.UPDATE_EVENT);\n        } else if (event.type === GApplication.DocumentEvent.Type.Deactivated) {\n            var scene = this._document.getScene();\n            var editor = this._document.getEditor();\n\n            scene.removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            editor.removeEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n\n            this._document = null;\n            this._elements = null;\n\n            this._updateExports();\n\n            this.trigger(GPalette.UPDATE_EVENT);\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GExportPalette.prototype._afterPropertiesChange = function (evt) {\n        if (evt.node === this._element && (evt.properties.indexOf('export') >= 0 || evt.properties.indexOf('name') >= 0)) {\n            this._updateExports();\n        }\n    };\n\n    /**\n     * @private\n     */\n    GExportPalette.prototype._updateFromSelection = function () {\n        this._element = null;\n\n        var selection = this._document ? this._document.getEditor().getSelection() : null;\n\n        if (selection && selection.length === 1) {\n            this._element = selection[0];\n        } else if (this._document) {\n            // use active page as element if any\n            this._element = this._document.getScene().getActivePage();\n        }\n\n        this._updateExports();\n    };\n\n    GExportPalette.prototype._updateExports = function () {\n        this._htmlElement.empty();\n\n        if (this._element) {\n            var name = this._element.getProperty('name');\n\n            // TODO : I18N\n            var title = 'Export ' + this._element.getNodeNameTranslated();\n            if (name && name.trim() !== '') {\n                title += ' \"' + name + '\"';\n            }\n            title += ' as:';\n\n            $('<div></div>')\n                .addClass('title')\n                .text(title)\n                .appendTo(this._htmlElement);\n\n            var exportTable = $('<div></div>')\n                .addClass('export-table')\n                .appendTo(this._htmlElement);\n\n            var _addExportRow = function (exportRow, index) {\n                var extSelect = $('<select></select>');\n\n                for (var i = 0; i < this._extensions.length; ++i) {\n                    var ext = this._extensions[i];\n                    $('<option></option>')\n                        .text(ext.extension.toUpperCase())\n                        .val(ext.extension)\n                        .appendTo(extSelect);\n                }\n\n                $('<div></div>')\n                    .addClass('export-row')\n                    .data('export-index', i)\n                    .append($('<div></div>')\n                        .addClass('export-cell')\n                        .append($('<input>')\n                            .css('width', '8em')\n                            // TODO: I18N\n                            .attr('placeholder', 'Size')\n                            .val(exportRow.sz)\n                            .on('change', function (evt) {\n                                exportRow.sz = $(evt.target).val();\n                            }))\n                        .append($('<input>')\n                            .css('width', '4em')\n                            // TODO: I18N\n                            .attr('placeholder', 'Suffix')\n                            .val(exportRow.sf)\n                            .on('change', function (evt) {\n                                exportRow.sf = $(evt.target).val();\n                            }))\n                        .append(extSelect\n                            .val(exportRow.ex)\n                            .on('change', function (evt) {\n                                exportRow.ex = $(evt.target).val();\n                            })))\n                    .append($('<div></div>')\n                        .addClass('export-cell')\n                        .append($('<button></button>')\n                            // TODO : I18N\n                            .attr('title', 'Export this item only')\n                            .on('click', function () {\n                                //this._getExporterByExt(exportRow.ex).exportPart(this._element, exportRow.sz, null, '', exportRow.ex);\n\n\n                                var storage = gApp.getMatchingStorage(true, true, exportRow.ex, false, this._document.getStorage());\n                                if (storage) {\n                                    storage.saveResourcePrompt(this._document.getUrl(), this._element.getLabel() + exportRow.sf, [exportRow.ex], function (url) {\n                                        this._getExporterByExt(exportRow.ex).exportPart(this._element, exportRow.sz, storage, url, exportRow.ex);\n                                    }.bind(this));\n                                }\n                            }.bind(this))\n                            .append($('<span></span>')\n                                .addClass('fa fa-external-link-square')))\n                        .append($('<button></button>')\n                            .append($('<span></span>')\n                                .addClass('fa fa-trash-o'))\n                            .on('click', function () {\n                                var exports = this._element.getProperty('export', true).slice();\n                                exports.splice(index, 1);\n                                this._element.setProperty('export', exports, true);\n                            }.bind(this))))\n                    .appendTo(exportTable);\n            }.bind(this);\n\n            var exports = this._element.getProperty('export', true);\n            if (exports && exports.length > 0) {\n                for (var i = 0; i < exports.length; ++i) {\n                    _addExportRow(exports[i], i);\n                }\n\n                $('<div></div>')\n                    .addClass('controls')\n                    .append($('<button></button>')\n                        .on('click', function () {\n                            var storage = gApp.getMatchingStorage(true, true, null, true, this._document.getStorage());\n                            if (storage) {\n                                storage.openDirectoryPrompt(this._document.getUrl(), function (url) {\n                                    var exports = this._element.getProperty('export', true);\n                                    for (var i = 0; i < exports.length; ++i) {\n                                        var exportRow = exports[i];\n                                        var resourceUrl = new URI(url).filename(this._element.getLabel() + exportRow.sf + '.' + exportRow.ex).toString();\n                                        this._getExporterByExt(exportRow.ex).exportPart(this._element, exportRow.sz, storage, resourceUrl, exportRow.ex);\n                                    }\n                                }.bind(this));\n                            }\n                        }.bind(this))\n                        .append($('<span></span>')\n                            .text('Export All...')))\n                    .appendTo(this._htmlElement);\n            }\n        }\n\n        this._controls.find('[data-action=\"add\"]').prop('disabled', !this._element);\n    };\n\n    /**\n     * @param {String} extension\n     * @returns {GExporter}\n     * @private\n     */\n    GExportPalette.prototype._getExporterByExt = function (extension) {\n        extension = extension.toLowerCase();\n        for (var i = 0; i < this._extensions.length; ++i) {\n            if (this._extensions[i].extension === extension) {\n                return this._extensions[i].exporter;\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    GExportPalette.prototype.toString = function () {\n        return \"[Object GExportPalette]\";\n    };\n\n    _.GExportPalette = GExportPalette;\n})(this);"
  },
  {
    "path": "src/gravit/palette/stylepalette.js",
    "content": "(function (_) {\n\n    /**\n     * Style Palette\n     * @class GStylePalette\n     * @extends GPalette\n     * @constructor\n     */\n    function GStylePalette() {\n        GPalette.call(this);\n        this._styleEntries = {};\n    }\n\n    IFObject.inherit(GStylePalette, GPalette);\n\n    GStylePalette.ID = \"style\";\n    GStylePalette.TITLE = new IFLocale.Key(GStylePalette, \"title\");\n\n    /**\n     * @type {{}}\n     * @private\n     */\n    GStylePalette.prototype._styleEntries = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._htmlElement = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GStylePalette.prototype._document = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._styleDeleteControl = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._styleAddControl = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._styleSelector = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._styleSettings = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._paintsPanel = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._filtersPanel = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylePalette.prototype._effectsPanel = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    GStylePalette.prototype._styleElements = null;\n\n    /**\n     * @type {Array<Array<IFStyle>>}\n     * @private\n     */\n    GStylePalette.prototype._styles = null;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    GStylePalette.prototype._selectedStyleIndex = -1;\n\n    /** @override */\n    GStylePalette.prototype.getId = function () {\n        return GStylePalette.ID;\n    };\n\n    /** @override */\n    GStylePalette.prototype.getTitle = function () {\n        return GStylePalette.TITLE;\n    };\n\n    /** @override */\n    GStylePalette.prototype.getGroup = function () {\n        return \"style\";\n    };\n\n\n    /** @override */\n    GStylePalette.prototype.isEnabled = function () {\n        return !!gApp.getActiveDocument();\n    };\n\n    /** @override */\n    GStylePalette.prototype.init = function (htmlElement, controls) {\n        GPalette.prototype.init.call(this, htmlElement, controls);\n\n        this._htmlElement = htmlElement;\n\n        // Init controls\n        this._styleAddControl = $('<button></button>')\n            // TODO : I18N\n            .attr('title', 'Add new style')\n            .on('click', function (evt) {\n                $('<div></div>')\n                    .css({\n                        'width': '250px'\n                    })\n                    .addClass('g-style-list')\n                    .gStylePanel({\n                        nullStyle: $('<span></span>')\n                            .addClass('fa fa-plus-circle')\n                            .css({\n                                'font-size': '24px',\n                                'line-height': '30px'\n                            }),\n                        // TODO : I18N\n                        nullName: 'Add new style to element'\n                    })\n                    .gStylePanel('attach', this._document.getScene().getStyleCollection())\n                    .gOverlay({\n                        releaseOnClose: true\n                    })\n                    .gOverlay('open', evt.target)\n                    .on('close', function () {\n                        $(this).gStylePanel('detach');\n                    })\n                    .on('stylechange', function (evt, style) {\n                        $(evt.target).gOverlay('close');\n\n                        var styleIndex = -1;\n                        var editor = this._document.getEditor();\n                        editor.beginTransaction();\n                        try {\n                            for (var i = 0; i < this._styleElements.length; ++i) {\n                                var appliedStyle = null;\n\n                                if (style) {\n                                    appliedStyle = new IFLinkedStyle();\n                                    appliedStyle.setProperty('ref', style.getReferenceId());\n                                } else {\n                                    appliedStyle = new IFInlineStyle();\n                                }\n\n                                this._styleElements[i].getStyleSet().appendChild(appliedStyle);\n\n                                if (styleIndex < 0) {\n                                    styleIndex = this._getStyleIndex(appliedStyle);\n                                    this._setSelectedStyle(styleIndex);\n                                }\n                            }\n                        } finally {\n                            // TODO : I18N\n                            editor.commitTransaction('Add Style');\n                        }\n                    }.bind(this));\n            }.bind(this))\n            .append($('<span></span>')\n                .addClass('fa fa-plus'))\n            .appendTo(controls);\n\n        this._styleDeleteControl = $('<button></button>')\n            // TODO : I18N\n            .attr('title', 'Remove hidden styles')\n            .on('click', function () {\n                var editor = this._document.getEditor();\n                editor.beginTransaction();\n                try {\n                    var styles = this._styles.slice();\n                    for (var i = 0; i < styles.length; ++i) {\n                        var style = styles[i].slice();\n                        for (var j = 0; j < style.length; ++j) {\n                            if (style[j].getProperty('vs') === false) {\n                                style[j].getParent().removeChild(style[j]);\n                            }\n                        }\n                    }\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Removed Hidden Styles');\n                }\n            }.bind(this))\n            .append($('<span></span>')\n                .addClass('fa fa-trash-o'))\n            .appendTo(controls);\n\n        var filterEntries = [];\n        var effectEntries = [];\n\n        // Initialize all style entry handlers and create menus for them\n        for (var i = 0; i < gravit.styleEntries.length; ++i) {\n            var styleEntry = gravit.styleEntries[i];\n            var entryClass = styleEntry.getEntryClass();\n            this._styleEntries[IFObject.getTypeId(entryClass)] = styleEntry;\n\n            if (IFFilterEntry.prototype.isPrototypeOf(styleEntry.getEntryClass().prototype)) {\n                filterEntries.push({\n                    entry: styleEntry,\n                    name: ifLocale.get(styleEntry.getEntryName())\n                });\n            } else if (IFEffectEntry.prototype.isPrototypeOf(styleEntry.getEntryClass().prototype)) {\n                effectEntries.push({\n                    entry: styleEntry,\n                    name: ifLocale.get(styleEntry.getEntryName()),\n                    rootClass: IFEffectEntry\n                });\n            } else if (IFVEffectEntry.prototype.isPrototypeOf(styleEntry.getEntryClass().prototype)) {\n                effectEntries.push({\n                    entry: styleEntry,\n                    name: ifLocale.get(styleEntry.getEntryName()),\n                    rootClass: IFVEffectEntry\n                });\n            }\n        }\n\n        // Order filters by name, effects by type and name\n        filterEntries.sort(function (a, b) {\n            return a.name.localeCompare(b.name);\n        });\n        effectEntries.sort(function (a, b) {\n            if (a.rootClass === b.rootClass) {\n                return a.name.localeCompare(b.name);\n            } else {\n                return a.rootClass === IFVEffectEntry ? -1 : 1;\n            }\n        });\n\n        // Handler for adding a new style entry menu item\n        var _addStyleEntryMenu = function (styleEntryClass, name, menu) {\n            // TODO : I18N\n            menu.createAddItem('Add ' + name, function () {\n                this._modifyEachSelectedStyle(function (style) {\n                    style.getActualStyle().appendChild(new styleEntryClass());\n                });\n            }.bind(this));\n        }.bind(this);\n\n        // Add style selector\n        this._styleSelector = $('<div></div>')\n            .addClass('style-selector')\n            .gStylePanel({\n                allowDrop: true,\n                previewWidth: 40,\n                previewHeight: 40\n            })\n            .on('stylechange', function (evt, style) {\n                this._setSelectedStyle(this._getStyleIndex(style));\n            }.bind(this))\n            .on('styledragaway', function (evt, style) {\n                var styleIndex = this._getStyleIndex(style);\n                var styles = this._styles[styleIndex];\n                var editor = this._document.getEditor();\n                editor.beginTransaction();\n                try {\n                    for (var i = 0; i < styles.length; ++i) {\n                        styles[i].getParent().removeChild(styles[i]);\n                    }\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Remove Style');\n                }\n            }.bind(this))\n            .on('stylemove', function (evt, sourceStyle, targetStyle) {\n                var sourceStyleIndex = this._getStyleIndex(sourceStyle);\n                var targetStyleIndex = this._getStyleIndex(targetStyle);\n                var sourceStyles = this._styles[sourceStyleIndex].slice();\n                var targetStyles = this._styles[targetStyleIndex].slice();\n                this._selectedStyleIndex = -1;\n                var editor = this._document.getEditor();\n\n                editor.beginTransaction();\n                try {\n                    for (var i = 0; i < sourceStyles.length; ++i) {\n                        var parent = sourceStyles[i].getParent();\n                        parent.removeChild(sourceStyles[i]);\n                        parent.insertChild(sourceStyles[i], sourceStyleIndex < targetStyleIndex ? targetStyles[i].getNext() : targetStyles[i]);\n                    }\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Move Style');\n                }\n\n                this._setSelectedStyle(this._getStyleIndex(sourceStyle));\n            }.bind(this))\n            .appendTo(this._htmlElement);\n\n        // Style settings\n        this._styleSettings = $('<div></div>')\n            .addClass('style-settings')\n            .append($('<div></div>')\n                .addClass('visibility')\n                .append($('<span></span>')\n                    .addClass('fa')\n                    // TODO : I18N\n                    .attr('title', 'Toggle Style Visibility')\n                    .on('click', function () {\n                        var makeVisible = this._styles[this._selectedStyleIndex][0].getProperty('vs') === false;\n                        this._modifyEachSelectedStyle(function (style) {\n                            style.setProperty('vs', makeVisible);\n                        });\n                    }.bind(this))))\n            .append($('<div></div>')\n                .css('width', '100%')\n                .append($('<select></select>')\n                    .attr('data-property', 'blm')\n                    .gBlendMode()\n                    .on('change', function (evt) {\n                        var val = $(evt.target).val();\n                        this._modifyEachSelectedStyle(function (style) {\n                            style.setProperty('blm', val);\n                        });\n                    }.bind(this)))\n                .append($('<input>')\n                    .attr('data-property', 'opc')\n                    .css('width', '3em')\n                    .on('change', function (evt) {\n                        var opacity = IFLength.parseEquationValue($(evt.target).val());\n                        if (opacity !== null) {\n                            opacity = opacity < 0 ? 0 : opacity > 100 ? 100 : opacity;\n                            opacity /= 100.0;\n                            this._modifyEachSelectedStyle(function (style) {\n                                style.setProperty('opc', opacity);\n                            });\n                        } else {\n                            this._updateStyleSettings();\n                        }\n                    }.bind(this)))\n                .append($('<select></select>')\n                    .attr('data-property', 'tp')\n                    .append($('<option></option>')\n                        .attr('value', IFAppliedStyle.Type.Content)\n                        // TODO : I18N\n                        .text('Content'))\n                    .append($('<option></option>')\n                        .attr('value', IFAppliedStyle.Type.Knockout)\n                        // TODO : I18N\n                        .text('Knockout'))\n                    /* TODO\n                     .append($('<option></option>')\n                     .attr('value', IFAppliedStyle.Type.Mask)\n                     // TODO : I18N\n                     .text('Mask'))\n                     .append($('<option></option>')\n                     .attr('value', IFAppliedStyle.Type.Background)\n                     // TODO : I18N\n                     .text('Background'))*/\n                    .on('change', function (evt) {\n                        var val = $(evt.target).val();\n                        this._modifyEachSelectedStyle(function (style) {\n                            style.setProperty('tp', val);\n                        });\n                    }.bind(this))))\n            .append($('<div></div>')\n                .css('text-align', 'right')\n                .append($('<button></button>')\n                    .attr('data-property', '__link')\n                    .on('click', function () {\n                        this._toggleStyleLink();\n                    }.bind(this))\n                    .append($('<span></span>')\n                        .addClass('fa'))))\n            .appendTo(this._htmlElement);\n\n        // Paints section\n        this._paintsPanel = $('<div></div>')\n            .addClass('style-entries-panel')\n            .append($('<div></div>')\n                .addClass('style-entries-panel-table'));\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Fills & Borders',\n                content: this._paintsPanel,\n                controls: [\n                    $('<button></button>')\n                        // TODO : I18N\n                        .attr('title', 'Add Stroke')\n                        .on('click', function () {\n                            this._modifyEachSelectedStyle(function (style) {\n                                style.getActualStyle().appendChild(new IFStrokePaint());\n                            });\n                        }.bind(this))\n                        .append($('<span></span>')\n                            .addClass('fa fa-pencil')),\n                    $('<button></button>')\n                        // TODO : I18N\n                        .attr('title', 'Add Fill')\n                        .on('click', function () {\n                            this._modifyEachSelectedStyle(function (style) {\n                                style.getActualStyle().appendChild(new IFFillPaint());\n                            });\n                        }.bind(this))\n                        .append($('<span></span>')\n                            .addClass('fa fa-stop')),\n                    $('<button></button>')\n                        // TODO : I18N\n                        .attr('title', 'Remove hidden entries')\n                        .on('click', function () {\n                            this._removeHiddenEntries([IFPaintEntry]);\n                        }.bind(this))\n                        .append($('<span></span>')\n                            .addClass('fa fa-trash-o'))\n                ]\n            })\n            .appendTo(this._htmlElement);\n\n        // Filter section\n        var filtersAddMenu = new GMenu();\n        for (var i = 0; i < filterEntries.length; ++i) {\n            // TODO : I18N\n            _addStyleEntryMenu(filterEntries[i].entry.getEntryClass(), filterEntries[i].name, filtersAddMenu);\n        }\n\n        this._filtersPanel = $('<div></div>')\n            .addClass('style-entries-panel')\n            .append($('<div></div>')\n                .addClass('style-entries-panel-table'))\n            .appendTo(this._htmlElement);\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Filters',\n                content: this._filtersPanel,\n                controls: [\n                    $('<button></button>')\n                        .gMenuButton({\n                            menu: filtersAddMenu,\n                            arrow: false\n                        })\n                        .append($('<span></span>')\n                            .addClass('fa fa-plus')),\n                    $('<button></button>')\n                        // TODO : I18N\n                        .attr('title', 'Remove hidden entries')\n                        .on('click', function () {\n                            this._removeHiddenEntries([IFFilterEntry]);\n                        }.bind(this))\n                        .append($('<span></span>')\n                            .addClass('fa fa-trash-o'))\n                ]\n            })\n            .appendTo(this._htmlElement);\n\n        // Effects section\n        var effectsAddMenu = new GMenu();\n        var hasRasterEffect = false;\n        for (var i = 0; i < effectEntries.length; ++i) {\n            var entryClass = effectEntries[i].entry.getEntryClass();\n            var rootClass = effectEntries[i].rootClass;\n            if (!hasRasterEffect && rootClass === IFEffectEntry) {\n                effectsAddMenu.createAddDivider();\n                hasRasterEffect = true;\n            }\n\n            _addStyleEntryMenu(entryClass, effectEntries[i].name, effectsAddMenu);\n        }\n\n        this._effectsPanel = $('<div></div>')\n            .addClass('style-entries-panel')\n            .append($('<div></div>')\n                .addClass('style-entries-panel-table'))\n            .appendTo(this._htmlElement);\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Effects',\n                content: this._effectsPanel,\n                controls: [\n                    $('<button></button>')\n                        .gMenuButton({\n                            menu: effectsAddMenu,\n                            arrow: false\n                        })\n                        .append($('<span></span>')\n                            .addClass('fa fa-plus')),\n                    $('<button></button>')\n                        // TODO : I18N\n                        .attr('title', 'Remove hidden entries')\n                        .on('click', function () {\n                            this._removeHiddenEntries([IFEffectEntry, IFVEffectEntry]);\n                        }.bind(this))\n                        .append($('<span></span>')\n                            .addClass('fa fa-trash-o'))\n                ]\n            })\n            .appendTo(this._htmlElement);\n    };\n\n    /** @override */\n    GStylePalette.prototype._documentEvent = function (event) {\n        if (event.type === GApplication.DocumentEvent.Type.Activated) {\n            this._document = event.document;\n            var scene = this._document.getScene();\n            var editor = this._document.getEditor();\n\n            // Subscribe to scene events\n            scene.addEventListener(IFNode.AfterInsertEvent, this._afterInsert, this);\n            scene.addEventListener(IFNode.BeforeRemoveEvent, this._beforeRemove, this);\n            scene.addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            scene.addEventListener(IFStyle.StyleChangeEvent, this._styleChange, this);\n\n            // Subscribe to the editor's events\n            editor.addEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n\n            this._updateFromSelection();\n\n            this.trigger(GPalette.UPDATE_EVENT);\n        } else if (event.type === GApplication.DocumentEvent.Type.Deactivated) {\n            var scene = this._document.getScene();\n            var editor = this._document.getEditor();\n\n            // Unsubscribe from the editor's events\n            editor.removeEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection);\n\n            // Unsubscribe from scene events\n            scene.removeEventListener(IFNode.AfterInsertEvent, this._afterInsert, this);\n            scene.removeEventListener(IFNode.BeforeRemoveEvent, this._beforeRemove, this);\n            scene.removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            scene.removeEventListener(IFNode.StyleChangeEvent, this._styleChange, this);\n\n            this._document = null;\n            this._styleElements = null;\n            this._styles = null;\n            this._selectedStyleIndex = -1;\n            this._updateSelectedStyle();\n\n            this.trigger(GPalette.UPDATE_EVENT);\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterInsertEvent} evt\n     * @private\n     */\n    GStylePalette.prototype._afterInsert = function (evt) {\n        if (evt.node instanceof IFStyleEntry) {\n            var style = evt.node.getOwnerStyle();\n            if (style && this._isSelectedStyle(style)) {\n                this._insertEntryRow(evt.node);\n            }\n        } else if (evt.node instanceof IFStyle) {\n            this._insertStyles(evt.node);\n        }\n    };\n\n    /**\n     * @param {IFNode.BeforeRemoveEvent} evt\n     * @private\n     */\n    GStylePalette.prototype._beforeRemove = function (evt) {\n        if (evt.node instanceof IFStyleEntry) {\n            var style = evt.node.getOwnerStyle();\n            if (style && this._isSelectedStyle(style)) {\n                this._removeEntryRow(evt.node);\n            }\n        } else if (evt.node instanceof IFStyle) {\n            this._removeStyle(evt.node);\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} evt\n     * @private\n     */\n    GStylePalette.prototype._afterPropertiesChange = function (evt) {\n        if (evt.node instanceof IFStyleEntry) {\n            var style = evt.node.getOwnerStyle();\n            if (style && this._isSelectedStyle(style)) {\n                this._updateEntryRow(evt.node);\n            }\n        } else if (evt.node instanceof IFStyle && this._isSelectedStyle(evt.node)) {\n            this._updateStyleSettings();\n        }\n    };\n\n    /**\n     * @param {IFStyle.StyleChangeEvent} evt\n     * @private\n     */\n    GStylePalette.prototype._styleChange = function (evt) {\n        var styleIndex = this._getStyleIndex(evt.style, false);\n        if (styleIndex >= 0 && styleIndex === this._selectedStyleIndex) {\n            var style = this._styles[styleIndex][0];\n            this._styleSelector.gStylePanel('updateStyle', style);\n        }\n    };\n\n    /**\n     * @private\n     */\n    GStylePalette.prototype._updateFromSelection = function () {\n        this._styleElements = null;\n        this._styles = null;\n        this._selectedStyleIndex = -1;\n        var selection = this._document.getEditor().getSelection();\n\n        // Figure our available style elements\n        if (selection && selection.length > 0) {\n            for (var i = 0; i < selection.length; ++i) {\n                var element = selection[i];\n                if (element.hasMixin(IFElement.Style)) {\n                    if (!this._styleElements) {\n                        this._styleElements = [];\n                    }\n\n                    this._styleElements.push(element);\n                }\n            }\n        }\n\n        // Clear style selector\n        this._styleSelector.gStylePanel('clear');\n\n        if (this._styleElements) {\n            this._insertStyles();\n        }\n\n        // Reset style selection if there're no styles\n        if (!this._styles) {\n            this._setSelectedStyle(-1);\n        }\n    };\n\n    GStylePalette.prototype._setSelectedStyle = function (selectedIndex) {\n        this._styleSelector.gStylePanel('value', selectedIndex >= 0 ? this._styles[selectedIndex][0] : null);\n        this._selectedStyleIndex = selectedIndex;\n        this._updateSelectedStyle();\n    };\n\n    GStylePalette.prototype._modifyEachSelectedStyle = function (modifier, styleIndex) {\n        if (typeof styleIndex === 'number' || this._selectedStyleIndex >= 0) {\n            var editor = this._document.getEditor();\n            editor.beginTransaction();\n            try {\n                this._visitEachSelectedStyle(modifier, styleIndex);\n            } finally {\n                // TODO : I18N\n                editor.commitTransaction('Modify Style(s)');\n            }\n        }\n    };\n\n    GStylePalette.prototype._visitEachSelectedStyle = function (visitor, styleIndex) {\n        if (typeof styleIndex === 'number' || this._selectedStyleIndex >= 0) {\n            var style = this._styles[this._selectedStyleIndex >= 0 ? this._selectedStyleIndex : styleIndex].slice();\n            for (var i = 0; i < style.length; ++i) {\n                visitor(style[i]);\n            }\n        }\n    };\n\n    GStylePalette.prototype._insertStyles = function (style) {\n        var _addStyleBlock = function (style, index) {\n            this._styleSelector.gStylePanel('insertStyle', style, index);\n        }.bind(this);\n\n        var _addStyles = function (styles) {\n            var canAddStyles = false;\n\n            if (style) {\n                for (var i = 0; i < styles.length; ++i) {\n                    if (styles[i] === style) {\n                        canAddStyles = true;\n                        break;\n                    }\n                }\n            } else {\n                canAddStyles = true;\n            }\n\n            if (canAddStyles && this._styles && this._styles.length > 0) {\n                // Make sure the styles doesn't yet exist in our containers\n                for (var i = 0; i < this._styles.length; ++i) {\n                    if (this._styles[i][0] === styles[0]) {\n                        canAddStyles = false;\n                        break;\n                    }\n                }\n            }\n\n            if (canAddStyles) {\n                // Figure the right insertion point for the style\n                var style = styles[0];\n                var nextStyleIndex = -1;\n                for (var next = style.getNext(); next !== null; next = next.getNext()) {\n                    if (next instanceof IFStyle) {\n                        nextStyleIndex = this._getStyleIndex(next);\n                        break;\n                    }\n                }\n\n                if (!this._styles) {\n                    this._styles = [];\n                }\n\n                if (nextStyleIndex >= 0) {\n                    this._styles.splice(nextStyleIndex, 0, styles);\n                } else {\n                    this._styles.push(styles);\n                }\n\n                _addStyleBlock(styles[0], nextStyleIndex);\n            }\n        }.bind(this);\n\n        if (!this._styleElements || this._styleElements.length === 0) {\n            // NO-OP w/o stylable elements\n            return;\n        }\n\n        if (this._styleElements.length === 1) {\n            // Easy-peacy, add all styles from element\n            var styleSet = this._styleElements[0].getStyleSet();\n            for (var node = styleSet.getFirstChild(); node !== null; node = node.getNext()) {\n                if (node instanceof IFStyle) {\n                    _addStyles([node]);\n                }\n            }\n        } else {\n            // Iterate and add the first, non-linked style as default one\n            // as well as add all linked styles that are common to _all_ elements\n            var linkedStyles = [];\n            var defaultStyles = [];\n\n            for (var i = 0; i < this._styleElements.length; ++i) {\n                var styleSet = this._styleElements[i].getStyleSet();\n                var hasDefaultStyle = false;\n                for (var node = styleSet.getFirstChild(); node !== null; node = node.getNext()) {\n                    if (node instanceof IFLinkedStyle) {\n                        var hasLinkedStyle = false;\n                        for (var j = 0; j < linkedStyles.length; ++j) {\n                            if (linkedStyles[j][0].getProperty('ref') === node.getProperty('ref')) {\n                                linkedStyles[j].push(node);\n                                hasLinkedStyle = true;\n                                break;\n                            }\n                        }\n\n                        if (!hasLinkedStyle) {\n                            linkedStyles.push([node]);\n                        }\n                    }\n                    else if (node instanceof IFInlineStyle) {\n                        if (!hasDefaultStyle) {\n                            defaultStyles.push(node);\n                        }\n                        hasDefaultStyle = true;\n                    }\n                }\n            }\n\n            // Add default style if common to all elements\n            if (defaultStyles.length === this._styleElements.length) {\n                _addStyles(defaultStyles);\n            }\n\n            // Add all linked styles if they're common to all elements\n            for (var i = 0; i < linkedStyles.length; ++i) {\n                if (linkedStyles[i].length === this._styleElements.length) {\n                    _addStyles(linkedStyles[i]);\n                }\n            }\n        }\n\n        // Make default selection if there's none yet\n        if (this._selectedStyleIndex < 0 && this._styles && this._styles.length > 0) {\n            this._setSelectedStyle(0);\n        }\n    };\n\n    GStylePalette.prototype._removeStyle = function (style) {\n        if (this._styles) {\n            var styleIndex = this._getStyleIndex(style);\n\n            if (styleIndex >= 0) {\n                // Remove from style selector\n                this._styleSelector.gStylePanel('removeStyle', this._styles[styleIndex][0]);\n\n                // Remove from styles array\n                this._styles.splice(styleIndex, 1);\n\n                // Update selected style if active\n                if (styleIndex === this._selectedStyleIndex) {\n                    this._setSelectedStyle(this._styles.length > 0 ? 0 : -1);\n                } else if (styleIndex < this._selectedStyleIndex) {\n                    this._selectedStyleIndex -= 1;\n                }\n\n                // Update style selector when there's no styles\n                if (this._styles.length === 0) {\n                    this._styles = null;\n                    this._styleSelector.css('display', 'none');\n                }\n            }\n        }\n    };\n\n    GStylePalette.prototype._isSelectedStyle = function (style) {\n        return this._selectedStyleIndex >= 0 && this._getStyleIndex(style, true) === this._selectedStyleIndex;\n    };\n\n    GStylePalette.prototype._getStyleIndex = function (style, handleSharedStyles) {\n        if (!this._styles || this._styles.length === 0) {\n            return -1;\n        }\n\n        for (var i = 0; i < this._styles.length; ++i) {\n            for (var j = 0; j < this._styles[i].length; ++j) {\n                if (style instanceof IFSharedStyle && handleSharedStyles) {\n                    if (this._styles[i][j] instanceof IFLinkedStyle && this._styles[i][j].getProperty('ref') === style.getReferenceId()) {\n                        return i;\n                    }\n                } else {\n                    if (this._styles[i][j] === style) {\n                        return i;\n                    }\n                }\n            }\n        }\n\n        return -1;\n    };\n\n    GStylePalette.prototype._removeHiddenEntries = function (entryClasses) {\n        this._modifyEachSelectedStyle(function (style) {\n            var style = style.getActualStyle();\n            var removal = [];\n\n            for (var entry = style.getFirstChild(); entry !== null; entry = entry.getNext()) {\n                if (entry instanceof IFStyleEntry && entry.getProperty('vs') === false) {\n                    for (var j = 0; j < entryClasses.length; ++j) {\n                        if (entryClasses[j].prototype.isPrototypeOf(entry)) {\n                            removal.push(entry);\n                            break;\n                        }\n                    }\n                }\n            }\n\n            for (var i = 0; i < removal.length; ++i) {\n                style.removeChild(removal[i]);\n            }\n        });\n    };\n\n    GStylePalette.prototype._toggleStyleLink = function () {\n        var activeStyle = this._styles[this._selectedStyleIndex][0];\n        if (activeStyle instanceof IFLinkedStyle) {\n            // Unlink\n            var editor = this._document.getEditor();\n            var scene = this._document.getScene();\n            editor.beginTransaction();\n            try {\n                // Get the shared style reference\n                var sharedStyle = activeStyle.getActualStyle();\n\n                // Save selected style index\n                var selectedStyleIndex = this._selectedStyleIndex;\n\n                // Replace all active style nodes with a new inline style\n                this._visitEachSelectedStyle(function (style) {\n                    // Create new inline style\n                    var inlineStyle = new IFInlineStyle();\n\n                    // Transfer style\n                    inlineStyle.transferProperties(style, [IFAppliedStyle.GeometryProperties, IFAppliedStyle.VisualProperties]);\n                    for (var child = sharedStyle.getFirstChild(); child !== null; child = child.getNext()) {\n                        if (child instanceof IFStyleEntry) {\n                            inlineStyle.appendChild(child.clone());\n                        }\n                    }\n\n                    // Insert before actual style\n                    style.getParent().insertChild(inlineStyle, style);\n\n                    // Remove original style\n                    style.getParent().removeChild(style);\n                });\n\n                // Re-assign selected style\n                this._setSelectedStyle(selectedStyleIndex);\n            } finally {\n                // TODO : I18N\n                editor.commitTransaction('Unlink Style');\n            }\n        } else {\n            // Link\n            var scene = this._document.getScene();\n\n            // TODO : I18N\n            var styleDefaultName = 'Style-' + (scene.getStyleCollection().queryCount('> sharedStyle') + 1).toString();\n            var name = prompt('Enter a name for the new style:', styleDefaultName);\n            if (name !== null) {\n                if (name.trim() === '') {\n                    name = styleDefaultName;\n                }\n\n                var editor = this._document.getEditor();\n                editor.beginTransaction();\n                try {\n                    // Create our shared style\n                    var sharedStyle = new IFSharedStyle();\n                    sharedStyle.setProperty('name', name);\n\n                    // Transfer style\n                    for (var child = activeStyle.getFirstChild(); child !== null; child = child.getNext()) {\n                        if (child instanceof IFStyleEntry) {\n                            sharedStyle.appendChild(child.clone());\n                        }\n                    }\n\n                    // Add the shared style to our collection\n                    scene.getStyleCollection().appendChild(sharedStyle);\n\n                    // Save selected style index\n                    var selectedStyleIndex = this._selectedStyleIndex;\n\n                    // Replace all active style nodes with a new linked style\n                    this._visitEachSelectedStyle(function (style) {\n                        // Insert new linked style before\n                        var linkedStyle = new IFLinkedStyle();\n                        linkedStyle.transferProperties(style, [IFAppliedStyle.GeometryProperties, IFAppliedStyle.VisualProperties]);\n                        linkedStyle.setProperty('ref', sharedStyle.getReferenceId());\n                        style.getParent().insertChild(linkedStyle, style);\n\n                        // Remove original style\n                        style.getParent().removeChild(style);\n                    });\n\n                    // Re-assign selected style\n                    this._setSelectedStyle(selectedStyleIndex);\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Link Style');\n                }\n            }\n        }\n    };\n\n    GStylePalette.prototype._updateSelectedStyle = function () {\n        this._styleSelector.css('display', this._styles ? '' : 'none');\n        this._updateStyleSettings();\n        this._updateEntries();\n    };\n\n    GStylePalette.prototype._updateStyleSettings = function () {\n        this._styleSettings.css('display', 'none');\n        this._styleDeleteControl.prop('disabled', true);\n        this._styleAddControl.prop('disabled', this._styleElements === null || this._styleElements.length === 0);\n\n        if (this._selectedStyleIndex >= 0) {\n            this._styleSettings.css('display', '');\n            var style = this._styles[this._selectedStyleIndex][0];\n\n            this._styleSettings.find('.visibility > span')\n                .toggleClass('fa-eye', style.getProperty('vs') == true)\n                .toggleClass('fa-eye-slash', style.getProperty('vs') == false)\n\n            this._styleSettings.find('[data-property=\"__link\"]')\n                // TODO : I18N\n                .attr('title', style instanceof IFLinkedStyle ? 'Unlink style' : 'Link style')\n                /* !! */\n                .find('> span')\n                .toggleClass('fa-link', !(style instanceof IFLinkedStyle))\n                .toggleClass('fa-unlink', style instanceof IFLinkedStyle);\n\n            this._styleDeleteControl.prop('disabled', false);\n\n            this._styleSettings.find('[data-property=\"blm\"]').val(style.getProperty('blm'));\n            this._styleSettings.find('[data-property=\"opc\"]').val(ifUtil.formatNumber(style.getProperty('opc') * 100));\n\n            this._styleSettings.find('[data-property=\"tp\"]').val(style.getProperty('tp'));\n        }\n    };\n\n    GStylePalette.prototype._updateEntries = function () {\n        this._paintsPanel.closest('.g-panel').css('display', 'none');\n        this._paintsPanel.find('.style-entries-panel-table').empty();\n        this._filtersPanel.closest('.g-panel').css('display', 'none');\n        this._filtersPanel.find('.style-entries-panel-table').empty();\n        this._effectsPanel.closest('.g-panel').css('display', 'none');\n        this._effectsPanel.find('.style-entries-panel-table').empty();\n\n        if (this._selectedStyleIndex >= 0) {\n            this._paintsPanel.closest('.g-panel').css('display', '');\n            this._filtersPanel.closest('.g-panel').css('display', '');\n            this._effectsPanel.closest('.g-panel').css('display', '');\n            var style = this._styles[this._selectedStyleIndex][0].getActualStyle();\n\n            for (var entry = style.getFirstChild(); entry !== null; entry = entry.getNext()) {\n                if (entry instanceof IFStyleEntry) {\n                    this._insertEntryRow(entry);\n                }\n            }\n        }\n    };\n\n    var dragRow = null;\n    var hasDropped = false;\n\n    GStylePalette.prototype._insertEntryRow = function (entry) {\n        var handler = this._styleEntries[IFObject.getTypeId(entry)];\n\n        if (handler) {\n            var panel = this._getPanelFromEntry(entry);\n            var table = panel.find('.style-entries-panel-table');\n\n            var assign = function () {\n                this._assignEntryRow(entry);\n            }.bind(this);\n\n            var revert = function () {\n                this._updateEntryRow(entry);\n            }.bind(this);\n\n            var contents = handler.createContent(this._document.getScene(), assign, revert);\n\n            var _canDrop = function (source, target) {\n                return source && target && source !== target && source.parentNode === target.parentNode;\n            };\n\n            var row = $('<div></div>')\n                .data('entry', entry)\n                .attr('draggable', 'true')\n                .on('dragstart', function (evt) {\n                    var $this = $(this);\n\n                    var event = evt.originalEvent;\n                    event.stopPropagation();\n\n                    event.dataTransfer.effectAllowed = 'move';\n                    // dummy data as some browser may not drag otherwise\n                    event.dataTransfer.setData('text/plain', '');\n                    this.className = 'drag';\n                    dragRow = this;\n                    hasDropped = false;\n\n                    // Add drag overlays\n                    $this.closest('.style-entries-panel-table').find('> div').each(function (index, element) {\n                        $(element)\n                            .append($('<div></div>')\n                                .addClass('drag-overlay')\n                                .on('dragenter', function (evt) {\n                                    if (_canDrop(dragRow, this.parentNode)) {\n                                        $(this).parent().addClass('drop');\n                                    }\n                                })\n                                .on('dragleave', function (evt) {\n                                    if (_canDrop(dragRow, this.parentNode)) {\n                                        $(this).parent().removeClass('drop');\n                                    }\n                                })\n                                .on('dragover', function (evt) {\n                                    var event = evt.originalEvent;\n                                    // Let everything to through to escalate a drop\n                                    // event, we'll check later if possible or not\n                                    event.preventDefault();\n                                    event.stopPropagation();\n                                    event.dataTransfer.dropEffect = 'move';\n                                })\n                                .on('drop', function (evt) {\n                                    var $this = $(this);\n                                    var $parent = $(this.parentNode);\n\n                                    hasDropped = true;\n                                    $parent.removeClass('drop');\n\n                                    // Remove drag overlays\n                                    $parent.closest('.style-entries-panel-table').find('.drag-overlay').remove();\n\n                                    if (_canDrop(dragRow, this.parentNode)) {\n                                        // TODO : Move our entry\n                                    }\n                                }));\n                    });\n                })\n                .on('dragend', function (evt) {\n                    var $this = $(this);\n\n                    var event = evt.originalEvent;\n                    event.stopPropagation();\n\n                    // Remove drag overlays\n                    $this.closest('.style-entries-panel-table').find('.drag-overlay').remove();\n\n                    // Delete our entry when not dropped\n                    if (!hasDropped) {\n                        // TODO : Undo + Redo + Apply to all\n                        entry.getParent().removeChild(entry);\n                    }\n\n                    this.className = '';\n                    dragRow = null;\n                    hasDropped = false;\n                })\n                .append($('<div></div>')\n                    .addClass('visibility')\n                    .append($('<span></span>')\n                        // TODO : I18N\n                        .attr('title', 'Toggle visibility')\n                        .on('click', function () {\n                            // TODO : Undo + Redo + Apply to all\n                            entry.setProperty('vs', !entry.getProperty('vs'));\n                        })))\n                .append($('<div></div>')\n                    .addClass('contents')\n                    .append(contents))\n                .appendTo(table);\n\n            this._updateEntryRow(entry, row);\n        }\n    };\n\n    GStylePalette.prototype._removeEntryRow = function (entry, row) {\n        row = row || this._getRowForEntry(entry);\n\n        if (row) {\n            row.remove();\n        }\n    };\n\n    GStylePalette.prototype._updateEntryRow = function (entry, row) {\n        var handler = this._styleEntries[IFObject.getTypeId(entry)];\n\n        if (handler) {\n            row = row || this._getRowForEntry(entry);\n\n            if (row) {\n                row.find('.visibility span').attr('class', 'fa fa-eye' + (!entry.getProperty('vs') ? '-slash' : ''));\n                handler.updateProperties(row.find('.contents > :first-child'), row.data('entry'), this._document.getScene());\n            }\n        }\n    };\n\n    GStylePalette.prototype._assignEntryRow = function (entry, row) {\n        var handler = this._styleEntries[IFObject.getTypeId(entry)];\n\n        if (handler) {\n            row = row || this._getRowForEntry(entry);\n\n            if (row) {\n                var editor = this._document.getEditor();\n                editor.beginTransaction();\n                try {\n                    handler.assignProperties(row.find('.contents > :first-child'), entry, this._document.getScene());\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Modify ' + handler.getEntryName() + ' Style');\n                }\n            }\n        }\n    };\n\n    GStylePalette.prototype._getRowForEntry = function (entry) {\n        var panel = this._getPanelFromEntry(entry);\n        var table = panel.find('.style-entries-panel-table');\n\n        var result = null;\n        table.find('> div').each(function (index, element) {\n            var $element = $(element);\n            if ($element.data('entry') === entry) {\n                result = $element;\n                return false;\n            }\n        });\n\n        return result;\n    };\n\n    GStylePalette.prototype._getPanelFromEntry = function (entry) {\n        if (entry instanceof IFPaintEntry) {\n            return this._paintsPanel;\n        } else if (entry instanceof IFFilterEntry) {\n            return this._filtersPanel;\n        } else if (entry instanceof IFEffectEntry || entry instanceof IFVEffectEntry) {\n            return this._effectsPanel;\n        }\n    };\n\n    /** @override */\n    GStylePalette.prototype.toString = function () {\n        return \"[Object GStylePalette]\";\n    };\n\n    _.GStylePalette = GStylePalette;\n})(this);"
  },
  {
    "path": "src/gravit/panel/propertiespanel.js",
    "content": "(function (_) {\n\n    /**\n     * Properties Panel\n     * @class GPropertiesPanel\n     * @extends GPanel\n     * @constructor\n     */\n    function GPropertiesPanel() {\n        GPanel.call(this);\n        this._propertyPanels = [];\n    }\n\n    IFObject.inherit(GPropertiesPanel, GPanel);\n\n    GPropertiesPanel.ID = \"properties\";\n    GPropertiesPanel.TITLE = new IFLocale.Key(GPropertiesPanel, \"title\");\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPropertiesPanel.prototype._htmlElement = null;\n\n    /**\n     * The property panels\n     * @type {Array<{{panel: JQuery, properties: GProperties}}>}\n     * @private\n     */\n    GPropertiesPanel.prototype._propertyPanels = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GPropertiesPanel.prototype._document = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    GPropertiesPanel.prototype._elements = null;\n\n    /** @override */\n    GPropertiesPanel.prototype.getId = function () {\n        return GPropertiesPanel.ID;\n    };\n\n    /** @override */\n    GPropertiesPanel.prototype.getTitle = function () {\n        return GPropertiesPanel.TITLE;\n    };\n\n    /** @override */\n    GPropertiesPanel.prototype.init = function (htmlElement, controls) {\n        GPanel.prototype.init.call(this, htmlElement, controls);\n\n        this._htmlElement = htmlElement;\n\n        var propertiesPanels = $('<div></div>')\n            .addClass('properties-panels')\n            .appendTo(this._htmlElement);\n\n        var _addPropertiesPanel = function (properties) {\n            // Create panel\n            var panel = $('<div></div>')\n                .css('display', 'none')\n                .addClass('properties-panel-content');\n\n            // Init properties\n            properties.init(panel);\n\n            // Append panel\n            panel.appendTo(propertiesPanels);\n\n            this._propertyPanels.push({\n                panel: panel,\n                properties: properties\n            })\n        }.bind(this);\n\n        // Initialize our properties panels\n        for (var i = 0; i < gravit.properties.length; ++i) {\n            _addPropertiesPanel(gravit.properties[i]);\n        }\n    };\n\n    /** @override */\n    GPropertiesPanel.prototype._documentEvent = function (event) {\n        if (event.type === GApplication.DocumentEvent.Type.Activated) {\n            this._document = event.document;\n            var scene = this._document.getScene();\n            var editor = this._document.getEditor();\n\n            editor.addEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n            scene.addEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n\n            this._updateFromSelection();\n\n            this.trigger(GPanel.UPDATE_EVENT);\n        } else if (event.type === GApplication.DocumentEvent.Type.Deactivated) {\n            var scene = this._document.getScene();\n            var editor = this._document.getEditor();\n\n            // Unsubscribe from the editor's events\n            editor.removeEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n            scene.removeEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n\n            this._document = null;\n            this._elements = null;\n\n            this._updatePropertyPanels();\n\n            this.trigger(GPanel.UPDATE_EVENT);\n        }\n    };\n\n    /**\n     * @private\n     */\n    GPropertiesPanel.prototype._updateFromSelection = function () {\n        this._elements = this._document.getEditor().getSelection();\n\n        // If there's no selection, select the active page if any\n        if (!this._elements || this._elements.length === 0) {\n            var activePage = this._document.getScene().getActivePage();\n            if (activePage) {\n                this._elements = [activePage];\n            }\n        }\n\n        this._updatePropertyPanels();\n    };\n\n    /**\n     * @private\n     */\n    GPropertiesPanel.prototype._afterFlagChange = function (evt) {\n        // Special case - if element's consists of scene only and\n        // some element's activeness changes, trigger an update property\n        // panels as some panel do some special handling for this case\n        if (evt.flag === IFNode.Flag.Active && this._elements && this._elements.length === 1 && this._elements[0] instanceof IFScene) {\n            this._updatePropertyPanels();\n        }\n    };\n\n    /** @private */\n    GPropertiesPanel.prototype._updatePropertyPanels = function () {\n        for (var i = 0; i < this._propertyPanels.length; ++i) {\n            var propertyPanel = this._propertyPanels[i];\n            var available = !this._elements || this._elements.length === 0 ?\n                false : propertyPanel.properties.update(this._document, this._elements);\n\n            if (available) {\n                propertyPanel.panel.css('display', '');\n            } else {\n                propertyPanel.panel.css('display', 'none');\n            }\n        }\n    };\n\n    /** @override */\n    GPropertiesPanel.prototype.toString = function () {\n        return \"[Object GPropertiesPanel]\";\n    };\n\n    _.GPropertiesPanel = GPropertiesPanel;\n})(this);"
  },
  {
    "path": "src/gravit/panel/transformpanel.js",
    "content": "(function (_) {\n\n    /**\n     * Transform Panel\n     * @class GTransformPanel\n     * @extends GPanel\n     * @constructor\n     */\n    function GTransformPanel() {\n        GPanel.call(this);\n        this._transformPanels = [];\n    }\n\n    IFObject.inherit(GTransformPanel, GPanel);\n\n    GTransformPanel.ID = \"transform\";\n    GTransformPanel.TITLE = new IFLocale.Key(GTransformPanel, \"title\");\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GTransformPanel.prototype._htmlElement = null;\n\n    /**\n     * The transformer panels\n     * @type {Array<{{panel: JQuery, transformer: GTransformer}}>}\n     * @private\n     */\n    GTransformPanel.prototype._transformPanels = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GTransformPanel.prototype._document = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    GTransformPanel.prototype._elements = null;\n\n    /** @override */\n    GTransformPanel.prototype.getId = function () {\n        return GTransformPanel.ID;\n    };\n\n    /** @override */\n    GTransformPanel.prototype.getTitle = function () {\n        return GTransformPanel.TITLE;\n    };\n\n    /** @override */\n    GTransformPanel.prototype.init = function (htmlElement, controls) {\n        GPanel.prototype.init.call(this, htmlElement, controls);\n\n        this._htmlElement = htmlElement;\n\n        var transformPanels = $('<div></div>')\n            .addClass('transform-panels')\n            .appendTo(this._htmlElement);\n\n        var _addTransformPanel = function (transformer) {\n            // Create panel\n            var panel = $('<div></div>')\n                .css('display', 'none')\n                .addClass('transform-panel-content');\n\n            // Init transformer\n            transformer.init(panel);\n\n            // Append panel\n            panel.appendTo(transformPanels);\n\n            this._transformPanels.push({\n                panel: panel,\n                transformer: transformer\n            })\n        }.bind(this);\n\n        // Initialize our transform panels\n        for (var i = 0; i < gravit.transformers.length; ++i) {\n            _addTransformPanel(gravit.transformers[i]);\n        }\n    };\n\n    /** @override */\n    GTransformPanel.prototype._documentEvent = function (event) {\n        if (event.type === GApplication.DocumentEvent.Type.Activated) {\n            this._document = event.document;\n            var editor = this._document.getEditor();\n\n            editor.addEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n\n            this._updateFromSelection();\n\n            this.trigger(GPalette.UPDATE_EVENT);\n        } else if (event.type === GApplication.DocumentEvent.Type.Deactivated) {\n            var editor = this._document.getEditor();\n\n            // Unsubscribe from the editor's events\n            editor.removeEventListener(IFEditor.SelectionChangedEvent, this._updateFromSelection, this);\n\n            this._document = null;\n            this._elements = null;\n\n            this._updateTransformPanels();\n\n            this.trigger(GPalette.UPDATE_EVENT);\n        }\n    };\n\n    /**\n     * @private\n     */\n    GTransformPanel.prototype._updateFromSelection = function () {\n        this._elements = null;\n\n        var selection = this._document.getEditor().getSelection();\n\n        // Filter elements by transformables\n        if (selection) {\n            for (var i = 0; i < selection.length; ++i) {\n                if (selection[i].hasMixin(IFElement.Transform)) {\n                    if (!this._elements) {\n                        this._elements = [];\n                    }\n                    this._elements.push(selection[i]);\n                }\n            }\n        }\n\n        this._updateTransformPanels();\n    };\n\n    /** @private */\n    GTransformPanel.prototype._updateTransformPanels = function () {\n        for (var i = 0; i < this._transformPanels.length; ++i) {\n            var transformPanel = this._transformPanels[i];\n            var available = !this._elements || this._elements.length === 0 ?\n                false : transformPanel.transformer.update(this._document, this._elements);\n\n            if (available) {\n                transformPanel.panel.css('display', '');\n            } else {\n                transformPanel.panel.css('display', 'none');\n            }\n        }\n    };\n\n    /** @override */\n    GTransformPanel.prototype.toString = function () {\n        return \"[Object GTransformPanel]\";\n    };\n\n    _.GTransformPanel = GTransformPanel;\n})(this);"
  },
  {
    "path": "src/gravit/properties/documentproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Document properties panel\n     * @class GDocumentProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GDocumentProperties() {\n    };\n    IFObject.inherit(GDocumentProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GDocumentProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GDocumentProperties.prototype._document = null;\n\n    /** @override */\n    GDocumentProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Document';\n    };\n\n    /** @override */\n    GDocumentProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        $('<button></button>')\n            // TODO : I18N\n            .attr('title', 'More Settings')\n            .on('click', function (evt) {\n                var $target = $(evt.target).closest('button');\n                $target.toggleClass('g-active', !$target.hasClass('g-active'));\n                this._showMore($target.hasClass('g-active'));\n            }.bind(this))\n            .append($('<span></span>')\n                .addClass('fa fa-cog'))\n            .appendTo(controls);\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property === 'unit') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    //.css('width', '100%')\n                    .gUnit()\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else if (property === 'unitSnap') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    .append($('<option></option>')\n                        .attr('value', IFScene.UnitSnap.None)\n                        // TODO : I18N\n                        .text('None'))\n                    .append($('<option></option>')\n                        .attr('value', IFScene.UnitSnap.Full)\n                        // TODO : I18N\n                        .text('Full'))\n                    .append($('<option></option>')\n                        .attr('value', IFScene.UnitSnap.Half)\n                        // TODO : I18N\n                        .text('Half'))\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else if (property === 'gridSizeX' || property === 'gridSizeY') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .css('width', '3em')\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 1) {\n                            self._assignProperty(property, value < 0 ? 0 : value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'gridActive') {\n                return $('<div></div>')\n                    .css('width', '4em')\n                    .addClass('g-switch')\n                    .append($('<label></label>')\n                        .append($('<input>')\n                            .attr('type', 'checkbox')\n                            .attr('data-property', property)\n                            .on('change', function () {\n                                self._assignProperty(property, $(this).is(':checked'));\n                            }))\n                        .append($('<span></span>')\n                            .addClass('switch')\n                            .attr({\n                                // TODO : I18N\n                                'data-on': 'On',\n                                'data-off': 'Off'\n                            })));\n            } else if (property === 'crDistSmall' || property === 'crDistBig') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .css('width', '3em')\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 1) {\n                            self._assignProperty(property, value < 0 ? 0 : value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'crConstraint') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .css('width', '3em')\n                    .on('change', function () {\n                        var angle = IFLength.parseEquationValue($(this).val());\n                        if (angle !== null) {\n                            angle = ifMath.normalizeAngleRadians(ifMath.toRadians(angle));\n                            self._assignProperty(property, angle);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'snapDist' || property === 'pickDist') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .css('width', '3em')\n                    .on('change', function () {\n                        var value = parseInt($(this).val());\n                        if (!isNaN(value)) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'clspace') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    .append($('<option></option>')\n                        .attr('value', IFColorSpace.RGB)\n                        .text('RGB'))\n                    .append($('<option></option>')\n                        .attr('value', IFColorSpace.CMYK)\n                        .text('CMYK'))\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else if (property === 'pathImage' || property === 'pathFont' || property === 'pathExport') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .css('width', '100%')\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        $('<table></table>')\n            .addClass('g-form')\n            .css('margin', '0px auto')\n            .append($('<tr></tr>')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Unit/Snap:'))\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append(_createInput('unit'))\n                    .append(_createInput('unitSnap'))))\n            .append($('<tr></tr>')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Grid:'))\n                .append($('<td></td>')\n                    .append(_createInput('gridSizeX')\n                        // TODO : I18N\n                        .attr('title', 'Horizontal Grid-Size'))\n                    .append(_createInput('gridSizeY')\n                        // TODO : I18N\n                        .attr('title', 'Vertical Grid-Size')))\n                .append($('<td></td>')\n                    .attr('colspan', '2')\n                    .css('text-align', 'right')\n                    .append(_createInput('gridActive'))))\n            .append($('<tr></tr>')\n                .append($('<td></td>')\n                    .attr('colspan', 4)\n                    .append($('<h1></h1>')\n                        .addClass('g-divider')\n                        // TODO : I18N\n                        .text('Defaults'))))\n            .append($('<tr></tr>')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Cursor:'))\n                .append($('<td></td>')\n                    .append(_createInput('crDistSmall')\n                        // TODO : I18N\n                        .attr('title', 'Small Distance when moving via Arrow-Keys'))\n                    .append(_createInput('crDistBig')\n                        // TODO : I18N\n                        .attr('title', 'Large Distance when moving via Arrow-Keys')))\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('°'))\n                .append($('<td></td>')\n                    .append(_createInput('crConstraint')\n                        // TODO : I18N\n                        .attr('title', 'Constraints when moving via Shift in Degrees'))))\n            .append($('<tr></tr>')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .html('<span class=\"fa fa-arrows\"></span> / <span class=\"fa fa-magnet\"></span>'))\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append(_createInput('pickDist')\n                        // TODO : I18N\n                        .attr('title', 'Pick Distance in Pixels'))\n                    .append(_createInput('snapDist')\n                        // TODO : I18N\n                        .attr('title', 'Snap Distance'))))\n            .append($('<tr></tr>')\n                .attr('data-more', 'yes')\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append($('<h1></h1>')\n                        .addClass('g-divider')\n                        // TODO : I18N\n                        .text('Color'))))\n            .append($('<tr></tr>')\n                .attr('data-more', 'yes')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Color:'))\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append(_createInput('clspace')\n                        // TODO : I18N\n                        .attr('title', 'Default Colorspace of document'))))\n            .append($('<tr></tr>')\n                .attr('data-more', 'yes')\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append($('<h1></h1>')\n                        .addClass('g-divider')\n                        // TODO : I18N\n                        .text('Pathes'))))\n            .append($('<tr></tr>')\n                .attr('data-more', 'yes')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Images'))\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append(_createInput('pathImage')\n                        // TODO : I18N\n                        .attr('title', 'Path for imported image assets'))))\n            .append($('<tr></tr>')\n                .attr('data-more', 'yes')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Fonts'))\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append(_createInput('pathFont')\n                        // TODO : I18N\n                        .attr('title', 'Path for imported font assets'))))\n            .append($('<tr></tr>')\n                .attr('data-more', 'yes')\n                .append($('<td></td>')\n                    .addClass('label')\n                    // TODO : I18N\n                    .text('Export'))\n                .append($('<td></td>')\n                    .attr('colspan', '3')\n                    .append(_createInput('pathExport')\n                        // TODO : I18N\n                        .attr('title', 'Path for exported assets'))))\n            .appendTo(panel);\n\n        this._showMore(false);\n    };\n\n    /** @override */\n    GDocumentProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange);\n            this._document = null;\n        }\n\n        if (elements.length === 1 && elements[0] instanceof IFScene) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GDocumentProperties.prototype._afterPropertiesChange = function (event) {\n        if (event.node === this._document.getScene()) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @private\n     */\n    GDocumentProperties.prototype._updateProperties = function () {\n        var scene = this._document.getScene();\n        this._panel.find('select[data-property=\"unit\"]').val(scene.getProperty('unit'));\n        this._panel.find('select[data-property=\"unitSnap\"]').val(scene.getProperty('unitSnap'));\n        this._panel.find('input[data-property=\"gridSizeX\"]').val(scene.pointToString(scene.getProperty('gridSizeX')));\n        this._panel.find('input[data-property=\"gridSizeY\"]').val(scene.pointToString(scene.getProperty('gridSizeY')));\n        this._panel.find('input[data-property=\"gridActive\"]').prop('checked', scene.getProperty('gridActive'));\n        this._panel.find('input[data-property=\"crDistSmall\"]').val(scene.pointToString(scene.getProperty('crDistSmall')));\n        this._panel.find('input[data-property=\"crDistBig\"]').val(scene.pointToString(scene.getProperty('crDistBig')));\n        this._panel.find('input[data-property=\"crConstraint\"]').val(\n            ifUtil.formatNumber(ifMath.toDegrees(scene.getProperty('crConstraint')), 2));\n        this._panel.find('input[data-property=\"snapDist\"]').val(scene.pointToString(scene.getProperty('snapDist')));\n        this._panel.find('input[data-property=\"pickDist\"]').val(scene.pointToString(scene.getProperty('pickDist')));\n        this._panel.find('select[data-property=\"clspace\"]').val(scene.getProperty('clspace'));\n        this._panel.find('input[data-property=\"pathImage\"]').val(scene.getProperty('pathImage'));\n        this._panel.find('input[data-property=\"pathFont\"]').val(scene.getProperty('pathFont'));\n        this._panel.find('input[data-property=\"pathExport\"]').val(scene.getProperty('pathExport'));\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GDocumentProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GDocumentProperties.prototype._assignProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            this._document.getScene().setProperties(properties, values);\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Document Properties');\n        }\n    };\n\n    /** @private */\n    GDocumentProperties.prototype._showMore = function (more) {\n        this._panel.find('[data-more]').each(function (index, element) {\n            $(element).css('display', more ? '' : 'none');\n        });\n    };\n\n    /** @override */\n    GDocumentProperties.prototype.toString = function () {\n        return \"[Object GDocumentProperties]\";\n    };\n\n    _.GDocumentProperties = GDocumentProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/ellipseproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Ellipse properties panel\n     * @class GEllipseProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GEllipseProperties() {\n        this._ellipses = [];\n    };\n    IFObject.inherit(GEllipseProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GEllipseProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GEllipseProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFEllipse>}\n     * @private\n     */\n    GEllipseProperties.prototype._ellipses = null;\n\n    /** @override */\n    GEllipseProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Ellipse';\n    };\n\n    /** @override */\n    GEllipseProperties.prototype.init = function (panel) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property === 'etp') {\n                return $('<select></select>')\n                    .attr('data-property', 'etp')\n                    .append($('<option></option>')\n                        .attr('value', IFEllipse.Type.Arc)\n                        // TODO : I18N\n                        .text('Arc'))\n                    .append($('<option></option>')\n                        .attr('value', IFEllipse.Type.Chord)\n                        // TODO : I18N\n                        .text('Chord'))\n                    .append($('<option></option>')\n                        .attr('value', IFEllipse.Type.Pie)\n                        // TODO : I18N\n                        .text('Pie'))\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else if (property === 'sa' || property === 'ea') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var angle = IFLength.parseEquationValue($(this).val());\n                        if (angle !== null) {\n                            angle = ifMath.normalizeAngleRadians(ifMath.toRadians(angle));\n                            self._assignProperty(property, ifMath.PI2 - angle);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '127px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append(_createInput('etp')\n                    .css('width', '114px')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .html('<span class=\"fa fa-stop\" style=\"font-size:11px;transform:rotate(45deg)\"></span>')\n                .append(_createInput('sa')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '66px'\n                })\n                .html('<span class=\"fa fa-circle\"></span>')\n                .append(_createInput('ea')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })));\n    };\n\n    /** @override */\n    GEllipseProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange);\n            this._document = null;\n        }\n\n        // Collect all ellipse elements\n        this._ellipses = [];\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFEllipse) {\n                this._ellipses.push(elements[i]);\n            }\n        }\n\n        if (this._ellipses.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GEllipseProperties.prototype._afterPropertiesChange = function (event) {\n        // If properties of first ellipse has changed then update ourself\n        if (this._ellipses.length > 0 && this._ellipses[0] === event.node) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @param {Boolean} [noBBoxCalculation] if set, do not recalculate all element's bbox.\n     * Defaults to false.\n     * @private\n     */\n    GEllipseProperties.prototype._updateProperties = function () {\n        // We'll always read properties of first ellipse\n        var ellipse = this._ellipses[0];\n        this._panel.find('select[data-property=\"etp\"]').val(ellipse.getProperty('etp'));\n        this._panel.find('input[data-property=\"sa\"]').val(\n            ifUtil.formatNumber(ifMath.toDegrees(ifMath.PI2 - ellipse.getProperty('sa')), 2));\n        this._panel.find('input[data-property=\"ea\"]').val(\n            ifUtil.formatNumber(ifMath.toDegrees(ifMath.PI2 - ellipse.getProperty('ea')), 2));\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GEllipseProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GEllipseProperties.prototype._assignProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._ellipses.length; ++i) {\n                this._ellipses[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Ellipse Properties');\n        }\n    };\n\n    /** @override */\n    GEllipseProperties.prototype.toString = function () {\n        return \"[Object GEllipseProperties]\";\n    };\n\n    _.GEllipseProperties = GEllipseProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/imageproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Image properties panel\n     * @class GImageProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GImageProperties() {\n    };\n    IFObject.inherit(GImageProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GImageProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GImageProperties.prototype._document = null;\n\n    /**\n     * @type {IFImage}\n     * @private\n     */\n    GImageProperties.prototype._image = null;\n\n    /** @override */\n    GImageProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Image';\n    };\n\n    /** @override */\n    GImageProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        panel\n            .css('width', '210px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append($('<span></span>')\n                    .addClass('fa fa-image'))\n                .append($('<span></span>')\n                    .css({\n                        'text-overflow': 'ellipsis',\n                        'padding-left': '5px'\n                    })\n                    .attr('data-property', 'url')))\n            .append($('<div></div>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .append($('<button></button>')\n                    .attr('data-action', 'embed')\n                    // TODO : I18N\n                    .text('Embed')\n                    .on('click', function () {\n                        image2Base64(this._image.getImage(), function (data) {\n                            // TODO : I18N\n                            IFEditor.tryRunTransaction(this._image, function () {\n                                this._image.setProperty('url', data);\n                            }.bind(this), 'Embed Image');\n                        }.bind(this));\n                    }.bind(this)))\n                .append($('<button></button>')\n                    .attr('data-action', 'replace')\n                    // TODO : I18N\n                    .text('Replace')\n                    .on('click', function () {\n                        var topLeft = this._image.getGeometryBBox().getSide(IFRect.Side.TOP_LEFT);\n                        this._document.getStorage().openResourcePrompt(this._document.getUrl(), ['jpg', 'jpeg', 'png', 'gif'], function (url) {\n                            // TODO : I18N\n                            IFEditor.tryRunTransaction(this._image, function () {\n                                // make url relative to document & reset size\n                                this._image.setProperties(['url', 'trf'], [new URI(url).relativeTo(this._document.getUrl()).toString(), new IFTransform(1, 0, 0, 1, topLeft.getX(), topLeft.getY())]);\n                            }.bind(this), 'Replace Image');\n                        }.bind(this));\n                    }.bind(this)))\n                .append($('<button></button>')\n                    .attr('data-action', 'export')\n                    // TODO : I18N\n                    .text('Export')\n                    .on('click', function () {\n                        var storage = gApp.getMatchingStorage(true, true, 'png', false, this._document.getStorage());\n                        if (storage) {\n                            storage.saveResourcePrompt(this._document.getUrl(), this._image.getLabel(), ['png'], function (url) {\n                                image2ArrayBuffer(this._image.getImage(), function (buffer) {\n                                    storage.save(url, buffer, true);\n                                });\n                            }.bind(this));\n                        }\n                    }.bind(this)))\n                .append($('<button></button>')\n                    .attr('data-action', 'reset-size')\n                    // TODO : I18N\n                    .text('Reset Size')\n                    .on('click', function () {\n                        var topLeft = this._image.getGeometryBBox().getSide(IFRect.Side.TOP_LEFT);\n                        // TODO : I18N\n                        IFEditor.tryRunTransaction(this._image, function () {\n                            this._image.setProperty('trf', new IFTransform(1, 0, 0, 1, topLeft.getX(), topLeft.getY()));\n                        }.bind(this), 'Reset Size');\n                    }.bind(this))));\n    };\n\n    /** @override */\n    GImageProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document.getScene().removeEventListener(IFImage.StatusEvent, this._imageStatus, this);\n            this._document = null;\n        }\n\n        this._image = null;\n\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFImage) {\n                if (this._image) {\n                    // We'll work on a single image, only\n                    this._image = null;\n                    break;\n                } else {\n                    this._image = elements[i];\n                }\n            }\n        }\n\n        if (this._image) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document.getScene().addEventListener(IFImage.StatusEvent, this._imageStatus, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GImageProperties.prototype._afterPropertiesChange = function (event) {\n        if (this._image && this._image === event.node) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @param {IFImage.StatusEvent} event\n     * @private\n     */\n    GImageProperties.prototype._imageStatus = function (event) {\n        if (event.image === this._image && (event.status === IFImage.ImageStatus.Error || event.status === IFImage.ImageStatus.Loaded)) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @param {Boolean} [noBBoxCalculation] if set, do not recalculate all element's bbox.\n     * Defaults to false.\n     * @private\n     */\n    GImageProperties.prototype._updateProperties = function () {\n        var url = this._image.getProperty('url');\n        var isData = url.indexOf('data:') === 0;\n        var status = this._image.getStatus();\n        var image = this._image.getImage();\n        var hasImage = image && status === IFImage.ImageStatus.Loaded;\n        var imgBBox = this._image.getGeometryBBox();\n\n        // TODO : I18N\n        this._panel.find('[data-property=\"url\"]').text(isData ? '<Embedded Image>' : decodeURIComponent(url));\n        this._panel.find('button[data-action=\"embed\"]').prop('disabled', !hasImage || isData);\n        this._panel.find('button[data-action=\"replace\"]').prop('disabled', !this._document.isSaveable());\n        this._panel.find('button[data-action=\"export\"]').prop('disabled', !hasImage || !this._document.isSaveable());\n        this._panel.find('button[data-action=\"reset-size\"]').prop('disabled', !hasImage || (image.naturalWidth === imgBBox.getWidth() && image.naturalHeight === imgBBox.getHeight()));\n    };\n\n    /** @override */\n    GImageProperties.prototype.toString = function () {\n        return \"[Object GImageProperties]\";\n    };\n\n    _.GImageProperties = GImageProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/infoproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Info properties panel\n     * @class GInfoProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GInfoProperties() {\n        this._elements = [];\n    };\n    IFObject.inherit(GInfoProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GInfoProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GInfoProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    GInfoProperties.prototype._elements = null;\n\n    /**\n     * @type {IFRect}\n     * @private\n     */\n    GInfoProperties.prototype._elementsBBox = null;\n\n    /**\n     * @type {IFRect}\n     * @private\n     */\n    GInfoProperties.prototype._firstElementsBBox = null;\n\n    /** @override */\n    GInfoProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Dimensions';\n    };\n\n    /** @override */\n    GInfoProperties.prototype.init = function (panel) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n\n            if (property === 'name') {\n                return $('<input>')\n                    .css('width', '100%')\n                    .attr('data-name', '')\n                    .on('change', function (evt) {\n                        IFEditor.tryRunTransaction(self._elements[0], function () {\n                            self._elements[0].setProperty('name', $(evt.target).val());\n                        }, 'Rename Element');\n                    });\n            }\n            else if (property === 'x' || property === 'y' || property === 'w' || property === 'h') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-dimension', property)\n                    .on('change', function (evt) {\n                        self._assignDimension(property, $(this).val());\n                    });\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '136px')\n            .append($('<div></div>')\n                .addClass('g-input')\n                .css({\n                    'position': 'absolute',\n                    'left': '5px',\n                    'top': '9px',\n                    'width': '41px',\n                    'height': '41px'\n                }))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '51px',\n                    'top': '5px',\n                    'width': '77px',\n                    'text-transform': 'uppercase'\n                })\n                .attr('data-type', ''))\n            .append(_createInput('name')\n                .css({\n                    'position': 'absolute',\n                    'left': '51px',\n                    'top': '30px',\n                    'width': '77px'\n                }))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<button></button>')\n                .css({\n\n                    'position': 'absolute',\n                    'left': '5px',\n                    'top': '77px',\n                    'padding': '0px',\n                    'font-size': '10px'\n                })\n                .on('click', function (evt) {\n                    var $me = $(this);\n                    $me.toggleClass('g-active', !$me.hasClass('g-active'));\n                })\n                .addClass('g-flat fa fa-lock')\n                // TODO : I18N\n                .attr('title', 'Keep Ratio')\n                .attr('data-ratio', ''))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '15px',\n                    'top': '65px'\n                })\n                .text('W:')\n                .append(_createInput('w')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '15px',\n                    'top': '89px'\n                })\n                .text('H:')\n                .append(_createInput('h')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '75px',\n                    'top': '65px'\n                })\n                .text('X:')\n                .append(_createInput('x')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '41px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '75px',\n                    'top': '89px'\n                })\n                .text('Y:')\n                .append(_createInput('y')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '41px'\n                    })));\n    };\n\n    /** @override */\n    GInfoProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFElement.GeometryChangeEvent, this._geometryChange, this);\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document = null;\n        }\n\n        // Collect all transformable elements\n        this._elements = elements.slice();\n\n        if (this._elements.length > 0) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFElement.GeometryChangeEvent, this._geometryChange, this);\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._updateProperties();\n            this._updateDimensions();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFElement.GeometryChangeEvent} event\n     * @private\n     */\n    GInfoProperties.prototype._geometryChange = function (event) {\n        if ((event.type === IFElement.GeometryChangeEvent.Type.After) ||\n            (event.type === IFElement.GeometryChangeEvent.Type.Child))\n            if (this._elements.indexOf(event.element) >= 0) {\n                this._updateDimensions();\n            }\n    };\n\n    /**\n     * @param {IFElement.GeometryChangeEvent} event\n     * @private\n     */\n    GInfoProperties.prototype._afterPropertiesChange = function (event) {\n        if (this._elements && this._elements.length === 1 && this._elements[0] === event.node && event.properties.indexOf('name') >= 0) {\n            this._updateProperties();\n        }\n    };\n\n    /** @private */\n    GInfoProperties.prototype._updateProperties = function () {\n        this._panel.find('input[data-apply]').css('display', this._elements.length <= 1 ? 'none' : '');\n\n        this._panel.find('label[data-type]')\n            .text(this._elements.length === 1 ? this._elements[0].getNodeNameTranslated() : (this._elements.length.toString() + ' Elements'))\n\n        this._panel.find('input[data-name]')\n            .css('visibility', this._elements.length === 1 && this._elements[0] instanceof IFBlock ? 'visible' : 'hidden')\n            .val(this._elements.length === 1 && this._elements[0] instanceof IFBlock ? this._elements[0].getLabel() : '');\n    };\n\n    /**\n     * @param {Boolean} [noBBoxCalculation] if set, do not recalculate all element's bbox.\n     * Defaults to false.\n     * @private\n     */\n    GInfoProperties.prototype._updateDimensions = function (noBBoxCalculation) {\n        var _updateDimension = function (dimension, value) {\n            this._panel.find('input[data-dimension=\"' + dimension + '\"]')\n                .val(value !== null ? this._document.getScene().pointToString(value) : '')\n            /** !! */\n                .parents('label')\n                .css('display', value === null ? 'none' : '');\n        }.bind(this);\n\n        if (!noBBoxCalculation) {\n            this._elementsBBox = null;\n            this._firstElementsBBox = null;\n            for (var i = 0; i < this._elements.length; ++i) {\n                if (this._elements[i].hasMixin(IFElement.Transform)) {\n                    var bbox = this._elements[i].getGeometryBBox();\n                    if (bbox && !bbox.isEmpty()) {\n                        this._elementsBBox = this._elementsBBox ? this._elementsBBox.united(bbox) : bbox;\n\n                        if (!this._firstElementsBBox) {\n                            this._firstElementsBBox = bbox;\n                        }\n                    }\n                }\n            }\n\n            if (!this._elementsBBox) {\n                this._elementsBBox = null;\n                this._firstElementsBBox = this._elementsBBox;\n            }\n        }\n\n        if (!this._firstElementsBBox) {\n            this._panel.find('button[data-ratio]').css('display', 'none');\n            _updateDimension('x', null);\n            _updateDimension('y', null);\n            _updateDimension('w', null);\n            _updateDimension('h', null);\n        } else {\n            var applyToSelection = true;// TODO : this._elements.length > 1 && this._panel.find('input[data-apply]').is(':checked');\n            var delta = this._getDelta();\n\n            this._panel.find('button[data-ratio]').css('display', '');\n            if (applyToSelection) {\n                _updateDimension('x', this._elementsBBox.getX() - delta.getX());\n                _updateDimension('y', this._elementsBBox.getY() - delta.getY());\n                _updateDimension('w', this._elementsBBox.getWidth());\n                _updateDimension('h', this._elementsBBox.getHeight());\n            } else {\n                _updateDimension('x', this._firstElementsBBox.getX() - delta.getX());\n                _updateDimension('y', this._firstElementsBBox.getY() - delta.getY());\n                _updateDimension('w', this._firstElementsBBox.getWidth());\n                _updateDimension('h', this._firstElementsBBox.getHeight());\n            }\n        }\n    };\n\n    /**\n     * @private\n     */\n    GInfoProperties.prototype._assignDimension = function (dimension, valueString) {\n        var value = this._document.getScene().stringToPoint(valueString);\n\n        // Check for invalid value and if it is invalid, reset dimension values and return here\n        if (value === null || typeof value !== 'number' || ((dimension === 'w' || dimension == 'h') && value <= 0)) {\n            this._updateDimensions();\n            return;\n        }\n\n        // Correct x,y for delta if any\n        if (dimension === 'x' || dimension === 'y') {\n            var delta = this._getDelta();\n            switch (dimension) {\n                case 'x':\n                    value += delta.getX();\n                    break;\n                case 'y':\n                    value += delta.getY();\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        var _getTransformation = function (bbox, keepRatio) {\n            if (dimension === 'w' || dimension === 'h') {\n                var sx = 1;\n                var sy = 1;\n\n                switch (dimension) {\n                    case 'w':\n                        sx = value / bbox.getWidth();\n                        if (keepRatio) {\n                            sy = sx;\n                        }\n                        break;\n                    case 'h':\n                        sy = value / bbox.getHeight();\n                        if (keepRatio) {\n                            sx = sy;\n                        }\n                        break;\n                    default:\n                        break;\n                }\n                return new IFTransform()\n                    .translated(-bbox.getX(), -bbox.getY())\n                    .scaled(sx, sy)\n                    .translated(bbox.getX(), bbox.getY());\n            } else {\n                switch (dimension) {\n                    case 'x':\n                        return new IFTransform()\n                            .translated(value - bbox.getX(), 0);\n                    case 'y':\n                        return new IFTransform()\n                            .translated(0, value - bbox.getY());\n                    default:\n                        break;\n                }\n            }\n        };\n\n        var applyToSelection = true; // TODO : this._elements.length > 1 && this._panel.find('input[data-apply]').is(':checked');\n        var keepRatio = this._panel.find('button[data-ratio]').hasClass('g-active');\n\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            if (applyToSelection) {\n                var transform = _getTransformation(this._elementsBBox, keepRatio);\n                for (var i = 0; i < this._elements.length; ++i) {\n                    this._elements[i].transform(transform);\n                }\n            } else {\n                for (var i = 0; i < this._elements.length; ++i) {\n                    var transform = _getTransformation(this._elements[i].getGeometryBBox(), keepRatio);\n                    this._elements[i].transform(transform);\n                }\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Change Size');\n        }\n    };\n\n    /**\n     * @returns {IFPoint}\n     * @private\n     */\n    GInfoProperties.prototype._getDelta = function () {\n        var scene = this._document.getScene();\n        if (scene.getProperty('singlePage') === true) {\n            var activePage = scene.getActivePage();\n            if (activePage) {\n                return activePage.getGeometryBBox().getSide(IFRect.Side.TOP_LEFT);\n            }\n        }\n\n        return new IFPoint(0, 0);\n    }\n\n    /** @override */\n    GInfoProperties.prototype.toString = function () {\n        return \"[Object GInfoProperties]\";\n    };\n\n    _.GInfoProperties = GInfoProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/pageproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Page properties panel\n     * @class GPageProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GPageProperties() {\n        this._pages = [];\n    };\n    IFObject.inherit(GPageProperties, GProperties);\n\n    GPageProperties.SIZE_PRESETS = [\n        {\n            // TODO : I18N\n            name: 'Paper',\n            sizes: [\n                {\n                    name: 'A0',\n                    width: '841mm',\n                    height: '1189mm'\n                },\n                {\n                    name: 'A1',\n                    width: '594mm',\n                    height: '841mm'\n                },\n                {\n                    name: 'A2',\n                    width: '420mm',\n                    height: '594mm'\n                },\n                {\n                    name: 'A3',\n                    width: '297mm',\n                    height: '420mm'\n                },\n                {\n                    name: 'A4',\n                    width: '210mm',\n                    height: '297mm'\n                },\n                {\n                    name: 'A5',\n                    width: '148,5mm',\n                    height: '210mm'\n                }\n            ]\n        },\n        {\n            // TODO : I18N\n            name: 'Phone',\n            sizes: [\n                {\n                    name: 'Apple iPhone 4 (S)',\n                    width: '640px',\n                    height: '960px'\n                },\n                {\n                    name: 'Apple iPhone 5',\n                    width: '640px',\n                    height: '1136px'\n                }\n            ]\n        },\n        {\n            // TODO : I18N\n            name: 'Tablet',\n            sizes: [\n                {\n                    name: 'Apple iPad 1 & 2 & Mini',\n                    width: '768px',\n                    height: '1024px'\n                },\n                {\n                    name: 'Apple iPad 3 & 4',\n                    width: '1536px',\n                    height: '2048px'\n                }\n            ]\n        }\n    ];\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPageProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GPageProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFPage>}\n     * @private\n     */\n    GPageProperties.prototype._pages = null;\n\n    /** @override */\n    GPageProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Page';\n    };\n\n    /** @override */\n    GPageProperties.prototype.init = function (panel) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property === 'msref') {\n                return $('<select></select>')\n                    .attr('data-property', 'msref')\n                    .on('change', function () {\n                        var val = $(this).val();\n                        self._assignProperty(property, val === '' ? null : val);\n                    });\n            } else if (property === 'size-preset') {\n                var result = $('<select></select>')\n                    .attr('data-property', 'size-preset')\n                    .on('change', function () {\n                        var scene = self._document.getScene();\n                        var val = $(this).val();\n                        if (val.indexOf(',') >= 0) {\n                            var val2 = val.split(',');\n                            var sz = GPageProperties.SIZE_PRESETS[parseInt(val2[0])].sizes[parseInt(val2[1])];\n                            var wp = scene.stringToPoint(sz.width);\n                            var hp = scene.stringToPoint(sz.height);\n                            self._panel.find('[name=\"w\"]').val(scene.pointToString(wp));\n                            self._panel.find('[name=\"h\"]').val(scene.pointToString(hp));\n                            self._assignProperties(['w', 'h'], [wp, hp]);\n                        }\n                    });\n\n                result.append($('<option></option>')\n                    .attr('value', 'x')\n                    // TODO : I18N\n                    .text('Custom Size'));\n\n                for (var i = 0; i < GPageProperties.SIZE_PRESETS.length; ++i) {\n                    var group = GPageProperties.SIZE_PRESETS[i];\n                    var groupEl = $('<optgroup></optgroup>')\n                        .attr('label', group.name);\n\n                    result.append(groupEl);\n\n                    for (var k = 0; k < group.sizes.length; ++k) {\n                        var size = group.sizes[k];\n                        $('<option></option>')\n                            .attr('value', i.toString() + ',' + k.toString())\n                            .text(size.name)\n                            .appendTo(groupEl);\n                    }\n                }\n\n                return result;\n            } else if (property === 'cls') {\n                return $('<button></button>')\n                    .attr('data-property', property)\n                    .gColorButton({\n                        allowClear: true\n                    })\n                    .on('colorchange', function (evt, color) {\n                        self._assignProperty(property, color);\n                    });\n            } else if (property === 'w' || property === 'h') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                        self._selectSizePreset();\n                    });\n            } else if (property === 'bl') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'mt' || property === 'mb' || property === 'ml' || property === 'mr') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            var lockMargins = self._panel.find('button[data-lock-margin]').hasClass('g-active');\n                            if (lockMargins) {\n                                self._assignProperties(['mt', 'mb', 'ml', 'mr'], [value, value, value, value]);\n                            } else {\n                                self._assignProperty(property, value);\n                            }\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '250px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px',\n                })\n                .append(_createInput('size-preset')\n                    .css({\n                        'width': '110px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '125px'\n                })\n                .html('<span class=\"fa fa-link\"></span>')\n                .append(_createInput('msref')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '102px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .text('W:')\n                .append(_createInput('w')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '65px'\n                })\n                .text('H:')\n                .append(_createInput('h')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '125px'\n                })\n                .text('Bleed:')\n                .append(_createInput('bl')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'right': '5px'\n                })\n                .append(_createInput('cls')))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '5px',\n                    'top': '65px'\n                })\n                .text('L:')\n                .append(_createInput('ml')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '5px',\n                    'top': '89px'\n                })\n                .text('T:')\n                .append(_createInput('mt')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '65px',\n                    'top': '65px'\n                })\n                .text('R:')\n                .append(_createInput('mr')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'left': '65px',\n                    'top': '89px'\n                })\n                .text('B:')\n                .append(_createInput('mb')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<button></button>')\n                .css({\n\n                    'position': 'absolute',\n                    'left': '123px',\n                    'top': '77px',\n                    'padding': '0px',\n                    'font-size': '10px'\n                })\n                .on('click', function (evt) {\n                    var $me = $(this);\n                    $me.toggleClass('g-active', !$me.hasClass('g-active'));\n                })\n                .addClass('g-flat fa fa-lock g-active')\n                // TODO : I18N\n                .attr('title', 'Equal Margins')\n                .attr('data-lock-margin', ''));\n    };\n\n    /** @override */\n    GPageProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document.getScene().removeEventListener(IFNode.AfterInsertEvent, this._updatePages, this);\n            this._document.getScene().removeEventListener(IFNode.AfterRemoveEvent, this._updatePages, this);\n            this._document = null;\n        }\n\n        this._pages = [];\n\n        // Special case: if only scene is in node selection,\n        // then select the currently active page by default\n        if (elements.length === 1 && elements[0] instanceof IFScene) {\n            var activePage = elements[0].getActivePage();\n            if (activePage) {\n                this._pages.push(activePage);\n            }\n        } else {\n            for (var i = 0; i < elements.length; ++i) {\n                if (elements[i] instanceof IFPage) {\n                    this._pages.push(elements[i]);\n                }\n            }\n        }\n\n        if (this._pages.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document.getScene().addEventListener(IFNode.AfterInsertEvent, this._updatePages, this);\n            this._document.getScene().addEventListener(IFNode.AfterRemoveEvent, this._updatePages, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GPageProperties.prototype._afterPropertiesChange = function (event) {\n        // Update ourself if our first element is changed or the scene's unit\n        if (this._pages.length > 0 && (this._pages[0] === event.node || (event.node instanceof IFScene && event.properties.indexOf('unit') >= 0))) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @private\n     */\n    GPageProperties.prototype._updateProperties = function () {\n        // We'll always read properties of first page\n        var scene = this._document.getScene();\n        var page = this._pages[0];\n\n        this._updatePages();\n\n        this._panel.find('select[data-property=\"msref\"]').val(page.getProperty('msref'));\n        this._panel.find('input[data-property=\"bl\"]').val(page.getProperty('bl'));\n        this._panel.find('[data-property=\"cls\"]')\n            .gColorButton('value', page.getProperty('cls'))\n            .gColorButton('scene', scene);\n        this._panel.find('input[data-property=\"w\"]').val(scene.pointToString(page.getProperty('w')));\n        this._panel.find('input[data-property=\"h\"]').val(scene.pointToString(page.getProperty('h')));\n        this._panel.find('input[data-property=\"mt\"]').val(scene.pointToString(page.getProperty('mt')));\n        this._panel.find('input[data-property=\"mb\"]').val(scene.pointToString(page.getProperty('mb')));\n        this._panel.find('input[data-property=\"ml\"]').val(scene.pointToString(page.getProperty('ml')));\n        this._panel.find('input[data-property=\"mr\"]').val(scene.pointToString(page.getProperty('mr')));\n\n        this._selectSizePreset();\n    };\n\n    /**\n     * @private\n     */\n    GPageProperties.prototype._updatePages = function () {\n        var scene = this._document.getScene();\n\n        var select = this._panel.find('select[data-property=\"msref\"]');\n        var oldVal = select.val();\n        select.val(null);\n        select.empty();\n\n        $('<option></option>')\n            .attr('value', '')\n            .text('')\n            .appendTo(select);\n\n        for (var node = scene.getFirstChild(); node !== null; node = node.getNext()) {\n            if (node instanceof IFPage && this._pages.indexOf(node) < 0) {\n                $('<option></option>')\n                    .attr('value', node.getReferenceId())\n                    .text(node.getLabel())\n                    .appendTo(select);\n            }\n        }\n\n        select.val(oldVal);\n    };\n\n    GPageProperties.prototype._selectSizePreset = function () {\n        var page = this._pages[0];\n        var foundPreset = false;\n        var presetSelector = this._panel.find('[data-property=\"size-preset\"]');\n\n        var w = page.getProperty('w');\n        var h = page.getProperty('h');\n\n        for (var i = 0; i < GPageProperties.SIZE_PRESETS.length; ++i) {\n            var group = GPageProperties.SIZE_PRESETS[i];\n            for (var k = 0; k < group.sizes.length; ++k) {\n                var size = group.sizes[k];\n                var sw = page.getScene().stringToPoint(size.width);\n                var sh = page.getScene().stringToPoint(size.height);\n                if (sw === w && sh === h) {\n                    presetSelector.val(i.toString() + ',' + k.toString());\n                    foundPreset = true;\n                    break;\n                }\n            }\n        }\n\n        if (!foundPreset) {\n            presetSelector.val('x');\n        }\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GPageProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GPageProperties.prototype._assignProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._pages.length; ++i) {\n                this._pages[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Page Properties');\n        }\n    };\n\n    /** @override */\n    GPageProperties.prototype.toString = function () {\n        return \"[Object GPageProperties]\";\n    };\n\n    _.GPageProperties = GPageProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/pathproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Path properties panel\n     * @class GPathProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GPathProperties() {\n        this._pathes = [];\n    };\n    IFObject.inherit(GPathProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPathProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GPathProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFPath>}\n     * @private\n     */\n    GPathProperties.prototype._pathes = null;\n\n    /**\n     * @type {Array<IFPathBase.AnchorPoint>}\n     * @private\n     */\n    GPathProperties.prototype._points = null;\n\n    /** @override */\n    GPathProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Path';\n    };\n\n    /** @override */\n    GPathProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        var _createPathInput = function (property) {\n            var self = this;\n            if (property === 'evenodd' || property === 'closed') {\n                return $('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-path-property', property)\n                    .on('change', function () {\n                        self._assignPathProperty(property, $(this).is(':checked'));\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        var _createPointInput = function (property) {\n            var self = this;\n            if (property === 'x' || property === 'y' || property === 'cl' || property === 'cr') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-point-property', property)\n                    .on('change', function (evt) {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            self._assignPointProperty(property, value);\n                        } else {\n                            self._updatePointProperties();\n                        }\n                    });\n            } else if (property === 'type') {\n                return $('<select></select>')\n                    .attr('data-point-property', property)\n                    .append($('<optgroup></optgroup>')\n                        // TODO : I18N\n                        .attr('label', 'Curve')\n                        .append($('<option></option>')\n                            .attr('value', IFPathBase.AnchorPoint.Type.Symmetric)\n                            // TODO : I18N\n                            .text('Symmetric'))\n                        .append($('<option></option>')\n                            .attr('value', IFPathBase.AnchorPoint.Type.Asymmetric)\n                            // TODO : I18N\n                            .text('Asymmetric'))\n                        .append($('<option></option>')\n                            .attr('value', IFPathBase.AnchorPoint.Type.Mirror)\n                            // TODO : I18N\n                            .text('Mirror'))\n                        .append($('<option></option>')\n                            .attr('value', IFPathBase.AnchorPoint.Type.Connector)\n                            // TODO : I18N\n                            .text('Connector')))\n                    .append($('<optgroup></optgroup>')\n                        // TODO : I18N\n                        .attr('label', 'Corner'))\n                    .gCornerType()\n                    .on('change', function () {\n                        var val = $(this).val();\n                        if (val === '-') {\n                            val = IFPathBase.CornerType.Rounded;\n                        }\n                        self._assignPointProperty('tp', val);\n                    });\n            } else if (property === 'ah') {\n                return $('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-point-property', property)\n                    .on('change', function () {\n                        self._assignPointProperty(property, $(this).is(':checked'));\n                    });\n            } else if (property === 'cu') {\n                return $('<button></button>')\n                    .addClass('g-flat')\n                    .attr('data-point-property', property)\n                    .on('click', function () {\n                        self._assignPointProperty(property, !$(this).hasClass('g-active'));\n                        self._updatePointProperties();\n                    })\n                    .append($('<span></span>')\n                        .addClass('fa fa-lock'));\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '205px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append(_createPathInput('closed'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Closed')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '75px'\n                })\n                .append(_createPathInput('evenodd'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Even/odd fill')))\n            .append($('<label></label>')\n                .attr('data-point-property', '_row')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .text('X:')\n                .append(_createPointInput('x')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<label></label>')\n                .attr('data-point-property', '_row')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '65px'\n                })\n                .text('Y:')\n                .append(_createPointInput('y')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })))\n            .append($('<div></div>')\n                .attr('data-point-property', '_row')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '125px'\n                })\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Clear Left Handle')\n                    .on('click', function () {\n                        this._assignPointProperties(['hlx', 'hly'], [null, null]);\n                    }.bind(this))\n                    .append($('<span></span>')\n                        .addClass('fa fa-forward')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Clear Right Handle')\n                    .on('click', function () {\n                        this._assignPointProperties(['hrx', 'hry'], [null, null]);\n                    }.bind(this))\n                    .append($('<span></span>')\n                        .addClass('fa fa-backward')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Clear Handles')\n                    .on('click', function () {\n                        this._assignPointProperties(['hlx', 'hly', 'hrx', 'hry'], [null, null, null, null]);\n                    }.bind(this))\n                    .append($('<span></span>')\n                        .addClass('fa fa-times'))))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<label></label>')\n                .attr('data-point-property', '_row')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '5px'\n                })\n                .append(_createPointInput('type')\n                    .css('width', '100px')))\n            .append($('<label></label>')\n                .attr('data-point-property', '_row')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '110px'\n                })\n                .append(_createPointInput('ah'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Auto Handles')))\n            .append($('<label></label>')\n                .attr('data-point-property', '_row')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '5px'\n                })\n                .append(_createPointInput('cl')\n                    .css('width', '38px')\n                    // TODO : I18N\n                    .attr('title', 'Left Smoothness'))\n                .append(_createPointInput('cu')\n                    .css('width', '18px')\n                    // TODO : I18N\n                    .attr('title', 'Toggle Lock of Left & Right Smoothness'))\n                .append(_createPointInput('cr')\n                    .css('width', '38px')\n                    // TODO : I18N\n                    .attr('title', 'Right Smoothness')));\n    };\n\n    /** @override */\n    GPathProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange);\n            this._document.getScene().removeEventListener(IFElement.AfterFlagChangeEvent, this._afterFlagChange);\n            this._document = null;\n        }\n\n        // Collect all path elements and their selected anchor points\n        this._pathes = [];\n        this._points = [];\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFPath) {\n                var path = elements[i];\n\n                this._pathes.push(elements[i]);\n\n                for (var ap = path.getAnchorPoints().getFirstChild(); ap !== null; ap = ap.getNext()) {\n                    if (ap.hasFlag(IFNode.Flag.Selected)) {\n                        this._points.push(ap);\n                    }\n                }\n            }\n        }\n\n        if (this._pathes.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document.getScene().addEventListener(IFElement.AfterFlagChangeEvent, this._afterFlagChange, this);\n            this._updatePathProperties();\n            this._updatePointProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GPathProperties.prototype._afterPropertiesChange = function (event) {\n        // If properties of first path has changed then update ourself\n        if (this._pathes.length > 0 && this._pathes[0] === event.node) {\n            this._updatePathProperties();\n        }\n        // If properties of first anchor point has changed then update ourself\n        if (this._points.length > 0 && this._points[0] === event.node) {\n            this._updatePointProperties();\n        }\n    };\n\n    /**\n     * @param {IFElement.AfterFlagChangeEvent} event\n     * @private\n     */\n    GPathProperties.prototype._afterFlagChange = function (event) {\n        if (event.flag === IFNode.Flag.Selected && event.node instanceof IFPathBase.AnchorPoint) {\n            var path = event.node.getParent().getParent();\n            if (path && this._pathes.indexOf(path) >= 0) {\n                if (event.set) {\n                    this._points.push(event.node);\n                } else {\n                    this._points.splice(this._points.indexOf(event.node), 1);\n                }\n                this._updatePointProperties();\n            }\n        }\n    };\n\n    /**\n     * @private\n     */\n    GPathProperties.prototype._updatePathProperties = function () {\n        // We'll always read properties of first path\n        var path = this._pathes[0];\n        this._panel.find('input[data-path-property=\"evenodd\"]').prop('checked', path.getProperty('evenodd'));\n        this._panel.find('input[data-path-property=\"closed\"]').prop('checked', path.getProperty('closed'));\n    };\n\n    /**\n     * @private\n     */\n    GPathProperties.prototype._updatePointProperties = function () {\n        // We'll always read properties of first anchor point if any\n        var point = this._points.length > 0 ? this._points[0] : null;\n\n        if (point) {\n            this._panel.find('[data-point-property]').css('visibility', '');\n            this._panel.find('input[data-point-property=\"x\"]').val(\n                this._document.getScene().pointToString(point.getProperty('x')));\n            this._panel.find('input[data-point-property=\"y\"]').val(\n                this._document.getScene().pointToString(point.getProperty('y')));\n            this._panel.find('input[data-point-property=\"ah\"]').prop('checked', point.getProperty('ah'));\n\n            var isCorner = true;\n            var apType = point.getProperty('tp');\n            for (var p in IFPathBase.AnchorPoint.Type) {\n                if (IFPathBase.AnchorPoint.Type[p] === apType) {\n                    isCorner = false;\n                    break;\n                }\n            }\n\n            this._panel.find('select[data-point-property=\"type\"]').val(apType);\n\n            this._panel.find('input[data-point-property=\"cl\"]')\n                .prop('disabled', !isCorner)\n                .val(this._document.getScene().pointToString(point.getProperty('cl')));\n            this._panel.find('input[data-point-property=\"cr\"]')\n                .prop('disabled', !isCorner || point.getProperty('cu'))\n                .val(this._document.getScene().pointToString(point.getProperty('cr')));\n            this._panel.find('button[data-point-property=\"cu\"]')\n                .prop('disabled', !isCorner)\n                .toggleClass('g-active', point.getProperty('cu'));\n        } else {\n            this._panel.find('[data-point-property]').css('visibility', 'hidden');\n        }\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GPathProperties.prototype._assignPathProperty = function (property, value) {\n        this._assignPathProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GPathProperties.prototype._assignPathProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._pathes.length; ++i) {\n                this._pathes[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Path Properties');\n        }\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GPathProperties.prototype._assignPointProperty = function (property, value) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._points.length; ++i) {\n                var point = this._points[i];\n                if (property === 'x') {\n                    var dx = value - point.getProperty('x');\n                    var hlx = point.getProperty('hlx') ? point.getProperty('hlx') + dx : null;\n                    var hrx = point.getProperty('hrx') ? point.getProperty('hrx') + dx : null;\n                    point.setProperties(['x', 'hlx', 'hrx'], [value, hlx, hrx]);\n                } else if (property === 'y') {\n                    var dy = value - point.getProperty('y');\n                    var hly = point.getProperty('hly') ? point.getProperty('hly') + dy : null;\n                    var hry = point.getProperty('hry') ? point.getProperty('hry') + dy : null;\n                    point.setProperties(['y', 'hly', 'hry'], [value, hly, hry]);\n                } else {\n                    point.setProperties([property], [value]);\n                }\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Point Properties');\n        }\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GPathProperties.prototype._assignPointProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._points.length; ++i) {\n                this._points[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Point Properties');\n        }\n    };\n\n    /** @override */\n    GPathProperties.prototype.toString = function () {\n        return \"[Object GPathProperties]\";\n    };\n\n    _.GPathProperties = GPathProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/polygonproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Polygon properties panel\n     * @class GPolygonProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GPolygonProperties() {\n        this._polygons = [];\n    };\n    IFObject.inherit(GPolygonProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPolygonProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GPolygonProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFPolygon>}\n     * @private\n     */\n    GPolygonProperties.prototype._polygons = null;\n\n    /** @override */\n    GPolygonProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Polygon';\n    };\n\n    /** @override */\n    GPolygonProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property === 'pts') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', 'pts')\n                    .on('change', function () {\n                        var points = parseInt($(this).val());\n                        if (!isNaN(points)) {\n                            var innerAngle = ifMath.normalizeAngleRadians(\n                                self._polygons[0].getProperty('oa') + Math.PI / points);\n\n                            self._assignProperties([property, 'ia'],\n                                [ifMath.normalizeValue(points, 2, 360), innerAngle]);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'evenodd') {\n                return $('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).is(':checked'));\n                    });\n            } else if (property === 'ir' || property === 'or') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'ia' || property === 'oa') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var angle = IFLength.parseEquationValue($(this).val());\n                        if (angle !== null) {\n                            angle = ifMath.normalizeAngleRadians(ifMath.toRadians(angle));\n                            self._assignProperty(property, ifMath.PI2 - angle);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'ict' || property === 'oct') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    .gCornerType()\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else if (property === 'icr' || property === 'ocr') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function (evt) {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            self._assignProperty(property, value < 0 ? 0 : value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '198px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                // TODO : I18N\n                .text('Points:')\n                .append(_createInput('pts')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '48px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '101px'\n                })\n                .append(_createInput('evenodd'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Even/odd fill')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .html('<span class=\"fa fa-stop\" style=\"font-size:11px;transform:rotate(45deg)\"></span>')\n                .append(_createInput('or')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '48px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '103px'\n                })\n                .html('<span class=\"fa fa-circle\"></span>')\n                .append(_createInput('ir')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '48px'\n                    })))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '5px'\n                })\n                .html('<span class=\"fa fa-rotate-right\"></span>')\n                .append(_createInput('oa')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '48px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '103px'\n                })\n                .html('<span class=\"fa fa-rotate-right\" style=\"visibility: hidden\"></span>')\n                .append(_createInput('ia')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '48px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '90px',\n                    'left': '5px'\n                })\n                .html('<span class=\"fa fa-square\"></span>')\n                .append(_createInput('ocr')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '38px'\n                    }))\n                .append(_createInput('oct')\n                    .css('width', '32px')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '103px'\n                })\n                .html('<span class=\"fa fa-square\" style=\"visibility: hidden\"></span>')\n                .append(_createInput('icr')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    }))\n                .append(_createInput('ict')\n                    .css('width', '32px')));\n    };\n\n    /** @override */\n    GPolygonProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange);\n            this._document = null;\n        }\n\n        // Collect all polygon elements\n        this._polygons = [];\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFPolygon) {\n                this._polygons.push(elements[i]);\n            }\n        }\n\n        if (this._polygons.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GPolygonProperties.prototype._afterPropertiesChange = function (event) {\n        // If properties of first polygon has changed then update ourself\n        if (this._polygons.length > 0 && this._polygons[0] === event.node) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @private\n     */\n    GPolygonProperties.prototype._updateProperties = function () {\n        // We'll always read properties of first polygon\n        var polygon = this._polygons[0];\n        this._panel.find('input[data-property=\"pts\"]').val(polygon.getProperty('pts'));\n        this._panel.find('input[data-property=\"evenodd\"]').prop('checked', polygon.getProperty('evenodd'));\n        this._panel.find('input[data-property=\"or\"]').val(\n            this._document.getScene().pointToString(polygon.getProperty('or')));\n        this._panel.find('input[data-property=\"ir\"]').val(\n            this._document.getScene().pointToString(polygon.getProperty('ir')));\n        this._panel.find('input[data-property=\"oa\"]').val(\n            ifUtil.formatNumber(ifMath.toDegrees(ifMath.PI2 - polygon.getProperty('oa')), 2));\n        this._panel.find('input[data-property=\"ia\"]').val(\n            ifUtil.formatNumber(ifMath.toDegrees(ifMath.PI2 - polygon.getProperty('ia')), 2));\n        this._panel.find('select[data-property=\"oct\"]').val(polygon.getProperty('oct'));\n        this._panel.find('select[data-property=\"ict\"]').val(polygon.getProperty('ict'));\n        this._panel.find('input[data-property=\"ocr\"]').val(\n            this._document.getScene().pointToString(polygon.getProperty('ocr')));\n        this._panel.find('input[data-property=\"icr\"]').val(\n            this._document.getScene().pointToString(polygon.getProperty('icr')));\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GPolygonProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GPolygonProperties.prototype._assignProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._polygons.length; ++i) {\n                this._polygons[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Polygon Properties');\n        }\n    };\n\n    /** @override */\n    GPolygonProperties.prototype.toString = function () {\n        return \"[Object GPolygonProperties]\";\n    };\n\n    _.GPolygonProperties = GPolygonProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/rectangleproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Rectangle properties panel\n     * @class GRectangleProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GRectangleProperties() {\n        this._rectangles = [];\n    };\n    IFObject.inherit(GRectangleProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GRectangleProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GRectangleProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFRectangle>}\n     * @private\n     */\n    GRectangleProperties.prototype._rectangles = null;\n\n    /** @override */\n    GRectangleProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Rectangle';\n    };\n\n    /** @override */\n    GRectangleProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property === 'uf') {\n                return $('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        self._assignProperty('uf', $(this).is(':checked'));\n                        self._updateCornerProperties();\n                    });\n            }\n            else if (property === 'tl_sx' || property === 'tl_sy' || property === 'tr_sx' || property === 'tr_sy' ||\n                property === 'bl_sx' || property === 'bl_sy' || property === 'br_sx' || property === 'br_sy') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .css('width', '48px')\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateCornerProperties();\n                        }\n                    });\n            } else if (property === 'tl_ct' || property === 'tr_ct' || property === 'bl_ct' || property === 'br_ct') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    .css('width', '32px')\n                    .gCornerType()\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).val());\n                    });\n            } else if (property === 'tl_uf' || property === 'tr_uf' || property === 'bl_uf' || property === 'br_uf') {\n                return $('<button></button>')\n                    .addClass('g-flat')\n                    .css('width', '32px')\n                    .attr('data-property', property)\n                    .on('click', function () {\n                        self._assignProperty(property, !$(this).hasClass('g-active'));\n                        self._updateCornerProperties();\n                    })\n                    .append($('<span></span>')\n                        .addClass('fa fa-lock fa-fw'));\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        // TODO : I18N\n        var titleUniform = 'Uniform Corner-Smoothness';\n        var titleSmoothX = 'Horizontal Corner-Smoothness';\n        var titleSmoothY = 'Vertical Corner-Smoothness';\n        var titleCornerType = 'Corner-Type';\n\n        panel\n            .css('width', '180px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append(_createInput('uf'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Uniform Corners')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .append(_createInput('tl_ct')\n                    .attr('title', titleUniform))\n                .append(_createInput('tl_sx')\n                    .attr('title', titleSmoothX))\n                .append(_createInput('tr_sx')\n                    .attr('title', titleSmoothX))\n                .append(_createInput('tr_ct')\n                    .attr('title', titleUniform)))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '53px',\n                    'left': '5px'\n                })\n                .append(_createInput('tl_sy')\n                    .attr('title', titleSmoothY))\n                .append(_createInput('tl_uf')\n                    .attr('title', titleCornerType))\n                .append(_createInput('tr_uf')\n                    .attr('title', titleCornerType))\n                .append(_createInput('tr_sy')\n                    .attr('title', titleSmoothY)))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '76px',\n                    'left': '5px'\n                })\n                .append(_createInput('bl_sy')\n                    .attr('title', titleSmoothY))\n                .append(_createInput('bl_uf')\n                    .attr('title', titleCornerType))\n                .append(_createInput('br_uf')\n                    .attr('title', titleCornerType))\n                .append(_createInput('br_sy')\n                    .attr('title', titleSmoothY)))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '99px',\n                    'left': '5px'\n                })\n                .append(_createInput('bl_ct')\n                    .attr('title', titleUniform))\n                .append(_createInput('bl_sx')\n                    .attr('title', titleSmoothX))\n                .append(_createInput('br_sx')\n                    .attr('title', titleSmoothX))\n                .append(_createInput('br_ct')\n                    .attr('title', titleUniform)));\n    };\n\n    /** @override */\n    GRectangleProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange);\n            this._document = null;\n        }\n\n        // Collect all rectangle elements\n        this._rectangles = [];\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFRectangle) {\n                this._rectangles.push(elements[i]);\n            }\n        }\n\n        if (this._rectangles.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GRectangleProperties.prototype._afterPropertiesChange = function (event) {\n        // If properties of first ellipse has changed then update ourself\n        if (this._rectangles.length > 0 && this._rectangles[0] === event.node) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @private\n     */\n    GRectangleProperties.prototype._updateProperties = function () {\n        this._updateCornerProperties();\n    };\n\n    /**\n     * @private\n     */\n    GRectangleProperties.prototype._updateCornerProperties = function () {\n        // We'll always read properties of first ellipse\n        var rectangle = this._rectangles[0];\n        var allUniform = rectangle.getProperty('uf');\n\n        var _updateCorners = function (corners) {\n            for (var i = 0; i < corners.length; ++i) {\n                var corner = corners[i];\n\n                var uf = this._panel.find('button[data-property=\"' + corner + '_uf\"]');\n                var sx = this._panel.find('input[data-property=\"' + corner + '_sx\"]');\n                var sy = this._panel.find('input[data-property=\"' + corner + '_sy\"]');\n                var ct = this._panel.find('select[data-property=\"' + corner + '_ct\"]');\n\n                var hidden = allUniform && corner !== 'tl';\n                uf.css('visibility', hidden ? 'hidden' : 'visible');\n                sx.css('visibility', hidden ? 'hidden' : 'visible');\n                sy.css('visibility', hidden ? 'hidden' : 'visible');\n                ct.css('visibility', hidden ? 'hidden' : 'visible');\n\n                if (!hidden) {\n                    sx.val(this._document.getScene().pointToString(rectangle.getProperty(corner + '_sx')));\n                    sy.val(this._document.getScene().pointToString(rectangle.getProperty(corner + '_sy')));\n                    if (rectangle.getProperty(corner + '_uf')) {\n                        uf.addClass('g-active');\n                        sy.prop('disabled', true);\n                    } else {\n                        uf.removeClass('g-active');\n                        sy.prop('disabled', false);\n                    }\n\n                    uf.prop('disabled', allUniform);\n                }\n            }\n        }.bind(this);\n\n        this._panel.find('input[data-property=\"uf\"]').prop('checked', allUniform);\n        _updateCorners(['tl', 'tr', 'bl', 'br']);\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GRectangleProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GRectangleProperties.prototype._assignProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._rectangles.length; ++i) {\n                this._rectangles[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Rectangle Properties');\n        }\n    };\n\n    /** @override */\n    GRectangleProperties.prototype.toString = function () {\n        return \"[Object GRectangleProperties]\";\n    };\n\n    _.GRectangleProperties = GRectangleProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/sliceproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Slice properties panel\n     * @class GSliceProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GSliceProperties() {\n        this._slices = [];\n    };\n    IFObject.inherit(GSliceProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GSliceProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GSliceProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFSlice>}\n     * @private\n     */\n    GSliceProperties.prototype._slices = null;\n\n    /** @override */\n    GSliceProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Slice';\n    };\n\n    /** @override */\n    GSliceProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property === 'cls') {\n                return $('<button></button>')\n                    .attr('data-property', property)\n                    .gColorButton({\n                        allowClear: true\n                    })\n                    .on('colorchange', function (evt, color) {\n                        self._assignProperty(property, color);\n                    });\n            } else if (property === 'trm') {\n                return $('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).is(':checked'));\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '120px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                // TODO : I18N\n                .text('Color:')\n                .append(_createInput('cls')\n                    .css({\n                        'margin-left': '3px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .append(_createInput('trm'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Trim Transparent')));\n    };\n\n    /** @override */\n    GSliceProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document = null;\n        }\n\n        this._slices = [];\n\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFSlice) {\n                this._slices.push(elements[i]);\n            }\n        }\n\n        if (this._slices.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GSliceProperties.prototype._afterPropertiesChange = function (event) {\n        // Update ourself if our first element is changed\n        if (this._slices.length > 0 && this._slices[0] === event.node) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @private\n     */\n    GSliceProperties.prototype._updateProperties = function () {\n        // We'll always read properties of first element\n        var scene = this._document.getScene();\n        var slice = this._slices[0];\n\n        this._panel.find('[data-property=\"cls\"]')\n            .gColorButton('value', slice.getProperty('cls'))\n            .gColorButton('scene', scene);\n\n        this._panel.find('input[data-property=\"trm\"]').prop('checked', slice.getProperty('trm'));\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GSliceProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GSliceProperties.prototype._assignProperties = function (properties, values) {\n        var editor = this._document.getEditor();\n        editor.beginTransaction();\n        try {\n            for (var i = 0; i < this._slices.length; ++i) {\n                this._slices[i].setProperties(properties, values);\n            }\n        } finally {\n            // TODO : I18N\n            editor.commitTransaction('Modify Slice Properties');\n        }\n    };\n\n    /** @override */\n    GSliceProperties.prototype.toString = function () {\n        return \"[Object GSliceProperties]\";\n    };\n\n    _.GSliceProperties = GSliceProperties;\n})(this);"
  },
  {
    "path": "src/gravit/properties/textproperties.js",
    "content": "(function (_) {\n\n    /**\n     * Text properties panel\n     * @class GTextProperties\n     * @extends GProperties\n     * @constructor\n     */\n    function GTextProperties() {\n        this._text = [];\n    };\n    IFObject.inherit(GTextProperties, GProperties);\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GTextProperties.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GTextProperties.prototype._document = null;\n\n    /**\n     * @type {Array<IFText>}\n     * @private\n     */\n    GTextProperties.prototype._text = null;\n\n    /**\n     * @type {IFTextEditor}\n     * @private\n     */\n    GTextProperties.prototype._textEditor = null;\n\n    /** @override */\n    GTextProperties.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Text';\n    };\n\n    /** @override */\n    GTextProperties.prototype.init = function (panel, controls) {\n        this._panel = panel;\n\n        var _createInput = function (property) {\n            var self = this;\n            if (property.indexOf('va-') === 0) {\n                var icon = '';\n                var align = property.substr('va-'.length);\n                switch (align) {\n                    case IFText.VerticalAlign.Top:\n                        icon = 'fa-align-right fa-rotate-270';\n                        break;\n                    case IFText.VerticalAlign.Middle:\n                        icon = 'fa-align-center fa-rotate-270';\n                        break;\n                    case IFText.VerticalAlign.Bottom:\n                        icon = 'fa-align-left fa-rotate-270';\n                        break;\n                    default:\n                        break;\n                }\n\n                return $('<button></button>')\n                    .attr('data-property', property)\n                    .on('click', function () {\n                        self._assignProperty('va', align);\n                    })\n                    .append($('<span></span>')\n                        .addClass('fa ' + icon));\n            } else if (property.indexOf('al-') === 0) {\n                var iconName = '';\n                var alignment = property.substr('al-'.length);\n                switch (alignment) {\n                    case IFText.Paragraph.Alignment.Left:\n                        iconName = 'left';\n                        break;\n                    case IFText.Paragraph.Alignment.Center:\n                        iconName = 'center';\n                        break;\n                    case IFText.Paragraph.Alignment.Right:\n                        iconName = 'right';\n                        break;\n                    case IFText.Paragraph.Alignment.Justify:\n                        iconName = 'justify';\n                        break;\n                    default:\n                        break;\n                }\n\n                return $('<button></button>')\n                    .attr('data-property', property)\n                    .on('click', function () {\n                        self._assignProperty('al', $(this).hasClass('g-active') ? null : alignment);\n                    })\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-' + iconName));\n            } else if (property === 'aw' || property === 'ah') {\n                return $('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        self._assignProperty(property, $(this).is(':checked'));\n                    });\n            } else if (property === 'ff') {\n                var select = $('<select></select>')\n                    .attr('data-property', property)\n                    .append(\n                        $('<option></option>')\n                            .attr('value', '')\n                            .text(''))\n                    .on('change', function () {\n                        var val = $(this).val();\n                        self._assignProperty(property, val === '' ? null : val);\n                    });\n\n                // TODO : Group local & most used fonts first\n                var optGroups = {};\n\n                // Add typefaces\n                var families = ifFont.getFamilies();\n                for (var i = 0; i < families.length; ++i) {\n                    var category = ifFont.getCategory(families[i]);\n                    var optGroup = null;\n                    if (optGroups.hasOwnProperty(category)) {\n                        optGroup = optGroups[category];\n                    } else {\n                        optGroups[category] = optGroup = $('<optgroup></optgroup>')\n                            .attr('label', ifLocale.get(IFFont.CategoryName[category]))\n                            .appendTo(select);\n                    }\n\n                    $('<option></option>')\n                        .attr('value', families[i])\n                        .text(families[i])\n                        .appendTo(optGroup);\n                }\n\n                return select;\n            } else if (property === 'fi' || property === 'ws' || property === 'cs' || property === 'in' || property === 'cg') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = self._document.getScene().stringToPoint($(this).val());\n                        if (value === null || (typeof value === 'number' && value >= 0)) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'fw') {\n                var select = $('<select></select>')\n                    .attr('data-property', property)\n                    .append(\n                        $('<option></option>')\n                            .attr('value', '')\n                            .text(''))\n                    .on('change', function () {\n                        var val = $(this).val();\n                        self._assignProperty(property, val === '' ? null : val);\n                    });\n\n                for (var i = 100; i <= 900; i += 100) {\n                    $('<option></option>')\n                        .attr('value', i)\n                        .text(ifLocale.get(IFFont.WeightName[i]))\n                        .appendTo(select);\n                }\n\n                return select;\n            } else if (property === 'fs') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    .append($('<option></option>')\n                        .attr('value', '')\n                        .text(''))\n                    .append($('<option></option>')\n                        .attr('value', IFFont.Style.Normal)\n                        // TODO : I18N\n                        .text('Normal'))\n                    .append($('<option></option>')\n                        .attr('value', IFFont.Style.Italic)\n                        // TODO : I18N\n                        .text('Italic'))\n                    .on('change', function () {\n                        var val = $(this).val();\n                        self._assignProperty(property, val === '' ? null : val);\n                    });\n            } else if (property === 'fc') {\n                return $('<button></button>')\n                    .attr('data-property', property)\n                    .gColorButton({\n                        allowClear: true,\n                        scene: this._document.getScene()\n                    })\n                    .on('colorchange', function (evt, color) {\n                        self._assignProperty(property, color);\n                    });\n            } else if (property === 'wm') {\n                return $('<select></select>')\n                    .attr('data-property', property)\n                    .append($('<option></option>')\n                        .attr('value', '')\n                        .text(''))\n                    .append($('<option></option>')\n                        .attr('value', IFText.Paragraph.WrapMode.None)\n                        // TODO : I18N\n                        .text('None'))\n                    .append($('<option></option>')\n                        .attr('value', IFText.Paragraph.WrapMode.Words)\n                        // TODO : I18N\n                        .text('Words'))\n                    .append($('<option></option>')\n                        .attr('value', IFText.Paragraph.WrapMode.All)\n                        // TODO : I18N\n                        .text('All'))\n                    .on('change', function () {\n                        var val = $(this).val();\n                        self._assignProperty(property, val === '' ? null : val);\n                    });\n            } else if (property === 'lh') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = $(this).val();\n                        value = !value || value === \"\" ? null : IFLength.parseEquationValue(value);\n                        if (value === null || value > 0) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else if (property === 'cc') {\n                return $('<input>')\n                    .attr('type', 'text')\n                    .attr('data-property', property)\n                    .on('change', function () {\n                        var value = $(this).val();\n                        value = !value || value === \"\" ? null : parseInt(value);\n                        if (value === null || value > 1) {\n                            self._assignProperty(property, value);\n                        } else {\n                            self._updateProperties();\n                        }\n                    });\n            } else {\n                throw new Error('Unknown input property: ' + property);\n            }\n        }.bind(this);\n\n        panel\n            .css('width', '320px')\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append(_createInput('ff')\n                    .css({\n                        'width': '120px'\n                    }))\n                .append(_createInput('fw')\n                    .css({\n                        'width': '83px'\n                    }))\n                .append(_createInput('fs')\n                    .css({\n                        'width': '65px'\n                    }))\n                .append(_createInput('fi')\n                    .css({\n                        'width': '30px'\n                    })))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .html('<span class=\"fa fa-text-width\"></span>')\n                .append(_createInput('cs')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '30px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Character Spacing')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '60px'\n                })\n                .html('<span class=\"fa fa-text-width\"></span>')\n                .append(_createInput('ws')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '30px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Word Spacing')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '115px'\n                })\n                .html('<span class=\"fa fa-text-height\"></span>')\n                .append(_createInput('lh')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '30px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Line Height')))\n            .append($('<div></div>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '215px'\n                })\n                .append(_createInput('al-' + IFText.Paragraph.Alignment.Left)\n                    // TODO : I18N\n                    .attr('title', 'Align Left'))\n                .append(_createInput('al-' + IFText.Paragraph.Alignment.Center)\n                    // TODO : I18N\n                    .attr('title', 'Align Centered'))\n                .append(_createInput('al-' + IFText.Paragraph.Alignment.Right)\n                    // TODO : I18N\n                    .attr('title', 'Align Right'))\n                .append(_createInput('al-' + IFText.Paragraph.Alignment.Justify)\n                    // TODO : I18N\n                    .attr('title', 'Justify')))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<div></div>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '5px'\n                })\n                .append(_createInput('va-' + IFText.VerticalAlign.Top)\n                    // TODO : I18N\n                    .attr('title', 'Align Top'))\n                .append(_createInput('va-' + IFText.VerticalAlign.Middle)\n                    // TODO : I18N\n                    .attr('title', 'Align Middle'))\n                .append(_createInput('va-' + IFText.VerticalAlign.Bottom)\n                    // TODO : I18N\n                    .attr('title', 'Align Bottom')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '85px'\n                })\n                .html('<span class=\"fa fa-sort-alpha-asc\"></span>')\n                .append(_createInput('wm')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '60px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Wrap Mode')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '230px'\n                })\n                .append(_createInput('ah'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Auto Height')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '5px'\n                })\n                .html('<span class=\"fa fa-indent\"></span>')\n                .append(_createInput('in')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '30px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Indent')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '60px'\n                })\n                .html('<span class=\"fa fa-reorder fa-rotate-270\"></span>')\n                .append(_createInput('cc')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '30px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Columns')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '115px'\n                })\n                .html('<span class=\"fa fa-sort-amount-desc fa-rotate-270\"></span>')\n                .append(_createInput('cg')\n                    .css({\n                        'margin-left': '5px',\n                        'width': '30px'\n                    })\n                    // TODO : I18N\n                    .attr('title', 'Columns Gap')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '230px'\n                })\n                .append(_createInput('aw'))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Auto Width')));\n    };\n\n    /** @override */\n    GTextProperties.prototype.update = function (document, elements) {\n        if (this._document) {\n            this._document.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange);\n            this._document.getEditor().removeEventListener(IFEditor.InlineEditorEvent, this._inlineEditorEvent);\n            this._document = null;\n        }\n\n        // Collect all text elements\n        this._text = [];\n        for (var i = 0; i < elements.length; ++i) {\n            if (elements[i] instanceof IFText) {\n                this._text.push(elements[i]);\n            }\n        }\n\n        if (this._text.length === elements.length) {\n            this._document = document;\n            this._document.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            this._document.getEditor().addEventListener(IFEditor.InlineEditorEvent, this._inlineEditorEvent, this);\n            this._updateProperties();\n            return true;\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GTextProperties.prototype._afterPropertiesChange = function (event) {\n        // If properties of first text has changed then update ourself\n        if (this._text.length > 0 && (this._text[0] === event.node || this._text[0].getContent() === event.node)) {\n            this._updateProperties();\n        }\n    };\n\n    /**\n     * @param {IFEditor.InlineEditorEvent} event\n     * @private\n     */\n    GTextProperties.prototype._inlineEditorEvent = function (event) {\n        switch (event.type) {\n            case IFEditor.InlineEditorEvent.Type.AfterOpen:\n                this._textEditor = event.editor;\n                this._updateProperties();\n                break;\n            case IFEditor.InlineEditorEvent.Type.AfterClose:\n                this._textEditor = null;\n                this._updateProperties();\n                break;\n            case IFEditor.InlineEditorEvent.Type.SelectionChanged:\n                this._updateProperties();\n                break;\n            default:\n                break;\n        }\n    };\n\n    /**\n     * Defaults to false.\n     * @private\n     */\n    GTextProperties.prototype._updateProperties = function () {\n        // Read properties from active editor or first text' editor\n        var propertySource = this._textEditor ? this._textEditor : IFElementEditor.getEditor(this._text[0]);\n\n        // Text\n        this._panel.find('button[data-property^=\"va\"]').each(function (index, element) {\n            var $element = $(element);\n            var disabled = this._textEditor && this._textEditor.isInlineEdit() ? true : false;\n            $element\n                .prop('disabled', disabled)\n                .toggleClass('g-active', disabled ? false : ($element.attr('data-property') === 'va-' + propertySource.getProperty('va')));\n        }.bind(this));\n\n        this._panel.find('input[data-property=\"ah\"]')\n            .prop('disabled', this._textEditor && this._textEditor.isInlineEdit())\n            .prop('checked', propertySource.getProperty('ah'));\n\n        this._panel.find('input[data-property=\"aw\"]')\n            .prop('disabled', this._textEditor && this._textEditor.isInlineEdit())\n            .prop('checked', propertySource.getProperty('aw'));\n\n        // Block\n        var fontFamily = propertySource.getProperty('ff', true);\n\n        this._panel.find('select[data-property=\"ff\"]').val(propertySource.getProperty('ff'));\n        this._panel.find('input[data-property=\"fi\"]')\n            .val(this._document.getScene().pointToString(propertySource.getProperty('fi')));\n\n        var weightSelect = this._panel.find('select[data-property=\"fw\"]');\n        weightSelect.val(propertySource.getProperty('fw'));\n        var fontWeights = ifFont.getWeights(fontFamily);\n        for (var i = 100; i <= 900; i += 100) {\n            weightSelect.find('[value=\"' + i + '\"]').prop('disabled', !fontWeights || fontWeights.indexOf(i) < 0);\n        }\n\n        var styleSelect = this._panel.find('select[data-property=\"fs\"]');\n        styleSelect.val(propertySource.getProperty('fs'));\n        var fontStyles = ifFont.getStyles(fontFamily);\n        styleSelect.find('option').each(function (index, option) {\n            var $option = $(option);\n            var value = $option.attr('value');\n            if (value !== '') {\n                $option.prop('disabled', fontStyles.indexOf(value) < 0);\n            }\n        });\n\n        //this._panel.find('[data-property=\"fc\"]').gColorButton('value', propertySource.getProperty('fc'));\n\n        this._panel.find('input[data-property=\"ws\"]').val(\n            this._document.getScene().pointToString(propertySource.getProperty('ws')));\n        this._panel.find('input[data-property=\"cs\"]').val(\n            this._document.getScene().pointToString(propertySource.getProperty('cs')));\n\n\n        // Paragraph\n        this._panel.find('input[data-property=\"cc\"]').val(propertySource.getProperty('cc'));\n        this._panel.find('input[data-property=\"cg\"]')\n            .val(this._document.getScene().pointToString(propertySource.getProperty('cg')));\n\n        var alignVal = propertySource.getProperty('al') || '';\n        this._panel.find('button[data-property^=\"al\"]').each(function (index, element) {\n            var $element = $(element);\n            $element.toggleClass('g-active', $element.attr('data-property') === 'al-' + alignVal);\n        });\n\n        this._panel.find('select[data-property=\"wm\"]').val(propertySource.getProperty('wm'));\n\n        this._panel.find('input[data-property=\"in\"]')\n            .val(this._document.getScene().pointToString(propertySource.getProperty('in')));\n\n        var lh = propertySource.getProperty('lh');\n        this._panel.find('input[data-property=\"lh\"]').val(lh !== null ? ifUtil.formatNumber(lh) : \"\");\n    };\n\n    /**\n     * @param {String} property\n     * @param {*} value\n     * @private\n     */\n    GTextProperties.prototype._assignProperty = function (property, value) {\n        this._assignProperties([property], [value]);\n    };\n\n    /**\n     * @param {Array<String>} properties\n     * @param {Array<*>} values\n     * @private\n     */\n    GTextProperties.prototype._assignProperties = function (properties, values) {\n        if (this._textEditor) {\n            this._textEditor.setProperties(properties, values);\n        } else {\n            var editor = this._document.getEditor();\n            editor.beginTransaction();\n            try {\n                for (var i = 0; i < this._text.length; ++i) {\n                    var textEditor = IFElementEditor.getEditor(this._text[i]);\n                    textEditor.setProperties(properties, values);\n                }\n            } finally {\n                // TODO : I18N\n                editor.commitTransaction('Modify Text Properties');\n            }\n        }\n    };\n\n    /** @override */\n    GTextProperties.prototype.toString = function () {\n        return \"[Object GTextProperties]\";\n    };\n\n    _.GTextProperties = GTextProperties;\n})(this);"
  },
  {
    "path": "src/gravit/sidebar/pageslayerssidebar.js",
    "content": "(function (_) {\n\n    var dragPage = null;\n\n    function canDropPage(target) {\n        if (dragPage) {\n            var targetPage = $(target).data('page');\n\n            if (targetPage && (targetPage !== dragPage || ifPlatform.modifiers.shiftKey)) {\n                return dragPage.getParent() === targetPage.getParent();\n            }\n        }\n\n        return false;\n    };\n\n    /**\n     * The pages & layers sidebar\n     * @class GPagesLayersSidebar\n     * @extends GSidebar\n     * @constructor\n     */\n    function GPagesLayersSidebar() {\n        GSidebar.call(this);\n    }\n\n    IFObject.inherit(GPagesLayersSidebar, GSidebar);\n\n    GPagesLayersSidebar.ID = \"pages-layers\";\n    GPagesLayersSidebar.TITLE = new IFLocale.Key(GPagesLayersSidebar, \"title\");\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._pagesPanel = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._pageAddControl = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._pageDeleteControl = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._layersTree = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._layersTreeNodeMap = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._layerAddControl = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._layerDeleteControl = null;\n\n    /** @override */\n    GPagesLayersSidebar.prototype.getId = function () {\n        return GPagesLayersSidebar.ID;\n    };\n\n    /** @override */\n    GPagesLayersSidebar.prototype.getTitle = function () {\n        return GPagesLayersSidebar.TITLE;\n    };\n\n    /** @override */\n    GPagesLayersSidebar.prototype.getIcon = function () {\n        return '<span class=\"fa fa-fw fa-bars\"></span>';\n    };\n\n    /** @override */\n    GPagesLayersSidebar.prototype.init = function (htmlElement) {\n        GSidebar.prototype.init.call(this, htmlElement);\n\n        // -- Pages --\n        this._pagesPanel = $('<div></div>')\n            .addClass('pages');\n\n        this._pageAddControl =\n            $('<button></button>')\n                // TODO : I18N\n                .attr('title', 'Add Page')\n                .on('click', function () {\n                    gApp.executeAction(GAddPageAction.ID);\n                }.bind(this))\n                .append($('<span></span>')\n                    .addClass('fa fa-plus'));\n\n        this._pageDeleteControl =\n            $('<button></button>')\n                // TODO : I18N\n                .attr('title', 'Delete Page')\n                .on('click', function () {\n                    gApp.executeAction(GDeletePageAction.ID);\n                }.bind(this))\n                .append($('<span></span>')\n                    .addClass('fa fa-trash-o'));\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Pages',\n                content: this._pagesPanel,\n                controls: [\n                    this._pageAddControl,\n                    this._pageDeleteControl\n                ]\n            })\n            .appendTo(htmlElement);\n\n        // -- Layers --\n        this._layersTree = $('<div></div>')\n            .addClass('layers')\n            .tree({\n                data: [],\n                dragAndDrop: true,\n                openFolderDelay: 500,\n                closedIcon: $('<span class=\"fa fa-caret-right\"></span>'),\n                openedIcon: $('<span class=\"fa fa-caret-down\"></span>'),\n                slide: false,\n                selectable: false,\n                onIsMoveHandle: function ($element) {\n                    return ($element.is('.jqtree-title'));\n                },\n                onCreateLi: this._createLayerTreeItem.bind(this),\n                onCanMoveTo: this._canMoveLayerTreeNode.bind(this)\n            })\n            .on('tree.open', function (evt) {\n                if (evt.node.layerOrItem) {\n                    evt.node.layerOrItem.setFlag(IFNode.Flag.Expanded);\n                }\n            }.bind(this))\n            .on('tree.close', function (evt) {\n                if (evt.node.layerOrItem) {\n                    evt.node.layerOrItem.removeFlag(IFNode.Flag.Expanded);\n                }\n            }.bind(this))\n            .on('tree.click', this._clickLayerTreeNode.bind(this))\n            .on('tree.move', this._moveLayerTreeNode.bind(this));\n\n        this._layerAddControl =\n            $('<button></button>')\n                // TODO : I18N\n                .attr('title', 'Add Layer')\n                .on('click', function () {\n                    gApp.executeAction(GAddLayerAction.ID);\n                }.bind(this))\n                .append($('<span></span>')\n                    .addClass('fa fa-plus'));\n\n        this._layerDeleteControl =\n            $('<button></button>')\n                // TODO : I18N\n                .attr('title', 'Delete Layer')\n                .on('click', function () {\n                    gApp.executeAction(GDeleteLayerAction.ID);\n                }.bind(this))\n                .append($('<span></span>')\n                    .addClass('fa fa-trash-o'));\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Layers',\n                content: this._layersTree,\n                controls: [\n                    this._layerAddControl,\n                    this._layerDeleteControl\n                ]\n            })\n            .appendTo(htmlElement);\n    };\n\n    /** @override */\n    GPagesLayersSidebar.prototype._documentEvent = function (event) {\n        if (event.type === GApplication.DocumentEvent.Type.Activated) {\n            this._document = event.document;\n            var scene = this._document.getScene();\n            scene.addEventListener(IFNode.AfterInsertEvent, this._afterNodeInsert, this);\n            scene.addEventListener(IFNode.BeforeRemoveEvent, this._beforeNodeRemove, this);\n            scene.addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            scene.addEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n            scene.addEventListener(IFScene.ReferenceEvent, this._referenceEvent, this);\n            this._clear();\n        } else if (event.type === GApplication.DocumentEvent.Type.Deactivated) {\n            var scene = this._document.getScene();\n            this._document = null;\n            scene.removeEventListener(IFNode.AfterInsertEvent, this._afterNodeInsert, this);\n            scene.removeEventListener(IFNode.BeforeRemoveEvent, this._beforeNodeRemove, this);\n            scene.removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n            scene.removeEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n            scene.removeEventListener(IFScene.ReferenceEvent, this._referenceEvent, this);\n            this._clear();\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._clear = function () {\n        // first clear layers, then pages\n        this._clearLayers();\n        this._clearPages();\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._clearPages = function () {\n        this._pagesPanel.empty();\n        if (this._document) {\n            var scene = this._document.getScene();\n            for (var child = scene.getFirstChild(); child !== null; child = child.getNext()) {\n                if (child instanceof IFPage) {\n                    this._insertPage(child);\n                }\n            }\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._insertPage = function (page) {\n        var insertBefore = null;\n        if (page.getNext()) {\n            this._pagesPanel.find('.page-block').each(function (index, element) {\n                var $element = $(element);\n                if ($element.data('page') === page.getNext()) {\n                    insertBefore = $element;\n                    return false;\n                }\n            });\n        }\n\n        var block = $('<div></div>')\n            .addClass('page-block')\n            .data('page', page)\n            .attr('draggable', 'true')\n            .append($('<div></div>')\n                .addClass('page-visibility')\n                // TODO : I18N\n                .attr('title', 'Toggle Page Visibility')\n                .on('click', function (evt) {\n                    evt.stopPropagation();\n                    // TODO : I18N\n                    IFEditor.tryRunTransaction(page, function () {\n                        page.setProperty('visible', !page.getProperty('visible'));\n                    }, 'Toggle Page Visibility');\n                })\n                .append($('<span></span>')\n                    .addClass('fa fa-fw')))\n            .append($('<div></div>')\n                .addClass('page-lock')\n                // TODO : I18N\n                .attr('title', 'Toggle Page Lock')\n                .on('click', function (evt) {\n                    evt.stopPropagation();\n                    // TODO : I18N\n                    IFEditor.tryRunTransaction(page, function () {\n                        page.setProperty('locked', !page.getProperty('locked'));\n                    }, 'Toggle Page Lock');\n                })\n                .append($('<span></span>')\n                    .addClass('fa fa-fw')))\n            .append($('<div></div>')\n                .addClass('page-name')\n                .gAutoEdit({\n                })\n                .on('submitvalue', function (evt, value) {\n                    if (value && value.trim() !== '') {\n                        // TODO : I18N\n                        IFEditor.tryRunTransaction(page, function () {\n                            page.setProperty('name', value);\n                        }, 'Rename Page');\n                    }\n                }))\n            .append($('<div></div>')\n                .addClass('page-master')\n                .append($('<span></span>')\n                    .addClass('fa fa-fw')))\n            .on('mousedown', function () {\n                // TODO\n            })\n            .on('click', function () {\n                page.getScene().setActivePage(page);\n            })\n            .on('dragstart', function (evt) {\n                var $this = $(this);\n\n                var event = evt.originalEvent;\n                event.stopPropagation();\n\n                dragPage = $this.data('page');\n\n                // Setup our drag-event now\n                event.dataTransfer.effectAllowed = 'move';\n                event.dataTransfer.setData('text/plain', 'dummy_data');\n\n                // Add drag overlays\n                $this.closest('.pages').find('.page-block').each(function (index, element) {\n                    $(element)\n                        .append($('<div></div>')\n                            .addClass('drag-overlay')\n                            .on('dragenter', function (evt) {\n                                if (canDropPage(this.parentNode)) {\n                                    $(this).parent().addClass('drop');\n                                }\n                            })\n                            .on('dragleave', function (evt) {\n                                if (canDropPage(this.parentNode)) {\n                                    $(this).parent().removeClass('drop');\n                                }\n                            })\n                            .on('dragover', function (evt) {\n                                var event = evt.originalEvent;\n                                if (canDropPage(this.parentNode)) {\n                                    event.preventDefault();\n                                    event.stopPropagation();\n                                    event.dataTransfer.dropEffect = 'move';\n                                }\n                            })\n                            .on('drop', function (evt) {\n                                var $this = $(this);\n                                var $parent = $(this.parentNode);\n\n                                $parent.removeClass('drop');\n\n                                // Remove drag overlays\n                                $parent.closest('.pages').find('.drag-overlay').remove();\n\n                                var targetPage = $parent.data('page');\n                                if (dragPage && dragPage.getParent() === targetPage.getParent()) {\n                                    var parent = dragPage.getParent();\n                                    var sourceIndex = parent.getIndexOfChild(dragPage);\n                                    var targetIndex = parent.getIndexOfChild(targetPage);\n\n                                    // TODO : I18N\n                                    IFEditor.tryRunTransaction(parent, function () {\n                                        if (ifPlatform.modifiers.shiftKey) {\n                                            // Clone page\n                                            var insertPos = dragPage.getScene().getPageInsertPosition();\n                                            var pageClone = dragPage.clone();\n                                            pageClone.setProperties(['x', 'y', 'name'], [insertPos.getX(), insertPos.getY(), pageClone.getProperty('name') + '-copy']);\n                                            parent.insertChild(pageClone, sourceIndex < targetIndex ? targetPage.getNext() : targetPage);\n                                        } else {\n                                            // Move page\n                                            parent.removeChild(dragPage);\n                                            parent.insertChild(dragPage, sourceIndex < targetIndex ? targetPage.getNext() : targetPage);\n                                        }\n                                    }, ifPlatform.modifiers.shiftKey ? 'Duplicate Page' : 'Move Page');\n                                }\n                            }));\n                });\n            })\n            .on('dragend', function (evt) {\n                var $this = $(this);\n\n                var event = evt.originalEvent;\n                event.stopPropagation();\n\n                // Remove drag overlays\n                $this.closest('.pages').find('.drag-overlay').remove();\n\n                dragPage = null;\n            });\n\n        if (insertBefore && insertBefore.length > 0) {\n            block.insertBefore(insertBefore);\n        } else {\n            block.appendTo(this._pagesPanel);\n        }\n\n        this._updatePage(page);\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._updatePage = function (page) {\n        var pageVisible = page.getProperty('visible');\n        var pageLocked = page.getProperty('locked');\n\n        this._pagesPanel.find('.page-block').each(function (index, element) {\n            var $element = $(element);\n            if ($element.data('page') === page) {\n                $element.toggleClass('g-active', page.hasFlag(IFNode.Flag.Active));\n                $element.toggleClass('g-selected', page.hasFlag(IFNode.Flag.Selected));\n\n                $element.find('.page-visibility')\n                    .toggleClass('page-default', pageVisible)\n                    /*!!*/\n                    .find('> span')\n                    .toggleClass('fa-eye', pageVisible)\n                    .toggleClass('fa-eye-slash', !pageVisible);\n\n                $element.find('.page-lock')\n                    .toggleClass('page-default', !pageLocked)\n                    /*!!*/\n                    .find('> span')\n                    .toggleClass('fa-lock', pageLocked)\n                    .toggleClass('fa-unlock', !pageLocked);\n\n                $element.find('.page-name').text(page.getProperty('name'));\n\n                var linkCount = page.getScene().linkCount(page);\n                var master = page.getMasterPage();\n                var masterTitle = '';\n\n                if (linkCount) {\n                    // TODO : I18N\n                    masterTitle = 'Master of ' + linkCount.toString() + ' pages:';\n                    page.getScene().visitLinks(page, function (pageSource) {\n                        masterTitle += '\\n' + pageSource.getLabel();\n                    })\n                }\n                if (master) {\n                    if (masterTitle !== '') {\n                        masterTitle += '\\n\\n';\n                    }\n                    masterTitle += 'Slave of ' + master.getLabel();\n                }\n\n                $element.find('.page-master')\n                    .css('display', !!master || linkCount > 0 ? '' : 'none')\n                    /*!!*/\n                    .find('> span')\n                    .attr('title', masterTitle)\n                    .toggleClass('fa-link', !!master && linkCount === 0)\n                    .toggleClass('fa-crosshairs', linkCount > 0);\n                return false;\n            }\n        });\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._removePage = function (page) {\n        this._pagesPanel.find('.page-block').each(function (index, element) {\n            var $element = $(element);\n            if ($element.data('page') === page) {\n                $element.remove();\n                return false;\n            }\n        });\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._clearLayers = function () {\n        // Clear layer tree and mark root opened afterwards (!!)\n        this._layersTree.tree('loadData', []);\n        this._layersTree.tree('getTree').is_open = true;\n\n        this._layersTreeNodeMap = [];\n\n        if (this._document) {\n            var activePage = this._document.getScene().getActivePage();\n            if (activePage) {\n                for (var child = activePage.getFirstChild(); child !== null; child = child.getNext()) {\n                    if (child instanceof IFLayer) {\n                        this._insertLayer(child);\n                    }\n                }\n            }\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._insertLayer = function (layerOrItem) {\n        // Create an unique treeId for the new tree node\n        var treeId = ifUtil.uuid();\n\n        // Either insert before or append\n        var nextNode = layerOrItem.getNext() ? this._getLayerTreeNode(layerOrItem.getNext()) : null;\n        if (nextNode) {\n            this._layersTree.tree('addNodeBefore', { id: treeId, layerOrItem: layerOrItem }, nextNode);\n        } else {\n            var parent = layerOrItem.getParent();\n            var parentTreeNode = !parent || parent instanceof IFPage ? null : this._getLayerTreeNode(parent);\n            this._layersTree.tree('appendNode', { id: treeId, layerOrItem: layerOrItem }, parentTreeNode);\n        }\n\n        // Insert the mapping\n        this._layersTreeNodeMap.push({\n            node: layerOrItem,\n            treeId: treeId\n        });\n\n        // Make an initial update\n        this._updateLayer(layerOrItem);\n\n        // Iterate children and add them as well\n        if (layerOrItem.hasMixin(IFNode.Container)) {\n            for (var child = layerOrItem.getFirstChild(); child !== null; child = child.getNext()) {\n                if (child instanceof IFLayer || child instanceof IFItem) {\n                    this._insertLayer(child);\n                }\n            }\n        }\n\n        // Gather the new treenode for our node\n        var treeNode = this._getLayerTreeNode(layerOrItem);\n\n        // Select if item and selected\n        if (layerOrItem instanceof IFItem && layerOrItem.hasFlag(IFNode.Flag.Selected)) {\n            this._layersTree.tree('selectNode', treeNode);\n        }\n\n        // Open entry if collapsed\n        if (layerOrItem.hasFlag(IFNode.Flag.Expanded)) {\n            this._layersTree.tree('openNode', treeNode, false);\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._updateLayer = function (layerOrItem) {\n        // Gather a tree node for the item\n        var treeNode = this._getLayerTreeNode(layerOrItem);\n\n        if (treeNode) {\n            // Call an update for the node\n            var label = layerOrItem.getLabel();\n\n            // Mark draft layers\n            if (layerOrItem instanceof IFLayer && layerOrItem.getProperty('tp') === IFLayer.Type.Draft) {\n                label = '*' + label;\n            }\n\n            this._layersTree.tree('updateNode', treeNode, label);\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._removeLayer = function (layerOrItem) {\n        var treeNode = this._getLayerTreeNode(layerOrItem);\n        if (treeNode) {\n            this._layersTree.tree('removeNode', treeNode);\n\n            // Visit to remove each mapping as well\n            layerOrItem.accept(function (node) {\n                if (node instanceof IFLayer || node instanceof IFItem) {\n                    for (var i = 0; i < this._layersTreeNodeMap.length; ++i) {\n                        if (this._layersTreeNodeMap[i].node === node) {\n                            this._layersTreeNodeMap.splice(i, 1);\n                            break;\n                        }\n                    }\n                }\n            }.bind(this));\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterInsertEvent} event\n     * @private\n     */\n    GPagesLayersSidebar.prototype._afterNodeInsert = function (event) {\n        if (event.node instanceof IFPage) {\n            this._insertPage(event.node);\n        } else if (event.node instanceof IFLayer || event.node instanceof IFItem) {\n            var activePage = this._document.getScene().getActivePage();\n            if (event.node.getPage() === activePage) {\n                this._insertLayer(event.node);\n            }\n        }\n    };\n\n    /**\n     * @param {IFNode.BeforeRemoveEvent} event\n     * @private\n     */\n    GPagesLayersSidebar.prototype._beforeNodeRemove = function (event) {\n        if (event.node instanceof IFPage) {\n            this._removePage(event.node);\n        } else if (event.node instanceof IFLayer || event.node instanceof IFItem) {\n            this._removeLayer(event.node);\n\n            // If parent has no more children then update it accordingly\n            var parent = event.node.getParent();\n\n            if (parent instanceof IFLayer || parent instanceof IFItem) {\n                var hasChildren = false;\n                for (var child = parent.getFirstChild(); child !== null; child = child.getNext()) {\n                    if ((child instanceof IFLayer || child instanceof IFItem) && child !== event.node) {\n                        hasChildren = true;\n                        break;\n                    }\n                }\n\n                if (!hasChildren) {\n                    parent.removeFlag(IFNode.Flag.Expanded);\n                    this._updateLayer(parent);\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    GPagesLayersSidebar.prototype._afterPropertiesChange = function (event) {\n        if (event.node instanceof IFPage) {\n            this._updatePage(event.node);\n        } else if (event.node instanceof IFLayer || event.node instanceof IFItem) {\n            this._updateLayer(event.node);\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterFlagChangeEvent} event\n     * @private\n     */\n    GPagesLayersSidebar.prototype._afterFlagChange = function (event) {\n        if (event.node instanceof IFPage && (event.flag === IFNode.Flag.Active || event.flag === IFNode.Flag.Selected)) {\n            this._pagesPanel.find('.page-block').each(function (index, element) {\n                var $element = $(element);\n                if ($element.data('page') === event.node) {\n                    $element.toggleClass(event.flag === IFNode.Flag.Active ? 'g-active' : 'g-selected', event.set);\n                }\n            });\n\n            if (event.flag === IFNode.Flag.Active) {\n                // Page activeness change requires clearing layers\n                this._clearLayers();\n            }\n        } else if (event.node instanceof IFLayer && (event.flag === IFNode.Flag.Active || event.flag === IFNode.Flag.Selected || event.flag === IFNode.Flag.Expanded)) {\n            this._updateLayer(event.node);\n        } else if (event.node instanceof IFItem && event.flag === IFNode.Flag.Selected) {\n            this._updateLayer(event.node);\n        } else if ((event.node instanceof IFLayer || event.node instanceof IFItem) && (event.flag === IFElement.Flag.Hidden || event.flag === IFElement.Flag.Locked)) {\n            this._updateLayer(event.node);\n        }\n    };\n\n    /**\n     * @param {IFScene.ReferenceEvent} event\n     * @private\n     */\n    GPagesLayersSidebar.prototype._referenceEvent = function (event) {\n        if (event.reference instanceof IFPage) {\n            this._updatePage(event.reference);\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._clickLayerTreeNode = function (evt) {\n        if (evt.node.layerOrItem) {\n            if (evt.node.layerOrItem instanceof IFLayer) {\n                this._document.getScene().setActiveLayer(evt.node.layerOrItem);\n            } else if (evt.node.layerOrItem instanceof IFItem) {\n                if (ifPlatform.modifiers.shiftKey || !evt.node.layerOrItem.hasFlag(IFNode.Flag.Selected)) {\n                    // Add element to selection\n                    this._document.getEditor().updateSelection(ifPlatform.modifiers.shiftKey, [evt.node.layerOrItem]);\n                } else if (evt.node.layerOrItem.hasFlag(IFNode.Flag.Selected)) {\n                    // Clear selection leaving only the one element\n                    this._document.getEditor().clearSelection([evt.node.layerOrItem]);\n                }\n            }\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._createLayerTreeItem = function (node, li) {\n        if (node.layerOrItem) {\n            var layerOrItem = node.layerOrItem;\n\n            // Iterate parents up and collect some information\n            var itemLevel = 0;\n            var parentHidden = false;\n            var parentLocked = false;\n            var parentOutlined = false;\n\n            for (var p = layerOrItem.getParent(); p !== null; p = p.getParent()) {\n                // Stop on page root\n                if (p instanceof IFPage) {\n                    break;\n                }\n\n                // Query information\n                parentHidden = p.getProperty('visible') === false || parentHidden;\n                parentLocked = p.getProperty('locked') === true || parentLocked;\n\n                if (p instanceof IFLayer) {\n                    parentOutlined = p.getProperty('otl') === true || parentOutlined;\n                }\n\n                itemLevel += 1;\n            }\n\n            var isHidden = parentHidden || layerOrItem.getProperty('visible') === false;\n            var isLocked = parentLocked || layerOrItem.getProperty('locked') === true;\n            var isOutlined = parentOutlined || (layerOrItem instanceof IFLayer && layerOrItem.getProperty('otl'));\n\n            // Gather a reference to the element container\n            var container = li.find('div.jqtree-element');\n            var title = container.find('> .jqtree-title');\n\n            // First, we'll make our title editable and toogle active/selected\n            container\n                .toggleClass('g-active', layerOrItem.hasFlag(IFNode.Flag.Active))\n                .toggleClass('g-selected', layerOrItem.hasFlag(IFNode.Flag.Selected))\n                .gAutoEdit({\n                    selector: '> .jqtree-title'\n                })\n                .on('submitvalue', function (evt, value) {\n                    // TODO : I18M\n                    if (value && value.trim() !== '') {\n                        IFEditor.tryRunTransaction(layerOrItem, function () {\n                            layerOrItem.setProperty('name', value);\n                        }, 'Rename Layer/Item');\n                    }\n                });\n\n            // Prepend level spacers\n            for (var i = 0; i < itemLevel; ++i) {\n                $('<span></span>')\n                    .addClass('layer-spacer')\n                    .prependTo(container);\n            }\n\n            // Figure an icon for the item if any\n            var icon = null;\n            if (layerOrItem instanceof IFLayer) {\n                icon = layerOrItem.hasFlag(IFNode.Flag.Expanded) ? 'folder-open' : 'folder';\n            } else if (layerOrItem instanceof IFSlice) {\n                icon = 'crop';\n            } else if (layerOrItem instanceof IFShape) {\n                if (layerOrItem instanceof IFText) {\n                    icon = 'font';\n                } else if (layerOrItem instanceof IFImage) {\n                    icon = 'image';\n                } else if (layerOrItem instanceof IFEllipse) {\n                    icon = 'circle';\n                } else if (layerOrItem instanceof IFRectangle) {\n                    icon = 'stop';\n                } else if (layerOrItem instanceof IFPath) {\n                    icon = 'pencil';\n                } else if (layerOrItem instanceof IFPolygon) {\n                    icon = 'star';\n                }\n            }\n\n            if (icon) {\n                $('<span></span>')\n                    .addClass('layer-icon fa fa-' + icon)\n                    .insertBefore(title);\n            }\n\n            // Prepend locked and visibility markers\n            $('<span></span>')\n                .addClass('layer-lock fa fa-fw fa-' + (isLocked ? 'lock' : 'unlock'))\n                .toggleClass('layer-default', !isLocked)\n                // TODO : I18N\n                .attr('title', 'Toggle Lock')\n                .on('click', function (evt) {\n                    evt.stopPropagation();\n                    if (!parentLocked) {\n                        // TODO : I18N\n                        IFEditor.tryRunTransaction(layerOrItem, function () {\n                            layerOrItem.setProperty('locked', !layerOrItem.getProperty('locked'));\n                        }, 'Toggle Layer Locked');\n                    }\n                })\n                .prependTo(container);\n\n            var visibleContainer = $('<span></span>')\n                .addClass('layer-visibility fa fa-' + (isHidden ? 'eye-slash' : 'eye'))\n                .toggleClass('layer-default', !isHidden)\n                // TODO : I18N\n                .attr('title', 'Toggle Visibility')\n                .on('click', function (evt) {\n                    evt.stopPropagation();\n                    if (!parentHidden) {\n                        var show = !layerOrItem.getProperty('visible');\n\n                        // Remove highlight when made invisible\n                        if (!show) {\n                            layerOrItem.removeFlag(IFNode.Flag.Highlighted);\n                        }\n\n                        // TODO : I18N\n                        IFEditor.tryRunTransaction(layerOrItem, function () {\n                            layerOrItem.setProperty('visible', show);\n                        }, 'Toggle Layer Visibility');\n\n                        // Show highlight when made visible\n                        if (show) {\n                            layerOrItem.setFlag(IFNode.Flag.Highlighted);\n                        }\n                    }\n                })\n                .on('mouseenter', function (evt) {\n                    if (!layerOrItem.hasFlag(IFElement.Flag.Hidden)) {\n                        layerOrItem.setFlag(IFNode.Flag.Highlighted);\n                    }\n                })\n                .on('mouseleave', function (evt) {\n                    if (!layerOrItem.hasFlag(IFElement.Flag.Hidden)) {\n                        layerOrItem.removeFlag(IFNode.Flag.Highlighted);\n                    }\n                })\n                .prependTo(container);\n\n            // Append outline & color for layers\n            if (layerOrItem instanceof IFLayer) {\n                // Don't add outline for guide layers\n                if (layerOrItem.getProperty('tp') !== IFLayer.Type.Guide) {\n                    $('<span></span>')\n                        .addClass('layer-outline fa fa-' + (isOutlined ? 'circle-o' : 'circle'))\n                        .toggleClass('layer-default', !isOutlined)\n                        // TODO : I18N\n                        .attr('title', 'Toggle Outline')\n                        .on('click', function (evt) {\n                            evt.stopPropagation();\n                            if (!parentHidden) {\n                                // TODO : I18N\n                                IFEditor.tryRunTransaction(layerOrItem, function () {\n                                    layerOrItem.setProperty('otl', !layerOrItem.getProperty('otl'));\n                                }, 'Toggle Layer Outline');\n                            }\n                        })\n                        .appendTo(container);\n                }\n\n                $('<span></span>')\n                    .addClass('layer-color')\n                    .gColorButton({\n                        scene: this._document.getScene(),\n                        immediateClose: true\n                    })\n                    .gColorButton('value', layerOrItem.getProperty('cls'))\n                    .removeClass('g-input')\n                    .on('click', function (evt) {\n                        evt.stopPropagation();\n                    })\n                    .on('colorchange', function (evt, color) {\n                        // TODO : I18N\n                        IFEditor.tryRunTransaction(layerOrItem, function () {\n                            var myColor = layerOrItem.getProperty('cls');\n                            layerOrItem.setProperty('cls', color);\n\n                            // Apply color to all child layers recursively that\n                            // do have the same color as our layer\n                            layerOrItem.acceptChildren(function (node) {\n                                if (node instanceof IFLayer) {\n                                    var childColor = node.getProperty('cls');\n                                    if (IFColor.equals(childColor, myColor)) {\n                                        node.setProperty('cls', color);\n                                    }\n                                }\n                            });\n                        }, 'Change Layer Color');\n                    })\n                    .appendTo(container);\n            }\n        }\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._canMoveLayerTreeNode = function (moved_node, target_node, position) {\n        return this._getLayerTreeNodeMoveInfo(position, moved_node.layerOrItem, target_node.layerOrItem) !== null;\n    };\n\n    /** @private */\n    GPagesLayersSidebar.prototype._moveLayerTreeNode = function (event) {\n        event.preventDefault();\n\n        var moveInfo = this._getLayerTreeNodeMoveInfo(event.move_info.position,\n            event.move_info.moved_node.layerOrItem, event.move_info.target_node.layerOrItem);\n\n        if (moveInfo) {\n            // TODO : I18N\n            IFEditor.tryRunTransaction(this._document.getScene(), function () {\n                moveInfo.source.getParent().removeChild(moveInfo.source);\n                moveInfo.parent.insertChild(moveInfo.source, moveInfo.before);\n\n                // Having dragged something inside requires to expand parent(s) and update 'em'\n                var rootParent = null;\n                for (var parent = moveInfo.parent; parent !== null; parent = parent.getParent()) {\n                    if (parent instanceof IFPage) {\n                        break;\n                    }\n\n                    parent.setFlag(IFNode.Flag.Expanded);\n                    rootParent = parent;\n                }\n\n                this._updateLayer(rootParent);\n            }.bind(this), 'Move Layer/Item');\n        }\n    };\n\n    /**\n     * @param event\n     * @return {{parent: IFNode, before: IFNode, source: IFNode}} the result of the move\n     * or null if the actual move is not allowed\n     * @private\n     */\n    GPagesLayersSidebar.prototype._getLayerTreeNodeMoveInfo = function (position, source, target) {\n        target = target || this._document.getScene().getActivePage();\n\n        if (source && target && position !== 'none') {\n            var parent = null;\n            var before = null;\n\n            if (position === 'inside') {\n                parent = target;\n                before = target.getFirstChild();\n            } else if (position === 'before') {\n                if (target instanceof IFPage) {\n                    parent = target;\n                    before = target.getFirstChild();\n                } else {\n                    parent = target.getParent();\n                    before = target;\n                }\n            } else if (position == 'after') {\n                if (target instanceof IFPage) {\n                    parent = target;\n                    before = null;\n                } else {\n                    parent = target.getParent();\n                    before = target.getNext();\n                }\n            }\n\n            if (before === source) {\n                // we can not insert before ourself\n                return null;\n            }\n\n            if (source.validateInsertion(parent, before)) {\n                return {\n                    parent: parent,\n                    before: before,\n                    source: source\n                };\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * @param {IFNode} node\n     * @return {*}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._getLayerTreeNodeId = function (node) {\n        if (this._layersTreeNodeMap) {\n            for (var i = 0; i < this._layersTreeNodeMap.length; ++i) {\n                if (this._layersTreeNodeMap[i].node === node) {\n                    return this._layersTreeNodeMap[i].treeId;\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {IFNode} node\n     * @return {*}\n     * @private\n     */\n    GPagesLayersSidebar.prototype._getLayerTreeNode = function (node) {\n        return this._layersTree.tree('getNodeById', this._getLayerTreeNodeId(node));\n    };\n\n    /** @override */\n    GPagesLayersSidebar.prototype.toString = function () {\n        return \"[Object GPagesLayersSidebar]\";\n    };\n\n    _.GPagesLayersSidebar = GPagesLayersSidebar;\n})(this);"
  },
  {
    "path": "src/gravit/sidebar/stylesswatchessidebar.js",
    "content": "(function (_) {\n\n    /**\n     * The styles sidebar\n     * @class GStylesSwatchesSidebar\n     * @extends GSidebar\n     * @constructor\n     */\n    function GStylesSwatchesSidebar() {\n        GSidebar.call(this);\n    }\n\n    IFObject.inherit(GStylesSwatchesSidebar, GSidebar);\n\n    GStylesSwatchesSidebar.ID = \"swatches-layers\";\n    GStylesSwatchesSidebar.TITLE = new IFLocale.Key(GStylesSwatchesSidebar, \"title\");\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylesSwatchesSidebar.prototype._stylePanel = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylesSwatchesSidebar.prototype._swatchPanel = null;\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GStylesSwatchesSidebar.prototype._swatchDeleteControl = null;\n\n    /** @override */\n    GStylesSwatchesSidebar.prototype.getId = function () {\n        return GStylesSwatchesSidebar.ID;\n    };\n\n    /** @override */\n    GStylesSwatchesSidebar.prototype.getTitle = function () {\n        return GStylesSwatchesSidebar.TITLE;\n    };\n\n    /** @override */\n    GStylesSwatchesSidebar.prototype.getIcon = function () {\n        return '<span class=\"fa fa-fw fa-leaf\"></span>';\n    };\n\n    /** @override */\n    GStylesSwatchesSidebar.prototype.init = function (htmlElement) {\n        GSidebar.prototype.init.call(this, htmlElement);\n\n        this._stylePanel = $('<div></div>')\n            .addClass('g-style-list')\n            .gStylePanel({\n                allowNameEdit: true,\n                // TODO : I18N\n                placeholder: 'No Shared Styles'\n            })\n            .on('stylechange', function (evt, style) {\n                this._document.getScene().getStyleCollection().acceptChildren(function (node) {\n                    node.removeFlag(IFNode.Flag.Selected);\n                });\n\n                if (style) {\n                    style.setFlag(IFNode.Flag.Selected);\n                }\n\n                this._updateStyleControls();\n            }.bind(this));\n\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Shared Styles',\n                content: this._stylePanel\n            })\n            .appendTo(htmlElement);\n\n        this._swatchPanel = $('<div></div>')\n            .addClass('g-swatch-list')\n            .gSwatchPanel({\n                allowNameEdit: true,\n                // TODO : I18N\n                placeholder: 'Drop Swatches here'\n            })\n            .on('swatchchange', function (evt, swatch) {\n                this._document.getScene().getSwatchCollection().acceptChildren(function (node) {\n                    node.removeFlag(IFNode.Flag.Selected);\n                });\n\n                if (swatch) {\n                    swatch.setFlag(IFNode.Flag.Selected);\n                }\n\n                this._updateSwatchControls();\n            }.bind(this));\n\n        this._swatchDeleteControl = $('<button></button>')\n            // TODO : I18N\n            .attr('title', 'Delete Selected Swatch')\n            .on('click', function () {\n                var swatch = this._swatchPanel.gSwatchPanel('value');\n                var editor = this._document.getEditor();\n                editor.beginTransaction();\n                try {\n                    swatch.getParent().removeChild(swatch);\n                } finally {\n                    editor.commitTransaction('Delete Swatch');\n                }\n            }.bind(this))\n            .append($('<span></span>')\n                .addClass('fa fa-trash-o'));\n\n        this._updateStyleControls();\n        this._updateSwatchControls();\n\n        $('<div></div>')\n            .gPanel({\n                // TODO : I18N\n                title: 'Swatches',\n                content: this._swatchPanel,\n                controls: [\n                    this._swatchDeleteControl\n                ]\n            })\n            .appendTo(htmlElement);\n    };\n\n    /** @override */\n    GStylesSwatchesSidebar.prototype._documentEvent = function (event) {\n        if (event.type === GApplication.DocumentEvent.Type.Activated) {\n            this._document = event.document;\n            var scene = this._document.getScene();\n            this._stylePanel.gStylePanel('attach', scene.getStyleCollection());\n            this._stylePanel.gStylePanel('value', scene.getStyleCollection().querySingle('sharedStyle:selected'));\n            this._swatchPanel.gSwatchPanel('attach', scene.getSwatchCollection());\n            this._swatchPanel.gSwatchPanel('value', scene.getSwatchCollection().querySingle('swatch:selected'));\n            this._updateStyleControls();\n            this._updateSwatchControls();\n        } else if (event.type === GApplication.DocumentEvent.Type.Deactivated) {\n            var scene = this._document.getScene();\n            this._document = null;\n            this._stylePanel.gStylePanel('detach');\n            this._swatchPanel.gSwatchPanel('detach');\n            this._updateStyleControls();\n            this._updateSwatchControls();\n        }\n    };\n\n    /** @private */\n    GStylesSwatchesSidebar.prototype._updateStyleControls = function () {\n        var style = this._stylePanel.gStylePanel('value');\n        //TODO...\n    };\n\n    /** @private */\n    GStylesSwatchesSidebar.prototype._updateSwatchControls = function () {\n        var swatch = this._swatchPanel.gSwatchPanel('value');\n        this._swatchDeleteControl.prop('disabled', !swatch);\n    };\n\n    /** @override */\n    GStylesSwatchesSidebar.prototype.toString = function () {\n        return \"[Object GStylesSwatchesSidebar]\";\n    };\n\n    _.GStylesSwatchesSidebar = GStylesSwatchesSidebar;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/areapaintentry.js",
    "content": "(function (_) {\n\n    /**\n     * Area pattern paint style entry handler\n     * @class GAreaPaintEntry\n     * @extends GPatternPaintEntry\n     * @constructor\n     */\n    function GAreaPaintEntry() {\n        GPatternPaintEntry.call(this);\n    }\n\n    IFObject.inherit(GAreaPaintEntry, GPatternPaintEntry);\n\n    /** @override */\n    GAreaPaintEntry.prototype.createContent = function (scene, assign, revert) {\n        var content = GPatternPaintEntry.prototype.createContent.call(this, scene, assign, revert);\n\n        $('<div></div>')\n            .attr('data-element', 'transform')\n            .append($('<div></div>')\n                .append($('<input>')\n                    .attr('data-property', 'tx')\n                    .css('width', '3em')\n                    .on('change', function (evt) {\n                        var value = IFLength.parseEquationValue($(evt.target).val());\n                        if (value !== null) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    .text('X')))\n            .append($('<div></div>')\n                .append($('<input>')\n                    .attr('data-property', 'ty')\n                    .css('width', '3em')\n                    .on('change', function (evt) {\n                        var value = IFLength.parseEquationValue($(evt.target).val());\n                        if (value !== null) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    .text('Y')))\n            .append($('<div></div>')\n                .append($('<input>')\n                    .css('width', '3em')\n                    .attr('data-property', 'sx')\n                    .on('change', function (evt) {\n                        var value = IFLength.parseEquationValue($(evt.target).val());\n                        if (value !== null && value !== 0.0) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('W')))\n            .append($('<div></div>')\n                .append($('<input>')\n                    .attr('data-property', 'sy')\n                    .css('width', '3em')\n                    .on('change', function (evt) {\n                        var value = IFLength.parseEquationValue($(evt.target).val());\n                        if (value !== null && value !== 0.0) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('H')))\n            .append($('<div></div>')\n                .append($('<input>')\n                    .attr('data-property', 'rt')\n                    .css('width', '3em')\n                    .on('change', function (evt) {\n                        var value = IFLength.parseEquationValue($(evt.target).val());\n                        if (value !== null) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    .text('°')))\n            .appendTo(content);\n\n        return content;\n    };\n\n    /** @override */\n    GAreaPaintEntry.prototype.updateProperties = function (content, entry, scene) {\n        GPatternPaintEntry.prototype.updateProperties.call(this, content, entry, scene);\n\n        var pattern = entry.getProperty('pat');\n        var patternType = pattern ? pattern.getPatternType() : null;\n\n        // Transform\n        var transformContent = content.find('[data-element=\"transform\"]');\n        if (patternType !== IFPattern.Type.Color) {\n            transformContent.css('display', '');\n            transformContent.find('[data-property=\"tx\"]').val(ifUtil.formatNumber(entry.getProperty('tx') * 100));\n            transformContent.find('[data-property=\"ty\"]').val(ifUtil.formatNumber(entry.getProperty('ty') * 100));\n            transformContent.find('[data-property=\"sx\"]').val(ifUtil.formatNumber(entry.getProperty('sx') * 100));\n\n\n            transformContent.find('[data-property=\"sy\"]')\n                .val(ifUtil.formatNumber(entry.getProperty('sy') * 100))\n                .closest('div') // !! -->\n                .css('display', pattern.getType() === IFGradient.Type.Linear ? 'none' : '');\n\n            transformContent.find('[data-property=\"rt\"]').val(ifUtil.formatNumber(ifMath.toDegrees(entry.getProperty('rt')), 2));\n        } else {\n            transformContent.css('display', 'none');\n        }\n    };\n\n    /** @override */\n    GAreaPaintEntry.prototype._getPropertiesToAssign = function (content, entry, scene, properties, values) {\n        GPatternPaintEntry.prototype._getPropertiesToAssign.call(this, content, entry, scene, properties, values);\n\n        properties.push(\n            'tx',\n            'ty',\n            'sx',\n            'sy',\n            'rt'\n        );\n\n        var tx = IFLength.parseEquationValue(content.find('[data-property=\"tx\"]').val());\n        var ty = IFLength.parseEquationValue(content.find('[data-property=\"ty\"]').val());\n        var sx = IFLength.parseEquationValue(content.find('[data-property=\"sx\"]').val());\n        var sy = IFLength.parseEquationValue(content.find('[data-property=\"sy\"]').val());\n        var rt = IFLength.parseEquationValue(content.find('[data-property=\"rt\"]').val());\n\n        var tx = tx !== null ? tx / 100 : 0;\n        var ty = ty !== null ? ty / 100 : 0;\n        var sx = sx !== null ? sx / 100 : 1;\n        var sy = sy !== null ? sy / 100 : 1;\n        var rt = rt !== null ? (ifMath.normalizeAngleRadians(ifMath.toRadians(rt))) : 0;\n\n        var oldPattern = entry.getProperty('pat');\n        var oldPatternType = oldPattern ? oldPattern.getPatternType() : null;\n\n        var pattern = null;\n        var patternType = content.find('[data-element=\"type\"]').val();\n        var patternSubType = null;\n        if (patternType.indexOf('#') >= 0) {\n            var ptArray = patternType.split('#');\n            patternType = ptArray[0];\n            patternSubType = ptArray[1];\n        }\n\n        if (patternType === IFPattern.Type.Color) {\n            // reset transform values to default\n            tx = 0;\n            ty = 0;\n            sx = 1;\n            sy = 1;\n            rt = 0;\n        }\n        else if (patternType === IFPattern.Type.Gradient) {\n            // Set reasonable defaults for gradient if previous was either not\n            // a gradient or did have a different gradient type\n            if (oldPatternType !== IFPattern.Type.Gradient ||\n                oldPattern.getType() !== patternSubType) {\n                if (patternSubType === IFGradient.Type.Linear) {\n                    sx = 1;\n                    sy = 1;\n                    tx = 0.5;\n                    ty = 0.5;\n                    rt = ifMath.toRadians(90);\n                } else if (patternSubType === IFGradient.Type.Radial) {\n                    sx = 1;\n                    sy = 1;\n                    tx = 0.5;\n                    ty = 0.5;\n                    rt = 0;\n                } else {\n                    // TODO : Support more\n                    throw new Error('Unsupported Gradient Type');\n                }\n            }\n\n            if (oldPatternType === IFPattern.Type.Color) {\n                pattern = new IFGradient([\n                    {\n                        position: 0,\n                        color: oldPattern\n                    },\n                    {\n                        position: 100,\n                        color: IFColor.WHITE\n                    }\n                ], patternSubType);\n            } else {\n                pattern = new IFGradient(content.find('.g-gradient-editor').gGradientEditor('value'), patternSubType);\n            }\n        }\n\n        values.push(\n            tx,\n            ty,\n            sx,\n            sy,\n            rt\n        );\n    };\n\n    /** @override */\n    GAreaPaintEntry.prototype.toString = function () {\n        return \"[Object GAreaPaintEntry]\";\n    };\n\n    _.GAreaPaintEntry = GAreaPaintEntry;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/blurfilterentry.js",
    "content": "(function (_) {\n\n    /**\n     * Blur filter style entry handler\n     * @class GBlurFilterEntry\n     * @extends GStyleEntry\n     * @constructor\n     */\n    function GBlurFilterEntry() {\n    }\n\n    IFObject.inherit(GBlurFilterEntry, GStyleEntry);\n\n    /** @override */\n    GBlurFilterEntry.prototype.getEntryClass = function () {\n        return IFBlurFilter;\n    };\n\n    /** @override */\n    GBlurFilterEntry.prototype.getEntryName = function () {\n        // TODO : I18N\n        return 'Blur';\n    };\n\n    /** @override */\n    GBlurFilterEntry.prototype.createContent = function (scene, assign, revert) {\n        return $('<div></div>')\n            .addClass('g-form')\n            .append($('<div></div>')\n                .append($('<div></div>')\n                    // TODO : I18N\n                    .text('Blur'))\n                .append($('<div></div>')\n                    .css('width', '100%')\n                    .append($('<input>')\n                        .css('width', '100%')\n                        .attr('type', 'range')\n                        .attr('min', '0')\n                        .attr('max', '50')\n                        .attr('data-property', 'r')\n                        .on('input', function (evt) {\n                            var $this = $(this);\n                            $this.parents('.g-form').find('[data-property=\"r\"]:not([type=\"range\"])').val($this.val());\n                            assign();\n                        })))\n                .append($('<div></div>')\n                    .append($('<input>')\n                        .css('width', '3em')\n                        .attr('data-property', 'r')\n                        .on('change', function (evt) {\n                            var value = scene.stringToPoint($(this).val());\n                            if (value !== null && typeof value === 'number' && value >= 0) {\n                                assign();\n                            } else {\n                                revert();\n                            }\n                        }))));\n    };\n\n    /** @override */\n    GBlurFilterEntry.prototype.updateProperties = function (content, entry, scene) {\n        content.find('[data-property=\"r\"]').val(scene.pointToString(entry.getProperty('r')));\n    };\n\n    /** @override */\n    GBlurFilterEntry.prototype.assignProperties = function (content, entry, scene) {\n        entry.setProperties(['r'], [scene.stringToPoint(content.find('[data-property=\"r\"]:not([type=\"range\"])').val())]);\n    };\n\n    /** @override */\n    GBlurFilterEntry.prototype.toString = function () {\n        return \"[Object GBlurFilterEntry]\";\n    };\n\n    _.GBlurFilterEntry = GBlurFilterEntry;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/fillpaintentry.js",
    "content": "(function (_) {\n\n    /**\n     * Fill paint style entry handler\n     * @class GFillPaintEntry\n     * @extends GAreaPaintEntry\n     * @constructor\n     */\n    function GFillPaintEntry() {\n        GAreaPaintEntry.call(this);\n    }\n    IFObject.inherit(GFillPaintEntry, GAreaPaintEntry);\n\n    /** @override */\n    GFillPaintEntry.prototype.getEntryClass = function () {\n        return IFFillPaint;\n    };\n\n    /** @override */\n    GFillPaintEntry.prototype.getEntryName = function () {\n        // TODO : I18N\n        return 'Fill';\n    };\n\n    /** @override */\n    GFillPaintEntry.prototype.createContent = function (scene, assign, revert) {\n        return GAreaPaintEntry.prototype.createContent.call(this, scene, assign, revert);\n    };\n\n    /** @override */\n    GFillPaintEntry.prototype.updateProperties = function (content, entry, scene) {\n        GAreaPaintEntry.prototype.updateProperties.call(this, content, entry, scene);\n        // TODO\n    };\n\n    /** @override */\n    GFillPaintEntry.prototype.toString = function () {\n        return \"[Object GFillPaintEntry]\";\n    };\n\n    _.GFillPaintEntry = GFillPaintEntry;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/offsetveffectentry.js",
    "content": "(function (_) {\n\n    /**\n     * Offset vector effect style entry handler\n     * @class GOffsetVEffectEntry\n     * @extends GStyleEntry\n     * @constructor\n     */\n    function GOffsetVEffectEntry() {\n    }\n\n    IFObject.inherit(GOffsetVEffectEntry, GStyleEntry);\n\n    /** @override */\n    GOffsetVEffectEntry.prototype.getEntryClass = function () {\n        return IFOffsetVEffect;\n    };\n\n    /** @override */\n    GOffsetVEffectEntry.prototype.getEntryName = function () {\n        // TODO : I18N\n        return 'Offset';\n    };\n\n    /** @override */\n    GOffsetVEffectEntry.prototype.createContent = function (scene, assign, revert) {\n        // TODO\n        return $('<div></div>')\n            .addClass('g-form')\n            .append($('<div></div>')\n                .append($('<div></div>')\n                    // TODO : I18N\n                    .text('Offset'))\n                .append($('<div></div>')\n                    .css('width', '100%')\n                    .append($('<input>')\n                        .css('width', '100%')\n                        .attr('type', 'range')\n                        .attr('min', '0')\n                        .attr('max', '50')\n                        .attr('data-property', 'r')\n                        .on('input', function (evt) {\n                            var $this = $(this);\n                            $this.parents('.g-form').find('[data-property=\"r\"]:not([type=\"range\"])').val($this.val());\n                            assign();\n                        })))\n                .append($('<div></div>')\n                    .append($('<input>')\n                        .css('width', '3em')\n                        .attr('data-property', 'r')\n                        .on('change', function (evt) {\n                            var value = scene.stringToPoint($(this).val());\n                            if (value !== null && typeof value === 'number' && value >= 0) {\n                                assign();\n                            } else {\n                                revert();\n                            }\n                        })))\n                .append($('<div></div>')\n                    .append($('<select></select>')\n                        .attr('data-property', 'tp')\n                        .append($('<option></option>')\n                            .attr('value', IFOffsetVEffect.OffsetType.Inset)\n                            // TODO: I18N\n                            .text('Inset'))\n                        .append($('<option></option>')\n                            .attr('value', IFOffsetVEffect.OffsetType.Outset)\n                            // TODO: I18N\n                            .text('Outset'))\n                        .append($('<option></option>')\n                            .attr('value', IFOffsetVEffect.OffsetType.Both)\n                            // TODO: I18N\n                            .text('Both'))\n                        .on('change', function (evt) {\n                            assign();\n                        }))));\n    };\n\n    /** @override */\n    GOffsetVEffectEntry.prototype.updateProperties = function (content, entry, scene) {\n        content.find('[data-property=\"r\"]').val(scene.pointToString(entry.getProperty('r')));\n        content.find('[data-property=\"tp\"]').val(entry.getProperty('tp'));\n    };\n\n    /** @override */\n    GOffsetVEffectEntry.prototype.assignProperties = function (content, entry, scene) {\n        entry.setProperties(['r', 'tp'], [\n            scene.stringToPoint(content.find('[data-property=\"r\"]:not([type=\"range\"])').val()),\n            content.find('[data-property=\"tp\"]').val()\n        ]);\n    };\n\n    /** @override */\n    GOffsetVEffectEntry.prototype.toString = function () {\n        return \"[Object GOffsetVEffectEntry]\";\n    };\n\n    _.GOffsetVEffectEntry = GOffsetVEffectEntry;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/patternpaintentry.js",
    "content": "(function (_) {\n\n    /**\n     * Pattern paint style entry handler\n     * @class GPatternPaintEntry\n     * @extends GStyleEntry\n     * @constructor\n     */\n    function GPatternPaintEntry() {\n    }\n\n    IFObject.inherit(GPatternPaintEntry, GStyleEntry);\n\n    var DEFAULT_GRADIENT = new IFGradient([\n        {\n            position: 0,\n            color: IFColor.BLACK\n        },\n        {\n            position: 100,\n            color: IFColor.WHITE\n        }\n    ]);\n\n\n    /** @override */\n    GPatternPaintEntry.prototype.createContent = function (scene, assign, revert) {\n        return $('<div></div>')\n            .addClass('g-form')\n            .append($('<div></div>')\n                .append($('<div></div>')\n                    .css('width', '100%')\n                    .append($('<select></select>')\n                        .attr('data-element', 'type')\n                        .append($('<option></option>')\n                            .attr('value', IFPattern.Type.Color)\n                            // TODO : I18N\n                            .text('Color'))\n                        .append($('<optgroup></optgroup>')\n                            // TODO I18N\n                            .attr('label', 'Gradient')\n                        .append($('<option></option>')\n                            .attr('value', IFPattern.Type.Gradient + '#' + IFGradient.Type.Linear)\n                            // TODO : I18N\n                            .text('Linear'))\n                        .append($('<option></option>')\n                                .attr('value', IFPattern.Type.Gradient + '#' + IFGradient.Type.Radial)\n                            // TODO : I18N\n                            .text('Radial')))\n                        /* TODO :\n                         .append($('<option></option>')\n                         .attr('value', 'texture')\n                         .text('Texture'))\n                         .append($('<option></option>')\n                         .attr('value', 'noise')\n                         .text('Noise'))\n                         */\n                        .on('change', function (evt) {\n                            assign();\n                        }))\n                    .append($('<button></button>')\n                        .attr('data-element', 'color')\n                        .gColorButton({\n                            scene: scene\n                        })\n                        .on('colorchange', function (evt) {\n                            assign();\n                        })))\n                .append($('<div></div>')\n                    .append($('<select></select>')\n                        .attr('data-property', 'blm')\n                        .gBlendMode()\n                        .on('change', function (evt) {\n                            assign();\n                        }))\n                    .append($('<input>')\n                        .attr('data-property', 'opc')\n                        .css('width', '3em')\n                        .on('change', function (evt) {\n                            var opacity = IFLength.parseEquationValue($(evt.target).val());\n                            if (opacity !== null) {\n                                assign();\n                            } else {\n                                revert();\n                            }\n                        }))))\n            .append($('<div></div>')\n                .css('width', '100%')\n                .attr('data-element', 'gradient')\n                .append($('<div></div>')\n                    .css('width', '100%')\n                    .css('display', 'block')\n                    .append($('<div></div>')\n                        .css('width', '100%')\n                        .gGradientEditor({\n                            scene : scene\n                        })\n                        .on('change', function (evt) {\n                            assign();\n                        }))));\n    };\n\n    /** @override */\n    GPatternPaintEntry.prototype.updateProperties = function (content, entry, scene) {\n        var pattern = entry.getProperty('pat');\n        var patternType = pattern ? pattern.getPatternType() : null;\n\n        var patternSubType = null;\n        if (patternType === IFPattern.Type.Gradient) {\n            patternSubType = pattern.getType();\n        }\n\n        content.find('[data-element=\"type\"]').val(patternSubType ? (patternType + '#' + patternSubType) : patternType);\n        content.find('[data-element=\"color\"]')\n            .gColorButton('value', patternType === IFPattern.Type.Color ? pattern : IFColor.BLACK)\n            .css('display', patternType === IFPattern.Type.Color ? '' : 'none');\n        content.find('[data-property=\"blm\"]').val(entry.getProperty('blm'));\n        content.find('[data-property=\"opc\"]').val(ifUtil.formatNumber(entry.getProperty('opc') * 100));\n\n        // Gradient\n        if (patternType === IFPattern.Type.Gradient) {\n            content.find('[data-element=\"gradient\"]').css('display', '');\n            content.find('.g-gradient-editor').gGradientEditor('value', pattern.getStops());\n        } else {\n            content.find('[data-element=\"gradient\"]').css('display', 'none');\n            content.find('.g-gradient-editor').gGradientEditor('value', DEFAULT_GRADIENT.getStops());\n        }\n    };\n\n    /** @override */\n    GPatternPaintEntry.prototype.assignProperties = function (content, entry, scene) {\n        var properties = [];\n        var values = [];\n        this._getPropertiesToAssign(content, entry, scene, properties, values);\n        entry.setProperties(properties, values);\n    };\n\n    GPatternPaintEntry.prototype._getPropertiesToAssign = function (content, entry, scene, properties, values) {\n        properties.push(\n            'pat',\n            'blm',\n            'opc'\n        );\n\n        var opacity = IFLength.parseEquationValue(content.find('[data-property=\"opc\"]').val());\n\n        var oldPattern = entry.getProperty('pat');\n        var oldPatternType = oldPattern ? oldPattern.getPatternType() : null;\n\n        var pattern = null;\n        var patternType = content.find('[data-element=\"type\"]').val();\n        var patternSubType = null;\n        if (patternType.indexOf('#') >= 0) {\n            var ptArray = patternType.split('#');\n            patternType = ptArray[0];\n            patternSubType = ptArray[1];\n        }\n\n        if (patternType === IFPattern.Type.Color) {\n            if (oldPatternType === IFPattern.Type.Gradient) {\n                pattern = oldPattern.getStops()[0].color;\n            } else {\n                pattern = content.find('[data-element=\"color\"]').gColorButton('value');\n            }\n        } else if (patternType === IFPattern.Type.Gradient) {\n            if (oldPatternType === IFPattern.Type.Color) {\n                pattern = new IFGradient([\n                    {\n                        position: 0,\n                        color: oldPattern\n                    },\n                    {\n                        position: 100,\n                        color: IFColor.WHITE\n                    }\n                ], patternSubType);\n            } else {\n                pattern = new IFGradient(content.find('.g-gradient-editor').gGradientEditor('value'), patternSubType);\n            }\n        }\n\n        values.push(\n            pattern, // pat\n            content.find('[data-property=\"blm\"]').val(), // blm\n            (opacity < 0 ? 0 : opacity > 100 ? 100 : opacity) / 100.0 // opc\n        );\n    };\n\n    /** @override */\n    GPatternPaintEntry.prototype.toString = function () {\n        return \"[Object GPatternPaintEntry]\";\n    };\n\n    _.GPatternPaintEntry = GPatternPaintEntry;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/shadoweffectentry.js",
    "content": "(function (_) {\n\n    /**\n     * Shadow effect style entry handler\n     * @class GShadowEffectEntry\n     * @extends GStyleEntry\n     * @constructor\n     */\n    function GShadowEffectEntry() {\n    }\n\n    IFObject.inherit(GShadowEffectEntry, GStyleEntry);\n\n    /** @override */\n    GShadowEffectEntry.prototype.getEntryClass = function () {\n        return IFShadowEffect;\n    };\n\n    /** @override */\n    GShadowEffectEntry.prototype.getEntryName = function () {\n        // TODO : I18N\n        return 'Shadow';\n    };\n\n    /** @override */\n    GShadowEffectEntry.prototype.createContent = function (scene, assign, revert) {\n        // TODO\n        return $('<div></div>')\n            .addClass('g-form')\n            .append($('<div></div>')\n                .append($('<div></div>')\n                    .append($('<div></div>')\n                        .css('width', '4.5em')\n                        .addClass('g-switch')\n                        .append($('<label></label>')\n                            .append($('<input>')\n                                .attr('type', 'checkbox')\n                                .attr('data-property', 'in')\n                                .on('change', function () {\n                                    assign();\n                                }))\n                            .append($('<span></span>')\n                                .addClass('switch')\n                                .attr({\n                                    // TODO : I18N\n                                    'data-on': 'Inside',\n                                    'data-off': 'Outside'\n                                }))))\n                    .append($('<label></label>')\n                        // TODO : I18N\n                        .text('Shadow')))\n                .append($('<div></div>')\n                    .append($('<input>')\n                        .css('width', '3em')\n                        .attr('data-property', 'x')\n                        .on('change', function (evt) {\n                            var value = scene.stringToPoint($(this).val());\n                            if (value !== null && typeof value === 'number') {\n                                assign();\n                            } else {\n                                revert();\n                            }\n                        }))\n                    .append($('<label></label>')\n                        .text('X')))\n                .append($('<div></div>')\n                    .append($('<input>')\n                        .css('width', '3em')\n                        .attr('data-property', 'y')\n                        .on('change', function (evt) {\n                            var value = scene.stringToPoint($(this).val());\n                            if (value !== null && typeof value === 'number') {\n                                assign();\n                            } else {\n                                revert();\n                            }\n                        }))\n                    .append($('<label></label>')\n                        .text('Y')))\n                .append($('<div></div>')\n                    .append($('<input>')\n                        .css('width', '3em')\n                        .attr('data-property', 'r')\n                        .on('change', function (evt) {\n                            var value = scene.stringToPoint($(this).val());\n                            if (value !== null && typeof value === 'number' && value >= 0) {\n                                assign();\n                            } else {\n                                revert();\n                            }\n                        }))\n                    .append($('<label></label>')\n                        .text('Blur')))\n                .append($('<div></div>')\n                    .append($('<button></button>')\n                        .attr('data-property', 'cls')\n                        .gColorButton({\n                            scene: scene\n                        })\n                        .on('colorchange', function (evt) {\n                            assign();\n                        }))\n                    .append($('<label></label>')\n                        .text('Color'))));\n    };\n\n    /** @override */\n    GShadowEffectEntry.prototype.updateProperties = function (content, entry, scene) {\n        content.find('[data-property=\"in\"]').prop('checked', entry.getProperty('in'));\n        content.find('[data-property=\"x\"]').val(scene.pointToString(entry.getProperty('x')));\n        content.find('[data-property=\"y\"]').val(scene.pointToString(entry.getProperty('y')));\n        content.find('[data-property=\"r\"]').val(scene.pointToString(entry.getProperty('r')));\n        content.find('[data-property=\"cls\"]').gColorButton('value', entry.getProperty('cls'));\n    };\n\n    /** @override */\n    GShadowEffectEntry.prototype.assignProperties = function (content, entry, scene) {\n        entry.setProperties(['in', 'x', 'y', 'r', 'cls'], [\n            content.find('[data-property=\"in\"]').is(':checked'),\n            scene.stringToPoint(content.find('[data-property=\"x\"]').val()),\n            scene.stringToPoint(content.find('[data-property=\"y\"]').val()),\n            scene.stringToPoint(content.find('[data-property=\"r\"]').val()),\n            content.find('[data-property=\"cls\"]').gColorButton('value')\n        ]);\n    };\n\n    /** @override */\n    GShadowEffectEntry.prototype.toString = function () {\n        return \"[Object GShadowEffectEntry]\";\n    };\n\n    _.GShadowEffectEntry = GShadowEffectEntry;\n})(this);"
  },
  {
    "path": "src/gravit/styleentry/strokepaintentry.js",
    "content": "(function (_) {\n\n    /**\n     * Stroke paint style entry handler\n     * @class GStrokePaintEntry\n     * @extends GAreaPaintEntry\n     * @constructor\n     */\n    function GStrokePaintEntry() {\n        GAreaPaintEntry.call(this);\n    }\n    IFObject.inherit(GStrokePaintEntry, GAreaPaintEntry);\n\n    /** @override */\n    GStrokePaintEntry.prototype.getEntryClass = function () {\n        return IFStrokePaint;\n    };\n\n    /** @override */\n    GStrokePaintEntry.prototype.getEntryName = function () {\n        // TODO : I18N\n        return 'Stroke';\n    };\n\n    /** @override */\n    GStrokePaintEntry.prototype.createContent = function (scene, assign, revert) {\n        var content = GAreaPaintEntry.prototype.createContent.call(this, scene, assign, revert);\n\n        $('<div></div>')\n            .attr('data-element', 'stroke-settings')\n            .css('display', 'none')\n            .append($('<div></div>')\n                .append($('<select></select>')\n                    .attr('data-property', 'slc')\n                    .append($('<option></option>')\n                        .attr('value', IFPaintCanvas.LineCap.Butt)\n                        // TODO : I18N\n                        .text('Butt'))\n                    .append($('<option></option>')\n                        .attr('value', IFPaintCanvas.LineCap.Round)\n                        // TODO : I18N\n                        .text('Round'))\n                    .append($('<option></option>')\n                        .attr('value', IFPaintCanvas.LineCap.Square)\n                        // TODO : I18N\n                        .text('Square'))\n                    .on('change', function (evt) {\n                        assign();\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('Caption')))\n            .append($('<div></div>')\n                .append($('<select></select>')\n                    .attr('data-property', 'slj')\n                    .append($('<option></option>')\n                        .attr('value', IFPaintCanvas.LineJoin.Miter)\n                        // TODO : I18N\n                        .text('Miter'))\n                    .append($('<option></option>')\n                        .attr('value', IFPaintCanvas.LineJoin.Bevel)\n                        // TODO : I18N\n                        .text('Bevel'))\n                    .append($('<option></option>')\n                        .attr('value', IFPaintCanvas.LineJoin.Round)\n                        // TODO : I18N\n                        .text('Round'))\n                    .on('change', function (evt) {\n                        assign();\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('Join')))\n            .append($('<div></div>')\n                .append($('<input>')\n                    .css('width', '5em')\n                    .attr('data-property', 'slm')\n                    .on('change', function (evt) {\n                        var value = scene.stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value >= 0) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('Miter')))\n            .prependTo(content);\n\n        $('<div></div>')\n            .append($('<div></div>')\n                .append($('<input>')\n                    .attr('data-property', 'sw')\n                    .css('width', '5em')\n                    .on('change', function (evt) {\n                        var value = scene.stringToPoint($(this).val());\n                        if (value !== null && typeof value === 'number' && value > 0) {\n                            assign();\n                        } else {\n                            revert();\n                        }\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('Stroke')))\n            .append($('<div></div>')\n                .append($('<select></select>')\n                    .attr('data-property', 'sa')\n                    .append($('<option></option>')\n                        .attr('value', IFStrokePaint.Alignment.Center)\n                        // TODO : I18N\n                        .text('Center'))\n                    .append($('<option></option>')\n                        .attr('value', IFStrokePaint.Alignment.Inside)\n                        // TODO : I18N\n                        .text('Inside'))\n                    .append($('<option></option>')\n                        .attr('value', IFStrokePaint.Alignment.Outside)\n                        // TODO : I18N\n                        .text('Outside'))\n                    .on('change', function (evt) {\n                        assign();\n                    }))\n                .append($('<label></label>')\n                    // TODO : I18N\n                    .text('Align')))\n            .append($('<div></div>')\n                .css('width', '100%')\n                .css('text-align', 'right')\n                .append($('<button></button>')\n                    .css('margin-right', '0px')\n                    .attr('data-element', 'more')\n                    .on('click', function (evt) {\n                        var $this = $(this);\n                        var active = $this.hasClass('g-active');\n                        $this.toggleClass('g-active', !active);\n                        $this.closest('.g-form').find('[data-element=\"stroke-settings\"]')\n                            .css('display', active ? 'none' : '');\n                    })\n                    .append($('<span></span>')\n                        .addClass('fa fa-cog')))\n                .append($('<label>&nbsp;</label>')))\n            .prependTo(content);\n\n        return content;\n    };\n\n    /** @override */\n    GStrokePaintEntry.prototype.updateProperties = function (content, entry, scene) {\n        GAreaPaintEntry.prototype.updateProperties.call(this, content, entry, scene);\n        content.find('[data-property=\"sw\"]').val(scene.pointToString(entry.getProperty('sw')));\n        content.find('[data-property=\"sa\"]').val(entry.getProperty('sa'));\n        content.find('[data-property=\"slc\"]').val(entry.getProperty('slc'));\n        content.find('[data-property=\"slj\"]').val(entry.getProperty('slj'));\n        content.find('[data-property=\"slm\"]').val(scene.pointToString(entry.getProperty('slm')));\n    };\n\n    /** @override */\n    GStrokePaintEntry.prototype._getPropertiesToAssign = function (content, entry, scene, properties, values) {\n        GAreaPaintEntry.prototype._getPropertiesToAssign.call(this, content, entry, scene, properties, values);\n\n        properties.push(\n            'sw',\n            'sa',\n            'slc',\n            'slj',\n            'slm'\n        );\n\n        values.push(\n            scene.stringToPoint(content.find('[data-property=\"sw\"]').val()),\n            content.find('[data-property=\"sa\"]').val(),\n            content.find('[data-property=\"slc\"]').val(),\n            content.find('[data-property=\"slj\"]').val(),\n            scene.stringToPoint(content.find('[data-property=\"slm\"]').val())\n        );\n    };\n\n    /** @override */\n    GStrokePaintEntry.prototype.toString = function () {\n        return \"[Object GStrokePaintEntry]\";\n    };\n\n    _.GStrokePaintEntry = GStrokePaintEntry;\n})(this);"
  },
  {
    "path": "src/gravit/transformer/adjusttransformer.js",
    "content": "(function (_) {\n\n    /**\n     * Transform transform panel\n     * @class GAdjustTransformer\n     * @extends GTransformer\n     * @constructor\n     */\n    function GAdjustTransformer() {\n        this._elements = [];\n        this._savedValues = {\n            'Move': [0, 0],\n            'Scale': [100, 100],\n            'Rotate': [0],\n            'Skew': [0, 0],\n            'Reflect': [0]\n        };\n    };\n    IFObject.inherit(GAdjustTransformer, GTransformer);\n\n    GAdjustTransformer._TransformMode = {\n        Move: {\n            label1: {\n                prefix: 'X'\n            },\n            label2: {\n                prefix: 'Y'\n            },\n            pivot: false,\n            transformFunc: function (val1, val2, scene) {\n                var tx = scene.stringToPoint(val1) || 0;\n                var ty = scene.stringToPoint(val2) || 0;\n\n                if (tx !== 0 || ty !== 0) {\n                    return function (step, element, origin) {\n                        element.transform(new IFTransform(1, 0, 0, 1, tx * step, ty * step));\n                    }\n                }\n\n                return null;\n            }\n        },\n        Scale: {\n            label1: {\n                prefix: 'W',\n                postfix: '%'\n            },\n            label2: {\n                prefix: 'H',\n                postfix: '%'\n            },\n            pivot: true,\n            transformFunc: function (val1, val2, scene) {\n                var sx = parseFloat(val1) / 100.0 || 1;\n                var sy = parseFloat(val2) / 100.0 || 1;\n\n                if (sx !== 1 || sy !== 1) {\n                    return function (step, element, origin) {\n                        element.transform(new IFTransform()\n                            .translated(-origin.getX(), -origin.getY())\n                            .scaled(sx + (sx - 1) * (step - 1), sy + (sy - 1) * (step - 1))\n                            .translated(origin.getX(), origin.getY()));\n                    }\n                }\n                return null;\n            }\n        },\n        Rotate: {\n            label1: {\n                prefix: 'Angle',\n                postfix: '°'\n            },\n            pivot: true,\n            transformFunc: function (val1, val2, scene) {\n                var angle = ifMath.toRadians(parseFloat(val1)) || 0;\n\n                if (angle !== 0) {\n                    return function (step, element, origin) {\n                        element.transform(new IFTransform()\n                            .translated(-origin.getX(), -origin.getY())\n                            .rotated(-angle * step)\n                            .translated(origin.getX(), origin.getY()));\n                    }\n                }\n\n                return null;\n            }\n        },\n        Skew: {\n            label1: {\n                prefix: 'X',\n                postfix: '°'\n            },\n            label2: {\n                prefix: 'Y',\n                postfix: '°'\n            },\n            pivot: true,\n            transformFunc: function (val1, val2, scene) {\n                var sx = ifMath.toRadians(parseFloat(val1)) || 0;\n                var sy = ifMath.toRadians(parseFloat(val2)) || 0;\n\n                if ((sx !== 0 || sy !== 0) && (sx > -ifMath.PIHALF && sy > -ifMath.PIHALF && sx < ifMath.PIHALF && sy < ifMath.PIHALF)) {\n                    return function (step, element, origin) {\n                        element.transform(new IFTransform()\n                            .translated(-origin.getX(), -origin.getY())\n                            .skewed(sx * step, sy * step)\n                            .translated(origin.getX(), origin.getY()));\n                    }\n                }\n\n                return null;\n            }\n        },\n        Reflect: {\n            label1: {\n                prefix: 'Axis',\n                postfix: '°'\n            },\n            pivot: true,\n            transformFunc: function (val1, val2, scene) {\n                var angle = parseFloat(val1) || 0;\n                angle = ifMath.toRadians(-angle);\n                var cosA = Math.cos(angle);\n                var sinA = Math.sin(angle);\n\n                return function (step, element, origin) {\n                    if (step % 2) {\n                        element.transform(new IFTransform()\n                            .translated(-origin.getX(), -origin.getY())\n                            .multiplied(new IFTransform(cosA, -sinA, sinA, cosA, 0, 0))\n                            .multiplied(new IFTransform(1, 0, 0, -1, 0, 0))\n                            .multiplied(new IFTransform(cosA, sinA, -sinA, cosA, 0, 0))\n                            .translated(origin.getX(), origin.getY()));\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GAdjustTransformer.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GAdjustTransformer.prototype._document = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    GAdjustTransformer.prototype._elements = null;\n\n    /**\n     * @type {GAdjustTransformer._TransformMode}\n     * @private\n     */\n    GAdjustTransformer.prototype._transformMode = null;\n\n    /**\n     * @type {*}\n     * @private\n     */\n    GAdjustTransformer.prototype._savedValues = null;\n\n    /** @override */\n    GAdjustTransformer.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Adjust';\n    };\n\n    /** @override */\n    GAdjustTransformer.prototype.init = function (panel) {\n        this._panel = panel;\n\n        panel\n            .css('width', '166px')\n            .append($('<div></div>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append($('<button></button>')\n                    .addClass('g-flat')\n                    // TODO : I18N\n                    .attr('title', 'Move')\n                    .attr('data-mode', 'Move')\n                    .append($('<span></span>')\n                        .addClass('fa fa-arrows')))\n                .append($('<button></button>')\n                    .addClass('g-flat')\n                    // TODO : I18N\n                    .attr('title', 'Scale')\n                    .attr('data-mode', 'Scale')\n                    .append($('<span></span>')\n                        .addClass('fa fa-expand')))\n                .append($('<button></button>')\n                    .addClass('g-flat')\n                    // TODO : I18N\n                    .attr('title', 'Rotate')\n                    .attr('data-mode', 'Rotate')\n                    .append($('<span></span>')\n                        .addClass('fa fa-rotate-right')))\n                .append($('<button></button>')\n                    .addClass('g-flat')\n                    // TODO : I18N\n                    .attr('title', 'Skew')\n                    .attr('data-mode', 'Skew')\n                    .append($('<span></span>')\n                        .addClass('fa fa-eraser')))\n                .append($('<button></button>')\n                    .addClass('g-flat')\n                    // TODO : I18N\n                    .attr('title', 'Reflect')\n                    .attr('data-mode', 'Reflect')\n                    .append($('<span></span>')\n                        .addClass('fa fa-star-half-o')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .css('margin-left', '7px')\n                    // TODO : I18N\n                    .text('Apply')\n                    .on('click', this._apply.bind(this))))\n            .append($('<label></label>')\n                .attr('data-value', '1')\n                .css({\n                    'position': 'absolute',\n                    'left': '5px',\n                    'top': '30px'\n                })\n                .append($('<span></span>')\n                    .attr('data-prefix', ''))\n                .append($('<input>')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '48px'\n                    })\n                    .val('0')\n                    .on('keyup', function (evt) {\n                        if (evt.keyCode == 13) {\n                            this._apply();\n                        }\n                    }.bind(this)))\n                .append($('<span></span>')\n                    .attr('data-postfix', '')))\n            .append($('<label></label>')\n                .attr('data-value', '2')\n                .css({\n                    'position': 'absolute',\n                    'left': '90px',\n                    'top': '30px'\n                })\n                .append($('<span></span>')\n                    .attr('data-prefix', ''))\n                .append($('<input>')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '48px'\n                    })\n                    .val('0')\n                    .on('keyup', function (evt) {\n                        if (evt.keyCode == 13) {\n                            this._apply();\n                        }\n                    }.bind(this)))\n                .append($('<span></span>')\n                    .attr('data-postfix', '')))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<div></div>')\n                .attr('data-property', 'pivot')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '5px'\n                })\n                .gPivot())\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'right': '5px'\n                })\n                // TODO : I18N\n                .text('Copies:')\n                .append($('<input>')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '38px'\n                    })\n                    .attr('data-property', 'copies')\n                    .val('0')));\n\n        panel.find('button[data-mode]').each(function (index, element) {\n            var $element = $(element);\n            $element.on('click', function () {\n                this._setTransformMode($element.attr('data-mode'));\n            }.bind(this))\n        }.bind(this));\n\n        this._setTransformMode('Move');\n    };\n\n    /** @override */\n    GAdjustTransformer.prototype.update = function (document, elements) {\n        this._document = document;\n        this._elements = elements;\n\n        this._panel.find('[data-property=\"pivot\"]').gPivot('value', IFRect.Side.CENTER);\n\n        return true;\n    };\n\n    GAdjustTransformer.prototype._setTransformMode = function (mode) {\n        if (this._transformMode) {\n            this._savedValues[this._transformMode] = [\n                this._panel.find('label[data-value=\"1\"] input').val(),\n                this._panel.find('label[data-value=\"2\"] input').val()\n            ];\n        }\n\n        this._transformMode = mode;\n\n        this._panel.find('button[data-mode]').each(function (index, element) {\n            var $element = $(element);\n            $element.toggleClass('g-active', $element.attr('data-mode') === mode);\n        }.bind(this));\n\n        var _updateLabel = function (labelInfo, number) {\n            var label = this._panel.find('label[data-value=\"' + number.toString() + '\"]');\n            if (!labelInfo) {\n                label.css('display', 'none');\n            } else {\n                label.css('display', '');\n                label.find('span[data-prefix]').text(labelInfo.prefix ? (labelInfo.prefix + ':') : '');\n                label.find('span[data-postfix]').text(labelInfo.postfix ? labelInfo.postfix : '');\n                label.find('input').val(this._savedValues[mode][number - 1]);\n            }\n        }.bind(this);\n\n        var transModeInfo = GAdjustTransformer._TransformMode[mode];\n        _updateLabel(transModeInfo.label1, 1);\n        _updateLabel(transModeInfo.label2, 2);\n        this._panel.find('[data-property=\"pivot\"]').css('display', transModeInfo.pivot ? '' : 'none');\n    };\n\n    /**\n     * @private\n     */\n    GAdjustTransformer.prototype._apply = function () {\n        var scene = this._document.getScene();\n\n        var copies = parseInt(this._panel.find('[data-property=\"copies\"]').val());\n        var pivot = this._panel.find('[data-property=\"pivot\"]').gPivot('value');\n        var value1 = this._panel.find('label[data-value=\"1\"] input').val();\n        var value2 = this._panel.find('label[data-value=\"2\"] input').val();\n\n        var transformFunc = GAdjustTransformer._TransformMode[this._transformMode].transformFunc(value1, value2, scene);\n\n        if (transformFunc) {\n            // TODO : I18N\n            IFEditor.tryRunTransaction(scene, function () {\n                var transformElements = [];\n                var bbox = null;\n                for (var i = 0; i < this._elements.length; ++i) {\n                    var element = this._elements[i];\n                    if (pivot) {\n                        bbox = bbox ? bbox.united(element.getGeometryBBox()) : element.getGeometryBBox();\n                    }\n                    var elementElements = [element];\n\n                    if (copies > 0) {\n                        var parent = element.getParent();\n                        var insertReference = element.getNext() ? element.getNext() : null;\n                        for (var c = 0; c < copies; ++c) {\n                            var clone = element.clone();\n                            if (c == copies - 1) {\n                                clone.setFlag(IFNode.Flag.Selected);\n                                element.removeFlag(IFNode.Flag.Selected);\n                            }\n                            parent.insertChild(clone, insertReference);\n                            elementElements.push(clone);\n                        }\n                    }\n                    transformElements.push(elementElements);\n                }\n\n                var pivotPt = null;\n                if (bbox && !bbox.isEmpty()) {\n                    pivotPt = bbox.getSide(pivot);\n                }\n                for (var i = 0; i < transformElements.length; ++i) {\n                    var elementElements = transformElements[i];\n                    if (elementElements.length > 1) {\n                        for (var step = 0; step < elementElements.length; ++step) {\n                            transformFunc(step, elementElements[step], pivotPt);\n                        }\n                    } else if (elementElements.length == 1) {\n                        transformFunc(1, elementElements[0], pivotPt);\n                    }\n                }\n            }.bind(this), 'Adjust Transformation');\n        }\n    };\n\n    /** @override */\n    GAdjustTransformer.prototype.toString = function () {\n        return \"[Object GAdjustTransformer]\";\n    };\n\n    _.GAdjustTransformer = GAdjustTransformer;\n})(this);"
  },
  {
    "path": "src/gravit/transformer/aligntransformer.js",
    "content": "(function (_) {\n\n    /**\n     * Align transform panel\n     * @class GAlignTransformer\n     * @extends GTransformer\n     * @constructor\n     */\n    function GAlignTransformer() {\n        this._elements = [];\n    };\n    IFObject.inherit(GAlignTransformer, GTransformer);\n\n    /** @enum */\n    GAlignTransformer._AlignTo = {\n        Selection: 'selection',\n        Layer: 'layer',\n        Page: 'page',\n        PageMargins: 'page-margins',\n        FirstElement: 'first-element',\n        LastElement: 'last-element'\n    };\n\n    /**\n     * @type {JQuery}\n     * @private\n     */\n    GAlignTransformer.prototype._panel = null;\n\n    /**\n     * @type {GDocument}\n     * @private\n     */\n    GAlignTransformer.prototype._document = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    GAlignTransformer.prototype._elements = null;\n\n    /**\n     * @type {GAlignTransformer._AlignTo}\n     * @private\n     */\n    GAlignTransformer.prototype._savedAlignTo = GAlignTransformer._AlignTo.Selection;\n\n    /** @override */\n    GAlignTransformer.prototype.getCategory = function () {\n        // TODO : I18N\n        return 'Align';\n    };\n\n    /** @override */\n    GAlignTransformer.prototype.init = function (panel) {\n        this._panel = panel;\n\n        panel\n            .css('width', '182px')\n            .append($('<div></div>')\n                .css({\n                    'position': 'absolute',\n                    'top': '5px',\n                    'left': '5px'\n                })\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Align Left')\n                    .attr('data-align', GAlignAction.Type.AlignLeft)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-left')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Align Center')\n                    .attr('data-align', GAlignAction.Type.AlignCenter)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-center')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Align Right')\n                    .attr('data-align', GAlignAction.Type.AlignRight)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-right')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Justify Horizontal')\n                    .attr('data-align', GAlignAction.Type.AlignJustifyHorizontal)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-justify fa-rotate-270')))\n                .append($('<button></button>')\n                    .css('margin-left', '10px')\n                    // TODO : I18N\n                    .attr('title', 'Distribute Horizontal')\n                    .attr('data-dist', GDistributeAction.Type.Horizontal)\n                    .append($('<span></span>')\n                        .addClass('fa fa-reorder fa-rotate-270')))\n                .append($('<input>')\n                    // TODO : I18N\n                    .attr('title', 'Horizontal Spacing, zero will auto-space')\n                    .attr('data-dist', GDistributeAction.Type.Horizontal)\n                    .css('width', '38px')\n                    .val('0')))\n            .append($('<div></div>')\n                .css({\n                    'position': 'absolute',\n                    'top': '30px',\n                    'left': '5px'\n                })\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Align Top')\n                    .attr('data-align', GAlignAction.Type.AlignTop)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-right fa-rotate-270')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Align Middle')\n                    .attr('data-align', GAlignAction.Type.AlignMiddle)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-center fa-rotate-270')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Align Bottom')\n                    .attr('data-align', GAlignAction.Type.AlignBottom)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-left fa-rotate-270')))\n                .append($('<button></button>')\n                    // TODO : I18N\n                    .attr('title', 'Justify Vertical')\n                    .attr('data-align', GAlignAction.Type.AlignJustifyVertical)\n                    .append($('<span></span>')\n                        .addClass('fa fa-align-justify')))\n                .append($('<button></button>')\n                    .css('margin-left', '10px')\n                    // TODO : I18N\n                    .attr('title', 'Distribute Vertical')\n                    .attr('data-dist', GDistributeAction.Type.Vertical)\n                    .append($('<span></span>')\n                        .addClass('fa fa-reorder')))\n                .append($('<input>')\n                    // TODO : I18N\n                    .attr('title', 'Vertical Spacing, zero will auto-space')\n                    .attr('data-dist', GDistributeAction.Type.Vertical)\n                    .css('width', '38px')\n                    .val('0')))\n            .append($('<hr>')\n                .css({\n                    'position': 'absolute',\n                    'left': '0px',\n                    'right': '0px',\n                    'top': '50px'\n                }))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '65px',\n                    'left': '5px'\n                })\n                // TODO : I18N\n                .text('Align To:')\n                .append(($('<select></select>')\n                    .css({\n                        'margin-left': '3px',\n                        'width': '100px'\n                    })\n                    .attr('data-option', 'align-to')\n                    .append($('<option></option>')\n                        .attr('value', GAlignTransformer._AlignTo.Selection)\n                        // TODO : I18N\n                        .text('Selection'))\n                    .append($('<option></option>')\n                        .attr('value', GAlignTransformer._AlignTo.Layer)\n                        // TODO : I18N\n                        .text('Active Layer'))\n                    .append($('<option></option>')\n                        .attr('value', GAlignTransformer._AlignTo.Page)\n                        // TODO : I18N\n                        .text('Active Page'))\n                    .append($('<option></option>')\n                        .attr('value', GAlignTransformer._AlignTo.PageMargins)\n                        // TODO : I18N\n                        .text('Active Page Margins'))\n                    .append($('<option></option>')\n                        .attr('value', GAlignTransformer._AlignTo.FirstElement)\n                        // TODO : I18N\n                        .text('First Selected Element'))\n                    .append($('<option></option>')\n                        .attr('value', GAlignTransformer._AlignTo.LastElement)\n                        // TODO : I18N\n                        .text('Last Selected Element'))\n                    .on('change', function (evt) {\n                        this._savedAlignTo = $(evt.target).val();\n                        this._updateStates();\n                    }.bind(this)))))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '5px'\n                })\n                .append($('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-align-geometry', '')\n                    .prop('checked', true))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Geometry')))\n            .append($('<label></label>')\n                .css({\n                    'position': 'absolute',\n                    'top': '89px',\n                    'left': '80px'\n                })\n                .append($('<input>')\n                    .attr('type', 'checkbox')\n                    .attr('data-align-selection', '')\n                    .prop('checked', true))\n                .append($('<span></span>')\n                    // TODO : I18N\n                    .text(' Selection')));\n\n        var alignHandler = function (evt) {\n            this._executeAction($(evt.target).closest('button').attr('data-align'), 'align');\n        }.bind(this);\n\n        var distHandler = function (evt) {\n            this._executeAction($(evt.target).closest('button').attr('data-dist'), 'dist')\n        }.bind(this);\n\n        this._panel.find('button[data-align]').each(function (index, element) {\n            $(element).on('click', alignHandler);\n        });\n\n        this._panel.find('button[data-dist]').each(function (index, element) {\n            $(element).on('click', distHandler);\n        });\n\n        this._panel.find('input[data-dist]').each(function (index, element) {\n            $(element).on('keyup', function (evt) {\n                if (evt.keyCode === 13) {\n                    distHandler.call(this, evt);\n                }\n            });\n        });\n    };\n\n    /** @override */\n    GAlignTransformer.prototype.update = function (document, elements) {\n        this._document = document;\n        this._elements = elements;\n\n        // If selection alignment-to is selected and we have only one\n        // element available then we (temporarily) switch to align-to page,\n        // otherwise we'll reset to our saved align-to selection\n        if (this._elements && this._elements.length === 1) {\n            this._panel.find('select[data-option=\"align-to\"]').val(GAlignTransformer._AlignTo.Page);\n        } else {\n            this._panel.find('select[data-option=\"align-to\"]').val(this._savedAlignTo)\n        }\n\n        this._updateStates();\n\n        return true;\n    };\n\n    /**\n     * Returns the action args\n     * @param {GAlignAction.Type|GDistributeAction.Type} type\n     * @param {String} mode - 'align', 'dist'\n     * @return {{actionId: String, actionParams: Array<*>}}\n     * @private\n     */\n    GAlignTransformer.prototype._getActionArgs = function (type, mode) {\n        // Gather our reference box depending on the selection, first\n        var referenceBox = null;\n        var elements = this._elements.slice();\n        var scene = this._document.getScene();\n        var activePage = scene.getActivePage();\n        var activeLayer = scene.getActiveLayer();\n        var alignTo = this._panel.find('select[data-option=\"align-to\"]').val();\n\n        switch (alignTo) {\n            case GAlignTransformer._AlignTo.Layer:\n                referenceBox = activeLayer.getPaintBBox();\n                break;\n            case GAlignTransformer._AlignTo.Page:\n                referenceBox = activePage.getGeometryBBox();\n                break;\n            case GAlignTransformer._AlignTo.PageMargins:\n                referenceBox = activePage.getGeometryBBox().expanded(\n                    -activePage.getProperty('ml'),\n                    -activePage.getProperty('mt'),\n                    -activePage.getProperty('mr'),\n                    -activePage.getProperty('mb'));\n                break;\n            case GAlignTransformer._AlignTo.FirstElement:\n                referenceBox = elements[0];\n                elements.splice(0);\n                break;\n            case GAlignTransformer._AlignTo.LastElement:\n                referenceBox = elements[elements.length - 1];\n                elements.splice(elements.length - 1);\n                break;\n        }\n\n        if (elements.length > 0) {\n            var geometry = this._panel.find('input[data-align-geometry]').is(':checked');\n\n            if (mode === 'align') {\n                var compound = alignTo !== GAlignTransformer._AlignTo.Selection ? this._panel.find('input[data-align-selection]').is(':checked') : false;\n                return {\n                    actionId: GAlignAction.ID + '.' + type,\n                    actionParams: [elements, compound, geometry, referenceBox]\n                };\n            } else if (mode === 'dist') {\n                var spacing = scene.stringToPoint(this._panel.find('input[data-dist=\"' + type + '\"]').val()) || 0;\n                return {\n                    actionId: GDistributeAction.ID + '.' + type,\n                    actionParams: [elements, geometry, referenceBox, spacing]\n                };\n            } else {\n                throw new Error('Unknown align mode: ' + mode);\n            }\n        }\n    };\n\n    /**\n     * see _getActionArgs\n     * @private\n     */\n    GAlignTransformer.prototype._executeAction = function (type, mode) {\n        var actionArgs = this._getActionArgs(type, mode);\n        if (actionArgs) {\n            gApp.executeAction(actionArgs.actionId, actionArgs.actionParams);\n        }\n    };\n\n    /**\n     * see _getActionArgs\n     * @private\n     */\n    GAlignTransformer.prototype._isActionEnabled = function (type, mode) {\n        var actionArgs = this._getActionArgs(type, mode);\n        if (actionArgs) {\n            return gApp.canExecuteAction(actionArgs.actionId, actionArgs.actionParams);\n        }\n        return false;\n    };\n\n    /** @private */\n    GAlignTransformer.prototype._updateStates = function () {\n        var alignTo = this._panel.find('select[data-option=\"align-to\"]').val();\n        var compoundCtrls = alignTo !== GAlignTransformer._AlignTo.Selection && this._elements.length > 1;\n\n        this._panel.find('input[data-align-selection]').prop('disabled', !compoundCtrls);\n\n        this._panel.find('[data-align]').each(function (index, element) {\n            var $element = $(element);\n            $element.prop('disabled', !this._isActionEnabled($element.attr('data-align'), 'align'));\n        }.bind(this));\n\n        this._panel.find('[data-dist]').each(function (index, element) {\n            var $element = $(element);\n            $element.prop('disabled', !this._isActionEnabled($element.attr('data-dist'), 'dist'));\n        }.bind(this));\n    };\n\n    /** @override */\n    GAlignTransformer.prototype.toString = function () {\n        return \"[Object GAlignTransformer]\";\n    };\n\n    _.GAlignTransformer = GAlignTransformer;\n})(this);"
  },
  {
    "path": "src/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title></title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\n\n    <!-- build:css(tmp) gravit.css -->\n    <link rel=\"stylesheet\" href=\"gravit.css\">\n    <!-- endbuild -->\n</head>\n<body>\n\n<script src=\"../bower_components/jquery/dist/jquery.js\"></script>\n\n<!-- ############################################################## -->\n<!-- # Infinity Libs ############################################## -->\n<!-- ############################################################## -->\n<!-- build:js infinity-libraries.js -->\n<script src=\"../bower_components/jqtree/tree.jquery.js\"></script>\n\n<script src=\"../bower_components/mousetrap/mousetrap.js\"></script>\n\n<script src=\"../bower_components/opentype.js/opentype.js\"></script>\n\n<script src=\"../bower_components/rangy/rangy-core.js\"></script>\n<script src=\"../bower_components/rangy/rangy-cssclassapplier.js\"></script>\n<script src=\"../bower_components/rangy/rangy-selectionsaverestore.js\"></script>\n\n<script src=\"../bower_components/pako/dist/pako.js\"></script>\n\n<script src=\"../bower_components/color-thief/src/color-thief.js\"></script>\n\n<script src=\"../bower_components/uri.js/src/URI.js\"></script>\n\n<script src=\"../bower_components/Blob.js/Blob.js\"></script>\n<script src=\"../bower_components/canvas-toBlob.js/canvas-toBlob.js\"></script>\n<!-- endbuild -->\n\n<!-- ############################################################## -->\n<!-- # Infinity Core ############################################## -->\n<!-- ############################################################## -->\n<!-- build:js infinity-core.js -->\n<!-- Core -->\n<script src=\"infinity/core/object.js\"></script>\n<script src=\"infinity/core/system.js\"></script>\n<script src=\"infinity/core/cursor.js\"></script>\n<script src=\"infinity/core/key.js\"></script>\n<script src=\"infinity/core/locale.js\"></script>\n<script src=\"infinity/core/math.js\"></script>\n<script src=\"infinity/core/util.js\"></script>\n<!-- Event -->\n<script src=\"infinity/event/event.js\"></script>\n<script src=\"infinity/event/eventtarget.js\"></script>\n<script src=\"infinity/event/inputevent.js\"></script>\n<script src=\"infinity/event/keyevent.js\"></script>\n<script src=\"infinity/event/mouseevent.js\"></script>\n<!-- Geometry -->\n<script src=\"infinity/geometry/length.js\"></script>\n<script src=\"infinity/geometry/point.js\"></script>\n<script src=\"infinity/geometry/rect.js\"></script>\n<script src=\"infinity/geometry/transform.js\"></script>\n<!-- Vertex -->\n<script src=\"infinity/vertex/vertex.js\"></script>\n<script src=\"infinity/vertex/vertexsource.js\"></script>\n<script src=\"infinity/vertex/vertextarget.js\"></script>\n<script src=\"infinity/vertex/vertexcontainer.js\"></script>\n<script src=\"infinity/vertex/vertexinfo.js\"></script>\n<script src=\"infinity/vertex/vertexpixelaligner.js\"></script>\n<script src=\"infinity/vertex/vertextransformer.js\"></script>\n<script src=\"infinity/vertex/vertexoffsetter.js\"></script>\n<!-- Paint -->\n<script src=\"infinity/paint/pattern.js\"></script>\n<script src=\"infinity/paint/annotation.js\"></script>\n<script src=\"infinity/paint/bitmap.js\"></script>\n<script src=\"infinity/paint/font.js\"></script>\n<script src=\"infinity/paint/colorspace.js\"></script>\n<script src=\"infinity/paint/color.js\"></script>\n<script src=\"infinity/paint/colorprofile.js\"></script>\n<script src=\"infinity/paint/dirtylist.js\"></script>\n<script src=\"infinity/paint/gradient.js\"></script>\n<script src=\"infinity/paint/paintcanvas.js\"></script>\n<script src=\"infinity/paint/paintconfiguration.js\"></script>\n<script src=\"infinity/paint/paintcontext.js\"></script>\n<!-- Scene -->\n<script src=\"infinity/scene/node.js\"></script>\n<script src=\"infinity/scene/element.js\"></script>\n<script src=\"infinity/scene/block.js\"></script>\n<script src=\"infinity/scene/item.js\"></script>\n<script src=\"infinity/scene/scene.js\"></script>\n<script src=\"infinity/scene/scenepaintconfiguration.js\"></script>\n<script src=\"infinity/scene/selector.js\"></script>\n<script src=\"infinity/scene/style/style.js\"></script>\n<script src=\"infinity/scene/style/sharedstyle.js\"></script>\n<script src=\"infinity/scene/style/appliedstyle.js\"></script>\n<script src=\"infinity/scene/style/inlinestyle.js\"></script>\n<script src=\"infinity/scene/style/linkedstyle.js\"></script>\n<script src=\"infinity/scene/style/styleset.js\"></script>\n<script src=\"infinity/scene/style/styleentry.js\"></script>\n<script src=\"infinity/scene/style/filterentry.js\"></script>\n<script src=\"infinity/scene/style/effectentry.js\"></script>\n<script src=\"infinity/scene/style/paintentry.js\"></script>\n<script src=\"infinity/scene/style/veffectentry.js\"></script>\n<script src=\"infinity/scene/style/effect/shadoweffect.js\"></script>\n<script src=\"infinity/scene/style/filter/blurfilter.js\"></script>\n<script src=\"infinity/scene/style/paint/patternpaint.js\"></script>\n<script src=\"infinity/scene/style/paint/areapaint.js\"></script>\n<script src=\"infinity/scene/style/paint/fillpaint.js\"></script>\n<script src=\"infinity/scene/style/paint/strokepaint.js\"></script>\n<script src=\"infinity/scene/style/veffect/offsetveffect.js\"></script>\n<script src=\"infinity/scene/structure/page.js\"></script>\n<script src=\"infinity/scene/structure/layer.js\"></script>\n<script src=\"infinity/scene/structure/slice.js\"></script>\n<script src=\"infinity/scene/structure/swatch.js\"></script>\n<script src=\"infinity/scene/shape/shape.js\"></script>\n<script src=\"infinity/scene/shape/shapeset.js\"></script>\n<script src=\"infinity/scene/shape/pathbase.js\"></script>\n<script src=\"infinity/scene/shape/image.js\"></script>\n<script src=\"infinity/scene/shape/polygon.js\"></script>\n<script src=\"infinity/scene/shape/rectangle.js\"></script>\n<script src=\"infinity/scene/shape/ellipse.js\"></script>\n<script src=\"infinity/scene/shape/path.js\"></script>\n<script src=\"infinity/scene/shape/text.js\"></script>\n<!-- View -->\n<script src=\"infinity/view/stage.js\"></script>\n<script src=\"infinity/view/scenestage.js\"></script>\n<script src=\"infinity/view/widget.js\"></script>\n<script src=\"infinity/view/view.js\"></script>\n<!-- Root -->\n<script src=\"infinity/platform.js\"></script>\n<!-- I18N -->\n<script src=\"infinity/i18n/i18n_en.js\"></script>\n<script src=\"infinity/i18n/i18n_de.js\"></script>\n<!-- endbuild -->\n\n<!-- ############################################################## -->\n<!-- # Infinity-Editor ################################################### -->\n<!-- ############################################################## -->\n<!-- build:js infinity-editor.js -->\n<!-- Guide -->\n<script src=\"infinity-editor/guide/guides.js\"></script>\n<script src=\"infinity-editor/guide/guide.js\"></script>\n<script src=\"infinity-editor/guide/gridguide.js\"></script>\n<script src=\"infinity-editor/guide/unitguide.js\"></script>\n<script src=\"infinity-editor/guide/pageguide.js\"></script>\n<script src=\"infinity-editor/guide/shapeboxguide.js\"></script>\n<!-- Editor -->\n<script src=\"infinity-editor/scene/transformbox.js\"></script>\n<script src=\"infinity-editor/scene/elementeditor.js\"></script>\n<script src=\"infinity-editor/scene/blockeditor.js\"></script>\n<script src=\"infinity-editor/scene/sceneeditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/shapeeditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/shapeseteditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/pathbaseeditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/texteditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/ellipseeditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/rectangleeditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/polygoneditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/patheditor.js\"></script>\n<script src=\"infinity-editor/scene/shape/imageeditor.js\"></script>\n<script src=\"infinity-editor/scene/structure/pageeditor.js\"></script>\n<script src=\"infinity-editor/scene/structure/layereditor.js\"></script>\n<script src=\"infinity-editor/scene/structure/sliceeditor.js\"></script>\n<!-- Tool -->\n<script src=\"infinity-editor/tool/tool.js\"></script>\n<script src=\"infinity-editor/tool/toolmanager.js\"></script>\n<script src=\"infinity-editor/tool/selecttool.js\"></script>\n<script src=\"infinity-editor/tool/marqueetool.js\"></script>\n<script src=\"infinity-editor/tool/shapetool.js\"></script>\n<script src=\"infinity-editor/tool/subselecttool.js\"></script>\n<script src=\"infinity-editor/tool/lassotool.js\"></script>\n<script src=\"infinity-editor/tool/layertool.js\"></script>\n<script src=\"infinity-editor/tool/handtool.js\"></script>\n<script src=\"infinity-editor/tool/zoomtool.js\"></script>\n<script src=\"infinity-editor/tool/pathtool.js\"></script>\n<script src=\"infinity-editor/tool/pentool.js\"></script>\n<script src=\"infinity-editor/tool/bezigontool.js\"></script>\n<script src=\"infinity-editor/tool/linetool.js\"></script>\n<script src=\"infinity-editor/tool/rectangletool.js\"></script>\n<script src=\"infinity-editor/tool/ellipsetool.js\"></script>\n<script src=\"infinity-editor/tool/polygontool.js\"></script>\n<script src=\"infinity-editor/tool/texttool.js\"></script>\n<script src=\"infinity-editor/tool/pointertool.js\"></script>\n<script src=\"infinity-editor/tool/pagetool.js\"></script>\n<script src=\"infinity-editor/tool/transformtool.js\"></script>\n<script src=\"infinity-editor/tool/slicetool.js\"></script>\n<!-- View -->\n<script src=\"infinity-editor/view/editorbackstage.js\"></script>\n<script src=\"infinity-editor/view/editorscenestage.js\"></script>\n<script src=\"infinity-editor/view/editortoolstage.js\"></script>\n<script src=\"infinity-editor/view/editorfrontstage.js\"></script>\n<script src=\"infinity-editor/view/editorview.js\"></script>\n<!-- Root -->\n<script src=\"infinity-editor/editor.js\"></script>\n<script src=\"infinity-editor/editorpaintconfiguration.js\"></script>\n<!-- I18N -->\n<script src=\"infinity-editor/i18n/i18n_en.js\"></script>\n<script src=\"infinity-editor/i18n/i18n_de.js\"></script>\n<!-- endbuild -->\n\n\n<!-- build:js gravit.js -->\n<!-- Component -->\n<script src=\"application/component/autoedit.js\"></script>\n<script src=\"application/component/panel.js\"></script>\n<script src=\"application/component/patterntarget.js\"></script>\n<script src=\"application/component/colorbutton.js\"></script>\n<script src=\"application/component/colorpanel.js\"></script>\n<script src=\"application/component/cornertype.js\"></script>\n<script src=\"application/component/blendmode.js\"></script>\n<script src=\"application/component/unit.js\"></script>\n<script src=\"application/component/gradienteditor.js\"></script>\n<script src=\"application/component/overlay.js\"></script>\n<script src=\"application/component/pivot.js\"></script>\n<script src=\"application/component/stylepanel.js\"></script>\n<script src=\"application/component/swatchpanel.js\"></script>\n<script src=\"application/component/menu.js\"></script>\n<script src=\"application/component/menubar.js\"></script>\n<script src=\"application/component/menuitem.js\"></script>\n<script src=\"application/component/menubutton.js\"></script>\n<!-- Extension -->\n<script src=\"application/extension/action.js\"></script>\n<script src=\"application/extension/colormatcher.js\"></script>\n<script src=\"application/extension/exporter.js\"></script>\n<script src=\"application/extension/module.js\"></script>\n<script src=\"application/extension/view.js\"></script>\n<script src=\"application/extension/palette.js\"></script>\n<script src=\"application/extension/panel.js\"></script>\n<script src=\"application/extension/properties.js\"></script>\n<script src=\"application/extension/sidebar.js\"></script>\n<script src=\"application/extension/storage.js\"></script>\n<script src=\"application/extension/styleentry.js\"></script>\n<script src=\"application/extension/transformer.js\"></script>\n<!-- Workspace -->\n<script src=\"application/workspace/header.js\"></script>\n<script src=\"application/workspace/palettes.js\"></script>\n<script src=\"application/workspace/panels.js\"></script>\n<script src=\"application/workspace/sidebars.js\"></script>\n<script src=\"application/workspace/toolbar.js\"></script>\n<script src=\"application/workspace/window.js\"></script>\n<script src=\"application/workspace/windows.js\"></script>\n<!-- Util -->\n<script src=\"application/util/ciede2000.js\"></script>\n<script src=\"application/util/image.js\"></script>\n<script src=\"application/util/selectors.js\"></script>\n<!-- Root -->\n<script src=\"application/shell.js\"></script>\n<script src=\"application/application.js\"></script>\n<script src=\"application/document.js\"></script>\n<script src=\"application/bootstrap.js\"></script>\n<!-- I18N -->\n<script src=\"application/i18n/i18n_en.js\"></script>\n<script src=\"application/i18n/i18n_de.js\"></script>\n<!-- ############# -->\n<!-- BEGIN: GRAVIT-AddOn -->\n<!-- ############# -->\n<!-- Action -->\n<script src=\"gravit/action/addlayeraction.js\"></script>\n<script src=\"gravit/action/deletelayeraction.js\"></script>\n<script src=\"gravit/action/addpageaction.js\"></script>\n<script src=\"gravit/action/alignaction.js\"></script>\n<script src=\"gravit/action/cloneaction.js\"></script>\n<script src=\"gravit/action/closeaction.js\"></script>\n<script src=\"gravit/action/closeallaction.js\"></script>\n<script src=\"gravit/action/copyaction.js\"></script>\n<script src=\"gravit/action/copyattributesaction.js\"></script>\n<script src=\"gravit/action/cutaction.js\"></script>\n<script src=\"gravit/action/deleteaction.js\"></script>\n<script src=\"gravit/action/deletepageaction.js\"></script>\n<script src=\"gravit/action/distributeaction.js\"></script>\n<script src=\"gravit/action/duplicateaction.js\"></script>\n<script src=\"gravit/action/fitallaction.js\"></script>\n<script src=\"gravit/action/fitcurrentlayeraction.js\"></script>\n<script src=\"gravit/action/fitcurrentpageaction.js\"></script>\n<script src=\"gravit/action/fitselectionaction.js\"></script>\n<script src=\"gravit/action/groupaction.js\"></script>\n<script src=\"gravit/action/placeimageaction.js\"></script>\n<script src=\"gravit/action/invertselectionaction.js\"></script>\n<script src=\"gravit/action/layertypeaction.js\"></script>\n<script src=\"gravit/action/magnificationaction.js\"></script>\n<script src=\"gravit/action/newaction.js\"></script>\n<script src=\"gravit/action/newwindowaction.js\"></script>\n<script src=\"gravit/action/openaction.js\"></script>\n<script src=\"gravit/action/arrangeaction.js\"></script>\n<script src=\"gravit/action/originalviewaction.js\"></script>\n<script src=\"gravit/action/pixelpreviewaction.js\"></script>\n<script src=\"gravit/action/paintmodeaction.js\"></script>\n<script src=\"gravit/action/pasteaction.js\"></script>\n<script src=\"gravit/action/pasteinplaceaction.js\"></script>\n<script src=\"gravit/action/pasteinsideaction.js\"></script>\n<script src=\"gravit/action/pasteattributesaction.js\"></script>\n<script src=\"gravit/action/redoaction.js\"></script>\n<script src=\"gravit/action/saveaction.js\"></script>\n<script src=\"gravit/action/saveallaction.js\"></script>\n<script src=\"gravit/action/saveasaction.js\"></script>\n<script src=\"gravit/action/showrulersaction.js\"></script>\n<script src=\"gravit/action/selectallaction.js\"></script>\n<script src=\"gravit/action/showallpagesaction.js\"></script>\n<script src=\"gravit/action/showgridaction.js\"></script>\n<script src=\"gravit/action/slicefromselection.js\"></script>\n<script src=\"gravit/action/snapunitaction.js\"></script>\n<script src=\"gravit/action/transformaction.js\"></script>\n<script src=\"gravit/action/undoaction.js\"></script>\n<script src=\"gravit/action/ungroupaction.js\"></script>\n<script src=\"gravit/action/zoominaction.js\"></script>\n<script src=\"gravit/action/zoomoutaction.js\"></script>\n<!-- Colormatcher -->\n<script src=\"gravit/colormatcher/analogousmatcher.js\"></script>\n<script src=\"gravit/colormatcher/complementarymatcher.js\"></script>\n<!-- Exporter -->\n<script src=\"gravit/exporter/imagexporter.js\"></script>\n<!-- Palette -->\n<script src=\"gravit/palette/exportpalette.js\"></script>\n<script src=\"gravit/palette/stylepalette.js\"></script>\n<!-- Panel -->\n<script src=\"gravit/panel/propertiespanel.js\"></script>\n<script src=\"gravit/panel/transformpanel.js\"></script>\n<!-- Properties -->\n<script src=\"gravit/properties/documentproperties.js\"></script>\n<script src=\"gravit/properties/polygonproperties.js\"></script>\n<script src=\"gravit/properties/pathproperties.js\"></script>\n<script src=\"gravit/properties/rectangleproperties.js\"></script>\n<script src=\"gravit/properties/ellipseproperties.js\"></script>\n<script src=\"gravit/properties/imageproperties.js\"></script>\n<script src=\"gravit/properties/infoproperties.js\"></script>\n<script src=\"gravit/properties/pageproperties.js\"></script>\n<script src=\"gravit/properties/textproperties.js\"></script>\n<script src=\"gravit/properties/sliceproperties.js\"></script>\n<!-- Sidebar -->\n<script src=\"gravit/sidebar/pageslayerssidebar.js\"></script>\n<script src=\"gravit/sidebar/stylesswatchessidebar.js\"></script>\n<!-- Style-Entry -->\n<script src=\"gravit/styleentry/patternpaintentry.js\"></script>\n<script src=\"gravit/styleentry/areapaintentry.js\"></script>\n<script src=\"gravit/styleentry/fillpaintentry.js\"></script>\n<script src=\"gravit/styleentry/strokepaintentry.js\"></script>\n<script src=\"gravit/styleentry/blurfilterentry.js\"></script>\n<script src=\"gravit/styleentry/offsetveffectentry.js\"></script>\n<script src=\"gravit/styleentry/shadoweffectentry.js\"></script>\n<!-- Transformer -->\n<script src=\"gravit/transformer/aligntransformer.js\"></script>\n<script src=\"gravit/transformer/adjusttransformer.js\"></script>\n<!-- I18N -->\n<script src=\"gravit/i18n/i18n_en.js\"></script>\n<script src=\"gravit/i18n/i18n_de.js\"></script>\n<!-- Root -->\n<script src=\"gravit/gravit.js\"></script>\n<!-- ############# -->\n<!-- END: GRAVIT-MODULE -->\n<!-- ############# -->\n<!-- endbuild -->\n\n<!-- Development stuff -->\n\n<script src=\"development/bootstrap.js\"></script>\n<!-- Tests -->\n<script src=\"development/test/clone_scene.js\"></script>\n<script src=\"development/test/create_multiple_pages.js\"></script>\n<script src=\"development/test/create_rect_grid_page.js\"></script>\n<script src=\"development/test/serialize_scene.js\"></script>\n<script src=\"development/test/deserialize_scene.js\"></script>\n<!-- Root -->\n<script src=\"development/testaction.js\"></script>\n<script src=\"development/development.js\"></script>\n\n<!-- Include the proper shell for development -->\n<script type=\"text/javascript\">\n    if (this['process'] && this['require']) {\n        document.writeln(\"<script src=\\\"/shell/system/filestorage.js\\\" type=\\\"text\\/javascript\\\"><\\/script>\");\n        document.writeln(\"<script src=\\\"/shell/system/winstate.js\\\" type=\\\"text\\/javascript\\\"><\\/script>\");\n        document.writeln(\"<script src=\\\"/shell/system/shell.js\\\" type=\\\"text\\/javascript\\\"><\\/script>\");\n    } else {\n        document.writeln(\"<script src=\\\"/shell/browser/shell.js\\\" type=\\\"text\\/javascript\\\"><\\/script>\");\n    }\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "src/infinity/core/cursor.js",
    "content": "(function (_) {\n\n    /**\n     * @enum\n     */\n    var IFCursor = {\n        /**\n         * The default/auto cursor\n         */\n        Default: null,\n\n        /**\n         * Select cursor\n         * @version 1.0\n         */\n        Select: \"select\",\n\n        /**\n         * Select inverse cursor\n         * @version 1.0\n         */\n        SelectInverse: \"select-inverse\",\n\n        /**\n         * Select dot cursor\n         * @version 1.0\n         */\n        SelectDot: \"select-dot\",\n\n        /**\n         * Select dot inverse cursor\n         * @version 1.0\n         */\n        SelectDotInverse: \"select-dot-inverse\",\n\n        /**\n         * Select transform box rotation center cursor\n         */\n        SelectArrowOnly: \"select-arrow-only\",\n\n        /**\n         * Select transform box move cursor\n         */\n        SelectCross: \"select-cross\",\n\n        /**\n         * Select transform box resize vertically cursor\n         */\n        SelectResizeVert: \"select-resize-vert\",\n\n        /**\n         * Select transform box resize horizontally cursor\n         */\n        SelectResizeHoriz: \"select-resize-horiz\",\n\n        /**\n         * Select transform box resize via up left or down right corner cursor\n         */\n        SelectResizeUpLeftDownRight: \"select-upleft-downright\",\n\n        /**\n         * Select transform box resize via up right or down left corner cursor\n         */\n        SelectResizeUpRightDownLeft: \"select-upright-downleft\",\n\n        /**\n         * Select transform box skew vertically cursor\n         */\n        SelectSkewVert: \"select-skew-vert\",\n\n        /**\n         * Select transform box skew horizontally cursor\n         */\n        SelectSkewHoriz: \"select-skew-horiz\",\n\n        /**\n         * Select transform box rotation cursors\n         */\n        SelectRotate: [\"select-rot-tl\", \"select-rot-tc\", \"select-rot-tr\", \"select-rot-rc\", \"select-rot-br\",\n            \"select-rot-bc\", \"select-rot-bl\", \"select-rot-lc\"],\n\n        /**\n         * Zoom-Plus cursor\n         * @version 1.0\n         */\n        ZoomPlus: \"zoom-plus\",\n\n        /**\n         * Zoom-Minus cursor\n         * @version 1.0\n         */\n        ZoomMinus: \"zoom-minus\",\n\n        /**\n         * Zoom-None cursor\n         * @version 1.0\n         */\n        ZoomNone: \"zoom-none\",\n\n        /**\n         * Opened hand cursor\n         * @version 1.0\n         */\n        HandOpen: \"hand-open\",\n\n        /**\n         * Closed hand cursor\n         * @version 1.0\n         */\n        HandClosed: \"hand-closed\",\n\n        /**\n         * A small cross\n         * @version 1.0\n         */\n        Cross: \"cross\",\n\n        /**\n         * A pen\n         * @version 1.0\n         */\n        Pen: \"pen\",\n\n        /**\n         * A pen with a start indicator\n         * @version 1.0\n         */\n        PenStart: \"pen-start\",\n\n        /**\n         * A pen with an end indicator\n         * @version 1.0\n         */\n        PenEnd: \"pen-end\",\n\n        /**\n         * A pen with a plus indicator\n         * @version 1.0\n         */\n        PenPlus: \"pen-plus\",\n\n\n        /**\n         * A pen with a minus indicator\n         * @version 1.0\n         */\n        PenMinus: \"pen-minus\",\n\n        /**\n         * A pen with a modify indicator\n         * @version 1.0\n            */\n        PenModify: \"pen-modify\",\n\n        /**\n         * A black arrow\n         * @version 1.0\n         */\n        PenDrag: \"pen-drag\",\n\n        /**\n         * A lasso\n         * @version 1.0\n         */\n        Lasso: \"lasso\",\n\n        /**\n         * A pipette / eyedropper\n         */\n        Pipette: \"pipette\",\n\n        /**\n         * A text marker (beam)\n         */\n        Text: \"text\"\n    };\n\n    _.IFCursor = IFCursor;\n})(this);"
  },
  {
    "path": "src/infinity/core/key.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFKey\n     * @constructor\n     * @version 1.0\n     */\n    function IFKey() {\n    };\n\n    /**\n     * Enumeration of available key code constants\n     * @version 1.0\n     */\n    IFKey.Constant = {\n        /**\n         * A printable character\n         * @version 1.0\n         */\n        CHARACTER: 0,\n\n        /**\n         * Space key\n         * @version 1.0\n         */\n        SPACE: 1,\n\n        /**\n         * Enter key\n         * @version 1.0\n         */\n        ENTER: 2,\n\n        /**\n         * Tab key\n         * @version 1.0\n         */\n        TAB: 3,\n\n        /**\n         * Backspace key\n         * @version 1.0\n         */\n        BACKSPACE: 4,\n\n        /**\n         * Control key\n         * @version 1.0\n         */\n        CONTROL: 5,\n\n        /**\n         * Shift key\n         * @version 1.0\n         */\n        SHIFT: 6,\n\n        /**\n         * Alt key\n         * @version 1.0\n         */\n        ALT: 7,\n\n        /**\n         * Left arrow\n         * @version 1.0\n         */\n        LEFT: 8,\n\n        /**\n         * Up arrow\n         * @version 1.0\n         */\n        UP: 9,\n\n        /**\n         * Right arrow\n         * @version 1.0\n         */\n        RIGHT: 10,\n\n        /**\n         * Down arrow\n         * @version 1.0\n         */\n        DOWN: 11,\n\n        /**\n         * Page-up key\n         * @version 1.0\n         */\n        PAGE_UP: 12,\n\n        /**\n         * Page-down key\n         * @version 1.0\n         */\n        PAGE_DOWN: 13,\n\n        /**\n         * Home/POS1 key\n         * @version 1.0\n         */\n        HOME: 14,\n\n        /**\n         * End key\n         * @version 1.0\n         */\n        END: 15,\n\n        /**\n         * Insert key\n         * @version 1.0\n         */\n        INSERT: 16,\n\n        /**\n         * Delete key\n         * @version 1.0\n         */\n        DELETE: 17,\n\n        /**\n         * Command key\n         * @version 1.0\n         */\n        COMMAND: 19,\n\n        /**\n         * Function Key 'F1'\n         */\n        F1: 30,\n\n        /**\n         * Function Key 'F2'\n         */\n        F2: 31,\n\n        /**\n         * Function Key 'F3'\n         */\n        F3: 32,\n\n        /**\n         * Function Key 'F4'\n         */\n        F4: 33,\n\n        /**\n         * Function Key 'F5'\n         */\n        F5: 34,\n\n        /**\n         * Function Key 'F6'\n         */\n        F6: 35,\n\n        /**\n         * Function Key 'F7'\n         */\n        F7: 36,\n\n        /**\n         * Function Key 'F8'\n         */\n        F8: 37,\n\n        /**\n         * Function Key 'F9'\n         */\n        F9: 38,\n\n        /**\n         * Function Key 'F10'\n         */\n        F10: 39,\n\n        /**\n         * Function Key 'F11'\n         */\n        F11: 40,\n\n        /**\n         * Function Key 'F12'\n         */\n        F12: 41,\n\n        // Special identifiers\n\n        /**\n         * Meta key (command on mac, control on others)\n         * @version 1.0\n         */\n        META: 100,\n\n        /**\n         * Option key (mostly alt)\n         * @version 1.0\n         */\n        OPTION: 101,\n\n        /**\n         * Remove key (backspace on mac, del on others)\n         */\n        REMOVE: 102\n    };\n\n    IFKey.prototype.translateKey = function (keyCode) {\n        var result = null;\n        switch (keyCode) {\n            case 32 :\n                result = IFKey.Constant.SPACE;\n                break;\n            case 13 :\n                result = IFKey.Constant.ENTER;\n                break;\n            case 9 :\n                result = IFKey.Constant.TAB;\n                break;\n            case 8 :\n                result = IFKey.Constant.BACKSPACE;\n                break;\n            case 16 :\n                result = IFKey.Constant.SHIFT;\n                break;\n            case 17:\n                result = IFKey.Constant.CONTROL;\n                break;\n            case 18:\n                result = IFKey.Constant.ALT;\n                break;\n            case 37 :\n                result = IFKey.Constant.LEFT;\n                break;\n            case 38 :\n                result = IFKey.Constant.UP;\n                break;\n            case 39 :\n                result = IFKey.Constant.RIGHT;\n                break;\n            case 40 :\n                result = IFKey.Constant.DOWN;\n                break;\n            case 33 :\n                result = IFKey.Constant.PAGE_UP;\n                break;\n            case 34 :\n                result = IFKey.Constant.PAGE_DOWN;\n                break;\n            case 36 :\n                result = IFKey.Constant.HOME;\n                break;\n            case 35 :\n                result = IFKey.Constant.END;\n                break;\n            case 45 :\n                result = IFKey.Constant.INSERT;\n                break;\n            case 46 :\n                result = IFKey.Constant.DELETE;\n                break;\n            case 112 :\n                result = IFKey.Constant.F1;\n                break;\n            case 113 :\n                result = IFKey.Constant.F2;\n                break;\n            case 114 :\n                result = IFKey.Constant.F3;\n                break;\n            case 115 :\n                result = IFKey.Constant.F4;\n                break;\n            case 116 :\n                result = IFKey.Constant.F5;\n                break;\n            case 117 :\n                result = IFKey.Constant.F6;\n                break;\n            case 118 :\n                result = IFKey.Constant.F7;\n                break;\n            case 119 :\n                result = IFKey.Constant.F8;\n                break;\n            case 120 :\n                result = IFKey.Constant.F9;\n                break;\n            case 121 :\n                result = IFKey.Constant.F10;\n                break;\n            case 122 :\n                result = IFKey.Constant.F11;\n                break;\n            case 123 :\n                result = IFKey.Constant.F12;\n                break;\n            default:\n                break;\n        }\n\n        if (result == null) {\n            result = String.fromCharCode(keyCode);\n        }\n\n        return result;\n    };\n\n    IFKey.prototype.transformKey = function (keyCode) {\n        if (keyCode === IFKey.Constant.META || keyCode === IFKey.Constant.COMMAND) {\n            if (ifSystem.operatingSystem === IFSystem.OperatingSystem.OSX_IOS && ifSystem.hardware === IFSystem.Hardware.Desktop) {\n                return IFKey.Constant.COMMAND;\n            } else {\n                return IFKey.Constant.CONTROL;\n            }\n        } else if (keyCode === IFKey.Constant.OPTION) {\n            return IFKey.Constant.ALT;\n        } else if (keyCode === IFKey.Constant.REMOVE) {\n            if (ifSystem.operatingSystem === IFSystem.OperatingSystem.OSX_IOS) {\n                return IFKey.Constant.BACKSPACE;\n            } else {\n                return IFKey.Constant.DELETE;\n            }\n        } else {\n            return keyCode;\n        }\n    };\n\n    IFKey.prototype.toLocalizedName = function (keyCode) {\n        keyCode = this.transformKey(keyCode);\n        return ifLocale.getValue(IFKey, \"key.\" + keyCode.toString());\n    };\n\n    IFKey.prototype.toLocalizedShort = function (keyCode) {\n        // Handle special chars on mac\n        if (ifSystem.operatingSystem === IFSystem.OperatingSystem.OSX_IOS && ifSystem.hardware === IFSystem.Hardware.Desktop) {\n            if (keyCode == IFKey.Constant.TAB) {\n                return '\\u21E5';\n            } else if (keyCode == IFKey.Constant.OPTION || keyCode == IFKey.Constant.ALT) {\n                return '\\u2325';\n            } else if (keyCode == IFKey.Constant.META || keyCode == IFKey.Constant.COMMAND) {\n                return '\\u2318';\n            } else if (keyCode == IFKey.Constant.SHIFT) {\n                return '\\u21E7';\n            } else if (keyCode == IFKey.Constant.CONTROL) {\n                return '\\u2303';\n            } else if (keyCode == IFKey.Constant.SPACE) {\n                return '\\u2423';\n            } else if (keyCode == IFKey.Constant.ENTER) {\n                return '\\u23CE';\n            } else if (keyCode == IFKey.Constant.REMOVE) {\n                return '\\u232B';\n            } else if (keyCode == IFKey.Constant.UP) {\n                return '\\u2191';\n            } else if (keyCode == IFKey.Constant.DOWN) {\n                return '\\u2193';\n            } else if (keyCode == IFKey.Constant.LEFT) {\n                return '\\u2190';\n            } else if (keyCode == IFKey.Constant.RIGHT) {\n                return '\\u2192';\n            }\n        }\n\n        keyCode = this.transformKey(keyCode);\n        var name = ifLocale.getValue(IFKey, \"key.\" + keyCode.toString() + \".short\", null);\n        if (!name) {\n            return ifLocale.getValue(IFKey, \"key.\" + keyCode.toString());\n        } else {\n            return name;\n        }\n    };\n\n    IFKey.prototype.toSystemShortcut = function (character) {\n        if (ifSystem.operatingSystem === IFSystem.OperatingSystem.OSX_IOS && ifSystem.hardware === IFSystem.Hardware.Desktop) {\n            if (character === '-') {\n                return '\\u2212';\n            } else if (character === '+') {\n                return '\\u002B';\n            }\n        }\n        return character.toUpperCase();\n    }\n\n    IFKey.prototype.shortcutToString = function (shortcut) {\n        var result = \"\";\n        for (var i = 0; i < shortcut.length; ++i) {\n            if (i > 0) {\n                // On platform others than mac we'll use a separator\n                if (ifSystem.operatingSystem != IFSystem.OperatingSystem.OSX_IOS) {\n                    result += \"+\";\n                }\n            }\n            if (typeof shortcut[i] == 'number') {\n                result += this.toLocalizedShort(shortcut[i]);\n            } else {\n                // Return uppercase chars\n                result += this.toSystemShortcut(shortcut[i]);\n            }\n        }\n        return result;\n    };\n\n    _.IFKey = IFKey;\n    _.ifKey = new IFKey();\n})(this);"
  },
  {
    "path": "src/infinity/core/locale.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFLocale\n     * @extends IFObject\n     * @constructor\n     * @version 1.0\n     */\n    function IFLocale() {\n        this._values = {};\n        this._functions = {};\n\n        // Try to setup default language using system\n        if (\"en\" === ifSystem.language) {\n            this.setLanguage(IFLocale.Language.English);\n        } else if (\"de\" === ifSystem.language) {\n            this.setLanguage(IFLocale.Language.German);\n        }\n    };\n    IFObject.inheritAndMix(IFLocale, IFObject);\n\n    /**\n     * Enumeration of supported languages\n     * @enum\n     */\n    IFLocale.Language = {\n        /**\n         * English language\n         * @type {Number}\n         * @version 1.0\n         */\n        English: 0,\n\n        /**\n         * German language\n         * @type {Number}\n         * @version 1.0\n         */\n        German: 1,\n\n        /**\n         * Default language (english)\n         * @type {Number}\n         * @version 1.0\n         */\n        Default: 0\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFLocale.Key Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @param {Function|Object} clazz\n     * @param {String} key\n     * @class IFLocale.Key\n     * @constructor\n     */\n    IFLocale.Key = function (clazz, key) {\n        this._type_id = IFObject.getTypeId(clazz);\n        this._key = key;\n    };\n\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFLocale Constants\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * Enumeration of builtin language constants\n     * @enum\n     */\n    IFLocale.Constant = {\n        Create: new IFLocale.Key(IFLocale, \"create\"),\n        Add: new IFLocale.Key(IFLocale, \"add\"),\n        Edit: new IFLocale.Key(IFLocale, \"edit\"),\n        Remove: new IFLocale.Key(IFLocale, \"remove\"),\n        Delete: new IFLocale.Key(IFLocale, \"delete\"),\n        Open: new IFLocale.Key(IFLocale, \"open\"),\n        Save: new IFLocale.Key(IFLocale, \"save\"),\n        Cancel: new IFLocale.Key(IFLocale, \"cancel\"),\n        Ok: new IFLocale.Key(IFLocale, \"ok\"),\n        Close: new IFLocale.Key(IFLocale, \"close\"),\n        Loading: new IFLocale.Key(IFLocale, \"loading\"),\n        LoadingOf: new IFLocale.Key(IFLocale, \"loading_of\"),\n        Saving: new IFLocale.Key(IFLocale, \"saving\"),\n        SavingOf: new IFLocale.Key(IFLocale, \"saving_of\"),\n        Success: new IFLocale.Key(IFLocale, \"success\"),\n        Failure: new IFLocale.Key(IFLocale, \"failure\"),\n        Waiting: new IFLocale.Key(IFLocale, \"waiting\")\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFLocale Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFLocale.prototype._language = 0;\n\n    /**\n     * @type {{}}\n     * @private\n     */\n    IFLocale.prototype._values = null;\n\n    /**\n     * @type {{}}\n     * @private\n     */\n    IFLocale.prototype._functions = null;\n\n    /**\n     * Get the locale's current language\n     * @returns {Number}\n     * @version 1.0\n     */\n    IFLocale.prototype.getLanguage = function () {\n        return this._language;\n    };\n\n    /**\n     * Set the locale's current language\n     * @param {Number} language\n     * @version 1.0\n     */\n    IFLocale.prototype.setLanguage = function (language) {\n        if (language != this._language) {\n            this._language = language;\n        }\n    };\n\n    /**\n     * Get a localized value by using a given key. If the given key\n     * is an instance of IFLocale.Key then a lookup with the key takes\n     * place. Otherwise, the key itself will be returned which allows\n     * i.e. to provider either a string or a IFLocale.Key to this function.\n     * @param {IFLocale.Key|*} key\n     * @version 1.0\n     */\n    IFLocale.prototype.get = function (key) {\n        return key != null && key instanceof IFLocale.Key ? this.getValueByKey(key) : key;\n    };\n\n    /**\n     * Get a localized value for the current language.\n     * If there's no localized value for the current language\n     * available then this will try to return the default language's.\n     * @param {*} clazz the class to gather a value for\n     * @param {String} key the key of the value\n     * @param {String} [default_] default value to be returned if key not found\n     * @return {String} a localized value\n     * @throws Error when the value was not found\n     */\n    IFLocale.prototype.getValue = function (clazz, key, default_) {\n        var type_id = IFObject.getTypeId(clazz);\n\n        var result = this._getValue(this._language, type_id, key);\n        if (!result && this._language != IFLocale.Language.Default/* && typeof default_ == 'undefined'*/) {\n            result = this._getValue(IFLocale.Language.Default, type_id, key);\n        }\n        if (!result && typeof default_ == 'undefined') {\n            throw new Error(\"No value found for \" + IFObject.getName(clazz) + \" and key \" + key);\n        } else if (!result) {\n            return default_;\n        }\n        return result;\n    };\n\n    /**\n     * Get a localized value by using a given key\n     * @param {IFLocale.Key} localeKey\n     * @see getValue(clazz, key)\n     * @version 1.0\n     */\n    IFLocale.prototype.getValueByKey = function (localeKey) {\n        return this.getValue(localeKey._type_id, localeKey._key);\n    };\n\n    /**\n     * Register one or more localized values\n     * @param {*} clazz the class to register a value for\n     * @param {Number} language the language to register a value for\n     * @param {Array<String>} keys an array of keys to register\n     * @param {Array<String>} values an array of values to register\n     * @version 1.0\n     */\n    IFLocale.prototype.setValues = function (clazz, language, keys, values) {\n        var typeId = IFObject.getTypeId(clazz);\n\n        var locale = this._values[language];\n        if (!locale) {\n            locale = this._values[language] = {};\n        }\n        var vals = locale[typeId];\n        if (!vals) {\n            vals = locale[typeId] = {};\n        }\n\n        for (var i = 0; i < keys.length; ++i) {\n            vals[keys[i]] = values[i];\n        }\n    };\n\n    /**\n     * @param {Number} language\n     * @param {Number} type_id\n     * @param {String} key\n     * @return {String}\n     * @private\n     */\n    IFLocale.prototype._getValue = function (language, type_id, key) {\n        var locale = this._values[language];\n        if (locale) {\n            var vals = locale[type_id];\n            if (vals) {\n                return vals[key];\n            }\n        }\n    };\n\n    /**\n     * Register a localized function\n     * @param {Number} language the language to register a function for\n     * @param {String} key the key of the function to register for\n     * @param {Function} func the function to register\n     * @version 1.0\n     */\n    IFLocale.prototype.setFunction = function (language, key, func) {\n        var functions = this._functions[language];\n        if (!functions) {\n            functions = this._functions[language] = {};\n        }\n        functions[key] = func;\n    };\n\n    /**\n     * Get a locale function for the current language, falling\n     * back to the default language if none was found\n     *\n     * @param {String} key the key of the function to get\n     * @return {Function}\n     */\n    IFLocale.prototype.getFunction = function (key) {\n        var functions = this._functions[this._language];\n        if (functions) {\n            if (functions.hasOwnProperty(key)) {\n                return functions[key];\n            }\n        }\n\n        if (this._language != IFLocale.Language.Default) {\n            var functions = this._functions[IFLocale.Language.Default];\n            if (functions) {\n                if (functions.hasOwnProperty(key)) {\n                    return functions[key];\n                }\n            }\n        }\n\n        return null;\n    };\n\n    /** @override */\n    IFLocale.prototype.toString = function () {\n        return \"[Object IFLocale]\";\n    };\n\n    _.IFLocale = IFLocale;\n    _.ifLocale = new IFLocale();\n})(this);"
  },
  {
    "path": "src/infinity/core/math.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFMath\n     * @constructor\n     * @version 1.0\n     */\n    function IFMath() {\n    };\n\n    /**\n     * 2 * Math.PI\n     * @type {Number}\n     * @version 1.0\n     */\n    IFMath.prototype.PI2 = 2 * Math.PI;\n\n    /**\n     * 0.5 * Math.PI\n     * @type {Number}\n     * @version 1.0\n     */\n    IFMath.prototype.PIHALF = 0.5 * Math.PI;\n\n    /**\n     * The default epsilon to compare, defaults to 1.0e-14\n     */\n    IFMath.prototype.defaultEps = 1e-14;\n\n    /**\n     * Convert an angle in degrees into radians\n     * @param {Number} angle in degrees\n     * @return {Number} angle in radians\n     * @version 1.0\n     */\n    IFMath.prototype.toRadians = function (angle) {\n        return angle * Math.PI / 180;\n    };\n\n    /**\n     * Convert an angle in radians to degrees\n     * @param {Number} angle in radians\n     * @return {Number} angle in degrees\n     * @version 1.0\n     */\n    IFMath.prototype.toDegrees = function (angle) {\n        return angle * 180 / Math.PI;\n    };\n\n    /**\n     * Adjusts a given angle so that it was within 0 .. and 2 * Math.PI\n     * @param {Number} angle the angle to adjust in radians\n     * @return {Number} an adjusted angle\n     */\n    IFMath.prototype.normalizeAngleRadians = function (angle) {\n        if (angle >= 0) {\n            return this.mod(angle, this.PI2);\n        } else {\n            return angle + this.PI2 * Math.floor(-angle / this.PI2 + 1);\n        }\n    };\n\n    /**\n     * Adjusts a given angle so that it was within 0 .. and 360°\n     * @param {Number} angle the angle to adjust in degrees\n     * @return {Number} an adjusted angle\n     */\n    IFMath.prototype.normalizeAngleDegrees = function (angle) {\n        if (angle >= 0) {\n            return this.mod(angle, 360);\n        } else {\n            return angle + 360 * Math.floor(-angle / 360 + 1);\n        }\n    };\n\n    /**\n     * Normalize a value to be in a given range\n     * @param {Number} value\n     * @param {Number} min\n     * @param {Number} max\n     * @return {Number} min <= value >= max\n     */\n    IFMath.prototype.normalizeValue = function (value, min, max) {\n        return value < min ? min : (value > max ? max : value);\n    };\n\n    /**\n     * Compare two values for equality using an epsilon value\n     * @param {Number} v1 value one\n     * @param {Number} v2 value two\n     * @param {Number} [epsilon] the epsilon to compare, defaults to IFMath.prototype.defaultEps\n     * @return {Boolean} true if v1 == v2 using epsilon, otherwise false\n     * @version 1.0\n     */\n    IFMath.prototype.isEqualEps = function (v1, v2, epsilon) {\n        if (!epsilon) epsilon = this.defaultEps;\n        return Math.abs(v1 - v2) <= epsilon;\n    };\n\n    /**\n     * Round a given number with a given precision\n     * @param {Number} value the number to round\n     * @param {Boolean} [halfDown] If set to true, rounds\n     * half down (i.e. 1.5 becomes 1) else rounds half up (default)\n     * @param {Number} [precision] the precision of decimal numbers\n     * to use. A value of zero (default) rounds to integers\n     * @returns {Number}\n     */\n    IFMath.prototype.round = function (value, halfDown, precision) {\n        precision = Math.abs(precision) || 0;\n        var coefficient = precision ? Math.pow(10, precision) : 1;\n        if (halfDown) {\n            return Math.ceil(value * coefficient - 0.5) / coefficient;\n        } else {\n            return Math.round(value * coefficient) / coefficient;\n        }\n    };\n\n    /**\n     * @return {Number} x mod y\n     * @version 1.0\n     */\n    IFMath.prototype.mod = function (x, y) {\n        if (x < 0) {\n            return -this.mod(-x, y);\n        } else {\n            return x - Math.floor(x / y) * y;\n        }\n    };\n\n    /**\n     * @return {Number} x div y\n     * @version 1.0\n     */\n    IFMath.prototype.div = function (x, y) {\n        if (x < 0) {\n            return -Math.floor(-x / y);\n        } else {\n            return Math.floor(x / y);\n        }\n    };\n\n    /**\n     * Finds an intersection point of two segments,\n     * returns true if found\n     * @param {Number} a1x, a1y, a2x, a2y coordinates of the end points of the first segment\n     * @param {Number} b1x, b1y, b2x, b2y coordinates of the end points of the second segment\n     * @param {Array} [result] - if passed, intersection point between lines is calculated  even if segments don't\n     * intersect and parameter values for both segments are written into this array\n     * @return {IFPoint} an intersection point if the segments intersect, null otherwise\n     */\n    IFMath.prototype.getIntersectionPoint = function (a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, result) {\n        // segments intersect when the system below has the only one solution (ta, tb):\n        // a1x + ta (a2x - a1x) = a1x + tb (b2x - b1x)\n        // a1y + ta (a2y - a1y) = a1y + tb (b2y - b1y)\n        // and 0 <= ta <= 1, 0 <=tb <= 1\n        var d = (a1x - a2x) * (b2y - b1y) - (a1y - a2y) * (b2x - b1x);\n        var da = (a1x - b1x) * (b2y - b1y) - (a1y - b1y) * (b2x - b1x);\n        var db = (a1x - a2x) * (a1y - b1y) - (a1y - a2y) * (a1x - b1x);\n\n        if (Math.abs(d) < this.defaultEps) {\n            // segments are parallel\n            return null;\n        } else {\n            var ta = da / d;\n            var tb = db / d;\n            if (!result && (0 <= ta) && (ta <= 1) && (0 <= tb) && (tb <= 1) || result) {\n                if (result) {\n                    result[0] = ta;\n                    result[1] = tb;\n                }\n                // segments intersect, find an intersection point\n                return new IFPoint(a1x + ta * (a2x - a1x), a1y + ta * (a2y - a1y));\n            }\n        }\n\n        // segments are on lines which intersection, but the intersection point is outside of the segments,\n        // and we don't need this point as !result\n        return null;\n    };\n\n    /**\n     * Calculates intersection points of circle and line\n     * @param {Number} xL - line start point X coordinate\n     * @param {Number} yL - line start point Y coordinate\n     * @param {Number} dxL - line X slope\n     * @param {Number} dyL - line Y slope\n     * @param {Number} xC - circle center X coordinate\n     * @param {Number} yC - circle center Y coordinate\n     * @param {Number} rC - circle radius\n     * @param {Array{Number}} result - array of 0 - 2 line parameter values\n     */\n    IFMath.prototype.circleLineIntersection = function (xL, yL, dxL, dyL, xC, yC, rC, result) {\n        // (x - xC)^2 + (y - yC)^2 - rC^2 = 0\n        // x = xL + dxL * t\n        // y = yL + dyL * t\n        // From the quadratic equation for t, we get discriminant:\n        var rSqr = rC * rC;\n        var dxLSqr = dxL * dxL;\n        var dyLSqr = dyL * dyL;\n        var dev = dxLSqr + dyLSqr;\n        if (this.isEqualEps(dev, 0)) {\n            return;\n        }\n\n        var tmp = dxL * (yC - yL) - dyL * (xC - xL);\n        var discr = rSqr * dev - (tmp * tmp);\n\n        if (this.isEqualEps(discr, 0)) { // line is tangent to circle\n            result[0] = (dxL * (xC - xL) + dyL * (yC - yL)) / dev;\n        } else if (discr > 0) { // line intersects circle in two points\n            tmp = dxL * (xC - xL) + dyL * (yC - yL);\n            result[0] = (tmp - Math.sqrt(discr)) / dev;\n            result[1] = (tmp + Math.sqrt(discr)) / dev;\n        }\n    };\n\n    /**\n     * Calculates intersection points of two circles\n     * @param {Number} xC1 - the first circle center X coordinate\n     * @param {Number} yC1 - the first circle center Y coordinate\n     * @param {Number} rC1 - the first circle radius\n     * @param {Number} xC2 - the second circle center X coordinate\n     * @param {Number} yC2 - the second circle center Y coordinate\n     * @param {Number} rC2 - the second circle radius\n     * @param {Array{IFPoint}} result\n     */\n    IFMath.prototype.circleCircleIntersection = function (xC1, yC1, rC1, xC2, yC2, rC2, result) {\n        // To find intersection points, the formulas from here are used:\n        // http://www.sonoma.edu/users/w/wilsonst/papers/Geometry/circles/default.html\n        var dSqr = this.ptSqrDist(xC1, yC1, xC2, yC2);\n        var resid = Math.abs(rC1 - rC2);\n        var rSqr = resid * resid;\n        var rSum = rC1 + rC2;\n        var rSumSqr = rSum * rSum;\n        if (!this.isEqualEps(dSqr, 0)) {\n            var tmp = (rC1 * rC1 - rC2 * rC2) / (2 * dSqr);\n            var x = (xC1 + xC2) / 2 + (xC2 - xC1) * tmp;\n            var y = (yC1 + yC2) / 2 + (yC2 - yC1) * tmp;\n            if (this.isEqualEps(dSqr, rSumSqr) || !this.isEqualEps(dSqr, 0) && this.isEqualEps(dSqr, rSqr)) {\n                result[0] = new IFPoint(x, y);\n            } else if (rSqr < dSqr && dSqr < rSumSqr ) {\n                tmp = Math.sqrt((rSumSqr - dSqr) * (dSqr - rSqr)) / (2 * dSqr);\n                var xTmp = (yC2 - yC1) * tmp;\n                var yTmp = (xC1 - xC2) * tmp;\n                result[0] = new IFPoint(x + xTmp, y + yTmp);\n                result[1] = new IFPoint(x - xTmp, y - yTmp);\n            }\n        }\n    };\n\n    /**\n     * Returns intersection point of 2 lines, or null if they are parallel\n     * Lines are given as: a1*x + b1*y +c1 = 0 and a2*x + b2*y +c2 = 0\n     * @param {Number} a1, b1, c1 - coefficients of the first line\n     * @param {Number} a2, b2, c2 - coefficients of the second line\n     * @return {IFPoint} an intersection point if the lines intersection, null otherwise\n     * @version 1.0\n     */\n    IFMath.prototype.getLinesIntersection = function (a1, b1, c1, a2, b2, c2) {\n        var d = a1 * b2 - a2 * b1;\n        if (this.isEqualEps(d, 0)) {\n            return null;\n        }\n        return new IFPoint((b1 * c2 - b2 * c1) / d, (c1 * a2 - c2 * a1) / d);\n    };\n\n    /**\n     * Finds and returns coordinates of the center of circumcircle of the triangle\n     * null is returned if some points are equal\n     * @param {Number} x1 - coordinate of the first triangle vertex\n     * @param {Number} y1 - coordinate of the first triangle vertex\n     * @param {Number} x2 - coordinate of the second triangle vertex\n     * @param {Number} y2 - coordinate of the second triangle vertex\n     * @param {Number} x3 - coordinate of the third triangle vertex\n     * @param {Number} y3 - coordinate of the third triangle vertex\n     * @returns {IFPoint} - center coordinates\n     * @version 1.0\n     */\n    IFMath.prototype.getCircumcircleCenter = function (x1, y1, x2, y2, x3, y3) {\n        // Center of circumcircle of the triangle is an intersection point of perpendicular bisectors\n        // Perpendicular bisector (x1,x2)(y1,y2): (x1 - x2)*(x - (x1+x2)/2) + (y1 - y2)*(y - (y1*y2)/2) = 0\n        var dx1 = x1 - x2;\n        var dy1 = y1 - y2;\n        var dx2 = x2 - x3;\n        var dy2 = y2 - y3;\n\n        return this.getLinesIntersection(dx1, dy1, -dx1 * (x1 + x2) / 2 - dy1 * (y1 + y2) / 2,\n            dx2, dy2, -dx2 * (x2 + x3) / 2 - dy2 * (y2 + y3) / 2);\n    };\n\n    /**\n     * Finds a point at some offset from a segment start,\n     * @param {Number} x1, y1, x2, y2 coordinates of a segment end points\n     * @param {Number} [offs] offset from a segment start point (x1, y1)\n     * @return {IFPoint} a point at offset from the segment start, if offset appears between segment end points,\n     *  or the nearest to offset end-point otherwise\n     * @version 1.0\n     */\n    IFMath.prototype.getPointAtLength = function (x1, y1, x2, y2, offs) {\n        var len;\n        var t;\n\n        if (offs <= 0) {\n            return new IFPoint(x1, y1);\n        }\n\n        len = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n        if (offs >= len) {\n            return new IFPoint(x2, y2);\n        }\n        t = offs / len; // len != 0 as  0 <= offs < len\n        return new IFPoint(x1 + t * (x2 - x1), y1 + t * (y2 - y1));\n    };\n\n    /**\n     * Finds a coordinate of a point on parametric quadratic Bezier curve at parameter value t\n     * @param {Number} p1 a corresponding coordinate of the start point\n     * @param {Number} p2 a corresponding coordinate of the end point\n     * @param {Number} c a corresponding coordinate of the control point\n     * @param {Number} t - a parameter value\n     * @return {Number} a coordinate of a point on curve at parameter value t\n     * @version 1.0\n     */\n    IFMath.prototype.getCurveAtT = function (p1, p2, c, t) {\n        var a = p1 + t * (c - p1);\n        var b = c + t * (p2 - c);\n        return a + t * (b - a);\n    };\n\n    /**\n     * Finds a coordinate of a point on parametric cubic Bezier curve at parameter value t\n     * @param {Number} p1 a corresponding coordinate of the start point\n     * @param {Number} p2 a corresponding coordinate of the end point\n     * @param {Number} c1 a corresponding coordinate of the first control point\n     * @param {Number} c2 a corresponding coordinate of the second control point\n     * @param {Number} t - a parameter value\n     * @return {Number} a coordinate of a point on curve at parameter value t\n     * @version 1.0\n     */\n    IFMath.prototype.getCubicCurveAtT = function (p1, p2, c1, c2, t) {\n        var a = p1 + t * (c1 - p1);\n        var b = c1 + t * (c2 - c1);\n        var c = c2 + t * (p2 - c2);\n        var m = a + t * (b - a);\n        var n = b + t * (c - b);\n        return m + t * (n - m);\n    };\n\n    /**\n     * Finds dot product of two vectors\n     * @param {Number} x1 x-coordinate of the first vector\n     * @param {Number} y1 y-coordinate of the first vector\n     * @param {Number} x2 x-coordinate of the second vector\n     * @param {Number} y2 y-coordinate of the second vector\n     * @return {Number} dot product\n     * @version 1.0\n     */\n    IFMath.prototype.vDotProduct = function (x1, y1, x2, y2) {\n        return (x1 == null || y1 == null || x2 == null || y2 == null)\n            ? 0.0\n            : (x1 * x2) + (y1 * y2);\n    };\n\n    /**\n     * Finds squared distance between two points\n     * @param {Number} x1 x-coordinate of the first point\n     * @param {Number} y1 y-coordinate of the first point\n     * @param {Number} x2 x-coordinate of the second point\n     * @param {Number} y2 y-coordinate of the second point\n     * @return {Number} squared distance\n     */\n    IFMath.prototype.ptSqrDist = function (x1, y1, x2, y2) {\n        var tmp1, tmp2;\n\n        if (x1 == null || y1 == null || x2 == null || y2 == null) {\n            return 0.0;\n        }\n\n        tmp1 = x1 - x2;\n        tmp2 = y1 - y2;\n        return tmp1 * tmp1 + tmp2 * tmp2;\n    };\n\n    /**\n     * Finds distance between two points\n     * @param {Number} x1 x-coordinate of the first point\n     * @param {Number} y1 y-coordinate of the first point\n     * @param {Number} x2 x-coordinate of the second point\n     * @param {Number} y2 y-coordinate of the second point\n     * @return {Number} distance\n     */\n    IFMath.prototype.ptDist = function (x1, y1, x2, y2) {\n        return Math.sqrt(this.ptSqrDist(x1, y1, x2, y2));\n    };\n\n    /**\n     * Finds relative position of a point against a segment\n     * Returns 1 for points left (mirrored Y axis is not taken into account) from the segment line\n     * when moving from the segment end p1 to the end p2,\n     * 0 - for the points on the segment (with the IFMath.defaultEps accuracy)\n     * -1 - for the points to the right of the segment\n     * @param {Number} px1 x-coordinate of the start segment point\n     * @param {Number} py1 y-coordinate of the start segment point\n     * @param {Number} px2 x-coordinate of the end segment point\n     * @param {Number} py2 y-coordinate of the end segment point\n     * @param {Number} x x-coordinate of the point\n     * @param {Number} y y-coordinate of the point\n     * @return {Number} relative position of a point against a segment\n     * @version 1.0\n     */\n    IFMath.prototype.segmentSide = function (px1, py1, px2, py2, x, y) {\n        var val = (y - py1) * (px2 - px1) + (x - px1) * (py1 - py2);\n        if (this.isEqualEps(val, 0)) {\n            return 0;\n        }\n        if (val > 0) {\n            return 1;\n        }\n\n        // val < 0\n        return -1;\n    };\n\n    /**\n     * Finds squared distance from a point to a segment.\n     * Used approach is described here: http://msdn.microsoft.com/en-us/library/ms969920.aspx\n     * @param {Number} px1 x-coordinate of the start segment point\n     * @param {Number} py1 y-coordinate of the start segment point\n     * @param {Number} px2 x-coordinate of the end segment point\n     * @param {Number} py2 y-coordinate of the end segment point\n     * @param {Number} x x-coordinate of the point\n     * @param {Number} y y-coordinate of the point\n     * @param {Number} ptMin array from one item to pass out slope value of distance minimizing point, may be null\n     * @param {Number} sqrEndAcc squared distance of tolerance for end points, may be null if not needed\n     * @return {Number} squared distance from a point to a segment\n     * @version 1.0\n     */\n    IFMath.prototype.sqrSegmentDist = function (px1, py1, px2, py2, x, y, ptMin, sqrEndAcc) {\n        if (this.isEqualEps(px1, px2) && this.isEqualEps(py1, py2)) {\n            return this.ptSqrDist(px1, py1, x, y);\n        }\n\n        // Calculate distance using this approach:\n        // http://msdn.microsoft.com/en-us/library/ms969920.aspx\n        var ax, ay, bx, by;\n        var cx, cy; // projection vector a onto b\n        var nx, ny; // normal to b\n        var tmp = 0.0;\n        var sqrDst = 0.0;\n\n        ax = x - px1;\n        ay = y - py1;\n\n        if (px1 == px2 && py1 == py2) {\n            sqrDst = this.vDotProduct(ax, ay, ax, ay);\n            if (ptMin) {\n                ptMin[0] = 0;\n            }\n        } else if (ptMin && sqrEndAcc && this.vDotProduct(ax, ay, ax, ay) <= sqrEndAcc) {\n            ptMin[0] = 0;\n            sqrDst = 0.0;\n        } else if (ptMin && sqrEndAcc && this.ptSqrDist(x, y, px2, py2) <= sqrEndAcc) {\n            ptMin[0] = 1;\n            sqrDst = 0.0;\n        } else {\n            bx = px2 - px1;\n            by = py2 - py1;\n\n            //\n            //Obtain projection vector.\n            //\n            //c = ((a * b)/(|b|^2))*b\n            //\n            tmp = this.vDotProduct(ax, ay, bx, by) / this.vDotProduct(bx, by, bx, by);\n            if (tmp <= 0.0) {\n                sqrDst = this.vDotProduct(ax, ay, ax, ay);\n                if (ptMin) {\n                    ptMin[0] = 0;\n                }\n            }\n            else if (tmp >= 1.0) {\n                sqrDst = this.vDotProduct(x - px2, y - py2, x - px2, y - py2);\n                if (ptMin) {\n                    ptMin[0] = 1;\n                }\n            }\n            else {\n                cx = bx * tmp;\n                cy = by * tmp;\n\n                //\n                //Obtain perpendicular projection : n = a - c\n                //\n                nx = ax - cx;\n                ny = ay - cy;\n\n                sqrDst = this.vDotProduct(nx, ny, nx, ny);\n                if (ptMin) {\n                    ptMin[0] = tmp;\n                }\n            }\n        }\n\n        return sqrDst;\n    };\n\n    /**\n     * Calculates and returns squared distance between two line segments\n     * @param {IFPoint} pt11 - a start point of the first segment\n     * @param {IFPoint} pt12 - an end point of the first segment\n     * @param {IFPoint} pt21 - a start point of the second segment\n     * @param {IFPoint} pt22 - an end point of the second segment\n     * @return {Number} squared distance between two line segments\n     */\n    IFMath.prototype.getSegmToSegmSqrDist = function (pt11, pt12, pt21, pt22) {\n        var dst = this.sqrSegmentDist(pt11.getX(), pt11.getY(), pt12.getX(), pt12.getY(), pt21.getX(), pt21.getY());\n        var res = dst;\n        if (res > 0) {\n            dst = this.sqrSegmentDist(pt11.getX(), pt11.getY(), pt12.getX(), pt12.getY(), pt22.getX(), pt22.getY());\n            if (dst < res) {\n                res = dst;\n            }\n            if (res > 0) {\n                dst = this.sqrSegmentDist(pt21.getX(), pt21.getY(), pt22.getX(), pt22.getY(), pt11.getX(), pt11.getY());\n                if (dst < res) {\n                    res = dst;\n                }\n                if (res > 0) {\n                    dst = this.sqrSegmentDist(\n                        pt21.getX(), pt21.getY(), pt22.getX(), pt22.getY(), pt12.getX(), pt12.getY());\n\n                    if (dst < res) {\n                        res = dst;\n                    }\n                }\n            }\n        }\n        return res;\n    };\n\n    /**\n     * For points A(x1, y1), B(x2, y2), C(x3, y3) calculates and returns point C', so that AC' makes\n     * a collinear projection of the AC vector to the direction of vector AB.\n     * @param {Number} x1 - x-coordinate of the point A\n     * @param {Number} y1 - y-coordinate of the point A\n     * @param {Number} x2 - x-coordinate of the point B\n     * @param {Number} y2 - y-coordinate of the point B\n     * @param {Number} x3 - x-coordinate of the point C\n     * @param {Number} y3 - y-coordinate of the point C\n     * @param {Boolean} positiveOnly indicates if only positive projection is needed\n     * @return (IFPoint}\n     */\n    IFMath.prototype.getVectorProjection = function (x1, y1, x2, y2, x3, y3, positiveOnly) {\n        var ax = x3 - x1;\n        var ay = y3 - y1;\n        var bx = x2 - x1;\n        var by = y2 - y1;\n        // projection vector a onto b\n        //c = ((a * b)/(|b|^2))*b\n\n        var norm = this.vDotProduct(bx, by, bx, by);\n        var res;\n        if (this.isEqualEps(norm, 0)) {\n            res = new IFPoint(x3, y3);\n        } else {\n            var tmp = this.vDotProduct(ax, ay, bx, by) / norm;\n\n            if (tmp <= 0.0 && positiveOnly) {\n                res  = new IFPoint(x1, y1);\n            }\n            else {\n                res  = new IFPoint(bx * tmp + x1, by * tmp + y1);\n            }\n        }\n\n        return res;\n    };\n\n    IFMath.prototype.solveLinear2Pseudo = function (a11, a12, b1, a21, a22, b2) {\n        var res = this.getLinesIntersection(a11, a12, -b1, a21, a22, -b2);\n        if (res == null) { // try to find pseudo solution\n            var r1, r2;\n            if (!this.isEqualEps(a11 + a12, 0) && (!this.isEqualEps(b1, 0) || this.isEqualEps(b2, 0))) {\n                r1 = b1 / (a11 + a12);\n                r2 = r1;\n            } else if (!this.isEqualEps(a21 + a22, 0) && (!this.isEqualEps(b2, 0) || this.isEqualEps(b1, 0))) {\n                r1 = b2 / (a21 + a22);\n                r2 = r1;\n            } else if (!this.isEqualEps(a12, 0) || !this.isEqualEps(a22, 0)) {\n                r1 = 0.0;\n                if (!ifMath.isEqualEps(a12, 0)) {\n                    r2 = b1 / a12;\n                } else {\n                    r2 = b2 / a22;\n                }\n            } else if (!this.isEqualEps(a11, 0) || !this.isEqualEps(a21, 0)) {\n                r2 = 0.0;\n                if (!this.isEqualEps(a11, 0)) {\n                    r1 = b1 / a11;\n                } else {\n                    r1 = b2 / a21;\n                }\n            } else {\n                r1 = 0.0;\n                r2 = 0.0;\n            }\n\n            if (this.isEqualEps(a11 * r1 + a12 * r2, b1) && this.isEqualEps(a21 * r1 + a22 * r2, b2)) {\n                res = new IFPoint(r1, r2);\n            }\n        }\n\n        return res;\n    };\n\n    /**\n     * Divide quadratic Bezier curve into two parts using De Casteljau algorithm,\n     * and returns control points of two parts\n     * @param {Number} p1 a corresponding coordinate of the curve start point\n     * @param {Number} c a corresponding coordinate of the control point\n     * @param {Number} p2 a corresponding coordinate of the curve end point\n     * @param {Number} t a slope parameter value, where to divide the curve\n     * @param {Float64Array(3)} ctrls1 - array of the control points of the first part to be passed out\n     * @param {Float64Array(3)} ctrls2 - array of the control points of the second part to be passed out\n     */\n    IFMath.prototype.divideQuadraticCurve = function (p1, c, p2, t, ctrls1, ctrls2) {\n        var a = p1 + t * (c - p1);\n        var b = c + t * (p2 - c);\n        var m = a + t * (b - a);\n\n        ctrls1[0] = p1;\n        ctrls1[1] = a;\n        ctrls1[2] = m;\n        ctrls2[0] = m;\n        ctrls2[1] = b;\n        ctrls2[2] = p2;\n    };\n\n    /**\n     * Evaluates cubic polynomial.\n     * @param {Number} a - 3rd degree coefficient\n     * @param {Number} b - 2nd degree coefficient\n     * @param {Number} c - linear coefficient\n     * @param {Number} d - the constant term\n     * @param {Number} x - point of polynomial calculation\n     * @return {Number} evaluation result\n     * @version 1.0\n     */\n    IFMath.prototype.evalCubic = function (a, b, c, d, x) {\n        if (x == 0) {\n            return d;\n        }\n\n        if (x == 1) {\n            return a + b + c + d;\n        }\n\n        return ((x * a + b) * x + c) * x + d;\n    };\n\n    /**\n     * Calculates all inflate points of Bezier cubic curve and also all the points where tangent line is parallel\n     * to X or Y axis. Splitting a curve in these points will guarantee, that curvature sign is the same in each\n     * sub-curve, and that angle is not more than 90 degrees\n     * @param {Number} ax\n     * @param {Number} bx\n     * @param {Number} cx\n     * @param {Number} ay\n     * @param {Number} by\n     * @param {Number} cy\n     * @param {Array} sPts - split points (parameter values) plus two end points, sorted in ascending order\n     * @returns {Number} nPoints - the number of split points (including two original end points)\n     */\n    IFMath.prototype.getCubicCurveSplits = function(ax, bx, cx, ay, by, cy, sPts) {\n        // Find initial interval (curve) splitPoints at [0, 1],\n        // which are curve inflate points, or such points,\n        // that P'x = 0 or P'y = 0\n        var splitPoints = [0, 1.0];\n\n        // P(t) = P1 + 3t(C1 - P1) + 3t^2*(C2 - 2C1 + P1) + t^3*(P2 - 3C2 + 3C1 - P1)\n        // P' =3(C1 - P1) + 6t(C2 - 2C1 + P1) + 3t^2*(P2 - 3C2 + 3C1 - P1)\n        // P'x == 0 when tangent to vertical border, and P'y == 0 when tangent to horizontal border,\n        // Also locate all inflate points, where P'x * P''y - P'y * P''x = 0\n\n        // cx = cx1 - px1;\n        // cy = cy1 - py1;\n        // bx = 2 * (cx2 - cx1 - cx);\n        // by = 2 * (cy2 - cy1 - cy);\n        // ax = px2 - cx2 -cx - bx;\n        // ay = py2 - cy2 -cy - by;\n        // P' = 3(at^2 + bt + c)\n        // P'' = 3(2at + b)\n\n        // P' = 0;\n        ifMath.getQuadraticRoots(ax, bx, cx, splitPoints);\n        ifMath.getQuadraticRoots(ay, by, cy, splitPoints);\n\n        // P'x * P''y - P'y * P''x = 0\n        // (2bx*ay -2by*ax + ax*by - ay*bx)t^2 + (2cx*ay - 2cy*ax)t + cx*by - cy*bx = 0\n        // (bx*ay - by*ax)t^2 + 2*(cx*ay - cy*ax)t + cx*by - cy*bx = 0\n        // At^2 + Bt + C = 0\n        var A = bx * ay - by * ax;\n        var B = 2 * (cx * ay - cy * ax);\n        var C = cx * by - cy * bx;\n        ifMath.getQuadraticRoots(A, B, C, splitPoints);\n\n        return ifUtil.uSortSegment(0, 1, splitPoints, sPts);\n    };\n\n    /**\n     * Divide cubic Bezier curve into two parts using De Casteljau algorithm,\n     * and returns control points of the needed part\n     * @param {Number} p1 a corresponding coordinate of the curve start point\n     * @param {Number} c1 a corresponding coordinate of the first control point\n     * @param {Number} c2 a corresponding coordinate of the second control point\n     * @param {Number} p2 a corresponding coordinate of the curve end point\n     * @param {Number} t a slope parameter value, where to divide the curve\n     * @param {Number} part indicates which curve part is further needed: 1 - for the first part, 2 - for the second\n     * @param {Float64Array(4)} ctrls - array of the control points of needed part to be passed out\n     */\n    IFMath.prototype.getCtrlPtsCasteljau = function (p1, c1, c2, p2, t, part, ctrls, ctrls2) {\n        var a = p1 + t * (c1 - p1);\n        var b = c1 + t * (c2 - c1);\n        var c = c2 + t * (p2 - c2);\n        var m = a + t * (b - a);\n        var n = b + t * (c - b);\n        var s = m + t * (n - m);\n\n        if (part == null || part == 1) {\n            ctrls[0] = p1;\n            ctrls[1] = a;\n            ctrls[2] = m;\n            ctrls[3] = s;\n        }\n        if (part == null || part == 2) {\n            if (part == 2) {\n                var ctrls2 = ctrls;\n            }\n            ctrls2[0] = s;\n            ctrls2[1] = n;\n            ctrls2[2] = c;\n            ctrls2[3] = p2;\n        }\n    };\n\n    /**\n     * Divide cubic Bezier curve using De Casteljau algorithm\n     * to extract the curve part between parameter values t1 and t2,\n     * and returns control points of the needed part.\n     * @param {Number} p1 a corresponding coordinate of the curve start point\n     * @param {Number} c1 a corresponding coordinate of the first control point\n     * @param {Number} c2 a corresponding coordinate of the second control point\n     * @param {Number} p2 a corresponding coordinate of the curve end point\n     * @param {Number} t1 a slope parameter value, indicating curve part start\n     * @param {Number} t2 a slope parameter value, indicating curve part end\n     * @param {Float64Array(4)} ctrls - array of the control points of needed part to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.getCtrlPts = function (p1, p2, c1, c2, t1, t2, ctrls) {\n        var tNew;\n\n        if (t1 == 0) {\n            this.getCtrlPtsCasteljau(p1, c1, c2, p2, t2, 1, ctrls);\n            return;\n        }\n        if (t2 == 1) {\n            this.getCtrlPtsCasteljau(p1, c1, c2, p2, t1, 2, ctrls);\n            return;\n        }\n        this.getCtrlPtsCasteljau(p1, c1, c2, p2, t1, 2, ctrls);\n        tNew = (t2 - t1) / (1 - t1);\n        this.getCtrlPtsCasteljau(ctrls[0], ctrls[1], ctrls[2], ctrls[3], tNew, 1, ctrls);\n    };\n\n    /**\n     * Evaluates polynomial.\n     * @param {Array} coeffF - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreeF - polynomial degree\n     * @param {Number} x - point of polynomial calculation\n     * @return {Number} evaluation result\n     * @version 1.0\n     */\n    IFMath.prototype.evalPoly = function (coeffF, degreeF, x) {\n        var i = 0;\n        var res = null;\n\n        if (degreeF < 0) {\n            return null;\n        }\n\n        if (degreeF > 0) {\n            if (x != 0) {\n                res = coeffF[0];\n\n                if (x == 1) {\n                    for (i = 1; i <= degreeF; ++i) {\n                        res += coeffF[i];\n                    }\n                }\n                else {\n                    for (i = 1; i <= degreeF; ++i) {\n                        res = res * x + coeffF[i];\n                    }\n                }\n            }\n            else {\n                res = coeffF[degreeF];\n            }\n        }\n        else {\n            res = coeffF[degreeF];\n        }\n\n        return res;\n    };\n\n    /**\n     * Calculates coefficients of polynomial derivative.\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @param {Array} coeffPolyDeriv - coefficients of polynomial derivative to be passed out\n     * @return {Boolean} true if derivative coefficients were successfully calculated\n     * @version 1.0\n     */\n    IFMath.prototype.getCoeffPolyDeriv = function (coeffPoly, degreePoly, coeffPolyDeriv) {\n        var i = 0;\n        var res = false;\n\n        if (degreePoly >= 1) {\n            for (i = 0; i < degreePoly; ++i) {\n                coeffPolyDeriv[i] = coeffPoly[i] * (degreePoly - i);\n            }\n\n            res = true;\n        }\n\n        return res;\n    };\n\n    /**\n     * Finds roots of cubic polynomial on an interval.\n     * @param {Array} coeffG - array of cubic polynomial coefficients, starting from the highest degree\n     * @param {Number} p0 - interval start\n     * @param {Number} p1 - interval end\n     * @param {Array} gRoots - array of polynomial roots to be passed out\n     * @param {Boolean} inclEnds indicates if interval ends should be checked when locating polynomial roots\n     * @param {Number} acc - desired accuracy of roots calculation\n     * @return {Number} number of found roots\n     * @version 1.0\n     */\n    IFMath.prototype.getCubicRoots = function (coeffG, p0, p1, gRoots, inclEnds, acc) {\n        var t1, t2, discr, sqrtD, nRoots;\n        var a, b, c, d;\n        var g0, g1, gt1, gt2;\n        var gRootsN = 0;\n\n        var coeffs = new Float64Array(4);\n        var coeffInversed = new Float64Array(4);\n        var cDeriv = new Float64Array(3);\n        var cDeriv2 = new Float64Array(2);\n        //var acc = 1e-6;\n        var r;\n        var i;\n        var accNeg = -acc;\n\n        if (p0 >= p1) {\n            return 0;\n        }\n\n        if (coeffG[0] < 0) {\n            for (i = 0; i < 4; ++i) {\n                coeffs[i] = -coeffG[i];\n            }\n        }\n        else {\n            for (i = 0; i < 4; ++i) {\n                coeffs[i] = coeffG[i];\n            }\n        }\n\n        // g(t) = at^3 + b*t^2 +c*t + d = 0, t from [p0, p1]\n        // g't = 3at^2 + 2t*b + c   = 0  => t1 <= t2\n        // g''t = 6at +2b\n\n        // below is much code, but the method should be fast, because only one branch will work,\n        // TODO: but if the method below will not be fast enough, try exact formulas for\n        // roots of 3d-degree polynomial, may be they will be faster...\n\n        a = coeffs[0];\n        b = coeffs[1];\n        c = coeffs[2];\n        d = coeffs[3];\n\n        if (p0 == 0 && p1 == 1) {\n            this.inversePolyUnaryInterval(coeffs, 3, coeffInversed);\n        }\n        else {\n            this.inversePolyInterval(coeffs, 3, p0, p1, coeffInversed);\n        }\n\n\n        if (this.estimPositiveRootsDescartes(coeffInversed, 3) == 0) {\n            return 0;\n        }\n\n        this.getCoeffPolyDeriv(coeffs, 3, cDeriv);\n\n        cDeriv2[0] = 6 * a;\n        cDeriv2[1] = 2 * b;\n\n        discr = b * b - cDeriv[0] * c;\n        nRoots = 0;\n        if (discr == 0) {\n            nRoots = 1;\n            t1 = -b / cDeriv[0];\n            t2 = t1;\n        }\n        else if (discr > 0) {\n            nRoots = 2;\n            sqrtD = Math.sqrt(discr);\n            t1 = (-b - sqrtD) / cDeriv[0];\n            t2 = (-b + sqrtD) / cDeriv[0];\n        }\n\n        // value of polinomial at p0\n        g0 = this.evalCubic(a, b, c, d, p0);\n        // value of polinomial at p1\n        g1 = this.evalCubic(a, b, c, d, p1);\n\n        // [-inf, t1], [t2, inf]\n        if (nRoots == 0 || t1 >= p1 || t2 <= p0) {\n            if (accNeg <= g0 && g0 <= acc) {\n                if (inclEnds) {\n                    gRoots[gRootsN] = p0;\n                    gRootsN += 1;\n                }\n            }\n            else {\n                if (accNeg <= g1 && g1 <= acc) {\n                    if (inclEnds) {\n                        gRoots[gRootsN] = p1;\n                        gRootsN += 1;\n                    }\n                }\n                // g0 > 0 || g1 < 0 => no root\n                else if (g0 < 0 && g1 > 0) {\n\n                    r = this.locateByNewton(\n                        p0, p1, g0, g1,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (p1 + p0) / 2;\n                    }\n                    gRootsN += 1;\n                }\n            }\n        }\n        // nRoots > 0 && t1 < p1 && t2 > p0\n\n        // t1 <= p0 < p1 <= t2\n        else if (t1 <= p0 && t2 >= p1) {\n            if (accNeg <= g0 && g0 <= acc) {\n                if (inclEnds) {\n                    gRoots[gRootsN] = p0;\n                    gRootsN += 1;\n                }\n            }\n            else {\n                if (accNeg <= g1 && g1 <= acc) {\n                    if (inclEnds) {\n                        gRoots[gRootsN] = p1;\n                        gRootsN += 1;\n                    }\n                }\n                // g0 < 0 || g1 > 0 => no root\n                else if (g0 > 0 && g1 < 0) {\n                    r = this.locateByNewton(\n                        p0, p1, g0, g1,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (p1 + p0) / 2;\n                    }\n\n                    gRootsN += 1;\n                }\n            }\n        }\n\n        // p0 < t1 < p1 <= t2\n        else if (t1 > p0 && t2 >= p1) {\n            gt1 = this.evalCubic(a, b, c, d, t1);\n            if (accNeg <= gt1 && gt1 <= acc) {\n                gRoots[gRootsN] = t1;\n                gRootsN += 1;\n            }\n            // gt1 < 0 => no root\n            else if (gt1 > 0) {\n\n                // locate in [p0, t1]\n                if (accNeg <= g0 && g0 <= acc) {\n                    if (inclEnds) {\n                        gRoots[gRootsN] = p0;\n                        gRootsN += 1;\n                    }\n                }\n                // g0 > 0 => no root\n                else if (g0 < 0) {\n                    r = this.locateByNewton(\n                        p0, t1, g0, gt1,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (p0 + t1) / 2;\n                    }\n\n                    gRootsN += 1;\n                }\n\n                // locate in [t1, p1]\n                if (accNeg <= g1 && g1 <= acc) {\n                    if (inclEnds) {\n                        gRoots[gRootsN] = p1;\n                        gRootsN += 1;\n                    }\n                }\n                // g1 > 0 => no root\n                else if (g1 < 0) {\n                    r = this.locateByNewton(\n                        t1, p1, gt1, g1,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (t1 + p1) / 2;\n                    }\n\n                    gRootsN += 1;\n                }\n            }\n        }\n\n        // t1 <= p0 < t2 < p1\n        else if (t1 <= p0 && t2 < p1) {\n            gt2 = this.evalCubic(a, b, c, d, t2);\n            if (accNeg <= gt2 && gt2 <= acc) {\n                gRoots[gRootsN] = t2;\n                gRootsN += 1;\n            }\n            // gt2 > 0 => no root\n            else if (gt2 < 0) {\n\n                // locate in [p0, t2]\n                if (accNeg <= g0 && g0 <= acc) {\n                    if (inclEnds) {\n                        gRoots[gRootsN] = p0;\n                        gRootsN += 1;\n                    }\n                }\n                // g0 < 0 => no root\n                else if (g0 > 0) {\n                    r = this.locateByNewton(\n                        p0, t2, g0, gt2,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (p0 + t2) / 2;\n                    }\n\n                    gRootsN += 1;\n                }\n\n                // locate in [t2, p1]\n                if (accNeg <= g1 && g1 <= acc) {\n                    if (inclEnds) {\n                        gRoots[gRootsN] = p1;\n                        gRootsN += 1;\n                    }\n                }\n                // g1 < 0 => no root\n                else if (g1 > 0) {\n                    r = this.locateByNewton(\n                        t2, p1, gt2, g1,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (t2 + p1) / 2;\n                    }\n\n                    gRootsN += 1;\n                }\n            }\n        }\n\n        // p0 < t1 <= t2 < p1\n        else {\n            if (t1 == t2) {\n                gt1 = this.evalCubic(a, b, c, d, t1);\n                if (accNeg <= gt1 && gt1 <= acc) {\n                    gRoots[gRootsN] = t1;\n                    gRootsN += 1;\n                }\n                else {\n                    if (accNeg <= g0 && g0 <= acc) {\n                        if (inclEnds) {\n                            gRoots[gRootsN] = p0;\n                            gRootsN += 1;\n                        }\n                    }\n                    else {\n                        if (accNeg <= g1 && g1 <= acc) {\n                            if (inclEnds) {\n                                gRoots[gRootsN] = p1;\n                                gRootsN += 1;\n                            }\n                        }\n                        else if (gt1 < 0 && g1 > 0) {\n                            r = this.locateByNewton(\n                                t1, p1, gt1, g1,\n                                coeffs, 3, cDeriv, cDeriv2, acc);\n\n                            if (r != null) {\n                                gRoots[gRootsN] = r;\n                            }\n                            else {\n                                gRoots[gRootsN] = (t1 + p1) / 2;\n                            }\n\n                            gRootsN += 1;\n                        }\n                        else if (g0 < 0 && gt1 > 0) {\n                            r = this.locateByNewton(\n                                p0, t1, g0, gt1,\n                                coeffs, 3, cDeriv, cDeriv2, acc);\n\n                            if (r != null) {\n                                gRoots[gRootsN] = r;\n                            }\n                            else {\n                                gRoots[gRootsN] = (p0 + t1) / 2;\n                            }\n\n                            gRootsN += 1;\n                        } // else no root\n                    }\n                }\n            }\n            else { // p0 < t1 < t2 < p1\n                gt1 = this.evalCubic(a, b, c, d, t1);\n                gt2 = this.evalCubic(b, b, c, d, t2);\n\n                if (gt1 <= 0 || gt2 >= 0) {\n                    if (accNeg <= gt1 && gt1 <= acc) {\n                        gRoots[gRootsN] = t1;\n                        gRootsN += 1;\n                    }\n\n                    if (gt1 <= 0) {\n                        if (accNeg <= g1 && g1 <= acc) {\n                            if (inclEnds) {\n                                gRoots[gRootsN] = p1;\n                                gRootsN += 1;\n                            }\n                        }\n                        // g1 < 0 => no root\n                        else if (gt2 < 0 && g1 > 0) {\n                            r = this.locateByNewton(\n                                t2, p1, gt2, g1,\n                                coeffs, 3, cDeriv, cDeriv2, acc);\n\n                            if (r != null) {\n                                gRoots[gRootsN] = r;\n                            }\n                            else {\n                                gRoots[gRootsN] = (t2 + p1) / 2;\n                            }\n\n                            gRootsN += 1;\n                        } // else no root\n                    }\n\n                    if (accNeg <= gt2 && gt2 <= acc) {\n                        gRoots[gRootsN] = t2;\n                        gRootsN += 1;\n                    }\n\n                    if (gt2 >= 0) {\n                        if (accNeg <= g0 && g0 <= acc) {\n                            if (inclEnds) {\n                                gRoots[gRootsN] = p0;\n                                gRootsN += 1;\n                            }\n                        }\n                        // g0 > 0 => no root\n                        else if (g0 < 0 && gt1 > 0) {\n                            r = this.locateByNewton(\n                                p0, t1, g0, gt1,\n                                coeffs, 3, cDeriv, cDeriv2, acc);\n\n                            if (r != null) {\n                                gRoots[gRootsN] = r;\n                            }\n                            else {\n                                gRoots[gRootsN] = (p0 + t1) / 2;\n                            }\n\n                            gRootsN += 1;\n                        } // else no root\n                    }\n                }\n\n                else { // gt1 > 0 && gt2 < 0\n                    r = this.locateByNewton(\n                        t1, t2, gt1, gt2,\n                        coeffs, 3, cDeriv, cDeriv2, acc);\n\n                    if (r != null) {\n                        gRoots[gRootsN] = r;\n                    }\n                    else {\n                        gRoots[gRootsN] = (t1 + t2) / 2;\n                    }\n\n                    gRootsN += 1;\n\n                    if (accNeg <= g0 && g0 <= acc) {\n                        if (inclEnds) {\n                            gRoots[gRootsN] = p0;\n                            gRootsN += 1;\n                        }\n                    }\n                    // g0 > 0 => no root [p0, t1]\n                    else if (g0 < 0 && gt1 > 0) {\n                        r = this.locateByNewton(\n                            p0, t1, g0, gt1,\n                            coeffs, 3, cDeriv, cDeriv2, acc);\n\n                        if (r != null) {\n                            gRoots[gRootsN] = r;\n                        }\n                        else {\n                            gRoots[gRootsN] = (p0 + t1) / 2;\n                        }\n\n                        gRootsN += 1;\n                    }\n\n                    if (accNeg <= g1 && g1 <= acc) {\n                        gRoots[gRootsN] = p1;\n                        gRootsN += 1;\n                    }\n                    // g1 < 0 => no root [t2, p1]\n                    else if (gt2 < 0 && g1 > 0) {\n                        r = this.locateByNewton(\n                            t2, p1, gt2, g1,\n                            coeffs, 3, cDeriv, cDeriv2, acc);\n\n                        if (r != null) {\n                            gRoots[gRootsN] = r;\n                        }\n                        else {\n                            gRoots[gRootsN] = (t2 + p1) / 2;\n                        }\n\n                        gRootsN += 1;\n                    }\n                }\n            }\n        }\n\n        return gRootsN;\n    };\n\n    /**\n     * The maximal number of possible iterations to perform in Newton method (usually 4-10 should be enough)\n     * @private\n     */\n    IFMath.prototype._maxIter = 100;\n\n    /**\n     * Calculates root of a polynomial on a segment using Newton method.\n     * Only polynomials of degrees 3 and 5 are supported\n     * @param {Number} a - segment start\n     * @param {Number} b - segment end\n     * @param {Number} fa - value of polynomial at segment start\n     * @param {Number} fb - value of polynomial at segment end\n     * @param {Array} coeffF - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreeF - polynomial degree\n     * @param {Array} coeffFDeriv - coefficients of polynomial derivative\n     * @param {Array} coeffFDeriv2 - coefficients of polynomial second derivative\n     * @param {Number} acc - desired accuracy of a root calculation\n     * @param {Array} sturmSeq - generalized Sturm sequence (array of polynomial coefficients arrays),\n     * needed only for some specific cases of 5th degree polynomial, may be ommited in most cases\n     * @param {Array} nSignVars - array of two numbers of Sturm sequence sign variations at segment ends,\n     * needed only together with Sturm sequence, will be calculated if were not provided, or if some value was null\n\n     * @return {Number} root if it was found, or null otherwise\n     * @version 1.0\n     */\n    IFMath.prototype.locateByNewton = function (a, b, fa, fb, coeffF, degreeF, coeffFDeriv, coeffFDeriv2, acc, sturmSeq, nSignVars) {\n        // TODO: check if the last vars will be set to null, if they are not specified in function call\n        var x = null;\n        var tmp;\n        var degreeDeriv = degreeF - 1;\n        var accNeg = -acc;\n        var zeroNeg = -this.defaultEps;\n        var i = 0;\n        var val = acc + 1;\n        var valDeriv2;\n        var deriv2Root;\n        var a1;\n        var a2;\n        var fa1;\n        var fa2;\n        var locateInitial;\n        var nsv = [];\n        var nSVars = [];\n        var fVals = [];\n        var nr;\n        var x1;\n        var rootsD2 = [];\n        var rootsDeriv2 = [];\n        var inclEnds;\n        var useSt;\n        var useSign;\n\n        if (accNeg <= fa && fa <= acc) {\n            return a;\n        }\n        if (accNeg <= fb && fb <= acc) {\n            return b;\n        }\n\n        a1 = a;\n        a2 = b;\n\n        // locate correctly initial point: sign(f) == sign(f'')\n        if (degreeF == 3) {\n            deriv2Root = -coeffFDeriv2[1] / coeffFDeriv2[0]; // no need to check 0 here\n            if (deriv2Root < a || deriv2Root > b) {\n                valDeriv2 = coeffFDeriv2[0] * a + coeffFDeriv2[1];\n                if (valDeriv2 > 0 && fa > 0 || valDeriv2 < 0 && fa < 0) {\n                    x = a;\n                    val = fa;\n                }\n                else {\n                    valDeriv2 = coeffFDeriv2[0] * b + coeffFDeriv2[1];\n                    if (valDeriv2 > 0 && fb > 0 || valDeriv2 < 0 && fb < 0) {\n                        x = b;\n                        val = fb;\n                    }\n                    else { // internal error\n                        x = null;\n                    }\n\n                }\n            }\n            else {\n                val = this.evalPoly(coeffF, degreeF, deriv2Root);\n                if (accNeg <= val && val <= acc) {\n                    // solution is found\n                    x = deriv2Root;\n                }\n                else {\n                    if (val > 0 && fa > 0 || val < 0 && fa < 0) {\n                        a1 = deriv2Root + acc;\n                        val = this.evalPoly(coeffF, degreeF, a1);\n                        valDeriv2 = coeffFDeriv2[0] * a1 + coeffFDeriv2[1];\n                        if (valDeriv2 > 0 && val > 0 || valDeriv2 < 0 && val < 0) {\n                            x = a1;\n                        }\n                        else {\n                            valDeriv2 = coeffFDeriv2[0] * b + coeffFDeriv2[1];\n                            if (valDeriv2 > 0 && fb > 0 || valDeriv2 < 0 && fb < 0) {\n                                x = b;\n                                val = fb;\n                            }\n                            else { // internal error\n                                x = null;\n                            }\n\n                        }\n                    }\n                    else if (val > 0 && fb > 0 || val < 0 && fb < 0) {\n                        a2 = deriv2Root - acc;\n                        val = this.evalPoly(coeffF, degreeF, a2);\n                        valDeriv2 = coeffFDeriv2[0] * a2 + coeffFDeriv2[1];\n                        if (valDeriv2 > 0 && val > 0 || valDeriv2 < 0 && val < 0) {\n                            x = a2;\n                        }\n                        else {\n                            valDeriv2 = coeffFDeriv2[0] * a + coeffFDeriv2[1];\n                            if (valDeriv2 > 0 && fa > 0 || valDeriv2 < 0 && fa < 0) {\n                                x = a;\n                                val = fa;\n                            }\n                            else { // internal error\n                                x = null;\n                            }\n                        }\n                    }\n                    else { // internal error\n                        x = null;\n                    }\n                }\n            }\n        }\n        else {\n            if (degreeF != 5) {\n                throw new Error(\"Unsupported polynomial degree.\");\n            }\n\n            // find [a1, a2] and initial point x from [a1, a2]: sign(f(x)) == sign(f''(x)), and\n            // sign(f'') permanent on [a1, a2]\n\n            useSt = false;\n            useSign = false;\n\n            if (fa < 0 && fb > 0 || fa > 0 && fb < 0) {\n                useSign = true;\n            }\n            else if (sturmSeq && nSignVars) {\n                useSt = true;\n            }\n\n            locateInitial = true;\n\n            inclEnds = false;\n            this.getCubicRoots(coeffFDeriv2, a, b, rootsDeriv2, inclEnds, acc);\n\n            i = 0;\n            if (rootsDeriv2.length == 0) {\n                a1 = a;\n                fVals[0] = fa;\n                a2 = b;\n                fVals[1] = fb;\n                if (useSt) {\n                    nSVars[0] = nSignVars[0];\n                    nSVars[1] = nSignVars[1];\n                }\n            }\n            else {\n                ifUtil.uSortSegment(a, b, rootsDeriv2, rootsD2);\n                a1 = a;\n                fVals[0] = fa;\n                if (useSt) {\n                    nSVars[0] = nSignVars[0];\n                }\n                while (i <= rootsD2.length) {\n                    if (i > 0) {\n                        a1 = a2;\n                        fVals[0] = fVals[1];\n                        if (useSt) {\n                            nSVars[0] = nSVars[1];\n                        }\n                    }\n                    if (i < rootsD2.length) {\n                        a2 = rootsD2[i];\n                        fVals[1] = null;\n                        if (useSt) {\n                            nSVars[1] = null;\n                        }\n                    }\n                    else { // i == rootsD2.length\n                        a2 = b;\n                        fVals[1] = fb;\n                        if (useSt) {\n                            nSVars[1] = nSignVars[1];\n                        }\n                    }\n\n                    if (useSign) {\n                        if (fVals[1] == null) {\n                            fVals[1] = this.evalPoly(coeffF, degreeF, a2);\n                        }\n\n                        if (this.isEqualEps(fVals[1], 0, acc)) {\n                            x = a2;\n                            val = fVals[1];\n                            locateInitial = false;\n                        }\n                        if (fVals[0] > 0 && fVals[1] < 0 || fVals[0] < 0 && fVals[1] > 0) {\n                            break;\n                        }\n                    }\n                    if (useSt) {\n                        nr = this.countRootsNSturm(\n                            coeffF, degreeF, coeffFDeriv, a1, a2, sturmSeq, nSVars, fVals);\n\n                        if (nr != 0) {\n                            break;\n                        }\n                    }\n\n                    ++i;\n                }\n            }\n\n            // Now there is at least one root of F at [a1,a2], and no roots of F'' on (a1, a2)\n            if (locateInitial && i == 0) {\n                valDeriv2 = this.evalPoly(coeffFDeriv2, coeffFDeriv2.length - 1, a);\n                if (valDeriv2 > 0 && fa > 0 || valDeriv2 < 0 && fa < 0) {\n                    x = a;\n                    val = fa;\n                    locateInitial = false;\n                }\n            }\n            if (locateInitial && i == rootsD2.length) {\n                valDeriv2 = this.evalPoly(coeffFDeriv2, coeffFDeriv2.length - 1, b);\n                if (valDeriv2 > 0 && fb > 0 || valDeriv2 < 0 && fb < 0) {\n                    x = b;\n                    val = fb;\n                    locateInitial = false;\n                }\n            }\n            if (locateInitial) {\n                fa1 = fVals[0];\n                fa2 = fVals[1];\n                if (useSt) {\n                    nsv = nSVars;\n                }\n\n                x = (a1 + a2) / 2;\n                valDeriv2 = this.evalPoly(coeffFDeriv2, coeffFDeriv2.length - 1, x);\n\n                while (a2 - a1 > acc && locateInitial) {\n                    x = (a1 + a2) / 2;\n                    val = this.evalPoly(coeffF, degreeF, x);\n                    if (accNeg <= val && val <= acc) {\n                        locateInitial = false;\n                    }\n                    else if (valDeriv2 > 0 && val > 0 || valDeriv2 < 0 && val < 0) {\n                        locateInitial = false;\n                    }\n                    else if (val > 0 && fa1 < 0 || val < 0 && fa1 > 0) {\n                        a2 = x;\n                        fa2 = val;\n                        if (useSt) {\n                            nsv[1] = null;\n                        }\n                    }\n                    else if (val > 0 && fa2 < 0 || val < 0 && fa2 > 0) {\n                        a1 = x;\n                        fa1 = val;\n                        if (useSt) {\n                            nsv[0] = null;\n                        }\n                    }\n                    else if (useSign || !useSt) {\n                        // if useSign -> internal error;\n                        // if sturmSeq == null -> Though it is possible to calculate sturmSeq here,\n                        // it is not expected in Newton algorithm.\n                        //It is better to notify a caller that interval is not good enough for Newton algorithm.\n                        locateInitial = false;\n                        x = null;\n                    }\n                    else {  // sign(val) == sign(fa1) == sign(fa2) != sign(valDeriv2)\n                        fVals = [fa1, val];\n                        nSVars = [nsv[0], null];\n\n                        nr = this.countRootsNSturm(\n                            coeffF, degreeF, coeffFDeriv, a1, x, sturmSeq, nSVars, fVals);\n\n                        if (nr > 0) {\n                            a2 = x;\n                            fa2 = val;\n                            nsv[0] = nSVars[0];\n                            nsv[1] = nSVars[1];\n                        }\n                        else {\n                            if (nsv[1] != null && nSVars[1] == nsv[1]) {\n                                // no root in the second half also -> internal error\n                                locateInitial = false;\n                            }\n                            else {\n                                a1 = x;\n                                fa1 = val;\n                                nsv[0] = nSVars[0];\n                            }\n                        }\n                    }\n                } // while (a2 - a1 > acc && locateInitial)\n\n                if (locateInitial) {\n                    x = (a1 + a2) / 2;\n                    val = this.evalPoly(coeffF, degreeF, x);\n                }\n\n            }\n\n        } // degreeF != 3\n\n        // TODO: improve stop rule\n        i = 1;\n        while (x != null && (val < accNeg || acc < val) && i < this._maxIter) {\n            tmp = this.evalPoly(coeffFDeriv, degreeDeriv, x);\n            if (zeroNeg < tmp && tmp < this.defaultEps) {\n                val = this.evalPoly(coeffF, degreeF, x);\n                if (val < accNeg || acc < val) {\n                    x = null;\n                }\n            }\n            else {\n                val = this.evalPoly(coeffF, degreeF, x);\n                tmp = val / tmp;\n                x1 = x;\n                x = x - tmp;\n                if (x <= a1 || x >= a2) {\n                    // No convergence or calculations accuracy is reached\n                    x = null;\n                }\n                if (tmp > 0) {\n                    a2 = x1;\n                }\n                else if (tmp < 0) {\n                    a1 = x1;\n                }\n\n            }\n            ++i;\n        }\n\n        if (i == this._maxIter) {\n            x = null;\n        }\n\n        return x;\n    };\n\n    /**\n     * Finds roots of quadratic equation.\n     * @param {Number} a - 2nd degree coefficient\n     * @param {Number} b - linear coefficient\n     * @param {Number} c - the constant term\n     * @param {Array} roots - array of roots to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.getQuadraticRoots = function (a, b, c, roots) {\n        // ax^2 + bx + c = 0\n        var discr;\n        var sd;\n\n        if (a == 0) {\n            if (b != 0) {\n                roots.push(-c / b);\n            }\n        }\n        else {\n            discr = b * b - 4 * a * c;\n            if (discr == 0) {\n                roots.push(-b / (2 * a));\n            }\n            else if (discr > 0) {\n                sd = Math.sqrt(discr);\n                roots.push((-b + sd) / (2 * a));\n                roots.push((-b - sd) / (2 * a));\n            }\n        }\n    };\n\n    /**\n     * Returns pseudo reminder from polynomials division as described in the book of\n     * Chee-Keng Yap \"Fundamental Problems in Algorithmic Algebra\".\n     * @param {Array} coeffP1 - array of numerator polynomial coefficients, starting from the highest degree\n     * @param {Array} coeffP2 - array of divisor polynomial coefficients, starting from the highest degree\n     * @param {Array} prem - coefficients of pseudo-reminder to be passed out\n     * @return {Number} numerator multiplier\n     * @private\n     * @version 1.0\n     */\n    IFMath.prototype._pseudoRem = function (coeffP1, coeffP2, prem) {\n        var rem1 = [];\n        var j;\n        var q;\n        var rem2 = [];\n        var middlezero;\n        var cont = true;\n        var c = coeffP2[0];\n        var i;\n        var t;\n\n        if (coeffP2.length > coeffP1.length) {\n            prem = coeffP1;\n            return 1;\n        }\n\n        for (i = 2; i <= coeffP1.length - coeffP2.length + 1; ++i) {\n            c *= coeffP2[0];\n        }\n\n        for (i = 0; i < coeffP1.length; ++i) {\n            rem1[i] = coeffP1[i] * c;\n        }\n\n        while (cont) {\n            q = rem1[0] / coeffP2[0];\n            middlezero = false;\n            for (j = 1; j < coeffP2.length; ++j) {\n                t = rem1[j] - q * coeffP2[j];\n                if (t != 0 || middlezero) {\n                    rem2.push(t);\n                    if (t != 0) {\n                        middlezero = true;\n                    }\n                }\n            }\n\n            for (j = coeffP2.length; j < rem1.length; ++j) {\n                rem2.push(rem1[j]);\n            }\n\n            if (rem2.length >= coeffP2.length) {\n                rem1 = rem2;\n                rem2 = [];\n            }\n            else {\n                cont = false;\n            }\n        }\n\n        if (rem2.length > 0) {\n            for (i = 0; i < rem2.length; ++i) {\n                prem[i] = rem2[i];\n            }\n        }\n        return c;\n    };\n\n    /**\n     * Calculates generalized Sturm sequence based on improved Collins pseudo-reminder sequence.\n     * The used generalized Sturm sequence is described in the book of\n     * Chee-Keng Yap \"Fundamental Problems in Algorithmic Algebra\".\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @param {Array} coeffPolyDeriv - coefficients of polynomial derivative\n     * @param {Array} sturmPRS - generalized Sturm sequence (array of polynomial coefficients arrays) to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.getSturmPRS = function (coeffPoly, degreePoly, coeffPolyDeriv, sturmPRS) {\n        var a = [];\n        var beta = [];\n        var delta = [];\n        var ksi = [];\n        var prem = [];\n        var i;\n        var j;\n        var k;\n        var ksideg;\n        var onedeg;\n        var adeg;\n        var pCoeff;\n        var sturmD = [];\n\n        beta[0] = null;\n        sturmPRS[0] = coeffPoly;\n        sturmPRS[1] = coeffPolyDeriv;\n        a[0] = coeffPoly[0];\n        a[1] = coeffPolyDeriv[0];\n        delta[0] = 1;\n        beta[1] = 1;\n        ksi[0] = 1;\n        ksi[1] = a[1];\n\n        sturmD[0] = 1;\n        sturmD[1] = 1;\n\n        for (i = 1; i < degreePoly; ++i) {\n            prem = [];\n            pCoeff = this._pseudoRem(sturmPRS[i - 1], sturmPRS[i], prem);\n            if (prem.length == 0) {\n                break;\n            }\n            sturmPRS[i + 1] = [];\n            for (j = 0; j < prem.length; ++j) {\n                sturmPRS[i + 1][j] = prem[j] / beta[i];\n            }\n            delta[i] = sturmPRS[i + 1].length - sturmPRS[i].length;\n            a[i + 1] = sturmPRS[i + 1][0];\n            ksideg = 1;\n            onedeg = 1;\n            adeg = a[i + 1];\n            for (k = 2; k <= delta[i]; ++k) {\n                ksideg *= ksi[i];\n                onedeg = -onedeg;\n                adeg *= a[i + 1];\n            }\n            beta[i + 1] = onedeg * ksideg * ksi[i] * a[i];\n            ksi[i + 1] = adeg / ksideg;\n            if (beta[i] > 0 && pCoeff > 0 || beta[i] < 0 && pCoeff < 0) {\n                sturmD[i + 1] = -sturmD[i - 1];\n            }\n            else {\n                sturmD[i + 1] = sturmD[i - 1];\n            }\n        }\n\n        for (i = 2; i < sturmPRS.length; ++i) {\n            if (sturmD[i] < 0) {\n                for (j = 0; j < sturmPRS[i].length; ++j) {\n                    sturmPRS[i][j] = -sturmPRS[i][j];\n                }\n            }\n        }\n    };\n\n    /**\n     * Calculates number of distinct real roots of a polynomial on an interval using Sturm sequence.\n     * @param {Array} coeffF - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreeF - polynomial degree\n     * @param {Array} coeffFDeriv - coefficients of polynomial derivative\n     * @param {Number} a - segment start\n     * @param {Number} b - segment end\n     * @param {Array} sturmSeq - generalized Sturm sequence (array of polynomial coefficients arrays)\n     * @param {Array} nSignVars - array of two numbers of Sturm sequence sign variations at segment ends,\n     * will be calculated and passed out if were not provided, or if some value was null\n     * @param {Array} fVals - array of two numbers of polynomial values at segment ends,\n     * will be calculated and passed out if were not provided, or if some value was null\n\n     * @return {Number} number of distinct real roots of a polynomial on an interval\n     * @version 1.0\n     */\n    IFMath.prototype.countRootsNSturm = function (coeffF, degreeF, coeffFDeriv, a, b, sturmSeq, nSignVars, fVals) {\n        var na = 0;\n        var nb = 0;\n        var s1;\n        var s2;\n        var i;\n\n        if (nSignVars[0] == null) {\n            if (fVals[0] == null) {\n                fVals[0] = this.evalPoly(sturmSeq[0], sturmSeq[0].length - 1, a);\n            }\n            s1 = fVals[0];\n            for (i = 1; i < sturmSeq.length; ++i) {\n                s2 = this.evalPoly(sturmSeq[i], sturmSeq[i].length - 1, a);\n                if (s2 != 0 && (s1 < 0 && s2 > 0 || s1 > 0 && s2 < 0)) {\n                    ++na;\n                    s1 = s2;\n                }\n            }\n\n            nSignVars[0] = na;\n        }\n        else {\n            na = nSignVars[0];\n        }\n\n        if (nSignVars[1] == null) {\n            if (fVals[1] == null) {\n                fVals[1] = this.evalPoly(sturmSeq[0], sturmSeq[0].length - 1, b);\n            }\n            s1 = fVals[1];\n            for (i = 1; i < sturmSeq.length; ++i) {\n                s2 = this.evalPoly(sturmSeq[i], sturmSeq[i].length - 1, b);\n                if (s2 != 0 && (s1 < 0 && s2 > 0 || s1 > 0 && s2 < 0)) {\n                    ++nb;\n                    s1 = s2;\n                }\n            }\n\n            nSignVars[1] = nb;\n        }\n        else {\n            nb = nSignVars[1];\n        }\n\n        if (na > nb) {\n            return na - nb;\n        }\n        else {\n            return nb - na;\n        }\n    };\n\n    /**\n     * On an initial interval [a, b] locates smaller intervals,\n     * each containing only one distinct real root of a polynomial.\n     * Sturm sequence is used for this task.\n     * @param {Array} coeffF - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreeF - polynomial degree\n     * @param {Array} coeffFDeriv - coefficients of polynomial derivative\n     * @param {Number} a - segment start\n     * @param {Number} b - segment end\n     * @param {Array} sturmSeq - generalized Sturm sequence (array of polynomial coefficients arrays)\n     * @param {Number} nRoots - number of distinct roots on an initial interval [a, b]\n     * @param {Array} nSignVars - array of two numbers of Sturm sequence sign variations at segment ends,\n     * will be calculated and passed out if were not provided, or if some value was null\n     * @param {Array} fVals - array of two numbers of polynomial values at segment ends,\n     * will be calculated and passed out if were not provided, or if some value was null\n     * @param {Array} rIntervals - array of root location intervals (interval - array of two numbers, interval ends)\n     * @version 1.0\n     */\n    IFMath.prototype.locRootsSturm = function (coeffF, degreeF, coeffFDeriv, a, b, sturmSeq, nRoots, nSignVars, fVals, rIntervals) {\n        var midPt;\n        var nSignVars1;\n        var fVals1;\n        var n1, n2;\n\n        if (nRoots <= 1) {\n            return;\n        }\n\n        midPt = (a + b) / 2;\n        nSignVars1 = [nSignVars[0], null];\n        fVals1 = [fVals[0], null];\n        n1 = this.countRootsNSturm(coeffF, degreeF, coeffFDeriv, a, midPt, sturmSeq, nSignVars1, fVals1);\n        n2 = nRoots - n1;\n        if (n1 == 1) {\n            rIntervals.push([a, midPt, fVals1[0], fVals1[1]]);\n        }\n        if (n1 > 1) {\n            this.locRootsSturm(coeffF, degreeF, coeffFDeriv, a, midPt,\n                sturmSeq, n1, nSignVars1, fVals1, rIntervals);\n        }\n        if (n2 == 1) {\n            rIntervals.push([midPt, b, fVals1[1], fVals[1]]);\n        }\n        if (n2 > 1) {\n            var nSignVars2 = [nSignVars1[1], nSignVars[1]];\n            var fVals2 = [fVals1[1], fVals[1]];\n            this.locRootsSturm(coeffF, degreeF, coeffFDeriv, midPt, b,\n                sturmSeq, n2, nSignVars2, fVals2, rIntervals);\n        }\n    };\n\n    /**\n     * Calculates shifted polynomial coefficients (x = x+b).\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @param {Number} b - original parameter shift value: x = x+b\n     * @param {Array} coeffPolyShifted - coefficients of shifted polynomial to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.shiftPoly = function (coeffPoly, degreePoly, b, coeffPolyShifted) {\n        // the binomial theorem:\n        // (x + b)^n = SUM{i=0, i=n}(n!/(i!*(n-i)!))*x^(n-i)*b^i\n        var i, j;\n        var bD = [];\n        bD[0] = 1;\n        for (i = 1; i <= degreePoly; ++i) {\n            bD.push(b * bD[i - 1]);\n        }\n\n        coeffPolyShifted[0] = coeffPoly[0];\n\n        for (i = 1; i <= degreePoly; ++i) {\n            coeffPolyShifted[i] = coeffPoly[i];\n            for (j = 0; j < i; ++j) {\n                coeffPolyShifted[i] += this.combNK(degreePoly - j, i - j) * coeffPoly[j] * bD[i - j];\n            }\n        }\n    };\n\n    /**\n     * An array with the number combinations from 5\n     * @private\n     */\n    IFMath.prototype._numComb5 = [1, 5, 10, 10, 5, 1];\n\n    /**\n     * An array with the number combinations from 4\n     * @private\n     */\n    IFMath.prototype._numComb4 = [1, 4, 6, 4, 1];\n\n    /**\n     * An array with the number combinations from 3\n     * @private\n     */\n    IFMath.prototype._numComb3 = [1, 3, 3, 1];\n\n    /**\n     * An array with the number combinations from 2\n     * @private\n     */\n    IFMath.prototype._numComb2 = [1, 2, 1];\n\n    /**\n     * An array with the number combinations from 1\n     * @private\n     */\n    IFMath.prototype._numComb1 = [1, 1];\n\n    /**\n     * Returns a number of combinations from N by K.\n     * Only N from 1 to 5 is supported\n     * @param {Number} N\n     * @param {Number} K\n     * @return {Number} number of combinations from N by K\n     * @version 1.0\n     */\n    IFMath.prototype.combNK = function (N, K) {\n        if (N <= 5 && K <= N) {\n            if (N == 5) {\n                return this._numComb5[K];\n            }\n            if (N == 4) {\n                return this._numComb4[K];\n            }\n            if (N == 3) {\n                return this._numComb3[K];\n            }\n            if (N == 2) {\n                return this._numComb2[K];\n            }\n            if (N == 1) {\n                return this._numComb1[K];\n            }\n        }\n        else {\n            throw new Error(\"Combinations calculation not implemented\");\n        }\n        return 0;\n    };\n\n    /**\n     * Calculates shifted polynomial coefficients, when original interval is shifted to one (x = x+1).\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @param {Array} coeffPolyShifted - coefficients of shifted polynomial to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.shiftPolyOne = function (coeffPoly, degreePoly, coeffPolyShifted) {\n        // the binomial theorem:\n        // (x + 1)^n = SUM{i=0, i=n}(n!/(i!*(n-i)!))*x^(n-i)\n\n        var i, j;\n\n        coeffPolyShifted[0] = coeffPoly[0];\n\n        for (i = 1; i <= degreePoly; ++i) {\n            coeffPolyShifted[i] = coeffPoly[i];\n            for (j = 0; j < i; ++j) {\n                coeffPolyShifted[i] += this.combNK(degreePoly - j, i - j) * coeffPoly[j];\n            }\n        }\n    };\n\n    /**\n     * Applies transformations to original interval [a, b] so that it becomes (+inf, 0]:\n     * Pnew(x) = (1+x)^n * P((ax+b)/(1+x)),\n     * And calculates coefficients of the resulted polynomial\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @param {Number} a - segment start\n     * @param {Number} b - segment end\n     * @param {Array} coeffPolyInversed - coefficients of transformed polynomial to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.inversePolyInterval = function (coeffPoly, degreePoly, a, b, coeffPolyInversed) {\n        var i;\n        var c;\n        var aD;\n\n        var coeffs = new Float32Array(degreePoly + 1);\n\n        for (i = 0; i <= degreePoly; ++i) {\n            coeffs[i] = coeffPoly[i];\n        }\n\n        // x = a*x + b\n        // 1) x = x + b\n        this.shiftPoly(coeffPoly, degreePoly, a, coeffs);\n\n        // 2) x = ax\n        c = b - a;\n        if (c != 0) {\n            aD = 1;\n            for (i = 1; i <= degreePoly; ++i) {\n                aD /= c;\n                coeffs[degreePoly - i] *= aD;\n            }\n        }\n\n        this.inversePolyUnaryInterval(coeffs, degreePoly, coeffPolyInversed);\n    };\n\n    /**\n     * Applies transformations to original unary interval [0, 1] so that it becomes (+inf, 0]:\n     * Pnew(x) = (1+x)^n * P(1/(1+x)),\n     * And calculates coefficients of the resulted polynomial\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @param {Array} coeffPolyInversed - coefficients of transformed polynomial to be passed out\n     * @version 1.0\n     */\n    IFMath.prototype.inversePolyUnaryInterval = function (coeffPoly, degreePoly, coeffPolyInversed) {\n        var i;\n        var coeffs = new Float32Array(degreePoly + 1);\n        for (i = 0; i <= degreePoly; ++i) {\n            coeffs[i] = coeffPoly[degreePoly - i];\n        }\n\n        // x = x+1\n        this.shiftPolyOne(coeffs, degreePoly, coeffPolyInversed);\n    };\n\n    /**\n     * Estimates the number of positive real roots of a polynomial using Descartes rule of sign\n     * @param {Array} coeffPoly - array of polynomial coefficients, starting from the highest degree\n     * @param {Number} degreePoly - polynomial degree\n     * @return {Number} maximal number of positive real roots of a polynomial\n     * @version 1.0\n     */\n    IFMath.prototype.estimPositiveRootsDescartes = function (coeffPoly, degreePoly) {\n        var nonZeroCoeff = [];\n        var num = 0;\n        var nVarSign = 0;\n        var i;\n\n        for (i = 0; i <= degreePoly; ++i) {\n            if (coeffPoly[i] != 0) {\n                nonZeroCoeff.push(coeffPoly[i]);\n                ++num;\n            }\n        }\n\n        for (i = 0; i < num - 1; ++i) {\n            if (nonZeroCoeff[i] > 0 && nonZeroCoeff[i + 1] < 0 ||\n                nonZeroCoeff[i] < 0 && nonZeroCoeff[i + 1] > 0) {\n\n                nVarSign += 1;\n            }\n        }\n\n        return nVarSign;\n    };\n\n    /**\n     * Construct IFPoint so, that the segment from the previous point and the new point\n     * has the angle of 0 or 45 degrees with X or Y axis, and the new point has unchanged at least one of\n     * originally supplied x and y coordinates (the one with the highest delta from previous point)\n     * @param {Number} prevX - x coordinate of the previous point\n     * @param {Number} prevY - y coordinate of the previous point\n     * @param {Number} origX - originally supplied x coordinate for the new point\n     * @param {Number} origY - originally supplied y coordinate for the new point\n     * @param {Number} rotation - if supplied, means angle in radians at which axes should be rotated before constraining\n     * @returns {IFPoint} new point, making constrain segment with the previous point\n     * @version 1.0\n     */\n    IFMath.prototype.convertToConstrain = function (prevX, prevY, origX, origY, rotation) {\n        // TODO : Move this somewhere else as this is not really but but uses IFTransform which\n        // actually is not part of the core\n        var dx, dy;\n        var tan;\n        var tanPIdiv8 = 0.4142;\n        var newY, newX;\n\n        var backTransform = new IFTransform(1, 0, 0, 1, 0, 0);\n        if (rotation) {\n            backTransform = backTransform.rotated(rotation);\n        }\n        backTransform = backTransform.translated(prevX, prevY);\n        var transform = backTransform.inverted();\n\n        var origTransformed = transform.mapPoint(new IFPoint(origX, origY));\n        var origTrX = origTransformed.getX();\n        var origTrY = origTransformed.getY();\n        dx = Math.abs(origTrX);\n        dy = Math.abs(origTrY);\n        if (!this.isEqualEps(dx, 0) && !this.isEqualEps(dy, 0) && !this.isEqualEps(dx - dy, 0)) {\n            if (dx > dy) {\n                newX = origTrX;\n                tan = dy / dx;\n                if (tan < tanPIdiv8) {\n                    newY = 0;\n                } else {\n                    if (0 > origTrY) {\n                        newY = -dx;\n                    } else {\n                        newY = dx;\n                    }\n                }\n            } else {\n                newY = origTrY;\n                tan = dx / dy;\n                if (tan < tanPIdiv8) {\n                    newX = 0;\n                } else {\n                    if (0 > origTrX) {\n                        newX = -dy;\n                    } else {\n                        newX = dy;\n                    }\n                }\n            }\n        } else {\n            newX = origTrX;\n            newY = origTrY;\n        }\n\n        return backTransform.mapPoint(new IFPoint(newX, newY));\n    };\n\n    _.ifMath = new IFMath();\n})(this);"
  },
  {
    "path": "src/infinity/core/object.js",
    "content": "(function (_) {\n    /**\n     * IFObject is the base object for everything and all\n     * @class IFObject\n     * @constructor\n     * @version 1.0\n     */\n    function IFObject() {\n    }\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFObject.getTypeId Function\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Tries to gather the type id of a given object\n     * @param {Object|Function|Number} object\n     * @return {Number} the type id or null if none was found\n     */\n    IFObject.getTypeId = function (object) {\n        if (typeof object === 'number') {\n            return object;\n        } else if (typeof object === 'function' && object.prototype.hasOwnProperty('__gtype_id__')) {\n            return object.prototype.__gtype_id__;\n        } else if (object && typeof object.__gtype_id__ === 'number') {\n            return object.__gtype_id__;\n        } else {\n            return null;\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFObject.getName Function\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Tries to gather the name of a given source. Falls back to the toString() method.\n     * @param {Object|Function|Number} object\n     * @return {String} the name of the object or null for none\n     */\n    IFObject.getName = function (object) {\n        if (object) {\n            if (typeof object == 'object') {\n                object = object.constructor;\n            }\n\n            if (object && typeof object == 'function') {\n                var funcNameRegex = /function (.{1,})\\(/;\n                var results = (funcNameRegex).exec(object.toString());\n                return (results && results.length > 1) ? results[1] : \"anonymous\";\n            }\n\n            return object.toString();\n        } else {\n            return \"<null>\";\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFObject.inherit Function\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Inherit from another base including fixing the constructor\n     * @param {Object} target the class that should be inherited into\n     * @param {Object} base the base the other class should inherit from\n     * @version 1.0\n     */\n    IFObject.inherit = function (target, base) {\n        target.prototype = Object.create(base.prototype);\n        target.prototype.__gtype_id__ = IFObject._internalTypeIdCounter++;\n        target.prototype.constructor = target;\n\n        // Delete any existing mixins property to avoid writing to the same\n        delete target.prototype.__gmixins__;\n\n        // Ensure to inherit mixins as well\n        if (base.prototype.__gmixins__) {\n            target.prototype.__gmixins__ = {};\n            for (var mixin_id in base.prototype.__gmixins__) {\n                target.prototype.__gmixins__[mixin_id] = true;\n            }\n        }\n\n        // Mix properties of constructor here as they may contain constants and the such\n        if (base != IFObject) {\n            for (var prop in base) {\n                if (prop && prop.length > 0 && prop !== \"constructor\" && prop != \"__gmixins__\" && prop != \"toString\" && prop.charAt(0) != \"_\" && !target[prop]) {\n                    target[prop] = base[prop];\n                }\n            }\n        }\n    };\n\n    /**\n     * Mixin classes together\n     * @param {Object} target the class to be mixed into\n     * @param {Array} mixins array if mixins to mix into\n     * @version 1.0\n     */\n    IFObject.mix = function (target, mixins) {\n        IFObject.inheritAndMix(target, null, mixins);\n    };\n\n    /**\n     * Mixin classes than inherit whereas the inheriting class has the \"last word\"\n     * @param {Object} target the target class to add the mixins to and to inherit into\n     * @param {Object} base the base class to inherit from\n     * @param {Array} [mixins] array if mixins to mix into\n     * @version 1.0\n     */\n    IFObject.inheritAndMix = function (target, base, mixins) {\n        // Inherit from base (if any), first\n        if (base) {\n            this.inherit(target, base);\n        }\n\n        if (mixins) {\n            if (!target.prototype.__gmixins__) {\n                target.prototype.__gmixins__ = {};\n            }\n\n            for (var i = 0; i < mixins.length; ++i) {\n                var mixinPrototype = mixins[i].prototype;\n\n                for (var prop in mixinPrototype) {\n                    if (prop && prop !== \"constructor\" && prop != \"toString\" && prop != \"__gmixins__\" && prop != \"__gtype_id__\" && prop != \"hasMixin\") {\n                        if (prop in target.prototype) {\n                            throw new Error(\"Mixin \" + mixinPrototype + \" may not override \" + prop + \" in \" + target.prototype);\n                        }\n                        target.prototype[prop] = mixinPrototype[prop];\n                    }\n                }\n\n                if (!mixinPrototype.__gtype_id__) {\n                    mixinPrototype.__gtype_id__ = IFObject._internalTypeIdCounter++;\n                }\n\n                target.prototype.__gmixins__[mixinPrototype.__gtype_id__] = true;\n\n                // If the mixin prototype has by itself mixins, ensure to add their references\n                if (mixinPrototype.__gmixins__) {\n                    for (var mixin_id in mixinPrototype.__gmixins__) {\n                        target.prototype.__gmixins__[mixin_id] = true;\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFObject._internalTypeIdCounter = 0;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFObject.prototype.__gtype_id__ = -1;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    IFObject.prototype.__gmixins__ = null;\n\n    /**\n     * Returns whether the instance contains a given mixin\n     * @param {Object} mixin the mixin to check for\n     * @return {Boolean} true if this instance contains the given mixin\n     * @version 1.0\n     */\n    IFObject.prototype.hasMixin = function (mixin) {\n        return this.__gmixins__ && this.__gmixins__[mixin.prototype.__gtype_id__] ? true : false;\n    };\n\n    /** @override */\n    IFObject.prototype.toString = function () {\n        var cname = this.constructor.toString().match(/^function ([^\\(]*)/);\n        return \"[Object \" + (cname ? cname[1] : 'object') + \"]\";\n    };\n\n    _.IFObject = IFObject;\n\n})(this);"
  },
  {
    "path": "src/infinity/core/system.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFSystem\n     * @constructor\n     * @version 1.0\n     */\n    function IFSystem() {\n        // Test little/big-endian using typed arrays\n        this.littleEndian = (function () {\n            var testBuffer = new ArrayBuffer(8);\n            var testArray = new Uint32Array(testBuffer);\n            testArray[1] = 0x0a0b0c0d;\n            return !(testBuffer[4] === 0x0a && testBuffer[5] === 0x0b && testBuffer[6] === 0x0c && testBuffer[7] === 0x0d);\n        })();\n\n        this.hardware = (function () {\n            var tablet = !!navigator.userAgent.match(/(iPad|SCH-I800|xoom|kindle)/i);\n            var phone = !!navigator.userAgent.match(/(iPhone|iPod|blackberry|android 0.5|htc|lg|midp|mmp|mobile|nokia|opera mini|palm|pocket|psp|sgh|smartphone|symbian|treo mini|Playstation Portable|SonyEricsson|Samsung|MobileExplorer|PalmSource|Benq|Windows Phone|Windows Mobile|IEMobile|Windows CE|Nintendo Wii)/i);\n\n            if (tablet) {\n                return IFSystem.Hardware.Tablet;\n            } else if (phone) {\n                return IFSystem.Hardware.Phone;\n            } else {\n                return IFSystem.Hardware.Desktop;\n            }\n        })();\n\n        this.operatingSystem = (function () {\n            var os_data = [\n                { string: navigator.platform, subString: \"Win\", identity: IFSystem.OperatingSystem.Windows },\n                { string: navigator.platform, subString: \"Mac\", identity: IFSystem.OperatingSystem.OSX_IOS },\n                { string: navigator.userAgent, subString: \"iPhone\", identity: IFSystem.OperatingSystem.OSX_IOS },\n                { string: navigator.userAgent, subString: \"iPad\", identity: IFSystem.OperatingSystem.OSX_IOS },\n                { string: navigator.userAgent, subString: \"Android\", identity: IFSystem.OperatingSystem.Unix },\n                { string: navigator.platform, subString: \"Linux\", identity: IFSystem.OperatingSystem.Unix }\n            ];\n\n            for (var i = 0; i < os_data.length; i++) {\n                var dataString = os_data[i].string;\n                if (dataString.indexOf(os_data[i].subString) != -1) {\n                    return os_data[i].identity;\n                }\n            }\n\n            return IFSystem.OperatingSystem.Windows;\n        })();\n\n        this.language = (function () {\n            var lang = ((navigator.language || navigator.browserLanguage || navigator.systemLanguage || navigator.userLanguage) || '').split(\"-\");\n\n            if (lang.length == 2) {\n                return  lang[0].toLowerCase();\n            } else if (lang) {\n                return lang[0].toLowerCase();\n            }\n\n            return null;\n        })();\n\n        console.log('HW=' + this.hardware + '; OS=' + this.operatingSystem + '; LANG=' + this.language);\n    };\n\n    /**\n     * @enum\n     * @version 1.0\n     */\n    IFSystem.OperatingSystem = {\n        /**\n         * Linux/unix based operating system\n         * @type {Number}\n         * @version 1.0\n         */\n        Unix: 0,\n\n        /**\n         * Windows based operating system\n         * @type {Number}\n         * @version 1.0\n         */\n        Windows: 1,\n\n        /**\n         * OSX/IOS based operating system\n         * @type {Number}\n         * @version 1.0\n         */\n        OSX_IOS: 2\n    };\n\n    /**\n     * @enum\n     * @version 1.0\n     */\n    IFSystem.Hardware = {\n        /**\n         * PC/Laptop based hardware\n         * @type {Number}\n         * @version 1.0\n         */\n        Desktop: 0,\n\n        /**\n         * Tablet based hardware\n         * @type {Number}\n         * @version 1.0\n         */\n        Tablet: 1,\n\n        /**\n         * Phone based hardware\n         * @type {Number}\n         * @version 1.0\n         */\n        Phone: 2\n    };\n\n    /**\n     * Property defining whether the system is in little endian (true)\n     * or in big endian (false) mode\n     * @type {Boolean}\n     * @version 1.0\n     */\n    IFSystem.prototype.littleEndian = true;\n\n    /**\n     * Property defining the operating system type\n     * @type {Number}\n     * @see IFSystem.OperatingSystem\n     * @version 1.0\n     */\n    IFSystem.prototype.operatingSystem = null;\n\n    /**\n     * Property defining the hardware type\n     * @type {Number}\n     * @see IFSystem.Hardware\n     * @version 1.0\n     */\n    IFSystem.prototype.hardware = null;\n\n    /**\n     * Property defining the system's language\n     * @type {String}\n     * @version 1.0\n     */\n    IFSystem.prototype.language = null;\n\n    _.IFSystem = IFSystem;\n    _.ifSystem = new IFSystem();\n})(this);"
  },
  {
    "path": "src/infinity/core/util.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFUtil\n     * @constructor\n     * @version 1.0\n     */\n    function IFUtil() {\n    };\n\n    /**\n     * This is equal to the Array.indexOf function except that for\n     * comparing the values in the array, the ifUtil.equals function\n     * is used instead\n     * @param {Array} array the array to get an index for an element\n     * @param {*} element the element to get the index for\n     * @param {Boolean} [objectByValue] if set, objects are compared by their value and\n     * not by their reference. Defaults to false if not provided.\n     * @return {Number} a value less than zero if element is not found or\n     * the index of the given element in the given array\n     */\n    IFUtil.prototype.indexOfEquals = function (array, element, objectByValue) {\n        for (var i = 0; i < array.length; ++i) {\n            if (this.equals(array[i], element, objectByValue)) {\n                return i;\n            }\n        }\n        return -1;\n    };\n\n    /**\n     * Compare two objects for equality by their values. Also takes care of null parameters.\n     * If the function can not compare the type by value then it'll return false as if\n     * the two parameters wouldn't be equal.\n     * Currently supported types: Object, Boolean, Number, String, Array, Date, IFRect, IFPoint, IFTransform.\n     * For objects this will iterate only the object's own properties to an unnested deepness so\n     * take care in using this function for highly complex object structures.\n     * For numbers, the epsilon comparison will be used so that very small differences in numbers\n     * are considered equal to compensate for any floating point errors\n     * @param {*} left left side of comparison\n     * @param {*} right right side of comparison\n     * @param {Boolean} [objectByValue] if set, objects are compared by their value and\n     * not by their reference. Defaults to false if not provided.\n     * @return {Boolean} true if left and right are equal (also if they're null!)\n     */\n    IFUtil.prototype.equals = function (left, right, objectByValue) {\n        if (!left && left === right) {\n            return true;\n        } else if (left && right) {\n            // Check for special 'equals' function\n            if (left.constructor.equals || right.constructor.equals) {\n                if (left.constructor === right.constructor) {\n                    return left.constructor.equals(left, right);\n                } else {\n                    return false;\n                }\n            } else if (left instanceof Date || right instanceof Date) {\n                return left instanceof Date && right instanceof Date ? (+left == +right) : false;\n            } else if (left instanceof Array || right instanceof Array) {\n                if (left instanceof Array && right instanceof Array) {\n                    if (left.length !== right.length) {\n                        return false;\n                    }\n\n                    for (var i = 0; i < left.length; ++i) {\n                        if (!this.equals(left[i], right[i], objectByValue)) {\n                            return false;\n                        }\n                    }\n\n                    return true;\n                } else {\n                    return false;\n                }\n            } else {\n                var leftType = typeof left;\n                var rightType = typeof right;\n\n                if (leftType !== rightType) {\n                    return false;\n                }\n\n                if (leftType === 'number') {\n                    if (isNaN(left) || isNaN(right)) {\n                        return isNaN(left) && isNaN(right);\n                    } else {\n                        return ifMath.isEqualEps(left, right);\n                    }\n                } else if (leftType === 'string') {\n                    return left.localeCompare(right) === 0;\n                } else if (leftType === 'boolean') {\n                    return (+left == +right);\n                } else if (leftType === 'object') {\n                    if (!objectByValue) {\n                        return left === right;\n                    } else {\n                        var leftKeys = Object.keys(left);\n                        var rightKeys = Object.keys(right);\n\n                        if (!this.equals(leftKeys, rightKeys, objectByValue)) {\n                            return false;\n                        }\n\n                        for (var i = 0; i < leftKeys.length; ++i) {\n                            if (!this.equals(left[leftKeys[i]], right[leftKeys[i]]), objectByValue) {\n                                return false;\n                            }\n                        }\n\n                        return true;\n                    }\n                } else {\n                    return false;\n                }\n            }\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * Checks if a given array contains at least one key\n     * of a given object\n     * @param {Array<*>} array\n     * @param {*} object\n     */\n    IFUtil.prototype.containsObjectKey = function (array, object) {\n        for (var key in object) {\n            if (array.indexOf(key) >= 0) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');\n\n    /**\n     * Generate an unique id\n     * @param {Number} [len] the desired length of the uid, defaults to 32\n     * @returns {String} more or less unique id depending on the desired length\n     */\n    IFUtil.prototype.uuid = function (len) {\n        var chars = CHARS, uuid = [], i;\n        var radix = chars.length;\n        var len = len ? len : 32;\n        for (i = 0; i < len; i++) {\n            uuid[i] = chars[0 | Math.random() * radix];\n        }\n        return uuid.join('');\n    };\n\n    /**\n     * Replace all occurrences of a string with another string\n     * @param {String} string the string to replace within\n     * @param {String} what_ the string to look for\n     * @param {String} with_ the string to replace with\n     * @returns {String}\n     */\n    IFUtil.prototype.replaceAll = function (string, what_, with_) {\n        var result = string;\n        while (result.indexOf(what_) >= 0) {\n            result = result.replace(what_, with_);\n        }\n        return result;\n    };\n\n    // Makes unique sort of array elements, leaving only the elements from [a,b] segment\n    // New array is written into newnums\n    IFUtil.prototype.uSortSegment = function (a, b, nums, newnums) {\n        var nElms = 0;\n        nums.sort(function (s, k) {\n            return s - k;\n        });\n\n        if (nums[0] >= a && nums[0] <= b) {\n            newnums[0] = nums[0];\n            nElms = 1;\n\n            if (nums.length == 1) {\n                return nElms;\n            }\n        }\n\n        for (var i = 1; i < nums.length; i++) {\n            if (nums[i] != nums[i - 1] && nums[i] >= a && nums[i] <= b) {\n                newnums.push(nums[i]);\n                ++nElms;\n            }\n        }\n\n        return nElms;\n    };\n\n    /**\n     * Escape an unescaped html string\n     * @param {String} html\n     * @returns {String}\n     */\n    IFUtil.prototype.escape = function (html) {\n        return html.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#039;\");\n    };\n\n    /**\n     * Unscape an escaped html string\n     * @param {String} html\n     * @returns {String}\n     */\n    IFUtil.prototype.unescape = function (html) {\n        var result = ifUtil.replaceAll(html, \"&lt;\", '<');\n        result = ifUtil.replaceAll(result, \"&gt;\", '>');\n        result = ifUtil.replaceAll(result, \"&quot;\", '\"');\n        result = ifUtil.replaceAll(result, \"&#039;\", \"'\");\n        result = ifUtil.replaceAll(result, \"&amp;\", '&');\n        return result;\n    };\n\n    /**\n     * Checks and returns whether a given string is numeric or not\n     * @param {string} string\n     * @returns {boolean}\n     */\n    IFUtil.prototype.isNumeric = function (string) {\n        // parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n        // ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n        // subtraction forces infinities to NaN\n        return string - parseFloat(string) >= 0;\n    };\n\n    /**\n     * Format a number into a string\n     * @param {Number} number the number to format\n     * @param {Number} [decimalPlaces] the number of decimal places,\n     * defaults to 3\n     * @param {String} [decimalSeparator] the decimal separator to use,\n     * if not provided defaults to ','\n     * @returns {string}\n     */\n    IFUtil.prototype.formatNumber = function (number, decimalPlaces, decimalSeparator) {\n        decimalSeparator = decimalSeparator || ',';\n        decimalPlaces = typeof decimalPlaces === 'number' ? decimalPlaces : 3;\n        return ifMath.round(number, false, decimalPlaces).toString().replace('.', decimalSeparator);\n    };\n\n    /**\n     * Parses a string into a number\n     * @param {string} the string to be parsed as number\n     * @returns {Number}\n     */\n    IFUtil.prototype.parseNumber = function (string) {\n        var parseString = \"\";\n        var foundDecSep = false;\n        for (var i = string.length; i >= 0; --i) {\n            var char = string.charAt(i);\n            if (char === ',' && !foundDecSep) {\n                parseString = '.' + parseString;\n            } else if (this.isNumeric(char)) {\n                parseString = char + parseString;\n            }\n        }\n        return parseFloat(parseString);\n    };\n\n    /**\n     * Blends the fore color with the back color using\n     * a given alpha value\n     * @param {Array<Number>} back [r,g,b] color (0..255)\n     * @param {Array<Number>} fore [r,g,b] color (0..255)\n     * @param {Number} alpha between 0..1\n     * @return {Array<Number>} [r,g,b] blended result\n     */\n    IFUtil.prototype.blendRGBColors = function (back, fore, alpha) {\n        alpha = Math.min(Math.max(alpha, 0), 1);\n\n        return [\n            (back[0] * (1 - alpha)) + (fore[0] * alpha),\n            (back[1] * (1 - alpha)) + (fore[1] * alpha),\n            (back[2] * (1 - alpha)) + (fore[2] * alpha)\n        ];\n    };\n\n    /**\n     * Return a rgb array to a html hex string\n     * @param {Array<Number>} rgb [r,g,b] color (0..255)\n     * @returns {string}\n     */\n    IFUtil.prototype.rgbToHtmlHex = function (rgb) {\n        var bin = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n        return '#' + (function (h) {\n            return new Array(7 - h.length).join(\"0\") + h\n        })(bin.toString(16).toUpperCase());\n    };\n\n    _.ifUtil = new IFUtil();\n})(this);"
  },
  {
    "path": "src/infinity/event/event.js",
    "content": "(function (_) {\n    /**\n     * An object representing an event.\n     * @class GEvent\n     * @extends IFObject\n     * @constructor\n     * @version 1.0\n     */\n    function GEvent() {\n    }\n\n    IFObject.inherit(GEvent, IFObject);\n\n    /** @private */\n    GEvent.prototype._paramsToString = function () {\n        return \"\";\n    }\n\n    _.GEvent = GEvent;\n})(this);"
  },
  {
    "path": "src/infinity/event/eventtarget.js",
    "content": "(function (_) {\n    /**\n     * A mixin representing the target of an event.\n     * @class GEventTarget\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    function GEventTarget() {\n    }\n\n    /**\n     * @type Object\n     * @private\n     */\n    GEventTarget.prototype._listeners = null;\n\n    /**\n     * Add a new listener for a specific eventClass to this object\n     * @param {*} eventClass the eventClass to register the listener for\n     * @param {Function} listener the listener function to be called\n     * @param {Object} [target] optional target (\"this\") for the listener\n     * @param {Array} [args] optional arguments to be prepended to the listener call\n     * @version 1.0\n     */\n    GEventTarget.prototype.addEventListener = function (eventClass, listener, target, args) {\n        var event_id = IFObject.getTypeId(eventClass);\n\n        if (!this._listeners) {\n            this._listeners = {};\n        }\n\n        // Save the original listener for later removal identification\n        var sourceListener = listener;\n\n        // Check if we shall bind the listener\n        if (target || args) {\n            /** @type Array */\n            var argArray = args ? args.slice() : [];\n            argArray.unshift(target ? target : listener);\n            listener = Function.prototype.bind.apply(listener, argArray);\n        }\n\n        if (!(event_id in this._listeners)) {\n            this._listeners[event_id] = {\n                eventClass: eventClass,\n                listeners: []\n            };\n        }\n\n        this._listeners[event_id].listeners.push({listener: listener, sourceListener: sourceListener, target: target});\n    };\n\n    /**\n     * Remove a listener for a specific eventClass from this object\n     * @param {*} eventClass the constructor of the eventClass to unregister for\n     * @param {Function} listener the listener function to be removed\n     * @param {Object} [target] optional target (\"this\") for the listener\n     * @version 1.0\n     */\n    GEventTarget.prototype.removeEventListener = function (eventClass, listener, target) {\n        var event_id = IFObject.getTypeId(eventClass);\n\n        if (this._listeners && event_id in this._listeners) {\n            var array = this._listeners[event_id].listeners;\n            for (var i = 0; i < array.length; ++i) {\n                if (array[i].sourceListener == listener && (!target || array[i].target === target)) {\n                    array.splice(i, 1);\n                }\n            }\n            if (array.length == 0) {\n                delete this._listeners[event_id];\n            }\n        }\n    };\n\n    /**\n     * Checks and returns whether there's at least one listener registered\n     * for a specific eventClass\n     * @param {*} eventClass the constructor of the eventClass to check for\n     * @returns {Boolean} true if there's at least one listener, false if not\n     * @version 1.0\n     */\n    GEventTarget.prototype.hasEventListeners = function (eventClass) {\n        var event_id = IFObject.getTypeId(eventClass);\n        return this._listeners && event_id in this._listeners ? true : false;\n    };\n\n    /**\n     * Trigger an event for this object. Note: You should always check if there\n     * is an event listener registered for the given event before triggering.\n     * @param {GEvent} event the event to trigger\n     * @see hasEventListeners\n     * @version 1.0\n     */\n    GEventTarget.prototype.trigger = function (event) {\n        if (this._listeners) {\n            var event_id = IFObject.getTypeId(event);\n            if (event_id in this._listeners) {\n                var array = this._listeners[event_id].listeners;\n                for (var i = 0; i < array.length; ++i) {\n                    var listenerObj = array[i];\n                    listenerObj.listener.call(this, event);\n                }\n            }\n        }\n    };\n\n    _.GEventTarget = GEventTarget;\n})(this);"
  },
  {
    "path": "src/infinity/event/inputevent.js",
    "content": "(function (_) {\n    /**\n     * An object representing an input event.\n     * @class GUIInputEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    function GUIInputEvent() {\n    }\n\n    IFObject.inherit(GUIInputEvent, GEvent);\n\n    /** @override */\n    GUIInputEvent.prototype.toString = function () {\n        return \"[Object GUIInputEvent(\" + this._paramsToString() + \")]\";\n    };\n\n    /** @private */\n    GUIInputEvent.prototype._paramsToString = function () {\n        return \"\";\n    };\n\n    _.GUIInputEvent = GUIInputEvent;\n})(this);"
  },
  {
    "path": "src/infinity/event/keyevent.js",
    "content": "(function (_) {\n    /**\n     * An object representing a key input event.\n     * @class GUIKeyEvent\n     * @extends GUIInputEvent\n     * @constructor\n     * @version 1.0\n     */\n    function GUIKeyEvent() {\n    }\n\n    IFObject.inherit(GUIKeyEvent, GUIInputEvent);\n\n    /**\n     * The key for the key event. Might either be one of IFKey.Constant (number)\n     * or a String if printable character key\n     * @type {String|Number}\n     * @version 1.0\n     * @see IFKey.Constant\n     */\n    GUIKeyEvent.prototype.key = null;\n\n    /** @override */\n    GUIKeyEvent.prototype.toString = function () {\n        return \"[Object GUIKeyEvent(\" + this._paramsToString() + \")]\";\n    };\n\n    /** @override */\n    GUIKeyEvent.prototype.GUIKeyEvent = function () {\n        return \"key=\" + this.key;\n    }\n\n    _.GUIKeyEvent = GUIKeyEvent;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIKeyEvent.Down\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a key down event.\n     * @class GUIKeyEvent.Down\n     * @extends GUIKeyEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIKeyEvent.Down = function () {\n    }\n    IFObject.inherit(GUIKeyEvent.Down, GUIKeyEvent);\n\n\n    /** @override */\n    GUIKeyEvent.Down.prototype.toString = function () {\n        return \"[Object GUIKeyEvent.Down(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIKeyEvent.Release\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a key release event.\n     * @class GUIKeyEvent.Release\n     * @extends GUIKeyEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIKeyEvent.Release = function () {\n    }\n    IFObject.inherit(GUIKeyEvent.Release, GUIKeyEvent);\n\n\n    /** @override */\n    GUIKeyEvent.Release.prototype.toString = function () {\n        return \"[Object GUIKeyEvent.Release(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIKeyEvent.Press\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a key press event.\n     * @class GUIKeyEvent.Press\n     * @extends GUIKeyEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIKeyEvent.Press = function () {\n    }\n    IFObject.inherit(GUIKeyEvent.Press, GUIKeyEvent);\n\n\n    /** @override */\n    GUIKeyEvent.Press.prototype.toString = function () {\n        return \"[Object GUIKeyEvent.Press(\" + this._paramsToString() + \")]\";\n    };\n\n})(this);"
  },
  {
    "path": "src/infinity/event/mouseevent.js",
    "content": "(function (_) {\n    /**\n     * An object representing a mouse input event.\n     * @class GUIMouseEvent\n     * @extends GUIInputEvent\n     * @constructor\n     * @version 1.0\n     */\n    function GUIMouseEvent() {\n    }\n\n    IFObject.inherit(GUIMouseEvent, GUIInputEvent);\n\n    /**\n     * Constant defining the left mouse button\n     * @type {Number}\n     * @version 1.0\n     */\n    GUIMouseEvent.BUTTON_LEFT = 0;\n\n    /**\n     * Constant defining the middle mouse button\n     * @type {Number}\n     * @version 1.0\n     */\n    GUIMouseEvent.BUTTON_MIDDLE = 1;\n\n    /**\n     * Constant defining the right mouse button\n     * @type {Number}\n     * @version 1.0\n     */\n    GUIMouseEvent.BUTTON_RIGHT = 2;\n\n    /**\n     * Tests and returns whether a given event class is a drag event or not\n     * @param {Function|GUIMouseEvent} event the event class or event instance to test\n     * @returns {Boolean} true if event is a drag event, false if not\n     * @version 1.0\n     */\n    GUIMouseEvent.isDragEvent = function (event) {\n        return ((event instanceof GUIMouseEvent &&\n            (event instanceof GUIMouseEvent.DragStart || event instanceof GUIMouseEvent.Drag || event instanceof GUIMouseEvent.DragEnd)) ||\n            (event == GUIMouseEvent.DragStart || event == GUIMouseEvent.Drag || event == GUIMouseEvent.DragEnd));\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * The position of the cursor in client (widget) -coordinates\n     * @type {IFPoint}\n     * @version 1.0\n     */\n    GUIMouseEvent.prototype.client = 0;\n\n    /**\n     * The mouse button number held down\n     * @type {Number}\n     * @version 1.0\n     */\n    GUIMouseEvent.prototype.button = 0;\n\n    /** @override */\n    GUIMouseEvent.prototype.toString = function () {\n        return \"[Object GUIMouseEvent(\" + this._paramsToString() + \")]\";\n    };\n\n    /** @override */\n    GUIMouseEvent.prototype._paramsToString = function () {\n        return \"client=\" + this.client.toString() + \", \" + GUIInputEvent.prototype._paramsToString.call(this);\n    }\n\n    _.GUIMouseEvent = GUIMouseEvent;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Move\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse move event.\n     * Note that this will always be fired before any drag events.\n     * @class GUIMouseEvent.Move\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Move = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Move, GUIMouseEvent);\n\n\n    /** @override */\n    GUIMouseEvent.Move.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Move(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Enter\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse enter event.\n     * @class GUIMouseEvent.Enter\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Enter = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Enter, GUIMouseEvent);\n\n\n    /** @override */\n    GUIMouseEvent.Enter.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Enter(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Leave\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse leave event.\n     * @class GUIMouseEvent.Leave\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Leave = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Leave, GUIMouseEvent);\n\n\n    /** @override */\n    GUIMouseEvent.Leave.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Leave(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Down\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse down event.\n     * Note that this will always be fired before any drag events.\n     * @class GUIMouseEvent.Down\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Down = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Down, GUIMouseEvent);\n\n\n    /** @override */\n    GUIMouseEvent.Down.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Down(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Release\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse release (up) event.\n     * Note that this will always be fired before any drag events.\n     * @class GUIMouseEvent.Release\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Release = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Release, GUIMouseEvent);\n\n\n    /** @override */\n    GUIMouseEvent.Release.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Release(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Click\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse click event.\n     * @class GUIMouseEvent.Click\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Click = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Click, GUIMouseEvent);\n\n\n    /** @override */\n    GUIMouseEvent.Click.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Click(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.DblClick\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse double-click event.\n     * @class GUIMouseEvent.DblClick\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.DblClick = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.DblClick, GUIMouseEvent);\n\n    /** @override */\n    GUIMouseEvent.DblClick.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.DblClick(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.DragStart\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse drag-start event\n     * Note that this will always be fired after a GUIMouseEvent.Move event.\n     * @class GUIMouseEvent.DragStart\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.DragStart = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.DragStart, GUIMouseEvent);\n\n    /** @override */\n    GUIMouseEvent.DragStart.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.DragStart(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.Drag\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse drag (move) event\n     * Note that this will always be fired after a GUIMouseEvent.Move event.\n     * @class GUIMouseEvent.Drag\n     * @extends GUIMouseEvent\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.Drag = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.Drag, GUIMouseEvent);\n\n    /**\n     * The drag start position in client (widget) -coordinates\n     * @type {IFPoint}\n     * @version 1.0\n     */\n    GUIMouseEvent.prototype.clientStart = 0;\n\n    /**\n     * The drag subtract (current to previous pos) in client (widget) -coordinates\n     * @type {IFPoint}\n     * @version 1.0\n     */\n    GUIMouseEvent.prototype.clientDelta = 0;\n\n    /** @override */\n    GUIMouseEvent.Drag.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.Drag(\" + this._paramsToString() + \")]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIMouseEvent.DragEnd\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing a mouse drag-end event\n     * Note that this will always be fired after a GUIMouseEvent.Release event.\n     * @class GUIMouseEvent.DragEnd\n     * @extends GUIMouseEvent.Drag\n     * @constructor\n     * @version 1.0\n     */\n    GUIMouseEvent.DragEnd = function () {\n    }\n    IFObject.inherit(GUIMouseEvent.DragEnd, GUIMouseEvent.Drag);\n\n    /** @override */\n    GUIMouseEvent.DragEnd.prototype.toString = function () {\n        return \"[Object GUIMouseEvent.DragEnd(\" + this._paramsToString() + \")]\";\n    };\n\n})(this);"
  },
  {
    "path": "src/infinity/geometry/length.js",
    "content": "(function (_) {\n    /**\n     * A class representing a unit with a value\n     * @param {Number} value\n     * @param {IFLength.Unit} [unit] the unit unit, defaults to IFLength.Unit.PT\n     * @see IFLength.Unit\n     * @class IFLength\n     * @constructor\n     */\n    function IFLength(value, unit) {\n        this._value = value;\n        this._unit = unit ? unit : IFLength.Unit.PT;\n    };\n\n    /**\n     * The unit of a length\n     * @enum\n     */\n    IFLength.Unit = {\n        /**\n         * Point Unit ('pt')\n         * @unit Number\n         * @version 1.0\n         */\n        PT: 't',\n\n        /**\n         * Pixel Unit ('px')\n         * @unit Number\n         * @version 1.0\n         */\n        PX: 'x',\n\n        /**\n         * Pica Unit ('pc')\n         * @unit Number\n         * @version 1.0\n         */\n        PC: 'p',\n\n        /**\n         * Inch Unit ('in')\n         * @unit Number\n         * @version 1.0\n         */\n        IN: 'i',\n\n        /**\n         * Milimeter Unit ('mm')\n         * @unit Number\n         * @version 1.0\n         */\n        MM: 'm',\n\n        /**\n         * Centimeter Unit ('cm')\n         * @unit Number\n         * @version 1.0\n         */\n        CM: 'c'\n    };\n\n    // Use strict 72ppi for screen\n    var dpi = 72.0;\n\n    // Calculate our dpi-map\n    var DPI_MAP = {\n        't': 1.0, /* PT */\n        'x': 1, /* PX */\n        'p': dpi / 6.0, /* PC */\n        'i': dpi,\n        'm': dpi / 25.4, /* MM */\n        'c': dpi / 2.54 /* CM */\n    };\n\n    /**\n     * Parse and construct a unit from a string. If string is not parseable,\n     * this returns null. If string contains a number but invalid unit-unit or\n     * none, then the unit-unit of the result defaults to defaultUnit\n     * @param {String} string the string to parse for value and unit-unit\n     * @param {IFLength.Unit} [defaultUnit] the default unit to be used,\n     * defaults to IFLength.Unit.PT\n     */\n    IFLength.parseLength = function (string, defaultUnit) {\n        if (!string) {\n            return null;\n        }\n        string = string.trim();\n        if (string.length == 0) {\n            return null;\n        }\n\n        var number = ifUtil.parseNumber(string);\n        if (typeof number != \"number\") {\n            return null;\n        }\n\n        var unitType = defaultUnit ? defaultUnit : IFLength.Unit.PT;\n        var unitStr = string.substr(number.toString().length);\n        if (unitStr && unitStr.length > 0) {\n            unitStr = unitStr.trim().toLowerCase();\n            if (unitStr.length >= 2 && unitStr.charAt(0) == 'p' && unitStr.charAt(1) == 't') {\n                unitType = IFLength.Unit.PT;\n            } else if (unitStr.length >= 2 && unitStr.charAt(0) == 'p' && unitStr.charAt(1) == 'x') {\n                unitType = IFLength.Unit.PX;\n            } else if (unitStr.length >= 2 && unitStr.charAt(0) == 'p' && unitStr.charAt(1) == 'c') {\n                unitType = IFLength.Unit.PC;\n            } else if (unitStr.length >= 2 && unitStr.charAt(0) == 'i' && unitStr.charAt(1) == 'n') {\n                unitType = IFLength.Unit.IN;\n            } else if (unitStr.length >= 2 && unitStr.charAt(0) == 'm' && unitStr.charAt(1) == 'm') {\n                unitType = IFLength.Unit.MM;\n            } else if (unitStr.length >= 2 && unitStr.charAt(0) == 'c' && unitStr.charAt(1) == 'm') {\n                unitType = IFLength.Unit.CM;\n            } else if (unitStr.length >= 1 && unitStr.charAt(0) == 'm') {\n                unitType = IFLength.Unit.M;\n            }\n        }\n\n        return new IFLength(number, unitType);\n    };\n\n    /**\n     * Parses an equation (supports /, *, + and -) with optional unit\n     * identifiers and evaluates the equation by converting to points\n     * @param {String} string the source equation to parse\n     * @param {IFLength.Unit} [unit] the unit to be used,\n     * defaults to IFLength.Unit.PT\n     * @returns {IFLength} null if equation is invalid or a valid length\n     * in the given unit space\n     */\n    IFLength.parseEquation = function (string, unit) {\n        unit = unit || IFLength.Unit.PT;\n        var context = new LengthHelpers.Context(unit);\n        var evaluator = new LengthHelpers.Evaluator(context);\n        try {\n            result = evaluator.evaluate(string);\n            return new IFLength(result, unit);\n        } catch (e) {\n            return null;\n        }\n    };\n\n    /**\n     * Equal to parseEquation but ignores any units\n     * and returns a number value instead\n     * @param {string} expression\n     * @returns {Number} null for error in expression or a value number\n     */\n    IFLength.parseEquationValue = function (string) {\n        var length = IFLength.parseEquation(string);\n        return length ? length.getValue() : null;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFLength Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @unit {Number}\n     * @private\n     */\n    IFLength.prototype._value = null;\n\n    /**\n     * @unit {Number}\n     * @see IFLength.Unit\n     * @private\n     */\n    IFLength.prototype._unit = IFLength.Unit.PT;\n\n    /**\n     * @return {Number}\n     */\n    IFLength.prototype.getValue = function () {\n        return this._value;\n    };\n\n    /**\n     * @return {IFLength.Unit}\n     */\n    IFLength.prototype.getUnit = function () {\n        return this._unit;\n    };\n\n    IFLength.prototype.toPoint = function () {\n        if (this._unit != IFLength.Unit.PT) {\n            return DPI_MAP[this._unit] * this._value;\n        } else {\n            return this._value;\n        }\n    };\n\n    IFLength.prototype.toUnit = function (unit) {\n        if (this._unit != unit) {\n            var ptValue = this.toPoint();\n            return ptValue / DPI_MAP[unit];\n        } else {\n            return this._value;\n        }\n    };\n\n    IFLength.prototype.convert = function (unit) {\n        if (this._unit != unit) {\n            var ptValue = this.toPoint();\n            return new IFLength(ptValue / DPI_MAP[unit], unit);\n        } else {\n            return new IFLength(this._value, unit);\n        }\n    };\n\n    IFLength.prototype.toString = function (digits) {\n        var result = ifUtil.formatNumber(this._value, digits);\n\n        switch (this._unit) {\n            case IFLength.Unit.PT:\n                result += \"pt\";\n                break;\n            case IFLength.Unit.PX:\n                result += \"px\";\n                break;\n            case IFLength.Unit.PC:\n                result += \"pc\";\n                break;\n            case IFLength.Unit.IN:\n                result += \"in\";\n                break;\n            case IFLength.Unit.MM:\n                result += \"mm\";\n                break;\n            case IFLength.Unit.CM:\n                result += \"cm\";\n                break;\n        }\n\n        return result;\n    };\n\n    var LengthHelpers = {};\n\n    LengthHelpers.Token = {\n        Operator: 'Operator',\n        Identifier: 'Identifier',\n        Number: 'Number'\n    };\n\n    LengthHelpers.Lexer = function () {\n        var expression = '',\n            length = 0,\n            index = 0,\n            marker = 0,\n            T = LengthHelpers.Token;\n\n        function peekNextChar() {\n            var idx = index;\n            return ((idx < length) ? expression.charAt(idx) : '\\x00');\n        }\n\n        function getNextChar() {\n            var ch = '\\x00',\n                idx = index;\n            if (idx < length) {\n                ch = expression.charAt(idx);\n                index += 1;\n            }\n            return ch;\n        }\n\n        function isWhiteSpace(ch) {\n            return (ch === '\\u0009') || (ch === ' ') || (ch === '\\u00A0');\n        }\n\n        function isLetter(ch) {\n            return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');\n        }\n\n        function isDecimalDigit(ch) {\n            return (ch >= '0') && (ch <= '9');\n        }\n\n        function createToken(unit, value) {\n            return {\n                unit: unit,\n                value: value,\n                start: marker,\n                end: index - 1\n            };\n        }\n\n        function skipSpaces() {\n            var ch;\n\n            while (index < length) {\n                ch = peekNextChar();\n                if (!isWhiteSpace(ch)) {\n                    break;\n                }\n                getNextChar();\n            }\n        }\n\n        function scanOperator() {\n            var ch = peekNextChar();\n            if ('+-*/()^%=;,'.indexOf(ch) >= 0) {\n                return createToken(T.Operator, getNextChar());\n            }\n            return undefined;\n        }\n\n        function isIdentifierStart(ch) {\n            return (ch === '_') || isLetter(ch);\n        }\n\n        function isIdentifierPart(ch) {\n            return isIdentifierStart(ch) || isDecimalDigit(ch);\n        }\n\n        function scanIdentifier() {\n            var ch, id;\n\n            ch = peekNextChar();\n            if (!isIdentifierStart(ch)) {\n                return undefined;\n            }\n\n            id = getNextChar();\n            while (true) {\n                ch = peekNextChar();\n                if (!isIdentifierPart(ch)) {\n                    break;\n                }\n                id += getNextChar();\n            }\n\n            return createToken(T.Identifier, id);\n        }\n\n        function scanNumber() {\n            var ch, number;\n\n            ch = peekNextChar();\n            if (!isDecimalDigit(ch) && (ch !== '.')) {\n                return undefined;\n            }\n\n            number = '';\n            if (ch !== '.') {\n                number = getNextChar();\n                while (true) {\n                    ch = peekNextChar();\n                    if (!isDecimalDigit(ch)) {\n                        break;\n                    }\n                    number += getNextChar();\n                }\n            }\n\n            // We support both, dot and comma decimal separators\n            if (ch === '.' || ch === ',') {\n                number += getNextChar();\n                while (true) {\n                    ch = peekNextChar();\n                    if (!isDecimalDigit(ch)) {\n                        break;\n                    }\n                    number += getNextChar();\n                }\n            }\n\n            if (ch === 'e' || ch === 'E') {\n                number += getNextChar();\n                ch = peekNextChar();\n                if (ch === '+' || ch === '-' || isDecimalDigit(ch)) {\n                    number += getNextChar();\n                    while (true) {\n                        ch = peekNextChar();\n                        if (!isDecimalDigit(ch)) {\n                            break;\n                        }\n                        number += getNextChar();\n                    }\n                } else {\n                    ch = 'character ' + ch;\n                    if (index >= length) {\n                        ch = '<end>';\n                    }\n                    throw new SyntaxError('Unexpected ' + ch + ' after the exponent sign');\n                }\n            }\n\n            if (isLetter(ch)) {\n                number += getNextChar();\n                while (true) {\n                    ch = peekNextChar();\n                    if (!isLetter(ch)) {\n                        break;\n                    }\n                    number += getNextChar();\n                }\n            }\n\n            if (number === '.') {\n                throw new SyntaxError('Expecting decimal digits after the dot sign');\n            }\n\n            return createToken(T.Number, number);\n        }\n\n        function reset(str) {\n            expression = str;\n            length = str.length;\n            index = 0;\n        }\n\n        function next() {\n            var token;\n\n            skipSpaces();\n            if (index >= length) {\n                return undefined;\n            }\n\n            marker = index;\n\n            token = scanNumber();\n            if (typeof token !== 'undefined') {\n                return token;\n            }\n\n            token = scanOperator();\n            if (typeof token !== 'undefined') {\n                return token;\n            }\n\n            token = scanIdentifier();\n            if (typeof token !== 'undefined') {\n                return token;\n            }\n\n\n            throw new SyntaxError('Unknown token from character ' + peekNextChar());\n        }\n\n        function peek() {\n            var token, idx;\n\n            idx = index;\n            try {\n                token = next();\n                delete token.start;\n                delete token.end;\n            } catch (e) {\n                token = undefined;\n            }\n            index = idx;\n\n            return token;\n        }\n\n        return {\n            reset: reset,\n            next: next,\n            peek: peek\n        };\n    };\n\n    LengthHelpers.Parser = function () {\n\n        var lexer = new LengthHelpers.Lexer(),\n            T = LengthHelpers.Token;\n\n        function matchOp(token, op) {\n            return (typeof token !== 'undefined') &&\n                token.unit === T.Operator &&\n                token.value === op;\n        }\n\n        // ArgumentList := Expression |\n        //                 Expression ',' ArgumentList\n        function parseArgumentList() {\n            var token, expr, args = [];\n\n            while (true) {\n                expr = parseExpression();\n                if (typeof expr === 'undefined') {\n                    // TODO maybe throw exception?\n                    break;\n                }\n                args.push(expr);\n                token = lexer.peek();\n                if (!matchOp(token, ',')) {\n                    break;\n                }\n                lexer.next();\n            }\n\n            return args;\n        }\n\n        // FunctionCall ::= Identifier '(' ')' ||\n        //                  Identifier '(' ArgumentList ')'\n        function parseFunctionCall(name) {\n            var token, args = [];\n\n            token = lexer.next();\n            if (!matchOp(token, '(')) {\n                throw new SyntaxError('Expecting ( in a function call \"' + name + '\"');\n            }\n\n            token = lexer.peek();\n            if (!matchOp(token, ')')) {\n                args = parseArgumentList();\n            }\n\n            token = lexer.next();\n            if (!matchOp(token, ')')) {\n                throw new SyntaxError('Expecting ) in a function call \"' + name + '\"');\n            }\n\n            return {\n                'FunctionCall': {\n                    'name': name,\n                    'args': args\n                }\n            };\n        }\n\n        // Primary ::= Identifier |\n        //             Number |\n        //             '(' Assignment ')' |\n        //             FunctionCall\n        function parsePrimary() {\n            var token, expr;\n\n            token = lexer.peek();\n\n            if (typeof token === 'undefined') {\n                throw new SyntaxError('Unexpected termination of expression');\n            }\n\n            if (token.unit === T.Identifier) {\n                token = lexer.next();\n                if (matchOp(lexer.peek(), '(')) {\n                    return parseFunctionCall(token.value);\n                } else {\n                    return {\n                        'Identifier': token.value\n                    };\n                }\n            }\n\n            if (token.unit === T.Number) {\n                token = lexer.next();\n                return {\n                    'Number': token.value\n                };\n            }\n\n            if (matchOp(token, '(')) {\n                lexer.next();\n                expr = parseAssignment();\n                token = lexer.next();\n                if (!matchOp(token, ')')) {\n                    throw new SyntaxError('Expecting )');\n                }\n                return {\n                    'Expression': expr\n                };\n            }\n\n            throw new SyntaxError('Parse error, can not process token ' + token.value);\n        }\n\n        // Unary ::= Primary |\n        //           '-' Unary\n        function parseUnary() {\n            var token, expr;\n\n            token = lexer.peek();\n            if (matchOp(token, '-') || matchOp(token, '+')) {\n                token = lexer.next();\n                expr = parseUnary();\n                return {\n                    'Unary': {\n                        operator: token.value,\n                        expression: expr\n                    }\n                };\n            }\n\n            return parsePrimary();\n        }\n\n        // Multiplicative ::= Unary |\n        //                    Multiplicative '*' Unary |\n        //                    Multiplicative '/' Unary\n        function parseMultiplicative() {\n            var expr, token;\n\n            expr = parseUnary();\n            token = lexer.peek();\n            while (matchOp(token, '*') || matchOp(token, '/')) {\n                token = lexer.next();\n                expr = {\n                    'Binary': {\n                        operator: token.value,\n                        left: expr,\n                        right: parseUnary()\n                    }\n                };\n                token = lexer.peek();\n            }\n            return expr;\n        }\n\n        // Additive ::= Multiplicative |\n        //              Additive '+' Multiplicative |\n        //              Additive '-' Multiplicative\n        function parseAdditive() {\n            var expr, token;\n\n            expr = parseMultiplicative();\n            token = lexer.peek();\n            while (matchOp(token, '+') || matchOp(token, '-')) {\n                token = lexer.next();\n                expr = {\n                    'Binary': {\n                        operator: token.value,\n                        left: expr,\n                        right: parseMultiplicative()\n                    }\n                };\n                token = lexer.peek();\n            }\n            return expr;\n        }\n\n        // Assignment ::= Identifier '=' Assignment |\n        //                Additive\n        function parseAssignment() {\n            var token, expr;\n\n            expr = parseAdditive();\n\n            if (typeof expr !== 'undefined' && expr.Identifier) {\n                token = lexer.peek();\n                if (matchOp(token, '=')) {\n                    lexer.next();\n                    return {\n                        'Assignment': {\n                            name: expr,\n                            value: parseAssignment()\n                        }\n                    };\n                }\n                return expr;\n            }\n\n            return expr;\n        }\n\n        // Expression ::= Assignment\n        function parseExpression() {\n            return parseAssignment();\n        }\n\n        function parse(expression) {\n            var expr, token;\n\n            lexer.reset(expression);\n            expr = parseExpression();\n\n            token = lexer.next();\n            if (typeof token !== 'undefined') {\n                throw new SyntaxError('Unexpected token ' + token.value);\n            }\n\n            return {\n                'Expression': expr\n            };\n        }\n\n        return {\n            parse: parse\n        };\n    };\n\n    LengthHelpers.Context = function (unit) {\n        var Constants, Functions;\n\n        Constants = {\n            pi: 3.1415926535897932384,\n            phi: 1.6180339887498948482\n        };\n\n        Functions = {\n            abs: Math.abs,\n            acos: Math.acos,\n            asin: Math.asin,\n            atan: Math.atan,\n            ceil: Math.ceil,\n            cos: Math.cos,\n            exp: Math.exp,\n            floor: Math.floor,\n            ln: Math.ln,\n            random: Math.random,\n            sin: Math.sin,\n            sqrt: Math.sqrt,\n            tan: Math.tan\n        };\n\n        return {\n            Unit: unit,\n            Constants: Constants,\n            Functions: Functions,\n            Variables: {}\n        };\n    };\n\n    LengthHelpers.Evaluator = function (ctx) {\n\n        var parser = new LengthHelpers.Parser(),\n            context = (arguments.length < 1) ? new LengthHelpers.Context(IFLength.Unit.PT) : ctx;\n\n        function exec(node) {\n            var left, right, expr, args, i;\n\n            if (node.hasOwnProperty('Expression')) {\n                return exec(node.Expression);\n            }\n\n            if (node.hasOwnProperty('Number')) {\n                var length = IFLength.parseLength(node.Number, ctx.Unit);\n                if (!length) {\n                    throw new SyntaxError('Invalid length ' + node.Number);\n                }\n                return length.toUnit(ctx.Unit);\n            }\n\n            if (node.hasOwnProperty('Binary')) {\n                node = node.Binary;\n                left = exec(node.left);\n                right = exec(node.right);\n                switch (node.operator) {\n                    case '+':\n                        return left + right;\n                    case '-':\n                        return left - right;\n                    case '*':\n                        return left * right;\n                    case '/':\n                        return left / right;\n                    default:\n                        throw new SyntaxError('Unknown operator ' + node.operator);\n                }\n            }\n\n            if (node.hasOwnProperty('Unary')) {\n                node = node.Unary;\n                expr = exec(node.expression);\n                switch (node.operator) {\n                    case '+':\n                        return expr;\n                    case '-':\n                        return -expr;\n                    default:\n                        throw new SyntaxError('Unknown operator ' + node.operator);\n                }\n            }\n\n            if (node.hasOwnProperty('Identifier')) {\n                if (context.Constants.hasOwnProperty(node.Identifier)) {\n                    return context.Constants[node.Identifier];\n                }\n                if (context.Variables.hasOwnProperty(node.Identifier)) {\n                    return context.Variables[node.Identifier];\n                }\n                throw new SyntaxError('Unknown identifier');\n            }\n\n            if (node.hasOwnProperty('Assignment')) {\n                right = exec(node.Assignment.value);\n                context.Variables[node.Assignment.name.Identifier] = right;\n                return right;\n            }\n\n            if (node.hasOwnProperty('FunctionCall')) {\n                expr = node.FunctionCall;\n                if (context.Functions.hasOwnProperty(expr.name)) {\n                    args = [];\n                    for (i = 0; i < expr.args.length; i += 1) {\n                        args.push(exec(expr.args[i]));\n                    }\n                    return context.Functions[expr.name].apply(null, args);\n                }\n                throw new SyntaxError('Unknown function ' + expr.name);\n            }\n\n            throw new SyntaxError('Unknown syntax node');\n        }\n\n        function evaluate(expr) {\n            var tree = parser.parse(expr);\n            return exec(tree);\n        }\n\n        return {\n            evaluate: evaluate\n        };\n    };\n\n\n    _.IFLength = IFLength;\n})(this);"
  },
  {
    "path": "src/infinity/geometry/point.js",
    "content": "(function (_) {\n\n    /**\n     * A simple point construct. Note that this class is immutable.\n     * @class IFPoint\n     * @param {Number} x the x-position\n     * @param {Number} y the y-position\n     * @constructor\n     * @version 1.0\n     */\n    function IFPoint(x, y) {\n        this._x = x;\n        this._y = y;\n    }\n\n    /**\n     * Compare two points for equality by their x,y values. Also takes care of null parameters\n     * @param {IFPoint} left left side point\n     * @param {IFPoint} right right side point\n     * @return {Boolean} true if left and right are equal (also if they're null!)\n     * @version 1.0\n     */\n    IFPoint.equals = function (left, right) {\n        if (left && left == right) {\n            return true;\n        } else if (left && right) {\n            return ifMath.isEqualEps(left._x, right._x) && ifMath.isEqualEps(left._y, right._y);\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * Returns the minimum point for an unlimited number of point arguments\n     * @return {IFPoint}\n     * @version 1.0\n     */\n    IFPoint.min = function () {\n        var result = new IFPoint(null, null);\n        for (var i = 0; i < arguments.length; ++i) {\n            if (result._x == null || arguments[i]._x < result._x) result._x = arguments[i]._x;\n            if (result._y == null || arguments[i]._y < result._y) result._y = arguments[i]._y;\n        }\n        return result;\n    };\n\n    /**\n     * Returns the maximum point for an unlimited number of point arguments\n     * @return {IFPoint}\n     * @version 1.0\n     */\n    IFPoint.max = function () {\n        var result = new IFPoint(null, null);\n        for (var i = 0; i < arguments.length; ++i) {\n            if (result._x == null || arguments[i]._x > result._x) result._x = arguments[i]._x;\n            if (result._y == null || arguments[i]._y > result._y) result._y = arguments[i]._y;\n        }\n        return result;\n    };\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFPoint.prototype._x = 0;\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFPoint.prototype._y = 0;\n\n    /**\n     * @return {Number} the x-position of this point\n     * @version 1.0\n     */\n    IFPoint.prototype.getX = function () {\n        return this._x;\n    };\n\n    /**\n     * @return {Number} the y-position of this point\n     * @version 1.0\n     */\n    IFPoint.prototype.getY = function () {\n        return this._y;\n    };\n\n    /**\n     * Return a new subtract point\n     * @param {IFPoint} other the other point to subtract from this to get a subtract\n     * @return {IFPoint} a new subtract point which is this - other\n     * @version 1.0\n     */\n    IFPoint.prototype.subtract = function (other) {\n        return new IFPoint(this._x - other._x, this._y - other._y);\n    };\n\n    /**\n     * Return a new addition point\n     * @param {IFPoint} other the other point to add to this to get an addition\n     * @return {IFPoint} a new addition point which is this + other\n     * @version 1.0\n     */\n    IFPoint.prototype.add = function (other) {\n        return new IFPoint(this._x + other._x, this._y + other._y);\n    };\n\n    /**\n     * Return a new translated point\n     * @param {Number} tx horizontal translation offset\n     * @param {Number} ty vertical translation offset\n     * @return {IFPoint} a newly translated point\n     * @version 1.0\n     */\n    IFPoint.prototype.translated = function (tx, ty) {\n        return new IFPoint(this._x + tx, this._y + ty);\n    };\n\n    /**\n     * Return a new rotated point\n     * @param {Number} angle the angle to rotate for\n     * @return {IFPoint} a newly rotated point\n     * @version 1.0\n     */\n    IFPoint.prototype.rotated = function (angle) {\n        var cos_ = Math.cos(angle);\n        var sin_ = Math.sin(angle);\n\n        return new IFPoint(cos_ * this._x - sin_ * this._y, sin_ * this._x + cos_ * this._y);\n    };\n\n    /**\n     * Return a new rotated point rotated around an origin point\n     * @param {Number} angle the angle to rotate for\n     * @param {IFPoint} origin the origin point to rotate around\n     * @return {IFPoint} a newly rotated point\n     * @version 1.0\n     */\n    IFPoint.prototype.rotatedAt = function (angle, origin) {\n        if (!origin) {\n            return this.rotated(angle);\n        }\n\n        var cos_ = Math.cos(angle);\n        var sin_ = Math.sin(angle);\n\n        return new IFPoint((cos_ * (this._x - origin._x) - sin_ * (this._y - origin._y)) + origin._x, (sin_ * (this._x - origin._x) + cos_ * (this._y - origin._y)) + origin._y);\n    };\n\n    /** @override */\n    IFPoint.prototype.toString = function () {\n        return \"[Object IFPoint(x=\" + this._x + \", y=\" + this._y + \"]\";\n    };\n\n    _.IFPoint = IFPoint;\n})(this);"
  },
  {
    "path": "src/infinity/geometry/rect.js",
    "content": "(function (_) {\n\n    /**\n     * A simple rect construct. Note that this class is immutable.\n     * @class IFRect\n     * @param {Number} [x] the left-position of the rect, defaults to 0\n     * @param {Number} [y] the top-position of the rect, defaults to 0\n     * @param {Number} [width] the width of the rect, defaults to 0\n     * @param {Number} [height] the height of the rect, defaults to 0\n     * @constructor\n     * @version 1.0\n     */\n    function IFRect(x, y, width, height) {\n        this._x = x ? x : 0;\n        this._y = y ? y : 0;\n        this._width = width ? width : 0;\n        this._height = height ? height : 0;\n    };\n\n    /**\n     * An enum defining a side of a rect\n     * @enum\n     * @version 1.0\n     */\n    IFRect.Side = {\n        /**\n         * Constant defining the top-left side of a rectangle\n         */\n        TOP_LEFT: 'tl',\n\n        /**\n         * Constant defining the top-center side of a rectangle\n         */\n        TOP_CENTER: 'tc',\n\n        /**\n         * Constant defining the top-right side of a rectangle\n         */\n        TOP_RIGHT: 'tr',\n\n        /**\n         * Constant defining the right-center side of a rectangle\n         */\n        RIGHT_CENTER: 'rc',\n\n        /**\n         * Constant defining the bottom-right side of a rectangle\n         */\n        BOTTOM_RIGHT: 'br',\n\n        /**\n         * Constant defining the bottom-center side of a rectangle\n         */\n        BOTTOM_CENTER: 'bc',\n\n        /**\n         * Constant defining the bottom-left side of a rectangle\n         */\n        BOTTOM_LEFT: 'bl',\n\n        /**\n         * Constant defining the left-center side of a rectangle\n         */\n        LEFT_CENTER: 'lc',\n\n        /**\n         * Constant defining the center side of a rectangle\n         */\n        CENTER: 'cc'\n    };\n\n    /**\n     * A unit rect starting at 0,0 width an unit size of 1\n     * @type {IFRect}\n     */\n    IFRect.UNIT_RECT = new IFRect(0, 0, 1, 1);\n\n    /**\n     * Construct a rectangle from a set of given points. This\n     * @return {IFRect} a new rect enclosing all points\n     * @version 1.0\n     */\n    IFRect.fromPoints = function () {\n        var minPoint = IFPoint.min.apply(null, arguments);\n        var maxPoint = IFPoint.max.apply(null, arguments);\n        return new IFRect(minPoint.getX(), minPoint.getY(), maxPoint.getX() - minPoint.getX(), maxPoint.getY() - minPoint.getY());\n    };\n\n    /**\n     * Compare two rects for equality by their x,y,width,height. Also takes care of null parameters\n     * @param {IFRect} left left side rect\n     * @param {IFRect} right right side rect\n     * @return {Boolean} true if left and right are equal (also if they're null!)\n     * @version 1.0\n     */\n    IFRect.equals = function (left, right) {\n        if (!left && left === right) {\n            return true;\n        } else if (left && right) {\n            return ifMath.isEqualEps(left._x, right._x) && ifMath.isEqualEps(left._y, right._y) && ifMath.isEqualEps(left._width, right._width) && ifMath.isEqualEps(left._height, right._height);\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFRect.prototype._x = 0;\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFRect.prototype._y = 0;\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFRect.prototype._width = 0;\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFRect.prototype._height = 0;\n\n    /**\n     * @return {Number} the x-position of this rectangle\n     * @version 1.0\n     */\n    IFRect.prototype.getX = function () {\n        return this._x;\n    };\n\n    /**\n     * @return {Number} the y-position of this rectangle\n     * @version 1.0\n     */\n    IFRect.prototype.getY = function () {\n        return this._y;\n    };\n\n    /**\n     * @return {Number} the width of this rectangle\n     * @version 1.0\n     */\n    IFRect.prototype.getWidth = function () {\n        return this._width;\n    };\n\n    /**\n     * @return {Number} the height of this rectangle\n     * @version 1.0\n     */\n    IFRect.prototype.getHeight = function () {\n        return this._height;\n    };\n\n    /**\n     * @return {Boolean) whether this rectangle is empty or not\n     * @version 1.0\n     */\n    IFRect.prototype.isEmpty = function () {\n        return (this._width <= 0. && this._height <= 0.);\n    };\n\n    /**\n     * Checks whether this rectangle contains a given point\n     * @param {IFPoint} point the point to test for\n     * @return {Boolean} true if the point is contained by this rect\n     * @version 1.0\n     */\n    IFRect.prototype.containsPoint = function (point) {\n        return this.containsPointXY(point.getX(), point.getY());\n    };\n\n    /**\n     * Checks whether this rectangle contains a given point\n     * @param {Number} px x-coordinate of point\n     * @param {Number} py y-coordinate of point\n     * @return {Boolean} true if the point is contained by this rect\n     * @version 1.0\n     */\n    IFRect.prototype.containsPointXY = function (px, py) {\n        var l = this._x;\n        var r = this._x;\n        if (this._width < 0)\n            l += this._width;\n        else\n            r += this._width;\n        if (l == r)\n            return false;\n\n        if (px < l || px > r)\n            return false;\n\n        var t = this._y;\n        var b = this._y;\n        if (this._height < 0)\n            t += this._height;\n        else\n            b += this._height;\n        if (t == b)\n            return false;\n\n        if (py < t || py > b)\n            return false;\n\n        return true;\n    };\n\n    /**\n     * Checks whether this rectangle contains another rectangle\n     * @param {IFRect} rect the otherRect to test for\n     * @return {Boolean} true if the otherRect is contained by this one\n     * @version 1.0\n     */\n    IFRect.prototype.containsRect = function (rect) {\n        var l1 = this._x;\n        var r1 = this._x;\n        if (this._width < 0)\n            l1 += this._width;\n        else\n            r1 += this._width;\n        if (l1 == r1)\n            return false;\n\n        var l2 = rect._x;\n        var r2 = rect._x;\n        if (rect._width < 0)\n            l2 += rect._width;\n        else\n            r2 += rect._width;\n        if (l2 == r2)\n            return false;\n\n        if (l2 < l1 || r2 > r1)\n            return false;\n\n        var t1 = this._y;\n        var b1 = this._y;\n        if (this._height < 0)\n            t1 += this._height;\n        else\n            b1 += this._height;\n        if (t1 == b1)\n            return false;\n\n        var t2 = rect._y;\n        var b2 = rect._y;\n        if (rect._height < 0)\n            t2 += rect._height;\n        else\n            b2 += rect._height;\n        if (t2 == b2)\n            return false;\n\n        if (t2 < t1 || b2 > b1)\n            return false;\n\n        return true;\n    };\n\n    /**\n     * Tests whether this rect intersects with another one\n     * @param {IFRect} rect the rect to test if it intersects with this one\n     * @return {Boolean} true if both intersect, false if not\n     * @see intersect, intersected\n     * @version 1.0\n     */\n    IFRect.prototype.intersectsRect = function (rect) {\n        return this.intersectsRectXYWH(rect._x, rect._y, rect._width, rect._height);\n    };\n\n    /**\n     * Tests whether this rect intersects with another one\n     * @param {Number} x the x-position of the rect to test against\n     * @param {Number} y the y-position of the rect to test against\n     * @param {Number} w the width of the rect to test against\n     * @param {Number} h the height of the rect to test against\n     * @return {Boolean} true if both intersect, false if not\n     * @see intersect, intersected\n     * @version 1.0\n     */\n    IFRect.prototype.intersectsRectXYWH = function (x, y, w, h) {\n        var l1 = this._x;\n        var r1 = this._x;\n        if (this._width < 0)\n            l1 += this._width;\n        else\n            r1 += this._width;\n        if (l1 == r1)\n            return false;\n\n        var l2 = x;\n        var r2 = x;\n        if (w < 0)\n            l2 += w;\n        else\n            r2 += w;\n        if (l2 == r2)\n            return false;\n\n        if (l1 >= r2 || l2 >= r1)\n            return false;\n\n        var t1 = this._y;\n        var b1 = this._y;\n        if (this._height < 0)\n            t1 += this._height;\n        else\n            b1 += this._height;\n        if (t1 == b1)\n            return false;\n\n        var t2 = y;\n        var b2 = y;\n        if (h < 0)\n            t2 += h;\n        else\n            b2 += h;\n        if (t2 == b2)\n            return false;\n\n        if (t1 >= b2 || t2 >= b1)\n            return false;\n\n        return true;\n    };\n\n    /**\n     * Returns a new copy of this rect with expandings on each side\n     * @param {Number} l expand amount on the left side, negative value means shrink\n     * @param {Number} t expand amount on the top side, negative value means shrink\n     * @param {Number} r expand amount on the right side, negative value means shrink\n     * @param {Number} b expand amount on the bottom side, negative value means shrink\n     */\n    IFRect.prototype.expanded = function (l, t, r, b) {\n        return new IFRect(this._x - l, this._y - t, this._width + l + r, this._height + t + b);\n    };\n\n    /**\n     * Return a new, translated rectangle\n     * @param {Number} tx the horizontal translation offset\n     * @param {Number} ty the vertical translation offset\n     * @return {IFRect} a new, translated rect\n     * @version 1.0\n     */\n    IFRect.prototype.translated = function (tx, ty) {\n        return new IFRect(this._x + tx, this._y + ty, this._width, this._height);\n    };\n\n    /**\n     * Return a new, scaled rectangle\n     * @param {Number} sx the horizontal scaling factor\n     * @param {Number} sy the vertical scaling factor\n     * @return {IFRect} a new, scaled rectangle\n     * @version 1.0\n     */\n    IFRect.prototype.scaled = function (sx, sy) {\n        return new IFRect(this._x * sx, this._y * sy, this._width * sx, this._height * sy);\n    };\n\n    /**\n     * Return a new, scaled rectangle around and origin point\n     * @param {Number} sx the horizontal scaling factor\n     * @param {Number} sy the vertical scaling factor\n     * @param {IFPoint} origin the origin point to scale at\n     * @return {IFRect} a new, scaled rect\n     * @version 1.0\n     */\n    IFRect.prototype.scaledAt = function (sx, sy, origin) {\n        if (!origin) {\n            return this.scaled(sx, sy);\n        } else {\n            return new IFRect(\n                (this._x - origin.getX()) * sx + origin.getX(),\n                (this._y - origin.getY()) * sy + origin.getY(),\n                this._width * sx, this._height * sy);\n        }\n    };\n\n    /**\n     * Return a new rect that unites this and the other rect\n     * @param {IFRect} otherRect the other rect to unite with\n     * @return {IFRect} an united rect\n     * @version 1.0\n     */\n    IFRect.prototype.united = function (otherRect) {\n        var l1 = this._x;\n        var r1 = this._x;\n        if (this._width < 0)\n            l1 += this._width;\n        else\n            r1 += this._width;\n        if (l1 == r1)\n            return otherRect;\n\n        var l2 = otherRect._x;\n        var r2 = otherRect._x;\n        if (otherRect._width < 0)\n            l2 += otherRect._width;\n        else\n            r2 += otherRect._width;\n        if (l2 == r2)\n            return this;\n\n        var t1 = this._y;\n        var b1 = this._y;\n        if (this._height < 0)\n            t1 += this._height;\n        else\n            b1 += this._height;\n        if (t1 == b1)\n            return otherRect;\n\n        var t2 = otherRect._y;\n        var b2 = otherRect._y;\n        if (otherRect._height < 0)\n            t2 += otherRect._height;\n        else\n            b2 += otherRect._height;\n        if (t2 == b2)\n            return this;\n\n        var result = new IFRect();\n        result._x = Math.min(l1, l2);\n        result._y = Math.min(t1, t2);\n        result._width = Math.max(r1, r2) - result._x;\n        result._height = Math.max(b1, b2) - result._y;\n        return result;\n    };\n\n    /**\n     * Return a new rect that intersects this and the other rect\n     * @param {IFRect} otherRect the other rect to intersect with\n     * @return {IFRect} an intersected rect\n     * @version 1.0\n     */\n    IFRect.prototype.intersected = function (otherRect) {\n        var l1 = this._x;\n        var r1 = this._x;\n        if (this._width < 0)\n            l1 += this._width;\n        else\n            r1 += this._width;\n        if (l1 == r1)\n            return new IFRect(0, 0, 0, 0);\n\n        var l2 = otherRect._x;\n        var r2 = otherRect._x;\n        if (otherRect._width < 0)\n            l2 += otherRect._width;\n        else\n            r2 += otherRect._width;\n        if (l2 == r2)\n            return new IFRect(0, 0, 0, 0);\n\n        if (l1 >= r2 || l2 >= r1)\n            return new IFRect(0, 0, 0, 0);\n\n        var t1 = this._y;\n        var b1 = this._y;\n        if (this._height < 0)\n            t1 += this._height;\n        else\n            b1 += this._height;\n        if (t1 == b1)\n            return new IFRect(0, 0, 0, 0);\n\n        var t2 = otherRect._y;\n        var b2 = otherRect._y;\n        if (otherRect._height < 0)\n            t2 += otherRect._height;\n        else\n            b2 += otherRect._height;\n        if (t2 == b2)\n            return new IFRect(0, 0, 0, 0);\n\n        if (t1 >= b2 || t2 >= b1)\n            return new IFRect(0, 0, 0, 0);\n\n        var result = new IFRect();\n        result._x = Math.max(l1, l2);\n        result._y = Math.max(t1, t2);\n        result._width = Math.min(r1, r2) - result._x;\n        result._height = Math.min(b1, b2) - result._y;\n        return result;\n    };\n\n    /**\n     * @return {IFRect} a new from rect this one, aligned to integers\n     * @version 1.0\n     */\n    IFRect.prototype.toAlignedRect = function () {\n        var xmin = Math.floor(this._x);\n        var xmax = Math.ceil(this._x + this._width);\n        var ymin = Math.floor(this._y);\n        var ymax = Math.ceil(this._y + this._height);\n        return new IFRect(xmin, ymin, xmax - xmin, ymax - ymin);\n    };\n\n    /**\n     * Returns a point for a given rectangle side\n     * @param {Number} side  the side of the rectangle to get a point for\n     * @return {IFPoint} the point for the given side\n     * @version 1.0\n     */\n    IFRect.prototype.getSide = function (side) {\n        switch (side) {\n            case IFRect.Side.TOP_LEFT:\n                return new IFPoint(this._x, this._y);\n            case IFRect.Side.TOP_CENTER:\n                return new IFPoint(this._x + this._width / 2.0, this._y);\n            case IFRect.Side.TOP_RIGHT:\n                return new IFPoint(this._x + this._width, this._y);\n            case IFRect.Side.RIGHT_CENTER:\n                return new IFPoint(this._x + this._width, this._y + this._height / 2.0);\n            case IFRect.Side.BOTTOM_RIGHT:\n                return new IFPoint(this._x + this._width, this._y + this._height);\n            case IFRect.Side.BOTTOM_CENTER:\n                return new IFPoint(this._x + this._width / 2.0, this._y + this._height);\n            case IFRect.Side.BOTTOM_LEFT:\n                return new IFPoint(this._x, this._y + this._height);\n            case IFRect.Side.LEFT_CENTER:\n                return new IFPoint(this._x, this._y + this._height / 2.0);\n            case IFRect.Side.CENTER:\n                return new IFPoint(this._x + this._width / 2.0, this._y + this._height / 2.0);\n            default:\n                throw new Error(\"Illegal Argument: \" + side);\n        }\n    };\n\n    /**\n     * Based on the position, returns the rectangle nearest pivot point name\n     * @param {IFPoint} pos\n     * @returns {IFRect.Side}\n     */\n    IFRect.prototype.getClosestSideName = function (pos) {\n        var sides = [IFRect.Side.TOP_LEFT, IFRect.Side.TOP_CENTER, IFRect.Side.TOP_RIGHT,\n            IFRect.Side.LEFT_CENTER, IFRect.Side.CENTER, IFRect.Side.RIGHT_CENTER,\n            IFRect.Side.BOTTOM_LEFT, IFRect.Side.BOTTOM_CENTER, IFRect.Side.BOTTOM_RIGHT];\n\n        var i = 1;\n        var j = 1;\n        if (pos.getX() <= this._x + this._width / 3.0) {\n            i = 0;\n        } else if (pos.getX() >= this._x + this._width * 2 / 3.0) {\n            i = 2;\n        }\n        if (pos.getY() <= this._y + this._height / 3.0) {\n            j = 0;\n        } else if (pos.getY() >= this._y + this._height * 2 / 3.0) {\n            j = 2;\n        }\n        return sides[j * 3 + i];\n    };\n\n    /**\n     * Calculates and returns the rectangle transformation based on the handle delta. Keeps ratio if needed, and\n     * calculates center-resize if option is true.\n     * @param {IFRect.Side} side - moved resize handle\n     * @param {Number} dx - an X component of handle position delta\n     * @param {Number} dy - an Y component of handle position delta\n     * @param {Boolean} ratio - keep the same rectangle proportions (sx == sy)\n     * @param {Boolean} option - calculates center-resize\n     * @return {IFTransform} calculated transformation\n     */\n    IFRect.prototype.getResizeTransform = function (side, dx, dy, ratio, option) {\n        var sx = 1;\n        var sy = 1;\n        var tx = this._x + this._width / 2.0;\n        var ty = this._y + this._height / 2.0;\n\n        // Calculate horizontal factors\n        switch (side) {\n            case IFRect.Side.TOP_LEFT:\n            case IFRect.Side.LEFT_CENTER:\n            case IFRect.Side.BOTTOM_LEFT:\n                sx = (this._width - dx) / this._width;\n                if (option) {\n                    sx += sx - 1;\n                } else {\n                    tx = this._x + this._width;\n                }\n                break;\n            case IFRect.Side.TOP_RIGHT:\n            case IFRect.Side.RIGHT_CENTER:\n            case IFRect.Side.BOTTOM_RIGHT:\n                sx = (this._width + dx) / this._width;\n                if (option) {\n                    sx += sx - 1;\n                } else {\n                    tx = this._x;\n                }\n                break;\n            default:\n                break;\n        }\n\n        // Calculate vertical factors\n        switch (side) {\n            case IFRect.Side.TOP_LEFT:\n            case IFRect.Side.TOP_CENTER:\n            case IFRect.Side.TOP_RIGHT:\n                sy = (this._height - dy) / this._height;\n                if (option) {\n                    sy += sy - 1;\n                } else {\n                    ty = this._y + this._height;\n                }\n                break;\n            case IFRect.Side.BOTTOM_LEFT:\n            case IFRect.Side.BOTTOM_CENTER:\n            case IFRect.Side.BOTTOM_RIGHT:\n                sy = (this._height + dy) / this._height;\n                if (option) {\n                    sy += sy - 1;\n                } else {\n                    ty = this._y;\n                }\n                break;\n            default:\n                break;\n        }\n\n        // Honor shift\n        if (ratio) {\n            switch (side) {\n                case IFRect.Side.TOP_CENTER:\n                case IFRect.Side.BOTTOM_CENTER:\n                    sx = Math.abs(sy);\n                    break;\n                case IFRect.Side.LEFT_CENTER:\n                case IFRect.Side.RIGHT_CENTER:\n                    sy = Math.abs(sx);\n                    break;\n                default:\n                    if (Math.abs(sx) > Math.abs(sy)) {\n                        if (ifMath.isEqualEps(sy, 0)) {\n                            sy = sx;\n                        } else {\n                            sy = sy * Math.abs(sx) / Math.abs(sy);\n                        }\n                    } else {\n                        if (ifMath.isEqualEps(sx, 0)) {\n                            sx = sy;\n                        } else {\n                            sx = sx * Math.abs(sy) / Math.abs(sx);\n                        }\n                    }\n                    break;\n            }\n        }\n\n        return new IFTransform(1, 0, 0, 1, -tx, -ty)\n            .multiplied(new IFTransform(sx, 0, 0, sy, 0, 0))\n            .multiplied(new IFTransform(1, 0, 0, 1, tx, ty));\n    };\n\n    /** @override */\n    IFRect.prototype.toString = function () {\n        return \"[Object IFRect(x=\" + this._x + \", y=\" + this._y + \", width=\" + this._width + \", height=\" + this._height + \")]\";\n    };\n\n    _.IFRect = IFRect;\n})(this);"
  },
  {
    "path": "src/infinity/geometry/transform.js",
    "content": "(function (_) {\n\n    /**\n     * A 2d affine transform, if no parameters are given then\n     * this constructos an identity matrix. Note that this class is immutable.\n     * @class IFTransform\n     * @constructor\n     * @version 1.0\n     */\n    function IFTransform(sx, shy, shx, sy, tx, ty) {\n        this._sx = typeof sx === 'number' ? sx : 1.0;\n        this._shy = typeof shy === 'number' ? shy : 0.0;\n        this._shx = typeof shx === 'number' ? shx : 0.0;\n        this._sy = typeof sy === 'number' ? sy : 1.0;\n        this._tx = typeof tx === 'number' ? tx : 0.0;\n        this._ty = typeof ty === 'number' ? ty : 0.0;\n    }\n\n    /**\n     * Serializes a transformation into it's most simple form\n     * @returns {Array} serialized array or empty array for identity\n     */\n    IFTransform.serialize = function (transform) {\n        if (!transform.isIdentity()) {\n            return transform.getMatrix();\n        } else {\n            return [];\n        }\n    };\n\n    /**\n     * Deserializes a transformation from an array\n     * @param {Array} serialized array to deserialize from\n     * @return {IFTransform}\n     */\n    IFTransform.deserialize = function (array) {\n        if (array && array.length >= 6) {\n            return new IFTransform(array[0], array[1], array[2], array[3], array[4], array[5]);\n        } else {\n            return new IFTransform();\n        }\n    };\n\n    /**\n     * Compare two transforms for equality by their matrix. Also takes care of null parameters\n     * @param {IFTransform} left left side transform\n     * @param {IFTransform} right right side transform\n     * @return {Boolean} true if left and right are equal (also if they're null!)\n     * @version 1.0\n     */\n    IFTransform.equals = function (left, right) {\n        if (left && left == right) {\n            return true;\n        } else if (left && right) {\n            return ifMath.isEqualEps(left._sx, right._sx) && ifMath.isEqualEps(left._shy, right._shy) &&\n                ifMath.isEqualEps(left._shx, right._shx) && ifMath.isEqualEps(left._sy, right._sy) &&\n                ifMath.isEqualEps(left._tx, right._tx) && ifMath.isEqualEps(left._ty, right._ty);\n        } else {\n            return false;\n        }\n    };\n\n    /**\n     * Horizontal scale\n     * @type Number\n     * @version 1.0\n     */\n    IFTransform.prototype._sx;\n\n    /**\n     * Vertical shear\n     * @type Number\n     * @version 1.0\n     */\n    IFTransform.prototype._shy;\n\n    /**\n     * Horizontal shear\n     * @type Number\n     * @version 1.0\n     */\n    IFTransform.prototype._shx;\n\n    /**\n     * Vertical scale\n     * @type Number\n     * @version 1.0\n     */\n    IFTransform.prototype._sy;\n\n    /**\n     * Horiontal offset\n     * @type Number\n     * @version 1.0\n     */\n    IFTransform.prototype._tx;\n\n    /**\n     * Vertical offset\n     * @type Number\n     * @version 1.0\n     */\n    IFTransform.prototype._ty;\n\n    /**\n     * @return {Boolean} whether this transform reprsents an identity matrix or not\n     * @version 1.0\n     */\n    IFTransform.prototype.isIdentity = function () {\n        return ifMath.isEqualEps(this._sx, 1.0) && ifMath.isEqualEps(this._shy, 0.0) &&\n            ifMath.isEqualEps(this._shx, 0.0) && ifMath.isEqualEps(this._sy, 1.0) &&\n            ifMath.isEqualEps(this._tx, 0.0) && ifMath.isEqualEps(this._ty, 0.0);\n    };\n\n    /**\n     * @return {Boolean} whether this is a valid transform or not\n     * @version 1.0\n     */\n    IFTransform.prototype.isValid = function () {\n        return Math.abs(this._sx) > ifMath.defaultEps && Math.abs(this._sy) > ifMath.defaultEps;\n    };\n\n    /**\n     * Returns the underlying matrix [sx, shy, shx, sy, tx, ty]\n     * @returns {Array}\n     */\n    IFTransform.prototype.getMatrix = function () {\n        return [this._sx, this._shy, this._shx, this._sy, this._tx, this._ty];\n    };\n\n    /**\n     * Returns the determinant of the matrix\n     * @returns {Number}\n     */\n    IFTransform.prototype.getDeterminant = function () {\n        return this._sx * this._sy - this._shy * this._shx;\n    };\n\n    /**\n     * Returns the reciprocal of the determinant of the matrix\n     * @returns {Number}\n     */\n    IFTransform.prototype.getDeterminantReciprocal = function () {\n        return 1.0 / (this._sx * this._sy - this._shy * this._shx);\n    };\n\n    /**\n     * Returns the translation this transformation\n     * @return {IFPoint}\n     */\n    IFTransform.prototype.getTranslation = function () {\n        return new IFPoint(this._tx, this._ty);\n    };\n\n    /**\n     * Returns the scale factor of this transformation\n     * @return {Number}\n     */\n    IFTransform.prototype.getScaleFactor = function () {\n        var x = 0.707106781 * this._sx + 0.707106781 * this._shx;\n        var y = 0.707106781 * this._shy + 0.707106781 * this._sy;\n        return Math.sqrt(x * x + y * y);\n    };\n\n    /**\n     * Returns the rotation factor of this transformation in radians\n     * @return {Number}\n     */\n    IFTransform.prototype.getRotationFactor = function () {\n        return Math.atan2(this._shx, this._sx);\n    };\n\n    /**\n     * Returns a new, multiplied transformation\n     * @param {IFTransform} other\n     * @return {IFTransform}\n     */\n    IFTransform.prototype.multiplied = function (other) {\n        var sx = this._sx, shy = this._shy, shx = this._shx,\n            sy = this._sy, tx = this._tx, ty = this._ty;\n\n        var t0 = sx * other._sx + shy * other._shx;\n        var t2 = shx * other._sx + sy * other._shx;\n        var t4 = tx * other._sx + ty * other._shx + other._tx;\n        shy = sx * other._shy + shy * other._sy;\n        sy = shx * other._shy + sy * other._sy;\n        ty = tx * other._shy + ty * other._sy + other._ty;\n        sx = t0;\n        shx = t2;\n        tx = t4;\n        return new IFTransform(sx, shy, shx, sy, tx, ty);\n    };\n\n    /**\n     * Returns a new, pre-multiplied transformation\n     * @param {IFTransform} other\n     * @return {IFTransform}\n     */\n    IFTransform.prototype.preMultiplied = function (other) {\n        var sx = other._sx * this._sx + other._shy * this._shx;\n        var shy = other._sx * this._shy + other._shy * this._sy;\n        var sy = other._shx * this._shy + other._sy * this._sy;\n        var shx = other._shx * this._sx + other._sy * this._shx;\n        var tx = other._tx * this._sx + other._ty * this._shx + this._tx;\n        var ty = other._tx * this._shy + other._ty * this._sy + this._ty;\n        return new IFTransform(sx, shy, shx, sy, tx, ty);\n    };\n\n    /**\n     * Returns a new, inverted transformation\n     * @return {IFTransform}\n     */\n    IFTransform.prototype.inverted = function () {\n        var sx = this._sx, sy = this._sy,\n            shx = this._shx, shy = this._shy,\n            tx = this._tx, ty = this._ty;\n\n        var d = 1.0 / (sx * sy - shy * shx);\n\n        var t0 = sy * d;\n        sy = sx * d;\n        shy = -shy * d;\n        shx = -shx * d;\n\n        var t4 = -tx * t0 - ty * shx;\n        ty = -tx * shy - ty * sy;\n\n        sx = t0;\n        tx = t4;\n\n        return new IFTransform(sx, shy, shx, sy, tx, ty);\n    };\n\n    /**\n     * Returns a new, rotated transformation\n     * @param {Number} angle in radians\n     * @return {IFTransform}\n     */\n    IFTransform.prototype.rotated = function (angle) {\n        return this.multiplied(new IFTransform(Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0.0, 0.0));\n    };\n\n    /**\n     * Add translation to this transform and return the result\n     * @return {IFTransform} this transform with translation applied\n     * @version 1.0\n     */\n    IFTransform.prototype.translated = function (tx, ty) {\n        return this.multiplied(new IFTransform(1.0, 0.0, 0.0, 1.0, tx, ty));\n    };\n\n    /**\n     * Returns a new, scaled transformation\n     * @param {Number} sx\n     * @param {Number} sy\n     * @return {IFTransform}\n     */\n    IFTransform.prototype.scaled = function (sx, sy) {\n        if (!sy) sy = sx;\n        return this.multiplied(new IFTransform(sx, 0.0, 0.0, sy, 0.0, 0.0));\n    };\n\n    /**\n     * Returns a new, skewed transformation\n     * @param {Number} sx\n     * @param {Number} sy\n     * @return {IFTransform}\n     */\n    IFTransform.prototype.skewed = function (sx, sy) {\n        return this.multiplied(new IFTransform(1.0, Math.tan(sy), Math.tan(sx), 1.0, 0.0, 0.0));\n    };\n\n    /**\n     * Map a vertex with x/y-coordinates to this transformation\n     * @param {Object} vertex the vertex to map and modify. Note that is is\n     * expected that the vertex has two properties called \"x\" and \"y\"!\n     * @version 1.0\n     */\n    IFTransform.prototype.map = function (vertex) {\n        if (!this.isIdentity()) {\n            var x = vertex.x;\n            vertex.x = x * this._sx + vertex.y * this._shx + this._tx;\n            vertex.y = x * this._shy + vertex.y * this._sy + this._ty;\n        }\n    };\n\n    /**\n     * Map a point into this transformation\n     * @param {IFPoint} point the point to map\n     * @return {IFPoint} a new point mapped into this transformation\n     * @version 1.0\n     */\n    IFTransform.prototype.mapPoint = function (point) {\n        // If identity nothing to transform so return\n        if (this.isIdentity()) {\n            return point;\n        }\n\n        var px = point.getX();\n        var py = point.getY();\n\n        var x = px * this._sx + py * this._shx + this._tx;\n        var y = px * this._shy + py * this._sy + this._ty;\n        return new IFPoint(x, y);\n    };\n\n    /**\n     * Map a rectangle into this transformation\n     * @param {IFRect} rect the rectangle to map\n     * @return {IFRect} a new rect mapped into this transformation\n     * @version 1.0\n     */\n    IFTransform.prototype.mapRect = function (rect) {\n        // If identity nothing to transform so return\n        if (this.isIdentity() || rect == null) {\n            return rect;\n        }\n\n        var p1 = rect.getSide(IFRect.Side.TOP_LEFT);\n        var p2 = rect.getSide(IFRect.Side.TOP_RIGHT);\n        var p3 = rect.getSide(IFRect.Side.BOTTOM_RIGHT);\n        var p4 = rect.getSide(IFRect.Side.BOTTOM_LEFT);\n\n        return IFRect.fromPoints(this.mapPoint(p1), this.mapPoint(p2), this.mapPoint(p3), this.mapPoint(p4));\n    };\n\n    /** @override */\n    IFTransform.prototype.toString = function () {\n        return \"[Object IFTransform(sx=\" + this._sx.toString() + \", shy=\" + this._shy.toString() +\n            \", shx=\" + this._shx.toString() + \", sx=\" + this._sx.toString() + \", tx=\" + this._tx.toString() + \", ty=\" + this._ty.toString() + \")]\";\n    };\n\n    _.IFTransform = IFTransform;\n})(this);"
  },
  {
    "path": "src/infinity/i18n/i18n_de.js",
    "content": ""
  },
  {
    "path": "src/infinity/i18n/i18n_en.js",
    "content": "// Core\nifLocale.setValues(IFLocale, IFLocale.Language.English, [\"create\", \"add\", \"edit\", \"remove\", \"delete\", \"open\", \"save\", \"cancel\", \"ok\", \"close\", \"loading\", \"loading_of\", \"saving\", \"saving_of\", \"success\", \"failure\", \"waiting\"],\n    [\"Create\", \"Add\", \"Edit\", \"Remove\", \"Delete\", \"Open\", \"Save\", \"Cancel\", \"OK\", \"Close\", \"Loading\", \"Loading of\", \"Saving\", \"Saving of\", \"Success\", \"Failure\", \"Waiting\"]);\n\n// Keys - TODO : Merge into one call\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.1\"], [\"Space\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.2\"], [\"Enter\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.3\"], [\"Tab\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.4\"], [\"Backspace\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.5\", \"key.5.short\"], [\"Control\", \"Ctrl\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.6\"], [\"Shift\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.7\"], [\"Alt\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.8\"], [\"Left\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.9\"], [\"Up\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.10\"], [\"Right\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.11\"], [\"Down\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.12\"], [\"Page Up\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.13\"], [\"Page Down\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.14\"], [\"Home\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.15\"], [\"End\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.16\", \"key.16.short\"], [\"Insert\", \"Ins\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.17\", \"key.17.short\"], [\"Delete\", \"Del\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.18\", \"key.18.short\"], [\"Escape\", \"Esc\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.19\", \"key.19.short\"], [\"Command\", \"Cmd\"]);\nifLocale.setValues(IFKey, IFLocale.Language.English, [\"key.30\", \"key.31\", \"key.32\", \"key.33\", \"key.34\", \"key.35\", \"key.36\", \"key.37\", \"key.38\", \"key.39\", \"key.40\", \"key.41\"], [\"F1\", \"F2\", \"F3\", \"F4\", \"F5\", \"F6\", \"F7\", \"F8\", \"F9\", \"F10\", \"F11\", \"F12\"]);\n\n// Paint\nifLocale.setValues(IFFont, IFLocale.Language.English, [\"weight.thin\", \"weight.extra-light\", \"weight.light\", \"weight.regular\", \"weight.medium\", \"weight.semi-bold\", \"weight.bold\", \"weight.extra-bold\", \"weight.heavy\", \"category.other\", \"category.serif\", \"category.monospace\", \"category.iconic\"], [\"Thin\", \"Extra-Light\", \"Light\", \"Regular\", \"Medium\", \"Semi-Bold\", \"Bold\", \"Extra-Bold\", \"Heavy\", \"Other\", \"Serif\", \"Monospace\", \"Iconic\"]);\n\n// Scene\nifLocale.setValues(IFEllipse, IFLocale.Language.English, [\"name\"], [\"Ellipse\"]);\nifLocale.setValues(IFRectangle, IFLocale.Language.English, [\"name\"], [\"Rectangle\"]);\nifLocale.setValues(IFLayer, IFLocale.Language.English, [\"name\", \"type.output\", \"type.draft\", \"type.guide\"], [\"Layer\", \"Output\", \"Draft\", \"Guide\"]);\nifLocale.setValues(IFShapeSet, IFLocale.Language.English, [\"name\"], [\"Group\"]);\nifLocale.setValues(IFScene, IFLocale.Language.English, [\"name\"], [\"Scene\"]);\nifLocale.setValues(IFPolygon, IFLocale.Language.English, [\"name\"], [\"Polygon\"]);\nifLocale.setValues(IFPage, IFLocale.Language.English, [\"name\"], [\"Page\"]);\nifLocale.setValues(IFPath, IFLocale.Language.English, [\"name\"], [\"Path\"]);\nifLocale.setValues(IFText, IFLocale.Language.English, [\"name\"], [\"Text\"]);\nifLocale.setValues(IFScenePaintConfiguration, IFLocale.Language.English, [\"paint.full\", \"paint.fast\", \"paint.outline\", \"paint.output\"], [\"Full\", \"Fast\", \"Outline\", \"Output\"]);\nifLocale.setValues(IFSlice, IFLocale.Language.English, [\"name\"], [\"Slice\"]);"
  },
  {
    "path": "src/infinity/paint/annotation.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFAnnotation\n     * @constructor\n     * @version 1.0\n     */\n    function IFAnnotation() {\n    };\n\n    /**\n     * Type of an annotation\n     * @enum\n     */\n    IFAnnotation.prototype.AnnotType = {\n        Rectangle: 0,\n        Circle: 1,\n        Diamond: 2\n    };\n\n    var _annotationTemplates = {};\n\n    /**\n     * Paint an annotation\n     * @param {IFPaintContext} context the paint context to paint on\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPoint} center the center point of the annotation\n     * @param {IFAnnotation.AnnotType} annotation the annotation to be painted\n     * @param {Boolean} [selected] whether the annotation should be painted\n     * selected or not. Defaults to false.\n     * @param {Number} [size] annotation size\n     * @param {IFColor} [stroke] annotation stroke color, if not provided uses defaults\n     * @param {IFColor} [fill] annotation fill color, if not provided uses defaults\n     */\n    IFAnnotation.prototype.paintAnnotation = function (context, transform, center, annotation, selected, size, stroke, fill) {\n        var annotationTemplate = this._getAnnotationTemplate(annotation);\n\n        // Now paint our annotation\n        if (transform) {\n            center = transform.mapPoint(center);\n        }\n\n        var fillColor = fill ? fill : context.selectionOutlineColor;\n        var strokeColor = stroke ? stroke : null;\n        if (selected) {\n            strokeColor = fillColor;\n            fillColor = IFColor.WHITE;\n        }\n\n        var cx = Math.floor(center.getX()) + (strokeColor ? 0.5 : 0);\n        var cy = Math.floor(center.getY()) + (strokeColor ? 0.5 : 0);\n        var sx = size / 2 / annotationTemplate.scaleFactor;\n        var sy = size / 2 / annotationTemplate.scaleFactor;\n        var canvas = context.canvas;\n\n        var vertices = new IFVertexTransformer(annotationTemplate.vertices, new IFTransform(sx, 0, 0, sy, cx, cy));\n        canvas.putVertices(vertices);\n        canvas.fillVertices(fillColor);\n        // TODO : Transform and fill with stroke first, then fill to avoid expensive stroke operations for annotations at all\n        if (strokeColor) {\n            canvas.strokeVertices(strokeColor, 1);\n        }\n    };\n\n\n    /**\n     * Get bbox of an annotation\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPoint} center the center point of the annotation\n     * @param {Number} [size] the size of an anotation\n     */\n    IFAnnotation.prototype.getAnnotationBBox = function (transform, center, size) {\n        if (transform) {\n            center = transform.mapPoint(center);\n        }\n\n        var cx = Math.floor(center.getX()) + 0.5;\n        var cy = Math.floor(center.getY()) + 0.5;\n\n        return new IFRect(cx - size / 2 - 1, cy - size / 2 - 1, size + 2, size + 2);\n    };\n\n    IFAnnotation.prototype._getAnnotationTemplate = function (annotation) {\n        // Prepare vertex cache, first\n        var annotationTemplate = _annotationTemplates[annotation];\n        if (!annotationTemplate) {\n            var vertices = new IFVertexContainer();\n            var scaleFactor = 1;\n\n            switch (annotation) {\n                case this.AnnotType.Rectangle:\n                    vertices.addVertex(IFVertex.Command.Move, -1, -1);\n                    vertices.addVertex(IFVertex.Command.Line, 1, -1);\n                    vertices.addVertex(IFVertex.Command.Line, 1, 1);\n                    vertices.addVertex(IFVertex.Command.Line, -1, 1);\n                    vertices.addVertex(IFVertex.Command.Close);\n                    break;\n\n                case this.AnnotType.Circle:\n                    vertices.addVertex(IFVertex.Command.Move, -1, 0);\n                    vertices.addVertex(IFVertex.Command.Curve, 0, -1);\n                    vertices.addVertex(IFVertex.Command.Curve, -1, -1);\n                    vertices.addVertex(IFVertex.Command.Curve, 1, 0);\n                    vertices.addVertex(IFVertex.Command.Curve, 1, -1);\n                    vertices.addVertex(IFVertex.Command.Curve, 0, 1);\n                    vertices.addVertex(IFVertex.Command.Curve, 1, 1);\n                    vertices.addVertex(IFVertex.Command.Curve, -1, 0);\n                    vertices.addVertex(IFVertex.Command.Curve, -1, 1);\n                    break;\n\n                case this.AnnotType.Diamond:\n                    vertices.addVertex(IFVertex.Command.Move, -1, 0);\n                    vertices.addVertex(IFVertex.Command.Line, 0, -1);\n                    vertices.addVertex(IFVertex.Command.Line, 1, 0);\n                    vertices.addVertex(IFVertex.Command.Line, 0, 1);\n                    vertices.addVertex(IFVertex.Command.Close);\n                    scaleFactor = Math.cos(Math.PI / 4);\n                    break;\n            }\n\n            annotationTemplate = {\n                vertices: vertices,\n                scaleFactor: scaleFactor\n            }\n            _annotationTemplates[annotation] = annotationTemplate;\n        }\n        return annotationTemplate;\n    };\n\n    _.ifAnnotation = new IFAnnotation();\n})(this);"
  },
  {
    "path": "src/infinity/paint/bitmap.js",
    "content": "(function (_) {\n    /**\n     * A class representing a bitmap\n     * @param {Number|Image|HTMLImageElement|IFPaintCanvas|HtmlCanvasElement|CanvasRenderingContext2D} sourceOrWidth\n     * @param {Number} height\n     * @class IFBitmap\n     * @constructor\n     */\n    function IFBitmap(sourceOrWidth, height) {\n        var bitmapWidth = 0;\n        var bitmapHeight = 0;\n        var canvas = null;\n        var content = null;\n\n        if (typeof sourceOrWidth === 'number') {\n            bitmapWidth = sourceOrWidth;\n            bitmapHeight = height;\n        } else if (sourceOrWidth instanceof Image || sourceOrWidth instanceof HTMLImageElement) {\n            bitmapWidth = sourceOrWidth.naturalWidth;\n            bitmapHeight = sourceOrWidth.naturalHeight;\n            content = sourceOrWidth;\n        } else if (sourceOrWidth instanceof IFPaintCanvas) {\n            canvas = sourceOrWidth._canvasContext.canvas;\n        } else if (sourceOrWidth instanceof HTMLCanvasElement) {\n            canvas = sourceOrWidth;\n        } else if (sourceOrWidth instanceof CanvasRenderingContext2D) {\n            canvas = sourceOrWidth.canvas;\n        }\n\n        if (!canvas) {\n            if (bitmapWidth <= 0 || bitmapHeight <= 0) {\n                throw new Error('Invalid bitmap size');\n            }\n\n            this._canvas = document.createElement('canvas');\n            this._canvas.width = bitmapWidth;\n            this._canvas.height = bitmapHeight;\n        } else {\n            this._canvas = canvas;\n        }\n\n        this._canvasContext = this._canvas.getContext('2d');\n\n        if (content) {\n            this._canvasContext.drawImage(content);\n        }\n    };\n\n    IFBitmap.COLOR_MATRIX_IDENTITY = [\n        1, 0, 0, 0, 0,\n        0, 1, 0, 0, 0,\n        0, 0, 1, 0, 0,\n        0, 0, 0, 1, 0\n    ];\n\n    IFBitmap.COLOR_MATRIX_INVERT = [\n        -1, 0, 0, 0, 255,\n        0, -1, 0, 0, 255,\n        0, 0, -1, 0, 255,\n        0, 0, 0, 1, 0\n    ];\n\n    IFBitmap.COLOR_MATRIX_GRAYSCALE = [\n        0.33, 0.33, 0.33, 0, 0,\n        0.33, 0.33, 0.33, 0, 0,\n        0.33, 0.33, 0.33, 0, 0,\n        0, 0, 0, 1, 0\n    ];\n\n    /**\n     * @enum\n     */\n    IFBitmap.ImageType = {\n        // args: none\n        PNG: 'image/png',\n\n        // args: quality 0..1.0\n        JPEG: 'image/jpeg'\n    };\n\n    /**\n     * The underlying canvas\n     * @type {HtmlCanvasElement}\n     * @private\n     */\n    IFBitmap.prototype._canvas = null;\n\n    /**\n     * The underlying, 2d canvas context\n     * @type {CanvasRenderingContext2D}\n     */\n    IFBitmap.prototype._canvasContext = null;\n\n    /**\n     * Returns the width of this bitmap\n     * @return {Number}\n     */\n    IFBitmap.prototype.getWidth = function () {\n        return this._canvas.width;\n    };\n\n    /**\n     * Returns the height of this bitmap\n     * @return {Number}\n     */\n    IFBitmap.prototype.getHeight = function () {\n        return this._canvas.height;\n    };\n\n    /**\n     * Converts and returns the underlying bitmap into an image\n     * returned as a base64 encoded data-url\n     * @param {IFBitmap.ImageType} imageType the image type you want\n     * @param {*} args optional arguments, see image-type\n     * @return {String}\n     */\n    IFBitmap.prototype.toImageDataUrl = function (imageType, args) {\n        var params = [imageType];\n\n        if (args) {\n            params = params.concat(args);\n        }\n\n        return this._canvas.toDataURL.apply(this._canvas, params);\n    };\n\n    /**\n     * Converts and returns the underlying bitmap into an image\n     * returned as an ArrayBuffer\n     * @param {IFBitmap.ImageType} imageType the image type you want\n     * @param {Function} available the callback function called with\n     * the ArrayBuffer as parameter when available\n     * @param {*} args optional arguments, see image-type\n     */\n    IFBitmap.prototype.toImageBuffer = function (imageType, available, args) {\n        var params = [\n            function (blob) {\n                var reader = new FileReader();\n                reader.onload = function (event) {\n                    available(event.target.result);\n                };\n                reader.readAsArrayBuffer(blob);\n            },\n            imageType\n        ];\n\n        if (args) {\n            params = params.concat(args);\n        }\n\n        this._canvas.toBlob.apply(this._canvas, params);\n    };\n\n    /**\n     * Returns an exact copy of this bitmap that can be manipulated\n     * independantly from the source bitmap\n     * @param {IFRect} [area] optional area defining the cloned bitmap data,\n     * if not provided or null, takes the whole bitmap by default\n     * @return {IFBitmap}\n     */\n    IFBitmap.prototype.clone = function (area) {\n        area = area || new IFRect(0, 0, this.getWidth(), this.getHeight());\n\n        if (area.isEmpty()) {\n            return null;\n        }\n\n        var clone = new IFBitmap(area.getWidth(), area.getHeight());\n        var imageData = this._canvasContext.getImageData(area.getX(), area.getY(), area.getWidth(), area.getHeight());\n        clone._canvasContext.putImageData(imageData, 0, 0);\n\n        return clone;\n    };\n\n    /**\n     * Resize the bitmap making it smaller or larger as will without\n     * touching the original bitmap pixels\n     * @param {Number} width the new width, set to null or zero to leave\n     * the width untouched\n     * @param {Number} height the new height, set to null or zero to leave\n     * the width untouched\n     * @param {IFRect.Side} [pivot] the pivot to resize from. Defaults to top-left\n     * and thus expands in right-bottom direction.\n     */\n    IFBitmap.prototype.resize = function (width, height, pivot) {\n        width = width || 0;\n        height = height || 0;\n        pivot = pivot || IFRect.Side.TOP_LEFT;\n\n        if (width || height) {\n            var dw = width - this.getWidth();\n            var dh = height - this.getHeight();\n\n            var left = 0;\n            var top = 0;\n            var right = 0;\n            var bottom = 0;\n\n            if (dw !== this.getWidth()) {\n                switch (pivot) {\n                    case IFRect.Side.TOP_LEFT:\n                    case IFRect.Side.LEFT_CENTER:\n                    case IFRect.Side.BOTTOM_LEFT:\n                        right = dw;\n                        break;\n                    case IFRect.Side.TOP_CENTER:\n                    case IFRect.Side.CENTER:\n                    case IFRect.Side.BOTTOM_CENTER:\n                        left = -dw / 2;\n                        right = dw / 2;\n                        break;\n                    case IFRect.Side.TOP_RIGHT:\n                    case IFRect.Side.RIGHT_CENTER:\n                    case IFRect.Side.BOTTOM_RIGHT:\n                        left = -dw;\n                        break;\n                }\n            }\n\n            if (dh !== this.getHeight()) {\n                switch (pivot) {\n                    case IFRect.Side.TOP_LEFT:\n                    case IFRect.Side.TOP_CENTER:\n                    case IFRect.Side.TOP_RIGHT:\n                        bottom = dh;\n                        break;\n\n                    case IFRect.Side.LEFT_CENTER:\n                    case IFRect.Side.CENTER:\n                    case IFRect.Side.RIGHT_CENTER:\n                        top = -dh / 2;\n                        bottom = dh / 2;\n                        break;\n\n                    case IFRect.Side.BOTTOM_LEFT:\n                    case IFRect.Side.BOTTOM_CENTER:\n                    case IFRect.Side.BOTTOM_RIGHT:\n                        top = -dh;\n                        break;\n                }\n            }\n\n            var imageData = this._canvasContext.getImageData(0, 0, this.getWidth(), this.getHeight());\n            this._canvas.width = this.getWidth() - left + right;\n            this._canvas.height = this.getHeight() - top + bottom;\n            this._canvasContext.clearRect(0, 0, this.getWidth(), this.getHeight());\n            this._canvasContext.putImageData(imageData, -left, -top);\n        }\n    };\n\n    /**\n     * Crops this bitmap's sides\n     * @param {Number} left delta from left-side\n     * @param {Number} top delta from top-side\n     * @param {Number} right delta from right-side\n     * @param {Number} bottom delta from bottom-side\n     */\n    IFBitmap.prototype.crop = function (left, top, right, bottom) {\n        left = left || 0;\n        top = top || 0;\n        right = right || 0;\n        bottom = bottom || 0;\n\n        var newWidth = this.getWidth() - right;\n        var newHeight = this.getHeight() - bottom;\n        var imageData = this._canvasContext.getImageData(left, top, newWidth, newHeight);\n        this._canvas.width = newWidth;\n        this._canvas.height = newHeight;\n        this._canvasContext.clearRect(0, 0, newWidth, newHeight);\n        this._canvasContext.putImageData(imageData, 0, 0);\n    };\n\n    /**\n     * Trims this bitmap by removing all surrounding transparent pixels\n     */\n    IFBitmap.prototype.trim = function () {\n        var imageData = this._canvasContext.getImageData(0, 0, this.getWidth(), this.getHeight());\n        var dataLength = imageData.data.length;\n        var bounds = {top: null, left: null, right: null, bottom: null};\n        var width = this.getWidth();\n        var height = this.getHeight();\n        var x, y = null;\n\n        for (var i = 0; i < dataLength; i += 4) {\n            if (imageData.data[i + 3] !== 0) {\n                x = (i / 4) % width;\n                y = ~~((i / 4) / width);\n\n                if (bounds.top === null) {\n                    bounds.top = y;\n                }\n\n                if (bounds.left === null) {\n                    bounds.left = x;\n                } else if (x < bounds.left) {\n                    bounds.left = x;\n                }\n\n                if (bounds.right === null) {\n                    bounds.right = x;\n                } else if (bounds.right < x) {\n                    bounds.right = x;\n                }\n\n                if (bounds.bottom === null) {\n                    bounds.bottom = y;\n                } else if (bounds.bottom < y) {\n                    bounds.bottom = y;\n                }\n            }\n        }\n\n        this.crop(bounds.left, bounds.top, width - (bounds.right - bounds.left), height - (bounds.bottom - bounds.top));\n    };\n\n    /**\n     * This is called to modify the underlying bitmap data\n     * @param {Function} modifier the modifier function retrieving the bitmap data (32BPP RGBA), the width and the height\n     * @param {IFRect} [area] optional area defining the bitmap data to be manipulated,\n     * if not provided or null, takes the whole bitmap by default\n     */\n    IFBitmap.prototype.modifyPixels = function (modifier, area) {\n        area = area || new IFRect(0, 0, this.getWidth(), this.getHeight());\n\n        if (area.isEmpty()) {\n            return;\n        }\n\n        // get pixels\n        var imageData = this._canvasContext.getImageData(area.getX(), area.getY(), area.getWidth(), area.getHeight());\n\n        // run modifier\n        modifier(imageData.data, area.getWidth(), area.getHeight());\n\n        // push pixels back\n        this._canvasContext.putImageData(imageData, area.getX(), area.getY());\n    };\n\n    /**\n     * Apply a color transformation on this bitmap\n     * @param {Array<Number>} multiplier the rgba multipliers\n     * @param {Array<Number>} offsets the rgba offsets\n     * @param {IFRect} [extents] optional extents, if not provided or null,\n     * takes the whole bitmap by default\n     */\n    IFBitmap.prototype.colorTransform = function (multiplier, offsets, extents) {\n        this.modifyPixels(function (pixels, width, height) {\n            for (var y = 0; y < height; ++y) {\n                for (var x = 0; x < width; ++x) {\n                    var index = (y * width + x) * 4;\n                    pixels[index] = pixels[index] * multiplier[0] + offsets[0];\n                    pixels[index + 1] = pixels[index + 1] * multiplier[1] + offsets[1];\n                    pixels[index + 2] = pixels[index + 2] * multiplier[2] + offsets[2];\n                    pixels[index + 3] = pixels[index + 3] * multiplier[3] + offsets[3];\n                }\n            }\n        }, extents);\n    };\n\n    /**\n     * Apply a color matrix on this bitmap whereas the\n     * color-identity-matrix looks like this:\n     *\n     * |---|-R-|-G-|-B-|-A-|-Offset-|\n     * |-R-| 1 | 0 | 0 | 0 |    0   |\n     * |-G-| 0 | 1 | 0 | 0 |    0   |\n     * |-B-| 0 | 0 | 1 | 0 |    0   |\n     * |-A-| 0 | 0 | 0 | 1 |    0   |\n     *\n     * @param {Array<Number>} matrix the color matrix to be applied (4x5)\n     * @param {IFRect} [extents] optional extents, if not provided or null,\n     * takes the whole bitmap by default\n     */\n    IFBitmap.prototype.colorMatrix = function (matrix, extents) {\n        this.modifyPixels(function (pixels, width, height) {\n            for (var y = 0; y < height; ++y) {\n                for (var x = 0; x < width; ++x) {\n                    var index = (y * width + x) * 4;\n\n                    var oR = pixels[index];\n                    var oG = pixels[index + 1];\n                    var oB = pixels[index + 2];\n                    var oA = pixels[index + 3];\n\n                    pixels[index] = (matrix[0] * oR) + (matrix[1] * oG) + (matrix[2] * oB) + (matrix[3] * oA) + matrix[4];\n                    pixels[index + 1] = (matrix[5] * oR) + (matrix[6] * oG) + (matrix[7] * oB) + (matrix[8] * oA) + matrix[9];\n                    pixels[index + 2] = (matrix[10] * oR) + (matrix[11] * oG) + (matrix[12] * oB) + (matrix[13] * oA) + matrix[14];\n                    pixels[index + 3] = (matrix[15] * oR) + (matrix[16] * oG) + (matrix[17] * oB) + (matrix[18] * oA) + matrix[19];\n                }\n            }\n        }, extents);\n    };\n\n    /**\n     * Blur the bitmap or parts of it\n     * @param {Number} radius the blur radius to be used\n     * @param {IFRect} [extents] optional extents, if not provided or null,\n     * takes the whole bitmap by default\n     */\n    IFBitmap.prototype.blur = function (radius, extents) {\n        this.modifyPixels(function (pixels, width, height) {\n            if (isNaN(radius) || radius < 1) return;\n            radius |= 0;\n\n            var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,\n                r_out_sum, g_out_sum, b_out_sum, a_out_sum,\n                r_in_sum, g_in_sum, b_in_sum, a_in_sum,\n                pr, pg, pb, pa, rbs;\n\n            var div = radius + radius + 1;\n            var widthMinus1 = width - 1;\n            var heightMinus1 = height - 1;\n            var radiusPlus1 = radius + 1;\n            var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2;\n\n            var stackStart = new BlurStack();\n            var stack = stackStart;\n            for (i = 1; i < div; i++) {\n                stack = stack.next = new BlurStack();\n                if (i == radiusPlus1) var stackEnd = stack;\n            }\n            stack.next = stackStart;\n            var stackIn = null;\n            var stackOut = null;\n\n            yw = yi = 0;\n\n            var mul_sum = mul_table[radius];\n            var shg_sum = shg_table[radius];\n\n            for (y = 0; y < height; y++) {\n                r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;\n\n                r_out_sum = radiusPlus1 * ( pr = pixels[yi] );\n                g_out_sum = radiusPlus1 * ( pg = pixels[yi + 1] );\n                b_out_sum = radiusPlus1 * ( pb = pixels[yi + 2] );\n                a_out_sum = radiusPlus1 * ( pa = pixels[yi + 3] );\n\n                r_sum += sumFactor * pr;\n                g_sum += sumFactor * pg;\n                b_sum += sumFactor * pb;\n                a_sum += sumFactor * pa;\n\n                stack = stackStart;\n\n                for (i = 0; i < radiusPlus1; i++) {\n                    stack.r = pr;\n                    stack.g = pg;\n                    stack.b = pb;\n                    stack.a = pa;\n                    stack = stack.next;\n                }\n\n                for (i = 1; i < radiusPlus1; i++) {\n                    p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 );\n                    r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i );\n                    g_sum += ( stack.g = ( pg = pixels[p + 1])) * rbs;\n                    b_sum += ( stack.b = ( pb = pixels[p + 2])) * rbs;\n                    a_sum += ( stack.a = ( pa = pixels[p + 3])) * rbs;\n\n                    r_in_sum += pr;\n                    g_in_sum += pg;\n                    b_in_sum += pb;\n                    a_in_sum += pa;\n\n                    stack = stack.next;\n                }\n\n\n                stackIn = stackStart;\n                stackOut = stackEnd;\n                for (x = 0; x < width; x++) {\n                    pixels[yi] = (r_sum * mul_sum) >> shg_sum;\n                    pixels[yi + 1] = (g_sum * mul_sum) >> shg_sum;\n                    pixels[yi + 2] = (b_sum * mul_sum) >> shg_sum;\n                    pixels[yi + 3] = (a_sum * mul_sum) >> shg_sum;\n\n                    r_sum -= r_out_sum;\n                    g_sum -= g_out_sum;\n                    b_sum -= b_out_sum;\n                    a_sum -= a_out_sum;\n\n                    r_out_sum -= stackIn.r;\n                    g_out_sum -= stackIn.g;\n                    b_out_sum -= stackIn.b;\n                    a_out_sum -= stackIn.a;\n\n                    p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;\n\n                    r_in_sum += ( stackIn.r = pixels[p]);\n                    g_in_sum += ( stackIn.g = pixels[p + 1]);\n                    b_in_sum += ( stackIn.b = pixels[p + 2]);\n                    a_in_sum += ( stackIn.a = pixels[p + 3]);\n\n                    r_sum += r_in_sum;\n                    g_sum += g_in_sum;\n                    b_sum += b_in_sum;\n                    a_sum += a_in_sum;\n\n                    stackIn = stackIn.next;\n\n                    r_out_sum += ( pr = stackOut.r );\n                    g_out_sum += ( pg = stackOut.g );\n                    b_out_sum += ( pb = stackOut.b );\n                    a_out_sum += ( pa = stackOut.a );\n\n                    r_in_sum -= pr;\n                    g_in_sum -= pg;\n                    b_in_sum -= pb;\n                    a_in_sum -= pa;\n\n                    stackOut = stackOut.next;\n\n                    yi += 4;\n                }\n                yw += width;\n            }\n\n\n            for (x = 0; x < width; x++) {\n                g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0;\n\n                yi = x << 2;\n                r_out_sum = radiusPlus1 * ( pr = pixels[yi]);\n                g_out_sum = radiusPlus1 * ( pg = pixels[yi + 1]);\n                b_out_sum = radiusPlus1 * ( pb = pixels[yi + 2]);\n                a_out_sum = radiusPlus1 * ( pa = pixels[yi + 3]);\n\n                r_sum += sumFactor * pr;\n                g_sum += sumFactor * pg;\n                b_sum += sumFactor * pb;\n                a_sum += sumFactor * pa;\n\n                stack = stackStart;\n\n                for (i = 0; i < radiusPlus1; i++) {\n                    stack.r = pr;\n                    stack.g = pg;\n                    stack.b = pb;\n                    stack.a = pa;\n                    stack = stack.next;\n                }\n\n                yp = width;\n\n                for (i = 1; i <= radius; i++) {\n                    yi = ( yp + x ) << 2;\n\n                    r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i );\n                    g_sum += ( stack.g = ( pg = pixels[yi + 1])) * rbs;\n                    b_sum += ( stack.b = ( pb = pixels[yi + 2])) * rbs;\n                    a_sum += ( stack.a = ( pa = pixels[yi + 3])) * rbs;\n\n                    r_in_sum += pr;\n                    g_in_sum += pg;\n                    b_in_sum += pb;\n                    a_in_sum += pa;\n\n                    stack = stack.next;\n\n                    if (i < heightMinus1) {\n                        yp += width;\n                    }\n                }\n\n                yi = x;\n                stackIn = stackStart;\n                stackOut = stackEnd;\n                for (y = 0; y < height; y++) {\n                    p = yi << 2;\n                    pixels[p + 3] = pa = (a_sum * mul_sum) >> shg_sum;\n                    if (pa > 0) {\n                        pa = 255 / pa;\n                        pixels[p] = ((r_sum * mul_sum) >> shg_sum ) * pa;\n                        pixels[p + 1] = ((g_sum * mul_sum) >> shg_sum ) * pa;\n                        pixels[p + 2] = ((b_sum * mul_sum) >> shg_sum ) * pa;\n                    } else {\n                        pixels[p] = pixels[p + 1] = pixels[p + 2] = 0;\n                    }\n\n                    r_sum -= r_out_sum;\n                    g_sum -= g_out_sum;\n                    b_sum -= b_out_sum;\n                    a_sum -= a_out_sum;\n\n                    r_out_sum -= stackIn.r;\n                    g_out_sum -= stackIn.g;\n                    b_out_sum -= stackIn.b;\n                    a_out_sum -= stackIn.a;\n\n                    p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;\n\n                    r_sum += ( r_in_sum += ( stackIn.r = pixels[p]));\n                    g_sum += ( g_in_sum += ( stackIn.g = pixels[p + 1]));\n                    b_sum += ( b_in_sum += ( stackIn.b = pixels[p + 2]));\n                    a_sum += ( a_in_sum += ( stackIn.a = pixels[p + 3]));\n\n                    stackIn = stackIn.next;\n\n                    r_out_sum += ( pr = stackOut.r );\n                    g_out_sum += ( pg = stackOut.g );\n                    b_out_sum += ( pb = stackOut.b );\n                    a_out_sum += ( pa = stackOut.a );\n\n                    r_in_sum -= pr;\n                    g_in_sum -= pg;\n                    b_in_sum -= pb;\n                    a_in_sum -= pa;\n\n                    stackOut = stackOut.next;\n\n                    yi += width;\n                }\n            }\n        }, extents);\n    };\n\n    /** @override */\n    IFBitmap.prototype.toString = function () {\n        return \"[Object IFBitmap]\";\n    };\n\n    /*\n     StackBlur - a fast almost Gaussian Blur For Canvas\n\n     Version: \t0.6\n     Author:\t\tMario Klingemann\n     Contact: \tmario@quasimondo.com\n     Website:\thttp://www.quasimondo.com/StackBlurForCanvas\n     Twitter:\t@quasimondo\n\n     In case you find this class useful - especially in commercial projects -\n     I am not totally unhappy for a small donation to my PayPal account\n     mario@quasimondo.de\n\n     Or support me on flattr:\n     https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript\n\n     Copyright (c) 2010 Mario Klingemann\n\n     Permission is hereby granted, free of charge, to any person\n     obtaining a copy of this software and associated documentation\n     files (the \"Software\"), to deal in the Software without\n     restriction, including without limitation the rights to use,\n     copy, modify, merge, publish, distribute, sublicense, and/or sell\n     copies of the Software, and to permit persons to whom the\n     Software is furnished to do so, subject to the following\n     conditions:\n\n     The above copyright notice and this permission notice shall be\n     included in all copies or substantial portions of the Software.\n\n     THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n     OTHER DEALINGS IN THE SOFTWARE.\n     */\n    var mul_table = [\n        512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,\n        454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,\n        482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,\n        437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,\n        497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,\n        320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,\n        446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,\n        329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,\n        505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,\n        399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,\n        324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,\n        268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,\n        451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,\n        385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,\n        332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,\n        289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259];\n\n\n    var shg_table = [\n        9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,\n        17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,\n        19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,\n        20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,\n        21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,\n        21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,\n        22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,\n        22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,\n        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,\n        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,\n        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,\n        23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n        24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n        24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n        24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n        24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 ];\n\n    function BlurStack() {\n        this.r = 0;\n        this.g = 0;\n        this.b = 0;\n        this.a = 0;\n        this.next = null;\n    }\n\n    _.IFBitmap = IFBitmap;\n})(this);"
  },
  {
    "path": "src/infinity/paint/color.js",
    "content": "(function (_) {\n    /**\n     * A class representing a color\n     * @param {IFColor.Type} type\n     * @param {Array<Number>|String> [value]\n     * @class IFColor\n     * @extends IFPattern\n     * @constructor\n     */\n    function IFColor(type, value) {\n        this._type = type;\n        this._value = value && value instanceof Array ? value.slice() : value;\n    }\n\n    IFObject.inherit(IFColor, IFPattern);\n\n    /**\n     * @enum\n     */\n    IFColor.Type = {\n        /** RGB Color - \"rgb(0..255, 0..255, 0..255, 0..100)\" */\n        RGB: {\n            key: 'rgb',\n            space: IFColorSpace.RGB,\n            fromString: function (string) {\n                var result = [0, 0, 0, 0];\n                var values = string.split(',');\n                if (values.length !== 4) {\n                    result = null;\n                } else {\n                    for (var i = 0; i < 4; ++i) {\n                        var val = parseInt(values[i]);\n                        if (isNaN(val) || val < 0 || (i === 3 && val > 100) || (i < 3 && val > 255)) {\n                            result = null;\n                            break;\n                        } else {\n                            result[i] = val;\n                        }\n                    }\n                }\n                return result;\n            },\n            toString: function (value) {\n                return value.join(',');\n            }\n        },\n        /** HSL Color - \"hsl(0..360, 0..100, 0..100, 0..100)\" */\n        HSL: {\n            key: 'hsl',\n            space: IFColorSpace.RGB,\n            fromString: function (string) {\n                var result = [0, 0, 0, 0];\n                var values = string.split(',');\n                if (values.length !== 4) {\n                    result = null;\n                } else {\n                    for (var i = 0; i < 4; ++i) {\n                        var val = parseInt(values[i]);\n                        if (isNaN(val) || val < 0 || (i === 0 && val > 360) || (i > 0 && val > 100)) {\n                            result = null;\n                            break;\n                        } else {\n                            result[i] = val;\n                        }\n                    }\n                }\n                return result;\n            },\n            toString: function (value) {\n                return value.join(',');\n            }\n        },\n        /** Tone Color - \"tone(0..100, 0..100)\" */\n        Tone: {\n            key: 'tone',\n            space: IFColorSpace.RGB,\n            fromString: function (string) {\n                var result = [0, 0];\n                var values = string.split(',');\n                if (values.length !== 2) {\n                    result = null;\n                } else {\n                    for (var i = 0; i < 2; ++i) {\n                        var val = parseInt(values[i]);\n                        if (isNaN(val) || val < 0 || val > 100) {\n                            result = null;\n                            break;\n                        } else {\n                            result[i] = val;\n                        }\n                    }\n                }\n                return result;\n            },\n            toString: function (value) {\n                return value.join(',');\n            }\n        },\n        /** CMYK Color - \"cmyk(0..100, 0..100, 0..100)\" */\n        CMYK: {\n            key: 'cmyk',\n            space: IFColorSpace.CMYK,\n            fromString: function (string) {\n                var result = [0, 0, 0, 0];\n                var values = string.split(',');\n                if (values.length !== 4) {\n                    result = null;\n                } else {\n                    for (var i = 0; i < 4; ++i) {\n                        var val = parseInt(values[i]);\n                        if (isNaN(val) || val < 0 || val > 100) {\n                            result = null;\n                            break;\n                        } else {\n                            result[i] = val;\n                        }\n                    }\n                }\n                return result;\n            },\n            toString: function (value) {\n                return value.join(',');\n            }\n        },\n\n        /** Reference to another color - \"#ReferenceId\" */\n        Reference: {\n            key: '#',\n            space: IFColorSpace.None,\n            fromString: function (string) {\n                return string;\n            },\n            toString: function (value) {\n                return value;\n            }\n        },\n\n        /** Special white point - \"white\" - value = null */\n        White: {\n            key: 'white',\n            space: IFColorSpace.None\n        },\n        /** Special black point - \"black\"- value = null */\n        Black: {\n            key: 'black',\n            space: IFColorSpace.None\n        },\n        /** Special registration point - \"registration\" - value = null */\n        Registration: {\n            key: 'registration',\n            space: IFColorSpace.None\n        }\n    };\n\n    // Pre-defined color constants\n    IFColor.BLACK = new IFColor(IFColor.Type.Black);\n    IFColor.WHITE = new IFColor(IFColor.Type.White);\n    IFColor.TRANSPARENT_WHITE = new IFColor(IFColor.Type.RGB, [255, 255, 255, 0]);\n\n    IFColor.SELECTION_OUTLINE = new IFColor(IFColor.Type.RGB, [0, 168, 255, 100]);\n    IFColor.HIGHLIGHT_OUTLINE = new IFColor(IFColor.Type.RGB, [255, 0, 0, 100]);\n    IFColor.GUIDE_OUTLINE = new IFColor(IFColor.Type.RGB, [46, 204, 64, 100]);\n    IFColor.MARGIN_OUTLINE = new IFColor(IFColor.Type.RGB, [255, 0, 255, 100]);\n\n    /**\n     * Parse a string into a IFColor\n     * @param {String} string\n     * @return {IFColor}\n     */\n    IFColor.parseColor = function (string) {\n        if (!string || string === \"\") {\n            return null;\n        }\n\n        for (var typeKey in IFColor.Type) {\n            var type = IFColor.Type[typeKey];\n            if (string.indexOf(type.key) === 0) {\n                if (type.fromString) {\n                    var value = type.fromString(string.substring(type.key.length));\n                    if (value) {\n                        return new IFColor(type, value);\n                    }\n                } else {\n                    return new IFColor(type);\n                }\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Parse a CSS Color String\n     * @param {String} cssString\n     * @return {IFColor}\n     */\n    IFColor.parseCSSColor = function (cssString) {\n        // http://www.w3.org/TR/css3-color/\n        var kCSSColorTable = {\n            \"transparent\": [0, 0, 0, 0], \"aliceblue\": [240, 248, 255, 100],\n            \"antiquewhite\": [250, 235, 215, 100], \"aqua\": [0, 255, 255, 100],\n            \"aquamarine\": [127, 255, 212, 100], \"azure\": [240, 255, 255, 100],\n            \"beige\": [245, 245, 220, 100], \"bisque\": [255, 228, 196, 100],\n            \"black\": [0, 0, 0, 100], \"blanchedalmond\": [255, 235, 205, 100],\n            \"blue\": [0, 0, 255, 100], \"blueviolet\": [138, 43, 226, 100],\n            \"brown\": [165, 42, 42, 100], \"burlywood\": [222, 184, 135, 100],\n            \"cadetblue\": [95, 158, 160, 100], \"chartreuse\": [127, 255, 0, 100],\n            \"chocolate\": [210, 105, 30, 100], \"coral\": [255, 127, 80, 100],\n            \"cornflowerblue\": [100, 149, 237, 100], \"cornsilk\": [255, 248, 220, 100],\n            \"crimson\": [220, 20, 60, 100], \"cyan\": [0, 255, 255, 100],\n            \"darkblue\": [0, 0, 139, 100], \"darkcyan\": [0, 139, 139, 100],\n            \"darkgoldenrod\": [184, 134, 11, 100], \"darkgray\": [169, 169, 169, 100],\n            \"darkgreen\": [0, 100, 0, 100], \"darkgrey\": [169, 169, 169, 100],\n            \"darkkhaki\": [189, 183, 107, 100], \"darkmagenta\": [139, 0, 139, 100],\n            \"darkolivegreen\": [85, 107, 47, 100], \"darkorange\": [255, 140, 0, 100],\n            \"darkorchid\": [153, 50, 204, 100], \"darkred\": [139, 0, 0, 100],\n            \"darksalmon\": [233, 150, 122, 100], \"darkseagreen\": [143, 188, 143, 100],\n            \"darkslateblue\": [72, 61, 139, 100], \"darkslategray\": [47, 79, 79, 100],\n            \"darkslategrey\": [47, 79, 79, 100], \"darkturquoise\": [0, 206, 209, 100],\n            \"darkviolet\": [148, 0, 211, 100], \"deeppink\": [255, 20, 147, 100],\n            \"deepskyblue\": [0, 191, 255, 100], \"dimgray\": [105, 105, 105, 100],\n            \"dimgrey\": [105, 105, 105, 100], \"dodgerblue\": [30, 144, 255, 100],\n            \"firebrick\": [178, 34, 34, 100], \"floralwhite\": [255, 250, 240, 100],\n            \"forestgreen\": [34, 139, 34, 100], \"fuchsia\": [255, 0, 255, 100],\n            \"gainsboro\": [220, 220, 220, 100], \"ghostwhite\": [248, 248, 255, 100],\n            \"gold\": [255, 215, 0, 100], \"goldenrod\": [218, 165, 32, 100],\n            \"gray\": [128, 128, 128, 100], \"green\": [0, 128, 0, 100],\n            \"greenyellow\": [173, 255, 47, 100], \"grey\": [128, 128, 128, 100],\n            \"honeydew\": [240, 255, 240, 100], \"hotpink\": [255, 105, 180, 100],\n            \"indianred\": [205, 92, 92, 100], \"indigo\": [75, 0, 130, 100],\n            \"ivory\": [255, 255, 240, 100], \"khaki\": [240, 230, 140, 100],\n            \"lavender\": [230, 230, 250, 100], \"lavenderblush\": [255, 240, 245, 100],\n            \"lawngreen\": [124, 252, 0, 100], \"lemonchiffon\": [255, 250, 205, 100],\n            \"lightblue\": [173, 216, 230, 100], \"lightcoral\": [240, 128, 128, 100],\n            \"lightcyan\": [224, 255, 255, 100], \"lightgoldenrodyellow\": [250, 250, 210, 100],\n            \"lightgray\": [211, 211, 211, 100], \"lightgreen\": [144, 238, 144, 100],\n            \"lightgrey\": [211, 211, 211, 100], \"lightpink\": [255, 182, 193, 100],\n            \"lightsalmon\": [255, 160, 122, 100], \"lightseagreen\": [32, 178, 170, 100],\n            \"lightskyblue\": [135, 206, 250, 100], \"lightslategray\": [119, 136, 153, 100],\n            \"lightslategrey\": [119, 136, 153, 100], \"lightsteelblue\": [176, 196, 222, 100],\n            \"lightyellow\": [255, 255, 224, 100], \"lime\": [0, 255, 0, 100],\n            \"limegreen\": [50, 205, 50, 100], \"linen\": [250, 240, 230, 100],\n            \"magenta\": [255, 0, 255, 100], \"maroon\": [128, 0, 0, 100],\n            \"mediumaquamarine\": [102, 205, 170, 100], \"mediumblue\": [0, 0, 205, 100],\n            \"mediumorchid\": [186, 85, 211, 100], \"mediumpurple\": [147, 112, 219, 100],\n            \"mediumseagreen\": [60, 179, 113, 100], \"mediumslateblue\": [123, 104, 238, 100],\n            \"mediumspringgreen\": [0, 250, 154, 100], \"mediumturquoise\": [72, 209, 204, 100],\n            \"mediumvioletred\": [199, 21, 133, 100], \"midnightblue\": [25, 25, 112, 100],\n            \"mintcream\": [245, 255, 250, 100], \"mistyrose\": [255, 228, 225, 100],\n            \"moccasin\": [255, 228, 181, 100], \"navajowhite\": [255, 222, 173, 100],\n            \"navy\": [0, 0, 128, 100], \"oldlace\": [253, 245, 230, 100],\n            \"olive\": [128, 128, 0, 100], \"olivedrab\": [107, 142, 35, 100],\n            \"orange\": [255, 165, 0, 100], \"orangered\": [255, 69, 0, 100],\n            \"orchid\": [218, 112, 214, 100], \"palegoldenrod\": [238, 232, 170, 100],\n            \"palegreen\": [152, 251, 152, 100], \"paleturquoise\": [175, 238, 238, 100],\n            \"palevioletred\": [219, 112, 147, 100], \"papayawhip\": [255, 239, 213, 100],\n            \"peachpuff\": [255, 218, 185, 100], \"peru\": [205, 133, 63, 100],\n            \"pink\": [255, 192, 203, 100], \"plum\": [221, 160, 221, 100],\n            \"powderblue\": [176, 224, 230, 100], \"purple\": [128, 0, 128, 100],\n            \"red\": [255, 0, 0, 100], \"rosybrown\": [188, 143, 143, 100],\n            \"royalblue\": [65, 105, 225, 100], \"saddlebrown\": [139, 69, 19, 100],\n            \"salmon\": [250, 128, 114, 100], \"sandybrown\": [244, 164, 96, 100],\n            \"seagreen\": [46, 139, 87, 100], \"seashell\": [255, 245, 238, 100],\n            \"sienna\": [160, 82, 45, 100], \"silver\": [192, 192, 192, 100],\n            \"skyblue\": [135, 206, 235, 100], \"slateblue\": [106, 90, 205, 100],\n            \"slategray\": [112, 128, 144, 100], \"slategrey\": [112, 128, 144, 100],\n            \"snow\": [255, 250, 250, 100], \"springgreen\": [0, 255, 127, 100],\n            \"steelblue\": [70, 130, 180, 100], \"tan\": [210, 180, 140, 100],\n            \"teal\": [0, 128, 128, 100], \"thistle\": [216, 191, 216, 100],\n            \"tomato\": [255, 99, 71, 100], \"turquoise\": [64, 224, 208, 100],\n            \"violet\": [238, 130, 238, 100], \"wheat\": [245, 222, 179, 100],\n            \"white\": [255, 255, 255, 100], \"whitesmoke\": [245, 245, 245, 100],\n            \"yellow\": [255, 255, 0, 100], \"yellowgreen\": [154, 205, 50, 100]}\n\n        function clamp_css_byte(i) {  // Clamp to integer 0 .. 255.\n            i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n            return i < 0 ? 0 : i > 255 ? 255 : i;\n        }\n\n        function clamp_css_float(f) {  // Clamp to float 0.0 .. 1.0.\n            return f < 0 ? 0 : f > 1 ? 1 : f;\n        }\n\n        function parse_css_int(str) {  // int or percentage.\n            if (str[str.length - 1] === '%')\n                return clamp_css_byte(parseFloat(str) / 100 * 255);\n            return clamp_css_byte(parseInt(str));\n        }\n\n        function parse_css_float(str) {  // float or percentage.\n            if (str[str.length - 1] === '%')\n                return clamp_css_float(parseFloat(str) / 100);\n            return clamp_css_float(parseFloat(str));\n        }\n\n        function css_hue_to_rgb(m1, m2, h) {\n            if (h < 0) h += 1;\n            else if (h > 1) h -= 1;\n\n            if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;\n            if (h * 2 < 1) return m2;\n            if (h * 3 < 2) return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n            return m1;\n        }\n\n\n        // Remove all whitespace, not compliant, but should just be more accepting.\n        var str = cssString.replace(/ /g, '').toLowerCase();\n\n        // Color keywords (and transparent) lookup.\n        if (str in kCSSColorTable) return new IFColor(IFColor.Type.RGB, kCSSColorTable[str].slice());  // dup.\n\n        // #abc and #abc123 syntax.\n        if (str[0] === '#') {\n            if (str.length === 4) {\n                var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n                if (!(iv >= 0 && iv <= 0xfff)) return null;  // Covers NaN.\n                return new IFColor(IFColor.Type.RGB, [((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                    (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                    (iv & 0xf) | ((iv & 0xf) << 4),\n                    100]);\n            } else if (str.length === 7) {\n                var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n                if (!(iv >= 0 && iv <= 0xffffff)) return null;  // Covers NaN.\n                return new IFColor(IFColor.Type.RGB, [(iv & 0xff0000) >> 16,\n                    (iv & 0xff00) >> 8,\n                    iv & 0xff,\n                    100]);\n            }\n\n            return null;\n        }\n\n        var op = str.indexOf('('), ep = str.indexOf(')');\n        if (op !== -1 && ep + 1 === str.length) {\n            var fname = str.substr(0, op);\n            var params = str.substr(op + 1, ep - (op + 1)).split(',');\n            var alpha = 100;  // To allow case fallthrough.\n            switch (fname) {\n                case 'rgba':\n                    if (params.length !== 4) return null;\n                    alpha = Math.round(parse_css_float(params.pop()) * 100);\n                // Fall through.\n                case 'rgb':\n                    if (params.length !== 3) return null;\n                    return new IFColor(IFColor.Type.RGB, [parse_css_int(params[0]),\n                        parse_css_int(params[1]),\n                        parse_css_int(params[2]),\n                        alpha]);\n                case 'hsla':\n                    if (params.length !== 4) return null;\n                    alpha = Math.round(parse_css_float(params.pop()) * 100);\n                // Fall through.\n                case 'hsl':\n                    if (params.length !== 3) return null;\n                    var h = (((parseFloat(params[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n                    // NOTE(deanm): According to the CSS spec s/l should only be\n                    // percentages, but we don't bother and let float or percentage.\n                    var s = parse_css_float(params[1]);\n                    var l = parse_css_float(params[2]);\n                    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n                    var m1 = l * 2 - m2;\n                    return new IFColor(IFColor.Type.RGB, [clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1 / 3) * 255),\n                        clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255),\n                        clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1 / 3) * 255),\n                        alpha]);\n                default:\n                    return null;\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Compare two colors for equality Also takes care of null parameters\n     * @param {IFColor} left left side color\n     * @param {IFColor} right right side color\n     * @return {Boolean} true if left and right are equal (also if they're null!)\n     * @version 1.0\n     */\n    IFColor.equals = function (left, right) {\n        if (!left && left === right) {\n            return true;\n        } else if (left && right) {\n            if (left._type === right._type) {\n                var v1 = left._value;\n                var v2 = right._value;\n\n                if (!v1 && v1 === v2) {\n                    return true;\n                }\n\n                if (v1 instanceof Array && v2 instanceof Array) {\n                    if (v1.length !== v2.length) {\n                        return false;\n                    }\n\n                    for (var i = 0; i < v1.length; ++i) {\n                        if (v1[i] !== v2[i]) {\n                            return false;\n                        }\n                    }\n\n                    return true;\n                } else {\n                    return v1 === v2;\n                }\n            }\n        }\n        return false;\n    };\n\n    /**\n     * @type {IFColor.Type}\n     * @private\n     */\n    IFColor.prototype._type = null;\n\n    /**\n     * @type {Array<Number>|String|null}\n     * @private\n     */\n    IFColor.prototype._value = null;\n\n    /** @override */\n    IFColor.prototype.getPatternType = function () {\n        return IFPattern.Type.Color;\n    };\n\n    /**\n     * @returns {IFColor.Type}\n     */\n    IFColor.prototype.getType = function () {\n        return this._type;\n    };\n\n    /**\n     * DO NOT MODIFY RETURN VALUE!!!\n     * @returns {Array<Number>|String|null}\n     */\n    IFColor.prototype.getValue = function () {\n        return this._value;\n    };\n\n    /**\n     * @return {IFColorSpace}\n     */\n    IFColor.prototype.getSpace = function () {\n        return this._type.space;\n    };\n\n    /**\n     * Returns the color difference from this color to another\n     * color using the CIEDE2000 algorithm\n     * @param otherColor\n     * @returns {Number}\n     */\n    IFColor.prototype.difference = function (otherColor) {\n        var m = this.asLAB();\n        var o = otherColor.asLAB();\n        return ciede2000({L: m[0], a: m[1], b: m[2]}, {L: o[0], a: o[1], b: o[2]})\n    };\n\n    /**\n     * Return new instanceof this color with type RGB\n     * @returns {IFColor}\n     */\n    IFColor.prototype.toRGB = function () {\n        return new IFColor(IFColor.Type.RGB, this.asRGB());\n    };\n\n    /**\n     * Return new instanceof this color with type HSL\n     * @returns {IFColor}\n     */\n    IFColor.prototype.toHSL = function () {\n        return new IFColor(IFColor.Type.HSL, this.asHSL());\n    };\n\n    /**\n     * Return new instance of this color with type Tone\n     * @returns {IFColor}\n     */\n    IFColor.prototype.toTone = function () {\n        return new IFColor(IFColor.Type.Tone, this.asTone());\n    };\n\n    /**\n     * Return new instanceof this color with type CMYK\n     * @returns {IFColor}\n     */\n    IFColor.prototype.toCMYK = function () {\n        return new IFColor(IFColor.Type.CMYK, this.asCMYK());\n    };\n\n    /**\n     * Return new instanceof this color converted\n     * into a given color type. If the type is not a real\n     * color space like a reference or white black then\n     * this function will return a copy of the same color\n     * like this one with type RGB\n     * @param {IFColor.Type} type the target type\n     * @returns {IFColor}\n     */\n    IFColor.prototype.toType = function (type) {\n        switch (type) {\n            case IFColor.Type.HSL:\n                return this.toHSL();\n            case IFColor.Type.CMYK:\n                return this.toCMYK();\n            case IFColor.Type.Tone:\n                return this.toTone();\n            default:\n                return this.toRGB();\n        }\n    };\n\n    /**\n     * Return color as RGB-Array\n     * @return Array<Number> (0..255, 0..255, 0..255, 0..100)\n     */\n    IFColor.prototype.asRGB = function () {\n        if (this._type === IFColor.Type.RGB) {\n            return this._value.slice();\n        } else if (this._type === IFColor.Type.HSL) {\n            var h = this._value[0] / 360;\n            var s = this._value[1] / 100;\n            var l = this._value[2] / 100;\n            var r, g, b;\n            var temp1, temp2, temp3;\n            if (s === 0) {\n                r = g = b = l;\n            } else {\n                if (l < 0.5) temp2 = l * (1 + s);\n                else temp2 = (l + s) - (s * l);\n                temp1 = 2 * l - temp2;\n\n                // calculate red\n                temp3 = h + (1 / 3);\n                if (temp3 < 0) temp3 += 1;\n                if (temp3 > 1) temp3 -= 1;\n                if ((6 * temp3) < 1) r = temp1 + (temp2 - temp1) * 6 * temp3;\n                else if ((2 * temp3) < 1) r = temp2;\n                else if ((3 * temp3) < 2) r = temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6;\n                else r = temp1;\n\n                // calculate green\n                temp3 = h;\n                if (temp3 < 0) temp3 += 1;\n                if (temp3 > 1) temp3 -= 1;\n                if ((6 * temp3) < 1) g = temp1 + (temp2 - temp1) * 6 * temp3;\n                else if ((2 * temp3) < 1) g = temp2;\n                else if ((3 * temp3) < 2) g = temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6;\n                else g = temp1;\n\n                // calculate blue\n                temp3 = h - (1 / 3);\n                if (temp3 < 0) temp3 += 1;\n                if (temp3 > 1) temp3 -= 1;\n                if ((6 * temp3) < 1) b = temp1 + (temp2 - temp1) * 6 * temp3;\n                else if ((2 * temp3) < 1) b = temp2;\n                else if ((3 * temp3) < 2) b = temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6;\n                else b = temp1;\n            }\n\n            var R = Math.min(255, Math.max(0, Math.round(r * 255)));\n            var G = Math.min(255, Math.max(0, Math.round(g * 255)));\n            var B = Math.min(255, Math.max(0, Math.round(b * 255)));\n\n            return [R, G, B, this._value[3]];\n        } else if (this._type === IFColor.Type.Tone) {\n            var t = 255 - Math.min(255, Math.max(0, Math.round(this._value[0] / 100 * 255)));\n            return [t, t, t, this._value[1]];\n        } else if (this._type === IFColor.Type.CMYK) {\n            // CMYK -> CMY\n            var c = this._value[0] / 100;\n            var m = this._value[1] / 100;\n            var y = this._value[2] / 100;\n            var k = this._value[3] / 100;\n\n            var C = (c * (1 - k) + k);\n            var M = (m * (1 - k) + k);\n            var Y = (y * (1 - k) + k);\n\n            // CMY -> RGB\n            var R = Math.min(255, Math.max(0, Math.round((1 - C) * 255)));\n            var G = Math.min(255, Math.max(0, Math.round((1 - M) * 255)));\n            var B = Math.min(255, Math.max(0, Math.round((1 - Y) * 255)));\n\n            return [R, G, B, 100];\n        } else if (this._type === IFColor.Type.White) {\n            return [255, 255, 255, 100];\n        } else if (this._type === IFColor.Type.Black) {\n            return [0, 0, 0, 100];\n        } else if (this._type === IFColor.Type.Registration) {\n            return [0, 0, 0, 100];\n        } else {\n            throw new Error('Unable to convert to rgb from color type.');\n        }\n    };\n\n    /**\n     * Return color as 32-Bit integer\n     * @return {Number}\n     */\n    IFColor.prototype.asRGBInt = function () {\n        var rgb = this.asRGB();\n        var r = rgb[0];\n        var g = rgb[1];\n        var b = rgb[2];\n        var a = Math.round(rgb[3] * 2.55);\n\n        if (ifSystem.littleEndian) {\n            return (a << 24) | (b << 16) | (g << 8) | r;\n        } else {\n            return (r << 24) | (g << 16) | (b << 8) | a;\n        }\n    };\n\n    /**\n     * Return color as HSL-Array\n     * @return Array<Number> (0..360, 0..100, 0..100, 0..100)\n     */\n    IFColor.prototype.asHSL = function () {\n        if (this._type === IFColor.Type.HSL) {\n            return this._value.slice();\n        } else {\n            var rgb = this.asRGB();\n\n            var r = rgb[0] / 255,\n                g = rgb[1] / 255,\n                b = rgb[2] / 255,\n                a = rgb[3],\n                min = Math.min(r, g, b),\n                max = Math.max(r, g, b),\n                chroma = max - min,\n                h,\n                s,\n                l = (max + min) / 2;\n            if (chroma === 0) {\n                // No chroma\n                h = 0;\n                s = 0;\n            } else {\n                // Chromatic data\n                if (l < 0.5) s = chroma / (max + min);\n                else s = chroma / (2 - max - min);\n                var DR = (((max - r) / 6) + (chroma / 2)) / chroma;\n                var DG = (((max - g) / 6) + (chroma / 2)) / chroma;\n                var DB = (((max - b) / 6) + (chroma / 2)) / chroma;\n                if (r === max) h = DB - DG;\n                else if (g === max) h = (1 / 3) + DR - DB;\n                else if (b === max) h = (2 / 3) + DG - DR;\n                if (h < 0) h += 1;\n                if (h > 1) h -= 1;\n            }\n\n            var H = Math.min(360, Math.max(0, Math.round(h * 360)));\n            var S = Math.min(100, Math.max(0, Math.round(s * 100)));\n            var L = Math.min(100, Math.max(0, Math.round(l * 100)));\n\n            return [H, S, L, a];\n        }\n    };\n\n    /**\n     * Return color as Tone\n     * @return {Array<Number>} (0..100, 0..100)\n     */\n    IFColor.prototype.asTone = function () {\n        if (this._type === IFColor.Type.Tone) {\n            return this._value.slice();\n        } else {\n            var rgb = this.asRGB();\n\n            var r = rgb[0] / 255.0;\n            var g = rgb[1] / 255.0;\n            var b = rgb[2] / 255.0;\n            var a = rgb[3];\n\n            // linear tone\n            var t = 0.299 * r + 0.587 * g + 0.114 * b;\n            var T = 100 - Math.min(100, Math.max(0, Math.round(t * 100)));\n\n            return [T, a];\n        }\n    };\n\n    /**\n     * Return color as CMYK-Array\n     * @return Array<Number> (0..100, 0..100, 0.100, 0..100)\n     */\n    IFColor.prototype.asCMYK = function () {\n        if (this._type === IFColor.Type.CMYK) {\n            return this._value.slice();\n        } else {\n            var rgb = this.asRGB();\n\n            // RGB -> CMY\n            var c = 1 - (rgb[0] / 255);\n            var m = 1 - (rgb[1] / 255);\n            var y = 1 - (rgb[2] / 255);\n            var k = Math.min(y, Math.min(m, Math.min(c, 1)));\n            var a = rgb[3] / 100;\n\n            // CMY -> CMYK\n            var C = Math.round((c - k) / (1 - k) * 100 * a);\n            var M = Math.round((m - k) / (1 - k) * 100 * a);\n            var Y = Math.round((y - k) / (1 - k) * 100 * a);\n            var K = k * 100 * a;\n\n            return [C, M, Y, K];\n        }\n    };\n\n    /**\n     * Return color as XYZ-Array\n     * @param Array<Number> whitePointReference the whitepoint\n     * reference as XYZ (0..1.0, 0..1.0, 0..1.0)\n     * @return Array<Number> (0..1.0, 0..1.0, 0..1.0)\n     */\n    IFColor.prototype.asXYZ = function (whitePointReference) {\n        var rgb = this.asRGB();\n        var whitePointReference = whitePointReference ? whitePointReference : [];\n\n        // TODO : Properly calculate matrix\n\n        var convert = function (channel) {\n            return channel > 0.04045 ?\n                Math.pow(( ( channel + 0.055 ) / 1.055 ), 2.4) :\n                channel / 12.92;\n            ;\n        };\n\n        var r = convert(rgb[0] / 255) * 100;\n        var g = convert(rgb[1] / 255) * 100;\n        var b = convert(rgb[2] / 255) * 100;\n\n        // Observer. = 2°, Illuminant = D65\n        var x = r * 0.4124 + g * 0.3576 + b * 0.1805;\n        var y = r * 0.2126 + g * 0.7152 + b * 0.0722;\n        var z = r * 0.0193 + g * 0.1192 + b * 0.9505;\n\n        return [x, y, z];\n    };\n\n    /**\n     * Return color as LAB-Array\n     * @param Array<Number> whitePointReference the whitepoint\n     * reference as XYZ (0..1.0, 0..1.0, 0..1.0)\n     * @return Array<Number> TODO : Output description ranges\n     */\n    IFColor.prototype.asLAB = function (whitePointReference) {\n        var xyz = this.asXYZ(whitePointReference);\n\n        var convert = function (channel) {\n            return channel > 0.008856 ?\n                Math.pow(channel, 1 / 3) :\n                7.787037 * channel + 4 / 29;\n        };\n\n        var x = convert(xyz[0] / 95.047);\n        var y = convert(xyz[1] / 100.000);\n        var z = convert(xyz[2] / 108.883);\n\n        return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]\n    };\n\n    /**\n     * Return string representation of the underlying color\n     * @return {String}\n     */\n    IFColor.prototype.asString = function () {\n        var result = this._type.key;\n        if (this._type.toString) {\n            result += this._type.toString(this._value);\n        }\n        return result;\n    };\n\n    /**\n     * Return CSS-Compatible string representation of the underlying color\n     * @return {String}\n     */\n    IFColor.prototype.asCSSString = function () {\n        var rgb = this.asRGB();\n        if (rgb[3] === 100) {\n            return this.asHTMLHexString();\n        } else {\n            return 'rgba(' + rgb[0].toString() + ',' + rgb[1].toString() + ',' + rgb[2].toString() + ',' + (rgb[3] / 100.0).toString() + ')';\n        }\n    };\n\n    /**\n     * Return a html 6-digit hex color code excluding any alpha component\n     * @return {String}\n     */\n    IFColor.prototype.asHTMLHexString = function () {\n        var rgb = this.asRGB();\n\n        var bin = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n        return '#' + (function (h) {\n            return new Array(7 - h.length).join(\"0\") + h\n        })(bin.toString(16).toUpperCase());\n    };\n\n    /**\n     * Return new instanceof of this color with a given tint\n     * @param {Number} tint the tint from 0..100\n     * @returns {IFColor}\n     */\n    IFColor.prototype.withTint = function (tint) {\n        if (this._type === IFColor.Type.CMYK) {\n            // Special handling for CMYK\n            var factor = tint / 100.0;\n            var cmyk = this._value.slice();\n            for (var i = 0; i < 4; ++i) {\n                cmyk[i] = Math.round(cmyk[i] * factor);\n            }\n            return new IFColor(IFColor.Type.CMYK, cmyk);\n        } else {\n            // All others use rgb and try to convert back to source type\n            var factor = 1.0 - (tint / 100.0);\n            var rgb = this.asRGB();\n            rgb[0] = Math.round(((255 - rgb[0]) * factor) + rgb[0]);\n            rgb[1] = Math.round(((255 - rgb[1]) * factor) + rgb[1]);\n            rgb[2] = Math.round(((255 - rgb[2]) * factor) + rgb[2]);\n\n            return new IFColor(IFColor.Type.RGB, rgb).toType(this._type);\n        }\n    };\n\n    /**\n     * Return new instanceof of this color with a given shade\n     * @param {Number} shade the shade from 0..100\n     * @returns {IFColor}\n     */\n    IFColor.prototype.withShade = function (shade) {\n        if (this._type === IFColor.Type.CMYK) {\n            // Special handling for CMYK\n            var cmyk = this.asCMYK();\n            cmyk[3] = shade;\n            return new IFColor(IFColor.Type.CMYK, cmyk).toType(this._type);\n        } else {\n            // All others use rgb and try to convert back to source tpye\n            var factor = 1.0 - (shade / 100.0);\n            var rgb = this.asRGB();\n            rgb[0] = Math.round(rgb[0] * factor);\n            rgb[1] = Math.round(rgb[1] * factor);\n            rgb[2] = Math.round(rgb[2] * factor);\n\n            return new IFColor(IFColor.Type.RGB, rgb).toType(this._type);\n        }\n    };\n\n    /**\n     * Return new instanceof of this color with a given tone\n     * @param {Number} tone the tone from 0..100\n     * @returns {IFColor}\n     */\n    IFColor.prototype.withTone = function (tone) {\n        return this.withTint(tone).withShade(tone);\n    };\n\n    /** @override */\n    IFColor.prototype.toString = function () {\n        return \"[Object IFColor]\";\n    };\n\n    _.IFColor = IFColor;\n})(this);"
  },
  {
    "path": "src/infinity/paint/colorprofile.js",
    "content": "(function (_) {\n    /**\n     * A class representing a color profile\n     * @class IFColorProfile\n     * @constructor\n     */\n    function IFColorProfile() {\n    }\n\n    /**\n     * @type {IFColorSpace}\n     * @private\n     */\n    IFColorProfile.prototype._colorSpace = null;\n\n    /**\n     * @type {IFColorSpace}\n     * @private\n     */\n    IFColorProfile.prototype._pcsSpace = null;\n\n    /**\n     * @type {Array<Number>}\n     * @private\n     */\n    IFColorProfile.prototype._illumination = null;\n\n    /**\n     * TODO\n     */\n    IFColorProfile.convertColor = function (color) {\n        // Handle special color types first\n        if (color.getType() === IFColor.Type.White) {\n            // TODO : Convert white reference point\n        } else if (color.getType() === IFColor.Type.Black) {\n            // TODO : Convert black reference point\n        } else {\n            if (color.getSpace() !== this._colorSpace) {\n                throw new Error('Color space is different than profile color space.');\n            }\n\n            // Convert color into PCS\n            var pcs = null;\n            switch (this._pcsSpace) {\n                case IFColorProfile.Space.RGB:\n                    pcs = color.asRGB();\n                    pcs[0] = pcs[0] / 255.0;\n                    pcs[1] = pcs[1] / 255.0;\n                    pcs[2] = pcs[2] / 255.0;\n                    break;\n                case IFColorProfile.Space.CMYK:\n                    pcs = color.asCMYK();\n                    pcs[0] = pcs[0] / 100.0;\n                    pcs[1] = pcs[1] / 100.0;\n                    pcs[2] = pcs[2] / 100.0;\n                    pcs[3] = pcs[3] / 100.0;\n                    break;\n                case IFColorProfile.Space.LAB:\n                    pcs = color.asLAB(this._illumination);\n                    break;\n                case IFColorProfile.Space.XYZ:\n                    pcs = color.asXYZ(this._illumination);\n                    break;\n                default:\n                    throw new Error('Unable to convert.');\n            }\n\n            // TODO\n            // Convert PCS -> COLOR_SPACE\n            // RETURN CONVERTED COLOR\n        }\n    };\n\n    /** @override */\n    IFColorProfile.prototype.toString = function () {\n        return \"[Object IFColorProfile]\";\n    };\n\n    _.IFColorProfile = IFColorProfile;\n})(this);"
  },
  {
    "path": "src/infinity/paint/colorspace.js",
    "content": "(function (_) {\n    /**\n     * @enum\n     */\n    var IFColorSpace = {\n        None: 'n',\n        RGB: 'rgb',\n        CMYK: 'cmyk',\n        LAB: 'lab',\n        XYZ: 'xyz'\n    };\n\n    _.IFColorSpace = IFColorSpace;\n})(this);"
  },
  {
    "path": "src/infinity/paint/dirtylist.js",
    "content": "(function (_) {\n\n    /**\n     * A general-purpose data structure for holding a list of rectangular\n     * regions that need to be repainted, with intelligent coalescing.\n     *\n     * IFDirtyList will unify two regions A and B if the smallest rectangle\n     * enclosing both A and B occupies no more than epsilon + Area_A +\n     * Area_B. Failing this, if two corners of A fall within B, A will be\n     * shrunk to exclude the union of A and B.\n     *\n     * @class IFDirtyList\n     * @constructor\n     * @version 1.0\n     */\n    function IFDirtyList() {\n    }\n\n    /**\n     * Global IFDirtyList options\n     * @type {Object}\n     */\n    IFDirtyList.options = {\n        /**\n         * Maximum area to when to merge dirty regions\n         * @type {Number}\n         * @version 1.0\n         */\n        epsilon: 50 * 50,\n\n        /**\n         * Size of buffer hold for dirty rectangles\n         * @type {Number}\n         * @version 1.0\n         */\n        bufferSize: 10\n    };\n\n    //------------------------------------------------------------------------------------------------------------------\n    // IFDirtyList.Matcher Class\n    //------------------------------------------------------------------------------------------------------------------\n    /**\n     * The matcher is a consolidated result from a flushed dirty list\n     * @class IFDirtyList.Matcher\n     * @constructor\n     * @version 1.0\n     */\n    IFDirtyList.Matcher = function () {\n    };\n\n    /**\n     * @type {IFRect}\n     * @private\n     */\n    IFDirtyList.Matcher.prototype._unitedArea = null;\n\n    /**\n     * @type {Array}\n     * @private\n     */\n    IFDirtyList.Matcher.prototype._rects = null;\n\n    /**\n     * Called to test whether a given rectangle is within the dirty area(s)\n     * @param {IFRect} test [x, y, w, h] the rect to test against\n     * @return {Boolean} true if rect is within the dirty area(s), false if not\n     * @version 1.0\n     */\n    IFDirtyList.Matcher.prototype.isDirty = function (test) {\n        // Quick check against the overall area\n        if (this._unitedArea && !this._unitedArea.intersectsRect(test)) {\n            return false;\n        }\n\n        // Check against each saved rect now\n        if (this._rects && this._rects.length > 0) {\n            for (var i = 0; i < this._rects.length; ++i) {\n                var rect = this._rects[i];\n                if (rect.intersectsRect(test)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    };\n\n    /**\n     * Transform all dirty rectangles in this matcher with a given transformation\n     * @param {IFTransform} transform\n     * @version 1.0\n     */\n    IFDirtyList.Matcher.prototype.transform = function (transform) {\n        if (this._unitedArea) {\n            this._unitedArea = transform.mapRect(this._unitedArea);\n        }\n\n        if (this._rects && this._rects.length > 0) {\n            for (var i = 0; i < this._rects.length; ++i) {\n                this._rects[i] = transform.mapRect(this._rects[i]);\n            }\n        }\n    };\n\n    /**\n     * Clips all dirty rectangles into a given clip area\n     * or if there're no dirties, will add the clip area as\n     * united dirty area\n     * @param {IFRect} clipArea\n     */\n    IFDirtyList.Matcher.prototype.clip = function (clipArea) {\n        if (this._rects && this._rects.length > 0) {\n            if (this._unitedArea) {\n                this._unitedArea = clipArea.intersected(this._unitedArea);\n            }\n\n            for (var i = 0; i < this._rects.length; ++i) {\n                this._rects[i] = clipArea.intersected(this._rects[i]);\n            }\n        } else {\n            this._unitedArea = clipArea;\n            this._rects = [clipArea];\n        }\n    };\n\n    /**\n     * Returns an array of dirty rectangles within this matcher\n     * @return {Array} array of dirty rects in this matcher, may be null\n     * @version 1.0\n     */\n    IFDirtyList.Matcher.prototype.getDirtyRectangles = function () {\n        return this._rects;\n    };\n\n    //------------------------------------------------------------------------------------------------------------------\n    // IFDirtyList Class\n    //------------------------------------------------------------------------------------------------------------------\n\n    /**\n     * The actual area where dirty regions may take place. Anything\n     * outside of this area will be ignored\n     * @type {IFRect}\n     * @private\n     */\n    IFDirtyList.prototype._area = null;\n\n    /**\n     * The dirty regions (each one is an int[4])\n     * @private\n     */\n    IFDirtyList.prototype._dirties = null;\n\n    /**\n     * The number of dirty regions\n     * @private\n     */\n    IFDirtyList.prototype._numDirties = 0;\n\n\n    /**\n     * Assigns the active area for dirty regions. Anything\n     * outside of this area will be ignored as well as it is ensured\n     * that all dirty regions are bound to the area so that their\n     * coordintes will never lay outside this area. Note that if\n     * there're already dirty rectangles they'll be cut to fit\n     * within the new area.\n     * @param {IFRect} area\n     */\n    IFDirtyList.prototype.setArea = function (area) {\n        this._area = area;\n    };\n\n    /**\n     * Returns the currently active area\n     * @return {IFRect}\n     * @version 1.0\n     */\n    IFDirtyList.prototype.getArea = function () {\n        return this._area;\n    };\n\n    /**\n     * Add a new rectangle to the dirty list; returns false if the\n     * region fell completely within an existing rectangle or set of\n     * rectangles (ie did not expand the dirty area) or if it was not\n     * within the active area. Note that this will actually round\n     * the input values to integers, first, means that the actualy\n     * dirty array maybe up to 1px bigger on each side then the input.\n     *\n     * @param {Number} x the dirty rectangle's x-position\n     * @param {Number} y the dirty rectangle's y-position\n     * @param {Number} w the dirty rectangle's width\n     * @param {Number} h the dirty rectangle's height\n     * @return {Boolean}\n     * @version 1.0\n     */\n    IFDirtyList.prototype.dirty = function (x, y, w, h) {\n\n        // Fix coordinates, first\n        var tmp_x = Math.floor(x);\n        var tmp_y = Math.floor(y);\n        w = Math.ceil(x + w) - tmp_x;\n        h = Math.ceil(y + h) - tmp_y;\n        x = tmp_x;\n        y = tmp_y;\n\n        if (this._area) {\n            // Check if this._area is outside the active area\n            if (!this._area.intersectsRectXYWH(x, y, w, h)) {\n                return false;\n            }\n\n            // Normalize coords to not go beyond our area\n            if (x < this._area.getX()) x = this._area.getX();\n            if (y < this._area.getY()) y = this._area.getY();\n            if (x + w > this._area.getX() + this._area.getWidth()) w = this._area.getX() + this._area.getWidth() - x;\n            if (y + h > this._area.getY() + this._area.getHeight()) h = this._area.getY() + this._area.getHeight() - y;\n        }\n\n        if (this._dirties == null) {\n            this._dirties = new Array(IFDirtyList.options.bufferSize);\n        } else if (this._numDirties == this._dirties.length) {\n            this._dirties.length += IFDirtyList.options.bufferSize;\n        }\n\n        // we attempt the \"lossless\" combinations first\n        for (var i = 0; i < this._numDirties; i++) {\n            var cur = this._dirties[i];\n\n            // new region falls completely within existing region\n            if (x >= cur[0] && y >= cur[1] && x + w <= cur[0] + cur[2] && y + h <= cur[1] + cur[3]) {\n                return false;\n\n                // existing region falls completely within new region\n            } else if (x <= cur[0] && y <= cur[1] && x + w >= cur[0] + cur[2] && y + h >= cur[1] + cur[3]) {\n                this._dirties[i][2] = 0;\n                this._dirties[i][3] = 0;\n\n                // left end of new region falls within existing region\n            } else if (x >= cur[0] && x < cur[0] + cur[2] && y >= cur[1] && y + h <= cur[1] + cur[3]) {\n                w = x + w - (cur[0] + cur[2]);\n                x = cur[0] + cur[2];\n                i = -1;\n                continue;\n\n                // right end of new region falls within existing region\n            } else if (x + w > cur[0] && x + w <= cur[0] + cur[2] && y >= cur[1] && y + h <= cur[1] + cur[3]) {\n                w = cur[0] - x;\n                i = -1;\n                continue;\n\n                // top end of new region falls within existing region\n            } else if (x >= cur[0] && x + w <= cur[0] + cur[2] && y >= cur[1] && y < cur[1] + cur[3]) {\n                h = y + h - (cur[1] + cur[3]);\n                y = cur[1] + cur[3];\n                i = -1;\n                continue;\n\n                // bottom end of new region falls within existing region\n            } else if (x >= cur[0] && x + w <= cur[0] + cur[2] && y + h > cur[1] && y + h <= cur[1] + cur[3]) {\n                h = cur[1] - y;\n                i = -1;\n                continue;\n\n                // left end of existing region falls within new region\n            } else if (this._dirties[i][0] >= x && this._dirties[i][0] < x + w && this._dirties[i][1] >= y && this._dirties[i][1] + this._dirties[i][3] <= y + h) {\n                this._dirties[i][2] = this._dirties[i][2] - (x + w - this._dirties[i][0]);\n                this._dirties[i][0] = x + w;\n                i = -1;\n                continue;\n\n                // right end of existing region falls within new region\n            } else if (this._dirties[i][0] + this._dirties[i][2] > x && this._dirties[i][0] + this._dirties[i][2] <= x + w &&\n                this._dirties[i][1] >= y && this._dirties[i][1] + this._dirties[i][3] <= y + h) {\n                this._dirties[i][2] = x - this._dirties[i][0];\n                i = -1;\n                continue;\n\n                // top end of existing region falls within new region\n            } else if (this._dirties[i][0] >= x && this._dirties[i][0] + this._dirties[i][2] <= x + w && this._dirties[i][1] >= y && this._dirties[i][1] < y + h) {\n                this._dirties[i][3] = this._dirties[i][3] - (y + h - this._dirties[i][1]);\n                this._dirties[i][1] = y + h;\n                i = -1;\n                continue;\n\n                // bottom end of existing region falls within new region\n            } else if (this._dirties[i][0] >= x && this._dirties[i][0] + this._dirties[i][2] <= x + w &&\n                this._dirties[i][1] + this._dirties[i][3] > y && this._dirties[i][1] + this._dirties[i][3] <= y + h) {\n                this._dirties[i][3] = y - this._dirties[i][1];\n                i = -1;\n                continue;\n            }\n\n        }\n\n        // then we attempt the \"lossy\" combinations\n        for (var i = 0; i < this._numDirties; i++) {\n            var cur = this._dirties[i];\n            if (w > 0 && h > 0 && cur[2] > 0 && cur[3] > 0 &&\n                ((Math.max(x + w, cur[0] + cur[2]) - Math.min(x, cur[0])) *\n                    (Math.max(y + h, cur[1] + cur[3]) - Math.min(y, cur[1])) <\n                    w * h + cur[2] * cur[3] + IFDirtyList.options.epsilon)) {\n                var a = Math.min(cur[0], x);\n                var b = Math.min(cur[1], y);\n                var c = Math.max(x + w, cur[0] + cur[2]) - Math.min(cur[0], x);\n                var d = Math.max(y + h, cur[1] + cur[3]) - Math.min(cur[1], y);\n                this._dirties[i][2] = 0;\n                this._dirties[i][3] = 0;\n                return this.dirty(a, b, c, d);\n            }\n        }\n\n        this._dirties[this._numDirties++] = [x, y, w, h];\n        return true;\n    };\n\n    /**\n     * Flushes this dirty list which means that a matcher with dirty\n     * regions gets returned and the dirty list gets cleaned.\n     * @return {IFDirtyList.Matcher} null if there's nothing dirty or a valid matcher\n     * @version 1.0\n     */\n    IFDirtyList.prototype.flush = function () {\n\n        var matcher = null;\n        if (this._numDirties > 0) {\n            matcher = new IFDirtyList.Matcher();\n\n            matcher._rects = new Array(this._numDirties);\n            var index = 0;\n            for (var i = 0; i < this._numDirties; ++i) {\n                var rect = this._dirties[i];\n                if (rect && rect[2] > 0 && rect[3] > 0) {\n                    var newRect = new IFRect(rect[0], rect[1], rect[2], rect[3]);\n                    matcher._rects[index++] = newRect;\n                    if (matcher._unitedArea == null) {\n                        matcher._unitedArea = newRect;\n                    } else {\n                        matcher._unitedArea = matcher._unitedArea.united(newRect);\n                    }\n                }\n            }\n            matcher._rects.length = index;\n            if (matcher._rects.length == 0) {\n                matcher = null;\n            }\n        }\n\n        this.reset();\n\n        return matcher;\n    };\n\n    /**\n     * Simply reset this dirty list\n     * @version 1.0\n     */\n    IFDirtyList.prototype.reset = function () {\n        if (this._numDirties > 0) {\n            // Clear ourself\n            this._dirties.length = IFDirtyList.options.bufferSize;\n            this._numDirties = 0;\n        }\n    };\n\n    /** @override */\n    IFDirtyList.prototype.toString = function () {\n        return \"[Object IFDirtyList]\";\n    };\n\n    _.IFDirtyList = IFDirtyList;\n})(this);"
  },
  {
    "path": "src/infinity/paint/font.js",
    "content": "(function (_) {\n\n    /**\n     * @class IFFont\n     * @constructor\n     */\n    function IFFont() {\n        this._types = {};\n    };\n\n    /**\n     * The style of a font\n     * @enum\n     */\n    IFFont.Style = {\n        Normal: 'N',\n        Italic: 'I'\n    };\n\n    /**\n     * The weight of a font\n     * @enum\n     */\n    IFFont.Weight = {\n        Thin: 100,\n        ExtraLight: 200,\n        Light: 300,\n        Regular: 400,\n        Medium: 500,\n        SemiBold: 600,\n        Bold: 700,\n        ExtraBold: 800,\n        Heavy: 900\n    };\n\n    /**\n     * Localized names for IFFont.Weight\n     */\n    IFFont.WeightName = {\n        100: new IFLocale.Key(IFFont, 'weight.thin'),\n        200: new IFLocale.Key(IFFont, 'weight.extra-light'),\n        300: new IFLocale.Key(IFFont, 'weight.light'),\n        400: new IFLocale.Key(IFFont, 'weight.regular'),\n        500: new IFLocale.Key(IFFont, 'weight.medium'),\n        600: new IFLocale.Key(IFFont, 'weight.semi-bold'),\n        700: new IFLocale.Key(IFFont, 'weight.bold'),\n        800: new IFLocale.Key(IFFont, 'weight.extra-bold'),\n        900: new IFLocale.Key(IFFont, 'weight.heavy')\n    };\n\n    /**\n     * The category of a font\n     * @enum\n     */\n    IFFont.Category = {\n        Other: 0,\n        Serif: 100,\n        Monospace: 200,\n        Iconic: 300\n    };\n\n    /**\n     * Localized names for IFFont.Category\n     */\n    IFFont.CategoryName = {\n          0: new IFLocale.Key(IFFont, 'category.other'),\n        100: new IFLocale.Key(IFFont, 'category.serif'),\n        200: new IFLocale.Key(IFFont, 'category.monospace'),\n        300: new IFLocale.Key(IFFont, 'category.iconic')\n    };\n\n    /**\n     * @type {{}}\n     * @private\n     */\n    IFFont.prototype._types = null;\n\n    /**\n     * Register a new font type\n     * @param {String} family the font-family this type belongs to\n     * @param {IFFont.Style} style the style of the type\n     * @param {IFFont.Weight} weight the weight of the type\n     * @param {String} url the url to load the font-file from\n     * @param {Boolean} [category] the font type category. Needs to be called\n     * on the first typeface added only. Defaults to IFFont.Category.Other\n     */\n    IFFont.prototype.addType = function (family, style, weight, url, category) {\n        var type = this._types[family];\n\n        if (!type) {\n            type = {\n                styles: {},\n                weights: {},\n                variants: {},\n                category: category || IFFont.Category.Other\n            }\n\n            this._types[family] = type;\n        }\n\n        var variant = style + weight.toString();\n        type.styles[style] = true;\n        type.weights[weight] = true;\n\n        var _styleToCss = function (style) {\n            switch (style) {\n                case IFFont.Style.Normal:\n                    return 'normal';\n                case IFFont.Style.Italic:\n                    return 'italic';\n                default:\n                    throw new Error('Unknown style');\n            }\n        };\n\n        // Start loading of font and add variant when done\n        var request = new XMLHttpRequest();\n        request.open('get', url);\n        request.responseType = 'arraybuffer';\n        request.onload = function () {\n            if (request.response && request.response instanceof ArrayBuffer) {\n                var font = opentype.parse(request.response);\n                if (font && font.supported) {\n                    // Insert our variant\n                    type.variants[variant] = {\n                        url: url,\n                        font: font,\n                        outlines: {}\n                    };\n\n                    // Inject a new font-face style\n                    $('<style></style>')\n                        .attr('type', 'text/css')\n                        .text('@font-face {' +\n                            'font-family: \"' + family + '\";' +\n                            'src: url(\"' + url + '\");' +\n                            'font-weight: ' + weight.toString() + ';' +\n                            'font-style: ' + _styleToCss(style) + ';' +\n                            '} ')\n                        .appendTo($('body'));\n\n                    // Sucks but inject an invisible span to ensure the font gets loaded\n                    $('<span></span>')\n                        .css({\n                            'position': 'absolute',\n                            'opacity': '0',\n                            'font-family': family,\n                            'font-weight': weight.toString(),\n                            'font-style': _styleToCss(style)\n                        })\n                        .text('.')\n                        .appendTo($('body'));\n                }\n            }\n        };\n        request.send();\n    };\n\n    /**\n     * Returns an alphabetically sorted list of\n     * available font families\n     */\n    IFFont.prototype.getFamilies = function () {\n        var families = Object.keys(this._types);\n        families.sort();\n        return families;\n    };\n\n    /**\n     * Returns the typeface category for a given family\n     * @param {String} family\n     * @returns {IFFont.Category}\n     */\n    IFFont.prototype.getCategory = function (family) {\n        var type = this._types[family];\n        if (type) {\n            return type.category;\n        }\n        return IFFont.Category.Other;\n    };\n\n    /**\n     * Returns all available styles for a given family\n     * @param {String} family the family to query for\n     * @return {Array<IFFont.Style>} null if there's\n     * no such font-family or an array of available styles for the\n     * given family\n     */\n    IFFont.prototype.getStyles = function (family) {\n        var type = this._types[family];\n        if (type) {\n            return Object.keys(type.styles);\n        }\n        return null;\n    };\n\n    /**\n     * Returns all available weights for a given family\n     * @param {String} family the family to query for\n     * @return {Array<IFFont.Weight>} null if there's\n     * no such font-family or an array of available weights for the\n     * given family\n     */\n    IFFont.prototype.getWeights = function (family) {\n        var type = this._types[family];\n        if (type) {\n            var weights = Object.keys(type.weights);\n            var result = [];\n            for (var i = 0; i < weights.length; ++i) {\n                result.push(parseInt(weights[i]));\n            }\n            result.sort();\n            return result;\n        }\n        return null;\n    };\n\n    /**\n     * Returns a variant for a given family, style and weight\n     * @param {String} family the family to query for\n     * @param {IFFont.Style} style the style of the variant\n     * @param {IFFont.Weight} weight the weight of the variant\n     * @param {Boolean} [matchExact] if set, no variant will be returned\n     * if there's no exact match of the parameters, otherwise a closest\n     * matching variant will be returned. Defaults to false.\n     * @return {String} null if there's no such family. Otherwise a variant\n     * that either exactly matches the given parameters or the closest\n     * matching variant if matchExact is set to false\n     */\n    IFFont.prototype.getVariant = function (family, style, weight, matchExact) {\n        var type = this._types[family];\n        if (type) {\n            if (!type.styles.hasOwnProperty(style) && !matchExact) {\n                style = IFFont.Style.Normal;\n            }\n\n            weight = typeof weight === 'number' ? weight : parseInt(weight);\n\n            if (!matchExact) {\n                while (!type.weights.hasOwnProperty(weight) && weight >= 100) {\n                    weight -= 100;\n                }\n                while (!type.weights.hasOwnProperty(weight) && weight <= 900) {\n                    weight += 100;\n                }\n            }\n\n            var variant = style + weight.toString();\n\n            if (type.variants.hasOwnProperty(variant)) {\n                return variant;\n            }\n        }\n        return null;\n    };\n\n    /**\n     *\n     * @param family\n     * @param variant\n     * @param size\n     * @param char\n     * @returns {number}\n     */\n    IFFont.prototype.getGlyphBaseline = function (family, variant, size, char) {\n        var font = this._types[family].variants[variant].font;\n        var glyph = font.charToGlyph(char);\n        var scale = 1 / font.unitsPerEm * size;\n        var height = (glyph.yMax - glyph.yMin) * scale;\n        return height + (((font.ascender) * scale) - height);\n    };\n\n    /**\n     *\n     * @param family\n     * @param variant\n     * @param size\n     * @param x\n     * @param y\n     * @param char\n     * @returns {IFVertexSource}\n     */\n    IFFont.prototype.getGlyphOutline = function (family, variant, size, x, y, char) {\n        var fontVariant = this._types[family].variants[variant];\n        var font = fontVariant.font;\n        var outline = fontVariant.outlines[char];\n        var scale = 1 / font.unitsPerEm * size;\n\n        if (!outline) {\n            var glyph = font.charToGlyph(char);\n            var path = glyph.getPath(0, 0, font.unitsPerEm);\n            outline = new IFVertexContainer();\n            fontVariant.outlines[char] = outline;\n\n            for (var i = 0; i < path.commands.length; i += 1) {\n                var cmd = path.commands[i];\n                if (cmd.type === 'M') {\n                    outline.addVertex(IFVertex.Command.Move, cmd.x, cmd.y);\n                } else if (cmd.type === 'L') {\n                    outline.addVertex(IFVertex.Command.Line, cmd.x, cmd.y);\n                } else if (cmd.type === 'C') {\n                    outline.addVertex(IFVertex.Command.Curve2, cmd.x, cmd.y);\n                    outline.addVertex(IFVertex.Command.Curve2, cmd.x1, cmd.y1);\n                    outline.addVertex(IFVertex.Command.Curve2, cmd.x2, cmd.y2);\n                } else if (cmd.type === 'Q') {\n                    outline.addVertex(IFVertex.Command.Curve, cmd.x, cmd.y);\n                    outline.addVertex(IFVertex.Command.Curve, cmd.x1, cmd.y1);\n                } else if (cmd.type === 'Z') {\n                    outline.addVertex(IFVertex.Command.Close);\n                }\n            }\n        }\n\n        return new IFVertexTransformer(outline, new IFTransform(scale, 0, 0, scale, x, y));\n    };\n\n\n    _.IFFont = IFFont;\n    _.ifFont = new IFFont();\n})(this);"
  },
  {
    "path": "src/infinity/paint/gradient.js",
    "content": "(function (_) {\n    /**\n     * A class representing a color gradient\n     * @class IFGradient\n     * @extends IFPattern\n     * @constructor\n     */\n    function IFGradient(stops, type) {\n        if (stops) {\n            this._stops = [];\n            for (var i = 0; i < stops.length; ++i) {\n                this._stops.push({\n                    position: stops[i].position < 0 ? 0 : stops[i].position > 100 ? 100 : stops[i].position,\n                    color: stops[i].color\n                });\n            }\n        } else {\n            this._stops = [new IFColor(IFColor.Type.Black), new IFColor(IFColor.Type.White)];\n        }\n\n        this._type = type ? type : IFGradient.Type.Linear;\n    }\n\n    IFObject.inherit(IFGradient, IFPattern);\n\n    /**\n     * @enum\n     */\n    IFGradient.Type = {\n        Linear: 'L',\n        Radial: 'R'\n    };\n\n    /**\n     * Parse a string into a IFGradient\n     * @param {String} string\n     * @return {IFGradient}\n     */\n    IFGradient.parseGradient = function (string) {\n        if (!string || string === \"\") {\n            return null;\n        }\n\n        var blob = JSON.parse(string);\n        if (blob) {\n            var result = new IFGradient();\n\n            result._type = blob.t;\n            result._stops = [];\n\n            for (var i = 0; i < blob.s.length; ++i) {\n                var stop = blob.s[i];\n                result._stops.push({\n                    position: stop.p,\n                    color: IFColor.parseColor(stop.c)\n                })\n            }\n\n            return result;\n        }\n\n        return null;\n    };\n\n    /**\n     * Compare two gradients for equality Also takes care of null parameters\n     * @param {IFGradient} left left side gradient\n     * @param {IFGradient} right right side gradient\n     * @param {Boolean} [stopsOnly] if set, gradients are equal if their stop\n     * values are equal no matter of their type, defaults to false\n     * @return {Boolean} true if left and right are equal (also if they're null!)\n     */\n    IFGradient.equals = function (left, right, stopsOnly) {\n        if (!left && left === right) {\n            return true;\n        } else if (left && right) {\n            if (!stopsOnly) {\n                if (left._type !== right._type) {\n                    return false;\n                }\n            }\n\n            if (left._stops.length !== right._stops.length) {\n                return false;\n            }\n\n            var s1 = left._stops;\n            var s2 = right._stops;\n            for (var i = 0; i < s1.length; ++i) {\n                if (s1[i].position !== s2[i].position) {\n                    return false;\n                }\n\n                if (!IFColor.equals(s1[i].color, s2[i].color)) {\n                    return false;\n                }\n            }\n        }\n        return false;\n    };\n\n    /**\n     * @type {Array<{{position: Number, color: IFColor}}>}\n     * @private\n     */\n    IFGradient.prototype._stops = null;\n\n    /** @override */\n    IFGradient.prototype.getPatternType = function () {\n        return IFPattern.Type.Gradient;\n    };\n\n    /**\n     * @return {IFGradient.Type}\n     */\n    IFGradient.prototype.getType = function () {\n        return this._type;\n    };\n\n    /**\n     * You may modify the return value though this class\n     * is supposed to be immutable so ensure you know what\n     * you are actually doing!!\n     * @returns {Array<{{position: Number, color: IFColor}}>}\n     */\n    IFGradient.prototype.getStops = function () {\n        return this._stops;\n    };\n\n    /**\n     * Return string representation of the underlying gradient\n     * @return {String}\n     */\n    IFGradient.prototype.asString = function () {\n        var stops = [];\n        for (var i = 0; i < this._stops.length; ++i) {\n            stops.push({\n                p: this._stops[i].position,\n                c: this._stops[i].color.asString()\n            })\n        }\n\n        var blob = {\n            t: this._type,\n            s: stops\n        };\n\n        return JSON.stringify(blob);\n    };\n\n    /**\n     * Return CSS-Compatible string representation of the underlying gradient\n     * stops separated by comma\n     * @return {String}\n     */\n    IFGradient.prototype.asCSSString = function () {\n        var cssStops = [];\n\n        for (var i = 0; i < this._stops.length; ++i) {\n            var stop = this._stops[i];\n            cssStops.push('' + stop.color.asCSSString() + ' ' + stop.position + '%');\n        }\n\n        return cssStops.join(', ');\n    };\n\n    /**\n     * Return CSS-Compatible string representation of the underlying gradient\n     * including the gradient declaration used for css background\n     * @return {String}\n     */\n    IFGradient.prototype.asCSSBackgroundString = function () {\n        var cssStops = this.asCSSString();\n        switch (this._type) {\n            case IFGradient.Type.Radial:\n                return 'radial-gradient(ellipse at center, ' + cssStops + ')';\n            default:\n                return 'linear-gradient(90deg, ' + cssStops + ')';\n        }\n    };\n\n    /** @override */\n    IFGradient.prototype.toString = function () {\n        return \"[Object IFGradient]\";\n    };\n\n    _.IFGradient = IFGradient;\n})(this);"
  },
  {
    "path": "src/infinity/paint/paintcanvas.js",
    "content": "(function (_) {\n    /**\n     * A canvas wrapper to paint onto\n     * @class IFPaintCanvas\n     * @extends IFObject\n     * @constructor\n     */\n    function IFPaintCanvas() {\n        var canvasElement = document.createElement(\"canvas\");\n        this._canvasContext = canvasElement.getContext(\"2d\");\n    }\n\n    IFObject.inherit(IFPaintCanvas, IFObject);\n\n    /**\n     * @enum\n     */\n    IFPaintCanvas.LineCap = {\n        Butt: 'butt',\n        Round: 'round',\n        Square: 'square'\n    };\n\n    /**\n     * @enum\n     */\n    IFPaintCanvas.LineJoin = {\n        Miter: 'miter',\n        Bevel: 'bevel',\n        Round: 'round'\n    };\n\n    /**\n     * @enum\n     */\n    IFPaintCanvas.BlendMode = {\n        Normal: 'normal',\n        Multiply: 'multiply',\n        Screen: 'screen',\n        Overlay: 'overlay',\n        Darken: 'darken',\n        Lighten: 'lighten',\n        ColorDodge: 'color-dodge',\n        ColorBurn: 'color-burn',\n        HardLight: 'hard-light',\n        SoftLight: 'soft-light',\n        Difference: 'difference',\n        Exclusion: 'exclusion',\n        Hue: 'hue',\n        Saturation: 'saturation',\n        Color: 'color',\n        Luminosity: 'luminosity'\n    };\n\n    /**\n     * @enum\n     */\n    IFPaintCanvas.CompositeOperator = {\n        /**\n         * Displays the source image over the destination image\n         * @type {Number}\n         * @version 1.0\n         */\n        SourceOver: 'source-over',\n\n        /**\n         * Displays the source image on top of the destination image.\n         * The part of the source image that is outside the destination image is not shown\n         * @type {Number}\n         * @version 1.0\n         */\n        SourceAtTop: 'source-atop',\n\n        /**\n         * Displays the source image in to the destination image. Only the part of the source image that is\n         * INSIDE the destination image is shown, and the destination image is transparent\n         * @type {Number}\n         * @version 1.0\n         */\n        SourceIn: 'source-in',\n\n        /**\n         * Displays the source image out of the destination image. Only the part of the source image that is\n         * OUTSIDE the destination image is shown, and the destination image is transparent\n         * @type {Number}\n         * @version 1.0\n         */\n        SourceOut: 'source-out',\n\n        /**\n         * Displays the destination image over the source image\n         * @type {Number}\n         * @version 1.0\n         */\n        DestinationOver: 'destination-over',\n\n        /**\n         * Displays the destination image on top of the source image. The part of the destination image\n         * that is outside the source image is not shown\n         * @type {Number}\n         * @version 1.0\n         */\n        DestinationAtTop: 'destination-atop',\n\n        /**\n         * Displays the destination image in to the source image. Only the part of the destination image that is\n         * INSIDE the source image is shown, and the source image is transparent\n         * @type {Number}\n         * @version 1.0\n         */\n        DestinationIn: 'destination-in',\n\n        /**\n         * Displays the destination image out of the source image. Only the part of the destination image that is\n         * OUTSIDE the source image is shown, and the source image is transparent\n         * @type {Number}\n         * @version 1.0\n         */\n        DestinationOut: 'destination-out',\n\n        /**\n         * Displays the source image. The destination image is ignored\n         * @type {Number}\n         * @version 1.0\n         */\n        Copy: 'copy',\n\n        /**\n         * The source image is combined by using an exclusive OR with the destination image\n         * @type {Number}\n         * @version 1.0\n         */\n        Xor: 'xor',\n\n        /**\n         * Displays the source image + the destination image making the intersection lighter\n         * @type {Number}\n         * @version 1.0\n         */\n        Lighter: 'lighter',\n\n        /**\n         * Displays the source image + the destination image making the intersection darker\n         * @type {Number}\n         * @version 1.0\n         */\n        Darker: 'darker'\n    };\n\n    /**\n     * A repeat mode of patterns and gradients\n     * @enum\n     */\n    IFPaintCanvas.RepeatMode = {\n        /** Horizontal and vertical repeat */\n        Both: 'repeat',\n        /** Horizontal repeat */\n        Horizontal: 'repeat-x',\n        /** Vertical repeat */\n        Vertical: 'repeat-y',\n        /** No repeat */\n        None: 'no-repeat'\n    };\n\n    function createChessboardCanvas(size, backColor, foreColor) {\n        var result = document.createElement('canvas');\n        result.width = size * 2;\n        result.height = size * 2;\n        var context = result.getContext('2d');\n        context.fillStyle = backColor;\n        context.fillRect(0, 0, result.width, result.height);\n        context.fillStyle = foreColor;\n        context.fillRect(0, 0, size, size);\n        context.fillRect(size, size, size, size);\n        return result;\n    };\n\n    IFPaintCanvas.createChessboard = function (size, backColor, foreColor) {\n        var result = document.createElement('canvas');\n        result.width = size * 2;\n        result.height = size * 2;\n        var context = result.getContext('2d');\n        context.fillStyle = backColor;\n        context.fillRect(0, 0, result.width, result.height);\n        context.fillStyle = foreColor;\n        context.fillRect(0, 0, size, size);\n        context.fillRect(size, size, size, size);\n        return result;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFPaintCanvas Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type CanvasRenderingContext2D\n     * @private\n     */\n    IFPaintCanvas.prototype._canvasContext = null;\n\n    /**\n     * @type {IFBitmap}\n     * @private\n     */\n    IFPaintCanvas.prototype._bitmap = null;\n\n    /**\n     * @type IFTransform\n     * @private\n     */\n    IFPaintCanvas.prototype._transform = null;\n\n    /**\n     * @type IFPoint\n     * @private\n     */\n    IFPaintCanvas.prototype._offset = null;\n\n    /**\n     * @type IFPoint\n     * @private\n     */\n    IFPaintCanvas.prototype._origin = null;\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFPaintCanvas.prototype._scale = null;\n\n    /**\n     * @type Array<IFRect>\n     * @private\n     */\n    IFPaintCanvas.prototype._areas = null;\n\n    /**\n     * @return {Number} the width of the canvas\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.getWidth = function () {\n        return this._canvasContext.canvas.width;\n    };\n\n    /**\n     * @return {Number} the height of the canvas\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.getHeight = function () {\n        return this._canvasContext.canvas.height;\n    };\n\n    /**\n     * Returns the underlying bitmap of the canvas\n     * for direct pixel manipulation. This operation\n     * is cheap and doesn't allocate any memory\n     * @returns {IFBitmap}\n     */\n    IFPaintCanvas.prototype.getBitmap = function () {\n        if (!this._bitmap) {\n            this._bitmap = new IFBitmap(this);\n        }\n        return this._bitmap;\n    };\n\n    /**\n     * Returns the contents of the canvas as a png image\n     * with a resolution of 96dpi as a base64\n     * encoded data url\n     * @return {String}\n     */\n    IFPaintCanvas.prototype.asPNGImage = function () {\n        return this._canvasContext.canvas.toDataURL('image/png');\n    };\n\n    /**\n     * Returns the contents of the canvas as a jpeg image\n     * with a resolution of 96dpi as a base64\n     * encoded data url\n     * @param {Number} [quality] the quality of the image from\n     * 0.0 to 1.0, defaults to 1.0\n     * @return {String}\n     */\n    IFPaintCanvas.prototype.asJPEGImage = function (quality) {\n        quality = quality || 1.0;\n        return this._canvasContext.canvas.toDataURL('image/jpeg', quality);\n    };\n\n    /**\n     * Returns the contents of the canvas as a png image\n     * with a resolution of 96dpi as an ArrayBuffer\n     * @param {Function} done callback function called with the ArrayBuffer\n     */\n    IFPaintCanvas.prototype.asPNGImageBuffer = function (done) {\n        this._canvasContext.canvas.toBlob(function (blob) {\n            var reader = new FileReader();\n            reader.onload = function (event) {\n                done(event.target.result);\n            };\n            reader.readAsArrayBuffer(blob);\n        }, 'image/png');\n    };\n\n    /**\n     * Returns the contents of the canvas as a jpeg image\n     * with a resolution of 96dpi as an ArrayBuffer\n     * @param {Function} done callback function called with the ArrayBuffer\n     * @param {Number} [quality] the quality of the image from\n     * 0.0 to 1.0, defaults to 1.0\n     */\n    IFPaintCanvas.prototype.asJPEGImageBuffer = function (done, quality) {\n        quality = quality || 1.0;\n        this._canvasContext.canvas.toBlob(function (blob) {\n            var reader = new FileReader();\n            reader.onload = function (event) {\n                done(event.target.result);\n            };\n            reader.readAsArrayBuffer(blob);\n        }, 'image/jpeg', quality);\n    };\n\n    /**\n     * Resize this canvas\n     * @param {Number} width the new width for the canvas\n     * @param {Number} height the new height for the canvas\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.resize = function (width, height) {\n        if (width != this._canvasContext.canvas.width || height != this._canvasContext.canvas.height) {\n            this._canvasContext.canvas.width = width;\n            this._canvasContext.canvas.height = height;\n        }\n    };\n\n    /**\n     * Returns the offset of this canvas\n     * @returns {IFPoint}\n     */\n    IFPaintCanvas.prototype.getOffset = function () {\n        return this._offset;\n    };\n\n    /**\n     * Assigns the offset of this canvas\n     * @param {IFPoint} origin\n     */\n    IFPaintCanvas.prototype.setOffset = function (offset) {\n        this._offset = offset;\n    };\n\n    /**\n     * Returns the origin of this canvas\n     * @returns {IFPoint}\n     */\n    IFPaintCanvas.prototype.getOrigin = function () {\n        return this._origin;\n    };\n\n    /**\n     * Assigns the origin of this canvas. The origin\n     * will always be premultiplied with any transformation.\n     * @param {IFPoint} origin\n     */\n    IFPaintCanvas.prototype.setOrigin = function (origin) {\n        if (!IFPoint.equals(origin, this._origin)) {\n            this._origin = origin;\n            this._updateTransform();\n        }\n    };\n\n    /**\n     * Returns the scalation of this canvas\n     * @returns {Number}\n     */\n    IFPaintCanvas.prototype.getScale = function () {\n        return this._scale;\n    };\n\n    /**\n     * Assigns the scalation of this canvas. The scalation\n     * will always be premultiplied with any transformation.\n     * @param {IFPoint} origin\n     */\n    IFPaintCanvas.prototype.setScale = function (scale) {\n        if (scale !== this._scale) {\n            this._scale = scale;\n            this._updateTransform();\n        }\n    };\n\n    /**\n     * Return the current transform of the canvas, may never be null\n     * @param {Boolean} [local] if provided, returns only the local\n     * transformation which excludes the canvas' origin and scalation.\n     * This parameter defaults to false, thus returns the global transform.\n     * @return {IFTransform} current transform\n     */\n    IFPaintCanvas.prototype.getTransform = function (local) {\n        var transform = this._transform;\n        if (!local) {\n            var tx = this._origin.getX();\n            var ty = this._origin.getY();\n            var s = this._scale;\n            transform = transform.multiplied(new IFTransform().scaled(s, s).translated(-tx, -ty));\n        }\n        return transform;\n    };\n\n    /**\n     * Assign a new transformation to the canvas\n     * @param {IFTransform} transform the new transform to assign. If this\n     * is null, then the identiy transformation is used assigned instead\n     * @return {IFTransform} the old transform before assignment\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.setTransform = function (transform) {\n        if (transform == null) {\n            // Use identity transform\n            transform = new IFTransform();\n        }\n        var oldTransform = this._transform;\n        this._transform = transform;\n        this._updateTransform();\n\n        return oldTransform;\n    };\n\n    /**\n     * Reset the transformation to the identity transformation\n     * @return {IFTransform} the old transform before reset\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.resetTransform = function () {\n        return this.setTransform(null);\n    };\n\n    /**\n     * This needs to be called when the canvas should prepare\n     * itself for painting.\n     * @param {Array<IFRect>} areas an array of areas to be painted.\n     * those will be used for clipping any painting as well for\n     * clearing those regions before anything else. Note that you need\n     * to enforce to provide integer based rectangles only as internally,\n     * the canvas may need to convert into integers first which may\n     * result in rounding errors otherwise\n     */\n    IFPaintCanvas.prototype.prepare = function (areas) {\n        // save context before anything else\n        this._canvasContext.save();\n\n        // Reset some stuff\n        this._transform = new IFTransform();\n        this._origin = new IFPoint(0, 0);\n        this._scale = 1.0;\n        this._areas = areas ? areas.slice() : null;\n        this._updateTransform();\n\n        // Clip and clear our areas if any\n        if (areas && areas.length > 0) {\n            this._canvasContext.beginPath();\n            for (var i = 0; i < areas.length; ++i) {\n                var rect = areas[i];\n\n                var xMin = rect.getX();\n                var xMax = xMin + rect.getWidth();\n                var yMin = rect.getY();\n                var yMax = yMin + rect.getHeight();\n\n                // Clip to our own extents\n                xMin = Math.max(0, xMin);\n                xMax = Math.min(this.getWidth(), xMax);\n                yMin = Math.max(0, yMin);\n                yMax = Math.min(this.getHeight(), yMax);\n\n                // Add path\n                this._canvasContext.moveTo(xMin, yMin);\n                this._canvasContext.lineTo(xMax, yMin);\n                this._canvasContext.lineTo(xMax, yMax);\n                this._canvasContext.lineTo(xMin, yMax);\n                this._canvasContext.lineTo(xMin, yMin);\n                this._canvasContext.clearRect(xMin, yMin, xMax - xMin, yMax - yMin);\n            }\n            this._canvasContext.clip();\n        } else {\n            this._canvasContext.clearRect(0, 0, this.getWidth(), this.getHeight());\n        }\n    };\n\n    /**\n     * This needs to be called when the canvas is finished\n     * and should restore.\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.finish = function () {\n        this._canvasContext.restore();\n        this._transform = null;\n        this._origin = null;\n        this._scale = null;\n        this._areas = null;\n    };\n\n    /**\n     * Trim the canvas size for either a given area or\n     * if no area is provided trims the canvas to remove\n     * all transparent pixels on each side\n     * @param {IFRect} [area]\n     */\n    IFPaintCanvas.prototype.trim = function (area) {\n        alert('todo: trim_canvas');\n    };\n\n    /**\n     * Creates a temporary canvas with the given extents.\n     * The returned canvas will be compatible to this canvas\n     * and thus, will prepared in the same way as this one\n     * including the current zoom level and dirty areas. Note that the\n     * canvas will include a transformation so that the\n     * extent's x/y coordinates are equal to 0,0. Temporary canvases\n     * should never be used i.e. for effects as they might be cut off.\n     * @param {IFRect} extents the extents for the requested canvas\n     * Defaults to false.\n     */\n    IFPaintCanvas.prototype.createCanvas = function (extents, clipDirty) {\n        var result = new IFPaintCanvas();\n\n        // Convert extents into this canvas' coordinates and clip accordingly\n        var paintExtents = this.getTransform(false).mapRect(extents);\n        var left = paintExtents.getX();\n        var top = paintExtents.getY();\n        var width = paintExtents.getWidth();\n        var height = paintExtents.getHeight();\n\n        if (top < 0) {\n            height += top;\n            top = 0;\n        }\n\n        if (left < 0) {\n            width += left;\n            left = 0;\n        }\n\n        if (left + width > this.getWidth()) {\n            width = this.getWidth() - left;\n        }\n\n        if (top + height > this.getHeight()) {\n            height = this.getHeight() - top;\n        }\n\n        var sceneExtents = this.getTransform(false).inverted().mapRect(new IFRect(left, top, width, height));\n\n        var finalExtents = new IFRect(\n            sceneExtents.getX() * this._scale,\n            sceneExtents.getY() * this._scale,\n            sceneExtents.getWidth() * this._scale,\n            sceneExtents.getHeight() * this._scale\n        );\n\n        // Resize canvas including our scalation plus a small tolerance factor\n        result.resize(finalExtents.getWidth(), finalExtents.getHeight());\n\n        var areas = null;\n        if (clipDirty && this._areas) {\n            areas = [];\n            for (var i = 0; i < this._areas.length; ++i) {\n                areas.push(this._areas[i].translated(-left, -top));\n            }\n        }\n\n        // Let canvas prepare itself\n        result.prepare(areas);\n\n        // Set result's origin and scalation\n        var topLeft = finalExtents.getSide(IFRect.Side.TOP_LEFT);\n        result.setOrigin(topLeft);\n        result.setOffset(topLeft);\n        result.setScale(this._scale);\n\n        // Finally return our new canvas\n        return result;\n    };\n\n    /**\n     * Clears the whole canvas to be fully transparent\n     */\n    IFPaintCanvas.prototype.clear = function () {\n        var clearRect = this.getTransform(false).inverted().mapRect(new IFRect(0, 0, this.getWidth(), this.getHeight()));\n        this._canvasContext.clearRect(clearRect.getX(), clearRect.getY(), clearRect.getWidth(), clearRect.getHeight());\n    };\n\n    /**\n     * Draw a canvas on this one. The canvas will be painted at it's given\n     * offset position including the delta parameters. If the given canvas' scale\n     * is != 100%, the canvas will draw it at 100%\n     * @param {IFPaintCanvas} canvas\n     * @param {Number} [dx]\n     * @param {Number} [dy]\n     * @param {Number} [opacity]\n     * @param {IFPaintCanvas.CompositeOperator|IFPaintCanvas.BlendMode} [cmpOrBlend]\n     * @param {Boolean} [clear] if true, the underlying area the canvas will be put onto\n     * will be cleared first with transparent alpha values. Defaults to false.\n     */\n    IFPaintCanvas.prototype.drawCanvas = function (canvas, dx, dy, opacity, cmpOrBlend, clear) {\n        // Make sure to reset scale when drawing canvases + make non smooth\n        var hadSmooth = this._getImageSmoothingEnabled();\n        var oldScale = this._scale;\n        this._setImageSmoothingEnabled(oldScale < 1);\n        if (canvas.getScale() !== 1.0) {\n            this.setScale(1);\n        }\n        var oldTransform = this.resetTransform();\n        var oldTranslation = oldTransform ? oldTransform.getTranslation() : new IFPoint(0,0);\n\n        dx = dx | 0;\n        dy = dy | 0;\n\n        var offset = canvas.getOffset();\n        var x = offset ? offset.getX() : 0 | 0;\n        var y = offset ? offset.getY() : 0 | 0;\n        var w = canvas.getWidth();\n        var h = canvas.getHeight();\n        var canvasScale = canvas.getScale();\n        canvasScale = canvasScale ? canvasScale : 1.0;\n\n        x += dx + oldTranslation.getX() * canvasScale;\n        y += dy + oldTranslation.getY() * canvasScale;\n\n        if (clear) {\n            this._canvasContext.clearRect(x, y, w, h);\n        }\n\n        this._canvasContext.globalAlpha = typeof opacity == \"number\" ? opacity : 1.0;\n\n        this._canvasContext.globalCompositeOperation = cmpOrBlend ? cmpOrBlend : IFPaintCanvas.CompositeOperator.SourceOver;\n\n        this._canvasContext.drawImage(canvas._canvasContext.canvas, 0, 0, w, h,\n            x, y, w, h);\n\n        this.setTransform(oldTransform);\n        this.setScale(oldScale);\n        this._setImageSmoothingEnabled(hadSmooth);\n    };\n\n    /**\n     * Creates and returns a texture pattern\n     *\n     * @param {Image|IFPaintCanvas} image the image or canvas for the texture\n     * @param {IFPaintCanvas.RepeatMode} [repeat] the repeat mode, defaults\n     * to IFPaintCanvas.RepeatMode.Both\n     */\n    IFPaintCanvas.prototype.createTexture = function (image, repeat) {\n        repeat = repeat || IFPaintCanvas.RepeatMode.Both;\n        image = this._convertImage(image);\n        return this._canvasContext.createPattern(image, repeat);\n    };\n\n    /**\n     * Creates and returns a linear gradient pattern\n     * @param {Number} x1 horizontal start position\n     * @param {Number} y1 vertical start position\n     * @param {Number} x2 horizontal end position\n     * @param {Number} y2 vertical end position\n     * @param {IFGradient} gradient the gradient to be used\n     * @return {*} a pattern specific to this canvas-type\n     */\n    IFPaintCanvas.prototype.createLinearGradient = function (x1, y1, x2, y2, gradient) {\n        var result = this._canvasContext.createLinearGradient(x1, y1, x2, y2);\n        var stops = gradient.getStops();\n\n        for (var i = 0; i < stops.length; ++i) {\n            result.addColorStop(stops[i].position / 100.0, stops[i].color.asCSSString());\n        }\n\n        return result;\n    };\n\n    /**\n     * Creates and returns a radial gradient pattern\n     * @param {Number} cx the radial gradient's horizontal center position\n     * @param {Number} cy the radial gradient's vertical center position\n     * @param {Number} radius the radial gradient's radius\n     * @param {IFGradient} gradient the gradient to be used\n     * @return {*} a pattern specific to this canvas-type\n     */\n    IFPaintCanvas.prototype.createRadialGradient = function (cx, cy, radius, gradient) {\n        var result = this._canvasContext.createRadialGradient(cx, cy, 0, cx, cy, radius);\n        var stops = gradient.getStops();\n\n        for (var i = 0; i < stops.length; ++i) {\n            result.addColorStop(stops[i].position / 100.0, stops[i].color.asCSSString());\n        }\n\n        return result;\n    };\n\n    /**\n     * Use a rectangle source as clipping region (adds to the current one)\n     * @param {Number} x x-position of rectangle\n     * @param {Number} y y-position of rectangle\n     * @param {Number} width width of rectangle\n     * @param {Number} height height of rectangle\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.clipRect = function (x, y, width, height) {\n        // Too bad we need to use expensive save() / restore() on canvas for now for clipping :(\n        this._canvasContext.save();\n\n        this._canvasContext.beginPath();\n        this._canvasContext.moveTo(x, y);\n        this._canvasContext.lineTo(x + width, y);\n        this._canvasContext.lineTo(x + width, y + height);\n        this._canvasContext.lineTo(x, y + height);\n        this._canvasContext.lineTo(x, y);\n        this._canvasContext.clip();\n    };\n\n    /**\n     * Reset the last assigned clipping region\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.resetClip = function () {\n        this._canvasContext.restore();\n    };\n\n    /**\n     * Pushes a vertex source into this canvas overwriting any\n     * previously added vertices. This will act as source for different\n     * functions like clipVertices, strokeVertices and fillVertices\n     * @param {IFVertexSource} vertexSource the vertex source to use for clipping\n     */\n    IFPaintCanvas.prototype.putVertices = function (vertexSource) {\n        if (vertexSource.rewindVertices(0)) {\n            this._canvasContext.beginPath();\n\n            var vertex = new IFVertex();\n            while (vertexSource.readVertex(vertex)) {\n                switch (vertex.command) {\n                    case IFVertex.Command.Move:\n                        this._canvasContext.moveTo(vertex.x, vertex.y);\n                        break;\n                    case IFVertex.Command.Line:\n                        this._canvasContext.lineTo(vertex.x, vertex.y);\n                        break;\n                    case IFVertex.Command.Curve:\n                    {\n                        var xTo = vertex.x;\n                        var yTo = vertex.y;\n                        if (vertexSource.readVertex(vertex)) {\n                            this._canvasContext.quadraticCurveTo(vertex.x, vertex.y, xTo, yTo);\n                        }\n                    }\n                        break;\n                    case IFVertex.Command.Curve2:\n                    {\n                        var xTo = vertex.x;\n                        var yTo = vertex.y;\n                        if (vertexSource.readVertex(vertex)) {\n                            var cx1 = vertex.x;\n                            var cy1 = vertex.y;\n                            if (vertexSource.readVertex(vertex)) {\n                                this._canvasContext.bezierCurveTo(cx1, cy1, vertex.x, vertex.y, xTo, yTo);\n                            }\n                        }\n                    }\n                        break;\n                    case IFVertex.Command.Close:\n                        this._canvasContext.closePath();\n                        break;\n                    default:\n                        throw new Error(\"Unknown Command Type - \" + vertex.command);\n                }\n            }\n        }\n    };\n\n    /**\n     * Stroke the current vertices\n     * @param {*} stroke the stroke to be used which may not be unspecified and/or null. Providing\n     * a number will interpret the number as a 32-Bit RGBA Integer Value.\n     * @param {Number} [width] the width of the stroke in pixelMode. If not provided, defaults to 1.0 pixelMode\n     * @param {Number} [cap] the line cap used for stroking, defaults to IFPaintCanvas.LineCap.Butt\n     * @param {Number} [join] the line join used for stroking\n     * @param {Number} [miterLimit] the miter limit used for stroking\n     * @param {Number} [opacity] the total opacity to use for painting, defaults to 1.0 (full opaque)\n     * @param {IFPaintCanvas.CompositeOperator|IFPaintCanvas.BlendMode} [cmpOrBlend]\n     * @see IFPaintCanvas.LineCap\n     * @see IFPaintCanvas.LineJoin\n     * @see IFPaintCanvas.StrokeAlignment\n     * @see IFPaintCanvas.CompositeOperator\n     */\n    IFPaintCanvas.prototype.strokeVertices = function (stroke, width, cap, join, miterLimit, opacity, cmpOrBlend) {\n        this._canvasContext.strokeStyle = this._convertStyle(stroke);\n\n        if (typeof width == \"number\") {\n            this._canvasContext.lineWidth = width;\n        } else {\n            this._canvasContext.lineWidth = 1.0;\n        }\n\n\n        this._canvasContext.lineCap = cap ? cap : \"butt\";\n        this._canvasContext.lineJoin = join ? join : \"miter\";\n        this._canvasContext.miterLimit = typeof miterLimit == 'number' ? miterLimit : 10;\n\n        this._canvasContext.globalAlpha = typeof opacity == \"number\" ? opacity : 1.0;\n\n        this._canvasContext.globalCompositeOperation = cmpOrBlend ? cmpOrBlend : IFPaintCanvas.CompositeOperator.SourceOver;\n\n        this._canvasContext.stroke();\n    };\n\n    /**\n     * Fill the current vertices\n     * @param {*} [fill] the fill to be used which may not be unspecified and/or null. Providing\n     * a number will interpret the number as a 32-Bit RGBA Integer Value.\n     * @param {Number} [opacity] the total opacity to use for painting, defaults to 1.0 (full opaque)\n     * @param {IFPaintCanvas.CompositeOperator|IFPaintCanvas.BlendMode} [cmpOrBlend]\n     */\n    IFPaintCanvas.prototype.fillVertices = function (fill, opacity, cmpOrBlend) {\n        // save fill to avoid expensive recalculation\n        this._canvasContext.fillStyle = this._convertStyle(fill);\n\n        this._canvasContext.globalAlpha = typeof opacity == \"number\" ? opacity : 1.0;\n\n        this._canvasContext.globalCompositeOperation = cmpOrBlend ? cmpOrBlend : IFPaintCanvas.CompositeOperator.SourceOver;\n\n        this._canvasContext.fill();\n    };\n\n    /**\n     * Function to fill the whole canvas with a given fill.\n     * @param {*} [fill] the fill, defaults to full opaque black\n     */\n    IFPaintCanvas.prototype.fillCanvas = function (fill) {\n        var fillRect = this.getTransform(false).inverted().mapRect(new IFRect(0, 0, this.getWidth(), this.getHeight()));\n        this.fillRect(fillRect.getX(), fillRect.getY(), fillRect.getWidth(), fillRect.getHeight(), fill);\n    };\n\n    /**\n     * Function to fill a rectangle with fill. This does not care about\n     * any special operations like composite and the such though the rectangle\n     * gets transformed into the current space.\n     *\n     * @param {Number} x x-position of rectangle\n     * @param {Number} y y-position of rectangle\n     * @param {Number} width width of rectangle\n     * @param {Number} height height of rectangle\n     * @param {*} [fill] the fill, defaults to full opaque black\n     * @param {Number} [opacity] optional opacity to use for filling\n     */\n    IFPaintCanvas.prototype.fillRect = function (x, y, width, height, fill, opacity) {\n        fill = this._convertStyle(fill ? fill : IFColor.BLACK);\n        this._canvasContext.globalCompositeOperation = IFPaintCanvas.CompositeOperator.SourceOver;\n        this._canvasContext.globalAlpha = typeof opacity == \"number\" ? opacity : 1.0;\n        this._canvasContext.fillStyle = fill;\n        this._canvasContext.fillRect(x, y, width, height);\n    };\n\n    /**\n     * Function to stroke a rectangle with a stroke. This does not care about\n     * any special operations like composite and the such though the rectangle\n     * gets transformed into the current space.\n     *\n     * @param {Number} x x-position of rectangle\n     * @param {Number} y y-position of rectangle\n     * @param {Number} width width of rectangle\n     * @param {Number} height height of rectangle\n     * @param {Number} [strokeWidth] the width of the stroke, defaults to 1.0\n     * @param {Number} [stroke] the stroke, defaults to full opaque black\n     * @param {Number} [opacity] optional opacity to use for stroking\n     */\n    IFPaintCanvas.prototype.strokeRect = function (x, y, width, height, strokeWidth, stroke, opacity) {\n        stroke = this._convertStyle(stroke ? stroke : IFColor.BLACK);\n        strokeWidth = strokeWidth || 1.0;\n        this._canvasContext.globalCompositeOperation = IFPaintCanvas.CompositeOperator.SourceOver;\n        this._canvasContext.globalAlpha = typeof opacity == \"number\" ? opacity : 1.0;\n        this._canvasContext.strokeStyle = stroke;\n        this._canvasContext.lineWidth = strokeWidth;\n        this._canvasContext.strokeRect(x, y, width, height);\n    };\n\n    /**\n     * Function to stroke a line with a color. This does not care about\n     * any special operations like composite and the such though the line\n     * gets transformed into the current space.\n     *\n     * @param {Number} x1 first x-position of line\n     * @param {Number} y1 first y-position of line\n     * @param {Number} x2 second x-position of line\n     * @param {Number} y2 second y-position of line\n     * @param {Number} [strokeWidth] the width of the stroke, defaults to 1.0\n     * @param {Number} [stroke] the stroke, defaults to full opaque black\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.strokeLine = function (x1, y1, x2, y2, strokeWidth, stroke) {\n        stroke = this._convertStyle(stroke ? stroke : IFColor.BLACK);\n        strokeWidth = strokeWidth || 1.0;\n        this._canvasContext.globalCompositeOperation = IFPaintCanvas.CompositeOperator.SourceOver;\n        this._canvasContext.globalAlpha = 1.0;\n        this._canvasContext.strokeStyle = stroke;\n        this._canvasContext.lineWidth = strokeWidth;\n        this._canvasContext.beginPath();\n        this._canvasContext.moveTo(x1, y1);\n        this._canvasContext.lineTo(x2, y2);\n        this._canvasContext.stroke();\n    };\n\n    /**\n     * Draw an image or canvas\n     * @param {Image|IFPaintCanvas} image the image or canvas to be drawn\n     * @param {Number} [x] the x-position of the image, defaults to zero\n     * @param {Number} [y] the y-position of the image, defaults to zero\n     * @param {Boolean} [noSmooth] if set to true, will render pixelated without smoothing. Defaults to false.\n     * @param {Number} [opacity] the total opacity to use for painting, defaults to 1.0 (full opaque)\n     * @param {IFPaintCanvas.CompositeOperator|IFPaintCanvas.BlendMode} [cmpOrBlend]\n     * @see IFPaintCanvas.CompositeOperator\n     * @version 1.0\n     */\n    IFPaintCanvas.prototype.drawImage = function (image, x, y, noSmooth, opacity, cmpOrBlend) {\n        x = x || 0;\n        y = y || 0;\n\n        image = this._convertImage(image);\n\n        this._canvasContext.globalAlpha = typeof opacity == \"number\" ? opacity : 1.0;\n\n        this._canvasContext.globalCompositeOperation = cmpOrBlend ? cmpOrBlend : IFPaintCanvas.CompositeOperator.SourceOver;\n\n        var hadSmooth = this._getImageSmoothingEnabled();\n        this._setImageSmoothingEnabled(!noSmooth);\n\n        this._canvasContext.drawImage(image, x ? x : 0, y ? y : 0);\n\n        this._setImageSmoothingEnabled(hadSmooth);\n    };\n\n    /** @private */\n    IFPaintCanvas.prototype._updateTransform = function () {\n        // make sure to assign global transform matrix to canvas\n        var matrix = this.getTransform(false).getMatrix();\n        this._canvasContext.setTransform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);\n    };\n\n    /**\n     * @param {*} style\n     * @param {*} defaultReturn\n     * @returns {*}\n     * @private\n     */\n    IFPaintCanvas.prototype._convertStyle = function (style) {\n        // TODO : Support color conversion using paint configuration color profiles\n\n        if (style instanceof CanvasPattern || style instanceof CanvasGradient) {\n            return style;\n        } else if (style instanceof IFColor) {\n            return style.asCSSString();\n        } else {\n            throw new Error('Not Supported.');\n        }\n    };\n\n    /** @private */\n    IFPaintCanvas.prototype._convertImage = function (image) {\n        if (image instanceof HTMLImageElement || image instanceof Image || image instanceof HTMLCanvasElement) {\n            return image;\n        } else if (image instanceof IFPaintCanvas) {\n            return image._canvasContext.canvas;\n        } else {\n            throw new Error('Not Supported.');\n        }\n    };\n\n    var _imageSmoothingProperties = ['imageSmoothingEnabled', 'webkitImageSmoothingEnabled', 'mozImageSmoothingEnabled'];\n\n    /** @private */\n    IFPaintCanvas.prototype._getImageSmoothingEnabled = function () {\n        for (var i = 0; i < _imageSmoothingProperties.length; ++i) {\n            if (this._canvasContext.hasOwnProperty(_imageSmoothingProperties[i])) {\n                return this._canvasContext[_imageSmoothingProperties[i]];\n            }\n        }\n        //throw new Error('No Image-Smoothing-Enabled Setting available on Canvas.');\n    };\n\n    /** @private */\n    IFPaintCanvas.prototype._setImageSmoothingEnabled = function (smoothingEnabled) {\n        for (var i = 0; i < _imageSmoothingProperties.length; ++i) {\n            if (this._canvasContext.hasOwnProperty(_imageSmoothingProperties[i])) {\n                this._canvasContext[_imageSmoothingProperties[i]] = smoothingEnabled;\n                return;\n            }\n        }\n        //throw new Error('No Image-Smoothing-Enabled Setting available on Canvas.');\n    };\n\n    _.IFPaintCanvas = IFPaintCanvas;\n})(this);"
  },
  {
    "path": "src/infinity/paint/paintconfiguration.js",
    "content": "(function (_) {\n    /**\n     * A class representing the configuration for painting\n     * @class IFPaintConfiguration\n     * @constructor\n     * @version 1.0\n     */\n    function IFPaintConfiguration() {\n    }\n\n    /** @override */\n    IFPaintConfiguration.prototype.toString = function () {\n        return \"[Object IFPaintConfiguration]\";\n    };\n\n    _.IFPaintConfiguration = IFPaintConfiguration;\n})(this);"
  },
  {
    "path": "src/infinity/paint/paintcontext.js",
    "content": "(function (_) {\n    /**\n     * A class representing a context for painting\n     * @class IFPaintContext\n     * @constructor\n     */\n    function IFPaintContext() {\n        this.outlineColors = [];\n    }\n\n    /**\n     * The configuration for this context\n     * @type {IFPaintConfiguration}\n     */\n    IFPaintContext.prototype.configuration = null;\n\n    /**\n     * The canvas this context is working on\n     * @type IFPaintCanvas\n     * @version 1.0\n     */\n    IFPaintContext.prototype.canvas = null;\n\n    /**\n     * A dirty list matcher if painting dirty, may be null\n     * @type IFDirtyList.Matcher\n     * @version 1.0\n     */\n    IFPaintContext.prototype.dirtyMatcher = null;\n\n    /**\n     * An array of outline colors. If this has\n     * entries, then painting should take place\n     * as wireframe only and taking the last\n     * outline color entry of this array\n     * @type {Array<IFColor>}\n     */\n    IFPaintContext.prototype.outlineColors = null;\n\n    /**\n     * The current outline color for the selection\n     * @type IFColor\n     */\n    IFPaintContext.prototype.selectionOutlineColor = IFColor.SELECTION_OUTLINE;\n\n    /**\n     * The current outline color for the highlight\n     * @type IFColor\n     */\n    IFPaintContext.prototype.highlightOutlineColor = IFColor.HIGHLIGHT_OUTLINE;\n\n    /**\n     * The current outline color for the guides\n     * @type IFColor\n     */\n    IFPaintContext.prototype.guideOutlineColor = IFColor.GUIDE_OUTLINE;\n\n    /**\n     * Returns whether the paint context is in outline/wireframe mode or not\n     * @return {boolean}\n     */\n    IFPaintContext.prototype.isOutline = function () {\n        return this.outlineColors && this.outlineColors.length > 0;\n    };\n\n    /**\n     * Returns the current outline/wireframe color defaulting to black\n     * @returns {IFColor}\n     */\n    IFPaintContext.prototype.getOutlineColor = function () {\n        if (this.outlineColors && this.outlineColors.length > 0) {\n            return this.outlineColors[this.outlineColors.length - 1];\n        } else {\n            // TODO : Take this from configuration, instead?\n            return IFColor.BLACK;\n        }\n    };\n\n    /** @override */\n    IFPaintContext.prototype.toString = function () {\n        return \"[Object IFPaintContext]\";\n    };\n\n    _.IFPaintContext = IFPaintContext;\n})(this);"
  },
  {
    "path": "src/infinity/paint/pattern.js",
    "content": "(function (_) {\n    var SVG_CHESSBOARD_CSS_URL = 'url(\"data:image/svg+xml;base64,' +\n        btoa('<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\"><rect width=\"8\" height=\"8\" fill=\"white\"/><rect width=\"4\" height=\"4\" fill=\"#CDCDCD\"/><rect x=\"4\" y=\"4\" width=\"4\" height=\"4\" fill=\"#CDCDCD\"/></svg>') +\n        '\")';\n\n    /**\n     * A base class for patterns like color, gradients, etc.\n     * @mixin IFGradient\n     * @extends IFObject\n     * @constructor\n     */\n    function IFPattern() {\n    }\n\n    IFObject.inherit(IFPattern, IFObject);\n\n    /**\n     * The type of the pattern\n     * @enum\n     */\n    IFPattern.Type = {\n        Color: 'C',\n        Gradient: 'G',\n        Texture: 'T',\n        Noise: 'N'\n    };\n\n    /**\n     * Pattern's mime-type\n     * @type {string}\n     */\n    IFPattern.MIME_TYPE = \"application/infinity+pattern\";\n\n    /**\n     * Compares if two patterns are equal or not\n     * @param {IFPattern} left\n     * @param {IFPattern} right\n     * @return {Boolean}\n     */\n    IFPattern.equals = function (left, right) {\n        if (!left && left === right) {\n            return true;\n        } else if (left && right) {\n            if (left instanceof IFColor && right instanceof IFColor) {\n                return IFColor.equals(left, right);\n            } else if (left instanceof IFGradient && right instanceof IFGradient) {\n                return IFGradient.equals(left, right);\n            }\n        }\n        return false;\n    };\n\n    /**\n     * Parse a pattern string\n     * @param string\n     * @returns {IFPattern}\n     */\n    IFPattern.parsePattern = function (string) {\n        if (string && string.length > 0) {\n            var type = string.charAt(0);\n            string = string.substring(1);\n            if (type === IFPattern.Type.Color) {\n                return IFColor.parseColor(string);\n            } else if (type === IFPattern.Type.Gradient) {\n                return IFGradient.parseGradient(string);\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Convert a pattern into a string\n     * @param pattern\n     * @returns {String}\n     */\n    IFPattern.asString = function (pattern) {\n        if (pattern) {\n            return pattern.getPatternType() + pattern.asString();\n        }\n        return null;\n    };\n\n    IFPattern.asCSSBackground = function (pattern) {\n        var result = SVG_CHESSBOARD_CSS_URL;\n        if (pattern) {\n            switch (pattern.getPatternType()) {\n                case IFPattern.Type.Color:\n                    result = 'linear-gradient(' + pattern.asCSSString() + ', ' + pattern.asCSSString() + '), ' + result;\n                    break;\n                case IFPattern.Type.Gradient:\n                    result = pattern.asCSSBackgroundString() + ', ' + result;\n                    break;\n            }\n        }\n        return result;\n    };\n\n    /**\n     * Returns the pattern type\n     * @return {IFPattern.Type}\n     */\n    IFPattern.prototype.getPatternType = function () {\n        throw new Error('Not supported');\n    };\n\n    _.IFPattern = IFPattern;\n})(this);"
  },
  {
    "path": "src/infinity/platform.js",
    "content": "(function (_) {\n    /**\n     * Instance of a platform implementation\n     * @class GUIPlatform\n     * @extends IFObject\n     * @mixes GEventTarget\n     * @constructor\n     * @version 1.0\n     */\n    function GUIPlatform() {\n        document.addEventListener(\"keydown\", function (event) {\n            if (!document.activeElement ||\n                    ((!$(document.activeElement).is(\":input\") ||\n                            $(document.activeElement).is(\":button\")) &&\n                        !document.activeElement.isContentEditable)) {\n\n                if (document.activeElement && $(document.activeElement).is(\":button\") &&\n                        (event.keyCode == 13 || event.keyCode == 32)) {\n\n                    // By default Enter and Space keys fire up 'onclick' mouse event for active element\n                    // We use this trick to disable this default behavior for panel buttons,\n                    // which have been just pressed and released before Space or Enter has been pressed\n                    event.preventDefault();\n                    document.activeElement.blur();\n                }\n\n                this._updateModifiers(event);\n            }\n        }.bind(this), true);\n        document.addEventListener(\"keyup\", function (event) {\n            this._updateModifiers(event);\n        }.bind(this), true);\n    }\n\n    IFObject.inheritAndMix(GUIPlatform, IFObject, [GEventTarget]);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIPlatform.Modifiers Class\n    // -----------------------------------------------------------------------------------------------------------------\n    GUIPlatform.Modifiers = function () {\n    };\n\n    /**\n     * Whether the meta-key is held down or not (command on mac, ctrl on others)\n     * @type {Boolean}\n     * @version 1.0\n     */\n    GUIPlatform.Modifiers.metaKey = false;\n\n    /**\n     * Whether the shift-key is held down or not\n     * @type {Boolean}\n     * @version 1.0\n     */\n    GUIPlatform.Modifiers.shiftKey = false;\n\n    /**\n     * Whether the option-key is held down or not\n     * @type {Boolean}\n     * @version 1.0\n     */\n    GUIPlatform.Modifiers.optionKey = false;\n\n    /**\n     * Whether the space-key is held down or not\n     * @type {Boolean}\n     * @version 1.0\n     */\n    GUIPlatform.Modifiers.spaceKey = false;\n\n    /** @override */\n    GUIPlatform.Modifiers.prototype.toString = function () {\n        return \"[Object GUIPlatform.Modifiers]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIPlatform.ModifiersChangedEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An object representing an event when one or more modifiers have been changed globally\n     * @class GUIPlatform.ModifiersChangedEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     * @see GUIPlatform.modifiers\n     */\n    GUIPlatform.ModifiersChangedEvent = function () {\n        this.changed = new GUIPlatform.Modifiers();\n    }\n    IFObject.inherit(GUIPlatform.ModifiersChangedEvent, GEvent);\n\n    /**\n     * The modifiers that have been changed\n     * @type {GUIPlatform.Modifiers}\n     * @version 1.0\n     */\n    GUIPlatform.ModifiersChangedEvent.prototype.changed = null;\n\n    /** @override */\n    GUIPlatform.ModifiersChangedEvent.prototype.toString = function () {\n        return \"[Object GUIPlatform.ModifiersChangedEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // GUIPlatform Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * The globally accessible active modifiers\n     * @type {GUIPlatform.Modifiers}\n     * @version 1.0\n     */\n    GUIPlatform.prototype.modifiers = new GUIPlatform.Modifiers();\n\n    /**\n     * Cached modifiers changed event\n     * @type {GUIPlatform.ModifiersChangedEvent}\n     * @private\n     */\n    GUIPlatform.prototype._modifiersChangedEventCache = new GUIPlatform.ModifiersChangedEvent();\n\n    /**\n     * Schedule a new frame callback\n     * @param {Function} callback the callback to be executed\n     * @return {Object} an scheduleId which can be used to cancel the request\n     * @version 1.0\n     */\n    GUIPlatform.prototype.scheduleFrame = function (callback) {\n        return window.requestAnimationFrame(callback);\n    };\n\n    /**\n     * Cancel a scheduled frame\n     * @param {Object} scheduleId the id retrieved when calling scheduleFrame\n     * @version 1.0\n     */\n    GUIPlatform.prototype.cancelFrame = function (scheduleId) {\n        window.cancelRequestAnimationFrame(scheduleId);\n    };\n\n    /**\n     * @param {KeyboardEvent} event\n     * @private\n     */\n    GUIPlatform.prototype._updateModifiers = function (event) {\n        var optionKey = false;\n        var shiftKey = false;\n        var metaKey = false;\n        var spaceKey = false;\n\n        var _evMetaKey  = (ifSystem.operatingSystem !== IFSystem.OperatingSystem.OSX_IOS || ifSystem.hardware !== IFSystem.Hardware.Desktop) ? event.ctrlKey : event.metaKey;\n\n        // Update global modifiers\n        if (_evMetaKey != this.modifiers.metaKey) {\n            metaKey = true;\n            this.modifiers.metaKey = _evMetaKey;\n        }\n\n        if (event.altKey != this.modifiers.optionKey) {\n            optionKey = true;\n            this.modifiers.optionKey = event.altKey;\n        }\n\n        if (event.shiftKey != this.modifiers.shiftKey) {\n            shiftKey = true;\n            this.modifiers.shiftKey = event.shiftKey;\n        }\n\n        // Add some 'fake' modifier keys here\n        var eventSpaceKey = event.type === 'keydown' && event.keyCode === 32 ? true :\n            (event.type === 'keyup' && event.keyCode === 32 ? false : this.modifiers.spaceKey);\n\n        if (eventSpaceKey != this.modifiers.spaceKey) {\n            spaceKey = true;\n            this.modifiers.spaceKey = eventSpaceKey;\n        }\n\n        if (metaKey || optionKey || shiftKey || metaKey || spaceKey) {\n            if (this.hasEventListeners(GUIPlatform.ModifiersChangedEvent)) {\n                this._modifiersChangedEventCache.changed.metaKey = metaKey;\n                this._modifiersChangedEventCache.changed.optionKey = optionKey;\n                this._modifiersChangedEventCache.changed.shiftKey = shiftKey;\n                this._modifiersChangedEventCache.changed.spaceKey = spaceKey;\n                this.trigger(this._modifiersChangedEventCache);\n            }\n        }\n    };\n\n    _.GUIPlatform = GUIPlatform;\n    _.ifPlatform = new GUIPlatform();\n\n    /**\n     * Fixture for the various requestAnimationFrame implementations on the browsers\n     */\n    var lastTime = 0;\n    var vendors = ['ms', 'moz', 'webkit', 'o'];\n    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {\n        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];\n        window.cancelAnimationFrame =\n            window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];\n    }\n\n    if (!window.requestAnimationFrame) {\n        window.requestAnimationFrame = function (callback, element) {\n            var currTime = new Date().getTime();\n            var timeToCall = Math.max(0, 16 - (currTime - lastTime));\n            var id = window.setTimeout(function () {\n                    callback(currTime + timeToCall);\n                },\n                timeToCall);\n            lastTime = currTime + timeToCall;\n            return id;\n        };\n    }\n\n    if (!window.cancelAnimationFrame) {\n        window.cancelAnimationFrame = function (id) {\n            clearTimeout(id);\n        };\n    }\n})(this);"
  },
  {
    "path": "src/infinity/scene/block.js",
    "content": "(function (_) {\n    /**\n     * A block element that supports properties and storage\n     * @class IFBlock\n     * @extends IFElement\n     * @mixes IFNode.Properties\n     * @mixes IFNode.Store\n     * @constructor\n     */\n    function IFBlock() {\n        IFElement.call(this);\n        this._setDefaultProperties(IFBlock.VisualProperties, IFBlock.MetaProperties);\n    }\n\n    IFObject.inheritAndMix(IFBlock, IFElement, [IFNode.Properties, IFNode.Store]);\n\n    /**\n     * The visual properties of a block with their default values\n     */\n    IFBlock.VisualProperties = {\n        visible: true\n    };\n\n    /**\n     * The meta properties of a block with their default values\n     */\n    IFBlock.MetaProperties = {\n        name: null,\n        locked: false\n    };\n\n    /**\n     * The containting owner layer\n     * @type {IFLayer}\n     * @private\n     */\n    IFBlock.prototype._ownerLayer = null;\n\n    /**\n     * The containting root layer\n     * @type {IFLayer}\n     * @private\n     */\n    IFBlock.prototype._rootLayer = null;\n\n    /**\n     * The containting page\n     * @type {IFPage}\n     * @private\n     */\n    IFBlock.prototype._page = null;\n\n    /**\n     * Returns the label of the block which is either the name\n     * of the block if it has one or the name of the block's type\n     * @return {String}\n     */\n    IFBlock.prototype.getLabel = function () {\n        if (this.$name && this.$name !== \"\") {\n            return this.$name;\n        }\n        return this.getNodeNameTranslated();\n    };\n\n    /**\n     * Returns the owner layer of this block if any\n     * @return {IFLayer}\n     */\n    IFBlock.prototype.getOwnerLayer = function () {\n        return this._ownerLayer;\n    };\n\n    /**\n     * Returns the root layer of this block if any\n     * @return {IFLayer}\n     */\n    IFBlock.prototype.getRootLayer = function () {\n        return this._rootLayer;\n    };\n\n    /**\n     * Returns the owner page of this block if any\n     * @return {IFPage}\n     */\n    IFBlock.prototype.getPage = function () {\n        return this._page;\n    };\n\n    /** @override */\n    IFBlock.prototype.store = function (blob) {\n        if (IFNode.Store.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFBlock.VisualProperties);\n            this.storeProperties(blob, IFBlock.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFBlock.prototype.restore = function (blob) {\n        if (IFNode.Store.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFBlock.VisualProperties);\n            this.restoreProperties(blob, IFBlock.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFBlock.prototype._setParent = function (parent) {\n        IFElement.prototype._setParent.call(this, parent);\n\n        // update rootLayer, layer, page\n        if (parent) {\n            this._ownerLayer = parent instanceof IFLayer ? parent : parent instanceof IFBlock ? parent.getOwnerLayer() : null;\n            this._rootLayer = parent instanceof IFLayer && !parent.getOwnerLayer() ? parent : parent instanceof IFBlock ? parent.getRootLayer() : null;\n            this._page = parent instanceof IFPage ? parent : parent instanceof IFBlock ? parent.getPage() : null;\n        } else {\n            this._ownerLayer = null;\n            this._rootLayer = null;\n            this._page = null;\n        }\n    };\n\n    /** @override */\n    IFBlock.prototype._handleChange = function (change, args) {\n        if (change == IFNode._Change.AfterPropertiesChange) {\n            /** @type {{properties: Array<String>, values: Array<*>}} */\n            var propertyArgs = args;\n\n            // React on various known property changes\n            if (propertyArgs.properties.indexOf('visible') >= 0) {\n                var isVisible = this.getProperty('visible');\n\n                // Save our old paint bbox if we're getting hidden\n                var oldPaintBBox = !isVisible ? this.getPaintBBox() : null;\n\n                // Change hidden flag of this and all elemental children and invalidate their geometry\n                this.accept(function (node) {\n                    if (node instanceof IFElement) {\n                        if (isVisible) {\n                            node.removeFlag(IFElement.Flag.Hidden);\n                        } else {\n                            node.setFlag(IFElement.Flag.Hidden);\n                        }\n                        node._invalidateGeometry();\n                    }\n                });\n\n                // Deliver child geometry update to parent\n                if (this.getParent()) {\n                    this.getParent()._notifyChange(IFElement._Change.ChildGeometryUpdate, this);\n                }\n\n                // Request a repaint of either old paint bbox if getting hidden or from\n                // the current paint bbox if getting visible\n                if (isVisible) {\n                    this._handleChange(IFElement._Change.InvalidationRequest);\n                } else {\n                    this._requestInvalidationArea(oldPaintBBox);\n                }\n            } else if (propertyArgs.properties.indexOf('locked') >= 0) {\n                var isLocked = this.getProperty('locked');\n\n                // Change locked flag of this and all elemental children\n                this.accept(function (node) {\n                    if (node instanceof IFElement) {\n                        if (isLocked) {\n                            node.setFlag(IFElement.Flag.Locked);\n                        } else {\n                            node.removeFlag(IFElement.Flag.Locked);\n                        }\n                    }\n                });\n            }\n\n            // Call super and be done with it\n            IFElement.prototype._handleChange.call(this, change, args);\n        } else {\n            // Call super by default and be done with it\n            IFElement.prototype._handleChange.call(this, change, args);\n        }\n    };\n\n    _.IFBlock = IFBlock;\n})(this);"
  },
  {
    "path": "src/infinity/scene/element.js",
    "content": "(function (_) {\n    /**\n     * An element represent an elementary node within a scene, something like a layer,\n     * a shape, a group of shapes and more\n     * @class IFElement\n     * @extends IFNode\n     * @constructor\n     */\n    function IFElement() {\n    }\n\n    IFObject.inherit(IFElement, IFNode);\n\n    /**\n     * Known flags for a geometry\n     * @version 1.0\n     */\n    IFElement.Flag = {\n        /**\n         * Defines a flag for being hidden\n         * @type {Number}\n         */\n        Hidden: 1 << 21,\n\n        /**\n         * Defines a flag for being locked\n         * @type {Number}\n         */\n        Locked: 1 << 22,\n\n        /**\n         * Defines a flag for no painting which\n         * is different to hidden as this will\n         * behave as being visible just contents\n         * won't be painted at all\n         */\n        NoPaint: 1 << 23\n    };\n\n    /**\n     * Known flags for a collision check\n     * @version 1.0\n     */\n    IFElement.CollisionFlag = {\n        /**\n         * Flag that specifies partial collision matching, means\n         * that elements that are not fully enclosed by a collision\n         * area will still be added\n         * @type {Number}\n         * @version 1.0\n         */\n        Partial: 1 << 0,\n\n        /**\n         * Flag that specifies to test collision against element's\n         * geometry bounding box, only\n         * @type {Number}\n         * @version 1.0\n         */\n        GeometryBBox: 1 << 10,\n\n        /**\n         * Flag that specifies to test collision against element's\n         * paint bounding box, only\n         * @type {Number}\n         * @version 1.0\n         */\n        PaintBBox: 1 << 11\n    };\n\n    /**\n     * @enum\n     * @private\n     */\n    IFElement._Change = {\n        /**\n         * A child's geometry has been updated. This change gets populated up in hierarchy.\n         * args = the child which' geometry has been updated\n         * @type {Number}\n         */\n        ChildGeometryUpdate: 200,\n\n        /**\n         * A geometry update is prepared\n         * args = none\n         * @type {Number}\n         */\n        PrepareGeometryUpdate: 220,\n\n        /**\n         * A geometry update is finished\n         * args = Boolean whether to invalidate geometry or not, defaults to true\n         * @type {Number}\n         */\n        FinishGeometryUpdate: 221,\n\n        /**\n         * An invalidation is requested\n         * args = none\n         * @type {Number}\n         */\n        InvalidationRequest: 230,\n\n        /**\n         * An invalidation was requested. This change gets populated up in hierarchy.\n         * args = the requested invalidation area rect\n         * @type {Number}\n         */\n        InvalidationRequested: 231\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElement.GeometryChangeEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event on geometrical changes of an element sent via a scene\n     * @param {IFElement} element the affected element\n     * @param {IFElement.GeometryChangeEvent.Type} type the geometrical change type\n     * @class IFElement.GeometryChangeEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFElement.GeometryChangeEvent = function (element, type) {\n        this.element = element;\n        this.type = type;\n    };\n    IFObject.inherit(IFElement.GeometryChangeEvent, GEvent);\n\n    /**\n     * The type of a geometrical change\n     */\n    IFElement.GeometryChangeEvent.Type = {\n        /** Before the element's geometry gets changed */\n        Before: 0,\n        /** After the element's geometry has been changed */\n        After: 1,\n        /** After any of the element's child geometry has been changed */\n        Child: 2\n    };\n\n    /**\n     * The affected element\n     * @type IFElement\n     */\n    IFElement.GeometryChangeEvent.prototype.element = null;\n\n    /**\n     * The type of the geometrical change\n     * @type {IFElement.GeometryChangeEvent.Type}\n     */\n    IFElement.GeometryChangeEvent.prototype.type = null;\n\n    /** @override */\n    IFElement.GeometryChangeEvent.prototype.toString = function () {\n        return \"[Event IFElement.GeometryChangeEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElement.HitResult Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A hit result on an element\n     * @param {IFElement} element the element that was hit\n     * @param {*} args - other hit-test data\n     * @constructor\n     * @class IFElement.HitResult\n     */\n    IFElement.HitResult = function (element, args) {\n        this.element = element;\n        this.data = args;\n    };\n\n    /**\n     * The element that was hit\n     * @type {IFElement}\n     * @version 1.0\n     */\n    IFElement.HitResult.prototype.element = null;\n\n    /**\n     * Additional hit-test data\n     * @type {*}\n     */\n    IFElement.HitResult.prototype.data = null;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElement.Transform Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Marks an element to be transformable\n     * @class IFElement.Transform\n     * @constructor\n     * @mixin\n     */\n    IFElement.Transform = function () {\n    };\n\n    /**\n     * Returns the actual transformation the element has\n     * @return {IFTransform}\n     */\n    IFElement.Transform.prototype.getTransform = function () {\n        return null;\n    };\n\n    /**\n     * Assigns the actual transformation the element has\n     * @return {IFTransform}\n     */\n    IFElement.Transform.prototype.setTransform = function (transform) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Transforms this element with another given transformation\n     * including multiplication with the existing transformation\n     * the element may already have. This will by default simply\n     * apply the transformation to all direct children of the element if any\n     * @param {IFTransform} transform the transformation to be applied\n     */\n    IFElement.Transform.prototype.transform = function (transform) {\n        this._transformChildren(transform);\n    };\n\n    /**\n     * @param {IFTransform} transform the transformation to be applied\n     * @private\n     */\n    IFElement.Transform.prototype._transformChildren = function (transform) {\n        if (this.hasMixin(IFNode.Container)) {\n            for (var child = this.getFirstChild(true); child != null; child = child.getNext(true)) {\n                if (child instanceof IFElement && child.hasMixin(IFElement.Transform)) {\n                    child.transform(transform);\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFElement.Transform.prototype.toString = function () {\n        return \"[Mixin IFElement.Transform]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElement.Style Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Marks an element to be stylable\n     * @class IFElement.Style\n     * @constructor\n     * @mixin\n     */\n    IFElement.Style = function () {\n    };\n\n    /**\n     * @type {IFStyleSet}\n     * @private\n     */\n    IFElement.Style._styleSet = null;\n\n    /**\n     * Returns the style-set for this element\n     * @returns {IFStyleSet}\n     */\n    IFElement.Style.prototype.getStyleSet = function () {\n        // If we have a _styleSet reference and it not\n        // has ourself as a parent, then clear it, first\n        if (this._styleSet && this._styleSet.getParent() !== this) {\n            this._styleSet = null;\n        }\n\n        if (!this._styleSet) {\n            // Find our style-set and save reference for faster access\n            for (var child = this.getFirstChild(true); child !== null; child = child.getNext(true)) {\n                if (child instanceof IFStyleSet) {\n                    this._styleSet = child;\n                    break;\n                }\n            }\n        }\n        return this._styleSet;\n    };\n\n    /**\n     * Render with a given Style. This will render with raster and filter\n     * effects if there're any within the given style\n     * @param {IFPaintContext} context\n     * @param {IFStyle} style\n     * @param {Number} [styleIndex] the style's index\n     */\n    IFElement.Style.prototype.renderStyle = function (context, style, styleIndex) {\n        if (!context.configuration.isOutline(context)) {\n            var styleAsMask = false;\n            var styleOnBackground = false;\n            var styleKnockout = false;\n            var styleOpacity = 1.0;\n            var styleBlendMode = IFPaintCanvas.BlendMode.Normal;\n\n            if (style instanceof IFAppliedStyle) {\n                var styleType = style.getProperty('tp');\n                switch (styleType) {\n                    case IFAppliedStyle.Type.Content:\n                        break;\n                    case IFAppliedStyle.Type.Mask:\n                        styleAsMask = true;\n                        break;\n                    case IFAppliedStyle.Type.Knockout:\n                        styleKnockout = true;\n                        break;\n                    case IFAppliedStyle.Type.Background:\n                        styleOnBackground = true;\n                        break;\n                    default:\n                        break;\n                }\n\n                styleOpacity = style.getProperty('opc');\n                styleBlendMode = style.getProperty('blm');\n            }\n\n            var needSeparateCanvas =\n                styleOpacity !== 1.0 ||\n                    styleBlendMode !== IFPaintCanvas.BlendMode.Normal ||\n                    styleAsMask === true ||\n                    styleOnBackground === true;\n\n            // Collect filter and effects if desired\n            var effects = [];\n            var filters = [];\n\n            for (var child = style.getActualStyle().getFirstChild(); child !== null; child = child.getNext()) {\n                if (child instanceof IFStyleEntry && child.getProperty('vs') === true) {\n                    if (child instanceof IFEffectEntry) {\n                        effects.push(child);\n                        needSeparateCanvas = true;\n                    } else if (child instanceof IFFilterEntry) {\n                        filters.push(child);\n                        needSeparateCanvas = true;\n                    } else if (child instanceof IFPaintEntry) {\n                        // If paint entry has no default composite or blend mode\n                        // then we need a separate canvas as well if we're a vertex source\n                        if (this.hasMixin(IFVertexSource)) {\n                            var cmpOrBlend = child.getPaintCmpOrBlend();\n                            if (cmpOrBlend !== null && cmpOrBlend !== IFPaintCanvas.CompositeOperator.SourceOver && cmpOrBlend !== IFPaintCanvas.BlendMode.Normal) {\n                                needSeparateCanvas = true;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (needSeparateCanvas) {\n                var sourceCanvas = context.canvas;\n                var paintBBox = style.getBBox(this.getGeometryBBox());\n\n                // The canvas our results will be put onto. If we're in fast\n                // mode, we'll try to cache the result and paint at 100%, otherwise\n                // we'll be painting on a temporary canvas, instead\n                var styleCanvas = null;\n                if (context.configuration.paintMode === IFScenePaintConfiguration.PaintMode.Fast) {\n                    styleCanvas = new IFPaintCanvas();\n                    styleCanvas.resize(paintBBox.getWidth(), paintBBox.getHeight());\n                    styleCanvas.prepare();\n\n                    var topLeft = paintBBox.getSide(IFRect.Side.TOP_LEFT);\n                    styleCanvas.setOrigin(topLeft);\n                    styleCanvas.setOffset(topLeft);\n                } else {\n                    styleCanvas = sourceCanvas.createCanvas(paintBBox, false);\n                }\n\n                // The canvas for rendering the contents of ourself\n                var contentsCanvas = styleCanvas.createCanvas(paintBBox);\n                context.canvas = contentsCanvas;\n                try {\n                    this._paint(context, style, styleIndex);\n                } finally {\n                    context.canvas = sourceCanvas;\n                    contentsCanvas.finish();\n                }\n\n                var hasRenderedContents = styleKnockout; // knockout means no contents painting\n\n                // Apply effects if desired and stack them\n                if (effects.length > 0) {\n                    // Order effects whether they're pre- or post-effects\n                    effects.sort(function (a, b) {\n                        return (a.isPost() === b.isPost()) ? 0 : b.isPost() ? -1 : 1;\n                    });\n\n                    // Initiate an effect canvas to paint each effect on\n                    var effectCanvas = styleCanvas.createCanvas(paintBBox);\n                    for (var i = 0; i < effects.length; ++i) {\n                        var effect = effects[i];\n\n                        if (i > 0) {\n                            // Clear previous effect contents\n                            effectCanvas.clear();\n                        }\n\n                        // Paint contents before first post filter except if knocked out\n                        if (effect.isPost()) {\n                            if (!hasRenderedContents) {\n                                styleCanvas.drawCanvas(contentsCanvas);\n                                hasRenderedContents = true;\n                            }\n                        }\n\n                        // Render effect and paint the effect canvas on our stack canvas\n                        effect.render(effectCanvas, contentsCanvas, effectCanvas.getScale());\n                        styleCanvas.drawCanvas(effectCanvas);\n                    }\n                    effectCanvas.finish();\n                }\n\n                // Render contents if not yet done\n                if (!hasRenderedContents) {\n                    styleCanvas.drawCanvas(contentsCanvas);\n                }\n\n                // Apply any filters to our stack canvas\n                for (var i = 0; i < filters.length; ++i) {\n                    filters[i].apply(styleCanvas, styleCanvas.getScale());\n                }\n\n                // Finally paint our stack canvas back into source canvas\n                sourceCanvas.drawCanvas(styleCanvas, 0, 0, styleOpacity, styleBlendMode);\n\n                // Release our element's canvas\n                styleCanvas.finish();\n            } else {\n                this._paint(context, style, styleIndex);\n            }\n        } else {\n            this._paint(context, style, styleIndex);\n        }\n    };\n\n    /** @override */\n    IFElement.Style.prototype.toString = function () {\n        return \"[Mixin IFElement.Style]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElement\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @type IFRect\n     * @private\n     */\n    IFElement.prototype._geometryBBbox = null;\n\n    /**\n     * @type IFRect\n     * @private\n     */\n    IFElement.prototype._paintBBox = null;\n\n    /**\n     * Called to get the geometry bbox which usually is the bbox of the underlying shape\n     * @return {IFRect} the geometry bbox, may never be null\n     * @version 1.0\n     */\n    IFElement.prototype.getGeometryBBox = function () {\n        // Immediately return if not visible at all\n        if (!this.isVisible()) {\n            return null;\n        }\n\n        if (this._geometryBBbox == null) {\n            this._geometryBBbox = this._calculateGeometryBBox();\n        }\n        return this._geometryBBbox;\n    };\n\n    /**\n     * Calculates the united geometry bbox of the array of elements\n     * @param {Array<*>} group - an array of elements for calculating geometry bbox.\n     * Only IFElement members are taken into account.\n     * @returns {IFRect} the geometry bbox of the group\n     */\n    IFElement.prototype.getGroupGeometryBBox = function (group) {\n        var groupBBox = null;\n        if (group && group.length) {\n            for (var i = 0; i < group.length; ++i) {\n                if (group[i] instanceof IFElement) {\n                    var bbox = group[i].getGeometryBBox();\n                    if (bbox && !bbox.isEmpty()) {\n                        groupBBox = groupBBox ? groupBBox.united(bbox) : bbox;\n                    }\n                }\n            }\n        }\n\n        return groupBBox;\n    };\n\n    /**\n     * Called to get the united geometry bbox of all children of this node if this node is a container\n     * @return {IFRect} the united geometry bbox of all children or empty rect if this node does not have\n     * any children with valid geometry bboxes\n     * @version 1.0\n     */\n    IFElement.prototype.getChildrenGeometryBBox = function () {\n        // Immediately return if not visible at all\n        if (!this.isVisible()) {\n            return null;\n        }\n\n        if (this.hasMixin(IFNode.Container)) {\n            var result = null;\n            for (var node = this.getFirstChild(); node != null; node = node.getNext()) {\n                if (node instanceof IFElement) {\n                    var childBBox = node.getGeometryBBox();\n                    if (childBBox && !childBBox.isEmpty()) {\n                        result = result ? result.united(childBBox) : childBBox;\n                    }\n                }\n            }\n            return result ? result : null;\n        }\n        return null;\n    };\n\n    /**\n     * Called to get the paint bbox for this node including all possible\n     * artifacts like effects and the such\n     * @return {IFRect} the paint bbox, may never be null\n     * @version 1.0\n     */\n    IFElement.prototype.getPaintBBox = function () {\n        // Immediately return if not visible at all\n        if (!this.isVisible()) {\n            return null;\n        }\n\n        if (this._paintBBox == null) {\n            this._paintBBox = this._calculatePaintBBox();\n        }\n        return this._paintBBox;\n    };\n\n    /**\n     * Called to get the united paint bbox of all children of this node if this node is a container\n     * @return {IFRect} the united paint bbox of all children or empty rect if this node does not have\n     * any children with valid paint bboxes\n     * @version 1.0\n     */\n    IFElement.prototype.getChildrenPaintBBox = function () {\n        // Immediately return if not visible at all\n        if (!this.isVisible()) {\n            return null;\n        }\n\n        if (this.hasMixin(IFNode.Container)) {\n            var result = null;\n            for (var node = this.getFirstChild(); node != null; node = node.getNext()) {\n                if (node instanceof IFElement) {\n                    var childBBox = node.getPaintBBox();\n                    if (childBBox && !childBBox.isEmpty()) {\n                        result = result ? result.united(childBBox) : childBBox;\n                    }\n                }\n            }\n            return result ? result : new IFRect(0, 0, 0, 0);\n        }\n        return null;\n    };\n\n    /**\n     * Returns whether this geometry is actually visible. Note that even if this\n     * function returns true, it does not mean that the node is paintable after all\n     * as this doesn't include any specific checking for visibility.\n     * To check whether this geometry is really paintable, use the isRenderable function.\n     * Note that this will also return false even this geometry would be visible\n     * but one of it's parents is hidden.\n     * @see isRenderable\n     * @version 1.0\n     */\n    IFElement.prototype.isVisible = function () {\n        return (this._flags & IFElement.Flag.Hidden) == 0;\n    };\n\n    /**\n     * Called whenever a hit-test should be made on this element. Note that\n     * this should hit-test against it's sub-elements (bottom-up), first\n     * @param {IFPoint} location the position to trigger the hit test at\n     * in transformed view coordinates (see transform parameter)\n     * @param {IFTransform} transform the transformation of the scene\n     * or null if there's none\n     * @param {Function} [acceptor] optional callback function getting called\n     * for a hit and receiving the currently hit element as it's only parameter.\n     * The function should return true to accept the element or false for not.\n     * @param {Boolean} [stacked] if true, returns all hits (from top to bottom) on the given\n     * location, otherwise returns the topmost one, only. Defaults to false\n     * @param {Number} [level] the level of deepness. A value of zero or less ignores\n     * all children, a negative value iterates to deepest level. Defaults to -1\n     * @param {Number} [tolerance] a tolerance value for hit testing in view coordinates,\n     * defaults to zero if not provided.\n     * @param {Boolean} [force] if true, enforce hitting even if something is not visible\n     * or has no area etc. Defaults to false.\n     * @returns {Array<IFElement.HitResult>} either null for no hit or\n     * a certain hit result depending on the element type\n     */\n    IFElement.prototype.hitTest = function (location, transform, acceptor, stacked, level, tolerance, force) {\n        if (typeof level !== 'number') level = -1; // unlimited deepness\n        tolerance = tolerance || 0;\n\n        // Quick-Test -> if location doesn't fall into our bounding-area\n        // or we don't have a bounding area, then we can certainly not\n        // have any hit at all. We'll however extend our paint bbox by\n        // the pick distance to provide better pick-up of objects\n        var paintBBox = this.getPaintBBox();\n        if (!paintBBox || paintBBox.isEmpty()) {\n            return null;\n        }\n        if (transform) {\n            paintBBox = transform.mapRect(paintBBox);\n        }\n\n        if (!paintBBox.expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n            return null;\n        }\n\n        var result = null;\n\n        // We might have a possible hit so iterate our children if any\n        if (level !== 0 && this.hasMixin(IFNode.Container)) {\n            for (var child = this.getLastChild(); child != null; child = child.getPrevious()) {\n                if (child instanceof IFElement) {\n                    var subResult = child.hitTest(location, transform, acceptor, stacked, level - 1, tolerance, force);\n                    if (subResult) {\n                        if (stacked) {\n                            if (result) {\n                                Array.prototype.push.apply(result, subResult);\n                            } else {\n                                result = subResult;\n                            }\n                        } else {\n                            return subResult;\n                        }\n                    }\n                }\n            }\n        }\n\n        if ((acceptor && acceptor.call(null, this) == true) || !acceptor) {\n            // No hit so far so try to hit ourself\n            var myResult = this._detailHitTest(location, transform, tolerance, force);\n            if (myResult) {\n                if (stacked && result) {\n                    result.push(myResult);\n                } else {\n                    result = [myResult];\n                }\n            }\n        }\n\n        return result;\n    };\n\n    /**\n     * Gets a list of all coliiding elements including this element and\n     * all potential children if it if any\n     * @param {IFVertexSource} area the area to get colissions within\n     * @param {Number} flags one or more flags to use for collision testing\n     * @param {Function} [acceptor] optional callback function getting called\n     * for a hit and receiving the currently hit element as it's only parameter.\n     * @return {Array<IFElement>} an array including all coliding elements or\n     * an empty array for no collisions\n     * @see IFElement.CollisionFlag\n     */\n    IFElement.prototype.getCollisions = function (area, flags, acceptor) {\n        var result = [];\n\n        var _addToResult = function (element) {\n            if ((acceptor && acceptor.call(null, element) == true) || !acceptor) {\n                result.push(element);\n            }\n        };\n\n        // Handle the basic collision modes here\n        if ((flags & IFElement.CollisionFlag.GeometryBBox) != 0 || (flags & IFElement.CollisionFlag.PaintBBox) != 0) {\n\n            // Test ourself, first\n            var bbox = this.getPaintBBox();\n            if (bbox && !bbox.isEmpty()) {\n                // TODO : How to check bbox intersection with area vertex source including partial param?\n                // --> area.intersects(..)\n\n                var areaBounds = ifVertexInfo.calculateBounds(area, true);\n\n                if ((flags & IFElement.CollisionFlag.Partial) != 0) {\n                    if (areaBounds.intersectsRect(bbox)) {\n                        _addToResult(this);\n                    }\n                } else {\n                    if (areaBounds.containsRect(bbox)) {\n                        _addToResult(this);\n                    }\n                }\n            }\n        }\n\n        // Test children now\n        if (this.hasMixin(IFNode.Container)) {\n            for (var child = this.getFirstChild(); child != null; child = child.getNext()) {\n                if (child instanceof IFElement) {\n                    var subResult = child.getCollisions(area, flags);\n                    if (subResult && subResult.length) {\n                        for (var i = 0; i < subResult.length; ++i) {\n                            _addToResult(subResult[i]);\n                        }\n                    }\n                }\n            }\n        }\n\n        return result;\n    };\n\n    /**\n     * Prepare an update on this node. This will delay all update notifications\n     * until the corresponding endUpdate call was made. This helps in speeding up\n     * heavy operations that may result in multiple modifications. This function\n     * is recursive, i.e. multiple calls to this functions need to be finished\n     * with the corresponding numbers of endUpdate calls.\n     */\n    IFElement.prototype.beginUpdate = function () {\n        if (!this._updateCounter) {\n            this._updateCounter = 1;\n            this._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n            this._blockUpdateChanges();\n        } else {\n            this._updateCounter++;\n        }\n    };\n\n    /**\n     * Finish an update on this node and update it now. If there've been multiple\n     * beginUpdate calls before, this will not update before the last,\n     * corresponding endUpdate call has taken place.\n     * @param {Boolean} [noGeometryInvalidation] if set then does not invalidate the geometry,\n     * otherwise this will ensure to invalidate the geometry. Defaults to false.\n     */\n    IFElement.prototype.endUpdate = function (noGeometryInvalidation) {\n        if (this._updateCounter != null && --this._updateCounter == 0) {\n            this._releaseUpdateChanges();\n            this._notifyChange(IFElement._Change.FinishGeometryUpdate, noGeometryInvalidation ? false : true);\n            delete this._updateCounter;\n        }\n    };\n\n    /**\n     * Function to check whether a node is actually rednerable, this includes\n     * for example checking for display flag, checking for dirty regions,\n     * empty bounding box, visibility and more.\n     * @param {IFPaintContext} [context] the current paint context, if null,\n     * no check against a context will be made\n     * @return {Boolean} true if the node is paintable, false if not\n     * @private\n     */\n    IFElement.prototype.isRenderable = function (context) {\n        // Immediately return if not visible at all\n        if (!this.isVisible()) {\n            return false;\n        }\n\n        if (!context) {\n            // If there's no context we can only paint when attached and having a parent\n            // or when we are the scene by ourself\n            return (this.isAttached() && this.getParent()) || (this instanceof IFScene);\n        }\n\n        var paintBBox = this.getPaintBBox();\n        if (paintBBox == null || paintBBox.isEmpty()) {\n            return false;\n        }\n\n        if (context) {\n            if (context.dirtyMatcher && !context.dirtyMatcher.isDirty(paintBBox)) {\n                return false;\n            }\n\n            if (context.configuration && context.configuration.clipArea && !context.configuration.clipArea.intersectsRect(paintBBox)) {\n                return false;\n            }\n        }\n        return true;\n    };\n\n    /**\n     * Called to render this element\n     * @param {IFPaintContext} context the context to be used for drawing\n     */\n    IFElement.prototype.render = function (context) {\n        // Prepare paint\n        if (!this._preparePaint(context)) {\n            return;\n        }\n\n        var paintRegular = true;\n        if (this.hasMixin(IFElement.Style)) {\n            var styleSet = this.getStyleSet();\n            var styleIndex = 0;\n            for (var style = styleSet.getFirstChild(); style !== null; style = style.getNext()) {\n                if (style instanceof IFStyle && style.getProperty('vs') === true) {\n                    paintRegular = false;\n\n                    this.renderStyle(context, style, styleIndex);\n\n                    styleIndex++;\n                }\n            }\n        }\n\n        if (paintRegular) {\n            this._paint(context, null, null);\n        }\n\n        this._finishPaint(context);\n    };\n\n    /**\n     * Called to render this element into a new bitmap\n     * @param {Number|IFLength} [width] the width of the bitmap, set to 0|null\n     * to use the element's bbox as width. Defaults to null. If the value is\n     * a number, it reflects the scale factor, otherwise if it is an IFLength,\n     * it defines an absolute width.\n     * @param {Number|IFLength} [height] the height of the bitmap, set to 0|null\n     * to use the element's bbox as height. Defaults to null. If the value is\n     * a number, it reflects the scale factor, otherwise if it is an IFLength,\n     * it defines an absolute width.\n     * @param {Number} [ratio] the ratio mode to be used whereas 0|null\n     * means to keep minimum aspect ratio thus eventually adjusting width\n     * or height and making one smaller, 1 means to keep maximum aspect ratio\n     * thus eventually adjusting  width or height and making one larger and\n     * 2 means to keep the width/height but center the element on bitmap\n     * if it's bbox ratio doesn't match the one of width / height\n     */\n    IFElement.prototype.toBitmap = function (width, height, ratio) {\n        var paintArea = this._getBitmapPaintArea();\n\n        // Calculate scale & delta offsets\n        ratio = ratio || 0;\n        var scaleX = 1;\n        var scaleY = 1;\n        var scale = 1;\n        var deltaX = 0;\n        var deltaY = 0;\n\n        if (width) {\n            if (typeof width === 'number') {\n                scaleX = width;\n            } else if (width instanceof IFLength) {\n                scaleX = width.toPoint() / paintArea.getWidth();\n            }\n        }\n\n        if (height) {\n            if (typeof height === 'number') {\n                scaleY = height;\n            } else if (height instanceof IFLength) {\n                scaleY = height.toPoint() / paintArea.getHeight();\n            }\n        }\n\n        var canvasWidth = paintArea.getWidth() * scaleX;\n        var canvasHeight = paintArea.getHeight() * scaleY;\n\n        // Handle ratio\n        if (scaleX !== scaleY) {\n            switch (ratio) {\n                case 0:\n                    // minimum aspect ratio\n                    if (scaleX < scaleY) {\n                        scale = scaleX;\n                        canvasHeight = canvasWidth;\n                    } else {\n                        scale = scaleY;\n                        canvasWidth = canvasHeight;\n                    }\n                    break;\n\n                case 1:\n                    // maximum aspect ratio\n                    if (scaleX > scaleY) {\n                        canvasHeight = scaleX;\n                        scaleY = canvasWidth;\n                    } else {\n                        scale = scaleY;\n                        canvasWidth = canvasHeight;\n                    }\n                    break;\n\n                case 2:\n                    // centered aspect ratio\n                    if (scaleX < scaleY) {\n                        // center vertically\n                        scale = scaleX;\n                        deltaY = (canvasHeight - (paintArea.getHeight() * scale)) / 2;\n                        //deltaY = paintArea.getHeight() * (scaleY / scaleX) / 2;\n                    } else {\n                        // center horizontally\n                        //deltaX = paintArea.getWidth() * (scaleX / scaleY) / 2;\n                        scale = scaleY;\n                        deltaX = (canvasWidth - (paintArea.getWidth() * scale)) / 2;\n                    }\n                    break;\n            }\n        } else {\n            scale = scaleX;\n        }\n\n        // Create + Setup Paint-Canvas\n        var paintCanvas = new IFPaintCanvas();\n        paintCanvas.resize(canvasWidth, canvasHeight);\n\n        // Create + Setup Paint Context & Configuration\n        var paintContext = new IFPaintContext();\n        paintContext.canvas = paintCanvas;\n        var paintConfig = new IFScenePaintConfiguration();\n        paintConfig.paintMode = IFScenePaintConfiguration.PaintMode.Full;\n        paintConfig.annotations = false;\n        paintContext.configuration = paintConfig;\n        paintConfig.clipArea = paintArea;\n\n        paintCanvas.prepare();\n        paintCanvas.setOrigin(new IFPoint(paintArea.getX() * scale - deltaX, paintArea.getY() * scale - deltaY));\n        paintCanvas.setScale(scale);\n        try {\n            return this._renderToBitmap(paintContext);\n        } finally {\n            paintCanvas.finish();\n        }\n    };\n\n    /**\n     * Called to return the area for this element for painting into bitmap\n     * @returns {IFRect}\n     * @private\n     */\n    IFElement.prototype._getBitmapPaintArea = function () {\n        return this.getPaintBBox();\n    };\n\n    /**\n     * Called to render this element into a bitmap\n     * @param {IFPaintContext} context\n     * @returns {IFBitmap}\n     * @private\n     */\n    IFElement.prototype._renderToBitmap = function (context) {\n        this.render(context);\n        return context.canvas.getBitmap();\n    };\n\n    /**\n     * Called whenever this should paint itself\n     * @param {IFPaintContext} context the context to be used for drawing\n     * @param {IFStyle} [style] the current style used for painting, only\n     * provided if this element has the IFElement.Style mixin\n     * @param {Number} [styleIndex] the current style's index, only provided\n     * if this element has the IFElement.Style mixin\n     */\n    IFElement.prototype._paint = function (context, style, styleIndex) {\n        // Render children by default\n        this._renderChildren(context);\n    };\n\n    /**\n     * Called for preparing a paint\n     * @param {IFPaintContext} context the current paint context\n     * @return {Boolean} false if painting should be canceled, true otherwise\n     * @private\n     */\n    IFElement.prototype._preparePaint = function (context) {\n        if (this.hasFlag(IFElement.Flag.NoPaint)) {\n            return false;\n        }\n\n        return this.isRenderable(context);\n    };\n\n    /**\n     * Called for finishing a paint\n     * @param {IFPaintContext} context the current paint context\n     * @private\n     */\n    IFElement.prototype._finishPaint = function (context) {\n        // NO-OP\n    };\n\n    /**\n     * Called for painting all children if this element is a container\n     * @param {IFPaintContext} context the current paint context\n     * @private\n     */\n    IFElement.prototype._renderChildren = function (context) {\n        // default paint handling if node is a container\n        if (this.hasMixin(IFNode.Container)) {\n            for (var node = this.getFirstChild(); node != null; node = node.getNext()) {\n                if (node instanceof IFElement) {\n                    node.render(context);\n                }\n            }\n        }\n    };\n\n    /**\n     * Called whenever the underliny geometry bbox needs to be calculated\n     * @return {IFRect} the calculated geometry bbox, may never be null\n     * @private\n     */\n    IFElement.prototype._calculateGeometryBBox = function () {\n        // Default action unites all children geometry bboxes if this is a container\n        return this.getChildrenGeometryBBox();\n    };\n\n    /**\n     * Called whenever the underlying paint bbox needs to be calculated\n     * @return {IFRect} the calculated paint bbox, may never be null\n     * @private\n     */\n    IFElement.prototype._calculatePaintBBox = function () {\n        var result = this.getChildrenPaintBBox();\n\n        if (result && this.hasMixin(IFElement.Style)) {\n            result = this.getStyleSet().getBBox(result);\n        }\n\n        return result;\n    };\n\n    /**\n     * Called whenever a detail hit-test should be made on this element.\n     * Detail means that the caller has already checked against a valid\n     * bounding area of this element as well as that the given location\n     * falls within the bounding area.\n     * @param {IFPoint} location the position to trigger the hit test at\n     * in transformed view coordinates (see transform parameter)\n     * @param {IFTransform} transform the transformation of the scene\n     * or null if there's none\n     * @param {Number} tolerance a tolerance used for hit-testing\n     * @param {Boolean} force if true, enforce hitting even if something is not visible\n     * or has no area etc.\n     * @returns {IFElement.HitResult} either null for no hit or\n     * a certain hit result depending on the element type\n     */\n    IFElement.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        return null;\n    };\n\n    /**\n     * Blocks all update changes like geometry update, invalidation etc.\n     * @private\n     */\n    IFElement.prototype._blockUpdateChanges = function () {\n        this._beginBlockChanges([\n            IFElement._Change.InvalidationRequest,\n            IFElement._Change.PrepareGeometryUpdate,\n            IFElement._Change.FinishGeometryUpdate,\n            IFElement._Change.ChildGeometryUpdate\n        ]);\n    };\n\n    /**\n     * Releases all update changes like geometry update, invalidation etc.\n     * @private\n     */\n    IFElement.prototype._releaseUpdateChanges = function () {\n        this._endBlockChanges([\n            IFElement._Change.InvalidationRequest,\n            IFElement._Change.PrepareGeometryUpdate,\n            IFElement._Change.FinishGeometryUpdate,\n            IFElement._Change.ChildGeometryUpdate\n        ]);\n    };\n\n    /**\n     * Called to to request a invalidation for a given node\n     * @param {IFElement} node the node to request an invalidation for\n     * @private\n     */\n    IFElement.prototype._requestInvalidateNode = function (node) {\n        if (node.isRenderable()) {\n            var repaintArea = node.getPaintBBox();\n            if (repaintArea) {\n                // Expand repaint area a bit to accreditate for any aa-pixels\n                this._requestInvalidationArea(repaintArea.expanded(2, 2, 2, 2));\n            }\n        }\n    };\n\n    /**\n     * Called to request a invalidation for a given area\n     * @param {IFRect} area the area of invalidation\n     * @private\n     */\n    IFElement.prototype._requestInvalidationArea = function (area) {\n        if (this.isAttached()) {\n            this._scene._invalidateArea(area);\n            this._handleChange(IFElement._Change.InvalidationRequested, area);\n        }\n    };\n\n    /**\n     * Called to request an invalidation for this node\n     * @private\n     */\n    IFElement.prototype._requestInvalidation = function () {\n        this._requestInvalidateNode(this);\n    };\n\n    /**\n     * Invalidate the geometry to enforce a re-calculation\n     * @private\n     */\n    IFElement.prototype._invalidateGeometry = function () {\n        this._geometryBBbox = null;\n        this._paintBBox = null;\n    };\n\n    /** @override */\n    IFElement.prototype._handleChange = function (change, args) {\n        if (change == IFElement._Change.InvalidationRequest) {\n            if (this.isRenderable()) {\n                this._requestInvalidation();\n            }\n        } else if (change === IFElement._Change.InvalidationRequested) {\n            // Deliver invalidation requested up to parent\n            if (this.getParent()) {\n                this.getParent()._notifyChange(IFElement._Change.InvalidationRequested, args);\n            }\n        } else if (change == IFElement._Change.PrepareGeometryUpdate) {\n            if (this.isRenderable()) {\n                var paintBBox = this.getPaintBBox();\n                if (paintBBox && !paintBBox.isEmpty()) {\n                    this._savedPaintBBox = paintBBox;\n                }\n            }\n\n            if (this.isVisible()) {\n                if (this._canEventBeSend(IFElement.GeometryChangeEvent)) {\n                    this._scene.trigger(new IFElement.GeometryChangeEvent(this, IFElement.GeometryChangeEvent.Type.Before));\n                }\n            }\n        } else if (change == IFElement._Change.FinishGeometryUpdate) {\n            if (this.isVisible()) {\n                // Avoid invalidation only of args is explicitely set to false\n                if (!(false === args)) {\n                    this._invalidateGeometry();\n                }\n\n                if (this.isRenderable()) {\n                    var newPaintBBox = this.getPaintBBox();\n                    if (!IFRect.equals(newPaintBBox, this._savedPaintBBox)) {\n\n                        // Deliver child geometry update to parent\n                        if (this.getParent()) {\n                            this.getParent()._notifyChange(IFElement._Change.ChildGeometryUpdate, this);\n                        }\n\n                        // Request repaint of old paint bbox if there was any\n                        if (this._savedPaintBBox) {\n                            this._requestInvalidationArea(this._savedPaintBBox);\n                        }\n\n                        // Request a repaint of our new geometry\n                        this._handleChange(IFElement._Change.InvalidationRequest);\n                    } else {\n                        // Paintboxes are equal then do a simple invalidation request\n                        this._requestInvalidation();\n                    }\n                }\n\n                if (this._canEventBeSend(IFElement.GeometryChangeEvent)) {\n                    this._scene.trigger(new IFElement.GeometryChangeEvent(this, IFElement.GeometryChangeEvent.Type.After));\n                }\n\n                if (this._savedPaintBBox) {\n                    delete this._savedPaintBBox;\n                }\n            }\n        } else if (change == IFElement._Change.ChildGeometryUpdate) {\n            if (this.isVisible()) {\n                this._invalidateGeometry();\n\n                if (this._canEventBeSend(IFElement.GeometryChangeEvent)) {\n                    this._scene.trigger(new IFElement.GeometryChangeEvent(this, IFElement.GeometryChangeEvent.Type.Child));\n                }\n\n                // Forward to parent\n                if (this.getParent()) {\n                    this.getParent()._notifyChange(change, args);\n                }\n            }\n        } else if (change == IFNode._Change.AfterChildInsert) {\n            // If child is an element, notify about the change\n            if (args instanceof IFElement) {\n                this._notifyChange(IFElement._Change.ChildGeometryUpdate, args);\n                args._handleChange(IFElement._Change.InvalidationRequest);\n            }\n\n            // Call super and be done with it\n            IFNode.prototype._handleChange.call(this, change, args);\n        } else if (change == IFNode._Change.BeforeChildRemove) {\n\n            // If child is an element, request repaint for it's area\n            if (args instanceof IFElement) {\n                this._requestInvalidateNode(args);\n            }\n\n            // Call super and be done with it\n            IFNode.prototype._handleChange.call(this, change, args);\n        } else if (change == IFNode._Change.AfterChildRemove) {\n\n            // If child is an element, notify about the change\n            if (args instanceof IFElement) {\n                this._notifyChange(IFElement._Change.ChildGeometryUpdate, args);\n            }\n\n            // Call super and be done with it\n            IFNode.prototype._handleChange.call(this, change, args);\n        } else if (change == IFNode._Change.AfterFlagChange) {\n            switch (args.flag) {\n                case IFElement.Flag.NoPaint:\n                    this._requestInvalidation();\n                    break;\n                default:\n                    break;\n            }\n\n            // Call super and be done with it\n            IFNode.prototype._handleChange.call(this, change, args);\n        } else {\n            // Call super by default and be done with it\n            IFNode.prototype._handleChange.call(this, change, args);\n        }\n    };\n\n    /**\n     * This will fire a change event for geometry updates whenever a given\n     * geometry property has been changed. This is usually called from the\n     * _handleChange function.\n     * @param {Number} change\n     * @param {Object} args\n     * @param {Object} properties a hashmap of properties that satisfy for\n     * geometrical changes\n     * @return {Boolean} true if there was a property change that affected a\n     * change of the geometry\n     * @private\n     */\n    IFElement.prototype._handleGeometryChangeForProperties = function (change, args, properties) {\n        if (change == IFNode._Change.BeforePropertiesChange || change == IFNode._Change.AfterPropertiesChange) {\n            if (ifUtil.containsObjectKey(args.properties, properties)) {\n                switch (change) {\n                    case IFNode._Change.BeforePropertiesChange:\n                        this._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n                        break;\n                    case IFNode._Change.AfterPropertiesChange:\n                        this._notifyChange(IFElement._Change.FinishGeometryUpdate);\n                        break;\n                }\n                return true;\n            }\n        }\n        return false;\n    };\n\n    /**\n     * This will fire an invalidation event for visual updates whenever a given\n     * visual property has been changed. This is usually called from the\n     * _handleChange function.\n     * @param {Number} change\n     * @param {Object} args\n     * @param {Object} properties a hashmap of properties that satisfy for\n     * visual changes\n     * @return {Boolean} true if there was a property change that affected a\n     * visual change\n     * @private\n     */\n    IFElement.prototype._handleVisualChangeForProperties = function (change, args, properties) {\n        if (change == IFNode._Change.AfterPropertiesChange) {\n            if (ifUtil.containsObjectKey(args.properties, properties)) {\n                this._notifyChange(IFElement._Change.InvalidationRequest);\n                return true;\n            }\n        }\n        return false;\n    };\n\n    _.IFElement = IFElement;\n})\n    (this);"
  },
  {
    "path": "src/infinity/scene/item.js",
    "content": "(function (_) {\n    /**\n     * The base for items like shapes and groups\n     * @class IFItem\n     * @extends IFBlock\n     * @constructor\n     */\n    function IFItem() {\n        IFBlock.call(this);\n    }\n    IFObject.inherit(IFItem, IFBlock);\n\n    _.IFItem = IFItem;\n})(this);"
  },
  {
    "path": "src/infinity/scene/node.js",
    "content": "(function (_) {\n    /**\n     * Base node representing a single item within a scene\n     * @class IFNode\n     * @extends IFObject\n     * @constructor\n     * @version 1.0\n     */\n    function IFNode() {\n    };\n\n    IFObject.inherit(IFNode, IFObject);\n\n    /**\n     * Nodes's mime-type\n     * @type {string}\n     */\n    IFNode.MIME_TYPE = \"application/infinity+node\";\n\n    /**\n     * IFObject.inherit descendant for nodes\n     * @param {String} name the unique name for the node\n     * @see IFObject.inherit\n     */\n    IFNode.inherit = function (name, target, base) {\n        IFObject.inherit(target, base);\n        IFNode._registerNodeClass(name, target);\n    };\n\n    /**\n     * IFObject.inheritAndMix descendant for nodes\n     * @param {String} name the unique name for the node\n     * @see IFObject.inheritAndMix\n     */\n    IFNode.inheritAndMix = function (name, target, base, mixins) {\n        IFObject.inheritAndMix(target, base, mixins);\n        IFNode._registerNodeClass(name, target);\n    };\n\n    /**\n     * Returns the name for a given node or node class\n     * @param {Object|Function|Number} node\n     */\n    IFNode.getName = function (node) {\n        return IFNode._nodeClassToNameMap[IFObject.getTypeId(node)];\n    };\n\n    /**\n     * Called to store a given node into a blob\n     * @param {IFNode} node the node to be stored\n     * @returns {*} the stored blob for the node or null on failure\n     */\n    IFNode.store = function (node) {\n        if (node.hasMixin(IFNode.Store)) {\n            var blob = {\n                '@': IFNode._nodeClassToNameMap[IFObject.getTypeId(node)]\n            };\n\n            if (node.store(blob)) {\n                return blob;\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Restore a node from a given blob\n     * @param {*} blob the blob to restore from\n     * @returns {IFNode} a node instance of the blob-type or\n     * null for failure\n     */\n    IFNode.restore = function (blob) {\n        if (!blob || !blob.hasOwnProperty('@')) {\n            return null;\n        }\n\n        var nodeClass = IFNode._nameToNodeClassMap[blob['@']];\n        if (!nodeClass) {\n            return null;\n        }\n\n        // Create our node instance now and let it restore\n        var node = new nodeClass();\n        if (!node || !node.restore(blob)) {\n            return null;\n        }\n\n        return node;\n    };\n\n    /**\n     * Serialize a given node or an array of nodes into a string\n     * @param {IFNode|Array<IFNode>} node the node to serialize\n     * or an array of nodes to serialize\n     * @param {Boolean} [beautify] whether to beautify, defaults to false\n     * @param {String} serialized json code or null for failure\n     */\n    IFNode.serialize = function (node, beautify) {\n        if (node instanceof Array) {\n            var blobs = [];\n\n            for (var i = 0; i < node.length; ++i) {\n                var blob = IFNode.store(node[i]);\n                if (blob) {\n                    blobs.push(blob);\n                }\n            }\n\n            if (blobs.length > 0) {\n                return JSON.stringify(blobs, null, beautify ? 4 : null);\n            }\n        } else {\n            var blob = IFNode.store(node);\n            if (blob) {\n                return JSON.stringify(blob, null, beautify ? 4 : null);\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Deserialize a node or any array of nodes from a given json string\n     * @param {String} source the json string source to deserialize from\n     * @returns {IFNode|Array<IFNode>} the deserialized node\n     * or array of nodes or null for failure\n     */\n    IFNode.deserialize = function (source) {\n        if (source) {\n            var blob = JSON.parse(source);\n\n            if (blob && blob instanceof Array) {\n                var nodes = [];\n\n                for (var i = 0; i < blob.length; ++i) {\n                    var node = IFNode.restore(blob[i]);\n                    if (node) {\n                        nodes.push(node);\n                    }\n                }\n\n                return nodes && nodes.length > 0 ? nodes : null;\n            } else {\n                return IFNode.restore(blob);\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Returns a new array with an ordered direction\n     * of a given set of nodes depending on their\n     * position in the tree\n     * @param {Array<IFNode>} nodes an array of nodes to be ordered\n     * @param {Boolean} [reverse] if true, orders the way that\n     * parent comes first, last child comes first, otherwise\n     * orders that parent comes first, first child comes first,\n     * defaults to false\n     * @return {Array<IFNode>} A new, ordered array\n     */\n    IFNode.order = function (nodes, reverse) {\n        // TODO : Implement this!!\n        return nodes.slice();\n    };\n\n    /**\n     * Map of node-class type-ids to their names\n     * @type {Object}\n     * @private\n     */\n    IFNode._nodeClassToNameMap = {};\n\n    /**\n     * Map of names to their node-classes\n     * @type {Object}\n     * @private\n     */\n    IFNode._nameToNodeClassMap = {};\n\n    /**\n     * Register a name for a node class\n     * @param {String} name the unique name to register for the node class\n     * @param {Function} clazz the node class to be registered\n     * @private\n     */\n    IFNode._registerNodeClass = function (name, clazz) {\n        IFNode._nodeClassToNameMap[IFObject.getTypeId(clazz)] = name;\n        IFNode._nameToNodeClassMap[name] = clazz;\n    };\n\n    /**\n     * Known flags for a node\n     * @version 1.0\n     */\n    IFNode.Flag = {\n        /**\n         * Flag marking a node to be a shadow which means\n         * that if not explicitely requesting, the user\n         * won't see the node when iterating the model\n         * @type {Number}\n         * @version 1.0\n         */\n        Shadow: 1 << 0,\n\n        /**\n         * Flag marking a node to be selected\n         * @type {Number}\n         * @version 1.0\n         */\n        Selected: 1 << 1,\n\n        /**\n         * Flag marking a node to be highlighted\n         * @type {Number}\n         * @version 1.0\n         */\n        Highlighted: 1 << 2,\n\n        /**\n         * Flag marking a node to be active\n         * @type {Number}\n         * @version 1.0\n         */\n        Active: 1 << 3,\n\n        /**\n         * Flag marking a node to be expanded\n         * @type {Number}\n         * @version 1.0\n         */\n        Expanded: 1 << 4\n    };\n\n    /**\n     * @enum\n     * @private\n     */\n    IFNode._Change = {\n        /**\n         * A child is about to be inserted.\n         * args = child that will be inserted\n         * @type {Number}\n         */\n        BeforeChildInsert: 1,\n\n        /**\n         * A child has been inserted.\n         * args = child that was inserted\n         * @type {Number}\n         */\n        AfterChildInsert: 2,\n\n        /**\n         * A child is about to be removed\n         * args = child that will be removed\n         * @type {Number}\n         */\n        BeforeChildRemove: 10,\n\n        /**\n         * A child has been removed\n         * args = child that was removed\n         * @type {Number}\n         */\n        AfterChildRemove: 11,\n\n        /**\n         * The properties of a node are about to be changed\n         * args = {\n         *   {Array<String>} properties - the names of the properties that will be changed\n         *   {Array<Object>} values - the new values for the properties that'll be assigned\n         * }\n         * @type {Number}\n         */\n        BeforePropertiesChange: 20,\n\n        /**\n         * The properties of a node have been changed\n         * args = {\n         *   {Array<String>} properties - the names of the properties that were changed\n         *   {Array<Object>} values - the old values the properties had have before assignment\n         * }\n         * @type {Number}\n         */\n        AfterPropertiesChange: 21,\n\n        /**\n         * A flag of a node is about to be changed\n         * args = {\n         *   {Number} flag - the flag that is about to be changed\n         *   {Boolean} set - whether it will be set (true) or cleared/removed (false)\n         * }\n         * @type {Number}\n         */\n        BeforeFlagChange: 30,\n\n        /**\n         * A flag of a node has been changed\n         * args = {\n         *   {Number} flag - the flag that was changed\n         *   {Boolean} set - whether it will was set (true) or cleared/removed (false)\n         * }\n         * @type {Number}\n         */\n        AfterFlagChange: 31\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.BeforeInsertEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a future node insertion sent via a scene\n     * @param {IFNode} node the node that will be inserted\n     * @class IFNode.BeforeInsertEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.BeforeInsertEvent = function (node) {\n        this.node = node;\n    };\n    IFObject.inherit(IFNode.BeforeInsertEvent, GEvent);\n\n    /**\n     * The node that has will be inserted\n     * @type IFNode\n     * @version 1.0\n     */\n    IFNode.BeforeInsertEvent.prototype.node = null;\n\n    /** @override */\n    IFNode.BeforeInsertEvent.prototype.toString = function () {\n        return \"[Event IFNode.BeforeInsertEvent]\";\n    };\n\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.AfterInsertEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for node insertion sent via a scene\n     * @param {IFNode} node the node that was inserted\n     * @class IFNode.AfterInsertEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.AfterInsertEvent = function (node) {\n        this.node = node;\n    };\n    IFObject.inherit(IFNode.AfterInsertEvent, GEvent);\n\n    /**\n     * The node that was inserted\n     * @type IFNode\n     * @version 1.0\n     */\n    IFNode.AfterInsertEvent.prototype.node = null;\n\n    /** @override */\n    IFNode.AfterInsertEvent.prototype.toString = function () {\n        return \"[Event IFNode.AfterInsertEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.BeforeRemoveEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a future node removal sent via a scene\n     * @param {IFNode} node the node that will be removed\n     * @class IFNode.BeforeRemoveEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.BeforeRemoveEvent = function (node) {\n        this.node = node;\n    };\n    IFObject.inherit(IFNode.BeforeRemoveEvent, GEvent);\n\n    /**\n     * The node that will be removed\n     * @type IFNode\n     * @version 1.0\n     */\n    IFNode.BeforeRemoveEvent.prototype.node = null;\n\n    /** @override */\n    IFNode.BeforeRemoveEvent.prototype.toString = function () {\n        return \"[Event IFNode.BeforeRemoveEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.AfterRemoveEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a node removal sent via a scene\n     * @param {IFNode} node the node that was removed\n     * @class IFNode.AfterRemoveEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.AfterRemoveEvent = function (node) {\n        this.node = node;\n    };\n    IFObject.inherit(IFNode.AfterRemoveEvent, GEvent);\n\n    /**\n     * The node that was removed\n     * @type IFNode\n     * @version 1.0\n     */\n    IFNode.AfterRemoveEvent.prototype.node = null;\n\n    /** @override */\n    IFNode.AfterRemoveEvent.prototype.toString = function () {\n        return \"[Event IFNode.AfterRemoveEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.BeforePropertiesChangeEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a node properties change sent via a scene before the properties will be changed\n     * @param {IFNode} node the node which' properties are affected by the change\n     * @param {Array<String>} properties the names of the properties affected by the change\n     * @param {Array<*>} values the values that will be assigned\n     * @class IFNode.BeforePropertiesChangeEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFNode.BeforePropertiesChangeEvent = function (node, properties, values) {\n        this.node = node;\n        this.properties = properties;\n        this.values = values;\n    };\n\n    IFObject.inherit(IFNode.BeforePropertiesChangeEvent, GEvent);\n\n    /**\n     * The node which' property is affected by the change\n     * @type IFNode\n     */\n    IFNode.BeforePropertiesChangeEvent.prototype.node = null;\n    /**\n     * The names of the properties affected by the change\n     * @type Array<String>\n     */\n    IFNode.BeforePropertiesChangeEvent.prototype.properties = null;\n\n    /**\n     * The values that will be assigned\n     * @type Array<*>\n     */\n    IFNode.BeforePropertiesChangeEvent.prototype.values = null;\n\n    /** @override */\n    IFNode.BeforePropertiesChangeEvent.prototype.toString = function () {\n        return \"[Event IFNode.BeforePropertiesChangeEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.AfterPropertiesChangeEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a node properties change sent via a scene after the property has changed\n     * @param {IFNode} node the node which' properties are affected by the change\n     * @param {Array<String>} properties the names of the properties affected by the change\n     * @param {Array<*>} values the values that the properties previously had have\n     * @class IFNode.AfterPropertiesChangeEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.AfterPropertiesChangeEvent = function (node, properties, values) {\n        this.node = node;\n        this.properties = properties;\n        this.values = values;\n    };\n\n    IFObject.inherit(IFNode.AfterPropertiesChangeEvent, GEvent);\n\n    /**\n     * The node which' property is affected by the change\n     * @type IFNode\n     */\n    IFNode.AfterPropertiesChangeEvent.prototype.node = null;\n    /**\n     * The names of the properties affected by the change\n     * @type Array<String>\n     */\n    IFNode.AfterPropertiesChangeEvent.prototype.properties = null;\n\n    /**\n     * The values that the properties previously had have\n     * @type Array<*>\n     */\n    IFNode.AfterPropertiesChangeEvent.prototype.values = null;\n\n    /** @override */\n    IFNode.AfterPropertiesChangeEvent.prototype.toString = function () {\n        return \"[Event IFNode.AfterPropertiesChangeEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.BeforeFlagChangeEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a node flag change sent via a scene before the flag will be changed\n     * @param {IFNode} node the node which' flag is affected by the change\n     * @param {Number} flag the flag affected by the change\n     * @param {Boolean} set whether the flag will be set (true) or cleared/removed (false)\n     * @class IFNode.BeforeFlagChangeEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.BeforeFlagChangeEvent = function (node, flag, set) {\n        this.node = node;\n        this.flag = flag;\n        this.set = set;\n    };\n\n    IFObject.inherit(IFNode.BeforeFlagChangeEvent, GEvent);\n\n    /**\n     * The node which' flag is affected by the change\n     * @type IFNode\n     * @version 1.0\n     */\n    IFNode.BeforeFlagChangeEvent.prototype.node = null;\n    /**\n     * The flag affected by the change\n     * @type Number\n     * @version 1.0\n     */\n    IFNode.BeforeFlagChangeEvent.prototype.flag = null;\n\n    /**\n     * Whether the flag will be set (true) or cleared/removed (false)\n     * @type Boolean\n     * @version 1.0\n     */\n    IFNode.BeforeFlagChangeEvent.prototype.set = null;\n\n    /** @override */\n    IFNode.BeforeFlagChangeEvent.prototype.toString = function () {\n        return \"[Event IFNode.BeforeFlagChangeEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.AfterFlagChangeEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a node flag change sent via a scene after the flag was changed\n     * @param {IFNode} node the node which' flag was affected by the change\n     * @param {Number} flag the flag affected by the change\n     * @param {Boolean} set whether the flag will was set (true) or cleared/removed (false)\n     * @class IFNode.AfterFlagChangeEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.AfterFlagChangeEvent = function (node, flag, set) {\n        this.node = node;\n        this.flag = flag;\n        this.set = set;\n    };\n\n    IFObject.inherit(IFNode.AfterFlagChangeEvent, GEvent);\n\n    /**\n     * The node which' flag was affected by the change\n     * @type IFNode\n     * @version 1.0\n     */\n    IFNode.AfterFlagChangeEvent.prototype.node = null;\n    /**\n     * The flag affected by the change\n     * @type Number\n     * @version 1.0\n     */\n    IFNode.AfterFlagChangeEvent.prototype.flag = null;\n\n    /**\n     * Whether the flag was set (true) or cleared/removed (false)\n     * @type Boolean\n     * @version 1.0\n     */\n    IFNode.AfterFlagChangeEvent.prototype.set = null;\n\n    /** @override */\n    IFNode.AfterFlagChangeEvent.prototype.toString = function () {\n        return \"[Event IFNode.AfterFlagChangeEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.Properties Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin to make a node become a container for properties\n     * @class IFNode.Properties\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.Properties = function () {\n    };\n\n    /**\n     * Checks whether a given property is set on this node or not\n     * @param {String} property the name of the property\n     * @param {Boolean} [custom] whether property is a custom one or not, defaults to false\n     * @return {Boolean} true if property is set, false if not\n     */\n    IFNode.Properties.prototype.hasProperty = function (property, custom) {\n        var propName = (custom ? '@' : '$') + property;\n        return this.hasOwnProperty(propName);\n    };\n\n    /**\n     * Returns a given property if it is set\n     * @param {String} property the name of the property\n     * @param {Boolean} [custom] whether property is a custom one or not, defaults to false\n     * @param {*} [def] a default value to be returned if property is not set, defaults to null\n     * @return {*} the property or null if it is not set\n     */\n    IFNode.Properties.prototype.getProperty = function (property, custom, def) {\n        var propName = (custom ? '@' : '$') + property;\n        return this.hasOwnProperty(propName) ? this[propName] : def;\n    };\n\n    /**\n     * Returns multiple properties in the given order. If there's no such\n     * property set, the result will contain null values for those properties\n     * @param {Array<String>} properties the property names\n     * @param {Boolean} [custom] whether properties are a custom ones or not, defaults to false\n     * @param {Array<*>} [def] default values for properties not found, defaults to null\n     * @return {Array<*>} the property values in the order of the property names\n     */\n    IFNode.Properties.prototype.getProperties = function (properties, custom, def) {\n        var result = [];\n\n        for (var i = 0; i < properties.length; ++i) {\n            var defVal = def && def.length > i ? def[i] : null;\n            result.push(this.getProperty(properties[i], custom, defVal));\n        }\n\n        return result;\n    };\n\n    /**\n     * This is the same as calling setProperties([property], [value])\n     * @param {String} property the name of the property\n     * @param {*} value the new value of the property\n     * @param {Boolean} [custom] whether property is a custom one or not, defaults to false\n     * Defaults to false.\n     * @see setProperties\n     */\n    IFNode.Properties.prototype.setProperty = function (property, value, custom) {\n        return this.setProperties([property], [value], custom);\n    };\n\n    /**\n     * Assigns one or more properties a new values\n     * @param {Array<String>} properties the property names in the same order as values\n     * @param {Array<*>} values the new values in the same order as property names\n     * @param {Boolean} [custom] whether properties are a custom ones or not, defaults to false\n     * Defaults to false.\n     * @return {Boolean} true if at least one property has been modified, false if not (i.e. because\n     * the property was already set to the specified value)\n     */\n    IFNode.Properties.prototype.setProperties = function (properties, values, custom) {\n        if (properties.length !== values.length) {\n            throw new Error('Properties length does not match values length');\n        }\n\n        // First we'll iterate and collect all properties requiring a modification\n        var propertiesToModify = [];\n        var valuesToModify = [];\n        for (var i = 0; i < properties.length; ++i) {\n            var value = values[i];\n            var propName = (custom ? '@' : '$') + properties[i];\n            var oldValue = this[propName];\n\n            if (!ifUtil.equals(value, oldValue, false)) {\n                propertiesToModify.push(properties[i]);\n                valuesToModify.push(values[i])\n            }\n        }\n\n        // Return early if there're no properties to modify\n        if (propertiesToModify.length === 0) {\n            return false;\n        }\n\n        // Construct an event args object as it may be modified\n        var changeArgs = {\n            properties: propertiesToModify,\n            values: valuesToModify\n        };\n\n        // Notify before change\n        this._notifyChange(IFNode._Change.BeforePropertiesChange, changeArgs);\n\n        // Assign new property values now\n        var previousValues = [];\n        for (var i = 0; i < propertiesToModify.length; ++i) {\n            var propName = (custom ? '@' : '$') + propertiesToModify[i];\n            previousValues.push(this[propName]);\n            this[propName] = valuesToModify[i];\n        }\n\n        // Notify after change\n        this._notifyChange(IFNode._Change.AfterPropertiesChange, changeArgs);\n\n        return true;\n    };\n\n    /**\n     * Store a given set of properties into a given blob\n     * @param {*} blob the blob to save into\n     * @param {*} properties a hashmap of properties to their default values to be stored\n     * @param {Function} [filter] custom filter function (property,value} to return\n     * the value to be serialized for a given property\n     */\n    IFNode.Properties.prototype.storeProperties = function (blob, properties, filter) {\n        filter = filter || function (property, value) {\n            return value;\n        }\n        for (var property in properties) {\n            var defaultValue = properties[property];\n            var value = this['$' + property];\n            if (!ifUtil.equals(value, defaultValue, true)) {\n                var myValue = filter(property, value);\n                blob[property] = myValue;\n            }\n        }\n    };\n\n    /**\n     * Restore a given set of properties from a given blob. If the blob\n     * doesn't contain a given property, the default value will be used instead.\n     * @param {*} blob the blob to restore from\n     * @param {*} properties a hashmap of properties to their default values to be restored\n     * @param {Function} [filter] custom filter function (property,value} to return\n     * the value to be deserialized for a given property\n     */\n    IFNode.Properties.prototype.restoreProperties = function (blob, properties, filter) {\n        filter = filter || function (property, value) {\n            return value;\n        }\n\n        var propertiesToSet = [];\n        var valuesToSet = [];\n\n        for (var property in properties) {\n            propertiesToSet.push(property);\n\n            if (blob.hasOwnProperty(property)) {\n                valuesToSet.push(filter(property, blob[property]));\n            } else {\n                valuesToSet.push(properties[property]);\n            }\n        }\n\n        this.setProperties(propertiesToSet, valuesToSet, false);\n    };\n\n    /**\n     * Transfers a given set of properties from a given source node. If the source\n     * doesn't contain a given property, the default value will be used instead.\n     * @param {IFNode} node a properties node to transfer from\n     * @param {Array<*>} properties array of hashmaps of properties to their default values to be transfered\n     * Defaults to false.\n     */\n    IFNode.Properties.prototype.transferProperties = function (source, properties) {\n        var propertiesToSet = [];\n        var valuesToSet = [];\n\n        for (var i = 0; i < properties.length; ++i) {\n            for (var property in properties[i]) {\n                propertiesToSet.push(property);\n\n                if (source.hasProperty(property)) {\n                    valuesToSet.push(source.getProperty(property));\n                } else {\n                    valuesToSet.push(properties[i][property]);\n                }\n            }\n        }\n\n        this.setProperties(propertiesToSet, valuesToSet, false);\n    };\n\n    /**\n     * Assign default properties on this node.\n     * Provide a varArg with hashmaps of property-name to default value mappings.\n     */\n    IFNode.Properties.prototype._setDefaultProperties = function () {\n        for (var i = 0; i < arguments.length; ++i) {\n            var properties = arguments[i];\n            for (var property in properties) {\n                this['$' + property] = properties[property];\n            }\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.Identity Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin to make a node become identifiable (id)\n     * @class IFNode.Identity\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.Identity = function () {\n    };\n\n    /**\n     * Returns the id of the node\n     * @return {String}\n     * @version 1.0\n     */\n    IFNode.Identity.prototype.getId = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.Tag Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin to make a node become tagable\n     * @class IFNode.Tag\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.Tag = function () {\n    };\n\n    /**\n     * Returns the tags of the node\n     * @return {String}\n     * @version 1.0\n     */\n    IFNode.Tag.prototype.getTags = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.Reference Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin to make a node become referenceable\n     * @class IFNode.Reference\n     * @mixin\n     * @constructor\n     */\n    IFNode.Reference = function () {\n    };\n\n    IFNode.Reference.prototype._referenceId = null;\n\n    /**\n     * Returns the reference id of this node used for linking\n     * @return {String}\n     */\n    IFNode.Reference.prototype.getReferenceId = function () {\n        if (!this._referenceId) {\n            this._referenceId = ifUtil.uuid();\n        }\n        return this._referenceId;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.Container Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin to make a node become a container for children\n     * @class IFNode.Container\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.Container = function () {\n    };\n\n    /**\n     * @type IFNode\n     * @private\n     */\n    IFNode.Container.prototype._firstChild = null;\n\n    /**\n     * @type IFNode\n     * @private\n     */\n    IFNode.Container.prototype._lastChild = null;\n\n    /**\n     * Returns an array of all children within this node\n     * @param {Boolean} [shadow] if true, returns shadow nodes as well.\n     * This defaults to false.\n     * @return {Array<IFNode>} array of all children of this node or\n     * an empty array if there're no children\n     */\n    IFNode.Container.prototype.getChildren = function (shadow) {\n        var result = [];\n        for (var child = this.getFirstChild(shadow); child !== null; child = child.getNext(shadow)) {\n            result.push(child);\n        }\n        return result;\n    };\n\n    /**\n     * Access the first child of this node if any\n     * @param {Boolean} [shadow] if true, returns shadow nodes as well.\n     * This defaults to false.\n     * @return {IFNode} the first child of this node or null for none\n     * @version 1.0\n     */\n    IFNode.Container.prototype.getFirstChild = function (shadow) {\n        if (shadow || !this._firstChild) {\n            return this._firstChild;\n        } else {\n            for (var c = this._firstChild; c != null; c = c._next) {\n                if (!c.hasFlag(IFNode.Flag.Shadow)) {\n                    return c;\n                }\n            }\n            return null;\n        }\n    };\n\n    /**\n     * Access the last child of this node if any\n     * @param {Boolean} [shadow] if true, returns shadow nodes as well.\n     * This defaults to false.\n     * @return {IFNode} the last child of this node or null for none\n     * @version 1.0\n     */\n    IFNode.Container.prototype.getLastChild = function (shadow) {\n        if (shadow || !this._lastChild) {\n            return this._lastChild;\n        } else {\n            for (var c = this._lastChild; c != null; c = c._previous) {\n                if (!c.hasFlag(IFNode.Flag.Shadow)) {\n                    return c;\n                }\n            }\n            return null;\n        }\n    };\n\n    /**\n     * Append a new node as child to this node\n     * @param {IFNode} child the child to append to this one\n     */\n    IFNode.Container.prototype.appendChild = function (child) {\n        this.insertChild(child, null);\n    };\n\n    /**\n     * Insert a new child at a certain position\n     * @param {IFNode} child the child to append to into this one\n     * @param {IFNode} reference reference to insert before, can be null to append\n     */\n    IFNode.Container.prototype.insertChild = function (child, reference) {\n        if (child._scene != null) {\n            throw new Error(\"Child is already appended somewhere else\");\n        }\n        if (reference != null && reference.getParent() != this) {\n            throw new Error(\"Reference is not a child of this node\");\n        }\n        if (!child.validateInsertion(this, reference)) {\n            throw new Error(\"Child insertion validation failed.\");\n        }\n\n        this._notifyChange(IFNode._Change.BeforeChildInsert, child);\n\n        // Link our new child now\n        child._setParent(this);\n        if (reference != null) {\n            child._setNext(reference);\n            child._setPrevious(reference._previous);\n            reference._setPrevious(child);\n            if (child._previous == null) {\n                this._firstChild = child;\n            } else {\n                child._previous._setNext(child);\n            }\n        }\n        else {\n            if (this._lastChild != null) {\n                child._setPrevious(this._lastChild);\n                this._lastChild._setNext(child);\n                this._lastChild = child;\n            }\n            child._setNext(null);\n        }\n\n        if (this._firstChild == null) {\n            this._firstChild = child;\n            child._setPrevious(null);\n            child._setNext(null);\n        }\n\n        if (child._next == null) {\n            this._lastChild = child;\n        }\n\n        // If attached, attach all children recursively\n        if (this.isAttached()) {\n            var self = this;\n            if (child.accept) {\n                child.accept(function (node) {\n                    // Assign this scene to the node\n                    node._setScene(self._scene);\n                }, true);\n            }\n        }\n\n        this._notifyChange(IFNode._Change.AfterChildInsert, child);\n    };\n\n    /**\n     * Remove an existing child from this node\n     * @param {IFNode} child the child to remove from this one\n     */\n    IFNode.Container.prototype.removeChild = function (child) {\n        if (child._parent != this) {\n            throw new Error(\"Child is not a child of this node\");\n        }\n        if (!child.validateRemoval()) {\n            throw new Error(\"Child removal validation failed.\");\n        }\n\n\n        this._notifyChange(IFNode._Change.BeforeChildRemove, child);\n\n        if (this._firstChild == child) {\n            this._firstChild = child._next;\n        }\n        if (this._lastChild == child) {\n            this._lastChild = child._previous;\n        }\n        if (child._previous != null) {\n            child._previous._setNext(child._next);\n        }\n        if (child._next != null) {\n            child._next._setPrevious(child._previous);\n        }\n\n        child._setParent(null);\n        child._setPrevious(null);\n        child._setNext(null);\n\n        // If attached, detach all children recursively\n        if (this.isAttached()) {\n            if (child.accept) {\n                child.accept(function (node) {\n                    node._setScene(null);\n                }, true);\n            }\n        }\n\n        this._notifyChange(IFNode._Change.AfterChildRemove, child);\n    };\n\n    /**\n     * Remove all children of this node\n     * @param {Boolean} [shadow] if true, remove also shadow nodes,\n     * defaults to false\n     */\n    IFNode.Container.prototype.clearChildren = function (shadow) {\n        while (this.getFirstChild(shadow)) {\n            this.removeChild(this.getFirstChild(shadow));\n        }\n    };\n\n    /**\n     * Gets the index of a child node\n     * @param {IFNode} child the child to get an index for\n     * @param {Boolean} [shadow] if true, counts also shadow nodes,\n     * defaults to false\n     * @return {Number} the child index or a value less than zero\n     * if child is not a child of this node\n     */\n    IFNode.Container.prototype.getIndexOfChild = function (child, shadow) {\n        if (child._parent === this) {\n            var index = 0;\n            for (var node = this.getFirstChild(shadow); node !== null; node = node.getNext(shadow)) {\n                if (node === child) {\n                    return index;\n                }\n                index++;\n            }\n        }\n\n        return -1;\n    };\n\n    /**\n     * Gets a child of this node by a given index\n     * @param {Number} childIndex the index to get a child for\n     * @param {Boolean} [shadow] if true, counts also shadow nodes,\n     * defaults to false\n     * @return {IFNode} the child of this node at given index or\n     * null if no child was found at the given index\n     */\n    IFNode.Container.prototype.getChildByIndex = function (childIndex, shadow) {\n        var index = 0;\n        for (var node = this.getFirstChild(shadow); node !== null; node = node.getNext(shadow)) {\n            if (index === childIndex) {\n                return node;\n            }\n            index++;\n        }\n\n        return null;\n    };\n\n    /**\n     * Accept a visitor on this container's children\n     * @param {Function} visitor\n     * @param {Boolean} [shadow] if true, visits shadow nodes as well.\n     * This defaults to false.\n     * @return {Boolean}\n     * @version 1.0\n     */\n    IFNode.Container.prototype.acceptChildren = function (visitor, shadow) {\n        for (var child = this.getFirstChild(shadow); child != null; child = child.getNext(shadow)) {\n            if (child.accept(visitor, shadow) === false) {\n                return false;\n            }\n        }\n        return true;\n    };\n\n    /** @override */\n    IFNode.Container.prototype.toString = function () {\n        return \"[Mixin IFNode.Container]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode.Store Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin to make a node become storable\n     * @class IFNode.Store\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    IFNode.Store = function () {\n    };\n\n    /**\n     * Called to store this node into a given blob.\n     * The caller will already take care about storing any children.\n     * @param {*} blob the blob to store into\n     * @return {boolean} true if node could be stored, false if not\n     */\n    IFNode.Store.prototype.store = function (blob) {\n        if (this.hasMixin(IFNode.Container)) {\n            // Store children\n            for (var child = this.getFirstChild(true); child !== null; child = child.getNext(true)) {\n                var childBlob = IFNode.store(child);\n                if (childBlob) {\n                    if (!blob.hasOwnProperty('$')) {\n                        blob['$'] = [childBlob];\n                    } else {\n                        blob['$'].push(childBlob);\n                    }\n                }\n            }\n        }\n\n        if (this.hasMixin(IFNode.Properties)) {\n            // Store custom properties if any\n            for (var property in this) {\n                if (this.hasOwnProperty(property) && property.length > 1 && property.charAt(0) === '@') {\n                    blob[property] = this[property];\n                }\n            }\n        }\n\n        if (this.hasMixin(IFNode.Reference) && this._referenceId) {\n            // Restore referenceId\n            blob['#'] = this._referenceId;\n        }\n\n        // Return true by default\n        return true;\n    };\n\n    /**\n     * Called to restore this node from a given blob.\n     * The caller will already take care about restoring any children.\n     * @param {*} blob the blob to restore from\n     * @return {boolean} true if node could be restored, false if not\n     */\n    IFNode.Store.prototype.restore = function (blob) {\n        // Restore children if any\n        if (blob.hasOwnProperty('$') && this.hasMixin(IFNode.Container)) {\n            var children = blob['$'];\n            if (children.length > 0) {\n                for (var i = 0; i < children.length; ++i) {\n                    var child = IFNode.restore(children[i]);\n                    if (child) {\n                        this.appendChild(child);\n                    }\n                }\n            }\n        }\n\n        if (this.hasMixin(IFNode.Properties)) {\n            // Restore custom properties if any\n            for (var property in blob) {\n                if (blob.hasOwnProperty(property) && property.length > 1 && property.charAt(0) === '@') {\n                    this[property] = blob[property];\n                }\n            }\n        }\n\n        if (this.hasMixin(IFNode.Reference) && blob.hasOwnProperty('#')) {\n            // Restore referenceId\n            this._referenceId = blob['#'];\n        }\n\n        // Return true by default\n        return true;\n    };\n\n    /**\n     * Called to clone this node and return a new instance out of it\n     * @returns {IFNode}\n     */\n    IFNode.Store.prototype.clone = function () {\n        // Serialize and deserialize ourself\n        var serialized = IFNode.serialize(this);\n        if (serialized) {\n            var result = IFNode.deserialize(serialized);\n\n            // Make sure to reset referenceid on referenceables\n            if (result.hasMixin(IFNode.Reference)) {\n                result._referenceId = null;\n            }\n\n            return result;\n        }\n        return null;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFNode\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type IFScene\n     * @private\n     */\n    IFNode.prototype._scene = null;\n\n    /**\n     * @type IFNode\n     * @private\n     */\n    IFNode.prototype._parent = null;\n\n    /**\n     * @type IFNode\n     * @private\n     */\n    IFNode.prototype._previous = null;\n\n    /**\n     * @type IFNode\n     * @private\n     */\n    IFNode.prototype._next = null;\n\n    /**\n     * @type Number\n     * @private\n     */\n    IFNode.prototype._flags = 0;\n\n    /**\n     * Returns the name of the node type\n     * @return {String}\n     * @version 1.0\n     */\n    IFNode.prototype.getNodeName = function () {\n        return IFNode.getName(this);\n    };\n\n    /**\n     * Returns the (translated), human-readable name of the node type\n     * @return {String}\n     * @version 1.0\n     */\n    IFNode.prototype.getNodeNameTranslated = function () {\n        return ifLocale.getValue(this, \"name\", this.getNodeName());\n    };\n\n    /**\n     * Checks if this node is actually attached to a scene or not\n     * @return {Boolean} whether the node is attached or not\n     * @version 1.0\n     */\n    IFNode.prototype.isAttached = function () {\n        return this._scene != null;\n    };\n\n    /**\n     * Access the scene of this node\n     * @return {IFScene}\n     * @version 1.0\n     */\n    IFNode.prototype.getScene = function () {\n        return this._scene;\n    };\n\n    /**\n     * Access the parent of this node if any\n     * @return {IFNode} the parent of this node or null for none\n     * @version 1.0\n     */\n    IFNode.prototype.getParent = function () {\n        return this._parent;\n    };\n\n    /**\n     * Access the previous sibling of this node if any\n     * @param {Boolean} [shadow] if true, returns shadow nodes as well.\n     * This defaults to false.\n     * @return {IFNode} the previous sibling of this node or null for none\n     * @version 1.0\n     */\n    IFNode.prototype.getPrevious = function (shadow) {\n        if (shadow || !this._previous) {\n            return this._previous;\n        } else {\n            for (var c = this._previous; c != null; c = c._previous) {\n                if (!c.hasFlag(IFNode.Flag.Shadow)) {\n                    return c;\n                }\n            }\n            return null;\n        }\n    };\n\n    /**\n     * Access the next sibling of this node if any\n     * @param {Boolean} [shadow] if true, returns shadow nodes as well.\n     * This defaults to false.\n     * @return {IFNode} the next sibling of this node or null for none\n     * @version 1.0\n     */\n    IFNode.prototype.getNext = function (shadow) {\n        if (shadow || !this._next) {\n            return this._next;\n        } else {\n            for (var c = this._next; c != null; c = c._next) {\n                if (!c.hasFlag(IFNode.Flag.Shadow)) {\n                    return c;\n                }\n            }\n            return null;\n        }\n    };\n\n    /**\n     * Return all nodes within this one (if any) recursively\n     * with a given name or all for pseudo-selector '*'\n     * @param {String} nodeName either null or '*' for all or\n     * a specific nodeName to look for\n     * @return {Array<IFNode>} an array of found nodes or empty\n     * array for no match\n     * @version 1.0\n     */\n    IFNode.prototype.getNodesByName = function (nodeName, ignoreSelf) {\n        var result = [];\n        this.accept(function (node) {\n            if (!nodeName || nodeName == '*' || nodeName === node.getNodeName()) {\n                if (node !== this) {\n                    result.push(node);\n                }\n            }\n        }.bind(this));\n        return result;\n    };\n\n    /**\n     * Query for all nodes within this one and return their sum\n     * @param {String} selector a CSS3-compatible selector\n     * @returns {Number} the count, zero for none\n     */\n    IFNode.prototype.queryCount = function (selector) {\n        var result = IFSelector.queryAll(selector, this);\n        return result ? result.length : 0;\n    };\n\n    /**\n     * Query for all nodes within this one\n     * @param {String} selector a CSS3-compatible selector\n     * @returns {Array<IFNode>} all matched nodes or empty array for none\n     * @version 1.0\n     */\n    IFNode.prototype.queryAll = function (selector) {\n        return IFSelector.queryAll(selector, this);\n    };\n\n    /**\n     * Query for a single node within this one\n     * @param {String} selector a CSS3-compatible selector\n     * @returns {IFNode} a matched node or null for no match\n     * @version 1.0\n     */\n    IFNode.prototype.querySingle = function (selector) {\n        var result = IFSelector.querySingle(selector, this);\n        return result ? result : null;\n    };\n\n    /**\n     * Tests whether this node matches a certain selector. Matching\n     * is done by querying the actual structure (expensive) and comparing\n     * the result wether this node is part of it\n     * @param {String} selector a CSS3-compatible selector\n     * @returns {Boolean} true if this node matches the given selector, false if not\n     * @see filtered\n     */\n    IFNode.prototype.matches = function (selector) {\n        return IFSelector.match(selector, this);\n    };\n\n    /**\n     * Tests whether this node is filtered by a given selector.\n     * In the opposite to the matches function, this will not actually\n     * query the structure but simply iterate each selector part and\n     * try to match it onto this node.\n     * @param {String} selector a CSS3-compatible selector\n     * @returns {Boolean} true if this node matches the given selector, false if not\n     * @see matches\n     */\n    IFNode.prototype.filtered = function (selector) {\n        return IFSelector.filter(selector, [this]).length === 1;\n    };\n\n    /**\n     * Accept a visitor\n     * @param {Function} visitor a visitor function called for each visit retrieving the current\n     * node as first parameter. The function may return a boolean value indicating whether to\n     * return visiting (true) or whether to cancel visiting (false). Not returning anything or\n     * returning anything else than a Boolean will be ignored.\n     * @param {Boolean} [shadow] if true, visits shadow nodes as well.\n     * This defaults to false.\n     * @return {Boolean} result of visiting (false = canceled, true = went through)\n     * @version 1.0\n     */\n    IFNode.prototype.accept = function (visitor, shadow) {\n        if (shadow || !this.hasFlag(IFNode.Flag.Shadow)) {\n            if (visitor.call(null, this) === false) {\n                return false;\n            }\n        }\n\n        if (this.hasMixin(IFNode.Container)) {\n            return this.acceptChildren(visitor, shadow);\n        }\n\n        return true;\n    };\n\n    /**\n     * Checks whether this node has a certain flag setup\n     * @param {Number} flag\n     * @returns {Boolean}\n     * @version 1.0\n     */\n    IFNode.prototype.hasFlag = function (flag) {\n        return (this._flags & flag) != 0;\n    };\n\n    /**\n     * Set a flag on this node\n     * @param {Number} flag the flag to set\n     * @version 1.0\n     */\n    IFNode.prototype.setFlag = function (flag) {\n        // Ensure the flag may be modified\n        if (this._canModifyFlag(flag, true)) {\n            if ((this._flags & flag) == 0) {\n                this._notifyChange(IFNode._Change.BeforeFlagChange, {flag: flag, set: true});\n\n                this._flags = this._flags | flag;\n\n                this._notifyChange(IFNode._Change.AfterFlagChange, {flag: flag, set: true});\n            }\n        }\n    };\n\n    /**\n     * Remove a flag from this node\n     * @param {Number} flag the flag to remove\n     * @version 1.0\n     */\n    IFNode.prototype.removeFlag = function (flag) {\n        // Ensure the flag may be modified\n        if (this._canModifyFlag(flag, false)) {\n            if ((this._flags & flag) != 0) {\n                this._notifyChange(IFNode._Change.BeforeFlagChange, {flag: flag, set: false});\n\n                this._flags = this._flags & ~flag;\n\n                this._notifyChange(IFNode._Change.AfterFlagChange, {flag: flag, set: false});\n            }\n        }\n    };\n\n    /**\n     * Validates whether this node could be inserted into a given parent\n     * @param {IFNode} parent the parent to validate against\n     * @param {IFNode} reference optional reference to insert be for,\n     * defaults to null meaning to append at the end\n     * @return {Boolean} true if node could be inserted, false if not\n     */\n    IFNode.prototype.validateInsertion = function (parent, reference) {\n        // return false by default\n        return false;\n    };\n\n    /**\n     * Validates whether this node can be removed from it's parent.\n     * If this node is not attached to a parent, this will always\n     * return false\n     * @return {Boolean} true if node could be removed, false if not\n     */\n    IFNode.prototype.validateRemoval = function () {\n        // return true by default\n        return true;\n    };\n\n    /**\n     * Called to check if a flag can be set/cleared\n     * @param {Number} flag the flag that should be set or cleared\n     * @param {Boolean} set true if flag should be set, false if should be cleared\n     * @return {Boolean} true if flag can be set/cleared, false if not\n     * @private\n     */\n    IFNode.prototype._canModifyFlag = function (flag, set) {\n        // by default, we allow everything\n        return true;\n    };\n\n    /**\n     * Block one or more changes\n     * @param {Array<Number>} changes the array of changes to be blocked\n     * @private\n     */\n    IFNode.prototype._beginBlockChanges = function (changes) {\n        if (!(this._blockedChanges)) {\n            this._blockedChanges = {};\n            this._blockedChanges._counter = 0;\n        }\n\n        for (var i = 0; i < changes.length; ++i) {\n            var change = changes[i];\n            if (change in this._blockedChanges) {\n                this._blockedChanges[change]++;\n            } else {\n                this._blockedChanges[change] = 1;\n            }\n            this._blockedChanges._counter++;\n        }\n    };\n\n    /**\n     * Finish blocking one or more changes\n     * @param {Array<Number>} changes the array of changes to be unblocked\n     * @private\n     */\n    IFNode.prototype._endBlockChanges = function (changes) {\n        if (this._blockedChanges) {\n            for (var i = 0; i < changes.length; ++i) {\n                var change = changes[i];\n                if (change in this._blockedChanges) {\n                    if (--this._blockedChanges[change] == 0) {\n                        if (--this._blockedChanges._counter == 0) {\n                            delete this._blockedChanges;\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Block one or more events\n     * @param {Array<*>} eventClasses the array of event classes to be blocked\n     * @private\n     */\n    IFNode.prototype._beginBlockEvents = function (eventClasses) {\n        if (!(this._blockedEvents)) {\n            this._blockedEvents = {};\n            this._blockedEvents._counter = 0;\n        }\n\n        for (var i = 0; i < eventClasses.length; ++i) {\n            var event_id = IFObject.getTypeId(eventClasses[i]);\n            if (event_id in this._blockedEvents) {\n                this._blockedEvents[event_id]++;\n            } else {\n                this._blockedEvents[event_id] = 1;\n            }\n            this._blockedEvents._counter++;\n        }\n    };\n\n    /**\n     * Finish blocking one or more events.\n     * @param {Array<*>} eventClasses the array of event classes to be unblocked\n     * @private\n     */\n    IFNode.prototype._endBlockEvents = function (eventClasses) {\n        if (this._blockedEvents) {\n            for (var i = 0; i < eventClasses.length; ++i) {\n                var event_id = IFObject.getTypeId(eventClasses[i]);\n                if (event_id in this._blockedEvents) {\n                    if (--this._blockedEvents[event_id] == 0) {\n                        if (--this._blockedEvents._counter == 0) {\n                            delete this._blockedEvents;\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Util function to return a composite array of events\n     * @param {Boolean} structural structural events (insert, remove)\n     * @param {Boolean} [properties] property events\n     * @param {Boolean} [flags] flag events\n     * @private\n     */\n    IFNode.prototype._getCompositeEvents = function (structural, properties, flags) {\n        var events = [];\n\n        if (structural) {\n            events = events.concat([\n                IFNode.BeforeInsertEvent,\n                IFNode.AfterInsertEvent,\n                IFNode.BeforeRemoveEvent,\n                IFNode.AfterRemoveEvent\n            ]);\n        }\n\n        if (properties) {\n            events = events.concat([\n                IFNode.BeforePropertiesChangeEvent,\n                IFNode.AfterPropertiesChangeEvent\n            ]);\n        }\n\n        if (flags) {\n            events = events.concat([\n                IFNode.BeforeFlagChangeEvent,\n                IFNode.AfterFlagChangeEvent\n            ]);\n        }\n\n        return events;\n    };\n\n    /**\n     * Util function to block a composite number of events\n     * @param {Boolean} structural block structural events (insert, remove)\n     * @param {Boolean} [properties] block property events\n     * @param {Boolean} [flags] block flag events\n     * @private\n     */\n    IFNode.prototype._beginBlockCompositeEvents = function (structural, properties, flags) {\n        this._beginBlockEvents(this._getCompositeEvents(structural, properties, flags));\n    };\n\n    /**\n     * Util function to unblock a composite number of events\n     * @param {Boolean} structural unblock structural events (insert, remove)\n     * @param {Boolean} [properties] unblock property events\n     * @param {Boolean} [flags] unblock flag events\n     * @private\n     */\n    IFNode.prototype._endBlockCompositeEvents = function (structural, properties, flags) {\n        this._endBlockEvents(this._getCompositeEvents(structural, properties, flags));\n    };\n\n    /**\n     * Notify about a change and handle it if not blocked\n     * @param {Number} change the change we got notified\n     * @param {Object} [args] the arguments for the change, it's value\n     * depends on the current change and should be documented\n     * within the change constant type\n     * @private\n     */\n    IFNode.prototype._notifyChange = function (change, args) {\n        if (!this._blockedChanges || !this._blockedChanges[change]) {\n            this._handleChange(change, args);\n        }\n    };\n\n    /**\n     * Returns whether a given event can be send which is only the case\n     * when the node is attached, the scene has a listener for the event\n     * and the event is not blocked\n     * @param eventClass\n     * @returns {Boolean}\n     * @private\n     */\n    IFNode.prototype._canEventBeSend = function (eventClass) {\n        if (!this.isAttached()) {\n            return false;\n        }\n\n        if (!this._scene.hasEventListeners(eventClass)) {\n            return false;\n        }\n\n        var event_id = IFObject.getTypeId(eventClass);\n        return !this._blockedEvents || !this._blockedEvents[event_id];\n    };\n\n    /**\n     * @param {IFScene} scene\n     * @private\n     */\n    IFNode.prototype._setScene = function (scene) {\n        if (scene !== this._scene) {\n            if (this.hasMixin(IFNode.Reference)) {\n                if (scene) {\n                    scene.addReference(this);\n                } else {\n                    this._scene.removeReference(this);\n                }\n            }\n\n            this._scene = scene;\n        }\n    };\n\n    /**\n     * @param {IFNode} parent\n     * @private\n     */\n    IFNode.prototype._setParent = function (parent) {\n        this._parent = parent;\n    };\n\n    /**\n     * @param {IFNode} previous\n     * @private\n     */\n    IFNode.prototype._setPrevious = function (previous) {\n        this._previous = previous;\n    };\n\n    /**\n     * @param {IFNode} next\n     * @private\n     */\n    IFNode.prototype._setNext = function (next) {\n        this._next = next;\n    };\n\n    /**\n     * Handle a change\n     * @param {Number} change the change we got should handle\n     * @param {Object} [args] the arguments for the change, it's value\n     * depends on the current change and should be documented\n     * within the change constant type\n     * @private\n     */\n    IFNode.prototype._handleChange = function (change, args) {\n        if (change == IFNode._Change.BeforeChildInsert) {\n            /** @type {IFNode} */\n            var child = args;\n            if (this._canEventBeSend(IFNode.BeforeInsertEvent)) {\n                this._scene.trigger(new IFNode.BeforeInsertEvent(child));\n            }\n        }\n        else if (change == IFNode._Change.AfterChildInsert) {\n            /** @type {IFNode} */\n            var child = args;\n            if (this._canEventBeSend(IFNode.AfterInsertEvent)) {\n                this._scene.trigger(new IFNode.AfterInsertEvent(child));\n            }\n        } else if (change == IFNode._Change.BeforeChildRemove) {\n            /** @type {IFNode} */\n            var child = args;\n            if (this._canEventBeSend(IFNode.BeforeRemoveEvent)) {\n                this._scene.trigger(new IFNode.BeforeRemoveEvent(child));\n            }\n        }\n        else if (change == IFNode._Change.AfterChildRemove) {\n            /** @type {IFNode} */\n            var child = args;\n            if (this._canEventBeSend(IFNode.AfterRemoveEvent)) {\n                this._scene.trigger(new IFNode.AfterRemoveEvent(child));\n            }\n        } else if (change == IFNode._Change.BeforePropertiesChange) {\n            /** @type {{properties: Array<String>, values: Array<*>}} */\n            var propertyArgs = args;\n            if (this._canEventBeSend(IFNode.BeforePropertiesChangeEvent)) {\n                this._scene.trigger(new IFNode.BeforePropertiesChangeEvent(this, propertyArgs.properties, propertyArgs.values));\n            }\n        }\n        else if (change == IFNode._Change.AfterPropertiesChange) {\n            /** @type {{properties: Array<String>, values: Array<*>}} */\n            var propertyArgs = args;\n            if (this._canEventBeSend(IFNode.AfterPropertiesChangeEvent)) {\n                this._scene.trigger(new IFNode.AfterPropertiesChangeEvent(this, propertyArgs.properties, propertyArgs.values));\n            }\n        } else if (change == IFNode._Change.BeforeFlagChange) {\n            /** @type {{flag: Number, set: Boolean}} */\n            var flagArgs = args;\n            if (this._canEventBeSend(IFNode.BeforeFlagChangeEvent)) {\n                this._scene.trigger(new IFNode.BeforeFlagChangeEvent(this, flagArgs.flag, flagArgs.set));\n            }\n        }\n        else if (change == IFNode._Change.AfterFlagChange) {\n            /** @type {{flag: Number, set: Boolean}} */\n            var flagArgs = args;\n            if (this._canEventBeSend(IFNode.AfterFlagChangeEvent)) {\n                this._scene.trigger(new IFNode.AfterFlagChangeEvent(this, flagArgs.flag, flagArgs.set));\n            }\n        }\n    };\n\n    _.IFNode = IFNode;\n})(this);"
  },
  {
    "path": "src/infinity/scene/scene.js",
    "content": "(function (_) {\n    /**\n     * A scene covers all graphical resources\n     * @class IFScene\n     * @extends IFElement\n     * @mixes IFNode.Container\n     * @mixes IFNode.Properties\n     * @mixes IFNode.Store\n     * @mixes GEventTarget\n     * @constructor\n     */\n    function IFScene() {\n        IFElement.call(this);\n        this._scene = this;\n        this._references = {};\n        this._links = {};\n        this._setDefaultProperties(IFScene.MetaProperties);\n    }\n\n    IFNode.inheritAndMix(\"scene\", IFScene, IFElement, [IFNode.Container, IFNode.Properties, IFNode.Store, GEventTarget]);\n\n    /** @enum */\n    IFScene.UnitSnap = {\n        /**\n         * No unit snapping\n         */\n        None: 'N',\n\n        /**\n         * Snap to full units\n         */\n        Full: 'F',\n\n        /**\n         * Snap to half units\n         */\n        Half: 'H'\n    };\n\n    /**\n     * The padding between pages\n     * @type {number}\n     */\n    IFScene.PAGE_SPACING = 10;\n\n    /**\n     * The current version of scenes\n     * @type {Number}\n     */\n    IFScene.VERSION = 1;\n\n    /**\n     * The meta properties of a scene and their defaults\n     */\n    IFScene.MetaProperties = {\n        /** Version of the scene */\n        version: IFScene.VERSION,\n        /** The default color space */\n        clspace: IFColorSpace.RGB,\n        /** The unit used externally */\n        unit: IFLength.Unit.PT,\n        /** The unit snap-mode (IFScene.UnitSnap) */\n        unitSnap: IFScene.UnitSnap.Full,\n        /** The snap distance */\n        snapDist: 5,\n        /** The pick distance */\n        pickDist: 3,\n        /** The cursor distance (small and big) */\n        crDistSmall: 1,\n        crDistBig: 10,\n        /** The cursor constraint in radians */\n        crConstraint: 0,\n        /** The horizontal grid size */\n        gridSizeX: 10,\n        /** The vertical grid size */\n        gridSizeY: 10,\n        /** Whether the grid is active or not */\n        gridActive: false,\n        /** Whether to use single or multi page mode */\n        singlePage: true,\n        /** Relative path to image assets */\n        pathImage: 'images',\n        /** Relative path to font assets */\n        pathFont: 'fonts',\n        /** Relative path to export assets */\n        pathExport: 'export'\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFScene.InvalidationRequestEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for an invalidation request event\n     * @param {IFRect} [area] a repaint area, defaults to null means to repaint all\n     * @class IFScene.InvalidationRequestEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFScene.InvalidationRequestEvent = function (area) {\n        this.area = area ? area : null;\n    };\n    IFObject.inherit(IFScene.InvalidationRequestEvent, GEvent);\n\n    /** @type IFRect */\n    IFScene.InvalidationRequestEvent.prototype.area = null;\n\n    /** @override */\n    IFScene.InvalidationRequestEvent.prototype.toString = function () {\n        return \"[Event IFScene.InvalidationRequestEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFScene.ReferenceEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event whenever a reference has been either linked or unlinked\n     * @param {IFNode.Reference} reference the affected reference\n     * @param {IFNode} target the target that was linked/unlinked against reference\n     * @param {Boolean} linked if true, reference was linked, otherwise unlinked\n     * @class IFScene.ReferenceEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFScene.ReferenceEvent = function (reference, target, linked) {\n        this.reference = reference;\n        this.target = target;\n        this.linked = linked;\n    };\n    IFObject.inherit(IFScene.ReferenceEvent, GEvent);\n\n    /** @type {IFNode.Reference} */\n    IFScene.ReferenceEvent.prototype.reference = null;\n\n    /** @type {IFNode} */\n    IFScene.ReferenceEvent.prototype.target = null;\n\n    /** @type {Boolean} */\n    IFScene.ReferenceEvent.prototype.linked = null;\n\n    /** @override */\n    IFScene.ReferenceEvent.prototype.toString = function () {\n        return \"[Event IFScene.ReferenceEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFScene.ResolveUrlEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for resolving a given url. If one handles this event,\n     * it should call the resolved callback with the resolved url\n     * @param {String} url\n     * @param {Function} resolved\n     * @class IFScene.ResolveUrlEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFScene.ResolveUrlEvent = function (url, resolved) {\n        this.url = url;\n        this.resolved = resolved;\n    };\n    IFObject.inherit(IFScene.ResolveUrlEvent, GEvent);\n\n    /** @type String */\n    IFScene.ResolveUrlEvent.prototype.url = null;\n\n    /** @type Function */\n    IFScene.ResolveUrlEvent.prototype.resolved = null;\n\n    /** @override */\n    IFScene.ResolveUrlEvent.prototype.toString = function () {\n        return \"[Event IFScene.ResolveUrlEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFScene.StyleCollection Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFScene.StyleCollection\n     * @extends IFNode\n     * @mixes IFNode.Container\n     * @mixes IFNode.Store\n     * @private\n     */\n    IFScene.StyleCollection = function () {\n        IFNode.call(this);\n    }\n\n    IFNode.inheritAndMix(\"styleCollection\", IFScene.StyleCollection, IFNode, [IFNode.Container, IFNode.Store]);\n\n    /** @override */\n    IFScene.StyleCollection.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFScene;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFScene.SwatchCollection Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFScene.SwatchCollection\n     * @extends IFNode\n     * @mixes IFNode.Container\n     * @mixes IFNode.Store\n     * @private\n     */\n    IFScene.SwatchCollection = function () {\n        IFNode.call(this);\n    }\n\n    IFNode.inheritAndMix(\"swatchCollection\", IFScene.SwatchCollection, IFNode, [IFNode.Container, IFNode.Store]);\n\n    /** @override */\n    IFScene.SwatchCollection.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFScene;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFScene Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @type {{}}\n     * @private\n     */\n    IFScene.prototype._references = null;\n\n    /**\n     * @type {{}}\n     * @private\n     */\n    IFScene.prototype._links = null;\n\n    /**\n     * @type {IFScene.StyleCollection}\n     * @private\n     */\n    IFScene.prototype._styleCollection = null;\n\n    /**\n     * @type {IFScene.SwatchCollection}\n     * @private\n     */\n    IFScene.prototype._swatchCollection = null;\n\n    /**\n     * Returns the style-collection of this scene\n     * @returns {IFScene.StyleCollection}\n     */\n    IFScene.prototype.getStyleCollection = function () {\n        // If we have a _styleCollection reference and it not\n        // has ourself as a parent, then clear it, first\n        if (this._styleCollection && this._styleCollection.getParent() !== this) {\n            this._styleCollection = null;\n        }\n\n        if (!this._styleCollection) {\n            // Find our style-collection and save reference for faster access\n            for (var child = this.getFirstChild(true); child !== null; child = child.getNext(true)) {\n                if (child instanceof IFScene.StyleCollection) {\n                    this._styleCollection = child;\n                    break;\n                }\n            }\n        }\n\n        if (!this._styleCollection) {\n            this._styleCollection = new IFScene.StyleCollection();\n            this.appendChild(this._styleCollection);\n        }\n\n        return this._styleCollection;\n    };\n\n    /**\n     * Returns the swatch-collection of this scene\n     * @returns {IFScene.SwatchCollection}\n     */\n    IFScene.prototype.getSwatchCollection = function () {\n        // If we have a _swatchCollection reference and it not\n        // has ourself as a parent, then clear it, first\n        if (this._swatchCollection && this._swatchCollection.getParent() !== this) {\n            this._swatchCollection = null;\n        }\n\n        if (!this._swatchCollection) {\n            // Find our swatch-collection and save reference for faster access\n            for (var child = this.getFirstChild(true); child !== null; child = child.getNext(true)) {\n                if (child instanceof IFScene.SwatchCollection) {\n                    this._swatchCollection = child;\n                    break;\n                }\n            }\n        }\n\n        if (!this._swatchCollection) {\n            this._swatchCollection = new IFScene.SwatchCollection();\n            this.appendChild(this._swatchCollection);\n        }\n\n        return this._swatchCollection;\n    };\n\n    /** @override */\n    IFScene.prototype.store = function (blob) {\n        if (IFNode.Store.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFScene.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFScene.prototype.restore = function (blob) {\n        if (IFNode.Store.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFScene.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /**\n     * Converts a string into a length with the document's unit.\n     * @param {string} string a number, a length or an equation\n     * @returns {IFLength} a length in document units or null\n     * if string couldn't be parsed\n     */\n    IFScene.prototype.stringToLength = function (string) {\n        return IFLength.parseEquation(string, this.$unit);\n    };\n\n    /**\n     * Converts a string into a point value with the document's unit.\n     * @param {string} string a number, a length or an equation\n     * @returns {Number} a length in points or null\n     * if string couldn't be parsed\n     */\n    IFScene.prototype.stringToPoint = function (string) {\n        var length = this.stringToLength(string);\n        if (length) {\n            return length.toPoint();\n        }\n        return null;\n    };\n\n    /**\n     * Converts a length into a string with the document's unit.\n     * @param {IFLength} length the length to convert\n     * @returns {string} the resulting string without unit postfix\n     */\n    IFScene.prototype.lengthToString = function (length) {\n        return ifUtil.formatNumber(length.toUnit(this.$unit));\n    };\n\n    /**\n     * Converts a point value into a string with the document's unit.\n     * @param {Number} value the value in points to convert\n     * @returns {string} the resulting string without unit postfix\n     */\n    IFScene.prototype.pointToString = function (value) {\n        return this.lengthToString(new IFLength(value));\n    };\n\n    /**\n     * This will return all elements that are either intersecting\n     * with a given rectangle or are perfectly inside it. For testing,\n     * the element's paint bbox will be used.\n     * @param {IFRect} rect the rect to test against\n     * @param {Boolean} inside if true, matches need to be fully\n     * enclosed by the rect to be returned, otherwise it is enough\n     * when they're intersecting with rect. Defaults to false.\n     * @return {Array<IFElement>} an array of elements that are part\n     * of a given rectangle in their natural order. May return an empty array.\n     */\n    IFScene.prototype.getElementsByBBox = function (rect, inside) {\n        // TODO: Optimize this by using spatial map\n        var result = [];\n        this.acceptChildren(function (node) {\n                if (node instanceof IFElement) {\n                    var paintBBox = node.getPaintBBox();\n\n                    if (paintBBox && !paintBBox.isEmpty()) {\n                        if ((inside && rect.intersectsRect(paintBBox)) ||\n                            (!inside && rect.containsRect(paintBBox))) {\n                            result.push(node);\n                        }\n                    }\n                }\n            }\n        );\n        return result;\n    };\n\n    /**\n     * Returns the currently active page if any or null\n     * @return {IFPage}\n     */\n    IFScene.prototype.getActivePage = function () {\n        // TODO : Cache result\n        return this.querySingle('page:active');\n    };\n\n    /**\n     * Assigns a currently active page\n     * @param {IFPage} page the page made active\n     */\n    IFScene.prototype.setActivePage = function (page) {\n        if (!page.isAttached()) {\n            throw new Error('Page needs to be attached to be made active.');\n        }\n\n        for (var child = this.getFirstChild(); child !== null; child = child.getNext()) {\n            if (child instanceof IFPage && child !== page) {\n                child.removeFlag(IFNode.Flag.Active);\n            }\n        }\n\n        page.setFlag(IFNode.Flag.Active);\n    };\n\n    /**\n     * Returns the currently active layer if any or null\n     * @return {IFLayer}\n     */\n    IFScene.prototype.getActiveLayer = function () {\n        // TODO : Cache result\n        return this.querySingle('page:active layer:active');\n    };\n\n    /**\n     * Assigns a currently active layer, this may also switch\n     * the currently active page\n     * @param {IFLayer} layer the layer made active\n     */\n    IFScene.prototype.setActiveLayer = function (layer) {\n        if (!layer.isAttached()) {\n            throw new Error('Layer needs to be attached to be made active.');\n        }\n\n        // Make sure to activate parent page of layer, first\n        var layerPage = layer.getPage();\n        this.setActivePage(layerPage);\n\n        // Now activate the layer\n        layerPage.acceptChildren(function (node) {\n            if (node instanceof IFLayer && node !== layer) {\n                node.removeFlag(IFNode.Flag.Active);\n            }\n        });\n\n        layer.setFlag(IFNode.Flag.Active);\n    };\n\n    /**\n     * Returns a point for a new page to be inserted\n     * @returns {IFPoint}\n     */\n    IFScene.prototype.getPageInsertPosition = function () {\n        // TODO : Figure better way to avoid any potential intersection of the page with others\n        for (var child = this.getLastChild(); child !== null; child = child.getPrevious()) {\n            if (child instanceof IFPage) {\n                return new IFPoint(\n                    child.getProperty('x') + child.getProperty('w') + IFScene.PAGE_SPACING,\n                    child.getProperty('y')\n                );\n            }\n        }\n        return new IFPoint(0, 0);\n    };\n\n    /**\n     * Checks and returns wether a given page will intersect with\n     * any other page(s) with a given pageRect\n     * @param {IFPage} page the page to test for intersection w/ others\n     * @param {IFRect} pageRect the new page rect to test for intersection w/ others\n     */\n    IFScene.prototype.willPageIntersectWithOthers = function (page, pageRect) {\n        pageRect = pageRect.expanded(IFScene.PAGE_SPACING, IFScene.PAGE_SPACING, IFScene.PAGE_SPACING, IFScene.PAGE_SPACING);\n        for (var child = this.getLastChild(); child !== null; child = child.getPrevious()) {\n            if (child instanceof IFPage && child !== page) {\n                var currentPageRect = child.getGeometryBBox();\n                if (currentPageRect && currentPageRect.intersectsRect(pageRect)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    };\n\n    /**\n     * Links a referenceable target to a linked node\n     * @param {IFNode.Reference} target referenceable target to be linked against\n     * @param {IFNode} link linked node to be linked from\n     */\n    IFScene.prototype.link = function (target, link) {\n        var referenceId = target.getReferenceId();\n        if (!this._links.hasOwnProperty(referenceId)) {\n            this._links[referenceId] = [];\n        }\n        this._links[referenceId].push(link);\n\n        if (this.hasEventListeners(IFScene.ReferenceEvent)) {\n            this.trigger(new IFScene.ReferenceEvent(target, link, true));\n        }\n    };\n\n    /**\n     * Unlinks a referenceable target from a linked node\n     * @param {IFNode.Reference} target referenceable target to be unlinked to\n     * @param {IFNode} link linked node to be unlinked from\n     */\n    IFScene.prototype.unlink = function (target, link) {\n        var referenceId = target.getReferenceId();\n        if (this._links.hasOwnProperty(referenceId)) {\n            var links = this._links[referenceId];\n            var index = links.indexOf(link);\n            if (index >= 0) {\n                links.splice(index, 1);\n                if (links.length === 0) {\n                    delete this._links[referenceId];\n                }\n\n                if (this.hasEventListeners(IFScene.ReferenceEvent)) {\n                    this.trigger(new IFScene.ReferenceEvent(target, link, false));\n                }\n            }\n        }\n    };\n\n    /**\n     * Visits all links linking to a specific target node\n     * @param {IFNode.Reference} target the target node to visit links for\n     * @param {Function} visitor the visitor function called for each\n     * link with the link being the only argument\n     */\n    IFScene.prototype.visitLinks = function (target, visitor) {\n        var links = this._links[target.getReferenceId()];\n        if (links) {\n            for (var i = 0; i < links.length; ++i) {\n                visitor(links[i]);\n            }\n        }\n    };\n\n    /**\n     * Returns whether a given reference node has links or not\n     * @param {IFNode.Reference} reference\n     * @returns {boolean}\n     */\n    IFScene.prototype.hasLinks = function (reference) {\n        return this._links.hasOwnProperty(reference.getReferenceId());\n    };\n\n    /**\n     * Returns the number of links a given reference has\n     * @param {IFNode.Reference} reference\n     * @returns {Number}\n     */\n    IFScene.prototype.linkCount = function (reference) {\n        var links = this._links[reference.getReferenceId()];\n        if (links) {\n            return links.length;\n        }\n        return 0;\n    };\n\n    /**\n     * Register a referenceable node\n     * @param {IFNode.Reference} reference\n     */\n    IFScene.prototype.addReference = function (reference) {\n        var referenceId = reference.getReferenceId();\n        if (this._references.hasOwnProperty(referenceId)) {\n            throw new Error('Reference already added.');\n        }\n        this._references[referenceId] = reference;\n    };\n\n    /**\n     * Unregister a referenceable node\n     * @param {IFNode.Reference} reference\n     */\n    IFScene.prototype.removeReference = function (reference) {\n        var referenceId = reference.getReferenceId();\n        if (!this._references.hasOwnProperty(referenceId)) {\n            throw new Error('Reference not yet added.');\n        }\n        delete this._references[referenceId];\n    };\n\n    /**\n     * Returns a reference node by it's id if any\n     * @param {String} referenceId\n     * @return {IFNode.Reference}\n     */\n    IFScene.prototype.getReference = function (referenceId) {\n        if (this._references.hasOwnProperty(referenceId)) {\n            return this._references[referenceId];\n        }\n        return null;\n    };\n\n    /**\n     * Try to resolve a given url. This is asynchron.\n     * If the url is null or empty or a data url, it\n     * is returned as is. Otherwise, if it was resolved,\n     * the given resolved function containing the resolved\n     * url as parameter will be called.\n     * @param {String} url\n     * @param {Function} resolved\n     * @return {String}\n     */\n    IFScene.prototype.resolveUrl = function (url, resolved) {\n        if (!url || url.indexOf('data:') === 0) {\n            resolved(url);\n        } else if (this.hasEventListeners(IFScene.ResolveUrlEvent)) {\n            this.trigger(new IFScene.ResolveUrlEvent(url, resolved));\n        }\n    };\n\n    /** @override */\n    IFScene.prototype.hitTest = function (location, transform, acceptor, stacked, level, tolerance, force) {\n        // In single page mode go straight to active page\n        if (this.$singlePage) {\n            var activePage = this.getActivePage();\n            if (activePage) {\n                return activePage.hitTest(location, transform, acceptor, stacked, level, tolerance, force);\n            }\n        }\n\n        return IFElement.prototype.hitTest.call(this, location, transform, acceptor, stacked, level, tolerance, force);\n    };\n\n    /**\n     * Invalidate something\n     * @param {IFRect} [area] optional dirty area, if null marks the whole scene as being dirty\n     * @private\n     */\n    IFScene.prototype._invalidateArea = function (area) {\n        if (this.hasEventListeners(IFScene.InvalidationRequestEvent)) {\n            this.trigger(new IFScene.InvalidationRequestEvent(area));\n        }\n    };\n\n    /** @override */\n    IFScene.prototype._renderChildren = function (context) {\n        if (context.configuration.clipArea) {\n            var r = context.configuration.clipArea;\n            context.canvas.clipRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());\n        }\n\n        for (var node = this.getFirstChild(); node != null; node = node.getNext()) {\n            if (node instanceof IFPage) {\n                // Handle single-page mode if set\n                if (!this.$singlePage || node.hasFlag(IFNode.Flag.Active)) {\n                    node.render(context);\n                }\n            } else if (node instanceof IFElement) {\n                node.render(context);\n            }\n        }\n\n        if (context.configuration.clipArea) {\n            context.canvas.resetClip();\n        }\n    };\n\n    IFScene.prototype._calculatePaintBBox = function () {\n        var bbox = IFElement.prototype._calculatePaintBBox.call(this);\n        if (this.__editor__ && this.__editor__.isTransformBoxActive()) {\n            var transBBox = this.__editor__.getTransformBox()._calculatePaintBBox();\n            if (transBBox && !transBBox.isEmpty()) {\n                bbox = bbox ? bbox.united(transBBox) : transBBox;\n            }\n        }\n        return bbox;\n    };\n\n    IFScene.prototype._calculateGeometryBBox = function () {\n        var bbox = IFElement.prototype._calculateGeometryBBox.call(this);\n        if (this.__editor__ && this.__editor__.isTransformBoxActive()) {\n            var transBBox = this.__editor__.getTransformBox()._calculatePaintBBox();\n            if (transBBox && !transBBox.isEmpty()) {\n                bbox = bbox ? bbox.united(transBBox) : transBBox;\n            }\n        }\n        return bbox;\n    };\n\n    /** @override */\n    IFScene.prototype._handleChange = function (change, args) {\n        IFElement.prototype._handleChange.call(this, change, args);\n    };\n\n    _.IFScene = IFScene;\n})(this);"
  },
  {
    "path": "src/infinity/scene/scenepaintconfiguration.js",
    "content": "(function (_) {\n    /**\n     * A paint configuration for model painting\n     * @class IFScenePaintConfiguration\n     * @constructor\n     * @extends IFPaintConfiguration\n     */\n    function IFScenePaintConfiguration() {\n    }\n\n    IFObject.inherit(IFScenePaintConfiguration, IFPaintConfiguration);\n\n    /**\n     * The paint mode of painting\n     * @enum\n     */\n    IFScenePaintConfiguration.PaintMode = {\n        /**\n         * Full painting in highest quality\n         * including annotations\n         */\n        Full: 'F',\n\n        /**\n         * Fast painting in lower quality,\n         * including annotations\n         */\n        Fast: 'S',\n\n        /**\n         * Outline painting\n         * including annotations\n         */\n        Outline: 'L',\n\n        /**\n         * Full painting in highest quality\n         * excluding annotations and clipping\n         * to paper\n         */\n        Output: 'O'\n    };\n\n    /**\n     * Localized names for IFScenePaintConfiguration.PaintMode\n     */\n    IFScenePaintConfiguration.PaintModeName = {\n        'F': new IFLocale.Key(IFScenePaintConfiguration, 'paint.full'),\n        'S': new IFLocale.Key(IFScenePaintConfiguration, 'paint.fast'),\n        'L': new IFLocale.Key(IFScenePaintConfiguration, 'paint.outline'),\n        'O': new IFLocale.Key(IFScenePaintConfiguration, 'paint.output')\n    };\n\n    /**\n     * The current paint mode\n     * @type {IFScenePaintConfiguration.PaintMode}\n     */\n    IFScenePaintConfiguration.prototype.paintMode = IFScenePaintConfiguration.PaintMode.Fast;\n\n    /**\n     * Whether to render in pixel mode or not\n     * @type {Boolean}\n     */\n    IFScenePaintConfiguration.prototype.pixelMode = false;\n\n    /**\n     * Whether to clip pages or not\n     * @type {Boolean}\n     */\n    IFScenePaintConfiguration.prototype.pagesClip = false;\n\n    /**\n     * Whether to show guides or not\n     * @type {Boolean}\n     */\n    IFScenePaintConfiguration.prototype.guides = true;\n\n    /**\n     * Whether to show slices or not\n     * @type {Boolean}\n     */\n    IFScenePaintConfiguration.prototype.slices = true;\n\n    /**\n     * Whether to show annotations or not (guides, slices, margins, etc.)\n     * @type {Boolean}\n     */\n    IFScenePaintConfiguration.prototype.annotations = true;\n\n    /**\n     * A clip area defining the area of paint for the scene\n     * @type {IFRect}\n     */\n    IFScenePaintConfiguration.prototype.clipArea = null;\n\n    /**\n     * Checks and returns whether to paint outlined or not\n     * @param {IFPaintContext} [context] optional context\n     * to include when checking\n     * @returns {boolean}\n     */\n    IFScenePaintConfiguration.prototype.isOutline = function (context) {\n        if (this.paintMode === IFScenePaintConfiguration.PaintMode.Outline) {\n            return true;\n        }\n        if (context && context.isOutline()) {\n            return context.isOutline();\n        }\n        return false;\n    };\n\n    /**\n     * Checks and returns whether to paint raster effects or not\n     * @param {IFPaintContext} [context] optional context\n     * to include when checking\n     * @returns {boolean}\n     */\n    IFScenePaintConfiguration.prototype.isRasterEffects = function (context) {\n        if (!this.isOutline(context)) {\n            return this.paintMode !== IFScenePaintConfiguration.PaintMode.Fast;\n        }\n        return false;\n    };\n\n    /**\n     * Checks and returns whether to paint annotations or not\n     * @param {IFPaintContext} [context] optional context\n     * to include when checking\n     * @returns {boolean}\n     */\n    IFScenePaintConfiguration.prototype.isAnnotationsVisible = function (context) {\n        if (!this.annotations || this.paintMode === IFScenePaintConfiguration.PaintMode.Output) {\n            return false;\n        }\n        return true;\n    };\n\n    /**\n     * Checks and returns whether to paint guides or not\n     * @param {IFPaintContext} [context] optional context\n     * to include when checking\n     * @returns {boolean}\n     */\n    IFScenePaintConfiguration.prototype.isGuidesVisible = function (context) {\n        if (!this.guides || !this.isAnnotationsVisible()) {\n            return false;\n        }\n        return true;\n    };\n\n    /**\n     * Checks and returns whether to paint slices or not\n     * @param {IFPaintContext} [context] optional context\n     * to include when checking\n     * @returns {boolean}\n     */\n    IFScenePaintConfiguration.prototype.isSlicesVisible = function (context) {\n        if (!this.slices || !this.isAnnotationsVisible()) {\n            return false;\n        }\n        return true;\n    };\n\n    /**\n     * Tests and returns wether pages should be clipped or not\n     * @param context\n     */\n    IFScenePaintConfiguration.prototype.isPagesClip = function (context) {\n        return (this.pagesClip || this.paintMode === IFScenePaintConfiguration.PaintMode.Output);\n    };\n\n    /** @override */\n    IFScenePaintConfiguration.prototype.toString = function () {\n        return \"[Object IFScenePaintConfiguration]\";\n    };\n\n    _.IFScenePaintConfiguration = IFScenePaintConfiguration;\n})(this);"
  },
  {
    "path": "src/infinity/scene/selector.js",
    "content": "/**\n * IFSelector - Selector Engine for GNodes\n * Based on\n * Sly v1.0rc2 <http://sly.digitarald.com> - (C) 2009 Harald Kirschner <http://digitarald.de> - Open source under MIT License\n */\n\n\nvar IFSelector = (function () {\n\n    var cache = {};\n\n    /**\n     * IFSelector::constructor\n     *\n     * Acts also as shortcut for IFSelector::search if context argument is given.\n     */\n    var IFSelector = function (text, context, results, options) {\n        // normalise\n        text = (typeof(text) == 'string') ? text.replace(/^\\s+|\\s+$/g, '') : '';\n\n        var cls = cache[text] || (cache[text] = new IFSelector.initialize(text));\n        return (context == null) ? cls : cls.search(context, results, options);\n    };\n\n    IFSelector.initialize = function (text) {\n        this.text = text;\n    };\n\n    var proto = IFSelector.initialize.prototype = IFSelector.prototype;\n\n    var locateFast = function () {\n        return true;\n    };\n\n    /**\n     * IFSelector::queryAll\n     */\n    proto.queryAll = function (context, results, options) {\n        options = options || {};\n\n        var iterate, i, item;\n\n        if (!context || !(context instanceof IFNode)) {\n            throw new Error(\"Missing context or invalid context\");\n        } else if (!(context instanceof IFNode)) {\n            if (typeof(context) == 'string') {\n                context = IFSelector.queryAll(context);\n                iterate = true;\n            } else if (Object.prototype.toString.call(context) == '[object Array]' || (typeof(context.length) == 'number' && context.item)) { // simple isArray\n                var filtered = [];\n                for (i = 0; (item = context[i]); i++) {\n                    if (item instanceof IFNode) filtered.push(item);\n                }\n                iterate = (filtered.length > 1);\n                context = (iterate) ? filtered : filtered[0];\n            }\n        }\n\n        var mixed, // results need to be sorted, comma\n            combined, // found nodes from one iteration process\n            nodes, // context nodes from one iteration process\n            all = {}, // unique ids for overall result\n            state = {}; // matchers temporary state\n        var current = all; // unique ids for one iteration process\n\n        // unifiers\n        var getUid = IFSelector.getUid;\n        var locateCurrent = function (node) {\n            var uid = getUid(node);\n            return (current[uid]) ? null : (current[uid] = true);\n        };\n\n        if (results && results.length) { // fills unique ids, does not alter the given results\n            for (i = 0; (item = results[i]); i++) locateCurrent(item);\n        }\n\n        var parsed = this.parse();\n        if (!parsed.length) return [];\n\n        for (var i = 0, selector; (selector = parsed[i]); i++) {\n\n            var locate = locateCurrent;\n\n            if (selector.first) {\n                if (!results) locate = locateFast;\n                else mixed = true;\n                if (iterate) nodes = context;\n                else if (selector.combinator) nodes = [context]; // allows combinators before selectors\n            }\n\n            if (selector.last && results) {\n                current = all;\n                combined = results;\n            } else {\n                // default stack\n                current = {};\n                combined = [];\n            }\n\n            if (!selector.combinator && !iterate) {\n                // without prepended combinator\n                combined = selector.combine(combined, context, selector, state, locate, !(combined.length));\n            } else {\n                // with prepended combinators\n                for (var k = 0, l = nodes.length; k < l; k++) {\n                    combined = selector.combine(combined, nodes[k], selector, state, locate);\n                }\n            }\n\n            if (selector.last) {\n                if (combined.length) results = combined;\n            } else {\n                nodes = combined;\n            }\n        }\n\n        return results || [];\n    };\n\n    /**\n     * IFSelector::querySingle\n     */\n    proto.querySingle = function (context, results, options) {\n        return this.queryAll(context, results, options)[0];\n    };\n\n\n    /**\n     * IFSelector::match\n     */\n    proto.match = function (node, parent) {\n        var parsed = this.parse();\n        if (parsed.length == 1) return !!(this.parse()[0].match(node, {}));\n        if (!parent) {\n            parent = node;\n            while (parent.getParent()) {\n                parent = parent.getParent();\n            }\n        }\n        var found = this.queryAll(parent), i = found.length;\n        while (i--) {\n            if (found[i] == node) return true;\n        }\n        return false;\n    };\n\n\n    /**\n     * IFSelector::filter\n     */\n    proto.filter = function (nodes) {\n        var results = [], parsed = this.parse();\n        for (var i = 0, node; (node = nodes[i]); i++) {\n            for (var k = 0; k < parsed.length; ++k) {\n                var match = parsed[k].match;\n                if (match(node)) results.push(node);\n            }\n        }\n        return results;\n    };\n\n\n    /**\n     * IFSelector.recompile()\n     */\n    var pattern;\n\n    IFSelector.recompile = function () {\n\n        var key, combList = [','], operList = ['!'];\n\n        for (key in combinators) {\n            if (key != ' ') {\n                combList[(key.length > 1) ? 'unshift' : 'push'](IFSelector.escapeRegExp(key));\n            }\n        }\n        for (key in propertyOperators) operList.push(key);\n\n        /**\n         The regexp is a group of every possible selector part including combinators.\n         \"|\" separates the possible selectors.\n\n         Capturing parentheses:\n         1 - Combinator (only requires to allow multiple-character combinators)\n         2 - Property name\n         3 - Property operator\n         4, 5, 6 - The value\n         7 - Pseudo name\n         8, 9, 10 - The value\n         */\n\n        pattern = new RegExp(\n            // A nodeName\n            '[\\\\w\\\\u00a1-\\\\uFFFF][\\\\w\\\\u00a1-\\\\uFFFF-]*|' +\n\n                // An id or the tag\n                '[#.](?:[\\\\w\\\\u00a1-\\\\uFFFF-]|\\\\\\\\:|\\\\\\\\.)+|' +\n\n                // Whitespace (descendant combinator)\n                '[ \\\\t\\\\r\\\\n\\\\f](?=[\\\\w\\\\u00a1-\\\\uFFFF*#.[:])|' +\n\n                // Other combinators and the comma\n                '[ \\\\t\\\\r\\\\n\\\\f]*(' + combList.join('|') + ')[ \\\\t\\\\r\\\\n\\\\f]*|' +\n\n                // A property, with the various and optional value formats ([name], [name=value], [name=\"value\"], [name='value']\n                '\\\\[([\\\\w\\\\u00a1-\\\\uFFFF-]+)[ \\\\t\\\\r\\\\n\\\\f]*(?:([' + operList.join('') + ']?=)[ \\\\t\\\\r\\\\n\\\\f]*(?:\"([^\"]*)\"|\\'([^\\']*)\\'|([^\\\\]]*)))?]|' +\n\n                // A pseudo-class, with various formats\n                ':([-\\\\w\\\\u00a1-\\\\uFFFF]+)(?:\\\\((?:\"([^\"]*)\"|\\'([^\\']*)\\'|([^)]*))\\\\))?|' +\n\n                // The universial selector, not process\n                '\\\\*|(.+)', 'g'\n        );\n    };\n\n\n// I prefer it outside, not sure if this is faster\n    var create = function (combinator) {\n        return {\n            ident: [],\n            tags: [],\n            properties: [],\n            pseudos: [],\n            combinator: combinator\n        };\n    };\n\n    var blank = function ($0) {\n        return $0;\n    };\n\n    /**\n     * IFSelector::parse\n     *\n     * Returns an array with one object for every selector:\n     *\n     * {\n     *   nodeName: (String) Node-name (defaults to null for universal *)\n     *   id: (String) Id\n     *   tags: (Array) Tagnames\n     *   properties: (Array) Properties objects with \"name\", \"operator\" and \"value\"\n     *   pseudos: (Array) Pseudo objects with \"name\" and \"value\"\n     *   operator: (Char) The prepended operator (not comma)\n     *   first: (Boolean) true if it is the first selector or the first after a comma\n     *   last: (Boolean) true if it is the last selector or the last before a comma\n     *   ident: (Array) All parsed matches, can be used as cache identifier.\n     * }\n     */\n    proto.parse = function (plain) {\n        var save = (plain) ? 'plain' : 'parsed';\n        if (this[save]) return this[save];\n\n        var text = this.text;\n        var compute = (plain) ? blank : this.compute;\n\n        var parsed = [], current = create(null);\n        current.first = true;\n\n        var refresh = function (combinator) {\n            parsed.push(compute(current));\n            current = create(combinator);\n        };\n\n        pattern.lastIndex = 0; // to fix some weird behavior\n        var match, $0;\n\n        while ((match = pattern.exec(text))) {\n\n            if (match[11]) {\n                if (IFSelector.verbose) throw SyntaxError('Syntax error, \"' + $0 + '\" unexpected at #' + pattern.lastIndex + ' in \"' + text + '\"');\n                return (this[save] = []);\n            }\n\n            $0 = match[0];\n\n            switch ($0.charAt(0)) {\n                case '.':\n                    current.tags.push($0.slice(1).replace(/\\\\/g, ''));\n                    break;\n                case '#':\n                    current.id = $0.slice(1).replace(/\\\\/g, '');\n                    break;\n                case '[':\n                    current.properties.push({\n                        name: match[2],\n                        operator: match[3] || null,\n                        value: match[4] || match[5] || match[6] || null\n                    });\n                    break;\n                case ':':\n                    current.pseudos.push({\n                        name: match[7],\n                        value: match[8] || match[9] || match[10] || null\n                    });\n                    break;\n                case ' ':\n                case '\\t':\n                case '\\r':\n                case '\\n':\n                case '\\f':\n                    match[1] = match[1] || ' ';\n                default:\n                    var combinator = match[1];\n                    if (combinator) {\n                        if (combinator == ',') {\n                            current.last = true;\n                            refresh(null);\n                            current.first = true;\n                            continue;\n                        }\n                        if (current.first && !current.ident.length) current.combinator = combinator;\n                        else refresh(combinator);\n                    } else {\n                        if ($0 != '*') current.nodeName = $0;\n                    }\n            }\n            current.ident.push($0);\n        }\n\n        current.last = true;\n        parsed.push(compute(current));\n\n        return (this[save] = parsed);\n    };\n\n\n// chains two given functions\n\n    function chain(prepend, append, aux, unshift) {\n        return (prepend) ? ((unshift) ? function (node, state) {\n            return append(node, aux, state) && prepend(node, state);\n        } : function (node, state) {\n            return prepend(node, state) && append(node, aux, state);\n        }) : function (node, state) {\n            return append(node, aux, state);\n        };\n        // fn.$slyIndex = (prepend) ? (prepend.$slyIndex + 1) : 0;\n    };\n\n\n// prepared match comperators, probably needs namespacing\n    var empty = function () {\n        return true;\n    };\n\n    var matchId = function (node, id) {\n        if (node.hasMixin(IFNode.Identity)) {\n            return (id === node.getId());\n        }\n        return false;\n    };\n\n    var matchNodeName = function (node, nodeName) {\n        return (node.getNodeName().toUpperCase() == nodeName.toUpperCase());\n    };\n\n    var prepareTag = function (name) {\n        return (new RegExp('(?:^|[ \\\\t\\\\r\\\\n\\\\f])' + name + '(?:$|[ \\\\t\\\\r\\\\n\\\\f])'));\n    };\n\n    var matchTag = function (node, expr) {\n        if (node.hasMixin(IFNode.Tag)) {\n            var tags = node.getTags();\n            return tags && expr.test(tags);\n        }\n        return false;\n    };\n\n    var prepareProperty = function (prop) {\n        if (!prop.operator || !prop.value) return prop;\n        var parser = propertyOperators[prop.operator];\n        if (parser) { // @todo: Allow functions, not only regex\n            prop.escaped = IFSelector.escapeRegExp(prop.value);\n            prop.pattern = new RegExp(parser(prop.value, prop.escaped, prop));\n        }\n        return prop;\n    };\n\n    var matchProperty = function (node, prop) {\n        // TODO : Support user properties as well\n        var read = node.hasMixin(IFNode.Properties) ? node.getProperty(prop.name) : null;\n        switch (prop.operator) {\n            case null:\n                return read;\n            case '=':\n                return (read == prop.value);\n            case '!=':\n                return (read != prop.value);\n        }\n        if (!read && prop.value) return false;\n        return prop.pattern.test(read);\n    };\n\n\n    /**\n     * IFSelector::compute\n     *\n     * Attaches the following methods to the selector object:\n     *\n     * {\n     *   search: Uses the most convinient properties (id, nodeName and/or tag) of the selector as search.\n     *   matchAux: If search does not contain all selector properties, this method matches an element against the rest.\n     *   match: Matches an element against all properties.\n     *   simple: Set when matchAux is not needed.\n     *   combine: The callback for the combinator\n     * }\n     */\n    proto.compute = function (selector) {\n        var i, item, match, search, matchSearch, named,\n            nodeName = selector.nodeName,\n            id = selector.id,\n            tags = selector.tags;\n\n        if (id) {\n            named = true;\n\n            matchSearch = chain(null, matchId, id);\n\n            search = function (context) {\n                var node = context._scene.getById(id);\n                return (node && (!nodeName || matchNodeName(node, nodeName))) ? [node] : [];\n            };\n        }\n\n        if (tags.length > 0) {\n\n            if (!search && tags.length == 1) { // optimised for typical .one-tag-only\n\n                named = true;\n\n                var expr = prepareTag(tags[0]);\n                matchSearch = chain(matchSearch, matchTag, expr);\n\n                search = function (context) {\n                    var query = context.getNodesByName(nodeName || '*');\n                    var found = [];\n                    for (var i = 0, node; (node = query[i]); i++) {\n                        if (matchTag(node, tags[0])) found.push(node);\n                    }\n                    return found;\n                };\n\n            } else {\n\n                for (i = 0; (item = tags[i]); i++) {\n                    match = chain(match, matchTag, prepareTag(item));\n                }\n\n            }\n        }\n\n        if (nodeName) {\n\n            if (!search) {\n                matchSearch = chain(matchSearch, matchNodeName, nodeName);\n\n                search = function (context) {\n                    return context.getNodesByName(nodeName);\n                };\n            } else if (!named) { // search does not filter by name yet\n                match = chain(match, matchNodeName, nodeName);\n            }\n\n        } else if (!search) { // default engine\n\n            search = function (context) {\n                return context.getNodesByName('*');\n            };\n\n        }\n\n        for (i = 0; (item = selector.pseudos[i]); i++) {\n\n            if (item.name == 'not') { // optimised :not(), fast as possible\n                var not = IFSelector(item.value);\n                match = chain(match, function (node, not) {\n                    return !not.match(node);\n                }, (not.parse().length == 1) ? not.parsed[0] : not);\n            } else {\n                var parser = pseudos[item.name];\n                if (parser) match = chain(match, parser, item.value);\n            }\n\n        }\n\n        for (i = 0; (item = selector.properties[i]); i++) {\n            match = chain(match, matchProperty, prepareProperty(item));\n        }\n\n        if ((selector.simple = !(match))) {\n            selector.matchAux = empty;\n        } else {\n            selector.matchAux = match;\n            matchSearch = chain(matchSearch, match);\n        }\n\n        selector.match = matchSearch || empty;\n\n        selector.combine = IFSelector.combinators[selector.combinator || ' '];\n\n        selector.search = search;\n\n        return selector;\n    };\n\n// Combinators/Pseudos partly from MooTools 1.2-pre, (c) 2006-2009 Valerio Proietti, MIT License\n\n    /**\n     * Combinators\n     */\n    var combinators = IFSelector.combinators = {\n\n        ' ': function (combined, context, selector, state, locate, fast) {\n            var nodes = selector.search(context);\n            if (fast && selector.simple) return IFSelector.toArray(nodes);\n            for (var i = 0, node, aux = selector.matchAux; (node = nodes[i]); i++) {\n                if (locate(node) && aux(node, state)) combined.push(node);\n            }\n            return combined;\n        },\n\n        '>': function (combined, context, selector, state, locate) {\n            var nodes = selector.search(context);\n            for (var i = 0, node; (node = nodes[i]); i++) {\n                if (node.getParent() == context && locate(node) && selector.matchAux(node, state)) combined.push(node);\n            }\n            return combined;\n        },\n\n        '+': function (combined, context, selector, state, locate) {\n            while ((context = context.getNext())) {\n                if (locate(context) && selector.match(context, state)) combined.push(context);\n                break;\n            }\n            return combined;\n        },\n\n        '~': function (combined, context, selector, state, locate) {\n            while ((context = context.getNext())) {\n                if (!locate(context)) break;\n                if (selector.match(context, state)) combined.push(context);\n            }\n            return combined;\n        },\n\n        // Returns all matched parent nodes\n        '<': function (combined, context, selector, state, locate) {\n            while ((context = context.getParent()) && !(context instanceof IFScene)) {\n                if (locate(context) && selector.match(context, state)) combined.push(context);\n            }\n            return combined;\n        },\n\n        // Returns the first matched descendant children\n        '^': function (combined, context, selector, state, locate) {\n            if ((context = context.getFirstChild())) {\n                if (locate(context) && selector.match(context, state)) combined.push(context);\n                else combined = IFSelector.combinators['+'](combined, context, selector, context, state);\n            }\n            return combined;\n        },\n\n        // Returns all matched next slibings\n        '++': function (combined, context, selector, state, locate) {\n            while ((context = context.getNext())) {\n                if (locate(context) && this.match(context, state)) combined.push(context);\n            }\n            return combined;\n        },\n\n        // Returns all matched previous slibings\n        '--': function (combined, context, selector, state, locate) {\n            while ((context = context.getPrevious())) {\n                if (locate(context) && this.match(context, state)) combined.push(context);\n            }\n            return combined;\n        }\n\n    };\n\n\n    /**\n     * Pseudo-Classes\n     */\n    var pseudos = IFSelector.pseudos = {\n\n        // w3c pseudo classes\n\n        'first-child': function (node) {\n            return pseudos.index(node, 0);\n        },\n\n        'last-child': function (node) {\n            return node.getNext() == null;\n        },\n\n        'only-child': function (node) {\n            return node.getPrevious() == null && node.getNext() == null;\n        },\n\n        'nth-child': function (node, value, state) {\n            var parsed = IFSelector.parseNth(value || 'n');\n            if (parsed.special != 'n') return pseudos[parsed.special](node, parsed.a, state);\n            state = state || {}; // just to be sure\n            state.positions = state.positions || {};\n            var uid = IFSelector.getUid(node);\n            if (!state.positions[uid]) {\n                var count = 0;\n                while ((node = node.getPrevious())) {\n                    count++;\n                    var position = state.positions[IFSelector.getUid(node)];\n                    if (position != undefined) {\n                        count = position + count;\n                        break;\n                    }\n                }\n                state.positions[uid] = count;\n            }\n            return (state.positions[uid] % parsed.a == parsed.b);\n        },\n\n        'empty': function (node) {\n            // TODO : Support this - for text elements and for regular elements (no children)\n            //return !(node.innerText || node.textContent || '').length;\n            return false;\n        },\n\n        'contains': function (node, text) {\n            // TODO : Support this for text elements\n            //return (node.innerText || node.textContent || '').indexOf(text) != -1;\n            return false;\n        },\n\n        'index': function (node, index) {\n            var count = 1;\n            while ((node = node.getPrevious())) {\n                if (++count > index) return false;\n            }\n            return (count == index);\n        },\n\n        'even': function (node, value, state) {\n            return pseudos['nth-child'](node, '2n+1', state);\n        },\n\n        'odd': function (node, value, state) {\n            return pseudos['nth-child'](node, '2n', state);\n        },\n\n        // Custom selectors\n\n        // Matches elements which contain at least one element that matches the specified selector.\n        'has': function (node, argument) {\n            return IFSelector.querySingle(argument, node);\n        },\n\n        // Flag selectors\n\n        // Matches all nodes that are selected.\n        'active': function (node) {\n            return (node.hasFlag(IFNode.Flag.Active));\n        },\n\n        // Matches all nodes that are selected.\n        'selected': function (node) {\n            return (node.hasFlag(IFNode.Flag.Selected));\n        },\n\n        // Matches all elements that are hidden.\n        'hidden': function (node) {\n            return (node instanceof IFElement && node.hasFlag(IFElement.Flag.Hidden));\n        },\n\n        // Matches all elements that are visible.\n        'visible': function (node) {\n            return (node instanceof IFElement && !node.hasFlag(IFElement.Flag.Hidden));\n        }\n    };\n\n    pseudos.first = pseudos['first-child'];\n    pseudos.last = pseudos['last-child'];\n    pseudos.nth = pseudos['nth-child'];\n    pseudos.eq = pseudos.index;\n\n\n    /**\n     * Property operators\n     */\n    var propertyOperators = IFSelector.propertyOperators = {\n\n        '*=': function (value, escaped) {\n            return escaped;\n        },\n\n        '^=': function (value, escaped) {\n            return '^' + escaped;\n        },\n\n        '$=': function (value, escaped) {\n            return value + '$';\n        },\n\n        '~=': function (value, escaped) {\n            return '(?:^|[ \\\\t\\\\r\\\\n\\\\f])' + escaped + '(?:$|[ \\\\t\\\\r\\\\n\\\\f])';\n        },\n\n        '|=': function (value, escaped) {\n            return '(?:^|\\\\|)' + escaped + '(?:$|\\\\|)';\n        },\n\n        // Matches the property value against the given regexp, flags are not possible yet\n        '/=': function (value, escaped) {\n            return value;\n        }\n\n    };\n\n    /**\n     * IFSelector.toArray\n     */\n    var toArray = Array.slice || function (nodes) {\n        return Array.prototype.slice.call(nodes);\n    };\n\n    try {\n        toArray(scene.sceneElement.childNodes);\n    } catch (e) {\n        toArray = function (nodes) {\n            if (nodes instanceof Array) return nodes;\n            var i = nodes.length, results = new Array(i);\n            while (i--) results[i] = nodes[i];\n            return results;\n        };\n    }\n\n    IFSelector.toArray = toArray;\n\n    /**\n     * IFSelector.getUid\n     */\n    var nextUid = 1;\n\n    IFSelector.getUid = (window.ActiveXObject) ? function (node) {\n        return (node.__slyUid || (node.__slyUid = {id: nextUid++})).id;\n    } : function (node) {\n        return node.__slyUid || (node.__slyUid = nextUid++);\n    };\n\n\n    var nthCache = {};\n\n    IFSelector.parseNth = function (value) {\n        if (nthCache[value]) return nthCache[value];\n\n        var parsed = value.match(/^([+-]?\\d*)?([a-z]+)?([+-]?\\d*)?$/);\n        if (!parsed) return false;\n\n        var a = parseInt(parsed[1], 10), b = (parseInt(parsed[3], 10) || 0) - 1;\n\n        if ((a = (isNaN(a)) ? 1 : a)) {\n            while (b < 1) b += a;\n            while (b >= a) b -= a;\n        }\n        switch (parsed[2]) {\n            case 'n':\n                parsed = {a: a, b: b, special: 'n'};\n                break;\n            case 'odd':\n                parsed = {a: 2, b: 0, special: 'n'};\n                break;\n            case 'even':\n                parsed = {a: 2, b: 1, special: 'n'};\n                break;\n            case 'first':\n                parsed = {a: 0, special: 'index'};\n                break;\n            case 'last':\n                parsed = {special: 'last-child'};\n                break;\n            case 'only':\n                parsed = {special: 'only-child'};\n                break;\n            default:\n                parsed = {a: (a) ? (a - 1) : b, special: 'index'};\n        }\n\n        return (nthCache[value] = parsed);\n    };\n\n\n    IFSelector.escapeRegExp = function (text) {\n        return text.replace(/[-.*+?^${}()|[\\]\\/\\\\]/g, '\\\\$&');\n    };\n\n\n// generic accessors\n\n    IFSelector.generise = function (name) {\n        IFSelector[name] = function (text) {\n            var cls = IFSelector(text);\n            return cls[name].apply(cls, Array.prototype.slice.call(arguments, 1));\n        }\n    };\n\n    var generics = ['parse', 'queryAll', 'querySingle', 'match', 'filter'];\n    for (var i = 0; generics[i]; i++) IFSelector.generise(generics[i]);\n\n\n// compile pattern for the first time\n\n    IFSelector.recompile();\n\n// FIN\n\n    return IFSelector;\n})();"
  },
  {
    "path": "src/infinity/scene/shape/ellipse.js",
    "content": "(function (_) {\n\n    /**\n     * An ellipse shape\n     * @class IFEllipse\n     * @extends IFPathBase\n     * @constructor\n     */\n    function IFEllipse() {\n        IFPathBase.call(this);\n        this._setDefaultProperties(IFEllipse.GeometryProperties);\n        this._invalidatePath(); // create unit path\n    }\n\n    IFNode.inherit(\"ellipse\", IFEllipse, IFPathBase);\n\n    /**\n     * Various types for an ellipse\n     * @enum\n     * @version 1.0\n     */\n    IFEllipse.Type = {\n        /**\n         * Pie (center-closed ellipse) type\n         * @type {Number}\n         * @version 1.0\n         */\n        Pie: 0,\n\n        /**\n         * Chord (closed ellipse) type\n         * @type {Number}\n         * @version 1.0\n         */\n        Chord: 1,\n\n        /**\n         * Arc (opened ellipse) type\n         * @type {Number}\n         * @version 1.0\n         */\n        Arc: 2\n    };\n\n    /**\n     * The geometry properties of an ellipse with their default values\n     */\n    IFEllipse.GeometryProperties = {\n        /** The start angle */\n        sa: Math.PI,\n        /** The end angle */\n        ea: Math.PI,\n        /** The ellipse-type */\n        etp: IFEllipse.Type.Pie\n    };\n\n    /** @override */\n    IFEllipse.prototype.store = function (blob) {\n        if (IFPathBase.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFEllipse.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFEllipse.prototype.restore = function (blob) {\n        if (IFPathBase.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFEllipse.GeometryProperties);\n\n            this._invalidatePath();\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFEllipse.prototype._handleChange = function (change, args) {\n        if (this._handleGeometryChangeForProperties(change, args, IFEllipse.GeometryProperties) && change == IFNode._Change.AfterPropertiesChange) {\n            this._invalidatePath();\n        }\n        IFPathBase.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * @private\n     */\n    IFEllipse.prototype._invalidatePath = function () {\n        var anchorPoints = this._getAnchorPoints();\n\n        this.beginUpdate();\n        anchorPoints._beginBlockCompositeEvents(true, true, true);\n        try {\n            // Clear old path points\n            anchorPoints.clearChildren();\n\n            var an;\n            for (an = Math.PI / 2; an <= this.$sa || ifMath.isEqualEps(an, this.$sa); an += Math.PI / 2) {\n            }\n\n            var anchorPoint = new IFPathBase.AnchorPoint();\n            anchorPoint.setProperties(['x', 'y', 'tp', 'ah'], [Math.cos(this.$sa), Math.sin(this.$sa), IFPathBase.AnchorPoint.Type.Symmetric, true]);\n            anchorPoints.appendChild(anchorPoint);\n\n            var ea = ifMath.isEqualEps(this.$sa, this.$ea) ? this.$sa + ifMath.PI2 : this.$ea;\n            if (ea < this.$sa) {\n                ea += ifMath.PI2;\n            }\n\n            for (an; an < ea && !ifMath.isEqualEps(an, ea); an += Math.PI / 2) {\n                anchorPoint = new IFPathBase.AnchorPoint();\n                anchorPoint.setProperties(['x', 'y', 'tp', 'ah'], [Math.cos(an), Math.sin(an), IFPathBase.AnchorPoint.Type.Symmetric, true]);\n                anchorPoints.appendChild(anchorPoint);\n            }\n\n            if (!ifMath.isEqualEps(this.$sa + ifMath.PI2, ea)) {\n                anchorPoint = new IFPathBase.AnchorPoint();\n                anchorPoint.setProperties(['x', 'y', 'tp', 'ah'], [Math.cos(ea), Math.sin(ea), IFPathBase.AnchorPoint.Type.Symmetric, true]);\n                anchorPoints.appendChild(anchorPoint);\n            }\n\n            var extraPoint = null;\n            if (anchorPoints.getFirstChild().getNext() == anchorPoints.getLastChild()) {\n                // We have only two anchor points, so add one for proper auto-handles, making rounded shape,\n                // and then switch off auto-handles and remove that extra point\n                anchorPoint = new IFPathBase.AnchorPoint();\n                if (ifMath.isEqualEps(an, ea)) {\n                    an += Math.PI / 2;\n                }\n                anchorPoint.setProperties(['x', 'y', 'tp', 'ah'], [Math.cos(an), Math.sin(an), IFPathBase.AnchorPoint.Type.Symmetric, true]);\n                anchorPoints.appendChild(anchorPoint);\n                extraPoint = anchorPoint;\n            }\n\n            this.setProperty('closed', true);\n            for (var ap = anchorPoints.getFirstChild(); ap != null; ap = ap.getNext()) {\n                // Don't change auto-handles to true here! They must be true at first to be calculated properly for\n                // good rounded arc, but then they must be set to false, as they should not be affected with the\n                // rest changes\n                ap.setProperty('ah', false);\n            }\n\n            if (extraPoint) {\n                anchorPoints.removeChild(extraPoint);\n            }\n\n            if (!ifMath.isEqualEps(this.$sa + ifMath.PI2, ea)) {\n                anchorPoints.getFirstChild().setProperties(['tp', 'hlx', 'hly'], [IFPathBase.AnchorPoint.Type.Asymmetric, null, null]);\n                anchorPoints.getLastChild().setProperties(['tp', 'hrx', 'hry'], [IFPathBase.AnchorPoint.Type.Asymmetric, null, null]);\n\n                if (this.$etp == IFEllipse.Type.Pie) {\n                    anchorPoint = new IFPathBase.AnchorPoint();\n                    anchorPoints.appendChild(anchorPoint);\n                } else if (this.$etp == IFEllipse.Type.Arc) {\n                    this.setProperty('closed', false);\n                }\n            }\n        } finally {\n            this.endUpdate();\n            anchorPoints._endBlockCompositeEvents(true, true, true);\n        }\n    };\n\n    /** @override */\n    IFEllipse.prototype.toString = function () {\n        return \"[IFEllipse]\";\n    };\n\n    _.IFEllipse = IFEllipse;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/image.js",
    "content": "(function (_) {\n\n    /**\n     * A raster image shape\n     * @class IFImage\n     * @extends IFShape\n     * @constructor\n     */\n    function IFImage() {\n        IFShape.call(this);\n        this._setDefaultProperties(IFImage.VisualProperties);\n        this._image = new Image();\n        this._image.onload = this._updatedImage.bind(this);\n        this._image.onerror = this._updatedImage.bind(this);\n        this._image.onabort = this._updatedImage.bind(this);\n        this._updateImage();\n    }\n\n    IFNode.inheritAndMix(\"image\", IFImage, IFShape);\n\n    /**\n     * Visual properties of an image\n     */\n    IFImage.VisualProperties = {\n        url: null\n    };\n\n    /**\n     * @enum\n     */\n    IFImage.ImageStatus = {\n        Loaded: 0,\n        Resolving: 1,\n        Loading: 2,\n        Delayed: 3,\n        Error: 10\n    };\n\n    /**\n     * @type {Number}\n     */\n    IFImage.NO_IMAGE_WIDTH = 100;\n\n    /**\n     * @type {Number}\n     */\n    IFImage.NO_IMAGE_HEIGHT = 100;\n\n    /**\n     * @type {Number}\n     */\n    IFImage.NO_IMAGE_BACKGROUND = new IFColor(IFColor.Type.RGB, [240, 240, 240, 100]);\n\n    /**\n     * @type {Number}\n     */\n    IFImage.NO_IMAGE_ERROR_STROKE = new IFColor(IFColor.Type.RGB, [255, 0, 0, 100]);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFImage.StatusEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event called when the status of this image changes\n     * @param {IFImage} image the image\n     * @param {IFImage.ImageStatus} status the status\n     * @class IFImage.StatusEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFImage.StatusEvent = function (image, status) {\n        this.image = image;\n        this.status = status;\n    };\n    IFObject.inherit(IFImage.StatusEvent, GEvent);\n\n    /**\n     * The status\n     * @type IFImage\n     */\n    IFImage.StatusEvent.prototype.image = null;\n\n    /**\n     * The status\n     * @type IFImage.ImageStatus\n     */\n    IFImage.StatusEvent.prototype.status = null;\n\n    /** @override */\n    IFImage.StatusEvent.prototype.toString = function () {\n        return \"[Event IFImage.StatusEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFImage Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @type {IFImage.ImageStatus}\n     * @private\n     */\n    IFImage.prototype._status = null;\n\n    /**\n     * @type {Image}\n     * @private\n     */\n    IFImage.prototype._image = null;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    IFImage.prototype._vertexIterator = 0;\n\n    /**\n     * Returns the status of the image\n     * @return {IFImage.ImageStatus}\n     */\n    IFImage.prototype.getStatus = function () {\n        return this._status;\n    };\n\n    /**\n     * Returns the underlying image\n     * return {Image}\n     */\n    IFImage.prototype.getImage = function () {\n        return this._image;\n    };\n\n    /** @override */\n    IFImage.prototype.store = function (blob) {\n        if (IFShape.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFImage.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFImage.prototype.restore = function (blob) {\n        if (IFShape.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFImage.VisualProperties);\n            this._updateImage();\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFImage.prototype.rewindVertices = function (index) {\n        this._vertexIterator = index;\n        return true;\n    };\n\n    /** @override */\n    IFImage.prototype.readVertex = function (vertex) {\n        switch (this._vertexIterator) {\n            case 0:\n                vertex.command = IFVertex.Command.Move;\n                vertex.x = 0;\n                vertex.y = 0;\n                break;\n            case 1:\n                vertex.command = IFVertex.Command.Line;\n                vertex.x = this._getWidth();\n                vertex.y = 0;\n                break;\n            case 2:\n                vertex.command = IFVertex.Command.Line;\n                vertex.x = this._getWidth();\n                vertex.y = this._getHeight();\n                break;\n            case 3:\n                vertex.command = IFVertex.Command.Line;\n                vertex.x = 0;\n                vertex.y = this._getHeight();\n                break;\n            case 4:\n                vertex.command = IFVertex.Command.Close;\n                break;\n            default:\n                return false;\n        }\n\n        if (vertex.command !== IFVertex.Command.Close && this.$trf) {\n            this.$trf.map(vertex);\n        }\n\n        this._vertexIterator += 1;\n\n        return true;\n    };\n\n    /** @overide */\n    IFImage.prototype._paintBackground = function (context, style, styleIndex) {\n        // Only paint for no style and no outline, otherwise this will be done in _paintStyle\n        if (!style && !context.configuration.isOutline(context)) {\n            this._paintImage(context);\n        }\n\n        IFShape.prototype._paintBackground.call(this, context);\n    };\n\n    /** @override */\n    IFImage.prototype._paintStyle = function (context, style, styleIndex) {\n        if (this._status === IFImage.ImageStatus.Loaded) {\n            // Image styles are painted on temporary canvas and then clipped against the image\n            var sourceCanvas = context.canvas;\n            context.canvas = sourceCanvas.createCanvas(style.getBBox(this.getGeometryBBox()));\n\n            // Paint image contents now (for first style, only)\n            if (styleIndex === 0) {\n                this._paintImage(context);\n            }\n\n            try {\n                IFShape.prototype._paintStyle.call(this, context, style, styleIndex);\n            } finally {\n                // Paint image contents now again but cut it out\n                this._paintImage(context, IFPaintCanvas.CompositeOperator.DestinationIn)\n\n                // Paint canvas back and swap again\n                sourceCanvas.drawCanvas(context.canvas);\n                context.canvas = sourceCanvas;\n            }\n        } else {\n            this._paintImage(context);\n            IFShape.prototype._paintStyle.call(this, context, style, styleIndex);\n        }\n    };\n\n    /** @override */\n    IFImage.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        // TODO : Make correct shape hit test here instead\n        return new IFElement.HitResult(this);\n    };\n\n    /** @override */\n    IFImage.prototype._handleChange = function (change, args) {\n        if (change == IFNode._Change.AfterPropertiesChange) {\n            if (args.properties.indexOf('url') >= 0) {\n                this._updateImage();\n            }\n        }\n\n        IFShape.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFImage.prototype._setScene = function (scene) {\n        IFShape.prototype._setScene.call(this, scene);\n        if (this._scene && this._status === IFImage.ImageStatus.Delayed) {\n            this._updateImage();\n        }\n    };\n\n    /**\n     * @param {IFPaintContext} context\n     * @private\n     */\n    IFImage.prototype._paintImage = function (context, cmpOrBlend) {\n        // Apply our transformation (if any) before the canvas transformation\n        var canvasTransform = context.canvas.getTransform(true);\n        if (this.$trf) {\n            var tmpTransform = canvasTransform.preMultiplied(this.$trf);\n            context.canvas.setTransform(tmpTransform);\n        }\n\n        // Paint depending on our status\n        switch (this._status) {\n            case IFImage.ImageStatus.Loaded:\n                context.canvas.drawImage(this._image, 0, 0, false, 1, cmpOrBlend);\n                break;\n\n            default:\n                var width = this._getWidth();\n                var height = this._getHeight();\n\n                context.canvas.fillRect(0, 0, width, height, IFImage.NO_IMAGE_BACKGROUND);\n\n                // TODO : Paint some loading indicator!?\n\n                if (this._status === IFImage.ImageStatus.Error) {\n                    // Paint red cross\n                    context.canvas.strokeLine(0, 0, width, height, 2, IFImage.NO_IMAGE_ERROR_STROKE);\n                    context.canvas.strokeLine(width, 0, 0, height, 2, IFImage.NO_IMAGE_ERROR_STROKE);\n                }\n                break;\n        }\n\n        // Reset original transform\n        context.canvas.setTransform(canvasTransform);\n    };\n\n    /**\n     * Return the actual width of the image shape\n     * @returns {number}\n     * @private\n     */\n    IFImage.prototype._getWidth = function () {\n        if (this._image.naturalWidth) {\n            return this._image.naturalWidth;\n        } else {\n            return IFImage.NO_IMAGE_WIDTH;\n        }\n    };\n\n    /**\n     * Return the actual height of the image shape\n     * @returns {number}\n     * @private\n     */\n    IFImage.prototype._getHeight = function () {\n        if (this._image.naturalHeight) {\n            return this._image.naturalHeight;\n        } else {\n            return IFImage.NO_IMAGE_HEIGHT;\n        }\n    };\n\n    /**\n     * Called to update the url of our image\n     * @private\n     */\n    IFImage.prototype._updateImage = function () {\n        if (!this.isAttached()) {\n            this._setStatus(IFImage.ImageStatus.Delayed);\n        } else {\n            this._setStatus(IFImage.ImageStatus.Resolving);\n            this._scene.resolveUrl(this.$url, this._resolvedImage.bind(this));\n        }\n    };\n    /**\n     * Called to load the image when an url is resolved\n     * @private\n     */\n    IFImage.prototype._resolvedImage = function (url) {\n        this._setStatus(IFImage.ImageStatus.Loading);\n\n        this._notifyChange(IFElement._Change.InvalidationRequest);\n        this._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n\n        this._image.src = url;\n    };\n\n    /**\n     * Called from one of the listeners on our image\n     * @private\n     */\n    IFImage.prototype._updatedImage = function () {\n        this._notifyChange(IFElement._Change.FinishGeometryUpdate);\n\n        if (this._image.naturalWidth !== 0 && this._image.naturalHeight !== 0) {\n            this._setStatus(IFImage.ImageStatus.Loaded);\n        } else {\n            this._setStatus(IFImage.ImageStatus.Error);\n        }\n    };\n\n    /**\n     * @param {IFImage.ImageStatus} status\n     * @private\n     */\n    IFImage.prototype._setStatus = function (status) {\n        if (status !== this._status) {\n            this._status = status;\n            if (this.isAttached() && this._scene.hasEventListeners(IFImage.StatusEvent)) {\n                this._scene.trigger(new IFImage.StatusEvent(this, this._status));\n            }\n        }\n    };\n\n    /** @override */\n    IFImage.prototype.toString = function () {\n        return \"[IFImage]\";\n    };\n\n    _.IFImage = IFImage;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/path.js",
    "content": "(function (_) {\n\n    /**\n     * A path shape\n     * @class IFPath\n     * @extends IFPathBase\n     * @constructor\n     */\n    function IFPath(closed, evenOdd, anchorPoints) {\n        IFPathBase.call(this, closed, evenOdd, anchorPoints);\n        this._setDefaultProperties(IFPath.GeometryProperties);\n    }\n\n    IFNode.inherit(\"path\", IFPath, IFPathBase);\n\n    /**\n     * The geometry properties of a path with their default values\n     */\n    IFPath.GeometryProperties = {\n        /** Closed or not */\n        closed: false\n    };\n\n    /**\n     * Return the anchor points of the path\n     * @returns {IFPathBase.AnchorPoints}\n     */\n    IFPath.prototype.getAnchorPoints = function () {\n        return this._getAnchorPoints();\n    };\n\n    /** @override */\n    IFPath.prototype.store = function (blob) {\n        if (IFPathBase.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFPath.GeometryProperties);\n\n            // Store our anchor points\n            blob.pts = this.getAnchorPoints().serialize();\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPath.prototype.restore = function (blob) {\n        if (IFPathBase.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFPath.GeometryProperties);\n\n            // Restore our anchor points\n            if (blob.hasOwnProperty('pts')) {\n                this.getAnchorPoints().deserialize(blob.pts);\n            }\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPath.prototype.clone = function () {\n        var clone = IFPathBase.prototype.clone.call(this);\n\n        // Transfer selected anchor points as flags are not cloned\n        var selectedAnchorPoints = this.getAnchorPoints().queryAll(':selected');\n        for (var i = 0; i < selectedAnchorPoints.length; ++i) {\n            var anchorPointIndex = this.getAnchorPoints().getIndexOfChild(selectedAnchorPoints[i]);\n            var cloneAnchorPoint = clone.getAnchorPoints().getChildByIndex(anchorPointIndex);\n            if (cloneAnchorPoint) {\n                cloneAnchorPoint.setFlag(IFNode.Flag.Selected);\n            }\n        }\n\n        return clone;\n    };\n\n    /**\n     * Hit-tests the path for the location. Corner styles are not applied.\n     * @param {IFPoint} location\n     * @param {IFTransform} transform - a transformation to be applied to the path before hit-testing in addition to\n     * path internal transformation, if any\n     * @param {Boolean} area - indicates if path inside should be tested\n     * @param {Boolean} [tolerance] optional hit test tolerance, defaults to zero\n     * @returns {IFElement.HitResult} if hit, or null otherwise; hit result contains all data\n     * in the path native anchor points coordinates\n     */\n    IFPath.prototype.pathHitTest = function (location, transform, area, tolerance) {\n        tolerance = tolerance || 0;\n        var locationInvTransformed = location;\n        var scaleFactor = 1;\n\n        if (transform) {\n            var invTransform = transform.inverted();\n            locationInvTransformed = invTransform.mapPoint(location);\n            scaleFactor = scaleFactor * invTransform.getScaleFactor();\n        }\n\n        var origTransform = null;\n        if (this.$trf) {\n            origTransform = this.$trf;\n            this.$trf = null;\n            var invTransform = origTransform.inverted();\n            locationInvTransformed = invTransform.mapPoint(locationInvTransformed);\n            scaleFactor = scaleFactor * invTransform.getScaleFactor();\n        }\n\n        // Generate unstyled vertices\n        // TODO : Cache this???\n        var vertices = new IFVertexContainer();\n        this._getAnchorPoints()._generateVertices(vertices, this.$trf, false);\n\n        var hitResult = new IFVertexInfo.HitResult();\n        var elemHitRes = null;\n        var outlineWidth = scaleFactor + tolerance * 2;\n\n        if (ifVertexInfo.hitTest(locationInvTransformed.getX(), locationInvTransformed.getY(),\n            vertices, outlineWidth, this.$closed ? area : false, hitResult)) {\n            elemHitRes = new IFElement.HitResult(this, hitResult);\n        }\n\n        if (origTransform) {\n            this.$trf = origTransform;\n        }\n\n        return elemHitRes;\n    };\n\n    /**\n     * Creates and inserts a new point into the path. The point location is specified in the result of hit-test\n     * @param {IFVertexInfo.HitResult} hitResult\n     * @returns {IFPathBase.AnchorPoint} a newly inserted anchor point, or null if no new point was inserted\n     */\n    IFPath.prototype.insertHitPoint = function (hitResult) {\n        if (!hitResult || !hitResult.slope ||\n            ifMath.isEqualEps(hitResult.slope, 0) || ifMath.isEqualEps(hitResult.slope, 1)) {\n\n            return null;\n        }\n        var slope = hitResult.slope;\n\n        var idx = 1;\n        var aPt = this.getAnchorPoints().getFirstChild();\n        while (aPt != null && idx < hitResult.segment) {\n            aPt = aPt.getNext();\n            idx++;\n        }\n\n        var aPrev = aPt;\n        var aNext = aPrev ? this.getAnchorPoints().getNextPoint(aPrev) : null;\n        if (!aPrev || !aNext) {\n            return null;\n        } else {\n            this.beginUpdate();\n            aPrev.setProperty('ah', false);\n            aNext.setProperty('ah', false);\n\n            var tpaPrev = aPrev.getProperty('tp');\n            var tpaNext = aNext.getProperty('tp');\n            var tpaNew;\n            if (tpaPrev == IFPathBase.AnchorPoint.Type.Connector ||\n                tpaPrev == IFPathBase.AnchorPoint.Type.Symmetric ||\n                tpaPrev == IFPathBase.AnchorPoint.Type.Mirror ||\n                tpaNext == IFPathBase.AnchorPoint.Type.Connector ||\n                tpaNext == IFPathBase.AnchorPoint.Type.Symmetric ||\n                tpaNext == IFPathBase.AnchorPoint.Type.Mirror ||\n                (tpaPrev == IFPathBase.AnchorPoint.Type.Asymmetric &&\n                    tpaNext == IFPathBase.AnchorPoint.Type.Asymmetric)) {\n\n                // One of near points is smooth or both have no styled corners\n                tpaNew = IFPathBase.AnchorPoint.Type.Asymmetric;\n            } else if (tpaPrev != IFPathBase.AnchorPoint.Type.Symmetric &&\n                tpaPrev != IFPathBase.AnchorPoint.Type.Mirror &&\n                tpaPrev != IFPathBase.AnchorPoint.Type.Connector &&\n                tpaPrev != IFPathBase.AnchorPoint.Type.Asymmetric) {\n\n                // aPrev has styled corner\n                tpaNew = tpaPrev;\n            } else {\n                // aNext has styled corner\n                tpaNew = tpaNext;\n            }\n\n            var newAPt = null;\n            var p1x, c1x, c2x, p2x, p1y, c1y, c2y, p2y;\n\n            p1x = aPrev.getProperty('x');\n            p1y = aPrev.getProperty('y');\n            c1x = aPrev.getProperty('hrx');\n            c1y = aPrev.getProperty('hry');\n            p2x = aNext.getProperty('x');\n            p2y = aNext.getProperty('y');\n            c2x = aNext.getProperty('hlx');\n            c2y = aNext.getProperty('hly');\n\n            var zeroC1 = c1x == null || c1y == null || ifMath.isEqualEps(c1x, p1x) && ifMath.isEqualEps(c1y, p1y);\n            var zeroC2 = c2x == null || c2y == null || ifMath.isEqualEps(c2x, p2x) && ifMath.isEqualEps(c2y, p2y);\n\n            // If line\n            if (zeroC1 && zeroC2) {\n                newAPt = new IFPath.AnchorPoint();\n                newAPt.setProperties(['x', 'y', 'tp'],\n                    [p1x + slope * (p2x - p1x), p1y + slope * (p2y - p1y), tpaNew]);\n                this.getAnchorPoints().insertChild(newAPt, aNext);\n            } else if (zeroC1 || zeroC2) { // quadratic bezier curve\n                var cx = zeroC1 ? c2x : c1x;\n                var cy = zeroC1 ? c2y : c1y;\n                var ctrls1X = new Float64Array(3);\n                var ctrls1Y = new Float64Array(3);\n                var ctrls2X = new Float64Array(3);\n                var ctrls2Y = new Float64Array(3);\n                ifMath.divideQuadraticCurve(p1x, cx, p2x, slope, ctrls1X, ctrls2X);\n                ifMath.divideQuadraticCurve(p1y, cy, p2y, slope, ctrls1Y, ctrls2Y);\n\n                newAPt = new IFPath.AnchorPoint();\n                newAPt.setProperties(['x', 'y', 'tp'], [ctrls1X[2], ctrls1Y[2], tpaNew]);\n                this.getAnchorPoints().insertChild(newAPt, aNext);\n\n                if (zeroC1) {\n                    if (ifMath.isEqualEps(ctrls1X[1], ctrls1X[2]) && ifMath.isEqualEps(ctrls1Y[1], ctrls1Y[2])) {\n                        newAPt.setProperties(['hlx', 'hly'], [null, null]);\n                    } else {\n                        newAPt.setProperties(['hlx', 'hly'], [ctrls1X[1], ctrls1Y[1]]);\n                    }\n                    // Handle of the next point was not zero, so convert the second part into cubic curve\n                    // to assign handles to both points\n                    c1x = ctrls2X[0] + 2 / 3 * (ctrls2X[1] - ctrls2X[0]);\n                    c1y = ctrls2Y[0] + 2 / 3 * (ctrls2Y[1] - ctrls2Y[0]);\n                    c2x = ctrls2X[2] + 2 / 3 * (ctrls2X[1] - ctrls2X[2]);\n                    c2y = ctrls2Y[2] + 2 / 3 * (ctrls2Y[1] - ctrls2Y[2]);\n                    if (ifMath.isEqualEps(c1x, ctrls2X[0]) && ifMath.isEqualEps(c1y, ctrls2Y[0])) {\n                        newAPt.setProperties(['hrx', 'hry'], [null, null]);\n                    } else {\n                        newAPt.setProperties(['hrx', 'hry'], [c1x, c1y]);\n                    }\n\n                    if (ifMath.isEqualEps(c2x, ctrls2X[2]) && ifMath.isEqualEps(c2y, ctrls2Y[2])) {\n                        aNext.setProperties(['hlx', 'hly'], [null, null]);\n                    } else {\n                        aNext.setProperties(['hlx', 'hly'], [c2x, c2y]);\n                    }\n                } else { // zeroC2\n                    if (ifMath.isEqualEps(ctrls2X[0], ctrls2X[1]) && ifMath.isEqualEps(ctrls2Y[0], ctrls2Y[1])) {\n                        newAPt.setProperties(['hrx', 'hry'], [null, null]);\n                    } else {\n                        newAPt.setProperties(['hrx', 'hry'], [ctrls2X[1], ctrls2Y[1]]);\n                    }\n                    // Handle of the previous point was not zero, so convert the first part into cubic curve\n                    // to assign handles to both points\n                    c1x = ctrls1X[0] + 2 / 3 * (ctrls1X[1] - ctrls1X[0]);\n                    c1y = ctrls1Y[0] + 2 / 3 * (ctrls1Y[1] - ctrls1Y[0]);\n                    c2x = ctrls1X[2] + 2 / 3 * (ctrls1X[1] - ctrls1X[2]);\n                    c2y = ctrls1Y[2] + 2 / 3 * (ctrls1Y[1] - ctrls1Y[2]);\n                    if (ifMath.isEqualEps(c2x, ctrls1X[2]) && ifMath.isEqualEps(c2y, ctrls1Y[2])) {\n                        newAPt.setProperties(['hlx', 'hly'], [null, null]);\n                    } else {\n                        newAPt.setProperties(['hlx', 'hly'], [c2x, c2y]);\n                    }\n\n                    if (ifMath.isEqualEps(c1x, ctrls1X[0]) && ifMath.isEqualEps(c1y, ctrls1Y[0])) {\n                        aPrev.setProperties(['hrx', 'hry'], [null, null]);\n                    } else {\n                        aPrev.setProperties(['hrx', 'hry'], [c1x, c1y]);\n                    }\n                }\n            } else { // cubic bezier curve\n                var ctrls1X = new Float64Array(4);\n                var ctrls1Y = new Float64Array(4);\n                var ctrls2X = new Float64Array(4);\n                var ctrls2Y = new Float64Array(4);\n\n                ifMath.getCtrlPtsCasteljau(p1x, c1x, c2x, p2x, slope, 1, ctrls1X);\n                ifMath.getCtrlPtsCasteljau(p1y, c1y, c2y, p2y, slope, 1, ctrls1Y);\n                ifMath.getCtrlPtsCasteljau(p1x, c1x, c2x, p2x, slope, 2, ctrls2X);\n                ifMath.getCtrlPtsCasteljau(p1y, c1y, c2y, p2y, slope, 2, ctrls2Y);\n\n                if (ifMath.isEqualEps(ctrls1X[1], p1x) && ifMath.isEqualEps(ctrls1Y[1], p1y)) {\n                    aPrev.setProperties(['hrx', 'hry'], [null, null]);\n                } else {\n                    aPrev.setProperties(['hrx', 'hry'], [ctrls1X[1], ctrls1Y[1]]);\n                }\n\n                newAPt = new IFPath.AnchorPoint();\n                newAPt.setProperties(['x', 'y', 'tp'], [ctrls1X[3], ctrls1Y[3], tpaNew]);\n                this.getAnchorPoints().insertChild(newAPt, aNext);\n                if (ifMath.isEqualEps(ctrls1X[2], ctrls1X[3]) && ifMath.isEqualEps(ctrls1Y[2], ctrls1Y[3])) {\n                    newAPt.setProperties(['hlx', 'hly'], [null, null]);\n                } else {\n                    newAPt.setProperties(['hlx', 'hly'], [ctrls1X[2], ctrls1Y[2]]);\n                }\n                if (ifMath.isEqualEps(ctrls2X[0], ctrls2X[1]) && ifMath.isEqualEps(ctrls2Y[0], ctrls2Y[1])) {\n                    newAPt.setProperties(['hrx', 'hry'], [null, null]);\n                } else {\n                    newAPt.setProperties(['hrx', 'hry'], [ctrls2X[1], ctrls2Y[1]]);\n                }\n\n                if (ifMath.isEqualEps(ctrls2X[2], ctrls2X[3]) && ifMath.isEqualEps(ctrls2Y[2], ctrls2Y[3])) {\n                    aNext.setProperties(['hlx', 'hly'], [null, null]);\n                } else {\n                    aNext.setProperties(['hlx', 'hly'], [ctrls2X[2], ctrls2Y[2]]);\n                }\n            }\n            this.endUpdate();\n            return newAPt;\n        }\n    };\n\n    /** @override */\n    IFPath.prototype._handleChange = function (change, args) {\n        IFPathBase.prototype._handleChange.call(this, change, args);\n        this._handleGeometryChangeForProperties(change, args, IFPath.GeometryProperties);\n        this._handleGeometryChangeForProperties(change, args, IFPathBase.GeometryProperties);\n    };\n\n    /** @override */\n    IFPath.prototype.toString = function () {\n        return \"[IFPath]\";\n    };\n\n    _.IFPath = IFPath;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/pathbase.js",
    "content": "(function (_) {\n\n    /**\n     * The base for all path based shapes\n     * @class IFPathBase\n     * @extends IFShape\n     * @constructor\n     */\n    function IFPathBase() {\n        IFShape.call(this);\n\n        this._setDefaultProperties(IFPathBase.VisualProperties);\n\n        // Add anchor points\n        this._anchorPoints = new IFPathBase.AnchorPoints();\n        this.appendChild(this._anchorPoints);\n\n        this._vertices = new IFVertexContainer();\n        this._verticesDirty = true;\n    }\n\n    IFObject.inherit(IFPathBase, IFShape);\n\n    /**\n     * @enum\n     */\n    IFPathBase.CornerType = {\n        /**\n         * A rounded corner\n         */\n        Rounded: 'R',\n\n        /**\n         * An inverse rounded corner\n         */\n        InverseRounded: 'U',\n\n        /**\n         * A beveled corner\n         */\n        Bevel: 'B',\n\n        /**\n         * An inset corner\n         */\n        Inset: 'I',\n\n        /**\n         * A fancy corner\n         */\n        Fancy: 'F'\n    };\n\n    IFPathBase.isCornerType = function (tp) {\n        for (var key in IFPathBase.CornerType) {\n            if (IFPathBase[key] === tp) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    /**\n     * The visual properties of a path base with their default values\n     */\n    IFPathBase.VisualProperties = {\n        /** Even-Odd fill */\n        evenodd: false\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFPathBase.AnchorPoint Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFPathBase.AnchorPoint\n     * @extends IFNode\n     * @mixes IFNode.Properties\n     * @constructor\n     */\n    IFPathBase.AnchorPoint = function () {\n        this._setDefaultProperties(IFPathBase.AnchorPoint.GeometryProperties);\n        this._leadHr = false;\n    };\n    IFObject.inheritAndMix(IFPathBase.AnchorPoint, IFNode, [IFNode.Properties]);\n\n    /**\n     * Take care not to clanch values with IFPathBase.CornerType!\n     * @enum\n     */\n    IFPathBase.AnchorPoint.Type = {\n        /**\n         * Control points are completely independent of each other.\n         */\n        Asymmetric: 'TA',\n\n        /**\n         * Distance between the control points and the main point is independent, but they do mirror each other.\n         */\n        Symmetric: 'TS',\n\n        /**\n         * Control points mirror each other; they are opposite each other and at the same distance from the main point.\n         */\n        Mirror: 'TM',\n\n        /**\n         * Ensures that the handles defining a curve always stay aligned with the direction of its straight pathes.\n         */\n        Connector: 'TC'\n    };\n\n    /**\n     * Geometrical properties of an anchor point\n     */\n    IFPathBase.AnchorPoint.GeometryProperties = {\n        /** The type of the anchor point */\n        tp: IFPathBase.AnchorPoint.Type.Asymmetric,\n        /** The x position */\n        x: 0,\n        /** The y position */\n        y: 0,\n        /** The left handle's x position */\n        hlx: null,\n        /** The left handle's y position */\n        hly: null,\n        /** The right handle's x position */\n        hrx: null,\n        /** The right handle's y position */\n        hry: null,\n        /** Whether handles are auto-calculated or not */\n        ah: false,\n        /** Whether corner lengths are uniform or not */\n        cu: true,\n        /** The left corner length */\n        cl: 0,\n        /** The right corner length */\n        cr: 0\n    };\n\n    /**\n     * Constant used for approximating circle arcs with cubic bezier curve\n     * @type {Number}\n     */\n    IFPathBase.AnchorPoint.BEST_CIRCLE_COEFF = 0.55191502; // http://spencermortensen.com/articles/bezier-circle/\n\n    /**\n     * Coefficient, meaning the relevant length of handle in relevance to the distance between points,\n     * when handle length should be calculated automatically\n     * @type {number}\n     */\n    IFPathBase.AnchorPoint.HANDLE_COEFF = 0.39026286; // 0.551915024494 / sqrt(2)\n\n    /** @override */\n    IFPathBase.AnchorPoint.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFPathBase.AnchorPoints;\n    };\n\n    /**\n     * Serializes this point into a stream array\n     * @return {Array<*>}\n     */\n    IFPathBase.AnchorPoint.prototype.serialize = function () {\n        var stream = [];\n\n        // Encoding: TYPE | AH | X | Y | 'h' | HLX | HLY | 'H' | HRX | HRY | 'C' | CL | CR\n        if (this.$tp !== null && this.$tp !== IFPathBase.AnchorPoint.GeometryProperties.tp) {\n            stream.push(this.$tp);\n        }\n\n        if (this.$ah && this.$ah !== IFPathBase.AnchorPoint.GeometryProperties.ah) {\n            stream.push(this.$ah);\n        }\n\n        // Lets always serialize x,y properties, as it is a very rare case, when the value is the default (0,0).\n        // Just waist of time for check if differ from default, and then again the check on restoring\n        stream.push(this.$x);\n        stream.push(this.$y);\n\n        // If auto handles are not calculated automatically then save our handles if any\n        if (!this.$ah) {\n            // If handles are not null, save them even if they have default values,\n            // as default value may be not the same as null, and we will need to differ this when deserializing.\n            // Also currently the situation of default values is almost impossible for handles (possible only\n            // in the case of some error somewhere in the code), so should be no waist of space for storing them\n            if (this.$hlx !== null || this.$hly !== null) {\n                stream.push('h');\n                stream.push(this.$hlx);\n                stream.push(this.$hly);\n            }\n            if (this.$hrx !== null || this.$hry !== null) {\n                stream.push('H');\n                stream.push(this.$hrx);\n                stream.push(this.$hry);\n            }\n        }\n\n        // Corner shoulder\n        if ((this.$cl !== null && !ifMath.isEqualEps(this.$cl, IFPathBase.AnchorPoint.GeometryProperties.cl)) ||\n            (this.$cr !== null && !ifMath.isEqualEps(this.$cr, IFPathBase.AnchorPoint.GeometryProperties.cr))) {\n            stream.push('C');\n            stream.push(this.$cl);\n            stream.push(this.$cr);\n        }\n\n        return stream;\n    };\n\n    /**\n     * Deserializes this point from a stream array\n     * @param {Array<*>} stream\n     */\n    IFPathBase.AnchorPoint.prototype.deserialize = function (stream) {\n        var index = 0;\n\n        // Read our Type if any\n        if (stream.length > 0 && typeof stream[0] === 'string') {\n            this.$tp = stream[0];\n            index++;\n        }\n\n        // Read our auto-handles if any\n        if (stream.length > index && typeof stream[index] === 'boolean') {\n            this.$ah = stream[index];\n            index++;\n        }\n\n        // Read coordinates of anchor point\n        if (index + 1 < stream.length) {\n            this.$x = stream[index];\n            this.$y = stream[index + 1];\n            index += 2;\n        }\n\n        // check of 'index + 2' is needed here, as both x and y are read in one cycle\n        while (index + 2 < stream.length) {\n            if (stream[index] === 'h') {\n                this.$hlx = stream[index + 1];\n                this.$hly = stream[index + 2];\n            } else if (stream[index] === 'H') {\n                this.$hrx = stream[index + 1];\n                this.$hry = stream[index + 2];\n            } else if (stream[index] === 'C') {\n                this.$cl = stream[index + 1];\n                this.$cr = stream[index + 2];\n            }\n            index += 3;\n        }\n    };\n\n    /**\n     * Returns a transformed copy of an anchor point. Only the point coordinates and handles are transformed,\n     * but not the shoulders lengths\n     * @param {IFTransform} transform - a transform to apply\n     * @returns {IFPathBase.AnchorPoint} - a transformed copy of an anchor point\n     * @private\n     */\n    IFPathBase.AnchorPoint.prototype._getTransformedCopy = function (transform) {\n        var pt = new IFPathBase.AnchorPoint();\n\n        var leftH = this.$hlx !== null ? transform.mapPoint(new IFPoint(this.$hlx, this.$hly)) : null;\n        var rightH = this.$hrx !== null ? transform.mapPoint(new IFPoint(this.$hrx, this.$hry)) : null;\n        var coord = transform.mapPoint(new IFPoint(this.$x, this.$y));\n        pt.$x = coord.getX();\n        pt.$y = coord.getY();\n        pt.$hlx = leftH ? leftH.getX() : null;\n        pt.$hly = leftH ? leftH.getY() : null;\n        pt.$hrx = rightH ? rightH.getX() : null;\n        pt.$hry = rightH ? rightH.getY() : null;\n        pt.$cl = this.$cl;\n        pt.$cr = this.$cr;\n        pt.$ah = this.$ah;\n        pt.$tp = this.$tp;\n\n        return pt;\n    };\n\n    /**\n     * Returns a left shoulder point for points with set shoulder lengths, or null otherwise\n     * @param {Boolean} fictiveCorner - if true, shoulder point will be calculated even\n     * if there is no real corner due to absence of right shoulder\n     * @returns {IFPoint} a left shoulder point\n     */\n    IFPathBase.AnchorPoint.prototype.getLeftShoulderPoint = function (fictiveCorner) {\n        if (this.getPath() && this.$cl && (fictiveCorner || this.$cr)) {\n            var prevPt = this._parent.getPreviousPoint(this);\n            return this._parent._getLeftShoulderPoint(this, prevPt);\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Returns a left shoulder point for points with set shoulder lengths, or null otherwise\n     * Apply a passed transform to points before calculating shoulder point\n     * @param {IFTransform} transform - transform to apply\n     * @param {Boolean} fictiveCorner - if true, shoulder point will be calculated even\n     * if there is no real corner due to absence of right shoulder\n     * @returns {IFPoint} a left shoulder point\n     */\n    IFPathBase.AnchorPoint.prototype.getLeftShoulderPointTransformed = function (transform, fictiveCorner) {\n        var shoulderPt = null;\n\n        if (this.getPath() && this.$cl && (fictiveCorner || this.$cr)) {\n            var prevPt = this._parent.getPreviousPoint(this);\n            var curPtTr = this._getTransformedCopy(transform);\n            var prevPtTr = prevPt._getTransformedCopy(transform);\n            shoulderPt = this._parent._getLeftShoulderPoint(curPtTr, prevPtTr);\n        }\n\n        return shoulderPt;\n    };\n\n    /**\n     * Returns a right shoulder point for points with set shoulder lengths, or null otherwise\n     * @param {Boolean} fictiveCorner - if true, shoulder point will be calculated even\n     * if there is no real corner due to absence of left shoulder\n     * @returns {IFPoint} a right shoulder point\n     */\n    IFPathBase.AnchorPoint.prototype.getRightShoulderPoint = function (fictiveCorner) {\n        if (this.getPath() && this.$cr && (fictiveCorner || this.$cl)) {\n            var nextPt = this._parent.getNextPoint(this);\n            return this._parent._getRightShoulderPoint(this, nextPt);\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Returns a right shoulder point for points with set shoulder lengths, or null otherwise\n     * Apply a passed transform to points before calculating shoulder point\n     * @param {IFTransform} transform - transform to apply\n     * @param {Boolean} fictiveCorner - if true, shoulder point will be calculated even\n     * if there is no real corner due to absence of left shoulder\n     * @returns {IFPoint} a right shoulder point\n     */\n    IFPathBase.AnchorPoint.prototype.getRightShoulderPointTransformed = function (transform, fictiveCorner) {\n        var shoulderPt = null;\n\n        if (this.getPath() && this.$cr && (fictiveCorner || this.$cl)) {\n            var nextPt = this._parent.getNextPoint(this);\n            var curPtTr = this._getTransformedCopy(transform);\n            var nextPtTr = nextPt._getTransformedCopy(transform);\n            shoulderPt = this._parent._getRightShoulderPoint(curPtTr, nextPtTr);\n        }\n\n        return shoulderPt;\n    };\n\n    /**\n     * Returns a point until which left shoulder may be extended.\n     * @returns {IFPoint}\n     */\n    IFPathBase.AnchorPoint.prototype.getLeftShoulderLimitPoint = function () {\n        var limitPt = null;\n        if (this.getPath()) {\n            var prevPt = this._parent.getPreviousPoint(this);\n            if (prevPt) {\n                limitPt = this._parent._getLeftShoulderPoint(this, prevPt, true);\n            }\n        }\n        return limitPt;\n    };\n\n    /**\n     * Returns a point until which right shoulder may be extended.\n     * @returns {IFPoint}\n     */\n    IFPathBase.AnchorPoint.prototype.getRightShoulderLimitPoint = function () {\n        var limitPt = null;\n        if (this.getPath()) {\n            var nextPt = this._parent.getNextPoint(this);\n            if (nextPt) {\n                limitPt = this._parent._getRightShoulderPoint(this, nextPt, true);\n            }\n        }\n        return limitPt;\n    };\n\n    /** @override */\n    IFPathBase.AnchorPoint.prototype._handleChange = function (change, args) {\n        var path = this.getPath();\n        if (change == IFNode._Change.BeforePropertiesChange || change == IFNode._Change.AfterPropertiesChange) {\n            if (ifUtil.containsObjectKey(args.properties, IFPathBase.AnchorPoint.GeometryProperties)) {\n                if (change === IFNode._Change.BeforePropertiesChange) {\n                    // Handle uniformity of corner lengths\n                    var cuIndex = args.properties.indexOf('cu');\n                    var cu = cuIndex >= 0 ? args.values[cuIndex] : this.$cu;\n                    if (cu) {\n                        var clIndex = args.properties.indexOf('cl');\n                        var crIndex = args.properties.indexOf('cr');\n                        if (clIndex >= 0) {\n                            var newVal = args.values[clIndex];\n                            if (this.$cr != newVal) {\n                                if (crIndex >= 0) {\n                                    args.values[crIndex] = newVal;\n                                } else {\n                                    args.properties.push('cr');\n                                    args.values.push(newVal);\n                                }\n                            }\n                        } else if (crIndex >= 0) {\n                            var newVal = args.values[crIndex];\n                            if (this.$cl != newVal) {\n                                args.properties.push('cl');\n                                args.values.push(newVal);\n                            }\n                        }\n                    }\n\n                    // If we have a path, prepare it's geometrical change\n                    if (path) {\n                        path._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n                    }\n                } else if (change === IFNode._Change.AfterPropertiesChange) {\n                    if (this.$tp == IFPathBase.AnchorPoint.Type.Symmetric &&\n                            !this.$ah && this.$hlx != null && this.$hrx != null ||\n                        this.$tp == IFPathBase.AnchorPoint.Type.Mirror &&\n                            !this.$ah && (this.$hlx != null || this.$hrx != null)) {\n\n                        if ((args.properties.indexOf('hrx') >= 0 ||\n                            args.properties.indexOf('hry') >= 0) &&\n                            args.properties.indexOf('hlx') < 0 &&\n                            args.properties.indexOf('hly') < 0 ||\n                            args.properties.indexOf('tp') >= 0 &&\n                            args.properties.indexOf('hlx') < 0 &&\n                            args.properties.indexOf('hly') < 0 &&\n                            this.$hrx != null) {\n                            this._leadHr = true;\n                        } else {\n                            this._leadHr = false;\n                        }\n                    }\n\n                    if (path || // For Smooth point recalculate handles properly, even if point is not inserted yet\n                        this.$tp == IFPathBase.AnchorPoint.Type.Symmetric &&\n                            !this.$ah && this.$hlx != null && this.$hrx != null ||\n                        this.$tp == IFPathBase.AnchorPoint.Type.Mirror &&\n                            !this.$ah && (this.$hlx != null || this.$hrx != null)) {\n\n                        this._invalidateCalculations();\n                    }\n\n                    if (path) {\n                        // Changes in properties should have the following effect for neighbour points:\n                        // handles change - no effect\n                        // auto handles flag change - no effect\n                        // type change - one point from each side should be updated,\n                        //      if it has auto-handles or connector type\n                        // coordinate change - one point from each side should be updated,\n                        //      if it has auto-handles or connector type, and\n                        //      in the case, when the nearest point is smooth, the second point from the side of smooth\n                        //      point also should be updated if it has auto-handles\n\n                        if (this._parent) {\n                            if (args.properties.indexOf('x') >= 0 ||\n                                args.properties.indexOf('y') >= 0) {\n\n                                this._parent._invalidateLeft(this._parent.getPreviousPoint(this));\n                                this._parent._invalidateRight(this._parent.getNextPoint(this));\n                            } else if (args.properties.indexOf('tp') >= 0) {\n                                var prevPt = this._parent.getPreviousPoint(this);\n                                if (prevPt && (prevPt.$ah || prevPt.$tp == IFPathBase.AnchorPoint.Type.Connector )) {\n                                    prevPt._invalidateCalculations();\n                                }\n                                var nextPt = this._parent.getNextPoint(this);\n                                if (nextPt && (nextPt.$ah || nextPt.$tp == IFPathBase.AnchorPoint.Type.Connector )) {\n                                    nextPt._invalidateCalculations();\n                                }\n                            }\n                        }\n                        path._verticesDirty = true;\n                        path._notifyChange(IFElement._Change.FinishGeometryUpdate);\n                    }\n                }\n            }\n        }\n        IFNode.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * @returns {IFPathBase}\n     * @private\n     */\n    IFPathBase.AnchorPoint.prototype.getPath = function () {\n        return this._parent ? this._parent._parent : null;\n    };\n\n    /**\n     * Invalidate auto-calculated properties depending on type and other settings\n     * Properties have the following priority\n     * Connector > Auto > Smooth, Corner\n     * @private\n     */\n    IFPathBase.AnchorPoint.prototype._invalidateCalculations = function () {\n        var points = this._parent;\n\n        if (points && this.$tp == IFPathBase.AnchorPoint.Type.Connector) {\n            this._calculateConnectorPoint();\n        } else if (this.$tp == IFPathBase.AnchorPoint.Type.Symmetric && !this.$ah) {\n            // recalculate Smooth even if !points\n            this._calculateSmoothPoint();\n        } else if (this.$tp == IFPathBase.AnchorPoint.Type.Mirror && !this.$ah) {\n            // recalculate Mirror even if !points\n            this._calculateMirrorPoint();\n        } else if (points && this.$ah) {\n            this._calculateAutoHandles();\n        }\n    };\n\n    IFPathBase.AnchorPoint.prototype._calculateConnectorPoint = function () {\n        var points = this._parent;\n        if (points) {\n\n            var prevPt = points.getPreviousPoint(this);\n            var nextPt = points.getNextPoint(this);\n            var dirLenPrev = 0;\n            var dirLenNext = 0;\n\n            if (nextPt) {\n                dirLenNext = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, nextPt.$x, nextPt.$y));\n            }\n\n            if (prevPt) {\n                dirLenPrev = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, prevPt.$x, prevPt.$y));\n            }\n\n            var hLen;\n            var hx, hy;\n            if (this.$ah) {\n                if (nextPt && prevPt && (nextPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n                    nextPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) &&\n                    !ifMath.isEqualEps(dirLenNext, 0) && !ifMath.isEqualEps(dirLenPrev, 0)) {\n\n                    hLen = dirLenNext * IFPathBase.AnchorPoint.HANDLE_COEFF;\n                    hx = this.$x + (this.$x - prevPt.$x) / dirLenPrev * hLen;\n                    hy = this.$y + (this.$y - prevPt.$y) / dirLenPrev * hLen;\n                    this.setProperties(['hrx', 'hry'], [hx, hy]);\n                } else {\n                    this.setProperties(['hrx', 'hry'], [null, null]);\n                }\n                if (prevPt && nextPt && (prevPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n                    prevPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) &&\n                    !ifMath.isEqualEps(dirLenNext, 0) && !ifMath.isEqualEps(dirLenPrev, 0)) {\n\n                    hLen = dirLenPrev * IFPathBase.AnchorPoint.HANDLE_COEFF;\n                    hx = this.$x + (this.$x - nextPt.$x) / dirLenNext * hLen;\n                    hy = this.$y + (this.$y - nextPt.$y) / dirLenNext * hLen;\n                    this.setProperties(['hlx', 'hly'], [hx, hy]);\n                } else {\n                    this.setProperties(['hlx', 'hly'], [null, null]);\n                }\n            } else {\n                if (this.$hlx != null && nextPt && !ifMath.isEqualEps(dirLenNext, 0)) {\n                    // Use rotation if handle is already set\n                    hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, this.$hlx, this.$hly));\n                    hx = this.$x + (this.$x - nextPt.$x) / dirLenNext * hLen;\n                    hy = this.$y + (this.$y - nextPt.$y) / dirLenNext * hLen;\n                    // TODO: use projection in editor when modifying handle\n                    //var hnd = ifMath.getPositiveProjection(this.$x, this.$y,\n                    //    this.$x + (this.$x - nextPt.$x), this.$y + (this.$y - nextPt.$y), this.$hlx, this.$hly);\n                    this.setProperties(['hlx', 'hly'], [hx, hy]);\n                }\n\n                if (this.$hrx != null && prevPt && !ifMath.isEqualEps(dirLenPrev, 0)) {\n                    // Use rotation if handle is already set\n                    hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, this.$hrx, this.$hry));\n                    hx = this.$x + (this.$x - prevPt.$x) / dirLenPrev * hLen;\n                    hy = this.$y + (this.$y - prevPt.$y) / dirLenPrev * hLen;\n                    // TODO: use projection in editor when modifying handle\n                    //var hnd = ifMath.getPositiveProjection(this.$x, this.$y,\n                    //   this.$x + (this.$x - prevPt.$x), this.$y + (this.$y - prevPt.$y), this.$hrx, this.$hry);\n                    this.setProperties(['hrx', 'hry'], [hx, hy]);\n                }\n            }\n        }\n    };\n\n    IFPathBase.AnchorPoint.prototype._calculateSmoothPoint = function () {\n        var hLen, dirLen;\n        var hx, hy;\n\n        // we have two handles, and we need to rotate one of them to be in line with the other\n        if (this.$hlx != null && this.$hrx != null) {\n            if (this._leadHr) { // the left handle shall be rotated to be in line with the right one\n                dirLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, this.$hrx, this.$hry));\n                if (!ifMath.isEqualEps(dirLen, 0)) {\n                    hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, this.$hlx, this.$hly));\n                    hx = this.$x + (this.$x - this.$hrx) / dirLen * hLen;\n                    hy = this.$y + (this.$y - this.$hry) / dirLen * hLen;\n                    this.setProperties(['hlx', 'hly'], [hx, hy]);\n                }\n            } else { // the right handle shall be rotated to be in line with the left one\n                dirLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, this.$hlx, this.$hly));\n                if (!ifMath.isEqualEps(dirLen, 0)) {\n                    hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, this.$hrx, this.$hry));\n                    hx = this.$x + (this.$x - this.$hlx) / dirLen * hLen;\n                    hy = this.$y + (this.$y - this.$hly) / dirLen * hLen;\n                    this.setProperties(['hrx', 'hry'], [hx, hy]);\n                }\n            }\n        }\n    };\n\n    /** Calculate handles for point of type Mirror */\n    IFPathBase.AnchorPoint.prototype._calculateMirrorPoint = function () {\n        // we need to set one of handles to be in line with the other and have the same length\n        if (this._leadHr && this.$hrx != null) { // the left handle shall be rotated to be in line with the right one\n            var hx = this.$x + (this.$x - this.$hrx);\n            var hy = this.$y + (this.$y - this.$hry);\n            if (this.$hlx != hx || this.$hly != hy) {\n                this.setProperties(['hlx', 'hly'], [hx, hy]);\n            }\n        } else if (!this._leadHr && this.$hlx != null) { // the right handle shall be rotated to be in line with the left one\n            var hx = this.$x + (this.$x - this.$hlx);\n            var hy = this.$y + (this.$y - this.$hly);\n            if (this.$hrx != hx || this.$hry != hy) {\n                this.setProperties(['hrx', 'hry'], [hx, hy]);\n            }\n        }\n    };\n\n    IFPathBase.AnchorPoint.prototype._calculateAutoHandles = function () {\n        var points = this._parent;\n        if (points) {\n\n            var prevPt = points.getPreviousPoint(this);\n            var nextPt = points.getNextPoint(this);\n\n            var hx, hy;\n            var dirLen, hLen;\n            var offs = IFPathBase.AnchorPoint.HANDLE_COEFF;\n            var ccntr;\n            var dx, dy;\n            var px, py;\n\n            if (this.$tp == IFPathBase.AnchorPoint.Type.Symmetric || this.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n                if (!nextPt && !prevPt) {\n                    return;\n                } else if (nextPt && !prevPt ||\n                    nextPt && this.$x == prevPt.$x && this.$y == prevPt.$y) {\n\n                    hx = this.$x + (nextPt.$x - this.$x) * offs;\n                    hy = this.$y + (nextPt.$y - this.$y) * offs;\n                    this.setProperties(['hlx', 'hly', 'hrx', 'hry'],\n                        [this.$x + this.$x - hx, this.$y + this.$y - hy, hx, hy], false, true);\n                } else if (prevPt && !nextPt ||\n                    prevPt && this.$x == nextPt.$x && this.$y == nextPt.$y) {\n\n                    hx = this.$x + (prevPt.$x - this.$x) * offs;\n                    hy = this.$y + (prevPt.$y - this.$y) * offs;\n                    this.setProperties(['hlx', 'hly', 'hrx', 'hry'],\n                        [hx, hy, this.$x + this.$x - hx, this.$y + this.$y - hy], false, true);\n                } else if (prevPt && nextPt) {\n                    // calculate handles to be tangent circle(triag(prevPt, this, nextPt))\n                    ccntr = ifMath.getCircumcircleCenter(\n                        prevPt.$x, prevPt.$y, this.$x, this.$y, nextPt.$x, nextPt.$y);\n\n                    if (ccntr == null) { // prev and next points are the same, make handles to be perpendicular\n                        dx = (this.$y - prevPt.$y) * offs;\n                        dy = (prevPt.$x - this.$x) * offs;\n                        this.setProperties(['hlx', 'hly', 'hrx', 'hry'],\n                            [this.$x - dx, this.$y - dy, this.$x + dx, this.$y + dy], false, true);\n                    }\n                    else {\n                        dirLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, ccntr.getX(), ccntr.getY()));\n                        // no need to check dirLen for 0, as ccntr != this\n                        dx = (this.$y - ccntr.getY()) / dirLen;\n                        dy = (ccntr.getX() - this.$x) / dirLen;\n\n                        // check handles side\n                        px = (prevPt.$x + nextPt.$x) / 2;\n                        py = (prevPt.$y + nextPt.$y) / 2;\n                        if (ifMath.segmentSide(this.$x, this.$y, px, py, prevPt.$x, prevPt.$y) !=\n                            ifMath.segmentSide(this.$x, this.$y, px, py, this.$x - dx, this.$y - dy)) {\n                            dx = -dx;\n                            dy = -dy;\n                        }\n\n                        hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, prevPt.$x, prevPt.$y)) * offs;\n                        this.setProperties(['hlx', 'hly'], [this.$x - dx * hLen, this.$y - dy * hLen]);\n\n                        hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, nextPt.$x, nextPt.$y)) * offs;\n                        this.setProperties(['hrx', 'hry'], [this.$x + dx * hLen, this.$y + dy * hLen]);\n                    }\n                }\n            } else { // type != Smooth && type != Connector as this method should not be called for connector\n                if (prevPt && (prevPt.$x != this.$x || prevPt.$y != this.$y)) {\n                    if (prevPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n                            prevPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n\n                        var prevprevPt = points.getPreviousPoint(prevPt);\n                        if (!prevprevPt || (prevPt.$x == prevprevPt.$x && prevPt.$y == prevprevPt.$y)) {\n                            hx = this.$x + (prevPt.$x - this.$x) * offs;\n                            hy = this.$y + (prevPt.$y - this.$y) * offs;\n                            this.setProperties(['hlx', 'hly'], [hx, hy]);\n                        } else {\n                            // calculate left handle to be tangent circle(triag(this, prevPt, prevprevPt))\n                            ccntr = ifMath.getCircumcircleCenter(\n                                this.$x, this.$y, prevPt.$x, prevPt.$y, prevprevPt.$x, prevprevPt.$y);\n\n                            if (ccntr == null) { // this and prevprev points are the same, make handle to be perpendicular\n                                dx = (this.$y - prevPt.$y) * offs;\n                                dy = (prevPt.$x - this.$x) * offs;\n                                this.setProperties(['hlx', 'hly'], [this.$x - dx, this.$y - dy]);\n                            }\n                            else {\n                                dirLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, ccntr.getX(), ccntr.getY()));\n                                // no need to check dirLen for 0, as ccntr != this\n                                dx = (this.$y - ccntr.getY()) / dirLen;\n                                dy = (ccntr.getX() - this.$x) / dirLen;\n\n                                // check handle side\n                                px = (prevPt.$x + prevprevPt.$x) / 2;\n                                py = (prevPt.$y + prevprevPt.$y) / 2;\n                                if (ifMath.segmentSide(this.$x, this.$y, px, py, prevPt.$x, prevPt.$y) !=\n                                    ifMath.segmentSide(this.$x, this.$y, px, py, this.$x - dx, this.$y - dy)) {\n                                    dx = -dx;\n                                    dy = -dy;\n                                }\n\n                                hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, prevPt.$x, prevPt.$y)) * offs;\n                                this.setProperties(['hlx', 'hly'], [this.$x - dx * hLen, this.$y - dy * hLen]);\n                            }\n                        }\n                    } else { // prevPt.$tp != IFPathBase.AnchorPoint.Type.Symmetric || Mirror\n                        this.setProperties(['hlx', 'hly'], [null, null]);\n                    }\n                }\n\n                if (nextPt && (nextPt.$x != this.$x || nextPt.$y != this.$y)) {\n                    if (nextPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n                            nextPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n\n                        var nextnextPt = points.getNextPoint(nextPt);\n                        if (!nextnextPt || (nextPt.$x == nextnextPt.$x && nextPt.$y == nextnextPt.$y)) {\n                            hx = this.$x + (nextPt.$x - this.$x) * offs;\n                            hy = this.$y + (nextPt.$y - this.$y) * offs;\n                            this.setProperties(['hrx', 'hry'], [hx, hy]);\n                        } else {\n                            // calculate right handle to be tangent circle(triag(this, nextPt, nextnextPt))\n                            ccntr = ifMath.getCircumcircleCenter(\n                                this.$x, this.$y, nextPt.$x, nextPt.$y, nextnextPt.$x, nextnextPt.$y);\n\n                            if (ccntr == null) { // this and nextnext points are the same, make handle to be perpendicular\n                                dx = (this.$y - nextPt.$y) * offs;\n                                dy = (nextPt.$x - this.$x) * offs;\n                                this.setProperties(['hrx', 'hry'], [this.$x - dx, this.$y - dy]);\n                            }\n                            else {\n                                dirLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, ccntr.getX(), ccntr.getY()));\n                                // no need to check dirLen for 0, as ccntr != this\n                                dx = (this.$y - ccntr.getY()) / dirLen;\n                                dy = (ccntr.getX() - this.$x) / dirLen;\n\n                                // check handle side\n                                px = (nextPt.$x + nextnextPt.$x) / 2;\n                                py = (nextPt.$y + nextnextPt.$y) / 2;\n                                if (ifMath.segmentSide(this.$x, this.$y, px, py, nextPt.$x, nextPt.$y) !=\n                                    ifMath.segmentSide(this.$x, this.$y, px, py, this.$x + dx, this.$y + dy)) {\n                                    dx = -dx;\n                                    dy = -dy;\n                                }\n\n                                hLen = Math.sqrt(ifMath.ptSqrDist(this.$x, this.$y, nextPt.$x, nextPt.$y)) * offs;\n                                this.setProperties(['hrx', 'hry'], [this.$x + dx * hLen, this.$y + dy * hLen]);\n                            }\n                        }\n                    } else {\n                        this.setProperties(['hrx', 'hry'], [null, null]);\n                    }\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFPathBase.AnchorPoint.prototype.toString = function () {\n        return \"[Object IFPathBase.AnchorPoint]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFPathBase.AnchorPoints Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFPathBase.AnchorPoints\n     * @extends IFNode\n     * @mixes IFNode.Container\n     * @constructor\n     */\n    IFPathBase.AnchorPoints = function () {\n        // AnchorPoints is a \"shadow\" node\n        this._flags |= IFNode.Flag.Shadow;\n    };\n    IFObject.inheritAndMix(IFPathBase.AnchorPoints, IFNode, [IFNode.Container]);\n\n    /**\n     * Used for internal calculations.\n     * When a point is being removed from container, save here the link to the previous point\n     * to invalidate it after removal\n     * @type {IFPathBase.AnchorPoint}\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._dirtyPrev = null;\n\n    /**\n     * Used for internal calculations.\n     * When a point is being removed from container, save here the link to the next point\n     * to invalidate it after removal\n     * @type {IFPathBase.AnchorPoint}\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._dirtyNext = null;\n\n    /** @override */\n    IFPathBase.AnchorPoints.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFPathBase;\n    };\n\n    /** @override */\n    IFPathBase.AnchorPoints.prototype.validateRemoval = function () {\n        return false;\n    };\n\n    /**\n     * Serializes all points into a stream array\n     * @return {Array<*>}\n     */\n    IFPathBase.AnchorPoints.prototype.serialize = function () {\n        var stream = [];\n        for (var pt = this.getFirstChild(); pt !== null; pt = pt.getNext()) {\n            stream.push(pt.serialize());\n        }\n        return stream;\n    };\n\n    /**\n     * Deserializes all points from a stream array\n     * @param {Array<*>} stream\n     */\n    IFPathBase.AnchorPoints.prototype.deserialize = function (stream) {\n        for (var i = 0; i < stream.length; ++i) {\n            var pt = new IFPathBase.AnchorPoint();\n            pt.deserialize(stream[i]);\n            this.appendChild(pt);\n        }\n    };\n\n    /**\n     * Called when the coordinates of the point at right from the passed point have been changed.\n     * Then recalculate carefully the passed point, and the point at left from it if needed.\n     * @param {IFPathBase.AnchorPoint} [anchorPt] - the passed point to start recalculations from\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._invalidateLeft = function (anchorPt) {\n        if (!anchorPt) {\n            return;\n        }\n        // the point should be recalculated if it has auto-handles or connector type.\n        // In the case, when it has a smooth type, the left point also should be updated if it has auto-handles\n        if (anchorPt.$ah || anchorPt.$tp == IFPathBase.AnchorPoint.Type.Connector) {\n            anchorPt._invalidateCalculations();\n        }\n\n        if (anchorPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric || anchorPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n            var leftPt = this.getPreviousPoint(anchorPt);\n            if (leftPt && leftPt.$ah) {\n                leftPt._invalidateCalculations();\n            }\n        }\n    };\n\n    /**\n     * Called when the coordinates of the point at left from the passed point have been changed.\n     * Then recalculate carefully the passed point, and the point at right from it if needed.\n     * @param {IFPathBase.AnchorPoint} [anchorPt] - the passed point to start recalculations from\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._invalidateRight = function (anchorPt) {\n        if (!anchorPt) {\n            return;\n        }\n        // the point should be recalculated if it has auto-handles or connector type.\n        // In the case, when it has a smooth type, the right point also should be updated if it has auto-handles\n        if (anchorPt.$ah || anchorPt.$tp == IFPathBase.AnchorPoint.Type.Connector) {\n            anchorPt._invalidateCalculations();\n        }\n\n        if (anchorPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric || anchorPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n            var rightPt = this.getNextPoint(anchorPt);\n            if (rightPt && rightPt.$ah) {\n                rightPt._invalidateCalculations();\n            }\n        }\n    };\n\n    /**\n     * Called to generate vertices from this anchor points\n     * @param {IFVertexContainer} target the target vertex container to put vertices into\n     * @param {IFTransform} transform the transformation used for vertice generation, might be null\n     * @param {Boolean} styled - indicates if vertices should be calculated for path with styled corners\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._generateVertices = function (target, transform, styled) {\n        var i;\n        var pt;\n        var startPtX, startPtY;\n        var ap;\n\n        // First vertex\n        // Do not process first anchor point corner here,\n        // just calculate a path starting point on the way to the next anchor point\n        ap = this.getFirstChild();\n        if (!ap) {\n            return;\n        }\n\n        var path = this._parent;\n        var aptmp;\n        if (!styled ||\n            ap.$tp == IFPathBase.AnchorPoint.Type.Asymmetric ||\n            ap.$tp == IFPathBase.AnchorPoint.Type.Connector ||\n            ap.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n            ap.$tp == IFPathBase.AnchorPoint.Type.Mirror ||\n            !path || !path.$closed ||\n            ap == this.getLastChild()) {\n\n            if (transform) {\n                aptmp = ap._getTransformedCopy(transform);\n            } else {\n                aptmp = ap;\n            }\n            startPtX = aptmp.$x;\n            startPtY = aptmp.$y;\n        } else {\n            pt = this._getPathStartPt(transform);\n            startPtX = pt.getX();\n            startPtY = pt.getY();\n        }\n\n        target.addVertex(IFVertex.Command.Move, startPtX, startPtY);\n        if (ap == this.getLastChild()) {\n            return;\n        }\n\n        // Add all the vertices (including corners for the last point and the first point for closed path),\n        // except the vertices for the last point of open path\n        var prevPt = ap;\n        ap = ap.getNext();\n        var firstPt = ap;\n        var processingStarted = false;\n        var nextPt = this.getNextPoint(ap);\n        var prevPttmp, nextPttmp;\n        if (transform) {\n            aptmp = ap._getTransformedCopy(transform);\n            prevPttmp = prevPt._getTransformedCopy(transform);\n        }\n        while (nextPt && (ap != firstPt || !processingStarted)) {\n            processingStarted = true;\n            if (transform) {\n                nextPttmp = nextPt._getTransformedCopy(transform);\n\n                this._addMiddleVertices(\n                    target, aptmp, prevPttmp, nextPttmp, styled);\n\n                prevPttmp = aptmp;\n                aptmp = nextPttmp;\n            } else {\n                this._addMiddleVertices(\n                    target, ap, prevPt, nextPt, styled);\n            }\n\n            prevPt = ap;\n            ap = nextPt;\n            nextPt = this.getNextPoint(nextPt);\n        }\n\n        // the last point, !path.$closed\n        if (!nextPt) {\n            this._addPathEndVertices(target, transform);\n        } else {\n            target.addVertex(IFVertex.Command.Close, 0, 0);\n        }\n    };\n\n    /**\n     * Calculates and return the first vertex of the path, from which movement to the next point starts\n     * Takes into account corner type\n     * This function is supposed to be called only when the path is closed\n     * @param {IFTransform} transform - a transformation to apply to anchor points before generating vertices\n     * @returns {IFPoint} starting point of the path\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._getPathStartPt = function (transform) {\n        var ap = this.getFirstChild();\n        var prevPt = this.getPreviousPoint(ap);\n        var nextPt = this.getNextPoint(ap);\n\n        if (transform) {\n            ap = ap._getTransformedCopy(transform);\n            nextPt = nextPt._getTransformedCopy(transform);\n            prevPt = prevPt._getTransformedCopy(transform);\n        }\n\n        // no second corner shoulder\n        if (!ap.$cl || !ap.$cr ||\n            // specific corner type is not set\n            ap.$tp == IFPathBase.AnchorPoint.Type.Asymmetric ||\n            // the point is connector or smooth, no corner here\n            ap.$tp == IFPathBase.AnchorPoint.Type.Connector ||\n            ap.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n            ap.$tp == IFPathBase.AnchorPoint.Type.Mirror || !prevPt ||\n            prevPt.$tp == IFPathBase.AnchorPoint.Type.Connector && prevPt.$x == ap.$x && prevPt.$y == ap.$y) {\n\n            return new IFPoint(ap.$x, ap.$y);\n        }\n\n        return this._getRightShoulderPoint(ap, nextPt);\n    };\n\n    /**\n     * Calculates the point at which styled corner shoulder should finish or start, taken into account that\n     * near points may have total shoulders length more than the distance between points\n     * @param {Number} [pt1x] - x-coordinate of the first point\n     * @param {Number} [pt1y] - y-coordinate of the first point\n     * @param {Number} [pt1s] - shoulder of the first point\n     * @param {Number} [pt2x] - x-coordinate of the second point\n     * @param {Number} [pt2y] - y-coordinate of the second point\n     * @param {Number} [pt2s] - shoulder of the second point\n     * @return {IFPoint} the shoulder end connected to the first point\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._getShoulderPoint = function (pt1x, pt1y, pt1s, pt2x, pt2y, pt2s) {\n        var dist = ifMath.ptDist(pt1x, pt1y, pt2x, pt2y);\n        var sptdst;\n        var p1s, p2s;\n        if (pt1s == null || pt1s <= 0) {\n            p1s = 0;\n        } else {\n            p1s = pt1s;\n        }\n        if (pt2s == null || pt2s <= 0) {\n            p2s = 0;\n        } else {\n            p2s = pt2s;\n        }\n        var len = p1s + p2s;\n        if (len <= 0) {\n            return null;\n        }\n        if (dist >= len) {\n            sptdst = p1s;\n        } else {\n            sptdst = dist * p1s / len;\n        }\n        return ifMath.getPointAtLength(pt1x, pt1y, pt2x, pt2y, sptdst);\n    };\n\n    /**\n     * Returns a right shoulder point for the passed point, using the second passed point as a near point at right\n     * @param {IFPathBase.AnchorPoint} [curPt] the current anchor point for which shoulder is needed\n     * @param {IFPathBase.AnchorPoint} [nextPt] an anchor point to be use as a near point at right\n     * @param {Boolean} maxLen - if true, instead of a real shoulder point, return shoulder point maximal position\n     * @returns {IFPoint} a left shoulder point\n     */\n    IFPathBase.AnchorPoints.prototype._getRightShoulderPoint = function (curPt, nextPt, maxLen) {\n        // define corner end\n        var hx = null;\n        var hy = null;\n        if (curPt.$hrx != null) {\n            hx = curPt.$hrx;\n            hy = curPt.$hry;\n        } else if (nextPt.$hlx != null) {\n            hx = nextPt.$hlx;\n            hy = nextPt.$hly;\n        }\n        var pt;\n        if (hx != null) {\n            if (maxLen) {\n                pt = new IFPoint(hx, hy);\n            } else {\n                pt = ifMath.getPointAtLength(curPt.$x, curPt.$y, hx, hy, curPt.$cr);\n            }\n        } else {\n            if (maxLen) {\n                pt = new IFPoint(nextPt.$x, nextPt.$y);\n            } else {\n                pt = this._getShoulderPoint(curPt.$x, curPt.$y, curPt.$cr, nextPt.$x, nextPt.$y, nextPt.$cl);\n            }\n        }\n        return pt;\n    };\n\n    /**\n     * Returns a left shoulder point for the passed point, using the second passed point as a near point at left\n     * @param {IFPathBase.AnchorPoint} [curPt] the current anchor point for which shoulder is needed\n     * @param {IFPathBase.AnchorPoint} [prevPt] an anchor point to be use as a near point at left\n     * @param {Boolean} maxLen - if true, instead of a real shoulder point, return shoulder point maximal position\n     * @returns {IFPoint} a left shoulder point\n     */\n    IFPathBase.AnchorPoints.prototype._getLeftShoulderPoint = function (curPt, prevPt, maxLen) {\n        // define corner end\n        var hx = null;\n        var hy = null;\n        if (curPt.$hlx != null) {\n            hx = curPt.$hlx;\n            hy = curPt.$hly;\n        } else if (prevPt.$hrx != null) {\n            hx = prevPt.$hrx;\n            hy = prevPt.$hry;\n        }\n        var pt;\n        if (hx != null) {\n            if (maxLen) {\n                pt = new IFPoint(hx, hy);\n            } else {\n                pt = ifMath.getPointAtLength(curPt.$x, curPt.$y, hx, hy, curPt.$cl);\n            }\n        } else {\n            if (maxLen) {\n                pt = new IFPoint(prevPt.$x, prevPt.$y);\n            } else {\n                pt = this._getShoulderPoint(curPt.$x, curPt.$y, curPt.$cl, prevPt.$x, prevPt.$y, prevPt.$cr);\n            }\n        }\n        return pt;\n    };\n\n    /**\n     * Calculate and adds vertices for anchor point\n     * Anchor point type is taken into account only if styled corner is needed\n     * @param {IFVertexContainer} target the target vertex container to put vertices into\n     * @param {IFPathBase.AnchorPoint} [curPt] the current anchor point, used as a main source for segment and corner vertices\n     * @param {IFPathBase.AnchorPoint} [prevPt] the previous anchor point, used to correct vertices according to corner type\n     * @param {IFPathBase.AnchorPoint} [nextPt] the next anchor point, used to correct vertices according to corner type\n     * @param {Boolean} [styled] used to indicate if styled corner is needed\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._addMiddleVertices = function (target, curPt, prevPt, nextPt, styled) {\n        var hLen, dirLen;\n        var h2x = null;\n        var h2y = null;\n        var pt, pt2;\n        var hx = null;\n        var hy = null;\n\n        // define first and second handle coordinates if exist\n        if (curPt.$hlx != null && curPt.$hly != null && prevPt.$hrx != null && prevPt.$hry != null) {\n            hx = prevPt.$hrx;\n            hy = prevPt.$hry;\n            h2x = curPt.$hlx;\n            h2y = curPt.$hly;\n        } else if (curPt.$hlx != null && curPt.$hly != null) {\n            hx = curPt.$hlx;\n            hy = curPt.$hly;\n        } else if (prevPt.$hrx != null && prevPt.$hry != null) {\n            hx = prevPt.$hrx;\n            hy = prevPt.$hry;\n        }\n\n        // define curve end point and other corner points if applicable\n        if (!styled ||\n            curPt.$tp == IFPathBase.AnchorPoint.Type.Asymmetric ||\n            curPt.$tp == IFPathBase.AnchorPoint.Type.Connector ||\n            curPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric ||\n            curPt.$tp == IFPathBase.AnchorPoint.Type.Mirror ||\n            // shoulders are not defined or zero\n            !curPt.$cl || !curPt.$cr) {\n            // No any specific corner with shoulders\n\n            if (hx == null) {\n                target.addVertex(IFVertex.Command.Line, curPt.$x, curPt.$y);\n            } else if (h2x == null) {\n                target.addVertex(IFVertex.Command.Curve, curPt.$x, curPt.$y);\n                target.addVertex(IFVertex.Command.Curve, hx, hy);\n            } else {\n                target.addVertex(IFVertex.Command.Curve2, curPt.$x, curPt.$y);\n                target.addVertex(IFVertex.Command.Curve2, hx, hy);\n                target.addVertex(IFVertex.Command.Curve2, h2x, h2y);\n            }\n        } else { // corner with shoulders\n            if (hx == null) {\n                pt = this._getShoulderPoint(curPt.$x, curPt.$y, curPt.$cl, prevPt.$x, prevPt.$y, prevPt.$cr);\n                target.addVertex(IFVertex.Command.Line, pt.getX(), pt.getY());\n            } else if (h2x == null) {\n                pt = ifMath.getPointAtLength(curPt.$x, curPt.$y, hx, hy, curPt.$cl);\n                target.addVertex(IFVertex.Command.Curve, pt.getX(), pt.getY());\n                target.addVertex(IFVertex.Command.Curve, hx, hy);\n            } else {\n                pt = ifMath.getPointAtLength(curPt.$x, curPt.$y, h2x, h2y, curPt.$cl);\n                target.addVertex(IFVertex.Command.Curve2, pt.getX(), pt.getY());\n                target.addVertex(IFVertex.Command.Curve2, hx, hy);\n                target.addVertex(IFVertex.Command.Curve2, h2x, h2y);\n            }\n\n            pt2 = this._getRightShoulderPoint(curPt, nextPt);\n\n            this._addCornerToVertices(\n                target, pt.getX(), pt.getY(), pt2.getX(), pt2.getY(), curPt.$x, curPt.$y, curPt.$tp);\n        }\n    };\n\n    /**\n     * Adds extra (corner) vertices to _vertices\n     * @param {IFVertexContainer} target the target vertex container to put vertices into\n     * @param {Number} [pt1x] x coordinate of a corner start point\n     * @param {Number} [pt1y] y coordinate of a corner start point\n     * @param {Number} [pt2x] x coordinate of a corner end point\n     * @param {Number} [pt2y] y coordinate of a corner end point\n     * @param {Number} [edgePtx] x coordinate of a corner anchor point\n     * @param {Number} [edgePty] y coordinate of a corner anchor point\n     * @param {Number} [edgePtType] a type of of a corner anchor point\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._addCornerToVertices = function (target, pt1x, pt1y, pt2x, pt2y, edgePtx, edgePty, edgePtType) {\n\n        var endPtX, endPtY, chunk1X, chunk1Y, chunk2X, chunk2Y;\n        var edgeForInsetX, edgeForInsetY;\n        var edgeForArcX, edgeForArcY;\n\n        if (pt1x == pt2x && pt1y == pt2y) {\n            if (edgePtx != pt1x || edgePty != pt1y) {\n                target.addVertex(IFVertex.Command.Line, edgePtx, edgePty);\n                target.addVertex(IFVertex.Command.Line, pt2x, pt2y);\n            }\n            return;\n        }\n\n        if (pt1x == edgePtx && pt1y == edgePty || pt2x == edgePtx && pt2y == edgePty) {\n            target.addVertex(IFVertex.Command.Line, pt2x, pt2y);\n            return;\n        }\n\n        if (edgePtType == IFPathBase.CornerType.Rounded ||\n            edgePtType == IFPathBase.CornerType.InverseRounded) {\n            if ((pt1x == pt2x && pt1x == edgePtx) || (pt1y == pt2y && pt1y == edgePty)) {\n                target.addVertex(IFVertex.Command.Curve, pt2x, pt2y);\n                target.addVertex(IFVertex.Command.Curve, edgePtx, edgePty);\n            } else {\n                if (edgePtType == IFPathBase.CornerType.Rounded) {\n                    edgeForArcX = edgePtx;\n                    edgeForArcY = edgePty;\n                } else { // edgePtType == IFPathBase.AnchorPoint.Type.InverseRounded\n                    edgeForArcX = pt1x + pt2x - edgePtx;\n                    edgeForArcY = pt1y + pt2y - edgePty;\n                }\n                target.addVertex(IFVertex.Command.Curve2, pt2x, pt2y);\n                target.addVertex(IFVertex.Command.Curve2,\n                    pt1x + (edgeForArcX - pt1x) * IFPathBase.AnchorPoint.BEST_CIRCLE_COEFF,\n                    pt1y + (edgeForArcY - pt1y) * IFPathBase.AnchorPoint.BEST_CIRCLE_COEFF);\n                target.addVertex(IFVertex.Command.Curve2,\n                    pt2x + (edgeForArcX - pt2x) * IFPathBase.AnchorPoint.BEST_CIRCLE_COEFF,\n                    pt2y + (edgeForArcY - pt2y) * IFPathBase.AnchorPoint.BEST_CIRCLE_COEFF);\n            }\n        } else if (edgePtType == IFPathBase.CornerType.Fancy) {\n            chunk1X = (pt2x - edgePtx) / 3;\n            chunk1Y = (pt2y - edgePty) / 3;\n            chunk2X = (edgePtx - pt1x) / 3;\n            chunk2Y = (edgePty - pt1y) / 3;\n\n            endPtX = pt1x + 2 * chunk1X;\n            endPtY = pt1y + 2 * chunk1Y;\n            target.addVertex(IFVertex.Command.Line, endPtX, endPtY);\n\n            endPtX += 2 * chunk2X;\n            endPtY += 2 * chunk2Y;\n            target.addVertex(IFVertex.Command.Line, endPtX, endPtY);\n\n            endPtX -= chunk1X;\n            endPtY -= chunk1Y;\n            target.addVertex(IFVertex.Command.Line, endPtX, endPtY);\n\n            endPtX -= chunk2X;\n            endPtY -= chunk2Y;\n            target.addVertex(IFVertex.Command.Line, endPtX, endPtY);\n\n            endPtX += 2 * chunk1X;\n            endPtY += 2 * chunk1Y;\n            target.addVertex(IFVertex.Command.Line, endPtX, endPtY);\n\n            endPtX += 2 * chunk2X;\n            endPtY += 2 * chunk2Y;\n            target.addVertex(IFVertex.Command.Line, endPtX, endPtY);\n\n        } else if (edgePtType == IFPathBase.CornerType.Bevel) {\n            target.addVertex(IFVertex.Command.Line, pt2x, pt2y);\n\n        } else if (edgePtType == IFPathBase.CornerType.Inset) {\n            edgeForInsetX = pt1x + pt2x - edgePtx;\n            edgeForInsetY = pt1y + pt2y - edgePty;\n\n            target.addVertex(IFVertex.Command.Line, edgeForInsetX, edgeForInsetY);\n            target.addVertex(IFVertex.Command.Line, pt2x, pt2y);\n\n        } else {   // use IFPathBase.AnchorPoint.Type.Asymmetric for all the unsupported types\n            target.addVertex(IFVertex.Command.Line, edgePtx, edgePty);\n            target.addVertex(IFVertex.Command.Line, pt2x, pt2y);\n        }\n    };\n\n    /**\n     * Adds path end vertices to the _vertices container, used to finish path\n     * This function is supposed to be called only when the path is NOT closed\n     * @param {IFVertexContainer} target the target vertex container to put vertices into\n     * @param {IFTransform} transform - a transformation to apply to anchor points before generating vertices\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype._addPathEndVertices = function (target, transform) {\n        var hx, hy;\n        var endPt = this.getLastChild();\n        var prevPt = endPt.getPrevious();\n\n        if (transform) {\n            endPt = endPt._getTransformedCopy(transform);\n            prevPt = prevPt._getTransformedCopy(transform);\n        }\n\n        if (endPt.$hlx != null && endPt.$hly != null && prevPt.$hrx != null && prevPt.$hry != null) {\n            target.addVertex(IFVertex.Command.Curve2, endPt.$x, endPt.$y);\n            target.addVertex(IFVertex.Command.Curve2, prevPt.$hrx, prevPt.$hry);\n            target.addVertex(IFVertex.Command.Curve2, endPt.$hlx, endPt.$hly);\n        } else if ((endPt.$hlx == null || endPt.$hly == null) && (prevPt.$hrx == null || prevPt.$hry == null)) {\n            target.addVertex(IFVertex.Command.Line, endPt.$x, endPt.$y);\n        } else {\n            if (endPt.$hlx != null && endPt.$hly != null) {\n                hx = endPt.$hlx;\n                hy = endPt.$hly;\n            } else {\n                hx = prevPt.$hrx;\n                hy = prevPt.$hry;\n            }\n            target.addVertex(IFVertex.Command.Curve, endPt.$x, endPt.$y);\n            target.addVertex(IFVertex.Command.Curve, hx, hy);\n        }\n    };\n\n    /** @override */\n    IFPathBase.AnchorPoints.prototype._handleChange = function (change, args) {\n        var path = this._parent;\n\n        if (path) {\n            var prevPt, nextPt;\n            var anchorPoint = args;\n            var hx, hy;\n\n            if (change == IFNode._Change.BeforeChildInsert) {\n                if (this.getParent()) {\n                    this.getParent().beginUpdate();\n                }\n            } else if (change == IFNode._Change.AfterChildInsert) {\n                prevPt = this.getPreviousPoint(anchorPoint);\n                if (prevPt && prevPt.$hrx != null && anchorPoint.$tp == IFPathBase.AnchorPoint.Type.Connector) {\n                    hx = anchorPoint.$x + (prevPt.$x - anchorPoint.$x) * IFPathBase.AnchorPoint.HANDLE_COEFF;\n                    hy = anchorPoint.$y + (prevPt.$y - anchorPoint.$y) * IFPathBase.AnchorPoint.HANDLE_COEFF;\n                    if (!ifMath.isEqualEps(anchorPoint.$x - hx, 0) || !ifMath.isEqualEps(anchorPoint.$y - hy, 0)) {\n                        anchorPoint.setProperties(['hlx', 'hly'], [hx, hy]);\n                    }\n                }\n\n                nextPt = this.getNextPoint(anchorPoint);\n                if (nextPt && nextPt.$hlx != null && anchorPoint.$tp == IFPathBase.AnchorPoint.Type.Connector) {\n                    hx = anchorPoint.$x + (nextPt.$x - anchorPoint.$x) * IFPathBase.AnchorPoint.HANDLE_COEFF;\n                    hy = anchorPoint.$y + (nextPt.$y - anchorPoint.$y) * IFPathBase.AnchorPoint.HANDLE_COEFF;\n                    if (!ifMath.isEqualEps(anchorPoint.$x - hx, 0) || !ifMath.isEqualEps(anchorPoint.$y - hy, 0)) {\n                        anchorPoint.setProperties(['hrx', 'hry'], [hx, hy]);\n                    }\n                }\n\n                if (anchorPoint.$ah ||\n                    anchorPoint.$tp == IFPathBase.AnchorPoint.Type.Connector) {\n\n                    anchorPoint._invalidateCalculations();\n                }\n                this._invalidateLeft(prevPt);\n                this._invalidateRight(nextPt);\n\n                if (this.getParent()) {\n                    this.getParent().endUpdate();\n                }\n            } else if (change == IFNode._Change.BeforeChildRemove) {\n                if (this.getParent()) {\n                    this.getParent().beginUpdate();\n                }\n                this._dirtyPrev = this.getPreviousPoint(anchorPoint);\n                this._dirtyNext = this.getNextPoint(anchorPoint);\n            } else if (change == IFNode._Change.AfterChildRemove) {\n                if (this._dirtyPrev) {\n                    this._invalidateLeft(this._dirtyPrev);\n                }\n                if (this._dirtyNext) {\n                    this._invalidateRight(this._dirtyNext);\n                }\n\n                if (this.getParent()) {\n                    this.getParent().endUpdate();\n                }\n            }\n        }\n\n        if (path && (change == IFNode._Change.AfterChildInsert || change == IFNode._Change.AfterChildRemove)) {\n            // Notify path parent about the change\n            path._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n            path._verticesDirty = true;\n            path._notifyChange(IFElement._Change.FinishGeometryUpdate);\n        }\n\n        IFNode.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * Get next point from given source point\n     * @param {IFPathBase.AnchorPoint} source\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype.getNextPoint = function (source) {\n        var nextPt = source ? source.getNext() : null;\n        if (!nextPt && this._parent && this._parent.$closed && source == this.getLastChild()) {\n            nextPt = this.getFirstChild();\n        }\n        return nextPt;\n    };\n\n    /**\n     * Get previous point from given source point\n     * @param {IFPathBase.AnchorPoint} source\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype.getPreviousPoint = function (source) {\n        var prevPt = source ? source.getPrevious() : null;\n        if (!prevPt && this._parent && this._parent.$closed && source == this.getFirstChild()) {\n            prevPt = this.getLastChild();\n        }\n        return prevPt;\n    };\n\n    /**\n     * Get last related point from given source point\n     * @param {IFPathBase.AnchorPoint} source\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype.getLastRelatedPoint = function (source) {\n        var lastRelPt = source;\n        var nextPt = this.getNextPoint(source);\n        if (nextPt) {\n            lastRelPt = nextPt;\n            if (nextPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric || nextPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n                var nextnextPt = this.getNextPoint(nextPt);\n                if (nextnextPt && nextnextPt.$ah && nextnextPt != source) {\n                    lastRelPt = nextnextPt;\n                }\n            }\n        }\n\n        return lastRelPt;\n    };\n\n    /**\n     * Get first related point from given source point\n     * @param {IFPathBase.AnchorPoint} source\n     * @private\n     */\n    IFPathBase.AnchorPoints.prototype.getFirstRelatedPoint = function (source) {\n        var firstRelPt = source;\n        var prevPt = this.getPreviousPoint(source);\n        if (prevPt) {\n            firstRelPt = prevPt;\n            if (prevPt.$tp == IFPathBase.AnchorPoint.Type.Symmetric || prevPt.$tp == IFPathBase.AnchorPoint.Type.Mirror) {\n                var prevprevPt = this.getPreviousPoint(prevPt);\n                if (prevprevPt && prevprevPt.$ah && prevprevPt != source) {\n                    firstRelPt = prevprevPt;\n                }\n            }\n        }\n\n        return firstRelPt;\n    };\n\n    /** @override */\n    IFPathBase.AnchorPoints.prototype.toString = function () {\n        return \"[Object IFPathBase.AnchorPoints]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFPathBase Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {IFVertexContainer}\n     * @private\n     */\n    IFPathBase.prototype._vertices = null;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    IFPathBase.prototype._verticesDirty = false;\n\n    /**\n     * @type {IFPathBase.AnchorPoints}\n     * @private\n     */\n    IFPathBase.prototype._anchorPoints = null;\n\n    /** @override */\n    IFPathBase.prototype.rewindVertices = function (index) {\n        if (this._verticesDirty || this._vertices == null || this._vertices.getCount() == 0) {\n            this._vertices.clearVertices();\n            this._getAnchorPoints()._generateVertices(this._vertices, this.$trf, true);\n            this._verticesDirty = false;\n        }\n        return this._vertices.rewindVertices(index);\n    };\n\n    /** @override */\n    IFPathBase.prototype.readVertex = function (vertex) {\n        return this._vertices.readVertex(vertex);\n    };\n\n    /** @override */\n    IFPathBase.prototype.store = function (blob) {\n        if (IFShape.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFPathBase.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPathBase.prototype.restore = function (blob) {\n        if (IFShape.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFPathBase.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPathBase.prototype._handleChange = function (change, args) {\n        this._handleVisualChangeForProperties(change, args, IFPathBase.VisualProperties);\n\n        // Special handling when changing closed status of path\n        if (change === IFNode._Change.AfterPropertiesChange) {\n            if (args.properties.indexOf('closed') >= 0) {\n                var points = this._getAnchorPoints();\n                if (points) {\n                    points._invalidateRight(points.getFirstChild());\n                    points._invalidateLeft(points.getLastChild());\n                }\n                this._verticesDirty = true;\n            } else if (args.properties.indexOf('trf') >= 0) {\n                this._verticesDirty = true;\n            }\n        }\n        IFShape.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * @returns {IFPathBase.AnchorPoints}\n     * @private\n     */\n    IFPathBase.prototype._getAnchorPoints = function () {\n        return this._anchorPoints;\n    };\n\n    /** @override */\n    IFPathBase.prototype.toString = function () {\n        return \"[IFPathBase]\";\n    };\n\n    _.IFPathBase = IFPathBase;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/polygon.js",
    "content": "(function (_) {\n\n    /**\n     * A polygon shape\n     * @class IFPolygon\n     * @extends IFPathBase\n     * @constructor\n     */\n    function IFPolygon() {\n        IFPathBase.call(this);\n        this.$closed = true; // polygons are always closed\n        this._setDefaultProperties(IFPolygon.GeometryProperties);\n    }\n\n    IFNode.inherit(\"polygon\", IFPolygon, IFPathBase);\n\n    /**\n     * The geometry properties of a polygon with their default values\n     */\n    IFPolygon.GeometryProperties = {\n        /** Number of points / segments */\n        pts: 6,\n        /** Horizontal Center */\n        cx: 0,\n        /** Vertical Center */\n        cy: 0,\n        /** Outer Radius */\n        or: 0,\n        /** Inner Radius */\n        ir: 0,\n        /** Outer Angle */\n        oa: 0,\n        /** Inner Angle */\n        ia: ifMath.PI2 - Math.PI / 3,\n        /** Outer Corner Type */\n        oct: IFPathBase.CornerType.Rounded,\n        /** Inner Corner Type */\n        ict: IFPathBase.CornerType.Rounded,\n        /** Outer Corner Radius */\n        ocr: 0,\n        /** Inner Corner Radius */\n        icr: 0\n    };\n\n    /**\n     * Iterate all segments of the polygon\n     * @param {Function(point: IFPoint, inside: Boolean, angle: Number)} iterator the\n     * iterator receiving the parameters. If this returns true then the iteration will be stopped.\n     * @param {Boolean} [includeTransform] if true, includes the transformation of the polygon\n     * if any in the returned coordinates. Defaults to false.\n     */\n    IFPolygon.prototype.iterateSegments = function (iterator, includeTransform) {\n        // Accuracy or considering start and end angles the same (2*PI overall)\n        var ACC = 1.0e-6;\n        var endArc = this.$oa + ifMath.PI2;\n        var stepArc = ifMath.PI2 / this.$pts;\n        var deltaArc = this.$ia - this.$oa;\n\n        var transform = includeTransform ? this.$trf : null;\n\n        // iterate backwards, as we have reflected Y axis; also for compatibility with MX\n        for (var arc = this.$oa; arc < endArc - ACC; arc += stepArc) {\n            // Outside\n            var point = new IFPoint(this.$or * Math.cos(arc) + this.$cx, this.$or * Math.sin(arc) + this.$cy);\n\n            if (transform) {\n                point = transform.mapPoint(point);\n            }\n\n            if (iterator(point, false, arc) === true) {\n                break;\n            }\n\n            // Inside\n            point = new IFPoint(this.$ir * Math.cos(arc + deltaArc) + this.$cx, this.$ir * Math.sin(arc + deltaArc) + this.$cy);\n\n            if (transform) {\n                point = transform.mapPoint(point);\n            }\n\n            if (iterator(point, true, arc + deltaArc) === true) {\n                break;\n            }\n        }\n    };\n\n    /** @override */\n    IFPolygon.prototype.store = function (blob) {\n        if (IFPathBase.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFPolygon.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPolygon.prototype.restore = function (blob) {\n        if (IFPathBase.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFPolygon.GeometryProperties);\n            this._invalidatePath();\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPolygon.prototype._handleChange = function (change, args) {\n        if (this._handleGeometryChangeForProperties(change, args, IFPolygon.GeometryProperties) && change == IFNode._Change.AfterPropertiesChange) {\n            this._invalidatePath();\n        }\n        IFPathBase.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * @private\n     */\n    IFPolygon.prototype._invalidatePath = function () {\n        var anchorPoints = this._getAnchorPoints();\n\n        this.beginUpdate();\n        anchorPoints._beginBlockCompositeEvents(true, true, true);\n        try {\n            // Clear old path points\n            anchorPoints.clearChildren();\n\n            this.iterateSegments(function (point, inside, angle) {\n                var anchorPoint = new IFPathBase.AnchorPoint();\n                anchorPoint.setProperties(['tp', 'x', 'y', 'cl', 'cr'],\n                    [inside ? this.$ict : this.$oct, point.getX(), point.getY(), inside ? this.$icr : this.$ocr, inside ? this.$icr : this.$ocr]);\n                anchorPoints.appendChild(anchorPoint);\n            }.bind(this));\n\n        } finally {\n            this.endUpdate();\n            anchorPoints._endBlockCompositeEvents(true, true, true);\n        }\n    };\n\n    /** @override */\n    IFPolygon.prototype.getCenter = function (includeTransform) {\n        var center = new IFPoint(this.$cx, this.$cy);\n        if (includeTransform && this.$trf) {\n            center = this.$trf.mapPoint(center);\n        }\n        return center;\n    };\n\n    /** @override */\n    IFPolygon.prototype.getOrigHalfWidth = function () {\n        return this.$or >= this.$ir ? this.$or : this.$ir;\n    };\n\n    /** @override */\n    IFPolygon.prototype.getOrigHalfHeight = function () {\n        return this.$or >= this.$ir ? this.$or : this.$ir;\n    };\n\n    /** @override */\n    IFPolygon.prototype.toString = function () {\n        return \"[IFPolygon]\";\n    };\n\n    _.IFPolygon = IFPolygon;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/rectangle.js",
    "content": "(function (_) {\n\n    /**\n     * A rectangle shape\n     * @class IFRectangle\n     * @extends IFPathBase\n     * @constructor\n     */\n    function IFRectangle() {\n        IFPathBase.call(this);\n        this.$closed = true; // rectangles are always closed\n        this._setDefaultProperties(IFRectangle.GeometryProperties);\n        this._invalidatePath(); // create unit path\n    }\n\n    IFNode.inherit(\"rectangle\", IFRectangle, IFPathBase);\n\n    /**\n     * The geometry properties of a rectangle with their default values\n     */\n    IFRectangle.GeometryProperties = {\n        /** All corners uniform */\n        uf: true,\n        /** Top-Left uniform, corner-type, x-shoulder-length, y-shoulder-length */\n        tl_uf: true,\n        tl_ct: IFPathBase.CornerType.Rounded,\n        tl_sx: 0,\n        tl_sy: 0,\n        /** Top-Right uniform, corner-type, x-shoulder-length, y-shoulder-length */\n        tr_uf: true,\n        tr_ct: IFPathBase.CornerType.Rounded,\n        tr_sx: 0,\n        tr_sy: 0,\n        /** Bottom-Right uniform, corner-type, x-shoulder-length, y-shoulder-length */\n        br_uf: true,\n        br_ct: IFPathBase.CornerType.Rounded,\n        br_sx: 0,\n        br_sy: 0,\n        /** Bottom-Left uniform, corner-type, x-shoulder-length, y-shoulder-length */\n        bl_uf: true,\n        bl_ct: IFPathBase.CornerType.Rounded,\n        bl_sx: 0,\n        bl_sy: 0\n    };\n\n    /**\n     * Returns the property-prefix for a rectangle side\n     * @param {IFRect.Side} side the side to get a prefix for\n     * @returns {string} the prefix for the given side\n     */\n    IFRectangle.getGeometryPropertiesSidePrefix = function (side) {\n        switch (side) {\n            case IFRect.Side.TOP_LEFT:\n                return 'tl';\n            case IFRect.Side.TOP_RIGHT:\n                return 'tr';\n            case IFRect.Side.BOTTOM_RIGHT:\n                return 'br';\n            case IFRect.Side.BOTTOM_LEFT:\n                return 'bl';\n            default:\n                throw new Error(\"Invalid side\");\n        }\n    };\n\n    /**\n     * Rectangle sides in their correct order\n     * @type {Array<IFRect.Side>}\n     */\n    IFRectangle.SIDES = [IFRect.Side.TOP_LEFT, IFRect.Side.TOP_RIGHT, IFRect.Side.BOTTOM_RIGHT, IFRect.Side.BOTTOM_LEFT];\n\n    /**\n     * Iterate all segments of the rectangle\n     * @param {Function(point: IFPoint, side: IFRect.Side, cornerType: IFPathBase.CornerType, leftShoulderLength: Number, rightShoulderLength: Number, idx: Number)} iterator\n     * the iterator receiving the parameters. If this returns true then the iteration will be stopped.\n     * @param {Boolean} [includeTransform] if true, includes the transformation of the rectangle\n     * if any in the returned coordinates. Defaults to false.\n     */\n    IFRectangle.prototype.iterateSegments = function (iterator, includeTransform) {\n        var transform = includeTransform ? this.$trf : null;\n\n        for (var i = 0; i < IFRectangle.SIDES.length; ++i) {\n            var side = IFRectangle.SIDES[i];\n            var prefix = IFRectangle.getGeometryPropertiesSidePrefix(side);\n            var point = null;\n\n            switch (side) {\n                case IFRect.Side.TOP_LEFT:\n                    point = new IFPoint(-1, -1);\n                    break;\n                case IFRect.Side.TOP_RIGHT:\n                    point = new IFPoint(1, -1);\n                    break;\n                case IFRect.Side.BOTTOM_RIGHT:\n                    point = new IFPoint(1, 1);\n                    break;\n                case IFRect.Side.BOTTOM_LEFT:\n                    point = new IFPoint(-1, 1);\n                    break;\n            }\n\n            if (transform) {\n                point = transform.mapPoint(point);\n            }\n\n            if (iterator(point, side, this['$' + prefix + '_ct'], this['$' + prefix + '_sx'], this['$' + prefix + '_sy'], i) === true) {\n                break;\n            }\n        }\n    };\n\n    /** @override */\n    IFRectangle.prototype.store = function (blob) {\n        if (IFPathBase.prototype.store.call(this, blob)) {\n            if (this.$uf) {\n                blob.uf = true; // all uniform\n                blob.ct = this.$tl_ct; // all corner type\n                blob.sl = this.$tl_sx; // all shoulder length\n            } else {\n                for (var i = 0; i < IFRectangle.SIDES.length; ++i) {\n                    var side = IFRectangle.SIDES[i];\n                    var prefix = IFRectangle.getGeometryPropertiesSidePrefix(side);\n                    blob[prefix + 'uf'] = this['$' + prefix + '_uf'];\n                    blob[prefix + 'ct'] = this['$' + prefix + '_ct'];\n                    blob[prefix + 'sl'] = [this['$' + prefix + '_sx'], this['$' + prefix + '_sy']];\n                }\n            }\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFRectangle.prototype.restore = function (blob) {\n        if (IFPathBase.prototype.restore.call(this, blob)) {\n            // We'll use our custom restore routine here as we can save optimized\n            for (var i = 0; i < IFRectangle.SIDES.length; ++i) {\n                var side = IFRectangle.SIDES[i];\n                var prefix = IFRectangle.getGeometryPropertiesSidePrefix(side);\n                this.$uf = blob.uf;\n                this['$' + prefix + '_uf'] = blob.uf ? blob.uf : blob[prefix + 'uf'];\n                this['$' + prefix + '_ct'] = blob.uf ? blob.ct : blob[prefix + 'ct'];\n                this['$' + prefix + '_sx'] = blob.uf ? blob.sl : blob[prefix + 'sl'][0];\n                this['$' + prefix + '_sy'] = blob.uf ? blob.sl : blob[prefix + 'sl'][1];\n            }\n\n            this._invalidatePath();\n            return true;\n        }\n        return false;\n    };\n\n    /**\n     * Return the anchor points of the rectangle\n     * @returns {IFPathBase.AnchorPoints}\n     */\n    IFRectangle.prototype.getAnchorPoints = function () {\n        return this._getAnchorPoints();\n    };\n\n    /** @override */\n    IFRectangle.prototype._handleChange = function (change, args) {\n        if (this._handleGeometryChangeForProperties(change, args, IFRectangle.GeometryProperties) && change == IFNode._Change.AfterPropertiesChange) {\n            var propertiesToSet = [];\n            var valuesToSet = [];\n\n            var props = args.properties;\n            var vals = args.values;\n\n            if (this.$uf) {\n                var newSVal = null;\n                var newTVal = null;\n                var sValAssigned = false;\n                var tValAssigned = false;\n                for (var i = 0; i < IFRectangle.SIDES.length && (!sValAssigned || !tValAssigned); ++i) {\n                    var side = IFRectangle.SIDES[i];\n                    var prefix = IFRectangle.getGeometryPropertiesSidePrefix(side);\n                    if (!sValAssigned) {\n                        var prop = prefix + '_sx';\n                        var idx = props.indexOf(prop);\n                        if (idx >= 0) {\n                            newSVal = vals[idx];\n                            sValAssigned = true;\n                        } else {\n                            var prop = prefix + '_sy';\n                            var idx = props.indexOf(prop);\n                            if (idx >= 0) {\n                                newSVal = vals[idx];\n                                sValAssigned = true;\n                            }\n                        }\n                    }\n                    if (!tValAssigned) {\n                        var prop = prefix + '_ct';\n                        var idx = props.indexOf(prop);\n                        if (idx >= 0) {\n                            newTVal = vals[idx];\n                            tValAssigned = true;\n                        }\n                    }\n                }\n                if (!sValAssigned) {\n                    newSVal = this.getProperty('tl_sx');\n                }\n                if (!tValAssigned) {\n                    newTVal = this.getProperty('tl_ct');\n                }\n\n                propertiesToSet.push('tl_uf', 'tr_uf', 'br_uf', 'bl_uf');\n                valuesToSet.push(true, true, true, true);\n\n                propertiesToSet.push('tl_sx', 'tl_sy', 'tr_sx', 'tr_sy', 'br_sx', 'br_sy', 'bl_sx', 'bl_sy');\n                valuesToSet.push(newSVal, newSVal, newSVal, newSVal, newSVal, newSVal, newSVal, newSVal);\n\n                propertiesToSet.push('tl_ct', 'tr_ct', 'br_ct', 'bl_ct');\n                valuesToSet.push(newTVal, newTVal, newTVal, newTVal);\n            } else {\n                for (var i = 0; i < IFRectangle.SIDES.length; ++i) {\n                    var side = IFRectangle.SIDES[i];\n                    var prefix = IFRectangle.getGeometryPropertiesSidePrefix(side);\n                    var newSVal = null;\n                    var sValAssigned = false;\n\n                    if (this['$' + prefix + '_uf']) {\n                        var prop = prefix + '_sx';\n                        var idx = props.indexOf(prop);\n                        if (idx >= 0) {\n                            newSVal = vals[idx];\n                            sValAssigned = true;\n                        } else {\n                            var prop = prefix + '_sy';\n                            var idx = props.indexOf(prop);\n                            if (idx >= 0) {\n                                newSVal = vals[idx];\n                                sValAssigned = true;\n                            }\n                        }\n                        if (!sValAssigned) {\n                            newSVal = this.getProperty(prefix + '_sx');\n                        }\n\n                        propertiesToSet.push(prefix + '_sx');\n                        valuesToSet.push(newSVal);\n                        propertiesToSet.push(prefix + '_sy');\n                        valuesToSet.push(newSVal);\n                    }\n                }\n            }\n\n            if (!this.setProperties(propertiesToSet, valuesToSet)) {\n                this._invalidatePath();\n            }\n        }\n        IFPathBase.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * @private\n     */\n    IFRectangle.prototype._invalidatePath = function () {\n        var anchorPoints = this._getAnchorPoints();\n\n        this.beginUpdate();\n        anchorPoints._beginBlockCompositeEvents(true, true, true);\n        try {\n            // Clear old path points\n            anchorPoints.clearChildren();\n\n            this.iterateSegments(function (point, side, cornerType, xShoulderLength, yShoulderLength) {\n                var anchorPoint = new IFPathBase.AnchorPoint();\n                anchorPoint.setProperties(['tp', 'x', 'y', 'cl', 'cr', 'cu'],\n                    [cornerType, point.getX(), point.getY(), xShoulderLength, yShoulderLength, false]);\n\n                anchorPoints.appendChild(anchorPoint);\n            }.bind(this));\n\n        } finally {\n            this.endUpdate();\n            anchorPoints._endBlockCompositeEvents(true, true, true);\n        }\n    };\n\n    /** @override */\n    IFRectangle.prototype.toString = function () {\n        return \"[IFRectangle]\";\n    };\n\n    _.IFRectangle = IFRectangle;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/shape.js",
    "content": "(function (_) {\n\n    /**\n     * A base geometry based on vertices which is transformable and styleable\n     * and may contain other elements as sub-contents\n     * @class IFShape\n     * @extends IFItem\n     * @mixes IFNode.Container\n     * @mixes IFElement.Transform\n     * @mixes IFElement.Style\n     * @mixes IFVertexSource\n     * @constructor\n     */\n    function IFShape() {\n        IFItem.call(this);\n\n        // Assign default properties\n        this._setDefaultProperties(IFShape.GeometryProperties);\n    }\n\n    IFObject.inheritAndMix(IFShape, IFItem, [IFNode.Container, IFElement.Transform, IFElement.Style, IFVertexSource]);\n\n    /**\n     * The geometry properties of a shape with their default values\n     */\n    IFShape.GeometryProperties = {\n        trf: null\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFShape._StyleSet Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFShape._StyleSet\n     * @extends IFStyleSet\n     * @private\n     */\n    IFShape._StyleSet = function () {\n        this._flags |= IFNode.Flag.Shadow;\n    }\n\n    IFNode.inherit(\"shpStylSet\", IFShape._StyleSet, IFStyleSet);\n\n    /** @override */\n    IFShape._StyleSet.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFShape;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFShape Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /** @override */\n    IFShape.prototype.getStyleSet = function () {\n        var styleSet = IFElement.Style.prototype.getStyleSet.call(this);\n        if (!styleSet) {\n            styleSet = new IFShape._StyleSet();\n            this.appendChild(styleSet);\n        }\n        return styleSet;\n    };\n\n    /** @override */\n    IFShape.prototype.getTransform = function () {\n        return this.$trf;\n    };\n\n    /** @override */\n    IFShape.prototype.setTransform = function (transform) {\n        this.setProperty('trf', transform);\n    };\n\n    /** @override */\n    IFShape.prototype.transform = function (transform) {\n        if (transform && !transform.isIdentity()) {\n            this.setProperty('trf', this.$trf ? this.$trf.multiplied(transform) : transform);\n        }\n        IFElement.Transform.prototype._transformChildren.call(this, transform);\n    };\n\n    /** @override */\n    IFShape.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFLayer || parent instanceof IFShapeSet || parent instanceof IFShape;\n    };\n\n    /** @override */\n    IFShape.prototype.store = function (blob) {\n        if (IFItem.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFShape.GeometryProperties, function (property, value) {\n                if (property === 'trf' && value) {\n                    return IFTransform.serialize(value);\n                }\n                return value;\n            });\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFShape.prototype.restore = function (blob) {\n        if (IFItem.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFShape.GeometryProperties, function (property, value) {\n                if (property === 'trf' && value) {\n                    return IFTransform.deserialize(value);\n                }\n                return value;\n            });\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFShape.prototype._paint = function (context, style, styleIndex) {\n        if (!this.rewindVertices(0)) {\n            return;\n        }\n\n        // Paint our background before anything else\n        this._paintBackground(context, style, styleIndex);\n\n        // Handle different painting routes depending on outline mode\n        if (context.configuration.isOutline(context)) {\n            // Outline is painted with non-transformed stroke\n            // so we reset transform, transform the vertices\n            // ourself and then re-apply the transformation\n            var transform = context.canvas.resetTransform();\n            var transformedVertices = new IFVertexTransformer(style ? style.createVertexSource(this) : this, transform);\n            context.canvas.putVertices(transformedVertices);\n            context.canvas.strokeVertices(context.getOutlineColor());\n            context.canvas.setTransform(transform);\n\n            // Paint contents\n            this._paintContents(context, style, styleIndex);\n        } else if (style) {\n            this._paintStyle(context, style, styleIndex);\n        }\n\n        // Paint our foreground\n        this._paintForeground(context, style, styleIndex);\n    };\n\n    /**\n     * Called to paint any backgrounds painted at\n     * first before any styling and contents\n     * @param {IFPaintContext} context\n     * @private\n     */\n    IFShape.prototype._paintBackground = function (context, style, styleIndex) {\n        // NO-OP\n    };\n\n    /**\n     * Called to paint the foreground painted after\n     * any styling and everything else\n     * @param {IFPaintContext} context\n     * @private\n     */\n    IFShape.prototype._paintForeground = function (context, style, styleIndex) {\n    };\n\n\n    /**\n     * Called to paint with a given style\n     * @param {IFPaintContext} context\n     * @param {IFStyle} style\n     * @param {Number} styleIndex\n     * @private\n     */\n    IFShape.prototype._paintStyle = function (context, style, styleIndex) {\n        // Iterate all (visible) paints\n        var paints = null;\n        for (var entry = style.getActualStyle().getFirstChild(); entry !== null; entry = entry.getNext()) {\n            if (entry instanceof IFPaintEntry && entry.getProperty('vs') === true) {\n                if (!paints) {\n                    paints = [];\n                }\n                paints.push(entry);\n            }\n        }\n\n        if (paints) {\n            // Create vertex source and put 'em onto canvas\n            var vertexSource = style.createVertexSource(this);\n            context.canvas.putVertices(vertexSource);\n\n            var paintBBox = style.getBBox(this.getGeometryBBox());\n\n            // Paint all paints npw\n            for (var i = 0; i < paints.length; ++i) {\n                var paint = paints[i];\n\n                // Check whether to create a separate canvas\n                if (paint.isSeparate()) {\n                    // Create temporary canvas\n                    var paintCanvas = context.canvas.createCanvas(paintBBox);\n\n                    // Put our vertex source onto it\n                    paintCanvas.putVertices(vertexSource);\n\n                    // Paint\n                    paint.paint(paintCanvas, paintBBox);\n\n                    // Draw the temporary canvas back\n                    context.canvas.drawCanvas(paintCanvas, 0, 0, paint.getPaintOpacity(), paint.getPaintCmpOrBlend());\n                } else {\n                    // Regular painting on main canvas\n                    paint.paint(context.canvas, paintBBox);\n                }\n            }\n        }\n    };\n\n    /**\n     * Paint and clip any contents of this shape\n     * @param {IFPaintContext} context\n     * @private\n     */\n    IFShape.prototype._paintContents = function (context, style, styleIndex) {\n        // TODO : Check intersection of children paintbbox and if it is\n        // fully contained by this shape then don't clip\n        // Paint our contents if any and clip 'em to ourself\n        var oldContentsCanvas = null;\n        for (var child = this.getFirstChild(); child !== null; child = child.getNext()) {\n            if (child instanceof IFElement) {\n                // Create temporary canvas if none yet\n                if (!oldContentsCanvas) {\n                    oldContentsCanvas = context.canvas;\n                    context.canvas = oldContentsCanvas.createCanvas(this.getGeometryBBox());\n                }\n\n                child.render(context);\n            }\n        }\n\n        // If we have a old contents canvas, clip our contents and swap canvas back\n        if (oldContentsCanvas) {\n            context.canvas.putVertices(this);\n            context.canvas.fillVertices(IFColor.BLACK, 1, IFPaintCanvas.CompositeOperator.DestinationIn);\n            oldContentsCanvas.drawCanvas(context.canvas);\n            context.canvas.finish();\n            context.canvas = oldContentsCanvas;\n        }\n    };\n\n    /** @override */\n    IFShape.prototype.renderStyle = function (context, style, styleIndex) {\n        IFElement.Style.prototype.renderStyle.call(this, context, style, styleIndex);\n\n        // Render our contents here and clip' em if any after first style\n        if (styleIndex === 0) {\n            this._paintContents(context);\n        }\n    };\n\n    /** @override */\n    IFShape.prototype._calculateGeometryBBox = function () {\n        return ifVertexInfo.calculateBounds(this, true);\n    };\n\n    /** @override */\n    IFShape.prototype._calculatePaintBBox = function () {\n        var source = this.getGeometryBBox();\n        if (!source) {\n            return null;\n        }\n\n        return this.getStyleSet().getBBox(source);\n    };\n\n    /** @override */\n    IFShape.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFShape.GeometryProperties);\n        IFItem.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFShape.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        // Hit-Test styles, first\n        var styleHit = this.getStyleSet().hitTest(this, location, transform, tolerance);\n\n        if (styleHit) {\n            return new IFElement.HitResult(this, styleHit);\n        } else if (force) {\n            // When forced we'll always hit-test our whole \"invisible\" outline / fill area\n            var vertexHit = new IFVertexInfo.HitResult();\n            if (ifVertexInfo.hitTest(location.getX(), location.getY(), new IFVertexTransformer(this, transform), tolerance, true, vertexHit)) {\n                return new IFElement.HitResult(this, vertexHit);\n            }\n        } else {\n            // If we didn't hit a style entry, then hit-test our \"invisible\" tolerance outline area if any\n            if (tolerance) {\n                var vertexHit = new IFVertexInfo.HitResult();\n                if (ifVertexInfo.hitTest(location.getX(), location.getY(), new IFVertexTransformer(this, transform), tolerance, false, vertexHit)) {\n                    return new IFElement.HitResult(this, vertexHit);\n                }\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Returns a center of the shape in world coordinates. Shape's internal transformation is applied if needed\n     * @param {Boolean} includeTransform - whether to apply shape's internal transformation\n     * @returns {IFPoint}\n     */\n    IFShape.prototype.getCenter = function (includeTransform) {\n        var center = new IFPoint(0, 0);\n        if (includeTransform && this.$trf) {\n            center = this.$trf.mapPoint(center);\n        }\n        return center;\n    };\n\n    /**\n     * Returns shape's internal half width before applying any transformations\n     * @returns {Number}\n     */\n    IFShape.prototype.getOrigHalfWidth = function () {\n        return 1.0;\n    };\n\n    /**\n     * Returns shape's internal half width before applying any transformations\n     * @returns {Number}\n     */\n    IFShape.prototype.getOrigHalfHeight = function () {\n        return 1.0;\n    };\n\n    /** @override */\n    IFShape.prototype.toString = function () {\n        return \"[IFShape]\";\n    };\n\n    _.IFShape = IFShape;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/shapeset.js",
    "content": "(function (_) {\n    /**\n     * The base for a groups\n     * @class IFShapeSet\n     * @extends IFItem\n     * @mixes IFNode.Container\n     * @mixes IFElement.Transform\n     * @constructor\n     */\n    function IFShapeSet() {\n        IFItem.call(this);\n    }\n    IFNode.inheritAndMix('shapeSet', IFShapeSet, IFItem, [IFNode.Container, IFElement.Transform]);\n\n    /** @override */\n    IFShapeSet.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFLayer || parent instanceof IFShapeSet;\n    };\n\n    /** @override */\n    IFShapeSet.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        return new IFBlock.HitResult(this);\n    };\n\n    _.IFShapeSet = IFShapeSet;\n})(this);"
  },
  {
    "path": "src/infinity/scene/shape/text.js",
    "content": "(function (_) {\n    /**\n     * A text shape\n     * @class IFText\n     * @extends IFShape\n     * @constructor\n     */\n    function IFText() {\n        IFShape.call(this);\n        this._setDefaultProperties(IFText.GeometryProperties);\n        this._runs = [];\n        this._runsDirty = false;\n    }\n\n    IFNode.inherit(\"text\", IFText, IFShape);\n\n    /**\n     * Vertical align of a text\n     */\n    IFText.VerticalAlign = {\n        Top: 't',\n        Middle: 'm',\n        Bottom: 'b'\n    };\n\n    /**\n     * The geometry properties of text with their default values\n     */\n    IFText.GeometryProperties = {\n        /** Auto-width or not */\n        aw: true,\n        /** Auto-height or not */\n        ah: true,\n        /** Vertical alignment */\n        va: IFText.VerticalAlign.Top\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText.Chunk Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFText.Chunk\n     * @extends IFNode\n     * @mixes IFNode.Store\n     * @private\n     */\n    IFText.Chunk = function (content) {\n        IFNode.call(this);\n        this._content = content;\n    }\n\n    IFNode.inheritAndMix(\"txChk\", IFText.Chunk, IFNode, [IFNode.Store]);\n\n    /**\n     * @type {String}\n     * @private\n     */\n    IFText.Chunk.prototype._content = null;\n\n    /**\n     * @returns {String}\n     */\n    IFText.Chunk.prototype.getContent = function () {\n        return this._content;\n    };\n\n    /** @override */\n    IFText.Chunk.prototype.store = function (blob) {\n        if (IFNode.Store.prototype.store.call(this, blob)) {\n            blob.cnt = this._content;\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.Chunk.prototype.restore = function (blob) {\n        if (IFNode.Store.prototype.restore.call(this, blob)) {\n            this._content = blob.cnt;\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.Chunk.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFText.Block;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText.Break Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFText.Break\n     * @extends IFNode\n     * @mixes IFNode.Store\n     * @private\n     */\n    IFText.Break = function () {\n        IFNode.call(this);\n    }\n\n    IFNode.inheritAndMix(\"txBrk\", IFText.Break, IFNode, [IFNode.Store]);\n\n    /** @override */\n    IFText.Break.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFText.Block;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText.Block Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFText.Block\n     * @extends IFNode\n     * @mixes IFNode.Properties\n     * @mixes IFNode.Store\n     * @private\n     */\n    IFText.Block = function () {\n        this._setDefaultProperties(IFText.Block.Properties);\n    };\n\n    IFObject.inheritAndMix(IFText.Block, IFNode, [IFNode.Properties, IFNode.Store]);\n\n    /**\n     * The geometry properties of a block with their default values\n     */\n    IFText.Block.Properties = {\n        /** The font family */\n        ff: null,\n        /** The font size */\n        fi: null,\n        /** The font-weight (IFFont.Weight) */\n        fw: null,\n        /** The font-style (IFFont.Style) */\n        fs: null,\n        /** The font color */\n        fc: null,\n        /** The character spacing */\n        cs: null,\n        /** The word spacing */\n        ws: null\n    };\n\n    IFText.Block.propertyToCss = function (property, value, css) {\n        if (property === 'ff') {\n            css['font-family'] = value !== null ? value : '';\n        } else if (property === 'fi') {\n            css['font-size'] = value !== null ? value + 'px' : '';\n        } else if (property === 'fw') {\n            css['font-weight'] = value !== null ? value.toString() : '';\n        } else if (property === 'fs') {\n            if (value === null) {\n                css['font-style'] = '';\n            } else {\n                switch (value) {\n                    case IFFont.Style.Normal:\n                        css['font-style'] = 'normal';\n                        break;\n                    case IFFont.Style.Italic:\n                        css['font-style'] = 'italic';\n                        break;\n                    default:\n                        break;\n                }\n            }\n        } else if (property === 'fc') {\n            css['color'] = value !== null ? value.asCSSString() : '';\n        } else if (property === 'cs') {\n            css['letter-spacing'] = value !== null ? value + 'px' : '';\n        } else if (property === 'ws') {\n            css['word-spacing'] = value !== null ? value + 'px' : '';\n        } else {\n            throw new Error('Unimplemented property (propertyToCss): ' + property);\n        }\n    };\n\n    IFText.Block.cssToProperty = function (property, css) {\n        if (property === 'ff') {\n            if (css['font-family']) {\n                var family = css['font-family'];\n                if (family.length > 0) {\n                    if (family.indexOf(',') >= 0) {\n                        family = family.substr(0, family.indexOf(',')).trim();\n                    }\n\n                    if (family.charAt(0) === '\"' || family.charAt(0) === \"'\") {\n                        family = family.substr(1);\n                    }\n                    if (family.charAt(family.length - 1) === '\"' || family.charAt(family.length - 1) === \"'\") {\n                        family = family.substr(0, family.length - 1);\n                    }\n\n                    return family;\n                }\n            }\n        } else if (property === 'fi') {\n            var value = parseFloat(css['font-size']);\n            if (!isNaN(value)) {\n                return value;\n            }\n        } else if (property === 'fw') {\n            var value = parseInt(css['font-weight']);\n            if (!isNaN(value)) {\n                return value;\n            } else {\n                value = css['font-weight'];\n                if (value === 'normal') {\n                    return IFFont.Weight.Regular;\n                } else if (value === 'bold') {\n                    return IFFont.Weight.Bold;\n                }\n            }\n        } else if (property === 'fs') {\n            if (css['font-style'] === 'normal') {\n                return IFFont.Style.Normal;\n            } else if (css['font-style'] === 'italic') {\n                return IFFont.Style.Italic;\n            }\n        } else if (property === 'fc') {\n            var value = IFColor.parseCSSColor(css['color']);\n            if (value) {\n                return value;\n            }\n        } else if (property === 'cs') {\n            var value = parseFloat(css['letter-spacing']);\n            if (!isNaN(value)) {\n                return value;\n            }\n        } else if (property === 'ws') {\n            var value = parseFloat(css['word-spacing']);\n            if (!isNaN(value)) {\n                return value;\n            }\n        } else {\n            throw new Error('Unimplemented property (cssToProperty): ' + property);\n        }\n\n        return null;\n    };\n\n    /**\n     * @return {IFText}\n     */\n    IFText.Block.prototype.getText = function () {\n        for (var parent = this.getParent(); parent !== null; parent = parent.getParent()) {\n            if (parent instanceof IFText) {\n                return parent;\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    IFText.Block.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFText.Block;\n    };\n\n    /** @override */\n    IFText.Block.prototype.store = function (blob) {\n        if (IFNode.Store.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFText.Block.Properties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @Block */\n    IFText.Block.prototype.restore = function (blob) {\n        if (IFNode.Store.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFText.Block.Properties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.Block.prototype._handleChange = function (change, args) {\n        var text = this.getText();\n\n        if (text) {\n            if (text._handleGeometryChangeForProperties(change, args, IFText.Block.Properties) && change == IFNode._Change.BeforePropertiesChange) {\n                text._runsDirty = true;\n            } else if (change == IFNode._Change.BeforeChildInsert || change == IFNode._Change.BeforeChildRemove) {\n                text.beginUpdate();\n            } else if (change == IFNode._Change.AfterChildInsert || change == IFNode._Change.AfterChildRemove) {\n                text._runsDirty = true;\n                text.endUpdate();\n            }\n        }\n\n        IFNode.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * @param {{}} css\n     * @returns {{}}\n     */\n    IFText.Block.prototype.propertiesToCss = function (css) {\n        return this._propertiesToCss(css, IFText.Block.Properties, IFText.Block.propertyToCss);\n    };\n\n    /**\n     * @param {{}} css\n     */\n    IFText.Block.prototype.cssToProperties = function (css) {\n        this._cssToProperties(css, IFText.Block.Properties, IFText.Block.cssToProperty);\n    };\n\n    IFText.Block.prototype._propertiesToCss = function (css, propertyMap, propertyConverter) {\n        for (var property in propertyMap) {\n            var value = this.getProperty(property);\n            if (value !== null) {\n                propertyConverter(property, value, css);\n            }\n        }\n        return css;\n    };\n\n    IFText.Block.prototype._cssToProperties = function (css, propertyMap, propertyConverter) {\n        var properties = [];\n        var values = [];\n        for (var property in propertyMap) {\n            var value = propertyConverter(property, css);\n            properties.push(property);\n            values.push(value);\n        }\n\n        if (properties.length > 0) {\n            this.setProperties(properties, values);\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText.Span Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFText.Span\n     * @extends IFText.Block\n     * @mixes IFNode.Container\n     * @private\n     */\n    IFText.Span = function () {\n        IFText.Block.call(this);\n        this._setDefaultProperties(IFText.Span.Properties);\n    }\n\n    IFNode.inheritAndMix(\"txSpan\", IFText.Span, IFText.Block, [IFNode.Container]);\n\n    /** @override */\n    IFText.Span.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFText.Paragraph || parent instanceof IFText.Span;\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText.Paragraph Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFText.Paragraph\n     * @extends IFText.Block\n     * @mixes IFNode.Container\n     * @private\n     */\n    IFText.Paragraph = function () {\n        IFText.Block.call(this);\n        this._setDefaultProperties(IFText.Paragraph.Properties);\n    }\n\n    IFNode.inheritAndMix(\"txPara\", IFText.Paragraph, IFText.Block, [IFNode.Container]);\n\n    /**\n     * Alignment of a paragraph\n     * @enum\n     */\n    IFText.Paragraph.Alignment = {\n        Left: 'l',\n        Center: 'c',\n        Right: 'r',\n        Justify: 'j'\n    };\n\n    /**\n     * Wrap-Mode of a paragraph\n     * @enum\n     */\n    IFText.Paragraph.WrapMode = {\n        /**\n         * No word-break\n         */\n        None: 'n',\n\n        /**\n         * Break after words only\n         */\n        Words: 'w',\n\n        /**\n         * Break anywhere including characters\n         */\n        All: 'a'\n    };\n\n    /**\n     * The geometry properties of a paragraph with their default values\n     */\n    IFText.Paragraph.Properties = {\n        /** Column count */\n        cc: null,\n        /** Column gap */\n        cg: null,\n        /** Wrap-Mode of a paragraph (IFText.Paragraph.WrapMode) */\n        wm: null,\n        /** The paragraph's alignment (IFText.Paragraph.Alignment) */\n        al: null,\n        /** The first line intendation */\n        in: null,\n        /** The line height whereas 1 = 100% */\n        lh: null\n    };\n\n    IFText.Paragraph.propertyToCss = function (property, value, css) {\n        if (property === 'cc') {\n            value = value !== null ? value : '';\n            css['column-count'] = value;\n            css['-webkit-column-count'] = value;\n            css['-moz-column-count'] = value;\n        } else if (property === 'cg') {\n            value = value !== null ? value : '';\n            css['column-gap'] = value;\n            css['-webkit-column-gap'] = value;\n            css['-moz-column-gap'] = value;\n        } else if (property === 'wm') {\n            if (value === null) {\n                css['white-space'] = '';\n                css['word-break'] = '';\n            } else {\n                switch (value) {\n                    case IFText.Paragraph.WrapMode.None:\n                        css['white-space'] = 'nowrap';\n                        break;\n                    case IFText.Paragraph.WrapMode.Words:\n                        css['white-space'] = 'pre-wrap';\n                        break;\n                    case IFText.Paragraph.WrapMode.All:\n                        css['white-space'] = 'pre-wrap';\n                        css['word-break'] = 'break-all';\n                        break;\n                }\n            }\n        } else if (property === 'al') {\n            if (value === null) {\n                css['text-align'] = '';\n            } else {\n                switch (value) {\n                    case IFText.Paragraph.Alignment.Left:\n                        css['text-align'] = 'left';\n                        break;\n                    case IFText.Paragraph.Alignment.Center:\n                        css['text-align'] = 'center';\n                        break;\n                    case IFText.Paragraph.Alignment.Right:\n                        css['text-align'] = 'right';\n                        break;\n                    case IFText.Paragraph.Alignment.Justify:\n                        css['text-align'] = 'justify';\n                        break;\n                }\n            }\n        } else if (property === 'in') {\n            css['text-indent'] = value !== null ? value + 'px' : '';\n        } else if (property === 'lh') {\n            css['line-height'] = value !== null ? value : '';\n        } else {\n            throw new Error('Unimplemented property (propertyToCss): ' + property);\n        }\n    };\n\n    IFText.Paragraph.cssToProperty = function (property, css) {\n        if (property === 'cc') {\n            var str = css['column-count'] || css['-webkit-column-count'] || css['-moz-column-count'];\n            var value = parseInt(str);\n            if (!isNaN(value)) {\n                return value;\n            }\n        } else if (property === 'cg') {\n            var str = css['column-gap'] || css['-webkit-column-gap'] || css['-moz-column-gap'];\n            var value = parseFloat(str);\n            if (!isNaN(value)) {\n                return value;\n            }\n        } else if (property === 'wm') {\n            var wspace = css['white-space'];\n            var wbreak = css['word-break'];\n\n            if (wspace === 'pre-wrap') {\n                if (wbreak === 'break-all') {\n                    return IFText.Paragraph.WrapMode.All;\n                } else {\n                    return IFText.Paragraph.WrapMode.Words;\n                }\n            } else if (wspace === 'nowrap') {\n                return IFText.Paragraph.WrapMode.None;\n            }\n        } else if (property === 'al') {\n            if (value === 'left') {\n                return IFText.Paragraph.Alignment.Left;\n            } else if (value === 'center') {\n                return IFText.Paragraph.Alignment.Center;\n            } else if (value === 'right') {\n                return IFText.Paragraph.Alignment.Right;\n            } else if (value === 'justify') {\n                return IFText.Paragraph.Alignment.Justify;\n            }\n        } else if (property === 'in') {\n            var value = parseFloat(css['text-indent']);\n            if (!isNaN(value)) {\n                return value;\n            }\n        } else if (property === 'lh') {\n            var lineHeight = parseFloat(css['line-height']);\n            if (!isNaN(lineHeight)) {\n                return lineHeight;\n            }\n        } else {\n            throw new Error('Unimplemented property (cssToProperty): ' + property);\n        }\n        return null;\n    };\n\n    /** @override */\n    IFText.Paragraph.prototype._handleChange = function (change, args) {\n        var text = this.getText();\n\n        if (text) {\n            if (text._handleGeometryChangeForProperties(change, args, IFText.Paragraph.Properties) && change == IFNode._Change.BeforePropertiesChange) {\n                text._runsDirty = true;\n            }\n        }\n\n        IFText.Block.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFText.Paragraph.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFText.Content;\n    };\n\n    /** @override */\n    IFText.Paragraph.prototype.store = function (blob) {\n        if (IFText.Block.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFText.Paragraph.Properties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.Paragraph.prototype.restore = function (blob) {\n        if (IFText.Block.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFText.Paragraph.Properties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.Paragraph.prototype.propertiesToCss = function (css) {\n        this._propertiesToCss(css, IFText.Paragraph.Properties, IFText.Paragraph.propertyToCss);\n        return IFText.Block.prototype.propertiesToCss.call(this, css);\n    };\n\n    /**\n     * @param {{}} css\n     */\n    IFText.Paragraph.prototype.cssToProperties = function (css) {\n        this._cssToProperties(css, IFText.Paragraph.Properties, IFText.Paragraph.cssToProperty);\n        IFText.Block.prototype.cssToProperties.call(this, css);\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText.Content Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFText.Content\n     * @extends IFText.Paragraph\n     * @private\n     */\n    IFText.Content = function () {\n        IFText.Paragraph.call(this);\n        this._flags |= IFNode.Flag.Shadow;\n\n        // Setup default font stuff\n        this.$ff = 'Open Sans';\n        this.$fi = 20;\n        this.$fw = IFFont.Weight.Regular;\n        this.$fs = IFFont.Style.Normal;\n        this.$lh = 1;\n        this.$wm = IFText.Paragraph.WrapMode.All;\n    };\n\n    IFNode.inherit(\"txContent\", IFText.Content, IFText.Paragraph);\n\n    /** @override */\n    IFText.Content.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFText;\n    };\n\n    /** @override */\n    IFText.Content.prototype.propertiesToCss = function (css) {\n        // Setup default color taking care of style if any\n        var color = 'black';\n        var text = this._parent;\n        if (text) {\n            // TODO : Figure color of topmost visible styleSet and assign it to color\n        }\n        css['color'] = color;\n\n        return IFText.Paragraph.prototype.propertiesToCss.call(this, css);\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFText Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @type {IFText.Content}\n     * @private\n     */\n    IFText.prototype._content = null;\n\n    /**\n     * @type {IFPoint}\n     * @private\n     */\n    IFText.prototype._size = null;\n\n    /**\n     * @type {Array<{}>}\n     * @private\n     */\n    IFText.prototype._runs = null;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    IFText.prototype._runsDirty = false;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    IFText.prototype._runItIndex = null;\n\n    /**\n     * @type {IFVertexSource}\n     * @private\n     */\n    IFText.prototype._runItOutline = null;\n\n    /**\n     * Returns the content container of the text node\n     * @returns {IFText.Content}\n     */\n    IFText.prototype.getContent = function () {\n        // If we have a _content reference and it not\n        // has ourself as a parent, then clear it, first\n        if (this._content && this._content.getParent() !== this) {\n            this._content = null;\n        }\n\n        if (!this._content) {\n            // Find our content and save reference for faster access\n            for (var child = this.getFirstChild(true); child !== null; child = child.getNext(true)) {\n                if (child instanceof IFText.Content) {\n                    this._content = child;\n                    break;\n                }\n            }\n\n            if (!this._content) {\n                this._content = new IFText.Content();\n                this.appendChild(this._content);\n            }\n        }\n\n        return this._content;\n    };\n\n    /**\n     * Returns the bounding box of the content\n     * @return {IFRect} null if there's no bbox or a valid bbox\n     */\n    IFText.prototype.getContentBBox = function () {\n        return this._size ? new IFRect(0, 0, this._size.getX(), this._size.getY()) : null;\n    };\n\n    /**\n     * Converts the underlying content to a html string\n     * @param {Boolean} segments if true, each single character\n     * will be enclosed by a span. Defaults to false.\n     * Defaults to false.\n     * @returns {String}\n     */\n    IFText.prototype.asHtml = function (segments) {\n        var dummy = $('<div></div>');\n        this._asHtml(dummy, this.getContent(), segments);\n        return dummy.html();\n    };\n\n    /**\n     * Clears and replaces the contents of this text from\n     * a given html string\n     * @param {String} html\n     */\n    IFText.prototype.fromHtml = function (html) {\n        this.beginUpdate();\n        try {\n            var content = this.getContent();\n\n            // Clear our contents\n            content.clearChildren(true);\n\n            // Parse html into a dummy element for iterating (if any)\n            if (html && html !== \"\") {\n                var doc = document.createElement('div');\n                doc.innerHTML = html;\n                for (var child = doc.firstChild; child !== null; child = child.nextSibling) {\n                    this._fromHtml(child, content);\n                }\n            }\n        } finally {\n            this.endUpdate();\n        }\n    };\n\n    /** @override */\n    IFText.prototype.store = function (blob) {\n        if (IFShape.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFText.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.prototype.restore = function (blob) {\n        if (IFShape.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFText.GeometryProperties);\n            this._runsDirty = true;\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.prototype.rewindVertices = function (index) {\n        if (this._runsDirty || this._runs == null) {\n            this._runs = [];\n\n            // Calculate our actual text box and line length\n            var textBox = IFRect.fromPoints(new IFPoint(0, 0), new IFPoint(1, 1));\n            if (this.$trf) {\n                textBox = this.$trf.mapRect(textBox);\n            }\n\n            // Create our temporary container for holding our html contents\n            var container = $('<div></div>')\n                .addClass('contenteditable')\n                .css(this.getContent().propertiesToCss({}))\n                .css({\n                    'position': 'absolute',\n                    'top': '0px',\n                    'left': '0px',\n                    'visibility': 'hidden',\n                    'width': textBox.getWidth() > 1 && !this.$aw ? textBox.getWidth() + 'px' : '',\n                    'height': textBox.getHeight() > 1 && this.$ah ? textBox.getHeight() + 'px' : ''\n                })\n                .html(this.asHtml(true))\n                .appendTo($('body'));\n\n            // Calculate dimensions, first\n            var maxWidth = null;\n            var maxHeight = null;\n            container.find('p,span').each(function (index, element) {\n                var $element = $(element);\n                var offset = $element.offset();\n                var width = $element.outerWidth();\n                var height = $element.outerHeight();\n\n                if (maxWidth === null || (offset.left + width) > maxWidth) {\n                    maxWidth = offset.left + width;\n                }\n                if (maxHeight === null || (offset.top + height) > maxHeight) {\n                    maxHeight = offset.top + height;\n                }\n            }.bind(this));\n\n            // Assign calculated dimensions\n            this._size = maxWidth !== null && maxHeight !== null ? new IFPoint(maxWidth, maxHeight) : null;\n\n            // Calculate vertical shift depending on vertical alignment\n            var verticalShift = 0;\n            if (!this.$ah && this._size && this._size.getY() < textBox.getHeight()) {\n                switch (this.$va) {\n                    case IFText.VerticalAlign.Middle:\n                        verticalShift = (textBox.getHeight() - this._size.getY()) / 2;\n                        break;\n\n                    case IFText.VerticalAlign.Bottom:\n                        verticalShift = textBox.getHeight() - this._size.getY();\n                        break;\n                }\n            }\n\n            container.find('span:not(:has(span))').each(function (index, span) {\n                var $span = $(span);\n                var rect = span.getBoundingClientRect();\n                var textContent = $span.text();\n                if (textContent.length === 0) {\n                    return;\n                }\n                var char = textContent[0];\n\n                // Ignore zero height/width, spaces and binary chars\n                if (rect.height <= 0 || rect.width <= 0 || char === ' ' || char >= '\\x00' && char <= '\\x1F') {\n                    return;\n                }\n\n                var css = {\n                    'font-family': $span.css('font-family'),\n                    'font-size': $span.css('font-size'),\n                    'font-style': $span.css('font-style'),\n                    'font-weight': $span.css('font-weight')\n                }\n                var fontFamily = IFText.Block.cssToProperty('ff', css);\n                var fontSize = IFText.Block.cssToProperty('fi', css);\n                var fontStyle = IFText.Block.cssToProperty('fs', css);\n                var fontWeight = IFText.Block.cssToProperty('fw', css);\n                var fontVariant = ifFont.getVariant(fontFamily, fontStyle, fontWeight);\n                var baseline = ifFont.getGlyphBaseline(fontFamily, fontVariant, fontSize, char);\n\n                this._runs.push({\n                    x: textBox.getX() + rect.left,\n                    y: textBox.getY() + rect.top + verticalShift + baseline,\n                    char: char,\n                    family: fontFamily,\n                    variant: fontVariant,\n                    size: fontSize\n                });\n            }.bind(this));\n\n            // Remove our container now\n            container.remove();\n\n            // We're done here\n            this._runsDirty = false;\n        }\n\n        if (this._runs && this._runs.length > 0) {\n            this._runItIndex = 0;\n            this._runItOutline = null;\n            return true;\n        }\n\n        return false;\n    };\n\n    /** @override */\n    IFText.prototype.readVertex = function (vertex) {\n        if (this._runItOutline) {\n            if (this._runItOutline.readVertex(vertex)) {\n                return true;\n            } else {\n                this._runItOutline = null;\n                if (++this._runItIndex >= this._runs.length) {\n                    return false;\n                }\n            }\n        }\n\n        if (!this._runItOutline) {\n            var run = this._runs[this._runItIndex];\n            if (!run) {\n                return false;\n            }\n            this._runItOutline = ifFont.getGlyphOutline(run.family, run.variant, run.size, run.x, run.y, run.char);\n            if (!this._runItOutline.rewindVertices(0)) {\n                throw new Error('Unexpected end of outline');\n            }\n            return this._runItOutline.readVertex(vertex);\n        }\n    };\n\n    /** @override */\n    IFText.prototype._calculateGeometryBBox = function () {\n        // Always rewind to ensure integrity\n        this.rewindVertices(0);\n\n        // Not having a size means not having a bbox\n        if (!this._size) {\n            return null;\n        }\n\n        var textBox = IFRect.fromPoints(new IFPoint(0, 0), new IFPoint(1, 1));\n        if (this.$trf) {\n            textBox = this.$trf.mapRect(textBox);\n        }\n\n        var width = !this.$aw ? textBox.getWidth() : this._size.getX();\n        var height = !this.$ah ? textBox.getHeight() : this._size.getY();\n\n        return new IFRect(textBox.getX(), textBox.getY(), width, height);\n    };\n\n    /** @override */\n    IFText.prototype._preparePaint = function (context) {\n        if (IFShape.prototype._preparePaint.call(this, context)) {\n            // Check if we need to clip rect\n            var clipBox = this._getClipBox(context);\n            if (clipBox) {\n                context.canvas.clipRect(clipBox.getX(), clipBox.getY(), clipBox.getWidth(), clipBox.getHeight());\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFText.prototype._finishPaint = function (context) {\n        // Reset clipping if done previously\n        if (this._getClipBox(context) !== null) {\n            context.canvas.resetClip();\n        }\n\n        IFShape.prototype._finishPaint.call(this, context);\n    };\n\n    /** @override */\n    IFText.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        // For now, text is always hit-test by its bbox only so return ourself\n        // TODO : Add support for detailed range hit test information here\n        return new IFElement.HitResult(this);\n    };\n\n    /** @override */\n    IFText.prototype._handleChange = function (change, args) {\n        IFShape.prototype._handleChange.call(this, change, args);\n\n        if (this._handleGeometryChangeForProperties(change, args, IFText.GeometryProperties) && change == IFNode._Change.BeforePropertiesChange) {\n            this._runsDirty = true;\n        }\n\n        if (change === IFNode._Change.BeforePropertiesChange) {\n            var transformIdx = args.properties.indexOf('trf');\n            if (transformIdx >= 0 && !this._runsDirty) {\n                // TODO : Optimize for cases where no invalidation of vertices is required\n                /*\n                 // Check whether only translation was changed and if that's\n                 // the case we'll simply translate our existing vertices,\n                 // otherwise we'll invalidate the vertices\n                 var newTransform = args.values[transformIdx];\n                 var inverseTransform = this.$trf ? this.$trf.inverted() : new IFTransform(1, 0, 0, 1, 0, 0);\n                 var deltaTransform = newTransform.multiplied(inverseTransform);\n                 if (deltaTransform.isIdentity(true)) {\n                 if (this._vertices) {\n                 var translation = deltaTransform.getTranslation();\n                 this._vertices.transformVertices(new IFTransform(1, 0, 0, 1, translation.getX(), translation.getY()));\n                 }\n                 } else {\n                 this._runsDirty = true;\n                 }\n                 */\n                this._runsDirty = true;\n            }\n        }\n    };\n\n    /**\n     * Returns a clip-box if required, otherwise null\n     * @param context\n     * @returns {IFRect}\n     * @private\n     */\n    IFText.prototype._getClipBox = function (context) {\n        var bbox = this.getGeometryBBox();\n        if (this._size &&\n            ((!this.$aw && this._size.getX() >= bbox.getWidth()) ||\n                (!this.$ah && this._size.getY() >= bbox.getHeight()))) {\n\n            return new IFRect(bbox.getX(), bbox.getY(),\n                !this.$aw ? bbox.getWidth() : context.canvas.getWidth(),\n                !this.$ah ? bbox.getHeight() : context.canvas.getHeight());\n        }\n        return null;\n    };\n\n    /**\n     * Convert contents to html\n     * @param parent\n     * @param node\n     * @param segments\n     * @private\n     */\n    IFText.prototype._asHtml = function (parent, node, segments) {\n        if (node instanceof IFText.Break) {\n            $('<br>')\n                .appendTo(parent);\n        } else if (node instanceof IFText.Chunk) {\n            var content = node.getContent();\n            if (content && content !== \"\") {\n                if (segments) {\n                    for (var i = 0; i < content.length; ++i) {\n                        $('<span></span>')\n                            .text(content[i])\n                            .appendTo(parent);\n                    }\n                } else {\n                    parent.append(document.createTextNode(content));\n                }\n            }\n        } else if (node instanceof IFText.Content) {\n            // ignore root\n        } else if (node instanceof IFText.Paragraph) {\n            parent = $('<p></p>')\n                .css('margin', '0px') // !!\n                .css(node.propertiesToCss({}))\n                .appendTo(parent);\n        } else if (node instanceof IFText.Span) {\n            parent = $('<span></span>')\n                .css(node.propertiesToCss({}))\n                .appendTo(parent);\n        }\n        if (node.hasMixin(IFNode.Container)) {\n            for (var child = node.getFirstChild(); child !== null; child = child.getNext()) {\n                this._asHtml(parent, child, segments);\n            }\n        }\n    };\n\n    /**\n     * @param element\n     * @param parent\n     * @private\n     */\n    IFText.prototype._fromHtml = function (node, parent) {\n        if (node.nodeType === 1) {\n            var nodeName = node.nodeName.toLowerCase();\n\n            if (nodeName === 'p' || nodeName === 'div') {\n                var paragraph = new IFText.Paragraph();\n                paragraph.cssToProperties(node.style);\n                parent.appendChild(paragraph);\n                parent = paragraph;\n            } else if (nodeName === 'span' || nodeName === 'b' || nodeName === 'strong' || nodeName === 'i') {\n                var span = new IFText.Span();\n                span.cssToProperties(node.style);\n                parent.appendChild(span);\n                parent = span;\n\n                if (nodeName === 'b' || nodeName === 'strong') {\n                    span.setProperty('fw', IFFont.Weight.Bold);\n                } else if (nodeName === 'i') {\n                    span.setProperty('fs', IFFont.Style.Italic);\n                }\n            } else if (nodeName === 'br') {\n                parent.appendChild(new IFText.Break());\n                return; // no children for breaks\n            } else {\n                // ignore the element alltogether\n                return;\n            }\n\n            for (var child = node.firstChild; child !== null; child = child.nextSibling) {\n                this._fromHtml(child, parent);\n            }\n        } else if (node.nodeType === 3) {\n            if (node.textContent !== \"\") {\n                parent.appendChild(new IFText.Chunk(node.textContent));\n            }\n        }\n    };\n\n    /** @override */\n    IFText.prototype.toString = function () {\n        return \"[IFText]\";\n    };\n\n    _.IFText = IFText;\n})(this);"
  },
  {
    "path": "src/infinity/scene/structure/layer.js",
    "content": "(function (_) {\n    /**\n     * An element representing a layer\n     * @class IFLayer\n     * @extends IFBlock\n     * @mixes IFNode.Container\n     * @mixes IFElement.Transform\n     * @constructor\n     */\n    function IFLayer() {\n        IFBlock.call(this);\n        this._setDefaultProperties(IFLayer.VisualProperties, IFLayer.MetaProperties);\n    }\n\n    IFNode.inheritAndMix(\"layer\", IFLayer, IFBlock, [IFNode.Container, IFElement.Transform]);\n\n    IFLayer.GUIDE_COLOR_DEFAULT = new IFColor(IFColor.Type.RGB, [0, 255, 255, 100]);\n\n    /**\n     * The tp of a layer\n     * @enum\n     */\n    IFLayer.Type = {\n        /**\n         * An output layer, will make it into\n         * the actual output\n         */\n        Output: 'O',\n\n        /**\n         * A draft layer consisting of vector shapes\n         * but won't make it into the output\n         */\n        Draft: 'D',\n\n        /**\n         * A guide layer consisting of vector shapes\n         * but won't make it into the output and is\n         * the source of snapping / guides\n         */\n        Guide: 'G'\n    };\n\n    /**\n     * Localized names for IFLayer.Type\n     */\n    IFLayer.TypeName = {\n        'O': new IFLocale.Key(IFLayer, 'type.output'),\n        'D': new IFLocale.Key(IFLayer, 'type.draft'),\n        'G': new IFLocale.Key(IFLayer, 'type.guide')\n    };\n\n    /**\n     * The meta properties of a layer with their default values\n     */\n    IFLayer.MetaProperties = {\n        tp: IFLayer.Type.Output\n    };\n\n    /**\n     * The visual properties of a layer with their default values\n     */\n    IFLayer.VisualProperties = {\n        // Whether layer is outlined or not\n        otl: false,\n        // The color of the layer\n        cls: new IFColor(IFColor.Type.RGB, [0, 168, 255, 100])\n    };\n\n    /** @override */\n    IFLayer.prototype.store = function (blob) {\n        if (IFBlock.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFLayer.VisualProperties, function (property, value) {\n                if (property === 'cls' && value) {\n                    return value.asString();\n                }\n                return value;\n            });\n            this.storeProperties(blob, IFLayer.MetaProperties);\n\n            // Store activeness flag which is special to pages and layers\n            if (this.hasFlag(IFNode.Flag.Active)) {\n                blob.__active = true;\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFLayer.prototype.restore = function (blob) {\n        if (IFBlock.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFLayer.VisualProperties, function (property, value) {\n                if (property === 'cls' && value) {\n                    return IFColor.parseColor(value);\n                }\n                return value;\n            });\n            this.restoreProperties(blob, IFLayer.MetaProperties);\n\n            // Restore activeness flag which is special to pages and layers\n            if (blob.__active) {\n                this.setFlag(IFNode.Flag.Active);\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFLayer.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFLayer || parent instanceof IFPage;\n    };\n\n    /** @override */\n    IFLayer.prototype._preparePaint = function (context) {\n        if (IFBlock.prototype._preparePaint.call(this, context)) {\n            if (this.$tp === IFLayer.Type.Guide) {\n                if (!context.configuration.isGuidesVisible(context)) {\n                    return false;\n                } else if (context.configuration.paintMode !== IFScenePaintConfiguration.PaintMode.Outline && !this.$otl) {\n                    // Add outline color if not outline to behave like a guide layer means\n                    // to paint everything underneath in outline color\n                    context.outlineColors.push(this.$cls);\n                }\n            } else if (this.$tp === IFLayer.Type.Draft) {\n                if (!context.configuration.isAnnotationsVisible(context)) {\n                    return false;\n                }\n\n                // TODO : Mark draft layers like changing opacity etc.\n            }\n\n            if (context.configuration.paintMode !== IFScenePaintConfiguration.PaintMode.Outline && this.$otl) {\n                context.outlineColors.push(this.$cls);\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFLayer.prototype._finishPaint = function (context) {\n        if (this.$tp === IFLayer.Type.Guide && context.configuration.paintMode !== IFScenePaintConfiguration.PaintMode.Outline && !this.$otl) {\n            // Remove outline color if not outlined\n            context.outlineColors.pop();\n        } else if (this.$tp === IFLayer.Type.Draft) {\n            // TODO : Reset marked draft layers like changed opacity etc.\n        }\n\n        if (context.configuration.paintMode !== IFScenePaintConfiguration.PaintMode.Outline && this.$otl) {\n            context.outlineColors.pop();\n        }\n\n        IFBlock.prototype._finishPaint.call(this, context);\n    };\n\n    /** @override */\n    IFLayer.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        return new IFBlock.HitResult(this);\n    };\n\n    /** @override */\n    IFLayer.prototype._handleChange = function (change, args) {\n        this._handleVisualChangeForProperties(change, args, IFLayer.VisualProperties);\n\n        if (change == IFNode._Change.AfterPropertiesChange) {\n            var typeIndex = args.properties.indexOf('tp');\n            if (typeIndex >= 0) {\n                var oldTypeValue = args.values[typeIndex];\n\n                // Switch tp from guide <-> * must reset colors if defaults are set\n                if (oldTypeValue === IFLayer.Type.Guide && this.$cls === IFLayer.GUIDE_COLOR_DEFAULT) {\n                    this.$cls = IFLayer.VisualProperties.cls;\n                } else if (this.$tp === IFLayer.Type.Guide && this.$cls === IFLayer.VisualProperties.cls) {\n                    this.$cls = IFLayer.GUIDE_COLOR_DEFAULT;\n                }\n                this._notifyChange(IFElement._Change.InvalidationRequest);\n            }\n        }\n\n        IFBlock.prototype._handleChange.call(this, change, args);\n    };\n\n    _.IFLayer = IFLayer;\n})(this);"
  },
  {
    "path": "src/infinity/scene/structure/page.js",
    "content": "(function (_) {\n    /**\n     * An element representing a page\n     * @class IFPage\n     * @extends IFBlock\n     * @mixes IFNode.Container\n     * @mixes IFNode.Reference\n     * @constructor\n     */\n    function IFPage() {\n        IFBlock.call(this);\n        this._setDefaultProperties(IFPage.GeometryProperties, IFPage.VisualProperties);\n    };\n    IFNode.inheritAndMix(\"page\", IFPage, IFBlock, [IFNode.Container, IFNode.Reference]);\n\n    /**\n     * The geometry properties of a page with their default values\n     */\n    IFPage.GeometryProperties = {\n        /** Master-Page reference */\n        msref: null,\n        /** Page position */\n        x: 0,\n        y: 0,\n        /** Page size */\n        w: 0,\n        h: 0,\n        /** Additional bleeding */\n        bl: 0,\n        /** Margins (left, top, right, bottom, column, row) */\n        ml: 0,\n        mt: 0,\n        mr: 0,\n        mb: 0\n    };\n\n    /**\n     * The visual properties of a page with their default values\n     */\n    IFPage.VisualProperties = {\n        cls: null\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFPage Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * Returns whether this page is a master page or not (always returns false if not attached)\n     * @returns {boolean}\n     */\n    IFPage.prototype.isMaster = function () {\n        return this.isAttached() ? this.getScene().hasLinks(this) : false;\n    };\n\n    /**\n     * Returns the master page if attached and the page has a master\n     * @returns {IFNode.Reference}\n     */\n    IFPage.prototype.getMasterPage = function () {\n        var result = this.$msref && this.isAttached() ? this.getScene().getReference(this.$msref) : null;\n\n        // try to avoid returning ourself\n        if (result === this) {\n            return null;\n        }\n\n        return result;\n    };\n\n    /**\n     * Returns the page's clip box which always is the page's\n     * geometry bbox plus additional bleeding if any\n     * @return {IFRect}\n     */\n    IFPage.prototype.getPageClipBBox = function () {\n        var bbox = this.getGeometryBBox();\n        if (bbox && !bbox.isEmpty()) {\n            var bl = this.$bl || 0;\n            return bbox.expanded(bl, bl, bl, bl);\n        }\n        return bbox;\n    };\n\n    /** @override */\n    IFPage.prototype.store = function (blob) {\n        if (IFBlock.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFPage.GeometryProperties);\n            this.storeProperties(blob, IFPage.VisualProperties, function (property, value) {\n                if (property === 'cls' && value) {\n                    return value.asString();\n                }\n                return value;\n            });\n\n            // Store activeness flag which is special to pages and layers\n            if (this.hasFlag(IFNode.Flag.Active)) {\n                blob.__active = true;\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPage.prototype.restore = function (blob) {\n        // Ugly hack to prevent transforming children when restoring\n        this.__restoring = true;\n        try {\n            if (IFBlock.prototype.restore.call(this, blob)) {\n                this.restoreProperties(blob, IFPage.GeometryProperties);\n                this.restoreProperties(blob, IFPage.VisualProperties, function (property, value) {\n                    if (property === 'cls' && value) {\n                        return IFColor.parseColor(value);\n                    }\n                    return value;\n                });\n\n                // Restore activeness flag which is special to pages and layers\n                if (blob.__active) {\n                    this.setFlag(IFNode.Flag.Active);\n                }\n\n                return true;\n            }\n            return false;\n        } finally {\n            delete this.__restoring;\n        }\n    };\n\n    /** @override */\n    IFPage.prototype._getBitmapPaintArea = function () {\n        return this.getPageClipBBox();\n    };\n\n    /** @override */\n    IFPage.prototype._renderToBitmap = function (context) {\n        // Enable page clipping\n        paintConfig.pagesClip = true;\n        return IFBlock.prototype._renderToBitmap(context);\n    };\n\n    /** @override */\n    IFPage.prototype._paint = function (context) {\n        // Paint master page if we have any\n        var masterPage = this.getMasterPage();\n\n        // Indicates whether page clipped it's contents\n        var isClipped = false;\n\n        // Figure if we have any contents\n        var hasContents = false;\n        for (var child = this.getFirstChild(); child !== null; child = child.getNext()) {\n            if (child instanceof IFElement) {\n                hasContents = true;\n                break;\n            }\n        }\n\n        // Reset canvas transform and save it\n        var canvasTransform = context.canvas.resetTransform();\n\n        // Get page rectangle and transform it into world space\n        var pageRect = new IFRect(this.$x, this.$y, this.$w, this.$h);\n        var transformedPageRect = canvasTransform.mapRect(pageRect).toAlignedRect();\n        var x = transformedPageRect.getX(), y = transformedPageRect.getY(), w = transformedPageRect.getWidth(), h = transformedPageRect.getHeight();\n\n        // If we have contents test if we shall clip to our extents\n        if (hasContents && masterPage || context.configuration.isPagesClip()) {\n            // Include bleeding in clipping coordinates if any\n            var bl = this.$bl || 0;\n            context.canvas.clipRect(x - bl, y - bl, w + bl * 2, h + bl * 2);\n            isClipped = true;\n        }\n\n        // Assign original transform again\n        context.canvas.setTransform(canvasTransform);\n\n        // Render master page if any\n        if (masterPage) {\n            var canvasTransform = context.canvas.getTransform(true);\n            var mx = masterPage.getProperty('x');\n            var my = masterPage.getProperty('y');\n            var dx = this.$x - mx;\n            var dy = this.$y - my;\n            var masterTransform = new IFTransform(1, 0, 0, 1, dx, dy);\n\n            // Prepare master paint:\n            // 1.) Translate canvas to our own x,y coordinates\n            // 2.) Reverse translate dirty areas with our own x,y coordinates\n            context.canvas.setTransform(canvasTransform.preMultiplied(masterTransform));\n            context.dirtyMatcher.transform(new IFTransform(1, 0, 0, 1, -dx, -dy));\n\n            // Let our master render now\n            masterPage.render(context);\n\n            // Restore in reverse order of preparation\n            context.dirtyMatcher.transform(masterTransform);\n            context.canvas.setTransform(canvasTransform);\n        }\n\n        // Render contents if any\n        if (hasContents) {\n            this._renderChildren(context);\n        }\n\n        // Reset clipping if we've clipped\n        if (isClipped) {\n            context.canvas.resetClip();\n        }\n    };\n\n    /** @override */\n    IFPage.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFScene;\n    };\n\n    /** @override */\n    IFPage.prototype._calculateGeometryBBox = function () {\n        return new IFRect(this.$x, this.$y, this.$w, this.$h);\n    };\n\n    /** @override */\n    IFPage.prototype._calculatePaintBBox = function () {\n        var bbox = this.getGeometryBBox();\n\n        if (this.$bl && this.$bl > 0) {\n            bbox = bbox.expanded(this.$bl, this.$bl, this.$bl, this.$bl);\n        }\n\n        var superBBox = IFBlock.prototype._calculatePaintBBox.call(this);\n\n        return superBBox ? superBBox.united(bbox) : bbox;\n    };\n\n    /** @override */\n    IFPage.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        var geoBox = this.getGeometryBBox();\n\n        if (transform) {\n            geoBox = transform.mapRect(geoBox);\n        }\n\n        if (geoBox.expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n            return new IFBlock.HitResult(this);\n        }\n\n        return IFBlock.prototype._detailHitTest.call(this, location, transform, tolerance, force);\n        ;\n    };\n\n    /** @override */\n    IFPage.prototype._handleChange = function (change, args) {\n        if (this._handleGeometryChangeForProperties(change, args, IFPage.GeometryProperties)) {\n            if (change === IFNode._Change.BeforePropertiesChange && !this.__restoring) {\n                // Check for position change in page\n                var xIndex = args.properties.indexOf('x');\n                var yIndex = args.properties.indexOf('y');\n                if (xIndex >= 0 || yIndex >= 0) {\n                    // Changing x and/or y requires translating all direct children\n                    var dx = xIndex >= 0 ? args.values[xIndex] - this.$x : 0;\n                    var dy = yIndex >= 0 ? args.values[yIndex] - this.$y : 0;\n\n                    if (dx !== 0 || dy !== 0) {\n                        var transform = new IFTransform(1, 0, 0, 1, dx, dy);\n                        for (var child = this.getFirstChild(true); child != null; child = child.getNext(true)) {\n                            if (child instanceof IFElement && child.hasMixin(IFElement.Transform)) {\n                                child.transform(transform);\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (args.properties.indexOf('msref') >= 0) {\n                var masterPage = this.getMasterPage();\n                if (masterPage) {\n                    switch (change) {\n                        case IFNode._Change.BeforePropertiesChange:\n                            this.getScene().unlink(masterPage, this);\n                            break;\n                        case IFNode._Change.AfterPropertiesChange:\n                            this.getScene().link(masterPage, this);\n                            break;\n                    }\n                }\n            }\n        }\n\n        this._handleVisualChangeForProperties(change, args, IFPage.VisualProperties);\n\n        if (change === IFElement._Change.InvalidationRequested) {\n            /** @type IFRect */\n            var area = args;\n\n            // Handle invalidation if we're a master\n            if (area && !area.isEmpty() && this.isMaster() && this.getScene().getProperty('singlePage') === false) {\n                // If the invalidation area intersects with our page clipping box then\n                // we need to invalidate the same area on all renderable linked pages as well\n                var clipBBox = this.getPageClipBBox();\n                if (clipBBox && !clipBBox.isEmpty() && clipBBox.intersectsRect(area)) {\n                    this.getScene().visitLinks(this, function (link) {\n                        if (link instanceof IFPage && link.isRenderable()) {\n                            // Move invalidation area relative to the linked page and let the\n                            // page invalidate the area which by itself my trigger more invalidations\n                            // when the linked page is also a master\n                            var dx = link.getProperty('x') - this.$x;\n                            var dy = link.getProperty('y') - this.$y;\n                            link._requestInvalidationArea(area.translated(dx, dy));\n                        }\n                    }.bind(this));\n                }\n            }\n        }\n\n        IFBlock.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFPage.prototype._setScene = function (scene) {\n        if (scene !== this._scene) {\n            if (scene) {\n                var masterPage = scene.getReference(this.$msref);\n                if (masterPage) {\n                    scene.link(masterPage, this)\n                }\n            } else {\n                var masterPage = this._scene.getReference(this.$msref);\n                if (masterPage) {\n                    this._scene.unlink(masterPage, this);\n                }\n            }\n        }\n        IFBlock.prototype._setScene.call(this, scene);\n    };\n\n    _.IFPage = IFPage;\n})(this);"
  },
  {
    "path": "src/infinity/scene/structure/slice.js",
    "content": "(function (_) {\n    /**\n     * An element representing a slice\n     * @class IFSlice\n     * @extends IFItem\n     * @mixes IFElement.Transform\n     * @constructor\n     */\n    function IFSlice() {\n        IFItem.call(this);\n        this._setDefaultProperties(IFSlice.VisualProperties, IFSlice.GeometryProperties, IFSlice.MetaProperties);\n    }\n\n    IFNode.inheritAndMix(\"slice\", IFSlice, IFItem, [IFElement.Transform]);\n\n    /**\n     * The meta properties of a slice with their default values\n     */\n    IFSlice.MetaProperties = {\n        // Whether to trim on exporting or not\n        trm: true\n    };\n\n    /**\n     * The geometry properties of a slice with their default values\n     */\n    IFSlice.GeometryProperties = {\n        trf: null\n    };\n\n    /**\n     * The visual properties of a slice with their default values\n     */\n    IFSlice.VisualProperties = {\n        // The color of the slice\n        cls: new IFColor(IFColor.Type.RGB, [0, 116, 217, 100])\n    };\n\n    /** @override */\n    IFSlice.prototype.getTransform = function () {\n        return this.$trf;\n    };\n\n    /** @override */\n    IFSlice.prototype.setTransform = function (transform) {\n        this.setProperty('trf', transform);\n    };\n\n    /** @override */\n    IFSlice.prototype.transform = function (transform) {\n        if (transform && !transform.isIdentity()) {\n            this.setProperty('trf', this.$trf ? this.$trf.multiplied(transform) : transform);\n        }\n        IFElement.Transform.prototype._transformChildren.call(this, transform);\n    };\n\n    /** @override */\n    IFSlice.prototype.store = function (blob) {\n        if (IFItem.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFSlice.VisualProperties, function (property, value) {\n                if (property === 'cls' && value) {\n                    return value.asString();\n                }\n                return value;\n            });\n\n            this.storeProperties(blob, IFSlice.GeometryProperties, function (property, value) {\n                if (property === 'trf' && value) {\n                    return IFTransform.serialize(value);\n                }\n                return value;\n            });\n\n            this.storeProperties(blob, IFSlice.MetaProperties);\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFSlice.prototype.restore = function (blob) {\n        if (IFItem.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFSlice.VisualProperties, function (property, value) {\n                if (property === 'cls' && value) {\n                    return IFColor.parseColor(value);\n                }\n                return value;\n            });\n\n            this.restoreProperties(blob, IFSlice.GeometryProperties, function (property, value) {\n                if (property === 'trf' && value) {\n                    return IFTransform.deserialize(value);\n                }\n                return value;\n            });\n\n            this.restoreProperties(blob, IFSlice.MetaProperties);\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFSlice.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFLayer;\n    };\n\n    /** @override */\n    IFPage.prototype._renderToBitmap = function (context) {\n        // Render scene and not ourself\n        this.getScene().render(context);\n\n        var bitmap = context.canvas.getBitmap();\n\n        // Clip bitmap if necessary\n        if (this.getProperty('trm')) {\n            bitmap.trim();\n        }\n\n        return bitmap;\n    };\n\n    /** @override */\n    IFSlice.prototype._paint = function (context) {\n        if (context.configuration.isSlicesVisible(context)) {\n            var sourceBBox = new IFRect(-1, -1, 2, 2);\n            sourceBBox = this.$trf ? this.$trf.mapRect(sourceBBox) : sourceBBox;\n\n            if (context.configuration.isOutline(context)) {\n                var transform = context.canvas.resetTransform();\n                var transformedRect = transform ? transform.mapRect(sourceBBox) : sourceBBox;\n                context.canvas.strokeRect(transformedRect.getX(), transformedRect.getY(),\n                    transformedRect.getWidth(), transformedRect.getHeight(), 1, context.getOutlineColor());\n                context.canvas.setTransform(transform);\n            } else {\n                var transformedRect = sourceBBox;\n                context.canvas.fillRect(transformedRect.getX(), transformedRect.getY(),\n                    transformedRect.getWidth(), transformedRect.getHeight(), this.$cls, 0.5);\n            }\n        }\n    };\n\n    /** @override */\n    IFSlice.prototype._calculateGeometryBBox = function () {\n        var rect = new IFRect(-1, -1, 2, 2);\n        return this.$trf ? this.$trf.mapRect(rect) : rect;\n    };\n\n    /** @override */\n    IFSlice.prototype._calculatePaintBBox = function () {\n        return this.getGeometryBBox();\n    };\n\n    /** @override */\n    IFSlice.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFSlice.GeometryProperties);\n        this._handleVisualChangeForProperties(change, args, IFSlice.VisualProperties);\n        IFItem.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFSlice.prototype._detailHitTest = function (location, transform, tolerance, force) {\n        return new IFItem.HitResult(this);\n    };\n\n    _.IFSlice = IFSlice;\n})(this);"
  },
  {
    "path": "src/infinity/scene/structure/swatch.js",
    "content": "(function (_) {\n    /**\n     * A swatch keeping colors, gradients, etc.\n     * @class IFSwatch\n     * @extends IFNode\n     * @mixes IFNode.Store\n     * @mixes IFNode.Properties\n     * @constructor\n     */\n    function IFSwatch() {\n        IFNode.call(this);\n        this._setDefaultProperties(IFSwatch.VisualProperties, IFSwatch.MetaProperties);\n    }\n\n    IFNode.inheritAndMix('swatch', IFSwatch, IFNode, [IFNode.Store, IFNode.Properties]);\n\n    /**\n     * Visual properties\n     */\n    IFSwatch.VisualProperties = {\n        // The pattern of the swatch (IFPattern)\n        pat: null\n    };\n\n    /**\n     * Meta properties\n     */\n    IFSwatch.MetaProperties = {\n        name: null\n    };\n\n    /** @override */\n    IFSwatch.prototype.getPatternType = function () {\n        return this.$pat ? this.$pat.getPatternType() : null;\n    };\n\n    /** @override */\n    IFSwatch.prototype.store = function (blob) {\n        if (IFNode.Store.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFSwatch.VisualProperties, function (property, value) {\n                if (value) {\n                    if (property === 'pat') {\n                        return IFPattern.asString(value);\n                    }\n                }\n                return value;\n            });\n            this.storeProperties(blob, IFSwatch.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFSwatch.prototype.restore = function (blob) {\n        if (IFNode.Store.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFSwatch.VisualProperties, function (property, value) {\n                if (value) {\n                    if (property === 'pat') {\n                        return IFPattern.parsePattern(value);\n                    }\n                }\n            });\n            this.restoreProperties(blob, IFSwatch.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFSwatch.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFScene.SwatchCollection;\n    };\n\n    _.IFSwatch = IFSwatch;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/appliedstyle.js",
    "content": "(function (_) {\n\n    /**\n     * The applied style class\n     * @class IFAppliedStyle\n     * @extends IFStyle\n     * @constructor\n     */\n    function IFAppliedStyle() {\n        IFStyle.call(this);\n        this._setDefaultProperties(IFAppliedStyle.GeometryProperties, IFAppliedStyle.VisualProperties);\n    }\n\n    IFObject.inherit(IFAppliedStyle, IFStyle);\n\n    /**\n     * The type of a style\n     * @enum\n     */\n    IFAppliedStyle.Type = {\n        /**\n         * Content type - Render contents and effects\n         */\n        Content: 'C',\n\n        /**\n         * Knockout - Applies effects on contents\n         * but doesn't render the contents\n         */\n        Knockout: 'K',\n\n        /**\n         * Mask - Applies effects on contents\n         * and clips background with them\n         */\n        Mask: 'M',\n\n        /**\n         * Background - Applies effects on\n         * backgrounds and clips it with contents\n         */\n        Background: 'B'\n    };\n\n    /**\n     * Geometry properties\n     */\n    IFAppliedStyle.GeometryProperties = {\n        // Whether the style is visible or not\n        vs: true\n    };\n\n    /**\n     * Visual properties\n     */\n    IFAppliedStyle.VisualProperties = {\n        // The type of the style\n        tp: IFAppliedStyle.Type.Content,\n        // The blend mode of the style\n        blm: IFPaintCanvas.BlendMode.Normal,\n        // The opacity of the style\n        opc: 1.0\n    };\n\n    /**\n     * Returns the owner element of this style if any or null\n     * @return {IFElement}\n     */\n    IFAppliedStyle.prototype.getOwnerElement = function () {\n        for (var p = this.getParent(); p !== null; p = p.getParent()) {\n            if (p instanceof IFElement) {\n                return p;\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.prepareGeometryChange = function () {\n        var ownerElement = this.getOwnerElement();\n        if (ownerElement) {\n            ownerElement._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n        }\n        IFStyle.prototype.prepareGeometryChange.call(this);\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.finishGeometryChange = function () {\n        var ownerElement = this.getOwnerElement();\n        if (ownerElement) {\n            ownerElement._notifyChange(IFElement._Change.FinishGeometryUpdate);\n        }\n        IFStyle.prototype.finishGeometryChange.call(this);\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.visualChange = function () {\n        var ownerElement = this.getOwnerElement();\n        if (ownerElement) {\n            ownerElement._notifyChange(IFElement._Change.InvalidationRequest);\n        }\n        IFStyle.prototype.visualChange.call(this);\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.store = function (blob) {\n        if (IFStyle.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFAppliedStyle.GeometryProperties);\n            this.storeProperties(blob, IFAppliedStyle.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.restore = function (blob) {\n        if (IFStyle.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFAppliedStyle.GeometryProperties);\n            this.restoreProperties(blob, IFAppliedStyle.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFStyleSet;\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFAppliedStyle.GeometryProperties);\n        this._handleVisualChangeForProperties(change, args, IFAppliedStyle.VisualProperties);\n        IFStyle.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFAppliedStyle.prototype.toString = function () {\n        return \"[IFAppliedStyle]\";\n    };\n\n    _.IFAppliedStyle = IFAppliedStyle;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/effect/shadoweffect.js",
    "content": "(function (_) {\n\n    /**\n     * A shadow effect\n     * @class IFShadowEffect\n     * @extends IFEffectEntry\n     * @constructor\n     */\n    function IFShadowEffect() {\n        IFEffectEntry.call(this);\n        this._setDefaultProperties(IFShadowEffect.GeometryProperties, IFShadowEffect.VisualProperties);\n    }\n\n    IFNode.inherit('shadowEffect', IFShadowEffect, IFEffectEntry);\n\n    /**\n     * Geometry properties\n     */\n    IFShadowEffect.GeometryProperties = {\n        // Inner shadow or not (drop shadow)\n        in: false,\n        // The radius of the shadow\n        r: 5,\n        // The horizontal shift of the shadow\n        x: 0,\n        // The vertical shift of the shadow\n        y: 0\n    };\n\n    /**\n     * Visual properties\n     */\n    IFShadowEffect.VisualProperties = {\n        // The color of the shadow\n        cls: IFColor.parseCSSColor('rgba(0,0,0,0.5)')\n    };\n\n    /** @override */\n    IFShadowEffect.prototype.getPadding = function () {\n        return [this.$r - this.$x, this.$r - this.$y, this.$r + this.$x, this.$r + this.$y];\n    };\n\n    /** @override */\n    IFShadowEffect.prototype.isPost = function () {\n        return this.$in ? true : false;\n    };\n\n    /** @override */\n    IFShadowEffect.prototype.render = function (canvas, contents, scale) {\n        // Fill our whole canvas with the shadow color\n        canvas.fillCanvas(this.$cls);\n\n        var x = this.$x * scale;\n        var y = this.$y * scale;\n        var r = this.$r * scale;\n\n        // Paint shadow now\n        if (this.$in) {\n            canvas.drawCanvas(contents, x, y, 1, IFPaintCanvas.CompositeOperator.DestinationOut);\n            canvas.getBitmap().blur(r);\n            canvas.drawCanvas(contents, 0, 0, 1, IFPaintCanvas.CompositeOperator.DestinationIn);\n        } else {\n            // Drop shadow\n            canvas.drawCanvas(contents, x, y, 1, IFPaintCanvas.CompositeOperator.DestinationIn);\n            canvas.getBitmap().blur(r);\n        }\n    };\n\n    /** @override */\n    IFShadowEffect.prototype.store = function (blob) {\n        if (IFEffectEntry.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFShadowEffect.GeometryProperties);\n            this.storeProperties(blob, IFShadowEffect.VisualProperties, function (property, value) {\n                if (value) {\n                    if (property === 'cls') {\n                        return value.asString();\n                    }\n                }\n                return value;\n            });\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFShadowEffect.prototype.restore = function (blob) {\n        if (IFEffectEntry.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFShadowEffect.GeometryProperties);\n            this.restoreProperties(blob, IFShadowEffect.VisualProperties, function (property, value) {\n                if (value) {\n                    if (property === 'cls') {\n                        return IFColor.parseColor(value);\n                    }\n                }\n            });\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFShadowEffect.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFShadowEffect.GeometryProperties);\n        this._handleVisualChangeForProperties(change, args, IFShadowEffect.VisualProperties);\n        IFEffectEntry.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFShadowEffect.prototype.toString = function () {\n        return \"[IFShadowEffect]\";\n    };\n\n    _.IFShadowEffect = IFShadowEffect;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/effectentry.js",
    "content": "(function (_) {\n\n    /**\n     * A base for raster effects\n     * @class IFEffectEntry\n     * @extends IFStyleEntry\n     * @constructor\n     */\n    function IFEffectEntry() {\n        IFStyleEntry.call(this);\n    }\n\n    IFObject.inherit(IFEffectEntry, IFStyleEntry);\n\n    /**\n     * Should return whether this filter is applied\n     * *after* contents are rendered (true) or before (false)\n     * @return {boolean}\n     */\n    IFEffectEntry.prototype.isPost = function () {\n        throw new Error(\"Not Supported\");\n    };\n\n    /**\n     * @param {IFPaintCanvas} canvas the target canvas for the effect\n     * @param {IFPaintCanvas} contents the contents the effect is applied on\n     * @param {Number} scale a scale factor you need to multiply your params with\n     */\n    IFEffectEntry.prototype.render = function (canvas, contents, scale) {\n        throw new Error(\"Not Supported\");\n    };\n\n    /** @override */\n    IFEffectEntry.prototype.toString = function () {\n        return \"[IFEffectEntry]\";\n    };\n\n    _.IFEffectEntry = IFEffectEntry;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/filter/blurfilter.js",
    "content": "(function (_) {\n\n    /**\n     * A blur filter\n     * @class IFBlurFilter\n     * @extends IFFilterEntry\n     * @constructor\n     */\n    function IFBlurFilter() {\n        IFFilterEntry.call(this);\n        this._setDefaultProperties(IFBlurFilter.GeometryProperties);\n    }\n\n    IFNode.inherit('blurFilter', IFBlurFilter, IFFilterEntry);\n\n    /**\n     * Geometry properties\n     */\n    IFBlurFilter.GeometryProperties = {\n        // The radius of the blur\n        r: 5\n    };\n\n    /** @override */\n    IFBlurFilter.prototype.getPadding = function () {\n        return [this.$r, this.$r, this.$r, this.$r];\n    };\n\n    /** @override */\n    IFBlurFilter.prototype.apply = function (contents, scale) {\n        contents.getBitmap().blur(this.$r * scale);\n    };\n\n    /** @override */\n    IFBlurFilter.prototype.store = function (blob) {\n        if (IFFilterEntry.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFBlurFilter.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFBlurFilter.prototype.restore = function (blob) {\n        if (IFFilterEntry.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFBlurFilter.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFBlurFilter.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFBlurFilter.GeometryProperties);\n        IFFilterEntry.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFBlurFilter.prototype.toString = function () {\n        return \"[IFBlurFilter]\";\n    };\n\n    _.IFBlurFilter = IFBlurFilter;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/filterentry.js",
    "content": "(function (_) {\n\n    /**\n     * A base for raster filters\n     * @class IFFilterEntry\n     * @extends IFStyleEntry\n     * @constructor\n     */\n    function IFFilterEntry() {\n        IFStyleEntry.call(this);\n    }\n\n    IFObject.inherit(IFFilterEntry, IFStyleEntry);\n\n    /**\n     * @param {IFPaintCanvas} contents the contents canvas to apply the filter onto\n     * @param {Number} scale a scale factor you need to multiply your params with\n     */\n    IFFilterEntry.prototype.apply = function (contents, scale) {\n        throw new Error(\"Not Supported\");\n    };\n\n    /** @override */\n    IFFilterEntry.prototype.toString = function () {\n        return \"[IFFilterEntry]\";\n    };\n\n    _.IFFilterEntry = IFFilterEntry;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/inlinestyle.js",
    "content": "(function (_) {\n\n    /**\n     * The inline style class\n     * @class IFInlineStyle\n     * @extends IFAppliedStyle\n     * @mixes IFNode.Container\n     * @constructor\n     */\n    function IFInlineStyle() {\n        IFAppliedStyle.call(this);\n    }\n\n    IFNode.inheritAndMix('style', IFInlineStyle, IFAppliedStyle, [IFNode.Container]);\n\n    /** @override */\n    IFInlineStyle.prototype.toString = function () {\n        return \"[IFInlineStyle]\";\n    };\n\n    _.IFInlineStyle = IFInlineStyle;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/linkedstyle.js",
    "content": "(function (_) {\n\n    /**\n     * The linked style class\n     * @class IFLinkedStyle\n     * @extends IFAppliedStyle\n     * @constructor\n     */\n    function IFLinkedStyle() {\n        IFAppliedStyle.call(this);\n        this._setDefaultProperties(IFLinkedStyle.GeometryProperties);\n    }\n\n    IFNode.inherit('lnStyle', IFLinkedStyle, IFAppliedStyle);\n\n    /**\n     * Geometry properties\n     */\n    IFLinkedStyle.GeometryProperties = {\n        // The linked style reference id\n        ref: null\n    };\n\n    /** @override */\n    IFLinkedStyle.prototype.getActualStyle = function () {\n        return this.$ref && this.isAttached() ? this.getScene().getReference(this.$ref) : null;\n    };\n\n    /** @override */\n    IFLinkedStyle.prototype.store = function (blob) {\n        if (IFAppliedStyle.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFLinkedStyle.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFLinkedStyle.prototype.restore = function (blob) {\n        if (IFAppliedStyle.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFLinkedStyle.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFLinkedStyle.prototype._handleChange = function (change, args) {\n        if (this._handleGeometryChangeForProperties(change, args, IFLinkedStyle.GeometryProperties)) {\n            if (args.properties.indexOf('ref') >= 0) {\n                var referencedStyle = this.getActualStyle();\n                if (referencedStyle) {\n                    switch (change) {\n                        case IFNode._Change.BeforePropertiesChange:\n                            this.getScene().unlink(referencedStyle, this);\n                            break;\n                        case IFNode._Change.AfterPropertiesChange:\n                            this.getScene().link(referencedStyle, this);\n                            break;\n                    }\n                }\n            }\n        }\n\n        IFAppliedStyle.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFLinkedStyle.prototype._setScene = function (scene) {\n        if (scene !== this._scene) {\n            if (scene) {\n                var referencedStyle = scene.getReference(this.$ref);\n                if (referencedStyle) {\n                    scene.link(referencedStyle, this)\n                }\n            } else {\n                var referencedStyle = this._scene.getReference(this.$ref);\n                if (referencedStyle) {\n                    this._scene.unlink(referencedStyle, this);\n                }\n            }\n        }\n        IFAppliedStyle.prototype._setScene.call(this, scene);\n    };\n\n    /** @override */\n    IFLinkedStyle.prototype.toString = function () {\n        return \"[IFLinkedStyle]\";\n    };\n\n    _.IFLinkedStyle = IFLinkedStyle;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/paint/areapaint.js",
    "content": "(function (_) {\n\n    /**\n     * A base for area pattern painting like fill & stroke\n     * @class IFAreaPaint\n     * @extends IFPatternPaint\n     * @constructor\n     */\n    function IFAreaPaint() {\n        IFPatternPaint.call(this);\n        this._setDefaultProperties(IFAreaPaint.VisualProperties);\n    }\n\n    IFObject.inherit(IFAreaPaint, IFPatternPaint);\n\n    /**\n     * Visual properties\n     */\n    IFAreaPaint.VisualProperties = {\n        // The horizontal translation of the pattern in % (0..1.0)\n        tx: 0,\n        // The horizontal translation of the pattern in % (0..1.0)\n        ty: 0,\n        // The horizontal scalation of the pattern in % (0..1.0)\n        sx: 1,\n        // The vertical scalation of the pattern in % (0..1.0)\n        sy: 1,\n        // The rotation of the pattern in radians\n        rt: 0\n    };\n\n    /** @override */\n    IFAreaPaint.prototype.store = function (blob) {\n        if (IFPatternPaint.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFAreaPaint.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFAreaPaint.prototype.restore = function (blob) {\n        if (IFPatternPaint.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFAreaPaint.VisualProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFAreaPaint.prototype._handleChange = function (change, args) {\n        this._handleVisualChangeForProperties(change, args, IFAreaPaint.VisualProperties);\n        IFPatternPaint.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * This will create a paint pattern and return it\n     * @param {IFPaintCanvas} canvas the canvas used for creating the pattern\n     * @return {*} a paint pattern or null for none\n     * @private\n     */\n    IFAreaPaint.prototype._createPaintPattern = function (canvas) {\n        if (this.$pat) {\n            if (this.$pat instanceof IFColor) {\n                return this.$pat;\n            } else if (this.$pat instanceof IFGradient) {\n                var gradient = null;\n\n                if (this.$pat.getType() === IFGradient.Type.Linear) {\n                    return canvas.createLinearGradient(-0.5, 0, 0.5, 0, this.$pat);\n                } else if (this.$pat.getType() === IFGradient.Type.Radial) {\n                    return canvas.createRadialGradient(0, 0, 0.5, this.$pat);\n                }\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Returns the transformation for painting the pattern\n     * @param {IFRect} bbox the bounding box to be used\n     * @returns {IFTransform} null for no transform or a valid transformation\n     * @private\n     */\n    IFAreaPaint.prototype._getPaintPatternTransform = function (bbox) {\n        if (this.$pat) {\n            if (this.$pat instanceof IFGradient) {\n                    var left = bbox.getX();\n                    var top = bbox.getY();\n                    var width = bbox.getWidth();\n                    var height = bbox.getHeight();\n\n                    return new IFTransform()\n                        .scaled(this.$sx, this.$sy)\n                        .rotated(this.$rt)\n                        .translated(this.$tx, this.$ty)\n                        .scaled(width, height)\n                        .translated(left, top);\n            }\n        }\n\n        return null;\n    };\n\n    /** @override */\n    IFAreaPaint.prototype.toString = function () {\n        return \"[IFAreaPaint]\";\n    };\n\n    _.IFAreaPaint = IFAreaPaint;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/paint/fillpaint.js",
    "content": "(function (_) {\n\n    /**\n     * A fill paint\n     * @class IFFillPaint\n     * @extends IFAreaPaint\n     * @constructor\n     */\n    function IFFillPaint() {\n        IFAreaPaint.call(this);\n    }\n\n    IFNode.inherit('fillPaint', IFFillPaint, IFAreaPaint);\n\n    /** @override */\n    IFFillPaint.prototype.hitTest = function (source, location, transform, tolerance) {\n        var vertexHit = new IFVertexInfo.HitResult();\n        if (ifVertexInfo.hitTest(location.getX(), location.getY(), new IFVertexTransformer(source, transform), tolerance, true, vertexHit)) {\n            return new IFStyle.HitResult(this, vertexHit);\n        }\n        return null;\n    };\n\n    /** @override */\n    IFFillPaint.prototype.paint = function (canvas, bbox) {\n        var pattern = this._createPaintPattern(canvas);\n        if (pattern) {\n            var patternTransform = this._getPaintPatternTransform(bbox);\n            if (patternTransform) {\n                var oldTransform = canvas.setTransform(canvas.getTransform(true).preMultiplied(patternTransform));\n                canvas.fillVertices(pattern, this.$opc, this.$blm);\n                canvas.setTransform(oldTransform);\n            } else {\n                canvas.fillVertices(pattern, this.$opc, this.$blm);\n            }\n        }\n    };\n\n    /** @override */\n    IFFillPaint.prototype.toString = function () {\n        return \"[IFFillPaint]\";\n    };\n\n    _.IFFillPaint = IFFillPaint;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/paint/patternpaint.js",
    "content": "(function (_) {\n\n    /**\n     * A base for pattern painting\n     * @class IFPatternPaint\n     * @extends IFPaintEntry\n     * @constructor\n     */\n    function IFPatternPaint() {\n        IFPaintEntry.call(this);\n        this._setDefaultProperties(IFPatternPaint.VisualProperties);\n    }\n\n    IFObject.inherit(IFPatternPaint, IFPaintEntry);\n\n    /**\n     * Visual properties\n     */\n    IFPatternPaint.VisualProperties = {\n        // Pattern (IFPattern)\n        pat: IFColor.BLACK,\n        // The blend mode of the paint\n        blm: IFPaintCanvas.BlendMode.Normal,\n        // The opacity of the style\n        opc: 1.0\n    };\n\n    /** @override */\n    IFPatternPaint.prototype.getPaintCmpOrBlend = function () {\n        return this.$blm;\n    };\n\n    /** @override */\n    IFPatternPaint.prototype.getPaintOpacity = function () {\n        return this.$opc;\n    };\n\n    /** @override */\n    IFPatternPaint.prototype.store = function (blob) {\n        if (IFPaintEntry.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFPatternPaint.VisualProperties, function (property, value) {\n                if (value) {\n                    if (property === 'pat') {\n                        return IFPattern.asString(value);\n                    }\n                }\n                return value;\n            });\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPatternPaint.prototype.restore = function (blob) {\n        if (IFPaintEntry.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFPatternPaint.VisualProperties, function (property, value) {\n                if (value) {\n                    if (property === 'pat') {\n                        return IFPattern.parsePattern(value);\n                    }\n                }\n                return value;\n            });\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPatternPaint.prototype._handleChange = function (change, args) {\n        this._handleVisualChangeForProperties(change, args, IFPatternPaint.VisualProperties);\n        IFPaintEntry.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFPatternPaint.prototype.toString = function () {\n        return \"[IFPatternPaint]\";\n    };\n\n    _.IFPatternPaint = IFPatternPaint;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/paint/strokepaint.js",
    "content": "(function (_) {\n\n    /**\n     * A stroke paint\n     * @class IFStrokePaint\n     * @extends IFAreaPaint\n     * @constructor\n     */\n    function IFStrokePaint() {\n        IFAreaPaint.call(this);\n        this._setDefaultProperties(IFStrokePaint.GeometryProperties);\n    }\n\n    IFNode.inherit('strokePaint', IFStrokePaint, IFAreaPaint);\n\n    /**\n     * Alignment of a stroke\n     * @enum\n     */\n    IFStrokePaint.Alignment = {\n        /**\n         * Center alignment\n         */\n        Center: 'C',\n\n        /**\n         * Outside alignment\n         */\n        Outside: 'O',\n\n        /**\n         * Inside alignment\n         */\n        Inside: 'I'\n    };\n\n    /**\n     * Geometry properties\n     */\n    IFStrokePaint.GeometryProperties = {\n        // Stroke width\n        sw: 1,\n        // Stroke alignment\n        sa: IFStrokePaint.Alignment.Center,\n        // Stroke Line-Caption\n        slc: IFPaintCanvas.LineCap.Square,\n        // Stroke Line-Join\n        slj: IFPaintCanvas.LineJoin.Miter,\n        // Stroke Line-Miter-Limit\n        slm: 10\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.isSeparate = function () {\n        if (IFAreaPaint.prototype.isSeparate.call(this) === false) {\n            // If we're not having a center-aligned stroke then\n            // we need a separate canvas here\n            if (this.$sa !== IFStrokePaint.Alignment.Center) {\n                return true;\n            }\n\n            // Having a scale of !== 0 always requires a separate canvas\n            return this.$sx !== 1.0 || this.$sy !== 1.0;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.hitTest = function (source, location, transform, tolerance) {\n        var outlineWidth = this.$sw * transform.getScaleFactor() + tolerance * 2;\n        var vertexHit = new IFVertexInfo.HitResult();\n        if (ifVertexInfo.hitTest(location.getX(), location.getY(), new IFVertexTransformer(source, transform), outlineWidth, false, vertexHit)) {\n            return new IFStyle.HitResult(this, vertexHit);\n        }\n        return null;\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.getPadding = function () {\n        // Padding depends on stroke-width and alignment\n        if (this.$sa === IFStrokePaint.Alignment.Center) {\n            var val = this.$sw / 2;\n            return [val, val, val, val];\n        } else if (this.$sa === IFStrokePaint.Alignment.Outside) {\n            return [this.$sw, this.$sw, this.$sw, this.$sw];\n        }\n        return null;\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.paint = function (canvas, bbox) {\n        var strokeBBox = bbox;\n        var padding = this.getPadding();\n\n        if (padding) {\n            strokeBBox = strokeBBox.expanded(padding[0], padding[1], padding[2], padding[3]);\n        }\n\n        var pattern = this._createPaintPattern(canvas);\n        if (pattern) {\n            var patternTransform = this._getPaintPatternTransform(strokeBBox);\n\n            var strokeWidth = this.$sw;\n\n            // Except center alignment we need to double the stroke width\n            // as we're gonna clip half away\n            if (this.$sa !== IFStrokePaint.Alignment.Center) {\n                strokeWidth *= 2;\n            }\n\n            // Stroke vertices now\n            if (patternTransform) {\n                var blendMode = this.$blm;\n                var opacity = this.$opc;\n\n                // If we're on a separate canvas then use the standard opacity and blend mode\n                // as our canvas will be blended in using the given options\n                if (this.isSeparate()) {\n                    blendMode = IFPaintCanvas.BlendMode.Normal;\n                    opacity = 1;\n                }\n\n                // If any scale factor is != 1.0 we need to fill the whole area\n                // and clip our stroke away to ensure stroke width consistency\n                if (this.$sx !== 1.0 || this.$sy !== 1.0) {\n                    // Fill everything with the pattern, first\n                    var oldTransform = canvas.setTransform(canvas.getTransform(true).multiplied(patternTransform));\n                    var patternFillArea = patternTransform.inverted().mapRect(bbox);\n                    canvas.fillRect(patternFillArea.getX(), patternFillArea.getY(), patternFillArea.getWidth(), patternFillArea.getHeight(), pattern);\n                    canvas.setTransform(oldTransform);\n\n                    // Now stroke as regular but use our stroke as mask\n                    canvas.strokeVertices(pattern, strokeWidth, this.$slc, this.$slj, this.$slm, 1, IFPaintCanvas.CompositeOperator.DestinationIn);\n                } else {\n                    var oldTransform = canvas.setTransform(canvas.getTransform(true).multiplied(patternTransform));\n                    canvas.strokeVertices(pattern, strokeWidth / patternTransform.getScaleFactor(), this.$slc, this.$slj, this.$slm, opacity, blendMode);\n                    canvas.setTransform(oldTransform);\n                }\n            } else {\n                canvas.strokeVertices(pattern, strokeWidth, this.$slc, this.$slj, this.$slm, this.$opc, this.$blm);\n            }\n\n            // Depending on the stroke alignment we might need to clip now\n            if (this.$sa === IFStrokePaint.Alignment.Inside) {\n                canvas.fillVertices(IFColor.BLACK, 1, IFPaintCanvas.CompositeOperator.DestinationIn);\n            } else if (this.$sa === IFStrokePaint.Alignment.Outside) {\n                canvas.fillVertices(IFColor.BLACK, 1, IFPaintCanvas.CompositeOperator.DestinationOut);\n            }\n        }\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.store = function (blob) {\n        if (IFAreaPaint.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFStrokePaint.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.restore = function (blob) {\n        if (IFAreaPaint.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFStrokePaint.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFStrokePaint.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFStrokePaint.GeometryProperties);\n        IFAreaPaint.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFStrokePaint.prototype.toString = function () {\n        return \"[IFStrokePaint]\";\n    };\n\n    _.IFStrokePaint = IFStrokePaint;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/paintentry.js",
    "content": "(function (_) {\n\n    /**\n     * A base for vector paintings\n     * @class IFPaintEntry\n     * @extends IFStyleEntry\n     * @constructor\n     */\n    function IFPaintEntry() {\n        IFStyleEntry.call(this);\n    }\n\n    IFObject.inherit(IFPaintEntry, IFStyleEntry);\n\n    /**\n     * Called to test on whether this paint requires to paint\n     * itself on a separate canvas or not\n     * @returns {Boolean}\n     */\n    IFPaintEntry.prototype.isSeparate = function () {\n        return false;\n    };\n\n    /**\n     * Returns the composite or blend mode for this paint\n     * or null if there's none such\n     * @return {IFPaintCanvas.CompositeOperator|IFPaintCanvas.BlendMode}\n     */\n    IFPaintEntry.prototype.getPaintCmpOrBlend = function () {\n        return null;\n    };\n\n    /**\n     * Returns the opacity for this paint or null if there's none such\n     * @return {Number}\n     */\n    IFPaintEntry.prototype.getPaintOpacity = function () {\n        return null;\n    };\n\n    /**\n     * Called whenever a hit-test should be made on this paint entry.\n     * @parma {IFVertexSource} source the vertice source\n     * @param {IFPoint} location the position to trigger the hit test at\n     * in transformed view coordinates (see transform parameter)\n     * @param {IFTransform} transform the transformation of the scene\n     * or null if there's none\n     * @param {Number} tolerance a tolerance value for hit testing in view coordinates\n     * @returns {IFStyle.HitResult} the hit result or null for none\n     */\n    IFPaintEntry.prototype.hitTest = function (source, location, transform, tolerance) {\n        return null;\n    };\n\n    /**\n     * Called to paint. Note that the given canvas is already\n     * pre-filled with the given vertex source.\n     * @param {IFPaintCanvas} canvas the canvas used for painting\n     * @param {IFRect} bbox the bbox used for painting\n     */\n    IFPaintEntry.prototype.paint = function (canvas, bbox) {\n        throw new Error(\"Not Supported\");\n    };\n\n    /** @override */\n    IFPaintEntry.prototype.toString = function () {\n        return \"[IFPaintEntry]\";\n    };\n\n    _.IFPaintEntry = IFPaintEntry;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/sharedstyle.js",
    "content": "(function (_) {\n\n    /**\n     * The shared style class\n     * @class IFSharedStyle\n     * @extends IFStyle\n     * @mixes IFNode.Container\n     * @mixes IFNode.Reference\n     * @constructor\n     */\n    function IFSharedStyle() {\n        IFStyle.call(this);\n        this._setDefaultProperties(IFSharedStyle.MetaProperties);\n    }\n\n    IFNode.inheritAndMix('sharedStyle', IFSharedStyle, IFStyle, [IFNode.Container, IFNode.Reference]);\n\n    /**\n     * The meta properties of a shared style with their default values\n     */\n    IFSharedStyle.MetaProperties = {\n        name: null\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.prepareGeometryChange = function () {\n        var scene = this.getScene();\n        if (scene) {\n            scene.visitLinks(this, function (link) {\n                if (link instanceof IFStyle) {\n                    link.prepareGeometryChange();\n                }\n            });\n        }\n        IFStyle.prototype.prepareGeometryChange.call(this);\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.finishGeometryChange = function () {\n        var scene = this.getScene();\n        if (scene) {\n            scene.visitLinks(this, function (link) {\n                if (link instanceof IFStyle) {\n                    link.finishGeometryChange();\n                }\n            });\n        }\n        IFStyle.prototype.finishGeometryChange.call(this);\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.visualChange = function () {\n        var scene = this.getScene();\n        if (scene) {\n            scene.visitLinks(this, function (link) {\n                if (link instanceof IFStyle) {\n                    link.visualChange();\n                }\n            });\n        }\n        IFStyle.prototype.visualChange.call(this);\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.store = function (blob) {\n        if (IFStyle.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFSharedStyle.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.restore = function (blob) {\n        if (IFStyle.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFSharedStyle.MetaProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFScene.StyleCollection;\n    };\n\n    /** @override */\n    IFSharedStyle.prototype.toString = function () {\n        return \"[IFSharedStyle]\";\n    };\n\n    _.IFSharedStyle = IFSharedStyle;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/style.js",
    "content": "(function (_) {\n    var PREVIEW_CHESSBOARD_FILL = null;\n\n    /**\n     * Base style class\n     * @class IFStyle\n     * @extends IFNode\n     * @mixes IFNode.Store\n     * @mixes IFNode.Properties\n     * @constructor\n     */\n    function IFStyle() {\n        IFNode.call(this);\n    }\n\n    IFObject.inheritAndMix(IFStyle, IFNode, [IFNode.Store, IFNode.Properties]);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFStyle.StyleChangeEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for a style change notification sent via a scene\n     * @param {IFStyle} style the style that has changed\n     * @class IFStyle.StyleChangeEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFStyle.StyleChangeEvent = function (style) {\n        this.style = style;\n    };\n    IFObject.inherit(IFStyle.StyleChangeEvent, GEvent);\n\n    /**\n     * The style that has been changed\n     * @type IFStyle\n     */\n    IFStyle.StyleChangeEvent.prototype.style = null;\n\n    /** @override */\n    IFStyle.StyleChangeEvent.prototype.toString = function () {\n        return \"[Event IFStyle.StyleChangeEvent]\";\n    };    \n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFStyle.HitResult Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A hit result on a style\n     * @param {IFStyleEntry} entry the style entry that had been hit\n     * @param {*} args - other hit-test data\n     * @constructor\n     * @class IFStyle.HitResult\n     */\n    IFStyle.HitResult = function (entry, args) {\n        this.entry = entry;\n        this.data = args;\n    };\n\n    /**\n     * The style entry that had been hit\n     * @type {IFStyleEntry}\n     */\n    IFStyle.HitResult.prototype.entry = null;\n\n    /**\n     * Additional hit-test data\n     * @type {*}\n     */\n    IFStyle.HitResult.prototype.data = null;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFStyle Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Returns the actual style. You should always use this one to act on the style\n     * when reading something from it. Note that this should always return a style\n     * with a container.\n     * @param {IFStyle}\n     */\n    IFStyle.prototype.getActualStyle = function () {\n        return this;\n    };\n\n    /**\n     * Creates a preview image of this canvas\n     * @param {Number} width the width of the preview\n     * @param {Number} height the height of the preview\n     * @return {String} a base64-encoded image data url with the preview\n     */\n    IFStyle.prototype.createPreviewImage = function (width, height) {\n        // Create a temporary rectangle shape for preview painting\n        var previewRect = new IFRectangle();\n        previewRect.setProperty('trf', new IFTransform(width / 2, 0, 0, height / 2, width / 2, height / 2));\n\n        // Setup canvas and context for painting\n        var canvas = new IFPaintCanvas();\n        canvas.resize(width, height);\n        canvas.prepare();\n        var context = new IFPaintContext();\n        context.canvas = canvas;\n        context.configuration = new IFScenePaintConfiguration();\n\n        // Paint transparent background\n        if (!PREVIEW_CHESSBOARD_FILL) {\n            PREVIEW_CHESSBOARD_FILL = IFPaintCanvas.createChessboard(4, 'white', 'rgb(185, 185, 185)');\n        }\n        context.canvas.fillRect(0, 0, width, height, context.canvas.createTexture(PREVIEW_CHESSBOARD_FILL));\n\n        // Calculate real bounding box\n        var bbox = this.getBBox(new IFRect(0, 0, width, height));\n\n        // Transform canvas to fit bounding box exactly\n        var bboxCenter = bbox.getSide(IFRect.Side.CENTER);\n        var realCenter = new IFPoint(width / 2, height / 2);\n        var scaleX = 1.0 / (bbox.getWidth() / width);\n        var scaleY = 1.0 / (bbox.getHeight() / height);\n        var matrix = new IFTransform()\n            .translated(-bboxCenter.getX(), -bboxCenter.getY())\n            .scaled(scaleX, scaleY)\n            .translated(realCenter.getX(), realCenter.getY())\n            .getMatrix();\n\n        canvas.setOrigin(new IFPoint(-matrix[4], -matrix[5]));\n        canvas.setScale(scaleX);\n\n        // Paint rectangle with this style\n        previewRect.renderStyle(context, this);\n\n        return canvas.asPNGImage();\n    };\n\n    /**\n     * Returns the bounding box of the style. This includes only\n     * visible style entries\n     * @param {IFRect} source the source bbox\n     * @returns {IFRect}\n     */\n    IFStyle.prototype.getBBox = function (source) {\n        var vEffectPadding = [0, 0, 0, 0];\n        var filterPadding = [0, 0, 0, 0];\n        var effectPadding = [0, 0, 0, 0];\n        var paintPadding = [0, 0, 0, 0];\n\n        for (var child = this.getActualStyle().getFirstChild(); child !== null; child = child.getNext()) {\n            if (child instanceof IFStyleEntry && child.getProperty('vs') === true) {\n                var padding = child.getPadding();\n                if (padding) {\n                    if (child instanceof IFVEffectEntry) {\n                        // vEffects are additive\n                        vEffectPadding = [\n                            vEffectPadding[0] + padding[0],\n                            vEffectPadding[1] + padding[1],\n                            vEffectPadding[2] + padding[2],\n                            vEffectPadding[3] + padding[3]\n                        ];\n                    } else if (child instanceof IFFilterEntry) {\n                        // filters always sum up\n                        filterPadding = [\n                            filterPadding[0] + Math.abs(padding[0]),\n                            filterPadding[1] + Math.abs(padding[1]),\n                            filterPadding[2] + Math.abs(padding[2]),\n                            filterPadding[3] + Math.abs(padding[3])\n                        ];\n                    } else if (child instanceof IFEffectEntry) {\n                        // effects approximate the largest\n                        effectPadding = [\n                            Math.max(effectPadding[0], padding[0]),\n                            Math.max(effectPadding[1], padding[1]),\n                            Math.max(effectPadding[2], padding[2]),\n                            Math.max(effectPadding[3], padding[3])\n                        ];\n                    } else if (child instanceof IFPaintEntry) {\n                        // paints approximate the largest\n                        paintPadding = [\n                            Math.max(paintPadding[0], padding[0]),\n                            Math.max(paintPadding[1], padding[1]),\n                            Math.max(paintPadding[2], padding[2]),\n                            Math.max(paintPadding[3], padding[3])\n                        ];\n                    } else {\n                        throw new Error('Unknown entry with padding.');\n                    }\n                }\n            }\n        }\n\n        var bbox = source.expanded(\n            vEffectPadding[0] + paintPadding[0] + filterPadding[0] + effectPadding[0],\n            vEffectPadding[1] + paintPadding[1] + filterPadding[1] + effectPadding[1],\n            vEffectPadding[2] + paintPadding[2] + filterPadding[2] + effectPadding[2],\n            vEffectPadding[3] + paintPadding[3] + filterPadding[3] + effectPadding[3]\n        );\n\n        // Due to pixel aligning, we may need extra half pixel in some cases\n        var paintExtraExpand = [0, 0, 0, 0];\n        if (bbox.getX() != Math.floor(bbox.getX())) {\n            paintExtraExpand[0] = 0.5;\n        }\n        if (bbox.getY() != Math.floor(bbox.getY())) {\n            paintExtraExpand[1] = 0.5;\n        }\n        var br = bbox.getSide(IFRect.Side.BOTTOM_RIGHT);\n        if (br.getX() != Math.ceil(br.getX())) {\n            paintExtraExpand[2] = 0.5;\n        }\n        if (br.getY() != Math.ceil(br.getY())) {\n            paintExtraExpand[3] = 0.5;\n        }\n        return bbox.expanded(paintExtraExpand[0], paintExtraExpand[1], paintExtraExpand[2], paintExtraExpand[3]);\n    };\n\n    /**\n     * Creates a vertex source based on a source and any potential\n     * (visible) vector effects within this style\n     * @param {IFVertexSource} source\n     * @return {IFVertexSource}\n     */\n    IFStyle.prototype.createVertexSource = function (source) {\n        for (var entry = this.getActualStyle().getFirstChild(); entry !== null; entry = entry.getNext()) {\n            if (entry instanceof IFVEffectEntry && entry.getProperty('vs') === true) {\n                source = entry.createEffect(source);\n            }\n        }\n        return source;\n    };\n\n    /**\n     * Called whenever a hit-test should be made on this style. Only\n     * paint style entries can be hit. Note that if there're any vector\n     * effects in this style, they're applied to the source before hit-\n     * testing takes place. Goes from top-to-bottom.\n     * @parma {IFVertexSource} source the vertice source\n     * @param {IFPoint} location the position to trigger the hit test at\n     * in transformed view coordinates (see transform parameter)\n     * @param {IFTransform} transform the transformation of the scene\n     * or null if there's none\n     * @param {Number} tolerance a tolerance value for hit testing in view coordinates\n     * @returns {IFStyle.HitResult} the hit result or null for none\n     */\n    IFStyle.prototype.hitTest = function (source, location, transform, tolerance) {\n        // Make sure to get a transformed / effected source\n        source = this.createVertexSource(source);\n\n        // Hit test our children now\n        for (var entry = this.getActualStyle().getLastChild(); entry !== null; entry = entry.getPrevious()) {\n            if (entry instanceof IFPaintEntry && entry.getProperty('vs') === true) {\n                var result = entry.hitTest(source, location, transform, tolerance);\n                if (result) {\n                    return result;\n                }\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Called to prepare this style for a geometrical change\n     */\n    IFStyle.prototype.prepareGeometryChange = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called to finish this style from a geometrical change\n     */\n    IFStyle.prototype.finishGeometryChange = function () {\n        if (this._canEventBeSend(IFStyle.StyleChangeEvent)) {\n            this._scene.trigger(new IFStyle.StyleChangeEvent(this));\n        }\n    };\n\n    /**\n     * Called to trigger a visual change on this style\n     */\n    IFStyle.prototype.visualChange = function () {\n        if (this._canEventBeSend(IFStyle.StyleChangeEvent)) {\n            this._scene.trigger(new IFStyle.StyleChangeEvent(this));\n        }\n    };\n\n    /** @override */\n    IFStyle.prototype.validateInsertion = function (parent, reference) {\n        return false;\n    };\n\n    /** @override */\n    IFStyle.prototype._handleChange = function (change, args) {\n        if (change == IFNode._Change.BeforeChildInsert || change === IFNode._Change.BeforeChildRemove) {\n            if (args instanceof IFStyleEntry) {\n                this.prepareGeometryChange();\n            }\n        } else if (change == IFNode._Change.AfterChildInsert || change === IFNode._Change.AfterChildRemove) {\n            if (args instanceof IFStyleEntry) {\n                this.finishGeometryChange();\n            }\n        }\n\n        IFNode.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * This will fire a change event for geometry updates on this style\n     * whenever a given property has been changed that affected the geometry.\n     * This is usually called from the _handleChange function.\n     * @param {Number} change\n     * @param {Object} args\n     * @param {Object} properties a hashmap of properties that satisfy for\n     * geometrical changes\n     * @return {Boolean} true if there was a property change that affected a\n     * change of the geometry and was handled (false i.e. for no owner element)\n     * @private\n     */\n    IFStyle.prototype._handleGeometryChangeForProperties = function (change, args, properties) {\n        if (change == IFNode._Change.BeforePropertiesChange || change == IFNode._Change.AfterPropertiesChange) {\n            if (ifUtil.containsObjectKey(args.properties, properties)) {\n                switch (change) {\n                    case IFNode._Change.BeforePropertiesChange:\n                        this.prepareGeometryChange();\n                        break;\n                    case IFNode._Change.AfterPropertiesChange:\n                        this.finishGeometryChange();\n                        break;\n                }\n                return true;\n            }\n        }\n        return false;\n    };\n\n    /**\n     * This will fire an invalidation event for visual updates on this style\n     * whenever a given property has been changed that affected the visual.\n     * This is usually called from the _handleChange function.\n     * @param {Number} change\n     * @param {Object} args\n     * @param {Object} properties a hashmap of properties that satisfy for\n     * visual changes\n     * @return {Boolean} true if there was a property change that affected a\n     * visual change and was handled (false i.e. for no owner element)\n     * @private\n     */\n    IFStyle.prototype._handleVisualChangeForProperties = function (change, args, properties) {\n        if (change == IFNode._Change.AfterPropertiesChange) {\n            if (ifUtil.containsObjectKey(args.properties, properties)) {\n                this.visualChange();\n                return true;\n            }\n        }\n        return false;\n    };\n\n    /** @override */\n    IFStyle.prototype.toString = function () {\n        return \"[IFStyle]\";\n    };\n\n    _.IFStyle = IFStyle;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/styleentry.js",
    "content": "(function (_) {\n\n    /**\n     * A base style entry class\n     * @class IFStyleEntry\n     * @extends IFNode\n     * @mixes IFNode.Store\n     * @mixes IFNode.Properties\n     * @constructor\n     */\n    function IFStyleEntry() {\n        IFNode.call(this);\n        this._setDefaultProperties(IFStyleEntry.GeometryProperties);\n    }\n\n    IFObject.inheritAndMix(IFStyleEntry, IFNode, [IFNode.Store, IFNode.Properties]);\n\n    /**\n     * Visual properties\n     */\n    IFStyleEntry.GeometryProperties = {\n        // Whether the node is visible or not\n        vs: true\n    };\n\n    /** @override */\n    IFStyleEntry.prototype.store = function (blob) {\n        if (IFNode.Store.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFStyleEntry.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFStyleEntry.prototype.restore = function (blob) {\n        if (IFNode.Store.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFStyleEntry.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /**\n     * If the style extends the paint area it should\n     * return the padding extensions here: [left, top, right, bottom]\n     * @returns {Array<Number>}\n     */\n    IFStyleEntry.prototype.getPadding = function () {\n        return null;\n    };\n\n    /** @override */\n    IFStyleEntry.prototype.validateInsertion = function (parent, reference) {\n        return parent instanceof IFStyle;\n    };\n\n    /** @override */\n    IFStyleEntry.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFStyleEntry.GeometryProperties);\n        IFNode.prototype._handleChange.call(this, change, args);\n    };\n\n    /**\n     * This will fire a change event for geometry updates on the owner style\n     * whenever a given property has been changed that affected the geometry.\n     * This is usually called from the _handleChange function.\n     * @param {Number} change\n     * @param {Object} args\n     * @param {Object} properties a hashmap of properties that satisfy for\n     * geometrical changes\n     * @return {Boolean} true if there was a property change that affected a\n     * change of the geometry and was handled (false i.e. for no owner element)\n     * @private\n     */\n    IFStyleEntry.prototype._handleGeometryChangeForProperties = function (change, args, properties) {\n        if (change == IFNode._Change.BeforePropertiesChange || change == IFNode._Change.AfterPropertiesChange) {\n            var style = this.getOwnerStyle();\n            if (style) {\n                if (ifUtil.containsObjectKey(args.properties, properties)) {\n                    switch (change) {\n                        case IFNode._Change.BeforePropertiesChange:\n                            style.prepareGeometryChange();\n                            break;\n                        case IFNode._Change.AfterPropertiesChange:\n                            style.finishGeometryChange();\n                            break;\n                    }\n                    return true;\n                }\n            }\n            return false;\n        }\n        return false;\n    };\n\n    /**\n     * This will fire an invalidation event for visual updates on the owner style\n     * whenever a given property has been changed that affected the visual.\n     * This is usually called from the _handleChange function.\n     * @param {Number} change\n     * @param {Object} args\n     * @param {Object} properties a hashmap of properties that satisfy for\n     * visual changes\n     * @return {Boolean} true if there was a property change that affected a\n     * visual change and was handled (false i.e. for no owner element)\n     * @private\n     */\n    IFStyleEntry.prototype._handleVisualChangeForProperties = function (change, args, properties) {\n        if (change == IFNode._Change.AfterPropertiesChange) {\n            var style = this.getOwnerStyle();\n            if (style) {\n                if (ifUtil.containsObjectKey(args.properties, properties)) {\n                    style.visualChange();\n                    return true;\n                }\n            }\n            return false;\n        }\n        return false;\n    };\n\n    /**\n     * Returns the owner style if any or null\n     * @returns {IFStyle}\n     */\n    IFStyleEntry.prototype.getOwnerStyle = function () {\n        var parent = this.getParent();\n        return parent && parent instanceof IFStyle ? parent : null;\n    };\n\n    /** @override */\n    IFStyleEntry.prototype.toString = function () {\n        return \"[IFStyleEntry]\";\n    };\n\n    _.IFStyleEntry = IFStyleEntry;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/styleset.js",
    "content": "(function (_) {\n\n    /**\n     * A set of styles appended to elements\n     * @class IFStyleSet\n     * @extends IFNode\n     * @mixes IFNode.Container\n     * @mixes IFNode.Store\n     * @constructor\n     */\n    function IFStyleSet() {\n        IFNode.call(this);\n    }\n\n    IFObject.inheritAndMix(IFStyleSet, IFNode, [IFNode.Container, IFNode.Store]);\n\n    /**\n     * Returns the bounding box of the styleSet which is\n     * the union of all visible style's bboxes\n     * @param {IFRect} source the source bbox\n     * @returns {IFRect}\n     */\n    IFStyleSet.prototype.getBBox = function (source) {\n        var result = source;\n        for (var node = this.getFirstChild(); node != null; node = node.getNext()) {\n            if (node instanceof IFStyle && node.getProperty('vs') === true) {\n                var childBBox = node.getBBox(source);\n                if (childBBox && !childBBox.isEmpty()) {\n                    result = result.united(childBBox);\n                }\n            }\n        }\n        return result;\n    };\n\n    /**\n     * Makes a hit-test on each visible style until a hit was found.\n     * Goes from top-to-bottom.\n     * @parma {IFVertexSource} source\n     * @param {IFPoint} location\n     * @param {IFTransform} transform\n     * @param {Number} tolerance\n     * @returns {IFStyle.HitResult}\n     * @see IFStyle.hitTest\n     */\n    IFStyleSet.prototype.hitTest = function (source, location, transform, tolerance) {\n        for (var node = this.getLastChild(); node !== null; node = node.getPrevious()) {\n            if (node instanceof IFStyle && node.getProperty('vs') === true) {\n                var result = node.hitTest(source, location, transform, tolerance);\n                if (result) {\n                    return result;\n                }\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    IFStyleSet.prototype._handleChange = function (change, args) {\n        var parent = this.getParent();\n        if (parent) {\n            if (change == IFNode._Change.BeforeChildInsert || change === IFNode._Change.BeforeChildRemove) {\n                if (args instanceof IFStyle) {\n                    parent._notifyChange(IFElement._Change.PrepareGeometryUpdate);\n                }\n            } else if (change == IFNode._Change.AfterChildInsert || change === IFNode._Change.AfterChildRemove) {\n                if (args instanceof IFStyle) {\n                    parent._notifyChange(IFElement._Change.FinishGeometryUpdate);\n                }\n            }\n        }\n\n        IFNode.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFStyleSet.prototype.toString = function () {\n        return \"[IFStyleSet]\";\n    };\n\n    _.IFStyleSet = IFStyleSet;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/veffect/offsetveffect.js",
    "content": "(function (_) {\n\n    /**\n     * A vector effect for offsetting\n     * @class IFOffsetVEffect\n     * @extends IFVEffectEntry\n     * @constructor\n     */\n    function IFOffsetVEffect() {\n        IFVEffectEntry.call(this);\n        this._setDefaultProperties(IFOffsetVEffect.GeometryProperties);\n    }\n\n    IFNode.inheritAndMix('offsetVEffect', IFOffsetVEffect, IFVEffectEntry);\n\n    /**\n     * Type of offset\n     * @enum\n     */\n    IFOffsetVEffect.OffsetType = {\n        Inset: 'i',\n        Outset:' o',\n        Both: 'b'\n    };\n\n    /**\n     * Geometry properties\n     */\n    IFOffsetVEffect.GeometryProperties = {\n        // Offset-Type\n        tp: IFOffsetVEffect.OffsetType.Outset,\n        // The offset radius\n        r: 5\n    };\n\n    /** @override */\n    IFOffsetVEffect.prototype.getPadding = function () {\n        if (this.$r > 0) {\n            // TODO : Right now we don't know whether we'll expand or inset as this depends\n            // on our path's direction so we'll always expand by default to cover any case\n            //var val = this.$tp === IFOffsetVEffect.OffsetType.Inset ? -this.$r : this.$r;\n            var val = this.$r;\n            return [val, val, val, val];\n        }\n        return null;\n    };\n\n    /** @override */\n    IFOffsetVEffect.prototype.createEffect = function (source) {\n        if (this.$r > 0) {\n            return new IFVertexOffsetter(\n                source,\n                this.$r,\n                this.$tp === IFOffsetVEffect.OffsetType.Inset || this.$tp === IFOffsetVEffect.OffsetType.Both,\n                this.$tp === IFOffsetVEffect.OffsetType.Outset || this.$tp === IFOffsetVEffect.OffsetType.Both\n            );\n        }\n        return source;\n    };\n\n    /** @override */\n    IFOffsetVEffect.prototype.store = function (blob) {\n        if (IFVEffectEntry.prototype.store.call(this, blob)) {\n            this.storeProperties(blob, IFOffsetVEffect.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFOffsetVEffect.prototype.restore = function (blob) {\n        if (IFVEffectEntry.prototype.restore.call(this, blob)) {\n            this.restoreProperties(blob, IFOffsetVEffect.GeometryProperties);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFOffsetVEffect.prototype._handleChange = function (change, args) {\n        this._handleGeometryChangeForProperties(change, args, IFOffsetVEffect.GeometryProperties);\n        IFVEffectEntry.prototype._handleChange.call(this, change, args);\n    };\n\n    /** @override */\n    IFOffsetVEffect.prototype.toString = function () {\n        return \"[IFOffsetVEffect]\";\n    };\n\n    _.IFOffsetVEffect = IFOffsetVEffect;\n})(this);"
  },
  {
    "path": "src/infinity/scene/style/veffectentry.js",
    "content": "(function (_) {\n\n    /**\n     * A base for vector effects\n     * @class IFVEffectEntry\n     * @extends IFStyleEntry\n     * @constructor\n     */\n    function IFVEffectEntry() {\n        IFStyleEntry.call(this);\n    }\n\n    IFObject.inherit(IFVEffectEntry, IFStyleEntry);\n\n    /**\n     * @param {IFVertexSource} source the source vertices this\n     * filter should be applied to\n     * @return {IFVertexSource} a new vertex source with the\n     * vector effect applied\n     */\n    IFVEffectEntry.prototype.createEffect = function (source) {\n        throw new Error(\"Not Supported\");\n    };\n\n    /** @override */\n    IFVEffectEntry.prototype.toString = function () {\n        return \"[IFVEffectEntry]\";\n    };\n\n    _.IFVEffectEntry = IFVEffectEntry;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertex.js",
    "content": "(function (_) {\n\n    /**\n     * A vertex class\n     * @class IFVertex\n     * @constructor\n     * @version 1.0\n     */\n    function IFVertex() {\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFVertex.Command\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A list of vertex commands\n     * @see IFVertex.verticeCount\n     */\n    IFVertex.Command = {\n        /**\n         * A move command\n         * Vertices: [x,y=point]\n         * @type {Number}\n         */\n        Move: 1,\n\n        /**\n         * A line command\n         * Vertices: [x,y=point]\n         * @type {Number}\n         */\n        Line: 2,\n\n        /**\n         * A quadtratic bezier curve command (one control point)\n         * Vertices: [x,y=point] [ x,y=control point]\n         * @type {Number}\n         */\n        Curve: 3,\n\n        /**\n         * A bezier curve command (two control points)\n         * Vertices: [x,y=point] [x,y=control point #1] [x,y=control point #2]\n         * @type {Number}\n         */\n        Curve2: 4,\n\n        /**\n         * A close command\n         * Vertices: none\n         * @type {Number}\n         */\n        Close: 5\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFVertex Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * The command of the vertex\n     * @type {Number}\n     */\n    IFVertex.prototype.command = null;\n\n    /**\n     * The x-coordinate of the vertex\n     * @type {Number}\n     */\n    IFVertex.prototype.x = null;\n\n    /**\n     * The y-coordinate of the vertex\n     * @type {Number}\n     */\n    IFVertex.prototype.y = null;\n\n    _.IFVertex = IFVertex;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertexcontainer.js",
    "content": "(function (_) {\n\n    /**\n     * A container for vertices\n     * @class IFVertexContainer\n     * @mixes IFVertexSource\n     * @mixes IFVertexTarget\n     * @constructor\n     */\n    function IFVertexContainer() {\n        this._vertices = [];\n    }\n\n    IFObject.mix(IFVertexContainer, [IFVertexSource, IFVertexTarget]);\n\n    /**\n     * @type {number}\n     * @private\n     */\n    IFVertexContainer.prototype._index = 0;\n\n    /**\n     * @type {Array{{c:Number, x:Number, y:Nuber}}}\n     * @private\n     */\n    IFVertexContainer.prototype._vertices = null;\n\n    /** @override */\n    IFVertexContainer.prototype.addVertex = function (command, x, y) {\n        this._vertices.push({\n            c : command,\n            x : x,\n            y : y\n        });\n        this._index = this._vertices.length + 1;;\n    };\n\n    /** @override */\n    IFVertexContainer.prototype.clearVertices = function () {\n        this._vertices = [];\n    };\n\n    /**\n     * Transform all vertices in this container with a given matrix\n     * @param {IFTransform} transform\n     */\n    IFVertexContainer.prototype.transformVertices = function (transform) {\n        for (var i = 0; i < this._vertices.length; ++i) {\n            transform.map(this._vertices[i]);\n        }\n    };\n\n    /**\n     * @returns {Number} the total number of vertices in this container\n     * @version 1.0\n     */\n    IFVertexContainer.prototype.getCount = function () {\n        return this._vertices.length;\n    };\n\n    /** @override */\n    IFVertexContainer.prototype.rewindVertices = function (index) {\n        if (index >= 0 && index <= this._vertices.length) {\n            this._index = index;\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFVertexContainer.prototype.readVertex = function (vertex) {\n        if (this._index >= 0 && this._index < this._vertices.length) {\n            var v = this._vertices[this._index];\n            vertex.command = v.c;\n            vertex.x = v.x;\n            vertex.y = v.y;\n            this._index++;\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFVertexContainer.prototype.toString = function () {\n        return \"[Object IFVertexContainer]\";\n    };\n\n    _.IFVertexContainer = IFVertexContainer;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertexinfo.js",
    "content": "(function (_) {\n\n    /**\n     * Static vertex information collector used for bbox calc, hit-test etc.\n     * @class IFVertexInfo\n     * @version 1.0\n     * @constructor\n     */\n    function IFVertexInfo() {\n    }\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFVertexInfo.HitResult Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A class to keep the result of a hit test\n     * @class IFVertexInfo.HitResult\n     * @constructor\n     * @version 1.0\n     */\n    IFVertexInfo.HitResult = function () {\n    };\n\n    /**\n     * Defines the index of the segment that\n     * has been hit\n     * @type {Number}\n     * @version 1.0\n     */\n    IFVertexInfo.HitResult.prototype.segment = null;\n\n    /**\n     * Defines the exact x-coordinate of the\n     * hit within the segment that was hit. The\n     * coordinate will always be on the exact\n     * outline no matter of the outline width\n     * or alignment.\n     * @type {Number}\n     * @version 1.0\n     */\n    IFVertexInfo.HitResult.prototype.x = null;\n\n    /**\n     * Defines the exact y-coordinate of the\n     * hit within the segment that was hit. The\n     * coordinate will always be on the exact\n     * outline no matter of the outline width\n     * or alignment.\n     * @type {Number}\n     * @version 1.0\n     */\n    IFVertexInfo.HitResult.prototype.y = null;\n\n    /**\n     * Defines the slope of the hit within\n     * the segment that was hit\n     * @type {Number}\n     * @version 1.0\n     */\n    IFVertexInfo.HitResult.prototype.slope = null;\n\n    /**\n     * Defines whether the hit is on the outline\n     * or not (which means it is on the area)\n     * @type {Boolean}\n     * @version 1.0\n     */\n    IFVertexInfo.HitResult.prototype.outline = null;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFVertexInfo Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * Tests if a point is on the segment stroke.\n     * Calculate distance using this approach:\n     * http://msdn.microsoft.com/en-us/library/ms969920.aspx\n     * @param {Number} px1 the x-position of the segment start point\n     * @param {Number} py1 the y-position of the segment start point\n     * @param {Number} px2 the x-position of the segment end point\n     * @param {Number} py2 the y-position of the segment end point\n     * @param {Number} x the x-position of the point to test\n     * @param {Number} y the y-position of the point to test\n     * @param {Number} sqrOutline squared half-width of stroke\n     * @param {Number} chainIdx an index of the segment in the path to be written into result, when segment is hit\n     * @param {IFVertexInfo.HitResult} result if the function returns true, means\n     * a hit was found then this is the result structure that will be filled\n     * with the hit information\n\n     * @return {Boolean} true, if a point is on the stroke\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._hitTestSegment = function (px1, py1, px2, py2, x, y, sqrOutline, chainIdx, result) {\n        // ptMin[0] for [a, b]: 0 - min dist in a; 1 - min dist in b; 0 < t < 1- min dist in a+t*(b-a) ==\n        var ptMin = [];\n        var sqrDst = ifMath.sqrSegmentDist(px1, py1, px2, py2, x, y, ptMin, sqrOutline);\n\n        if (sqrDst <= sqrOutline) {\n            // Fill result\n            if (result) {\n                result.segment = chainIdx;\n                result.x = px1 + ptMin[0] * (px2 - px1);\n                result.y = py1 + ptMin[0] * (py2 - py1);\n                result.slope = ptMin[0];\n                result.outline = true;\n            }\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Tests if a point is on the quadratic Bezier curve stroke.\n     * Polynomial equation of 3d degree is solved to find the minimal distance from point to curve.\n     * @param {Number} px1 the x-position of the curve start point\n     * @param {Number} py1 the y-position of the curve start point\n     * @param {Number} px2 the x-position of the curve end point\n     * @param {Number} py2 the y-position of the curve end point\n     * @param {Number} cx the x-position of the control point\n     * @param {Number} cy the y-position of the control point\n     * @param {Number} x the x-position of the point to test\n     * @param {Number} y the y-position of the point to test\n     * @param {Number} sqrOutline squared half-width of stroke\n     * @param {Number} chainIdx an index of the curve in the path to be written into result, when curve is hit\n     * @param {IFVertexInfo.HitResult} result if the function returns true, means\n     * a hit was found then this is the result structure that will be filled\n     * with the hit information\n\n     * @return {Boolean} true, if a point is on the stroke\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._hitTestCurve = function (px1, py1, px2, py2, cx, cy, x, y, sqrOutline, chainIdx, result) {\n        // The first and the second quadratic curve coefficients for P(t)x and P(t)y\n        var ax, ay, bx, by;\n\n        // Squared distances to curve convex hull segments\n        var d1, d2, d3;\n        var ptMin = []; // ptMin[0] for [a, b]: 0 - min dist in a; 1 - min dist in b; 0 < t < 1- min dist in a+t*(b-a)\n\n        // Coefficients of 4th degree distance polynomial\n        var coeffF = new Float64Array(5);\n\n        // Coefficients of derivative polynomial\n        var coeffG = new Float64Array(4);\n        var b, c, d;\n\n        // Roots of derivative polynomial and their number\n        var gRoots = [];\n        var gRootsN;\n\n        // Accuracy of roots calculation\n        var acc = 1e-6;\n\n        // Flags used for analysis of point and curve pience relative position\n        var hitPossible = false;\n        var insideFlag = true;\n\n        // Minimal distance from point to curve\n        var min;\n        // Index of distance minimizing point in the array of derivative polynomial roots\n        var hitPtIdx;\n\n        // Indicates if interval ends should be checked when locating polynomial roots on the interval\n        var inclEnds;\n\n        // Coordinates of curve control points center of gravity\n        var middlePtx, middlePty;\n\n        // Auxiliary variables\n        var tmp1;\n        var i;\n\n        middlePtx = (px1 + px2 + cx) / 3;\n        middlePty = (py1 + py2 + cy) / 3;\n\n        d1 = ifMath.sqrSegmentDist(px1, py1, px2, py2, x, y, ptMin, sqrOutline);\n        if (d1 <= sqrOutline) {\n            hitPossible = true;\n        }\n        else if (ifMath.segmentSide(px1, py1, px2, py2, x, y) *\n            ifMath.segmentSide(px1, py1, px2, py2, middlePtx, middlePty) < 0) {\n            insideFlag = false;\n        }\n\n        // Curve end is hit, no need to look for closer point\n        if (hitPossible && (ptMin[0] == 0 || ptMin[0] == 1)) {\n            if (result) {\n                result.segment = chainIdx;\n                result.outline = true;\n                result.slope = ptMin[0];\n\n                if (ptMin[0] == 0) {\n                    result.x = px1;\n                    result.y = py1;\n                }\n                else { // ptMin[0] == 1\n                    result.x = px2;\n                    result.y = py2;\n                }\n            }\n            return true;\n        }\n\n        d2 = ifMath.sqrSegmentDist(px1, py1, cx, cy, x, y);\n        if (d2 <= sqrOutline) {\n            hitPossible = true;\n        }\n        else if (ifMath.segmentSide(px1, py1, cx, cy, x, y) *\n            ifMath.segmentSide(px1, py1, cx, cy, middlePtx, middlePty) < 0) {\n            insideFlag = false;\n        }\n\n        d3 = ifMath.sqrSegmentDist(cx, cy, px2, py2, x, y);\n        if (d3 <= sqrOutline) {\n            hitPossible = true;\n        }\n        else if (ifMath.segmentSide(cx, cy, px2, py2, x, y) *\n            ifMath.segmentSide(cx, cy, px2, py2, middlePtx, middlePty) < 0) {\n            insideFlag = false;\n        }\n\n        if (!hitPossible && !insideFlag) {\n            return false;\n        }\n\n        // find directly curve point, minimizing distance\n        // P(t) = t^2(P2 - 2C + P1) + 2t(C-P1) + P1\n        // P(t) = t^2A + tB + D\n        // F(x(t), y(t)) = (x - x(t))^2 + (y - y(t))^2 -> min\n        // F(t) = t^4*ax^2 + t^2*bx^2 + dx^2 +\n        //        2t^3*ax*bx + 2t^2* ax*dx + 2t*bx*dx + \n        //        x^2 - 2x*t^2*ax - 2x*t*bx -2x*dx +\n        //        t^4*ay^2 + t^2*by^2 + dy^2 +\n        //        2t^3*ay*by + 2t^2* ay*dy + 2t*by*dy + \n        //        y^2 - 2y*t^2*ay - 2y*t*by -2y*dy\n        // dF(t)/dt = 4t^3*ax^2 + 2t*bx^2 + 6t^2*ax*bx + 4t*ax*dx + 2bx*dx - \n        //            4t*x*ax - 2x*bx +\n        //            4t^3*ay^2 + 2t*by^2 + 6t^2*ay*by + 4t*ay*dy + 2by*dy - \n        //            4t*y*ay - 2y*by =\n        //    = 2* ( \n        //      2t^3(ax^2 + ay^2) + 3t^2(ax*bx + ay*by) +\n        //      t(bx^2 + 2ax*dx - 2x*ax + by^2 + 2ay*dy - 2y*ay) +\n        //      bx*dx - x*bx + by*dy - y*by\n        //      )\n        // df/dt = 0 <==> 2t^3(a, a) + 3t^2(a,b) + \n        // t( (b,b) + 2(a,d) -2(p,a) ) + (b,d) - (p,b) = 0\n        // \n        // g(t) = t^3 + b*t^2 +c*t + d = 0, t from [0, 1]\n        // g't = 3t^2 + 2t*b + c   = 0  => t1 <= t2 \n        // g''t = 6t +2b\n\n        ax = px2 - 2 * cx + px1;\n        ay = py2 - 2 * cy + py1;\n\n        if (ax == 0 && ay == 0) {\n            return this._hitTestSegment(px1, py1, px2, py2, x, y, sqrOutline, chainIdx, result);\n        }\n\n        bx = 2 * (cx - px1);\n        by = 2 * (cy - py1);\n\n        coeffF[0] = ax * ax + ay * ay;\n        coeffF[1] = 2 * (ax * bx + ay * by);\n        coeffF[2] = bx * bx + by * by + 2 * ax * (px1 - x) + 2 * ay * (py1 - y);\n        coeffF[3] = 2 * (bx * (px1 - x) + by * (py1 - y));\n        coeffF[4] = (px1 - x) * (px1 - x) + (py1 - y) * (py1 - y);\n\n        tmp1 = 2 * coeffF[0];\n        b = 3 * coeffF[1] / (2 * tmp1);\n        c = coeffF[2] / tmp1;\n        d = coeffF[3] / (2 * tmp1);\n\n        coeffG[0] = 1;\n        coeffG[1] = b;\n        coeffG[2] = c;\n        coeffG[3] = d;\n\n        inclEnds = false;\n        gRootsN = ifMath.getCubicRoots(coeffG, 0.0, 1.0, gRoots, inclEnds, acc);\n\n        if (gRootsN == 0) {\n            // ends are already checked\n            return false;\n        }\n\n        min = sqrOutline + 1;\n        hitPtIdx = gRootsN + 1;\n        // calculate F(t) in g(t) roots, find min\n        for (i = 0; i < gRootsN; ++i) {\n            tmp1 = ifMath.evalPoly(coeffF, 4, gRoots[i]);\n            if (min > tmp1) {\n                min = tmp1;\n                hitPtIdx = i;\n            }\n        }\n\n        if (min <= sqrOutline) {\n            // Fill result\n            if (result) {\n                result.segment = chainIdx;\n                result.x = (gRoots[hitPtIdx] * ax + bx) * gRoots[hitPtIdx] + px1;\n                result.y = (gRoots[hitPtIdx] * ay + by) * gRoots[hitPtIdx] + py1;\n                result.outline = true;\n                result.slope = gRoots[hitPtIdx];\n            }\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Tests if a point is on the cubic Bezier curve stroke.\n     * Algorithm uses the generalized Sturm sequence based on Collins pseudo-reminder sequence\n     * for locating the roots of polynomial equation of 5th degree.\n     * This generalized Sturm sequence is described in the book of\n     * Chee-Keng Yap \"Fundamental Problems in Algorithmic Algebra\"\n     * @param {Number} px1 the x-position of the curve start point\n     * @param {Number} py1 the y-position of the curve start point\n     * @param {Number} px2 the x-position of the curve end point\n     * @param {Number} py2 the y-position of the curve end point\n     * @param {Number} cx1 the x-position of the first control point\n     * @param {Number} cy1 the y-position of the first control point\n     * @param {Number} cx2 the x-position of the second control point\n     * @param {Number} cy2 the y-position of the second control point\n     * @param {Number} x the x-position of the point to test\n     * @param {Number} y the y-position of the point to test\n     * @param {Number} sqrOutline squared half-width of stroke\n     * @param {Number} chainIdx an index of the curve in the path to be written into result, when curve is hit\n     * @param {IFVertexInfo.HitResult} result if the function returns true, means\n     * a hit was found then this is the result structure that will be filled\n     * with the hit information\n\n     * @return {Boolean} true, if a point is on the stroke\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._hitTestCurve2 = function (px1, py1, px2, py2, cx1, cy1, cx2, cy2, x, y, sqrOutline, chainIdx, result) {\n        // There is a hit if the shortest squared distance from point to curve is less than sqrOutline.\n        // An exact distance from a point to a point on curve is a polynomial of 6 degree.\n        // To find a distance minimization point, we need to check curve ends and find and check roots\n        // of the distance polynomial derivative on the segment [0, 1], which is a polynomial of 5 degree.\n        // To find the roots of 5-th degree polynomial, they will be located first, and then calculated\n        // with Newton method.\n        // The root location problem is solved in two steps: on the first step a curve is split into\n        // several pieces in curve inflate points, and then on the second step the roots location is continued\n        // using bisection and generalized Sturm sequence based on pseudo-reminder sequence and Collins algorithm,\n        // described in the book of Chee-Keng Yap \"Fundamental Problems in Algorithmic Algebra\".\n\n        // Algorithm is divided into 8 steps. See comments in the algorithm for each step description.\n\n        // Array of points in which curve is split\n        var splitPoints;\n        // Sorted split points\n        var sPtsNew = [];\n        // number of split points\n        var nPoints;\n\n        // Coefficients, used in P'(t) = 0 equation\n        var ax, ay, bx, by, cx, cy;\n\n        // Coefficients, used in P(t) formula\n        var b1x, b1y, c1x, c1y;\n\n        // Coefficients of 6 degree distance polynomial\n        var coeffF = new Float64Array(7);\n\n        // Coefficients of 5 degree derivative polynomial\n        var coeffFDeriv = new Float64Array(6);\n\n        // Coefficients of 5 degree polynomial, calculated from derivative polynomial and interval transformation\n        var coeffInversed = new Float64Array(6);\n\n        // Squared distances from point to P1 and P2\n        var sqrDst1, sqrDst2;\n\n        // Coefficients, used in quadratic equation for inflate points\n        var A, B, C;\n\n        // Auxiliary variables for calculations\n        var tmp;\n        var d1, d2;\n\n        // parameter values for ends of each peace of curve\n        var A1, A2;\n        // coordinates or ends of each peace of curve\n        var pA1x, pA1y, pA2x, pA2y;\n        // squared distances to ends of each peace of curve\n        var dA1, dA2;\n        // arrays, used for storing coordinates of control points for each peace of curve\n        var ctrlsx = new Float64Array(4);\n        var ctrlsy = new Float64Array(4);\n        // values of derivative polynomial at ends of each peace of curve\n        var v51, v52;\n        // Number of real roots of derivative polynomial at roots location interval,\n        // estimated with Descartes rule of sign\n        var nRoots;\n        // Number of distinct real roots of derivative polynomial at roots location interval,\n        // estimated with Sturm sequence\n        var nRootsNew;\n\n        // Coeffitients of the second and third derivative polynomials\n        var coeffFDeriv2 = null;\n        var coeffFDeriv3 = null;\n\n        // Derivative polynomial root, and point x and y coordinates at the root value\n        var r1, r1x, r1y;\n\n        // squared distance between points\n        var sqrDst;\n\n        // Auxiliary index variables\n        var j, k;\n\n        // Flags used for analysis of point and curve pience relative position\n        var hitPossible = false;\n        var insideFlag = true;\n\n        // Coordinates of each curve piece control points center of gravity\n        var middlePtx, middlePty;\n\n        // generalized Sturm sequence (array of polynomial coefficients arrays)\n        var sturmSeq = [];\n\n        // Number of Sturm sequence sign variations at roots location interval ends\n        var nSignVars;\n        // Derivative polynomial values at roots location interval ends\n        var fVals;\n\n        // 1. Inverse interval [0, 1] to [0, inf) and estimate by Descartes rule of sign\n        // if the number of positive real roots could be > 0\n        // If == 0, select the lowest distance to Pt from P1 and P2.\n        // Otherwise, proceed to step 2.\n\n        // Pdist(t) = (Px(t) - x)^2 + (Py(t) - y)^2 =\n        // = Px(t)^2 + Py(t)^2 - 2x*Px(t) - 2y*Px(t) + x^2 +y^2\n        //\n        // P(t) = P1 + 3t(C1 - P1) + 3t^2*(C2 - 2C1 + P1) + t^3*(P2 - 3C2 + 3C1 - P1)\n        // P' =3(C1 - P1) + 6t(C2 - 2C1 + P1) + 3t^2*(P2 - 3C2 + 3C1 - P1)\n        // P' = 3(at^2 + bt + c)\n        // P(t) = at^3 + 3/2*bt^2 + 3ct + d = a1t^3 + b1t^2 + c1t + d1\n        // a1 = a, d1 = p1\n\n        cx = cx1 - px1;\n        c1x = 3 * cx;\n        cy = cy1 - py1;\n        c1y = 3 * cy;\n        tmp = cx2 - cx1 - cx;\n        b1x = 3 * tmp;\n        bx = 2 * tmp;\n        tmp = cy2 - cy1 - cy;\n        b1y = 3 * tmp;\n        by = 2 * tmp;\n        ax = px2 - cx2 - cx - bx;\n        ay = py2 - cy2 - cy - by;\n\n        // P(t)^2 = a1^2*t^6 + b1^2*t^4 + c1^2*t^2 + d1^2 + 2*a1b1*t^5 + 2a1c1*t^4 +\n        //        + 2(a1d1 + b1c1)t^3 + 2b1d1*t^2 + 2c1d1*t\n        //\n        // d1 = d1 - x, d2 = d2 - y\n        //\n        // Pdist(t) = (a1^2 + a2^2)*t^6 + 2*(a1b1 + a2b2)*t^5 + (b1^2 + 2a1c1 + b2^2 + 2a2c2)*t^4 +\n        //         + 2(a1(d1 - x) + b1c1 + a2(d2 - y) + b2c2)*t^3 + (c1^2 + 2b1(d1 - x) + c2^2 + 2b2(d2 -y))*t^2 +\n        //         + 2(c1(d1 - x) + c2(d2 - y))*t + (d1 - x)^2 + (d2 - y)^2\n        d1 = px1 - x;\n        d2 = py1 - y;\n        coeffF[0] = ax * ax + ay * ay;\n        coeffF[1] = 2 * (ax * b1x + ay * b1y);\n        coeffF[2] = b1x * b1x + b1y * b1y + 2 * (ax * c1x + ay * c1y);\n        coeffF[3] = (ax * d1 + b1x * c1x + ay * d2 + b1y * c1y) * 2;\n        coeffF[4] = c1x * c1x + c1y * c1y + (b1x * d1 + b1y * d2) * 2;\n        coeffF[5] = (c1x * d1 + c1y * d2) * 2;\n        coeffF[6] = d1 * d1 + d2 * d2;\n\n        ifMath.getCoeffPolyDeriv(coeffF, 6, coeffFDeriv);\n\n        ifMath.inversePolyUnaryInterval(coeffFDeriv, 5, coeffInversed);\n\n        if (ifMath.estimPositiveRootsDescartes(coeffInversed, 5) == 0) {\n            sqrDst1 = ifMath.ptSqrDist(px1, py1, x, y);\n            sqrDst2 = ifMath.ptSqrDist(px2, py2, x, y);\n\n            if (sqrDst1 <= sqrOutline || sqrDst2 <= sqrOutline) {\n                if (result) {\n                    result.segment = chainIdx;\n                    result.outline = true;\n                    if (sqrDst1 < sqrDst2) {\n                        result.x = px1;\n                        result.y = py1;\n                        result.slope = 0.0;\n                    }\n                    else {\n                        result.x = px2;\n                        result.y = py2;\n                        result.slope = 1.0;\n                    }\n                }\n                return true;\n            }\n            return false;\n        }\n\n        // 2. Find initial interval (curve) splitPoints at [0, 1],\n        // which are curve inflate points, or such points,\n        // that P'x = 0 or P'y = 0\n        nPoints = ifMath.getCubicCurveSplits(ax, bx, cx, ay, by, cy, sPtsNew);\n\n        // 3. Based on splitPoints iterate through intervals,\n        // and for each interval perform the following steps:\n\n        for (var i = 0; i < nPoints - 1; ++i) {\n\n            // 4.\n            // Evaluate dist to bounding segments between splitPoints\n            // If sqrDist > sqrOutline, proceed to next segment\n            // If sqrDist <= sqrOutline and min is at segment ends,\n            // return true and result if needed\n\n            if (i == 0) {\n                A1 = sPtsNew[i];\n                pA1x = ifMath.evalCubic(ax, b1x, c1x, px1, A1);\n                pA1y = ifMath.evalCubic(ay, b1y, c1y, py1, A1);\n                dA1 = ifMath.ptSqrDist(pA1x, pA1y, x, y);\n                if (dA1 <= sqrOutline) {\n                    if (result) {\n                        result.segment = chainIdx;\n                        result.outline = true;\n                        result.x = pA1x;\n                        result.y = pA1y;\n                        result.slope = A1;\n                    }\n                    return true;\n                }\n            }\n            else {\n                A1 = A2;\n                pA1x = pA2x;\n                pA1y = pA2y;\n                dA1 = dA2;\n            }\n            A2 = sPtsNew[i + 1];\n            pA2x = ifMath.evalCubic(ax, b1x, c1x, px1, A2);\n            pA2y = ifMath.evalCubic(ay, b1y, c1y, py1, A2);\n            dA2 = ifMath.ptSqrDist(pA2x, pA2y, x, y);\n            if (dA2 <= sqrOutline) {\n                if (result) {\n                    result.segment = chainIdx;\n                    result.outline = true;\n                    result.x = pA2x;\n                    result.y = pA2y;\n                    result.slope = A2;\n                }\n                return true;\n            }\n\n            ifMath.getCtrlPts(px1, px2, cx1, cx2, A1, A2, ctrlsx);\n            ifMath.getCtrlPts(py1, py2, cy1, cy2, A1, A2, ctrlsy);\n\n            // splitPoints were received such a way, that curve parts don't change curvature direction,\n            // and winding angle from one end to the other is not more than 90 degrees.\n            // This mean, that control points don't change their order when convex hull is constructed.\n            // And a distance to this part of curve may be estimated as the distance to polyhedron,\n            // constructed from control points\n            hitPossible = false;\n            insideFlag = true;\n            middlePtx = (ctrlsx[0] + ctrlsx[1] + ctrlsx[2] + ctrlsx[3]) / 4;\n            middlePty = (ctrlsy[0] + ctrlsy[1] + ctrlsy[2] + ctrlsy[3]) / 4;\n            for (j = 0; j < 4; ++j) {\n\n                if (j == 3) {\n                    k = 0;\n                }\n                else {\n                    k = j + 1;\n                }\n                if (ifMath.sqrSegmentDist(ctrlsx[j], ctrlsy[j], ctrlsx[k], ctrlsy[k], x, y) <= sqrOutline) {\n                    hitPossible = true;\n                    break;\n                }\n                if (ifMath.segmentSide(ctrlsx[j], ctrlsy[j], ctrlsx[k], ctrlsy[k], x, y) *\n                    ifMath.segmentSide(ctrlsx[j], ctrlsy[j], ctrlsx[k], ctrlsy[k], middlePtx, middlePty) < 0) {\n                    insideFlag = false;\n                }\n            }\n\n            if (!hitPossible && !insideFlag) {\n                continue;\n            }\n\n\n            // 5. For interval [Ai, Ai+1], check ends\n            // If f5(Ai) = 0, set Ai = Ai + eps\n            // If f5(Ai+1) = 0, set Ai+1 = Ai+1 - eps\n\n            v51 = ifMath.evalPoly(coeffFDeriv, 5, A1);\n            // TODO: change 0.005 with the correct value, which guarantees accuracy\n            if (ifMath.isEqualEps(v51, 0)) {\n                A1 += 0.005;\n                v51 = ifMath.evalPoly(coeffFDeriv, 5, A1);\n            }\n            v52 = ifMath.evalPoly(coeffFDeriv, 5, A2);\n            if (ifMath.isEqualEps(v52, 0)) {\n                A2 -= 0.005;\n                v52 = ifMath.evalPoly(coeffFDeriv, 5, A2);\n            }\n\n            // 6. Inverse interval [Ai, Ai+1] to [0, inf) and estimate by Descartes rule of sign\n            // if the number of positive real roots N could be > 0\n            // If N = 0, lowerest distance to Pt from P(ai) and P(ai+1) should be checked.\n            // Actually, no such check is needed due to step 4.\n            // If N = 1 , proceed to step 7.\n            // If N > 1, proceed to step 8.\n            ifMath.inversePolyInterval(coeffFDeriv, 5, A1, A2, coeffInversed);\n\n            nRoots = ifMath.estimPositiveRootsDescartes(coeffInversed, 5);\n            if (nRoots == 0) {\n                continue;\n            }\n\n            // 7. N = 1\n            // apply Newton method to find the root,\n            // calculate distance for this root, return true if <= sqrOutline\n            if (!coeffFDeriv2) {\n                coeffFDeriv2 = new Float64Array(5);\n                ifMath.getCoeffPolyDeriv(coeffFDeriv, 5, coeffFDeriv2);\n            }\n\n            if (!coeffFDeriv3) {\n                coeffFDeriv3 = new Float64Array(4);\n                ifMath.getCoeffPolyDeriv(coeffFDeriv2, 4, coeffFDeriv3);\n            }\n\n            if (nRoots == 1) {\n                r1 = ifMath.locateByNewton(A1, A2, v51, v52, coeffFDeriv, 5, coeffFDeriv2, coeffFDeriv3, 0.005);\n                if (r1 == null) {\n                    r1 = (A1 + A2) / 2;\n                }\n                r1x = ifMath.evalCubic(ax, b1x, c1x, px1, r1);\n                r1y = ifMath.evalCubic(ay, b1y, c1y, py1, r1);\n                sqrDst = ifMath.ptSqrDist(r1x, r1y, x, y);\n                if (sqrDst <= sqrOutline) {\n                    if (result) {\n                        result.segment = chainIdx;\n                        result.outline = true;\n                        result.x = r1x;\n                        result.y = r1y;\n                        result.slope = r1;\n                    }\n                    return true;\n                }\n            }\n\n            // 8. N > 1\n            // Find Sturm sequense, and count the exact number NS of distinct real roots at [Ai, Ai+1]\n            // if NS > 1, apply bisection and recursion Sturm to isolate intervals, where = 1,\n            // apply Newton for each new interval with 1 real root\n            // Calculate distance for each found root, return true if <= sqrOutline\n\n            if (nRoots > 1) {\n                if (sturmSeq.length == 0) {\n                    ifMath.getSturmPRS(coeffFDeriv, 5, coeffFDeriv2, sturmSeq);\n                }\n\n                nSignVars = [];\n                fVals = [v51, v52];\n                nRootsNew = ifMath.countRootsNSturm(coeffFDeriv, 5, coeffFDeriv2, A1, A2,\n                    sturmSeq, nSignVars, fVals);\n\n                if (nRootsNew == 0) {\n                    continue;\n                }\n\n                if (nRootsNew == 1) {\n                    r1 = ifMath.locateByNewton(A1, A2, v51, v52, coeffFDeriv, 5, coeffFDeriv2, coeffFDeriv3, 0.005,\n                        sturmSeq, nSignVars);\n                    if (r1 == null) {\n                        r1 = (A1 + A2) / 2;\n                    }\n                    r1x = ifMath.evalCubic(ax, b1x, c1x, px1, r1);\n                    r1y = ifMath.evalCubic(ay, b1y, c1y, py1, r1);\n                    sqrDst = ifMath.ptSqrDist(r1x, r1y, x, y);\n                    if (sqrDst <= sqrOutline) {\n                        if (result) {\n                            result.segment = chainIdx;\n                            result.outline = true;\n                            result.x = r1x;\n                            result.y = r1y;\n                            result.slope = r1;\n                        }\n                        return true;\n                    }\n                }\n\n                if (nRootsNew > 1) {\n                    var rIntervals = [];\n                    ifMath.locRootsSturm(coeffFDeriv, 5, coeffFDeriv2, A1, A2, sturmSeq, nRootsNew,\n                        nSignVars, fVals, rIntervals);\n\n                    for (var s = 0; s < rIntervals.length; ++s) {\n                        r1 = ifMath.locateByNewton(rIntervals[s][0], rIntervals[s][1],\n                            rIntervals[s][2], rIntervals[s][3], coeffFDeriv, 5, coeffFDeriv2, coeffFDeriv3, 0.005,\n                            sturmSeq);\n                        if (r1 == null) {\n                            r1 = (rIntervals[s][0] + rIntervals[s][1]) / 2;\n                        }\n                        r1x = ifMath.evalCubic(ax, b1x, c1x, px1, r1);\n                        r1y = ifMath.evalCubic(ay, b1y, c1y, py1, r1);\n                        sqrDst = ifMath.ptSqrDist(r1x, r1y, x, y);\n                        if (sqrDst <= sqrOutline) {\n                            if (result) {\n                                result.segment = chainIdx;\n                                result.outline = true;\n                                result.x = r1x;\n                                result.y = r1y;\n                                result.slope = r1;\n                            }\n                            return true;\n                        }\n                    }\n                }\n            } // nRoots > 1\n\n        } // for splitPoints\n\n        return false;\n    };\n\n    /**\n     * Counts a point inside score for line segment according to\n     * the paper of J. Ruiz de Miras and F. R. Feito \"Inclusion Test for Curved-Edge Polygons\".\n     * @param {Number} px1 the x-position of the segment start point\n     * @param {Number} py1 the y-position of the segment start point\n     * @param {Number} px2 the x-position of the segment end point\n     * @param {Number} py2 the y-position of the segment end point\n     * @param {Number} x the x-position of the point to count score\n     * @param {Number} y the y-position of the point to count score\n     * @param {Boolean} countSegm if true, segment inside is counted as under segment\n\n     * @return {Number} a point inside score\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._hitUnderSegment = function (px1, py1, px2, py2, x, y, countSegm) {\n        var s1, s2, s3;\n\n        s1 = ifMath.segmentSide(0, 0, px1, py1, x, y);\n        s2 = ifMath.segmentSide(px1, py1, px2, py2, x, y);\n        s3 = ifMath.segmentSide(px2, py2, 0, 0, x, y);\n\n        if (s1 > 0 && s2 > 0 && s3 > 0) {\n            return 2;\n        }\n\n        if (s1 < 0 && s2 < 0 && s3 < 0) {\n            return -2;\n        }\n\n        if (s1 == 0) {\n            if (s2 > 0 && s3 > 0) {\n                return 1;\n            }\n            if (s2 < 0 && s3 < 0) {\n                return -1;\n            }\n            return 0;\n        }\n\n        if (s3 == 0) {\n            if (s1 > 0 && s2 > 0) {\n                return 1;\n            }\n            if (s1 < 0 && s2 < 0) {\n                return -1;\n            }\n            return 0;\n        }\n\n        if (countSegm && s2 == 0) {\n            if (s1 > 0 && s3 > 0) {\n                return 1;\n            }\n            if (s1 < 0 && s3 < 0) {\n                return -1;\n            }\n            return 0;\n        }\n\n        return 0;\n    };\n\n    /**\n     * Counts a point inside score for conic curve region according to\n     * the paper of J. Ruiz de Miras and F. R. Feito \"Inclusion Test for Curved-Edge Polygons\".\n     * @param {Number} px1 the x-position of the curve start point\n     * @param {Number} py1 the y-position of the curve start point\n     * @param {Number} px2 the x-position of the curve end point\n     * @param {Number} py2 the y-position of the curve end point\n     * @param {Number} cx the x-position of a control point\n     * @param {Number} cy the y-position of a control point\n     * @param {Function} cHullCheck the function to check if the point inside convex hull of control points\n     * @param {Function} curvFunc the implicit equation for curve\n     * @param {Number} x the x-position of the point to count score\n     * @param {Number} y the y-position of the point to count score\n\n     * @return {Number} a point inside score\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._evalConicReg = function (px1, py1, px2, py2, cx, cy, cHullCheck, curvFunc, x, y) {\n        var alpha;\n        var chullres; // result of checking against controls convex hull\n        var sideC; // value of curve function in the control point\n        var sidePt; // value of curve function in the point to test\n        var signReg = -ifMath.segmentSide(px1, py1, px2, py2, cx, cy); // the region sign\n\n        if (signReg == 0) {\n            // mirrored Y is noticed\n            return this._hitUnderSegment(px1, py1, px2, py2, x, y);\n        }\n\n        // mirrored Y is noticed\n        alpha = this._hitUnderSegment(px1, py1, px2, py2, x, y, true);\n\n        // Check point is from convex hull\n        chullres = cHullCheck(x, y);\n        if (chullres < 0) {\n            return alpha;\n        }\n\n        // Pt is inside convex hull\n        if (chullres == 0) { // point is on the foundation of conic region\n            return signReg + alpha;\n        }\n\n        sideC = -curvFunc(cx, cy);\n\n        // Mirrored Y axis gives:\n        sidePt = -curvFunc(x, y);\n\n        if (sidePt > 0 && sideC < 0 || sidePt < 0 && sideC > 0) {\n            // Pt is inside arc\n            return signReg + signReg + alpha;\n        }\n\n        return alpha;\n    };\n\n    /**\n     * Counts a point inside score for quadartic Bezier curve according to\n     * the paper of J. Ruiz de Miras and F. R. Feito \"Inclusion Test for Curved-Edge Polygons\"\n     * and using the results presented in the document of Alois Zingl \"A Rasterizing Algorithm for Drawing Curves\".\n     * @param {Number} px1 the x-position of the curve start point\n     * @param {Number} py1 the y-position of the curve start point\n     * @param {Number} px2 the x-position of the curve end point\n     * @param {Number} py2 the y-position of the curve end point\n     * @param {Number} cx the x-position of the control point\n     * @param {Number} cy the y-position of the control point\n     * @param {Number} x the x-position of the point to count score\n     * @param {Number} y the y-position of the point to count score\n\n     * @return {Number} a point inside score\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._hitUnderCurve = function (px1, py1, px2, py2, cx, cy, x, y) {\n        // Here is used formulas for curve implicitization from the document of\n        // Alois Zingl \"A Rasterizing Algorithm for Drawing Curves\"\n\n        function curvFunc(x, y) {\n            //implicit formula for curve is:\n            //(x*(py1 - 2cy + py2) - y*(px1 - 2cx + px2))^2 + 2(x(py1 - py2) - y(px1 - px2))*curvature + curvature^2 = 0\n            // where x and y are shifted to cx and cy\n\n            var curvature = (px1 - cx) * (py2 - cy) + (cx - px2) * (py1 - cy);\n            var xn = x - cx;\n            var yn = y - cy;\n            var tmp1 = xn * (py1 - 2 * cy + py2) - yn * (px1 - 2 * cx + px2);\n            return tmp1 * tmp1 + (2 * (xn * (py1 - py2) + yn * (px2 - px1)) + curvature) * curvature;\n        }\n\n        function cHullCheck(x, y) {\n            var s1, s2, s3;\n            var middlePtx = (px1 + cx + px2) / 3;\n            var middlePty = (py1 + cy + py2) / 3;\n\n            s3 = ifMath.segmentSide(px2, py2, px1, py1, x, y);\n            if (s3 == 0) {\n                return 0;\n            }\n\n            s1 = ifMath.segmentSide(px1, py1, cx, cy, x, y);\n            s2 = ifMath.segmentSide(cx, cy, px2, py2, x, y);\n\n            if (s1 != ifMath.segmentSide(px1, py1, cx, cy, middlePtx, middlePty) ||\n                s2 != ifMath.segmentSide(cx, cy, px2, py2, middlePtx, middlePty) ||\n                s3 != ifMath.segmentSide(px2, py2, px1, py1, middlePtx, middlePty)) {\n\n                return -1;\n            }\n\n            // Pt is inside convex hull\n            return 1;\n        }\n\n        return this._evalConicReg(px1, py1, px2, py2, cx, cy, cHullCheck, curvFunc, x, y);\n    };\n\n    /**\n     * Counts a point inside score for cubic Bezier curve according to\n     * the paper of J. Ruiz de Miras and F. R. Feito \"Inclusion Test for Curved-Edge Polygons\"\n     * and using the results presented in the document of Alois Zingl \"A Rasterizing Algorithm for Drawing Curves\".\n     * @param {Number} px1 the x-position of the curve start point\n     * @param {Number} py1 the y-position of the curve start point\n     * @param {Number} px2 the x-position of the curve end point\n     * @param {Number} py2 the y-position of the curve end point\n     * @param {Number} cx1 the x-position of the first control point\n     * @param {Number} cy1 the y-position of the first control point\n     * @param {Number} cx2 the x-position of the second control point\n     * @param {Number} cy2 the y-position of the second control point\n     * @param {Number} x the x-position of the point to count score\n     * @param {Number} y the y-position of the point to count score\n\n     * @return {Number} a point inside score\n     * @private\n     * @version 1.0\n     */\n    IFVertexInfo.prototype._hitUnderCurve2 = function (px1, py1, px2, py2, cx1, cy1, cx2, cy2, x, y) {\n        // Here is used formulas for curve implicitization and self-intersection point from the document of\n        // Alois Zingl \"A Rasterizing Algorithm for Drawing Curves\"\n\n        // Overall algorithm for counting a point inside score (for path inside hit-test) is the following:\n        // 1. Split curve in self-intersection points and inflate points\n        // 2. Implicitize each peace\n        // 3. Apply the same algorithm for checking curve region inside as for quadratic curves\n\n        var tot = 0;\n        var splitPoints = [];\n\n        // Coefficients, used in P'(t) = 0 equation\n        var ax, ay, bx, by, cx, cy;\n\n        // Coefficients, used in P(t) formula\n        var b1x, b1y, c1x, c1y;\n        var coeffPX;\n        var coeffPY;\n        // With shifted t to [-1/2, 1/2]\n        var coeffPShiftedX;\n        var coeffPShiftedY;\n\n        // Coefficients, used in quadratic equation for inflate points\n        var A, B, C;\n\n        var tmp;\n\n        // variables for finding a self-intersection point\n        var Xa, Xb, Xc, Ya, Yb, Yc, Cac, Cab, Cbc;\n        var sqrtC;\n        var tv1, tv2;\n\n        // arrays, used for storing coordinates of control points for each peace of curve\n        var ctrlsx;\n        var ctrlsy;\n\n        // parameter values for ends of each peace of curve\n        var A1, A2;\n\n        // 1. Find inflate points:\n        // P'x * P''y - P'y * P''x = 0\n        // P(t) = P1 + 3t(C1 - P1) + 3t^2*(C2 - 2C1 + P1) + t^3*(P2 - 3C2 + 3C1 - P1)\n        // P' =3(C1 - P1) + 6t(C2 - 2C1 + P1) + 3t^2*(P2 - 3C2 + 3C1 - P1)\n        // P' = 3(at^2 + bt + c)\n        // P(t) = at^3 + 3/2*bt^2 + 3ct + d = a1t^3 + b1t^2 + c1t + d1\n        // a1 = a, d1 = p1\n        cx = cx1 - px1;\n        c1x = 3 * cx;\n        cy = cy1 - py1;\n        c1y = 3 * cy;\n        tmp = cx2 - cx1 - cx;\n        b1x = 3 * tmp;\n        bx = 2 * tmp;\n        tmp = cy2 - cy1 - cy;\n        b1y = 3 * tmp;\n        by = 2 * tmp;\n        ax = px2 - cx2 - cx - bx;\n        ay = py2 - cy2 - cy - by;\n\n        // (2bx*ay -2by*ax + ax*by - ay*bx)t^2 + (2cx*ay - 2cy*ax)t + cx*by - cy*bx = 0\n        // (bx*ay - by*ax)t^2 + 2*(cx*ay - cy*ax)t + cx*by - cy*bx = 0\n        // At^2 + Bt + C = 0\n        A = bx * ay - by * ax;\n        B = 2 * (cx * ay - cy * ax);\n        C = cx * by - cy * bx;\n        ifMath.getQuadraticRoots(A, B, C, splitPoints);\n\n        // a curve may have a self-intersection point only if it doesn't have inflate points\n        if (splitPoints.length == 0) {\n            // Find self-intersection points:\n            // t from [0, 1] -> t = ^t + 1/2 -> ^t from [-1/2, 1,2]\n            coeffPX = new Float64Array(4);\n            coeffPY = new Float64Array(4);\n            coeffPShiftedX = new Float64Array(4);\n            coeffPShiftedY = new Float64Array(4);\n\n            coeffPX[0] = ax;\n            coeffPX[1] = b1x;\n            coeffPX[2] = c1x;\n            coeffPX[3] = px1;\n\n            coeffPY[0] = ay;\n            coeffPY[1] = b1y;\n            coeffPY[2] = c1y;\n            coeffPY[3] = py1;\n\n            ifMath.shiftPoly(coeffPX, 3, 0.5, coeffPShiftedX);\n            ifMath.shiftPoly(coeffPY, 3, 0.5, coeffPShiftedY);\n\n            // ^t1,2 = (Cac +- sqrt(12Cab*Cbc - 3Cac^2)) / 2Cab\n            Xa = -coeffPShiftedX[0];\n            Xb = coeffPShiftedX[1] / 3;\n            Xc = -coeffPShiftedX[2] / 3;\n            Ya = -coeffPShiftedY[0];\n            Yb = coeffPShiftedY[1] / 3;\n            Yc = -coeffPShiftedY[2] / 3;\n\n            Cac = Xa * Yc - Xc * Ya;\n            Cab = Xa * Yb - Xb * Ya;\n            Cbc = Xb * Yc - Xc * Yb;\n\n            tmp = 12 * Cab * Cbc - 3 * Cac * Cac;\n            if (tmp > 0) { // case of a cusp when tmp == 0 is not interested, as it was calculated in inflate points\n                sqrtC = Math.sqrt(tmp);\n                tv1 = (Cac - sqrtC) / (Cab * 2);\n                tv2 = (Cac + sqrtC) / (Cab * 2);\n\n                if (-0.5 < tv1 && tv1 < 0.5) {\n                    splitPoints.push(tv1 + 0.5);\n                    if (-0.5 < tv2 && tv2 < 0.5) {\n                        splitPoints.push(tv2 + 0.5);\n\n                        // a slope inside curve, add a split point in the middle\n                        splitPoints.push((tv1 + tv2) / 2 + 0.5);\n                    }\n                }\n\n                if (-0.5 < tv2 && tv2 < 0.5) {\n                    splitPoints.push(tv2 + 0.5);\n                }\n            } // tmp > 0\n        } // splitPoints.length == 0\n\n        splitPoints.push(0.0);\n        splitPoints.push(1.0);\n        var sPtsNew = [];\n        var nPoints = ifUtil.uSortSegment(0, 1, splitPoints, sPtsNew);\n\n        // 2. Implicitize each peace\n        ctrlsx = new Float64Array(4);\n        ctrlsy = new Float64Array(4);\n\n        for (var i = 0; i < nPoints - 1; ++i) {\n            if (i == 0) {\n                A1 = sPtsNew[i];\n            }\n            else {\n                A1 = A2;\n            }\n            A2 = sPtsNew[i + 1];\n\n            if (A1 == 0.0 && A2 == 1.0) {\n                ctrlsx[0] = px1;\n                ctrlsx[1] = cx1;\n                ctrlsx[2] = cx2;\n                ctrlsx[3] = px2;\n\n                ctrlsy[0] = py1;\n                ctrlsy[1] = cy1;\n                ctrlsy[2] = cy2;\n                ctrlsy[3] = py2;\n            }\n            else {\n                ifMath.getCtrlPts(px1, px2, cx1, cx2, A1, A2, ctrlsx);\n                ifMath.getCtrlPts(py1, py2, cy1, cy2, A1, A2, ctrlsy);\n            }\n\n            // splitPoints were received such a way, that curve parts don't change curvature direction,\n            // and winding angle from one end to the other is less than 360 degrees.\n            // Also there are no singular (self-intersection) points inside each peace\n            // So each peace is a valid conic region, and we can use it in algorithm for inside of a path checking\n            // 3. Apply the same algorithm as for quadratic curves\n\n            function curvFunc(x, y) {\n                // calculate the implicit equation for this curve:\n                // ax^3 - 3bx^2y + 3cxy^2 - dy^3 + 3ex^2 - 3fxy + 3gy^2 + 3hx - 3iy + j = 0\n\n                // According to Alois Zingl \"A Rasterizing Algorithm for Drawing Curves\":\n                var Xa = ctrlsx[0] - 3 * ctrlsx[1] + 3 * ctrlsx[2] - ctrlsx[3];\n                var Xb = (ctrlsx[0] - ctrlsx[1] - ctrlsx[2] + ctrlsx[3]) / 2;\n                var Xc = (ctrlsx[0] + ctrlsx[1] - ctrlsx[2] - ctrlsx[3]) / 4;\n                var Xd = (ctrlsx[0] + 3 * ctrlsx[1] + 3 * ctrlsx[2] + ctrlsx[3]) / 8;\n                var Ya = ctrlsy[0] - 3 * ctrlsy[1] + 3 * ctrlsy[2] - ctrlsy[3];\n                var Yb = (ctrlsy[0] - ctrlsy[1] - ctrlsy[2] + ctrlsy[3]) / 2;\n                var Yc = (ctrlsy[0] + ctrlsy[1] - ctrlsy[2] - ctrlsy[3]) / 4;\n                var Yd = (ctrlsy[0] + 3 * ctrlsy[1] + 3 * ctrlsy[2] + ctrlsy[3]) / 8;\n\n                var Cac = Xa * Yc - Xc * Ya;\n                var Cab = Xa * Yb - Xb * Ya;\n                var Cbc = Xb * Yc - Xc * Yb;\n                var Cad = Xa * Yd - Xd * Ya;\n                var Cbd = Xb * Yd - Xd * Yb;\n                var Ccd = Xc * Yd - Xd * Yc;\n\n                var XaSqr = Xa * Xa;\n                var XbSqr = Xb * Xb;\n                var YaSqr = Ya * Ya;\n                var YbSqr = Yb * Yb;\n\n                var CacSqr = Cac * Cac;\n                var CadSqr = Cad * Cad;\n\n                var CabCbc = Cab * Cbc;\n                var CabCbd = Cab * Cbd;\n                var CabCac = Cab * Cac;\n\n                var mu1 = 3 * CabCbd - Cac * Cad;\n                var mu2 = 3 * CacSqr - Cab * (4 * Cad + 9 * Cbc);\n\n                var a = YaSqr * Ya;\n                var b = Xa * YaSqr;\n                var c = XaSqr * Ya;\n                var d = XaSqr * Xa;\n                var e = Cad * YaSqr - 3 * Ya * (2 * Cab * Yc + Cac * Yb) + 9 * Cab * YbSqr;\n                var f = (2 * Cad + 3 * Cbc) * Xa * Ya + 9 * (2 * Cab * Xb * Yb + Xb * Xc * YaSqr - XaSqr * Yb * Yc);\n                var g = Cad * XaSqr - 3 * (2 * Cab * Xc + Cac * Xb) * Xa + 9 * Cab * XbSqr;\n                var h = CadSqr * Ya + 6 * mu1 * Yb + 3 * mu2 * Yc + 9 * CabCac * Yd;\n                var i = CadSqr * Xa + 6 * mu1 * Xb + 3 * mu2 * Xc + 9 * CabCac * Xd;\n                var j = Cad * (CadSqr - 9 * (Cac * Cbd + 2 * Cab * Ccd)) + 27 * (CabCbd * Cbd + CacSqr * Ccd) - 81 * CabCbc * Ccd;\n\n                var XSqr = x * x;\n                var YSqr = y * y;\n\n                return (a * x - 3 * b * y + 3 * e) * XSqr + (3 * c * x - d * y + 3 * g) * YSqr + ((h - f * y) * x - i * y) * 3 + j;\n            }\n\n            function cHullCheck(x, y) {\n                var middlePtx = (ctrlsx[0] + ctrlsx[1] + ctrlsx[2] + ctrlsx[3]) / 4;\n                var middlePty = (ctrlsy[0] + ctrlsy[1] + ctrlsy[2] + ctrlsy[3]) / 4;\n                var s1;\n                var j;\n                var k;\n\n                for (j = 0; j < 4; ++j) {\n\n                    if (j == 3) {\n                        k = 0;\n                    }\n                    else {\n                        k = j + 1;\n                    }\n\n                    s1 = ifMath.segmentSide(ctrlsx[j], ctrlsy[j], ctrlsx[k], ctrlsy[k], x, y);\n                    if (j == 3 && s1 == 0) {\n                        return 0;\n                    }\n                    if (s1 * ifMath.segmentSide(ctrlsx[j], ctrlsy[j], ctrlsx[k], ctrlsy[k], middlePtx, middlePty) < 0) {\n                        return -1;\n                    }\n                }\n\n                return 1;\n            }\n\n            if (ifMath.isEqualEps(ctrlsx[0], ctrlsx[1]) && ifMath.isEqualEps(ctrlsy[0], ctrlsy[1])) {\n                tot += this._evalConicReg(ctrlsx[0], ctrlsy[0], ctrlsx[3], ctrlsy[3], ctrlsx[2], ctrlsy[2],\n                    cHullCheck, curvFunc, x, y);\n            }\n            else {\n                tot += this._evalConicReg(ctrlsx[0], ctrlsy[0], ctrlsx[3], ctrlsy[3], ctrlsx[1], ctrlsy[1],\n                    cHullCheck, curvFunc, x, y);\n            }\n        }\n\n        return tot;\n    };\n\n    /**\n     * Make a hit-test against a vertex source and a point.\n     * The vertex source will be automatically rewinded to the beginning.\n     * If orientation is not provided, inside will be defined automatically for even/odd fill of the shape\n     * @param {Number} x the x-position of the point to hit-test against\n     * @param {Number} y the y-position of the point to hit-test against\n     * @param {IFVertexSource} source the vertex source used for hit-testing\n     * @param {Number} outlineWidth the width of the outline. If this is\n     * zero, it is assumed that it is sqrt(ifMath.defaultEps)\n     * @param {Boolean} area if true, the fill area will be tested as well,\n     * otherwise only the outline will be considered\n     * @param {IFVertexInfo.HitResult} result if the function returns true, means\n     * a hit was found then this is the result structure that will be filled\n     * with the hit information\n     * @param {Boolean} orientationCW - true means that clock-wise orientation should be used,\n     * false - counter-clockwise, null - define orientation automatically\n\n     * @return {Boolean} true if a hit was made, false if not\n     * @version 1.0\n     */\n    IFVertexInfo.prototype.hitTest = function (x, y, source, outlineWidth, area, result, orientationCW) {\n        var px1, py1, px2, py2, cx1, cy1, pStartX, pStartY;\n        var chainIdx = 0;\n        var res = false;\n        var vertex = new IFVertex();\n        var sqrOutline = outlineWidth ? (outlineWidth / 2) * (outlineWidth / 2) : ifMath.defaultEps;\n        var tot = 0;\n        var xshift = 0;\n\n        pStartX = null;\n        pStartY = null;\n\n        // The approach is based on the paper of\n        // J. Ruiz de Miras and F. R. Feito \"Inclusion Test for Curved-Edge Polygons\"\n        // With the change while counting result: [-1, -1/2, 0, 1/2, 1] -> [-2, -1, 0, 1, 2]\n\n        // if x == 0 and y == 0, everything must be shifted for inside testing\n        if (ifMath.isEqualEps(x, 0.0) && ifMath.isEqualEps(y, 0.0)) {\n            xshift = 1;\n        }\n\n        if (source.rewindVertices(0)) {\n            // iterate through curves\n            while (source.readVertex(vertex)) {\n                switch (vertex.command) {\n                    case IFVertex.Command.Move:\n                        px1 = vertex.x;\n                        py1 = vertex.y;\n                        pStartX = px1;\n                        pStartY = py1;\n                        break;\n\n                    case IFVertex.Command.Line:\n                        ++chainIdx;\n                        res = this._hitTestSegment(px1, py1, vertex.x, vertex.y, x, y, sqrOutline, chainIdx, result);\n                        if (res) {\n                            return res;\n                        }\n                        if (area) {\n                            tot += this._hitUnderSegment(px1 + xshift, py1, vertex.x + xshift, vertex.y,\n                                x + xshift, y);\n                        }\n                        px1 = vertex.x;\n                        py1 = vertex.y;\n                        break;\n\n                    case IFVertex.Command.Curve:\n                        ++chainIdx;\n                        px2 = vertex.x;\n                        py2 = vertex.y;\n                        if (source.readVertex(vertex)) {\n                            res = this._hitTestCurve(px1, py1, px2, py2, vertex.x, vertex.y,\n                                x, y, sqrOutline, chainIdx, result);\n                            if (res) {\n                                return res;\n                            }\n                            if (area) {\n                                tot += this._hitUnderCurve(px1 + xshift, py1, px2 + xshift, py2,\n                                    vertex.x + xshift, vertex.y, x + xshift, y);\n                            }\n                            px1 = px2;\n                            py1 = py2;\n                        }\n                        break;\n\n                    case IFVertex.Command.Curve2:\n                        ++chainIdx;\n                        px2 = vertex.x;\n                        py2 = vertex.y;\n                        if (source.readVertex(vertex)) {\n                            // Save first control point here\n                            cx1 = vertex.x;\n                            cy1 = vertex.y;\n                            if (source.readVertex(vertex)) {\n                                res = this._hitTestCurve2(px1, py1, px2, py2, cx1, cy1,\n                                    vertex.x, vertex.y, x, y, sqrOutline, chainIdx, result);\n                                if (res) {\n                                    return res;\n                                }\n                                if (area) {\n                                    tot += this._hitUnderCurve2(px1 + xshift, py1, px2 + xshift, py2, cx1 + xshift, cy1,\n                                        vertex.x + xshift, vertex.y, x + xshift, y);\n                                }\n                                px1 = px2;\n                                py1 = py2;\n                            }\n                        }\n                        break;\n\n                    case IFVertex.Command.Close:\n                        if (pStartX != px1 || pStartY != py1) {\n                            ++chainIdx;\n                            res = this._hitTestSegment(px1, py1, pStartX, pStartY, x, y, sqrOutline, chainIdx, result);\n                            if (res) {\n                                return res;\n                            }\n                            if (area) {\n                                tot += this._hitUnderSegment(px1 + xshift, py1, pStartX + xshift, pStartY,\n                                    x + xshift, y);\n                            }\n                        }\n                        pStartX = px1;\n                        pStartY = py1;\n                        break;\n\n                    default:\n                        throw new Error(\"Unknown vertex command: \" + vertex.command.toString());\n                } // switch\n            } // while\n\n            if (area) {\n                if (orientationCW == null && (tot == 2 || tot == -2) ||\n                        tot == 2 && !orientationCW || tot == -2 && orientationCW) {\n\n                    if (result) {\n                        result.outline = false;\n                    }\n                    res = true;\n                }\n            }\n        }\n\n        return res;\n    };\n\n    /**\n     * Calculate bounding box for a vertex source. The vertex source will\n     * be automatically rewinded to the beginning.\n     * @param {IFVertexSource} source the vertex source used for calculation\n     * @param {Boolean} exact if true, the bounding box will include exact\n     * curve calculation, otherwise if false, the bounding box will include\n     * the max. bbox also surrounding any curve control points\n     * @return {IFRect} the calculated bounds rect, this might be null if\n     * there're no valid bounds available as well as this might be an\n     * empty rectangle if segments are at the same position or too less.\n     * @version 1.0\n     */\n    IFVertexInfo.prototype.calculateBounds = function (source, exact) {\n        if (source.rewindVertices(0)) {\n            var minX = null;\n            var minY = null;\n            var maxX = null;\n            var maxY = null;\n\n            function measurePoint(x, y) {\n                if (minX == null || x < minX) {\n                    minX = x;\n                }\n                if (maxX == null || x > maxX) {\n                    maxX = x;\n                }\n\n                if (minY == null || y < minY) {\n                    minY = y;\n                }\n                if (maxY == null || y > maxY) {\n                    maxY = y;\n                }\n            };\n\n            function measureCurve(px1, py1, px2, py2, cx, cy) {\n                var t = 0;\n                var s = 0;\n                var px = 0;\n                var py = 0;\n\n                measurePoint(px2, py2);\n\n                // P(t) = t^2(P2 - 2C + P1) + 2t(C-P1) + P1\n                // P' = 2t(P2 - 2C + P1) + 2(C-P1)\n                // P'x == 0 when tangent to vertical border, and P'y == 0 when tangent to horizontal border,\n                // t = (P1 - C) / (P2 - 2C + P1), P = (P1*P2 -C^2) / (P2 - 2C + P1)\n\n                // when cx in the middle of [px1,px2], P(t)x is linear,\n                // no single tangent point to vertical border between P1 and P2,\n                // so not interested in this case\n                s = px2 - 2 * cx + px1;\n                if (s != 0) {\n                    t = (px1 - cx) / s;\n                    if (t > 0 && t < 1) {\n                        px = (px1 * px2 - cx * cx) / (px2 - 2 * cx + px1);\n                        py = ifMath.getCurveAtT(py1, py2, cy, t);\n                        measurePoint(px, py);\n                    }\n                }\n\n                // when cy in the middle of [py1,py2], P(t)y is linear,\n                // no single tangent point to horizontal border between P1 and P2,\n                // so not interested in this case\n                s = py2 - 2 * cy + py1;\n                if (s != 0) {\n                    t = (py1 - cy) / s;\n                    if (t > 0 && t < 1) {\n                        py = (py1 * py2 - cy * cy) / (py2 - 2 * cy + py1);\n                        px = ifMath.getCurveAtT(px1, px2, cx, t);\n                        measurePoint(px, py);\n                    }\n                }\n            };\n\n            function measureCurve2(px1, py1, px2, py2, cx1, cy1, cx2, cy2) {\n                var t = 0;\n                var s = 0;\n                var px = 0;\n                var py = 0;\n\n                measurePoint(px2, py2);\n\n                // P(t) = P1 + 3t(C1 - P1) + 3t^2*(C2 - 2C1 + P1) + t^3*(P2 - 3C2 + 3C1 - P1)\n                // P' =3(C1 - P1) + 6t(C2 - 2C1 + P1) + 3t^2*(P2 - 3C2 + 3C1 - P1)\n                // P'x == 0 when tangent to vertical border, and P'y == 0 when tangent to horizontal border,\n                // Cubic curve may have 'spike' inflate point, but in it also P'x = 0 and P'y = 0\n\n                var cx = cx1 - px1;\n                var cy = cy1 - py1;\n                var bx = 2 * (cx2 - cx1 - cx);\n                var by = 2 * (cy2 - cy1 - cy);\n                var ax = px2 - cx2 - cx - bx;\n                var ay = py2 - cy2 - cy - by;\n                // P' = 3(at^2 + bt + c)\n\n                function measureAtT(t) {\n                    var px = 0;\n                    var py = 0;\n\n                    if (t > 0 && t < 1) {\n                        px = ifMath.getCubicCurveAtT(px1, px2, cx1, cx2, t);\n                        py = ifMath.getCubicCurveAtT(py1, py2, cy1, cy2, t);\n                        measurePoint(px, py);\n                    }\n                };\n\n                function measureAtRoot(a, b, c) {\n                    var discr = 0;\n                    var sd = 0;\n\n                    if (a == 0) {\n                        if (b != 0) // otherwise, P(t) is linear by x or y, no interest points between 0 and 1\n                        {\n                            t = -c / b;\n                            measureAtT(t);\n                        }\n                    }\n                    else {\n                        discr = b * b - 4 * a * c;\n                        if (discr == 0) {\n                            t = -b / (2 * a);\n                            measureAtT(t);\n                        }\n                        else if (discr > 0) {\n                            sd = Math.sqrt(discr);\n                            t = (-b + sd) / (2 * a);\n                            measureAtT(t);\n                            t = (-b - sd) / (2 * a);\n                            measureAtT(t);\n                        }\n                    }\n                };\n\n                measureAtRoot(ax, bx, cx);\n                measureAtRoot(ay, by, cy);\n            }\n\n            var vertex = new IFVertex();\n\n            var px1, py1, px2, py2, cx1, cy1;\n\n            while (source.readVertex(vertex)) {\n                switch (vertex.command) {\n                    case IFVertex.Command.Move:\n                    case IFVertex.Command.Line:\n                        measurePoint(vertex.x, vertex.y);\n                        px1 = vertex.x;\n                        py1 = vertex.y;\n                        break;\n\n                    case IFVertex.Command.Curve:\n                        px2 = vertex.x;\n                        py2 = vertex.y;\n                        if (source.readVertex(vertex)) {\n                            if (exact) {\n                                measureCurve(px1, py1, px2, py2, vertex.x, vertex.y);\n                            } else {\n                                measurePoint(px2, py2);\n                                measurePoint(vertex.x, vertex.y);\n                            }\n                            px1 = px2;\n                            py1 = py2;\n                        }\n                        break;\n\n                    case IFVertex.Command.Curve2:\n                        px2 = vertex.x;\n                        py2 = vertex.y;\n                        if (source.readVertex(vertex)) {\n                            // Save first control point here\n                            cx1 = vertex.x;\n                            cy1 = vertex.y;\n                            if (source.readVertex(vertex)) {\n                                if (exact) {\n                                    measureCurve2(px1, py1, px2, py2, cx1, cy1, vertex.x, vertex.y);\n                                } else {\n                                    measurePoint(px2, py2);\n                                    measurePoint(cx1, cy1);\n                                    measurePoint(vertex.x, vertex.y);\n                                }\n                                px1 = px2;\n                                py1 = py2;\n                            }\n                        }\n                        break;\n\n                    case IFVertex.Command.Close:\n                        break;\n\n                    default:\n                        throw new Error(\"Unknown vertex command: \" + vertex.command.toString());\n                }\n            }\n\n            if (minX != null && minY != null) {\n                return new IFRect(minX, minY, maxX != null ? maxX - minX : 0, maxY != null ? maxY - minY : 0);\n            }\n        }\n        return null;\n    };\n\n    /** @override */\n    IFVertexInfo.prototype.toString = function () {\n        return \"[Object IFVertexInfo]\";\n    };\n\n    _.IFVertexInfo = IFVertexInfo;\n    _.ifVertexInfo = new IFVertexInfo();\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertexoffsetter.js",
    "content": "(function (_) {\n    /**\n     * @class IFVertexOffsetter\n     * @extends IFVertexSource\n     * @param {IFVertexSource} source the underyling vertex source to work on\n     * @param {Number} offset - the distance at which offset should be calculated\n     * @param {Boolean} inset - indicates if an inset is required\n     * @param {Boolean} outset - indicates if an outset is required\n     * @param {Number} tol - offset approximation tolerance value (preciseness)\n     * @constructor\n     */\n    function IFVertexOffsetter(source, offset, inset, outset, tol) {\n        this._tolerance = tol ? tol / 3 : 0.03;\n        this._source = source;\n        this._offset = offset;\n        this._makeInset = inset;\n        this._makeOutset = outset;\n        this._startVertex = null;\n        var tolRange = 1;\n        var tol = this._tolerance;\n        for (var i = 0; tol < 1; ++i) {\n            tol *= 10;\n            tolRange *= 10;\n        }\n        this._tolRange = tolRange;\n    }\n\n    IFObject.inherit(IFVertexOffsetter, IFVertexSource);\n\n    IFVertexOffsetter.MAX_RECURS = 100;\n\n    /**\n     *\n     * @param {IFPoint} point\n     * @param {Number} bulge\n     * @param {IFPoint} center\n     * @param {Number} radius\n     * @constructor\n     */\n    IFVertexOffsetter.PolySegment = function (point, bulge, center, radius) {\n        this.point = point;\n\n        if (bulge != null) {\n            this.bulge = bulge;\n            if (bulge) {\n                if (!center || !radius || radius < 0) {\n                    return;\n                }\n                this.center = center;\n                this.radius = radius;\n            }\n        }\n    };\n\n    IFVertexOffsetter.PolySegment.prototype.point = null;\n\n    IFVertexOffsetter.PolySegment.prototype.bulge = null;\n\n    IFVertexOffsetter.PolySegment.prototype.center = null;\n\n    IFVertexOffsetter.PolySegment.prototype.radius = null;\n\n    IFVertexOffsetter.PolySegment.prototype.next = null;\n\n    IFVertexOffsetter.PolySegment.prototype.previous = null;\n\n    IFVertexOffsetter.PolyOffsetSegment = function (basepoint, point1, point2, bulge, center, radius) {\n        IFVertexOffsetter.PolySegment.call(this, point1, bulge, center, radius);\n        this.basepoint = basepoint;\n        if (point2) {\n            this.point2 = point2;\n        }\n    };\n    IFObject.inherit(IFVertexOffsetter.PolyOffsetSegment, IFVertexOffsetter.PolySegment);\n\n    IFVertexOffsetter.PolyOffsetSegment.prototype.basepoint = null;\n\n    IFVertexOffsetter.PolyOffsetSegment.prototype.point2 = null;\n\n    IFVertexOffsetter.IntersectionType = function () {\n    };\n\n    /**\n     * If intersection point is a True Intersection Point\n     * @type {boolean}\n     */\n    IFVertexOffsetter.IntersectionType.prototype.TIP = false;\n\n    /**\n     * If intersection point is a False Intersection Point\n     * @type {boolean}\n     */\n    IFVertexOffsetter.IntersectionType.prototype.FIP = false;\n\n    /**\n     * If intersection point is a Positive False Intersection Point\n     * Otherwise if point FIP and not PFIP, it is considered NFIP (Negative False Intersection Point)\n     * @type {boolean}\n     */\n    IFVertexOffsetter.IntersectionType.prototype.PFIP = false;\n\n    IFVertexOffsetter.IntersectionResult = function () {\n        this.intTypes = [new IFVertexOffsetter.IntersectionType(), new IFVertexOffsetter.IntersectionType()];\n    };\n\n    /**\n     * Intersection point\n     * @type {IFPoint}\n     */\n    IFVertexOffsetter.IntersectionResult.prototype.point = null;\n\n    /**\n     * Intersection types (IFVertexOffsetter.IntersectionType) of both segments\n     * @type {Array}\n     */\n    IFVertexOffsetter.IntersectionResult.prototype.intTypes = null;\n\n    IFVertexOffsetter.IntersectionResult.prototype.clear = function () {\n        this.point = null;\n        this.intTypes[0].TIP = false;\n        this.intTypes[0].FIP = false;\n        this.intTypes[0].PFIP = false;\n        this.intTypes[1].TIP = false;\n        this.intTypes[1].FIP = false;\n        this.intTypes[1].PFIP = false;\n    };\n\n    IFVertexOffsetter.PolySegmentContainer = function () {\n        this.count = 0;\n    };\n\n    IFVertexOffsetter.PolySegmentContainer.prototype.head = null;\n\n    IFVertexOffsetter.PolySegmentContainer.prototype.end = null;\n\n    IFVertexOffsetter.PolySegmentContainer.prototype.closed = null;\n\n    IFVertexOffsetter.PolySegmentContainer.prototype.count = 0;\n\n    IFVertexOffsetter.PolySegmentContainer.prototype.insertSegment = function (polySegment, next) {\n        polySegment.next = null;\n        polySegment.previous = null;\n        if (!this.head) {\n            this.head = polySegment;\n            this.end = polySegment;\n        } else if (next) {\n            if (this.head == next) {\n                this.head = polySegment;\n            } else {\n                polySegment.previous = next.previous;\n                next.previous.next = polySegment;\n            }\n            polySegment.next = next;\n            next.previous = polySegment;\n        } else {\n            this.end.next = polySegment;\n            polySegment.previous = this.end;\n            this.end = polySegment;\n        }\n        ++this.count;\n    };\n\n    IFVertexOffsetter.PolySegmentContainer.prototype.deleteSegment = function (polySegment) {\n        if (polySegment.previous) {\n            polySegment.previous.next = polySegment.next;\n        }\n        if (polySegment.next) {\n            polySegment.next.previous = polySegment.previous;\n        }\n        if (this.head == polySegment) {\n            this.head = polySegment.next;\n        }\n        if (this.end == polySegment) {\n            this.end = polySegment.previous;\n        }\n        --this.count;\n    };\n\n    IFVertexOffsetter.IntersectionPt = function (x, y, slope, segment, idx) {\n        this.x = x;\n        this.y = y;\n        this.slope = slope;\n        this.segm = segment;\n        this.segmIdx = idx;\n    };\n\n    IFVertexOffsetter.IntersectionPt.prototype.x = null;\n    IFVertexOffsetter.IntersectionPt.prototype.y = null;\n    IFVertexOffsetter.IntersectionPt.prototype.slope = null;\n    IFVertexOffsetter.IntersectionPt.prototype.segm = null;\n    IFVertexOffsetter.IntersectionPt.prototype.segmIdx = null;\n\n    /**\n     * @type {IFVertexSource}\n     * @private\n     */\n    IFVertexOffsetter.prototype._source = null;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFVertexOffsetter.prototype._offset = null;\n\n    /**\n     * @type {Boolean}\n     * @private\n     */\n    IFVertexOffsetter.prototype._makeInset = false;\n\n    /**\n     * @type {Boolean}\n     * @private\n     */\n    IFVertexOffsetter.prototype._makeOutset = false;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFVertexOffsetter.prototype._tolerance = null;\n\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFVertexOffsetter.prototype._tolRange = 1;\n\n    /**\n     *\n     * @type {IFVertexOffsetter.PolySegmentContainer}\n     * @private\n     */\n    IFVertexOffsetter.prototype._polyline = null;\n\n    IFVertexOffsetter.prototype._polyinset = null;\n\n    IFVertexOffsetter.prototype._polyoutset = null;\n\n    IFVertexOffsetter.prototype._pieces = null;\n\n    IFVertexOffsetter.prototype._pieceIdx = 0;\n\n    /**\n     * Stores the new path start position when 'Close' or 'Move' is used in the middle of vertex sequence\n     * @type {IFVertex}\n     * @private\n     */\n    IFVertexOffsetter.prototype._startVertex = null;\n\n    /** @override */\n    IFVertexOffsetter.prototype.rewindVertices = function (index) {\n        if (index != 0) {\n            return false;\n        }\n        this._pieces= null;\n        this._pieceIdx = 0;\n        this._startVertex = null;\n\n        return this._source.rewindVertices(0);\n    };\n\n    /** override */\n    IFVertexOffsetter.prototype.readVertex = function (vertex) {\n        if (this._pieces && this._pieces.length && this._readVertex(vertex)) {\n            return true;\n        }\n\n        this._polyline = new IFVertexOffsetter.PolySegmentContainer();\n        this._polyoutset = [];\n        this._polyinset = [];\n        this._pieces = [];\n        this._pieceIdx = 0;\n        this._startVertex = this.generatePolyLine(this._tolerance, this._startVertex);\n\n        if (this._polyline.count) {\n            this.generatePolyOffset(Math.abs(this._offset), this._makeInset, this._makeOutset, this._tolerance);\n            this.generateOffset(this._makeInset, this._makeOutset, this._tolerance);\n            if (this._pieces.length) {\n                this._rewindVertices();\n                this._pieceIdx = 0;\n            }\n\n            if (this._pieces && this._pieces.length && this._readVertex(vertex)) {\n                return true;\n            }\n        }\n\n        return false;\n    };\n\n    /**\n     *\n     * @param {IFPoint} B0 - a start point of Quadratic Bezier curve\n     * @param {IFPoint} B1 - a control point of Quadratic Bezier curve\n     * @param {IFPoint} B2 - an end point of Quadratic Bezier curve\n     * @param {Number} tolerance\n     * @param {Number} counter\n     */\n    IFVertexOffsetter.prototype.addCurveToPolyline = function (B0, B1, B2, tolerance, counter) {\n        ++counter;\n\n        // 1. Approximation of quadratic Bezier curves by arc splines\n        // D.J. Walton, D.S. Meek, 1992\n        //\n        // 2. An offset algorithm for polyline curves\n        // Xu-Zheng Liu, Jun-Hai Yong, Guo-Qin Zheng, Jia-Guang Sun, 2006\n        //\n        // 3. Modeling of Bézier Curves Using a Combination of Linear and Circular Arc Approximations\n        // P. Kaewsaiha, N. Dejdumrong, 2012\n\n        // 0. Try segment approximation\n        if (this._isQudraticCurveFlat(B0, B1, B2, tolerance)) {\n            var segm = new IFVertexOffsetter.PolySegment(B0, 0);\n            this._polyline.insertSegment(segm);\n            return;\n        }\n\n        // 1. approximate curve by bi-arc\n        var a = ifMath.ptDist(B0.getX(), B0.getY(), B1.getX(), B1.getY());\n        var b = ifMath.ptDist(B1.getX(), B1.getY(), B2.getX(), B2.getY());\n        var d = ifMath.ptDist(B0.getX(), B0.getY(), B2.getX(), B2.getY());\n        // TODO: check for zeros\n        var T0 = new IFPoint((B1.getX() - B0.getX()) / a, (B1.getY() - B0.getY()) / a);\n        var T1 = new IFPoint((B2.getX() - B1.getX()) / b, (B2.getY() - B1.getY()) / b);\n        var T = new IFPoint((B2.getX() - B0.getX()) / d, (B2.getY() - B0.getY()) / d);\n        var cosEtha = ifMath.vDotProduct(T0.getX(), T0.getY(), T1.getX(), T1.getY());\n\n        // D(u) = a*(T1 - T0*cosEtha) + ((a*cosEtha - b)T0 + (b*cosEtha - a)T1)*u\n        // N(u) = D(u) / ||D(u)||\n        var D0 = new IFPoint(a * (T1.getX() - T0.getX() * cosEtha), a * (T1.getY() - T0.getY() * cosEtha));\n        var tmp1 = a * cosEtha - b;\n        var tmp2 = b * cosEtha - a;\n        var D1 = new IFPoint(\n            D0.getX() + tmp1 * T0.getX() + tmp2 * T1.getX(), D0.getY() + tmp1 * T0.getY() + tmp2 * T1.getY());\n\n        tmp1 = Math.sqrt(ifMath.vDotProduct(D0.getX(), D0.getY(), D0.getX(), D0.getY()));\n        tmp2 = Math.sqrt(ifMath.vDotProduct(D1.getX(), D1.getY(), D1.getX(), D1.getY()));\n        // TODO: check for zeros\n        var N0 = new IFPoint(D0.getX() / tmp1, D0.getY() / tmp1);\n        var N1 = new IFPoint(D1.getX() / tmp2, D1.getY() / tmp2);\n\n        // f(s) = a1*s^2 + b1*s + c1\n        // f(s) = (1 - cosEtha)s^2 + (T1N0 * TT0 / TN0 + T0N1 * TT1 / TN1)s - 0.5 * (T1N0 * T0N1) / (TN0 * TN1)\n        // f(s) = 0\n        // lambda*T0N1 = s*d*TN1\n        // myu*T1N0 = s*d*TN0\n        var a1 = 1 - cosEtha;\n        var T1N0 = ifMath.vDotProduct(T1.getX(), T1.getY(), N0.getX(), N0.getY());\n        var TT0 = ifMath.vDotProduct(T.getX(), T.getY(), T0.getX(), T0.getY());\n        var TN0 = ifMath.vDotProduct(T.getX(), T.getY(), N0.getX(), N0.getY());\n        var T0N1 = ifMath.vDotProduct(T0.getX(), T0.getY(), N1.getX(), N1.getY());\n        var TT1 = ifMath.vDotProduct(T.getX(), T.getY(), T1.getX(), T1.getY());\n        var TN1 = ifMath.vDotProduct(T.getX(), T.getY(), N1.getX(), N1.getY());\n        var b1 = T1N0 * TT0 / TN0 + T0N1 * TT1 / TN1;\n        var c1 = -(T1N0 * T0N1) / (TN0 * TN1 * 2);\n        var roots = [];\n        ifMath.getQuadraticRoots(a1, b1, c1, roots);\n        var s = null;\n        if (roots[0] != null && roots[0] < 1 && roots[0] > 0) {\n            s = roots[0];\n        } else if (roots[1] != null && roots[1] < 1 && roots[1] > 0) {\n            s = roots[1];\n        } else {\n            // TODO: go away\n        }\n\n        // TODO: check for zeros\n        var lambda = s*d*TN1 / T0N1;\n        var myu = s*d*TN0 / T1N0;\n\n        // V = B0 + lambda*T0\n        // G = V + lambda*T\n        // W = B2 - myu*T1\n        // G is incentre of B0B1B2 =>\n        // gamma = phi/2, cos(phi) = TT0, sin(gamma) = sqrt((1 - cos(phi)) / 2),\n        // cos(gamma) = sqrt((1 + cos(phi)) / 2), Rb0 = lambda * cos(gamma) / sin(gamma),\n        // psi = theta/2, cos(theta) = TT1, sin(gamma) = sqrt((1 - cos(theta)) / 2),\n        // cos(gamma) = sqrt((1 + cos(theta)) / 2), Rb2 = myu * cos(psi) / sin(psi),\n        var sinGamma = Math.sqrt((1 - TT0) / 2);\n        var cosGamma = Math.sqrt((1 + TT0) / 2);\n        var Rb0 = lambda * cosGamma / sinGamma;\n        var sinPsi = Math.sqrt((1 - TT1) / 2);\n        var cosPsi = Math.sqrt((1 + TT1) / 2);\n        var Rb2 = myu * cosPsi / sinPsi;\n        var C0 = new IFPoint(B0.getX() + Rb0 * N0.getX(), B0.getY() + Rb0 * N0.getY());\n        var C1 = new IFPoint(B2.getX() + Rb2 * N1.getX(), B2.getY() + Rb2 * N1.getY());\n\n        // 2. measure dist\n        // By Theorem 2: sigma from (0,1): g(u) = (d - 2a*cos(phi))u^2 + 2a*cos(phi)u - lambda*(1 + cos(phi)) = 0\n        tmp1 = 2 * a * TT0;\n        roots = [];\n        ifMath.getQuadraticRoots(d - tmp1, tmp1, -lambda * (1 + TT0), roots);\n        var sigma = 0.5;\n        if (roots[0] != null && roots[0] < 1 && roots[0] > 0) {\n            sigma = roots[0];\n        } else if (roots[1] != null && roots[1] < 1 && roots[1] > 0) {\n            sigma = roots[1];\n        } else {\n            // TODO: go away\n        }\n        var sinPhi = Math.sqrt(1 - TT0 * TT0);\n        var kSigma = Math.abs((2*a*sigma*(1 - sigma) - lambda) * sinPhi);\n\n        // By Theorem 3:\n        // t01, t02:\n        // z0(u) = (a^2 + b^2 - a*b*cos(etha))*u^2 + 3a(b*cos(etha) - a)u + 2a^2 - Rb0*b*sin(etha) = 0\n        // t11, t12:\n        // z1(u) = (a^2 + b^2 - a*b*cos(etha))*u^2 + (-2a^2 + b^2 +ab*cos(etha))u + a^2 + ab*cos(etha) - Rb2*a*sin(etha) = 0\n        // rho0(u) = abs(Rb0 - ||Q(u) - C0||)\n        // rho1(u) = abs(Rb2 - ||Q(u) - C1||)\n        // delta = max(kSigma, rho0(t01), rho0(t02), rho(t11), rho(t12))\n        var aSqr = a * a;\n        var bSqr = b * b;\n        var abcosEtha = a * b * cosEtha;\n        tmp1 = aSqr + bSqr - abcosEtha;\n        var sinEtha = Math.sqrt(1 - cosEtha * cosEtha);\n        var delta = kSigma;\n        var tMax = sigma;\n        roots = [];\n        ifMath.getQuadraticRoots(tmp1, 3 * (abcosEtha - aSqr), 2 * aSqr - Rb0 * b * sinEtha, roots);\n        if (roots[0] != null && roots[0] < sigma && roots[0] > 0) {\n            var Qt01 = new IFPoint(ifMath.getCurveAtT(B0.getX(), B2.getX(), B1.getX(), roots[0]),\n                ifMath.getCurveAtT(B0.getY(), B2.getY(), B1.getY(), roots[0]));\n            var pho01 = Math.abs(Rb0 - ifMath.ptDist(Qt01.getX(), Qt01.getY(), C0.getX(), C0.getY()));\n            if (delta < pho01) {\n                delta = pho01;\n                tMax = roots[0];\n            }\n        }\n        if (roots[1] != null && roots[1] < sigma && roots[1] > 0) {\n            var Qt02 = new IFPoint(ifMath.getCurveAtT(B0.getX(), B2.getX(), B1.getX(), roots[1]),\n                ifMath.getCurveAtT(B0.getY(), B2.getY(), B1.getY(), roots[1]));\n            var pho02 = Math.abs(Rb0 - ifMath.ptDist(Qt02.getX(), Qt02.getY(), C0.getX(), C0.getY()));\n            if (delta < pho02) {\n                delta = pho02;\n                tMax = roots[1];\n            }\n        }\n\n        roots = [];\n        ifMath.getQuadraticRoots(tmp1, -2 * aSqr + bSqr + abcosEtha, aSqr + abcosEtha - Rb2 * a * sinEtha, roots);\n        if (roots[0] != null && roots[0] < 1 && roots[0] > sigma) {\n            var Qt11 = new IFPoint(ifMath.getCurveAtT(B0.getX(), B2.getX(), B1.getX(), roots[0]),\n                ifMath.getCurveAtT(B0.getY(), B2.getY(), B1.getY(), roots[0]));\n            var pho11 = Math.abs(Rb2 - ifMath.ptDist(Qt11.getX(), Qt11.getY(), C1.getX(), C1.getY()));\n            if (delta < pho11) {\n                delta = pho11;\n                tMax = roots[0];\n            }\n        }\n        if (roots[1] != null && roots[1] < 1 && roots[1] > sigma) {\n            var Qt12 = new IFPoint(ifMath.getCurveAtT(B0.getX(), B2.getX(), B1.getX(), roots[1]),\n                ifMath.getCurveAtT(B0.getY(), B2.getY(), B1.getY(), roots[1]));\n            var pho12 = Math.abs(Rb2 - ifMath.ptDist(Qt12.getX(), Qt12.getY(), C1.getX(), C1.getY()));\n            if (delta < pho12) {\n                delta = pho12;\n                tMax = roots[1];\n            }\n        }\n\n        // 3. if delta > tolerance => divide && repeat;\n        // else => add bi-arc to polyline\n        if (delta > tolerance && counter < IFVertexOffsetter.MAX_RECURS) {\n            var ctrls1X = new Float64Array(3);\n            var ctrls1Y = new Float64Array(3);\n            var ctrls2X = new Float64Array(3);\n            var ctrls2Y = new Float64Array(3);\n            ifMath.divideQuadraticCurve(B0.getX(), B1.getX(), B2.getX(), tMax, ctrls1X, ctrls2X);\n            ifMath.divideQuadraticCurve(B0.getY(), B1.getY(), B2.getY(), tMax, ctrls1Y, ctrls2Y);\n            this.addCurveToPolyline(B0, new IFPoint(ctrls1X[1], ctrls1Y[1]), new IFPoint(ctrls1X[2], ctrls1Y[2]), tolerance, counter);\n            this.addCurveToPolyline(new IFPoint(ctrls2X[0], ctrls2Y[0]), new IFPoint(ctrls2X[1], ctrls2Y[1]), B2, tolerance, counter);\n        } else {\n            // V = B0 + lambda*T0\n            // G = V + lambda*T\n            var G = new IFPoint(B0.getX() + lambda * (T0.getX() + T.getX()), B0.getY() + lambda * (T0.getY() + T.getY()));\n\n            // Define curve orientation\n            // We can check arc center location against B0G\n            var tgHalfGamma = sinGamma / (cosGamma + 1);\n            if (ifMath.segmentSide(B0.getX(), B0.getY(), G.getX(), G.getY(), C0.getX(), C0.getY()) > 0) {\n                tgHalfGamma = -tgHalfGamma;\n            }\n            var segm = new IFVertexOffsetter.PolySegment(B0, tgHalfGamma, C0, Rb0);\n            this._polyline.insertSegment(segm);\n            var tgHalfPsi = sinPsi / (cosPsi + 1);\n            if (tgHalfGamma < 0) {\n                tgHalfPsi = -tgHalfPsi;\n            }\n            segm = new IFVertexOffsetter.PolySegment(G, tgHalfPsi, C1, Rb2);\n            this._polyline.insertSegment(segm);\n        }\n    };\n\n    /**\n     *\n     * @param {IFPoint} B0 - a start point of cubic Bezier curve\n     * @param {IFPoint} B1 - the first control point of cubic Bezier curve\n     * @param {IFPoint} B2 - the second control point of cubic Bezier curve\n     * @param {IFPoint} B3 - an end point of cubic Bezier curve\n     * @param {Number} tolerance\n     */\n    IFVertexOffsetter.prototype.addCubicCurveToPolyline = function (B0, B1, B2, B3, tolerance) {\n        // 1. Approximation of a planar cubic Bezier spiral by circular arcs\n        // D.J. Walton, D.S. Meek, 1996\n        //\n        // 2. APPROXIMATION OF A CUBIC BEZIER CURVE BY CIRCULAR ARCS AND VICE VERSA\n        // A. Riškus, 2006\n        //\n        // 3. An offset algorithm for polyline curves\n        // Xu-Zheng Liu, Jun-Hai Yong, Guo-Qin Zheng, Jia-Guang Sun, 2006\n        //\n        // 4. Modeling of Bézier Curves Using a Combination of Linear and Circular Arc Approximations\n        // P. Kaewsaiha, N. Dejdumrong, 2012\n        //\n        // For dividing a cubic Bezier curve the approach A1 && S1 from the document 2 will be used, while the\n        // whole algorithm will be taken from the document 4.\n\n        // 1. Find initial interval (curve) splitPoints at [0, 1],\n        // which are curve inflate points, or such points,\n        // that P'x = 0 or P'y = 0\n        var cx = B1.getX() - B0.getX();\n        var cy = B1.getY() - B0.getY();\n        var bx = 2 * (B2.getX() - B1.getX() - cx);\n        var by = 2 * (B2.getY() - B1.getY() - cy);\n        var ax = B3.getX() - B2.getX() - cx - bx;\n        var ay = B3.getY() - B2.getY() - cy - by;\n        var sPts = [];\n        var nPoints = ifMath.getCubicCurveSplits(ax, bx, cx, ay, by, cy, sPts);\n\n        // 2. Based on splitPoints iterate through intervals,\n        // and for each interval perform the curve approximation with a biArc:\n        var t1, t2;\n        var ctrlsx = new Float64Array(4);\n        var ctrlsy = new Float64Array(4);\n        for (var i = 0; i < nPoints - 1; ++i) {\n            t1 = sPts[i];\n            t2 = sPts[i + 1];\n            ifMath.getCtrlPts(B0.getX(), B3.getX(), B1.getX(), B2.getX(), t1, t2, ctrlsx);\n            ifMath.getCtrlPts(B0.getY(), B3.getY(), B1.getY(), B2.getY(), t1, t2, ctrlsy);\n            var counter = 0;\n            this._addCubicSegmToPolyline(ctrlsx, ctrlsy, tolerance, counter);\n        }\n    };\n\n    IFVertexOffsetter.prototype._isQudraticCurveFlat = function (B0, B1, B2, tolerance) {\n        var xB = ifMath.getCurveAtT(B0.getX(), B2.getX(), B1.getX(), 0.5);\n        var yB = ifMath.getCurveAtT(B0.getY(), B2.getY(), B1.getY(), 0.5);\n        var dst = ifMath.ptSqrDist(xB, yB, (B0.getX() + B2.getX()) / 2, (B0.getY() + B2.getY()) / 2);\n        return (dst <= tolerance * tolerance);\n    };\n\n    IFVertexOffsetter.prototype._isCubicCurveFlat = function (ctrlsx, ctrlsy, tolerance) {\n        // Piecewise Linear Approximation of Bezier Curves\n        // Kaspar Fischer, 2000\n        // (approved for publication part of algorithm with copyright by Roger Willcocks)\n        var ux = 3.0 * ctrlsx[1] - 2.0 * ctrlsx[0] - ctrlsx[3];\n        ux *= ux;\n        var uy = 3.0 * ctrlsy[1] - 2.0 * ctrlsy[0] - ctrlsy[3];\n        uy *= uy;\n        var vx = 3.0 * ctrlsx[2] - 2.0 * ctrlsx[3] - ctrlsx[0];\n        vx *= vx;\n        var vy = 3.0 * ctrlsy[2] - 2.0 * ctrlsy[3] - ctrlsy[0];\n        vy *= vy;\n        if (ux < vx) {\n            ux = vx;\n        }\n        if (uy < vy) {\n            uy = vy;\n        }\n        return (ux + uy <= 16 * tolerance * tolerance);\n    };\n    \n    /**\n     *\n     * @param {Float64Array(4)} ctrlsx - array of X coordinates of the control points\n     * @param {Float64Array(4)} ctrlsy - array of Y coordinates of the control points\n     * @param {Number} tolerance\n     * @param {Number} counter\n     */\n    IFVertexOffsetter.prototype._addCubicSegmToPolyline = function (ctrlsx, ctrlsy, tolerance, counter) {\n        ++counter;\n\n        // 1. Modeling of Bézier Curves Using a Combination of Linear and Circular Arc Approximations\n        // P. Kaewsaiha, N. Dejdumrong, 2012\n        var xA = ctrlsx[0];\n        var yA = ctrlsy[0];\n        var xB = ctrlsx[3];\n        var yB = ctrlsy[3];\n\n        // 0. try line approximation\n        if (this._isCubicCurveFlat(ctrlsx, ctrlsy, tolerance)) {\n            var segm = new IFVertexOffsetter.PolySegment(new IFPoint(xA, yA), 0);\n            this._polyline.insertSegment(segm);\n            return;\n        }\n\n        // 1. Construct approximating arc\n        var C;\n        var hndl1 = !ifMath.isEqualEps(xA, ctrlsx[1]) || !ifMath.isEqualEps(yA, ctrlsy[1]);\n        var hndl2 = !ifMath.isEqualEps(xB, ctrlsx[2]) || !ifMath.isEqualEps(yB, ctrlsy[2]);\n        if (hndl1 && hndl2) {\n            var result = [];\n            C = ifMath.getIntersectionPoint(xA, yA, ctrlsx[1], ctrlsy[1], ctrlsx[2], ctrlsy[2], xB, yB, result);\n        } else if (hndl1) {\n            C = new IFPoint(ctrlsx[1], ctrlsy[1]);\n        } else if (hndl2) {\n            C = new IFPoint(ctrlsx[2], ctrlsy[2]);\n        } else {\n            this._polyline.insertSegment(new IFVertexOffsetter.PolySegment(new IFPoint(xA, yA), 0));\n            return;\n        }\n        var ab = ifMath.ptDist(xA, yA, xB, yB);\n        var ac = ifMath.ptDist(xA, yA, C.getX(), C.getY());\n        var bc = ifMath.ptDist(xB, yB, C.getX(), C.getY());\n        var p = ab + ac + bc;\n        var xG = (xA * bc + xB * ac + C.getX() * ab) / p;\n        var yG = (yA * bc + yB * ac + C.getY() * ab) / p;\n        if (ifMath.isEqualEps(xA, xG) || ifMath.isEqualEps(yA, yG) ||\n            ifMath.isEqualEps(xB, xG) || ifMath.isEqualEps(yB, yG)) {\n            // Might be some error, as the original cubic curve has been split to not contain parts,\n            // where tangent line is parallel to X axis or Y axis.\n            var segm = new IFVertexOffsetter.PolySegment(new IFPoint(xA, yA), 0);\n            this._polyline.insertSegment(segm);\n        } else {\n            var mA = (yA - yG) / (xA - xG);\n            var mB = (yB - yG) / (xB - xG);\n            var xO = (mA * mB * (yA - yB) + mB * (xA + xG) - mA * (xG + xB)) / 2 / (mB - mA);\n            var yO = -1 / mA * (xO - (xA + xG) / 2) + (yA + yG) / 2;\n            var R = ifMath.ptDist(xA, yA, xO, yO);\n\n            // 2. Evaluate error by measuring minimal and maximal distance from curve to point O\n            // P(t) = P1 + 3t(C1 - P1) + 3t^2*(C2 - 2C1 + P1) + t^3*(P2 - 3C2 + 3C1 - P1)\n            // P(t) = a1t^3 + b1t^2 + c1t + d1\n            // d1 = A\n\n            var cx = ctrlsx[1] - xA;\n            var c1x = 3 * cx;\n            var cy = ctrlsy[1] - yA;\n            var c1y = 3 * cy;\n            var tmp = ctrlsx[2] - ctrlsx[1] - cx;\n            var b1x = 3 * tmp;\n            var bx = 2 * tmp;\n            tmp = ctrlsy[2] - ctrlsy[1] - cy;\n            var b1y = 3 * tmp;\n            var by = 2 * tmp;\n            var a1x = xB - ctrlsx[2] - cx - bx;\n            var a1y = yB - ctrlsy[2] - cy - by;\n\n            // P(t)^2 = a1^2*t^6 + b1^2*t^4 + c1^2*t^2 + d1^2 + 2*a1b1*t^5 + 2a1c1*t^4 +\n            //        + 2(a1d1 + b1c1)t^3 + 2b1d1*t^2 + 2c1d1*t\n            //\n            // d1 = d1 - x, d2 = d2 - y\n            //\n            // Pdist(t) = (a1^2 + a2^2)*t^6 + 2*(a1b1 + a2b2)*t^5 + (b1^2 + 2a1c1 + b2^2 + 2a2c2)*t^4 +\n            //         + 2(a1(d1 - x) + b1c1 + a2(d2 - y) + b2c2)*t^3 + (c1^2 + 2b1(d1 - x) + c2^2 + 2b2(d2 -y))*t^2 +\n            //         + 2(c1(d1 - x) + c2(d2 - y))*t + (d1 - x)^2 + (d2 - y)^2\n            var d1 = xA - xO;\n            var d2 = yA - yO;\n            // Coefficients of 6 degree polynomial - distance from cubic Bezier curve segment to arc center O\n            var coeffF = new Float64Array(7);\n            coeffF[0] = a1x * a1x + a1y * a1y;\n            coeffF[1] = 2 * (a1x * b1x + a1y * b1y);\n            coeffF[2] = b1x * b1x + b1y * b1y + 2 * (a1x * c1x + a1y * c1y);\n            coeffF[3] = (a1x * d1 + b1x * c1x + a1y * d2 + b1y * c1y) * 2;\n            coeffF[4] = c1x * c1x + c1y * c1y + (b1x * d1 + b1y * d2) * 2;\n            coeffF[5] = (c1x * d1 + c1y * d2) * 2;\n            coeffF[6] = d1 * d1 + d2 * d2;\n\n            // Coefficients of 5 degree derivative polynomial\n            var coeffFDeriv = new Float64Array(6);\n            ifMath.getCoeffPolyDeriv(coeffF, 6, coeffFDeriv);\n            // Coeffitients of the second and third derivative polynomials\n            var coeffFDeriv2 = new Float64Array(5);\n            ifMath.getCoeffPolyDeriv(coeffFDeriv, 5, coeffFDeriv2);\n            var coeffFDeriv3 = new Float64Array(4);\n            ifMath.getCoeffPolyDeriv(coeffFDeriv2, 4, coeffFDeriv3);\n\n            // Coefficients of 5 degree polynomial, calculated from derivative polynomial and interval transformation\n            var coeffInversed = new Float64Array(6);\n            ifMath.inversePolyUnaryInterval(coeffFDeriv, 5, coeffInversed);\n            var nRoots = ifMath.estimPositiveRootsDescartes(coeffInversed, 5);\n            var maxDst = 0;\n            var v51, v52;\n            // generalized Sturm sequence (array of polynomial coefficients arrays)\n            var sturmSeq = [];\n            // Number of Sturm sequence sign variations at roots location interval ends\n            var nSignVars;\n            // Derivative polynomial values at roots location interval ends\n            var fVals;\n            if (nRoots > 0) {\n                var t1 = 0.0;\n                var t2 = 1.0;\n                v51 = ifMath.evalPoly(coeffFDeriv, 5, t1);\n                if (ifMath.isEqualEps(v51, 0)) {\n                    t1 += 0.005;\n                    v51 = ifMath.evalPoly(coeffFDeriv, 5, t1);\n                }\n                v52 = ifMath.evalPoly(coeffFDeriv, 5, t2);\n                if (ifMath.isEqualEps(v52, 0)) {\n                    t2 -= 0.005;\n                    v52 = ifMath.evalPoly(coeffFDeriv, 5, t2);\n                }\n\n                if (nRoots > 1) {\n                    ifMath.getSturmPRS(coeffFDeriv, 5, coeffFDeriv2, sturmSeq);\n                    nSignVars = [];\n                    fVals = [v51, v52];\n                    nRoots = ifMath.countRootsNSturm(coeffFDeriv, 5, coeffFDeriv2, t1, t2,\n                        sturmSeq, nSignVars, fVals);\n                }\n            }\n            if (nRoots == 0) {\n                // Might be some error, return the arc\n            } else if (nRoots == 1) {\n                var r1 = ifMath.locateByNewton(t1, t2, v51, v52, coeffFDeriv, 5, coeffFDeriv2, coeffFDeriv3, 0.005);\n                if (r1 == null) {\n                    r1 = (t1 + t2) / 2;\n                }\n                var r1x = ifMath.evalCubic(a1x, b1x, c1x, xA, r1);\n                var r1y = ifMath.evalCubic(a1y, b1y, c1y, yA, r1);\n                maxDst = Math.abs(ifMath.ptDist(r1x, r1y, xO, yO) - R);\n            } else {\n                var rIntervals = [];\n                ifMath.locRootsSturm(coeffFDeriv, 5, coeffFDeriv2, t1, t2, sturmSeq, nRoots,\n                    nSignVars, fVals, rIntervals);\n\n                for (var s = 0; s < rIntervals.length; ++s) {\n                    r1 = ifMath.locateByNewton(rIntervals[s][0], rIntervals[s][1],\n                        rIntervals[s][2], rIntervals[s][3], coeffFDeriv, 5, coeffFDeriv2, coeffFDeriv3, 0.005,\n                        sturmSeq);\n                    if (r1 == null) {\n                        r1 = (rIntervals[s][0] + rIntervals[s][1]) / 2;\n                    }\n                    r1x = ifMath.evalCubic(a1x, b1x, c1x, xA, r1);\n                    r1y = ifMath.evalCubic(a1y, b1y, c1y, yA, r1);\n                    var dst = Math.abs(ifMath.ptDist(r1x, r1y, xO, yO) - R);\n                    if (dst > maxDst) {\n                        maxDst = dst;\n                    }\n                }\n            }\n\n            // 3. if distance > tolerance => divide && repeat;\n            // else => add arc to polyline\n            if (maxDst > tolerance && counter < IFVertexOffsetter.MAX_RECURS) {\n                var ctrlsNew1X = new Float64Array(4);\n                var ctrlsNew1Y = new Float64Array(4);\n                var ctrlsNew2X = new Float64Array(4);\n                var ctrlsNew2Y = new Float64Array(4);\n                ifMath.getCtrlPtsCasteljau(ctrlsx[0], ctrlsx[1], ctrlsx[2], ctrlsx[3], 0.5, null, ctrlsNew1X, ctrlsNew2X);\n                ifMath.getCtrlPtsCasteljau(ctrlsy[0], ctrlsy[1], ctrlsy[2], ctrlsy[3], 0.5, null, ctrlsNew1Y, ctrlsNew2Y);\n                this._addCubicSegmToPolyline(ctrlsNew1X, ctrlsNew1Y, tolerance, counter);\n                this._addCubicSegmToPolyline(ctrlsNew2X, ctrlsNew2Y, tolerance, counter);\n            } else {\n                var sinGamma = ab / 2 / R;\n                // As gamma <= 45 degrees, we are save with the following formmula:\n                var tgHalfGamma = sinGamma / (Math.sqrt(1 - sinGamma * sinGamma) + 1);\n                // Define curve orientation\n                // We can check arc center location against AB\n                if (ifMath.segmentSide(xA, yA, xB, yB, xO, yO) > 0) {\n                    tgHalfGamma = -tgHalfGamma;\n                }\n                //tgHalfGamma = this._calculateBulge(xA, yA, xB, yB, xO, yO);\n                var arc = new IFVertexOffsetter.PolySegment(new IFPoint(xA, yA), tgHalfGamma, new IFPoint(xO, yO), R);\n                this._polyline.insertSegment(arc);\n            }\n        }\n    };\n\n    IFVertexOffsetter.prototype.generatePolyLine = function (tolerance, startVertex) {\n        // The following documents will be used to approximate a bezier curve with polyline\n        // (a combination of linear segments and circular arcs):\n        //\n        // 1. Fast, precise flattening of cubic Be´zier path and offset curves\n        // Thomas F. Hain,\u0001Athar L. Ahmad, Sri Venkat R. Racherla, David D. Langan, 2005\n\n        //\n        // 3. Generalization of Approximation of Planar Spiral Segments by Arc Splines\n        // Lan Chen, 1998\n        //\n        // 4. APPROXIMATION OF A CUBIC BEZIER CURVE BY CIRCULAR ARCS AND VICE VERSA\n        // A. Riškus, 2006\n        //\n        // 5. Modeling of Bézier Curves Using a Combination of Linear and Circular Arc Approximations\n        // P. Kaewsaiha, N. Dejdumrong, 2012\n        var newStartVertex = null;\n        var origStartVertex = startVertex;\n        var vertex1 = origStartVertex;\n        var vertex2 = new IFVertex();\n        var polySegm;\n        var proceed = true;\n\n        while (proceed && this._source.readVertex(vertex2)) {\n            switch (vertex2.command) {\n                case IFVertex.Command.Move:\n                    if (!origStartVertex || !this._polyline.count) {\n                        vertex1 = vertex2;\n                        origStartVertex = vertex1;\n                        vertex2 = new IFVertex();\n                    } else {\n                        newStartVertex = vertex2;\n                        proceed = false;\n                    }\n                    break;\n                case IFVertex.Command.Line:\n                    if (!vertex1) {\n                        vertex1 = vertex2;\n                        vertex2 = new IFVertex();\n                    } else {\n                        polySegm = new IFVertexOffsetter.PolySegment(new IFPoint(vertex1.x, vertex1.y), 0);\n                        this._polyline.insertSegment(polySegm);\n                        vertex1 = vertex2;\n                        vertex2 = new IFVertex();\n                    }\n                    break;\n\n                case IFVertex.Command.Curve:\n                    if (!vertex1) {\n                        vertex1 = vertex2;\n                        vertex2 = new IFVertex();\n                    } else {\n                        var B0 = new IFPoint(vertex1.x, vertex1.y);\n                        vertex1 = vertex2;\n                        vertex2 = new IFVertex();\n                        if (this._source.readVertex(vertex2)) {\n                            var counter = 0;\n                            this.addCurveToPolyline(B0, new IFPoint(vertex2.x, vertex2.y),\n                                new IFPoint(vertex1.x, vertex1.y), tolerance, counter);\n\n                            vertex2 = new IFVertex();\n                        }\n                    }\n                    break;\n\n                case IFVertex.Command.Curve2:\n                    if (!vertex1) {\n                        vertex1 = vertex2;\n                        vertex2 = new IFVertex();\n                    } else {\n                        var B0 = new IFPoint(vertex1.x, vertex1.y);\n                        var B3 = new IFPoint(vertex2.x, vertex2.y);\n                        vertex1 = vertex2;\n                        vertex2 = new IFVertex();\n                        var vertex3 = new IFVertex();\n                        if (this._source.readVertex(vertex2) && this._source.readVertex(vertex3)) {\n                            this.addCubicCurveToPolyline(B0, new IFPoint(vertex2.x, vertex2.y),\n                                new IFPoint(vertex3.x, vertex3.y), B3, tolerance);\n\n                            vertex2 = new IFVertex();\n                        }\n                    }\n                    break;\n\n                case IFVertex.Command.Close:\n                    if (this._polyline) {\n                        if (vertex1) {\n                            polySegm = new IFVertexOffsetter.PolySegment(new IFPoint(vertex1.x, vertex1.y), 0);\n                            this._polyline.insertSegment(polySegm);\n                            vertex1 = null;\n                        }\n                        this._polyline.closed = true;\n                        polySegm = new IFVertexOffsetter.PolySegment(this._polyline.head.point, 0);\n                        this._polyline.insertSegment(polySegm);\n                        newStartVertex = new IFVertex();\n                        newStartVertex.command = IFVertex.Command.Move;\n                        newStartVertex.x = this._polyline.head.point.getX();\n                        newStartVertex.y = this._polyline.head.point.getY();\n                        proceed = false;\n                    }\n                    break;\n\n                default:\n                    throw new Error(\"Unknown vertex command: \" + vertex.command.toString());\n            }\n        }\n        if (vertex1 && this._polyline.count) {\n            polySegm = new IFVertexOffsetter.PolySegment(new IFPoint(vertex1.x, vertex1.y), 0);\n            this._polyline.insertSegment(polySegm);\n            if (ifMath.isEqualEps(vertex1.x, this._polyline.head.point.getX()) &&\n                    ifMath.isEqualEps(vertex1.y, this._polyline.head.point.getY())) {\n\n                this._polyline.closed = true;\n            }\n        }\n        return newStartVertex;\n    };\n\n    IFVertexOffsetter.prototype.generatePolyOffset = function (offset, inset, outset, tolerance) {\n        // An offset algorithm for polyline curves\n        // Xu-Zheng Liu, Jun-Hai Yong, Guo-Qin Zheng, Jia-Guang Sun, 2006\n\n        // 1. for each polySegment, generate polyOffsetSegment\n        var polyOffsetOut = null;\n        var polyOffsetIn = null;\n        if (outset) {\n            polyOffsetOut = new IFVertexOffsetter.PolySegmentContainer();\n        }\n        if (inset) {\n            polyOffsetIn = new IFVertexOffsetter.PolySegmentContainer();\n        }\n        var offsSegm;\n        for (var i = 0, curSegm = this._polyline.head; i < this._polyline.count; ++i) {\n            if (outset) {\n                offsSegm = this._offsetPolySegment(curSegm, -offset, tolerance);\n                if (offsSegm) {\n                    polyOffsetOut.insertSegment(offsSegm);\n                }\n            }\n            if (inset) {\n                offsSegm = this._offsetPolySegment(curSegm, offset, tolerance);\n                if (offsSegm) {\n                    polyOffsetIn.insertSegment(offsSegm);\n                }\n            }\n            curSegm = curSegm.next;\n        }\n\n        // 2. intersect untrimmed\n        var polyOutNew = new IFVertexOffsetter.PolySegmentContainer();\n        var polyInNew = new IFVertexOffsetter.PolySegmentContainer();\n        if (outset) {\n            this._trimOffsetPoly(polyOffsetOut, -offset, polyOutNew);\n        }\n        if (inset) {\n            this._trimOffsetPoly(polyOffsetIn, offset, polyInNew);\n        }\n\n        // 3. clipping algorithm\n        // Step 1. Dual clipping\n        var intPtsOut = [];\n        var intPtsIn = [];\n        if (inset && outset) {\n            this._calcIntersectionPoints(polyOutNew, polyInNew, intPtsOut, intPtsIn);\n        }\n        if (outset) {\n            this._calcSelfIntersectionPoints(polyOutNew, intPtsOut);\n        }\n        if (inset) {\n            this._calcSelfIntersectionPoints(polyInNew, intPtsIn);\n        }\n\n        if (intPtsOut.length > 0) {\n            this._sortInsertsectionPoints(intPtsOut);\n        }\n        if (intPtsIn.length > 0) {\n            this._sortInsertsectionPoints(intPtsIn);\n        }\n\n        var tmpArray1Out = [];\n        var tmpArray1In = [];\n        var outSplit = [];\n        var inSplit = [];\n        if (outset) {\n            if (intPtsOut.length > 0) {\n                outSplit = this._splitForClipping(polyOutNew, intPtsOut);\n                for (var i = 0; i < outSplit.length; ++i) {\n                    var intPts = [];\n                    var intPtsMain = [];\n                    this._calcIntersectionPoints(outSplit[i], this._polyline, intPts, intPtsMain);\n                    if (intPts.length == 0) {\n                        tmpArray1Out.push(outSplit[i]);\n                    } else if (!this._polyline.closed){\n                        var endSegm = false;\n                        for (var j = 0; j < intPtsMain.length; ++j) {\n                            if (intPtsMain[j].segmIdx == 0 || intPtsMain[j].segmIdx == this._polyline.count - 1) {\n                                endSegm = true;\n                                break;\n                            }\n                        }\n                        if (endSegm) {\n                            this._excludeCircleInside(outSplit[i], intPts, intPtsMain, offset, tmpArray1Out);\n                        }\n                    }\n                }\n            } else {\n                tmpArray1Out[0] = polyOutNew;\n            }\n        }\n        if (inset) {\n            if (intPtsIn.length > 0) {\n                inSplit = this._splitForClipping(polyInNew, intPtsIn);\n                for (var i = 0; i < inSplit.length; ++i) {\n                    var intPts = [];\n                    var intPtsMain = [];\n                    this._calcIntersectionPoints(inSplit[i], this._polyline, intPts, intPtsMain);\n                    if (intPts.length == 0) {\n                        tmpArray1In.push(inSplit[i]);\n                    } else if (!this._polyline.closed) {\n                        var endSegm = false;\n                        for (var j = 0; j < intPtsMain.count; ++j) {\n                            if (intPtsMain[j].segmIdx == 0 || intPtsMain[j].segmIdx == this._polyline.count - 1) {\n                                endSegm = true;\n                                break;\n                            }\n                        }\n                        if (endSegm) {\n                            this._excludeCircleInside(inSplit[i], intPts, intPtsMain, offset, tmpArray1In);\n                        }\n                    }\n                }\n            } else {\n                tmpArray1In[0] = polyInNew;\n            }\n        }\n\n        if (!(inset && outset)) {\n            // Step 2. General closest point pair (GCPP) clipping\n            this._gcppClipping(tmpArray1Out, this._polyline, offset, this._polyoutset);\n            this._gcppClipping(tmpArray1In, this._polyline, offset, this._polyinset);\n        } else {\n            // For each part from tmpArray if we have a point closer to main polyline than offset, discard the whole\n            // part\n            // TODO: change 3 with permanent coefficient\n            this._gcppFilter(tmpArray1Out, this._polyline, offset, tolerance * 3, this._polyoutset);\n            this._gcppFilter(tmpArray1In, this._polyline, offset, tolerance * 3, this._polyinset);\n        }\n    };\n\n    IFVertexOffsetter.prototype.generateOffset = function (inset, outset, tolerance) {\n        // 1. Drawing an elliptical arc using polylines, quadratic or cubic Bezier curves\n        // L. Maisonobe, 2003\n\n        var piecesTmp = [];\n\n        if (outset && inset && !this._polyline.closed) {\n            // TODO: this._genArc(this._polyoutset[0].head.point,\n            //      this._polyinset[0].head.point, this._polyline.head.point, offset, this._outset);\n            this._genCurves(this._polyoutset, piecesTmp, tolerance);\n            // TODO: this._genArc(this._polyoutset[this._polyoutset.count].end.point,\n            //      this._polyinset[this._polyinset.count].end.point, this._polyline.end.point, offset, this._outset);\n            this._genCurves(this._polyinset, piecesTmp, tolerance);\n        } else {\n            if (outset) {\n                this._genCurves(this._polyoutset, piecesTmp, tolerance);\n            }\n            if (inset) {\n                this._genCurves(this._polyinset, piecesTmp, tolerance);\n            }\n        }\n\n        this._pieces = this._mergePieces(piecesTmp);\n    };\n\n    IFVertexOffsetter.prototype._mergePieces = function (piecesTmp) {\n        var pieces = [];\n        while (piecesTmp.length > 0) {\n            var piece = piecesTmp[0];\n            piecesTmp.splice(0, 1);\n            var repeat = (piece.stPt.getX() != piece.endPt.getX()) || (piece.stPt.getY() != piece.endPt.getY());\n            while (repeat) {\n                repeat = false;\n                var pc = null;\n                for (var i = piecesTmp.length - 1; i >= 0; --i) {\n                    pc = piecesTmp[i];\n                    if ((pc.stPt.getX() == piece.endPt.getX()) && (pc.stPt.getY() == piece.endPt.getY())) {\n                        piece.endPt = pc.endPt;\n                        piece.vrt.push.apply(piece.vrt, pc.vrt);\n                        repeat = true;\n                        piecesTmp.splice(i, 1);\n                    } else if ((piece.stPt.getX() == pc.endPt.getX()) && (piece.stPt.getY() == pc.endPt.getY())) {\n                        pc.endPt = piece.endPt;\n                        pc.vrt.push.apply(pc.vrt, piece.vrt);\n                        piece = pc;\n                        repeat = true;\n                        piecesTmp.splice(i, 1);\n                    }\n                }\n            }\n            var pieceCont = new IFVertexContainer();\n            pieceCont.addVertex(IFVertex.Command.Move, piece.stPt.getX(), piece.stPt.getY());\n            for (var i = 0; i < piece.vrt.length; ++i) {\n                var vert = piece.vrt[i];\n                pieceCont.addVertex(vert.c, vert.x, vert.y);\n            }\n            pieces.push(pieceCont);\n        }\n\n        return pieces;\n    };\n\n    /**\n     *\n     * @param segm\n     * @param {Number} offset: positive - to the right along the path, negative - to the left\n     * @returns {null}\n     * @private\n     */\n    IFVertexOffsetter.prototype._offsetPolySegment = function(segm, offset, tolerance) {\n        var newSegm = null;\n        var absOffs = Math.abs(offset);\n        var x1 = segm.point.getX();\n        var y1 = segm.point.getY();\n        if (!segm.bulge) {\n            if(segm.next || this._polyline.closed) {\n                // x(y2 - y1) + y(x1 - x2) + x2y1 - x1y2 = 0\n                var x2, y2;\n                if (segm.next) {\n                    x2 = segm.next.point.getX();\n                    y2 = segm.next.point.getY();\n                } else { // closed\n                    x2 = this._polyline.head.point.getX();\n                    y2 = this._polyline.head.point.getY();\n                }\n                var dist = ifMath.ptDist(x1, y1, x2, y2);\n                if (!ifMath.isEqualEps(dist, 0)) {\n                    var delta = new IFPoint(-offset * (y2 - y1) / dist, -offset * (x1 - x2) / dist);\n                    var newPt1 = new IFPoint(x1 + delta.getX(), y1 + delta.getY());\n                    var newPt2 = new IFPoint(x2 + delta.getX(), y2 + delta.getY());\n                    newSegm = new IFVertexOffsetter.PolyOffsetSegment(segm.point, newPt1, newPt2, 0);\n                } // else do nothing\n            } // else do nothing\n        } else if (segm.radius) {\n            var radius = segm.radius;\n            var k = null;\n            if (offset * segm.bulge > 0) {\n                radius += absOffs;\n                k = radius / segm.radius;\n            } else if (!ifMath.isEqualEps(segm.radius, absOffs, tolerance)) {\n                if (segm.radius > absOffs) {\n                    radius -= absOffs;\n                    k = radius / segm.radius;\n                } else { // segm.radius < absOffs\n                    // construct symmetric arc with the same center and radius = absOffs - segm.radius\n                    radius = absOffs - segm.radius;\n                    k = absOffs / segm.radius;\n                }\n            }\n            if (k != null) {\n                var xO = segm.center.getX();\n                var yO = segm.center.getY();\n                var x2, y2;\n                if (segm.next) {\n                    x2 = segm.next.point.getX();\n                    y2 = segm.next.point.getY();\n                } else { // error\n                    x2 = this._polyline.head.point.getX();\n                    y2 = this._polyline.head.point.getY();\n                }\n                var newPt1 = new IFPoint(xO + k * (x1 - xO), yO + k * (y1 - yO));\n                var newPt2 = new IFPoint(xO + k * (x2 - xO), yO + k * (y2 - yO));\n                newSegm = new IFVertexOffsetter.PolyOffsetSegment(\n                    segm.point, newPt1, newPt2, segm.bulge, segm.center, radius);\n            }\n        }\n        return newSegm;\n    };\n\n    /**\n     *\n     * @param {IFVertexOffsetter.PolyOffsetSegment} psegm1\n     * @param {IFVertexOffsetter.PolyOffsetSegment} psegm2\n     * @param {IFVertexOffsetter.IntersectionResult} intResult\n     * @private\n     */\n    IFVertexOffsetter.prototype._insersectOffsetSegments = function (psegm1, psegm2, intResult) {\n        if (psegm1.bulge == 0 && psegm2.bulge == 0) { // line segments\n            var res = [null, null];\n            var pt = ifMath.getIntersectionPoint(\n                psegm1.point.getX(), psegm1.point.getY(), psegm1.point2.getX(), psegm1.point2.getY(),\n                psegm2.point.getX(), psegm2.point.getY(), psegm2.point2.getX(), psegm2.point2.getY(), res);\n\n            intResult.point = pt;\n            if (pt) {\n                this._fillLineIntType(res[0], intResult.intTypes[0]);\n                this._fillLineIntType(res[1], intResult.intTypes[1]);\n            }\n        } else if (psegm1.bulge != 0 && psegm2.bulge == 0 || psegm1.bulge == 0 && psegm2.bulge != 0) { // arc and line\n            var res = [null, null];\n            var x = null;\n            var y = null;\n            var t = null;\n\n            if (psegm1.bulge == 0) {\n                var xL = psegm1.point.getX();\n                var yL = psegm1.point.getY();\n                var dxL = psegm1.point2.getX() - psegm1.point.getX();\n                var dyL = psegm1.point2.getY() - psegm1.point.getY();\n                ifMath.circleLineIntersection(xL, yL, dxL, dyL,\n                    psegm2.center.getX(), psegm2.center.getY(), psegm2.radius, res);\n\n                if (res[0] != null) {\n                    x = xL + dxL * res[0];\n                    y = yL + dyL * res[0];\n                    t = res[0];\n                }\n                if (res[0] != null && res[1] != null) {\n                    var x2 = xL + dxL * res[1];\n                    var y2 = yL + dyL * res[1];\n                    var sDst1 = ifMath.ptSqrDist(x, y, psegm2.basepoint.getX(), psegm2.basepoint.getY());\n                    var sDst2 = ifMath.ptSqrDist(x2, y2, psegm2.basepoint.getX(), psegm2.basepoint.getY());\n                    if (sDst2 < sDst1) {\n                        x = x2;\n                        y = y2;\n                        t = res[1];\n                    }\n                }\n                if (t != null) {\n                    intResult.point = new IFPoint(x, y);\n                    // Define point type\n                    this._fillLineIntType(t, intResult.intTypes[0]);\n                    this._fillArcIntType(psegm2, x, y, intResult.intTypes[1]);\n                }\n            } else {\n                var xL = psegm2.point.getX();\n                var yL = psegm2.point.getY();\n                var dxL = psegm2.point2.getX() - psegm2.point.getX();\n                var dyL = psegm2.point2.getY() - psegm2.point.getY();\n                ifMath.circleLineIntersection(xL, yL, dxL, dyL,\n                    psegm1.center.getX(), psegm1.center.getY(), psegm1.radius, res);\n\n                if (res[0] != null) {\n                    x = xL + dxL * res[0];\n                    y = yL + dyL * res[0];\n                    t = res[0];\n                }\n                if (res[0] != null && res[1] != null) {\n                    var x2 = xL + dxL * res[1];\n                    var y2 = yL + dyL * res[1];\n                    var sDst1 = ifMath.ptSqrDist(x, y, psegm2.basepoint.getX(), psegm2.basepoint.getY());\n                    var sDst2 = ifMath.ptSqrDist(x2, y2, psegm2.basepoint.getX(), psegm2.basepoint.getY());\n                    if (sDst2 < sDst1) {\n                        x = x2;\n                        y = y2;\n                        t = res[1];\n                    }\n                }\n                if (t != null) {\n                    intResult.point = new IFPoint(x, y);\n                    // Define point type\n                    this._fillLineIntType(t, intResult.intTypes[1]);\n                    this._fillArcIntType(psegm1, x, y, intResult.intTypes[0]);\n                }\n            }\n        } else { // two arcs\n            var res = [null, null];\n            ifMath.circleCircleIntersection(psegm1.center.getX(), psegm1.center.getY(), psegm1.radius,\n                psegm2.center.getX(), psegm2.center.getY(), psegm2.radius, res);\n\n            var ptIdx = null;\n            if (res[0] != null) {\n                ptIdx = 0;\n            }\n            if (res[0] != null && res[1] != null) {\n                var sDst1 = ifMath.ptSqrDist(res[0].getX(), res[0].getY(),\n                    psegm2.basepoint.getX(), psegm2.basepoint.getY());\n\n                var sDst2 = ifMath.ptSqrDist(res[1].getX(), res[1].getY(),\n                    psegm2.basepoint.getX(), psegm2.basepoint.getY());\n\n                if (sDst2 < sDst1) {\n                    ptIdx = 1;\n                }\n            }\n\n            if (ptIdx !== null) {\n                intResult.point = res[ptIdx];\n                this._fillArcIntType(psegm1, res[ptIdx].getX(), res[ptIdx].getY(), intResult.intTypes[0]);\n                this._fillArcIntType(psegm2, res[ptIdx].getX(), res[ptIdx].getY(), intResult.intTypes[1]);\n            }\n        }\n    };\n\n    /**\n     * Fills arc intersection type based on the arc segment parameters and intersection point's coordinates\n     * @param {IFVertexOffsetter.PolyOffsetSegment} psegm\n     * @param {Number} x\n     * @param {Number} y\n     * @param {IFVertexOffsetter.IntersectionType} intType\n     * @private\n     */\n    IFVertexOffsetter.prototype._fillArcIntType = function (psegm, x, y, intType) {\n        // For an arc, if a point not on the arc, let's find arc's central point on the circle, and consider\n        // an opposite circle point as a measure for defining a PFIP or NFIP\n        var sp1x = psegm.point.getX();\n        var sp1y = psegm.point.getY();\n        var sp2x = psegm.point2.getX();\n        var sp2y = psegm.point2.getY();\n        var cX = psegm.center.getX();\n        var cY = psegm.center.getY();\n        // TODO: process accurately, when segment side is not evident\n        if (ifMath.segmentSide(sp1x, sp1y, sp2x, sp2y, x, y) ==\n            ifMath.segmentSide(sp1x, sp1y, sp2x, sp2y, cX, cY)) {\n\n            var pMx = (sp1x + sp2x) / 2;\n            var pMy = (sp1y + sp2y) / 2;\n            var tmp = psegm.radius / ifMath.ptDist(pMx, pMy, cX, cY);\n            var pOppX = cX + (cX - pMx) * tmp;\n            var pOppY = cY + (cY - pMy) * tmp;\n            if (ifMath.segmentSide(sp1x, sp1y, pOppX, pOppY, x, y) ==\n                ifMath.segmentSide(sp1x, sp1y, pOppX, pOppY, cX, cY)) {\n                intType.FIP = true;\n                intType.PFIP = true;\n            } else {\n                intType.FIP = true;\n            }\n        } else { // point is on the arc\n            intType.TIP = true;\n        }\n    };\n\n    IFVertexOffsetter.prototype._fillLineIntType = function (param, intType) {\n        if (param < 0.0) {\n            intType.FIP = true;\n        } else if (param > 1.0) {\n            intType.FIP = true;\n            intType.PFIP = true;\n        } else {\n            intType.TIP = true;\n        }\n    };\n\n    /**\n     *\n     * @param {IFVertexOffsetter.PolySegmentContainer} polyOffset\n     * @param {Number} offset\n     * @private\n     */\n    IFVertexOffsetter.prototype._trimOffsetPoly = function (polyOffset, offset, polyONew) {\n        // An offset algorithm for polyline curves\n        // Xu-Zheng Liu, Jun-Hai Yong, Guo-Qin Zheng, Jia-Guang Sun, 2006\n\n        var eps = 0.000001; // eps = 10-7 is already too small, as tangence calculation is not so accurate in our case\n        var segm1 = null;\n        var segm2 = polyOffset.head;\n        if (segm2) {\n            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                segm2.point, segm2.bulge, segm2.center, segm2.radius));\n\n            var iRes = new IFVertexOffsetter.IntersectionResult();\n            for (var i = 0; i < polyOffset.count - 1; ++i) {\n                // it is not necessary to recalculate basepoint here,\n                // as segm1.basepoint is not needed for further calculations\n                segm1 = new IFVertexOffsetter.PolyOffsetSegment(segm2.basepoint, polyONew.end.point, segm2.point2,\n                    polyONew.end.bulge, segm2.center, segm2.radius);\n                segm2 = segm2.next;\n\n                if (!ifMath.isEqualEps(segm1.point2.getX(), segm2.point.getX(), eps) ||\n                        !ifMath.isEqualEps(segm1.point2.getY(), segm2.point.getY(), eps)) {\n\n                    iRes.clear();\n                    this._insersectOffsetSegments(segm1, segm2, iRes);\n\n                    if (segm1.bulge == 0 && segm2.bulge == 0) { // Two line segments: use Algorithm 1\n                        if (!iRes.point) { // case 1\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n                        } else if (iRes.intTypes[0].TIP && iRes.intTypes[1].TIP || // case 2a\n                            iRes.intTypes[0].FIP && iRes.intTypes[1].FIP && iRes.intTypes[0].PFIP) { // case 2b part1\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, 0));\n                        } else { // case 2b part2 || case 2c\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                        }\n                    } else if (segm1.bulge == 0 && segm2.bulge != 0) { // Line segment and arc segment: use Algorithm 2\n                        if (iRes.point) { // case 1\n                            if (iRes.intTypes[0].TIP && iRes.intTypes[1].TIP || // case 1a\n                                // TIP && NFIP || PFIP && TIP -> should not be possible, might be some error,\n                                // behave the same as when TIP for both\n                                iRes.intTypes[0].TIP && iRes.intTypes[1].FIP && !iRes.intTypes[1].PFIP ||\n                                iRes.intTypes[0].PFIP && iRes.intTypes[1].TIP) {\n\n                                var ptMx = (iRes.point.getX() + segm2.point2.getX()) / 2;\n                                var ptMy = (iRes.point.getY() + segm2.point2.getY()) / 2;\n                                var bulge = this._calculateBulge(iRes.point.getX(), iRes.point.getY(),\n                                    segm2.point2.getX(), segm2.point2.getY(), segm2.center.getX(), segm2.center.getY(),\n                                    segm2.bulge);\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, bulge,\n                                    segm2.center, segm2.radius));\n                            } else if (iRes.intTypes[0].PFIP && iRes.intTypes[1].FIP) { // case 1b\n                                var arc = this._constructJoinArc(segm1, segm2, true);\n                                polyONew.insertSegment(arc);\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                                    segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                            } else { //iRes.intTypes[0].FIP && !iRes.intTypes[0].PFIP && iRes.intTypes[1].TIP ||  case 1c\n                                // iRes.intTypes[0].TIP && iRes.intTypes[1].PFIP)  case 1d\n\n                                // construct new line segment\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                                    segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                            }\n                        } else { // case 2, construct arc\n                            var arc = this._constructJoinArc(segm1, segm2, true);\n                            polyONew.insertSegment(arc);\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                                segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                        }\n                    } else if (segm1.bulge != 0 && segm2.bulge == 0) { // Arc segment and line segment: use Algorithm 3\n                        if (iRes.point) { // case 1\n                            if (iRes.intTypes[0].TIP && iRes.intTypes[1].TIP) { // case 1a\n                                var newBulge = this._calculateBulge(segm1.point.getX(), segm1.point.getY(),\n                                    iRes.point.getX(), iRes.point.getY(), segm1.center.getX(), segm1.center.getY(),\n                                    segm1.bulge);\n                                polyONew.end.bulge = newBulge;\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, 0));\n                            } else if (iRes.intTypes[0].FIP &&\n                                iRes.intTypes[1].FIP && !iRes.intTypes[1].PFIP) { // case 1b\n\n                                var arc = this._constructJoinArc(segm1, segm2, true);\n                                polyONew.insertSegment(arc);\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                                //segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                            } else { // case 1c, 1d\n                                // construct new line segment\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                            }\n                        } else {\n                            var arc = this._constructJoinArc(segm1, segm2, true);\n                            polyONew.insertSegment(arc);\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                        }\n                    } else { // two arc segments: use Algorithm 4\n                        if (iRes.point) { // case 1\n                            if (!(iRes.intTypes[0].FIP && !iRes.intTypes[0].PFIP) &&\n                                !iRes.intTypes[1].PFIP) { // case 1a\n\n                                var newBulge = this._calculateBulge(segm1.point.getX(), segm1.point.getY(),\n                                    iRes.point.getX(), iRes.point.getY(), segm1.center.getX(), segm1.center.getY(),\n                                    segm1.bulge);\n                                polyONew.end.bulge = newBulge;\n\n                                newBulge = this._calculateBulge(iRes.point.getX(), iRes.point.getY(),\n                                    segm2.point2.getX(), segm2.point2.getY(), segm2.center.getX(), segm2.center.getY(),\n                                    segm2.bulge);\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                                    iRes.point, newBulge, segm2.center, segm2.radius));\n                            } else { // case 1b, construct arc\n                                var arc = this._constructJoinArc(segm1, segm2, false);\n                                polyONew.insertSegment(arc);\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                                    segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                            }\n                        } else { // case 2\n                            var arc = this._constructJoinArc(segm1, segm2, true);\n                            polyONew.insertSegment(arc);\n\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                                segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                        }\n                    }\n                } else {\n                    polyONew.insertSegment(new IFVertexOffsetter.PolySegment(\n                        segm2.point, segm2.bulge, segm2.center, segm2.radius));\n                }\n            }\n            if (this._polyline.closed) {\n                // it is not necessary to recalculate basepoint here,\n                // as segm1.basepoint is not needed for further calculations\n                segm1 = new IFVertexOffsetter.PolyOffsetSegment(segm2.basepoint, polyONew.end.point, segm2.point2,\n                    polyONew.end.bulge, segm2.center, segm2.radius);\n\n                segm2 = polyOffset.head;\n                if (!ifMath.isEqualEps(segm1.point2.getX(), segm2.point.getX(), eps) ||\n                        !ifMath.isEqualEps(segm1.point2.getY(), segm2.point.getY(), eps)) {\n\n                    iRes.clear();\n                    this._insersectOffsetSegments(segm1, segm2, iRes);\n\n                    if (segm1.bulge == 0 && segm2.bulge == 0) { // Two line segments: use Algorithm 1\n                        if (!iRes.point) { // case 1\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n                        } else if (iRes.intTypes[0].TIP && iRes.intTypes[1].TIP || // case 2a\n                            iRes.intTypes[0].FIP && iRes.intTypes[1].FIP && iRes.intTypes[0].PFIP) { // case 2b part1\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, 0));\n                            polyONew.head.point = iRes.point;\n                        } else { // case 2b part2 || case 2c\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                        }\n                    } else if (segm1.bulge == 0 && segm2.bulge != 0) { // Line segment and arc segment: use Algorithm 2\n                        if (iRes.point) { // case 1\n                            if (iRes.intTypes[0].TIP && iRes.intTypes[1].TIP || // case 1a\n                                    // TIP && NFIP || PFIP && TIP -> should not be possible, might be some error,\n                                    // behave the same as when TIP for both\n                                    iRes.intTypes[0].TIP && iRes.intTypes[1].FIP && !iRes.intTypes[1].PFIP ||\n                                    iRes.intTypes[0].PFIP && iRes.intTypes[1].TIP) {\n\n                                var bulge = this._calculateBulge(iRes.point.getX(), iRes.point.getY(),\n                                    segm2.point2.getX(), segm2.point2.getY(), segm2.center.getX(), segm2.center.getY(),\n                                    segm2.bulge);\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, 0));\n\n                                polyONew.head.point = iRes.point;\n                                polyONew.head.bulge = bulge;\n                            } else if (iRes.intTypes[0].PFIP && iRes.intTypes[1].FIP) { // case 1b\n                                var arc = this._constructJoinArc(segm1, segm2, true);\n                                polyONew.insertSegment(arc);\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                            } else { //iRes.intTypes[0].FIP && !iRes.intTypes[0].PFIP && iRes.intTypes[1].TIP ||  case 1c\n                                // iRes.intTypes[0].TIP && iRes.intTypes[1].PFIP)  case 1d\n\n                                // construct new line segment\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                            }\n                        } else { // case 2, construct arc\n                            var arc = this._constructJoinArc(segm1, segm2, true);\n                            polyONew.insertSegment(arc);\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                        }\n                    } else if (segm1.bulge != 0 && segm2.bulge == 0) { // Arc segment and line segment: use Algorithm 3\n                        if (iRes.point) { // case 1\n                            if (iRes.intTypes[0].TIP && iRes.intTypes[1].TIP) { // case 1a\n                                var newBulge = this._calculateBulge(segm1.point.getX(), segm1.point.getY(),\n                                    iRes.point.getX(), iRes.point.getY(), segm1.center.getX(), segm1.center.getY(),\n                                    segm1.bulge);\n                                polyONew.end.bulge = newBulge;\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, 0));\n                                polyONew.head.point = iRes.point;\n                            } else if (iRes.intTypes[0].FIP &&\n                                    iRes.intTypes[1].FIP && !iRes.intTypes[1].PFIP) { // case 1b\n\n                                var arc = this._constructJoinArc(segm1, segm2, true);\n                                polyONew.insertSegment(arc);\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                            } else { // case 1c, 1d\n                                // construct new line segment\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm1.point2, 0));\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                            }\n                        } else {\n                            var arc = this._constructJoinArc(segm1, segm2, true);\n                            polyONew.insertSegment(arc);\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                        }\n                    } else { // two arc segments: use Algorithm 4\n                        if (iRes.point) { // case 1\n                            if (!(iRes.intTypes[0].FIP && !iRes.intTypes[0].PFIP) &&\n                                !iRes.intTypes[1].PFIP) { // case 1a\n\n                                var newBulge = this._calculateBulge(segm1.point.getX(), segm1.point.getY(),\n                                    iRes.point.getX(), iRes.point.getY(), segm1.center.getX(), segm1.center.getY(),\n                                    segm1.bulge);\n                                polyONew.end.bulge = newBulge;\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(iRes.point, 0));\n\n                                newBulge = this._calculateBulge(iRes.point.getX(), iRes.point.getY(),\n                                    segm2.point2.getX(), segm2.point2.getY(), segm2.center.getX(), segm2.center.getY(),\n                                    segm2.bulge);\n\n                                polyONew.head.point = iRes.point;\n                                polyONew.head.bulge = newBulge;\n                            } else { // case 1b, construct arc\n                                var arc = this._constructJoinArc(segm1, segm2, false);\n                                polyONew.insertSegment(arc);\n\n                                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                            }\n                        } else { // case 2\n                            var arc = this._constructJoinArc(segm1, segm2, true);\n                            polyONew.insertSegment(arc);\n\n                            polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                        }\n                    }\n                } else {\n                    polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point, 0));\n                }\n            } else {\n                polyONew.insertSegment(new IFVertexOffsetter.PolySegment(segm2.point2, 0));\n            }\n        }\n    };\n\n    /**\n     * Construct arc segment from segm1.point2 to segm2.point with center at segm2.basepoint\n     * @param {IFVertexOffsetter.PolyOffsetSegment} [segm1]\n     * @param {IFVertexOffsetter.PolyOffsetSegment} [segm2]\n     * @return {IFVertexOffsetter.PolySegment} [arc] - constructed arc segment\n     * @private\n     */\n    IFVertexOffsetter.prototype._constructJoinArc = function (segm1, segm2, collinear) {\n        // Define bulge sign\n        var sign = 0;\n        if (segm1.bulge) {\n            var sb = segm1.bulge > 0 ? 1 : -1;\n            var dx = (segm1.point2.getY() - segm1.center.getY()) * sb;\n            var dy = (segm1.center.getX() - segm1.point2.getX()) * sb;\n            /*if (segm1.bulge < 0) {\n                dx = -dx;\n                dy = -dy;\n            }*/\n            sign = -ifMath.segmentSide(segm1.point2.getX(), segm1.point2.getY(),\n                segm1.point2.getX() + dx, segm1.point2.getY() + dy,\n                segm2.point.getX(), segm2.point.getY()); // * segm1.bulge;\n        } else {\n            sign = -ifMath.segmentSide(segm1.point.getX(), segm1.point.getY(), segm1.point2.getX(), segm1.point2.getY(),\n                segm2.point.getX(), segm2.point.getY());\n        }\n\n        if (!collinear) {\n            sign = -sign;\n        }\n\n        var arc = null;\n        var bulge = 0;\n        if (sign) {\n            bulge = this._calculateBulge(segm1.point2.getX(), segm1.point2.getY(),\n                segm2.point.getX(), segm2.point.getY(), segm2.basepoint.getX(), segm2.basepoint.getY(), sign);\n        }\n        if (bulge) {\n            arc = new IFVertexOffsetter.PolySegment(segm1.point2, bulge, segm2.basepoint,\n                ifMath.ptDist(segm1.point2.getX(), segm1.point2.getY(), segm2.basepoint.getX(), segm2.basepoint.getY()));\n        } else {\n            arc = new IFVertexOffsetter.PolySegment(segm1.point2, 0);\n        }\n        return arc;\n    };\n\n    IFVertexOffsetter.prototype._calculateBulge = function (p1x, p1y, p2x, p2y, cx, cy, exampBulge) {\n        var d1 = ifMath.ptSqrDist(p1x, p1y, cx, cy);\n        var d2 = ifMath.ptSqrDist(p2x, p2y, cx, cy);\n        var bulge = 0;\n        if (ifMath.isEqualEps(d1, d2, 0.00000001)) {\n            // bulge = tg(alpha / 4): dividing 4 is necessary here, because angles > 180 degrees are possible\n            var a = ifMath.ptSqrDist((p1x + p2x) / 2, (p1y + p2y) / 2, cx, cy);\n            if (ifMath.isEqualEps(a, 0, 0.00000001)) {\n                bulge = 1;\n            } else {\n                var cos2alpha = Math.sqrt(a / d1);\n                bulge = Math.sqrt((1 - cos2alpha) / (1 + cos2alpha));\n            }\n            var r = Math.sqrt(d1);\n            var sinp1 = (p1y - cy) / r;\n            var cosp1 = (p1x - cx) / r;\n            var sinp2 = (p2y - cy) / r;\n            var cosp2 = (p2x - cx) / r;\n            var sinP1SubP2 = sinp1 * cosp2 - cosp1 * sinp2;\n            bulge = sinP1SubP2 < 0 ? -bulge : bulge;\n            if (exampBulge && (exampBulge < 0 && bulge > 0 || exampBulge > 0 && bulge < 0)) {\n                bulge = -1 / bulge; // tg((2Pi - alpha) / 4) = 1 / tg(alpha / 4), change in sign means direction change\n            }\n        }\n        return bulge;\n    };\n\n    /**\n     *\n     * @param {IFVertexOffsetter.PolySegmentContainer} [polyLn1]\n     * @param {IFVertexOffsetter.PolySegmentContainer} [polyLn2]\n     * @param {Array} [intPts1]\n     * @param {Array} [intPts2]\n     * @private\n     */\n    IFVertexOffsetter.prototype._calcIntersectionPoints = function (polyLn1, polyLn2, intPts1, intPts2) {\n        var s1 = polyLn1.head;\n        var s2;\n        for (var i = 0; i < polyLn1.count - 1; ++i) {\n            s2 = polyLn2.head;\n            for (var j = 0; j < polyLn2.count - 1; ++j) {\n                this._calcSegmIntersectionPoints(s1, s2, i, j, intPts1, intPts2);\n                s2 = s2.next;\n            }\n            s1 = s1.next;\n        }\n    };\n\n    /**\n     *\n     * @param {IFVertexOffsetter.PolySegmentContainer} [polyLn]\n     * @param {Array} [intPts]\n     * @private\n     */\n    IFVertexOffsetter.prototype._calcSelfIntersectionPoints = function (polyLn, intPts) {\n        var s1 = polyLn.head;\n        var s2;\n        for (var i = 0; i < polyLn.count - 2; ++i) {\n            s2 = s1.next;\n            for (var j = i + 1; j < polyLn.count - 1; ++j) {\n                this._calcSegmIntersectionPoints(s1, s2, i, j, intPts, intPts, j == i + 1);\n                s2 = s2.next;\n            }\n            s1 = s1.next;\n        }\n    };\n\n    IFVertexOffsetter.prototype._calcSegmIntersectionPoints = function (\n            s1, s2, idx1, idx2, intPts1, intPts2, ignoreCommonEnd) {\n\n        if (!s1.bulge && !s2.bulge) {\n            if (!ignoreCommonEnd) {\n                var res = [null, null];\n                var iPt = ifMath.getIntersectionPoint(s1.point.getX(), s1.point.getY(),\n                    s1.next.point.getX(), s1.next.point.getY(), s2.point.getX(), s2.point.getY(),\n                    s2.next.point.getX(), s2.next.point.getY(), res);\n                if (iPt && (0 <= res[0]) && (res[0] <= 1) && (0 <= res[1]) && (res[1] <= 1)) {\n                    intPts1.push(new IFVertexOffsetter.IntersectionPt(iPt.getX(), iPt.getY(), res[0], s1, idx1));\n                    intPts2.push(new IFVertexOffsetter.IntersectionPt(iPt.getX(), iPt.getY(), res[1], s2, idx2));\n                }\n            }\n        } else if (!s1.bulge && s2.bulge) {\n            var res = [null, null];\n            var dLx = s1.next.point.getX() - s1.point.getX();\n            var dLy = s1.next.point.getY() - s1.point.getY();\n            ifMath.circleLineIntersection(s1.point.getX(), s1.point.getY(), dLx, dLy,\n                s2.center.getX(), s2.center.getY(), s2.radius, res);\n\n            if (res[0] != null && res[0] >= 0 && res[0] <= 1 && (!ignoreCommonEnd || !ifMath.isEqualEps(res[0], 1))) {\n                var x = s1.point.getX() + dLx * res[0];\n                var y = s1.point.getY() + dLy * res[0];\n\n                var bulge = this._calculateBulge(s2.point.getX(), s2.point.getY(), x, y,\n                    s2.center.getX(), s2.center.getY(), s2.bulge);\n\n                if (bulge < 0 && bulge >= s2.bulge || bulge > 0 && bulge <= s2.bulge) {\n                    intPts1.push(new IFVertexOffsetter.IntersectionPt(x, y, res[0], s1, idx1));\n                    intPts2.push(new IFVertexOffsetter.IntersectionPt(x, y, bulge, s2, idx2));\n                }\n            }\n\n            if (res[1] != null && res[1] >= 0 && res[1] <= 1 && (!ignoreCommonEnd || !ifMath.isEqualEps(res[1], 1))) {\n                var x = s1.point.getX() + dLx * res[1];\n                var y = s1.point.getY() + dLy * res[1];\n\n                var bulge = this._calculateBulge(s2.point.getX(), s2.point.getY(), x, y,\n                s2.center.getX(), s2.center.getY(), s2.bulge);\n\n                if (bulge < 0 && bulge >= s2.bulge || bulge > 0 && bulge <= s2.bulge) {\n                    intPts1.push(new IFVertexOffsetter.IntersectionPt(x, y, res[1], s1, idx1));\n                    intPts2.push(new IFVertexOffsetter.IntersectionPt(x, y, bulge, s2, idx2));\n                }\n            }\n        } else if (s1.bulge && !s2.bulge) {\n            var res = [null, null];\n            var dLx = s2.next.point.getX() - s2.point.getX();\n            var dLy = s2.next.point.getY() - s2.point.getY();\n            ifMath.circleLineIntersection(s2.point.getX(), s2.point.getY(), dLx, dLy,\n                s1.center.getX(), s1.center.getY(), s1.radius, res);\n\n            if (res[0] != null && res[0] >= 0 && res[0] <= 1 && (!ignoreCommonEnd || !ifMath.isEqualEps(res[0], 0))) {\n                var x = s2.point.getX() + dLx * res[0];\n                var y = s2.point.getY() + dLy * res[0];\n                var bulge = this. _calculateBulge(s1.point.getX(), s1.point.getY(), x, y,\n                    s1.center.getX(), s1.center.getY(), s1.bulge);\n\n                if (bulge < 0 && bulge >= s1.bulge || bulge > 0 && bulge <= s1.bulge) {\n                    intPts1.push(new IFVertexOffsetter.IntersectionPt(x, y, bulge, s1, idx1));\n                    intPts2.push(new IFVertexOffsetter.IntersectionPt(x, y, res[0], s2, idx2));\n                }\n            }\n\n            if (res[1] != null && res[1] >= 0 && res[1] <= 1 && (!ignoreCommonEnd || !ifMath.isEqualEps(res[1], 0))) {\n                var x = s2.point.getX() + dLx * res[1];\n                var y = s2.point.getY() + dLy * res[1];\n                var bulge = this. _calculateBulge(s1.point.getX(), s1.point.getY(), x, y,\n                    s1.center.getX(), s1.center.getY(), s1.bulge);\n\n                if (bulge < 0 && bulge >= s1.bulge || bulge > 0 && bulge <= s1.bulge) {\n                    intPts1.push(new IFVertexOffsetter.IntersectionPt(x, y, bulge, s1, idx1));\n                    intPts2.push(new IFVertexOffsetter.IntersectionPt(x, y, res[1], s2, idx2));\n                }\n            }\n        } else { // s1.bulge && s2.bulge\n            var res = [null, null];\n            ifMath.circleCircleIntersection(s1.center.getX(), s1.center.getY(), s1.radius,\n                s2.center.getX(), s2.center.getY(), s2.radius, res);\n\n            if (res[0] && (!ignoreCommonEnd ||\n                    !ifMath.isEqualEps(res[0].getX(), s2.point.getX()) &&\n                    !ifMath.isEqualEps(res[0].getY(), s2.point.getY()))) {\n\n                var bulge01 = this. _calculateBulge(s1.point.getX(), s1.point.getY(),\n                    res[0].getX(), res[0].getY(), s1.center.getX(), s1.center.getY(), s1.bulge);\n\n                if (bulge01 < 0 && bulge01 >= s1.bulge || bulge01 > 0 && bulge01 <= s1.bulge) {\n                    var bulge02 = this. _calculateBulge(s2.point.getX(), s2.point.getY(),\n                        res[0].getX(), res[0].getY(), s2.center.getX(), s2.center.getY(), s2.bulge);\n\n                    if (bulge02 < 0 && bulge02 >= s2.bulge || bulge02 > 0 && bulge02 <= s2.bulge) {\n                        intPts1.push(new IFVertexOffsetter.IntersectionPt(res[0].getX(), res[0].getY(),\n                            bulge01, s1, idx1));\n\n                        intPts2.push(new IFVertexOffsetter.IntersectionPt(res[0].getX(), res[0].getY(),\n                            bulge02, s2, idx2));\n                    }\n                }\n            }\n\n            if (res[1] && (!ignoreCommonEnd ||\n                    !ifMath.isEqualEps(res[1].getX(), s2.point.getX()) &&\n                    !ifMath.isEqualEps(res[1].getY(), s2.point.getY()))) {\n\n                var bulge11 = this. _calculateBulge(s1.point.getX(), s1.point.getY(),\n                    res[1].getX(), res[1].getY(), s1.center.getX(), s1.center.getY(), s1.bulge);\n\n                if (bulge11 < 0 && bulge11 >= s1.bulge || bulge11 > 0 && bulge11 <= s1.bulge) {\n                    var bulge12 = this. _calculateBulge(s2.point.getX(), s2.point.getY(),\n                        res[1].getX(), res[1].getY(), s2.center.getX(), s2.center.getY(), s2.bulge);\n\n                    if (bulge12 < 0 && bulge12 >= s2.bulge || bulge12 > 0 && bulge12 <= s2.bulge) {\n                        intPts1.push(new IFVertexOffsetter.IntersectionPt(res[1].getX(), res[1].getY(),\n                            bulge11, s1, idx1));\n\n                        intPts2.push(new IFVertexOffsetter.IntersectionPt(res[1].getX(), res[1].getY(),\n                            bulge12, s2, idx2));\n                    }\n                }\n            }\n        }\n    };\n\n    IFVertexOffsetter.prototype._sortInsertsectionPoints = function (intPts) {\n        intPts.sort(function (p1, p2) {\n            return (p1.segmIdx != p2.segmIdx ? p1.segmIdx - p2.segmIdx :\n                (p1.slope > 0) ? p1.slope - p2.slope : p2.slope - p1.slope);\n        });\n    };\n\n    /**\n     *\n     * @param {IFVertexOffsetter.PolySegmentContainer} polyLn\n     * @param {Array{IFVertexOffsetter.IntersectionPt}} intPts\n     * @return {Array} split\n     * @private\n     */\n    IFVertexOffsetter.prototype._splitForClipping = function (polyLn, intPts) {\n        var eps = 0.000001;\n        var startSegm = polyLn.head;\n        var startIdx = 0;\n        var segm = startSegm;\n        var segmOrig = segm;\n        var bulge;\n        var split = [];\n        for (var i = 0; i < intPts.length; ++i) {\n            split[i] = new IFVertexOffsetter.PolySegmentContainer();\n\n            for (var j = startIdx; j < intPts[i].segmIdx; ++j) {\n                split[i].insertSegment(new IFVertexOffsetter.PolySegment(\n                    segm.point, segm.bulge, segm.center, segm.radius));\n\n                segm = segmOrig.next;\n                segmOrig = segm;\n            }\n            if (!segm.bulge) {\n                split[i].insertSegment(new IFVertexOffsetter.PolySegment(segm.point, 0));\n                if (!ifMath.isEqualEps(intPts[i].x, segm.point.getX(), eps) ||\n                        !ifMath.isEqualEps(intPts[i].y, segm.point.getY(), eps)) {\n\n                    segm = new IFVertexOffsetter.PolySegment(new IFPoint(intPts[i].x, intPts[i].y), 0);\n                    split[i].insertSegment(segm);\n                }\n            } else {\n                if (!ifMath.isEqualEps(intPts[i].x, segm.point.getX(), eps) ||\n                    !ifMath.isEqualEps(intPts[i].y, segm.point.getY(), eps)) {\n\n                    if (segm == segmOrig) {\n                        split[i].insertSegment(new IFVertexOffsetter.PolySegment(\n                            segm.point, intPts[i].slope, segm.center, segm.radius));\n                    } else {\n                        // TODO: check formula here\n                        bulge = (intPts[i].slope - intPts[i-1].slope) / (1 + intPts[i].slope * intPts[i-1].slope);\n                        split[i].insertSegment(new IFVertexOffsetter.PolySegment(\n                            segm.point, bulge, segm.center, segm.radius));\n                    }\n\n                    split[i].insertSegment(new IFVertexOffsetter.PolySegment(new IFPoint(intPts[i].x, intPts[i].y), 0));\n\n                    // TODO: check formula here\n                    bulge = (segmOrig.bulge - intPts[i].slope) / (1 + segmOrig.bulge * intPts[i].slope);\n                    segm = new IFVertexOffsetter.PolySegment(\n                        new IFPoint(intPts[i].x, intPts[i].y), bulge, segm.center, segm.radius);\n                } else {\n                    split[i].insertSegment(new IFVertexOffsetter.PolySegment(segm.point, 0));\n                }\n            }\n            startIdx = j;\n            if (ifMath.isEqualEps(intPts[i].x, segmOrig.next.point.getX(), eps) &&\n                    ifMath.isEqualEps(intPts[i].y, segmOrig.next.point.getY(), eps)) {\n\n                ++startIdx;\n                segm = segmOrig.next;\n                segmOrig = segm;\n            }\n        }\n        var joinends = this._polyline.closed;\n        if (startIdx != polyLn.count - 1) {\n            split[i] = new IFVertexOffsetter.PolySegmentContainer();\n            for (var j = startIdx; j < polyLn.count; ++j) {\n                split[i].insertSegment(new IFVertexOffsetter.PolySegment(\n                    segm.point, segm.bulge, segm.center, segm.radius));\n\n                segm = segmOrig.next;\n                segmOrig = segm;\n            }\n        } else {\n            joinends = false;\n        }\n        if (split[0].count == 1) {\n            split = split.slice(1);\n            joinends = false;\n        }\n        if (joinends) {\n            var len = split.length;\n            var lastPLn = split[len-1];\n            var endPt = lastPLn.end.point;\n            var startPt = split[0].head.point;\n            if (len > 1 && ifMath.isEqualEps(endPt.getX(), startPt.getX(), eps) &&\n                    ifMath.isEqualEps(endPt.getY(), startPt.getY(), eps)) {\n\n                lastPLn.deleteSegment(lastPLn.end);\n                segm = split[0].head;\n                for (var i = 0; i < split[0].count; ++i) {\n                    lastPLn.insertSegment(new IFVertexOffsetter.PolySegment(\n                        segm.point, segm.bulge, segm.center, segm.radius));\n\n                    segm = segm.next;\n                }\n                split = split.slice(1);\n            } else {\n                split[0].closed = true;\n            }\n        }\n        // TODO: fix here to be more accurate originally !!! instead\n\n        var splitLast = [];\n        for (var i = 0; i < split.length; ++i) {\n            if (split[i].count != 1) {\n                splitLast.push(split[i]);\n            }\n        }\n\n        return splitLast;\n    };\n\n    IFVertexOffsetter.prototype._excludeCircleInside = function (polyLn, intPts, intPtsMain, offset, resArray) {\n        // TODO: process cases, when several segments appears inside of the circle\n        var segmIdx = 0;\n        var segm = new IFVertexOffsetter.PolySegment(polyLn.head.point, polyLn.head.bulge,\n            polyLn.head.center, polyLn.head.radius);\n\n        var s = polyLn.head;\n        var tmpPoly = new IFVertexOffsetter.PolySegmentContainer();\n        for (var i = 0; i < intPts.length; ++i) {\n            for (var j = segmIdx; j < intPts[i].segmIdx - 1; ++j) {\n                tmpPoly.insertSegment(segm);\n                s = s.next;\n                segm = new IFVertexOffsetter.PolySegment(s.point, s.bulge, s.center, s.radius);\n            }\n\n            if (!segm.bulge) {\n                var res = [null, null];\n                var dLx = s.next.point.getX() - segm.point.getX();\n                var dLy = s.next.point.getY() - segm.point.getY();\n                ifMath.circleLineIntersection(segm.point.getX(), segm.point.getY(), dLx, dLy,\n                    intPtsMain[i].x, intPtsMain[i].y, offset, res);\n\n                if (res[0] != null) {\n                    if (res[0] <= 0) {\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(segm.point, 0));\n                        resArray.push(tmpPoly);\n                    } else if (res[0] > 0 && res[0] < 1) {\n                        var x = segm.point.getX() + dLx * res[0];\n                        var y = segm.point.getY() + dLy * res[0];\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(segm.point, 0));\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(new IFPoint(x, y), 0));\n                        resArray.push(tmpPoly);\n                    } else {\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(segm.point, 0));\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(s.next.point, 0));\n                        resArray.push(tmpPoly);\n                    }\n                }\n                if (res[1] != null && res[1] > res[0] && res[1] < 1) {\n                    tmpPoly = new IFVertexOffsetter.PolySegmentContainer();\n                    x = segm.point.getX() + dLx * res[1];\n                    y = segm.point.getY() + dLy * res[1];\n                    segm = new IFVertexOffsetter.PolySegment(new IFPoint(x, y), 0);\n                } else {\n                    tmpPoly = new IFVertexOffsetter.PolySegmentContainer();\n                }\n            } else {\n                var res = [null, null];\n                ifMath.circleCircleIntersection(s.center.getX(), s.center.getY(), s.radius,\n                    intPtsMain[i].x, intPtsMain[i].y, offset, res);\n\n                if (res[0] != null) {\n                    var bulge0 = this. _calculateBulge(segm.point.getX(), segm.point.getY(),\n                        res[0].getX(), res[0].getY(), s.center.getX(), s.center.getY(), segm.bulge);\n\n                    if (bulge0 < 0 && bulge0 > segm.bulge || bulge0 > 0 && bulge0 < segm.bulge) {\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(segm.point, bulge0, s.center, s.radius));\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(res[0], 0));\n                        resArray.push(tmpPoly);\n                    } else {\n                        tmpPoly.insertSegment(new IFVertexOffsetter.PolySegment(segm.point, 0));\n                        resArray.push(tmpPoly);\n                    }\n                }\n\n                if (res[1] != null) {\n                    var bulge1 = this. _calculateBulge(segm.point.getX(), segm.point.getY(),\n                        res[1].getX(), res[1].getY(), s.center.getX(), s.center.getY(), segm.bulge);\n\n                    if (bulge1 < 0 && bulge1 > segm.bulge && bulge1 < bulge0 ||\n                            bulge1 > 0 && bulge1 < segm.bulge && bulge1 > bulge0) {\n\n                        tmpPoly = new IFVertexOffsetter.PolySegmentContainer();\n                        // TODO: check formula here\n                        var bulge = (segm.bulge - bulge1) / (1 + segm.bulge * bulge1);\n                        segm = new IFVertexOffsetter.PolySegment(new IFPoint(x, y), bulge, s.center, s.radius);\n                    } else {\n                        tmpPoly = new IFVertexOffsetter.PolySegmentContainer();\n                    }\n                } else {\n                    tmpPoly = new IFVertexOffsetter.PolySegmentContainer();\n                }\n            }\n            segmIdx = intPts[i].segmIdx;\n        }\n        for (var j = segmIdx; j < polyLn.count; ++j) {\n            if (segm) {\n                tmpPoly.insertSegment(segm);\n                s = s.next;\n                segm = s ? new IFVertexOffsetter.PolySegment(s.point, s.bulge, s.center, s.radius) : null;\n            }\n        }\n    };\n\n    /**\n     *\n     * @param {Array{IFVertexOffsetter.PolySegmentContainer}} [polyLns]\n     * @param {IFVertexOffsetter.PolySegmentContainer} [basePolyLn]\n     * @param {Number} offset\n     * @param {Array{IFVertexOffsetter.PolySegmentContainer}} [resPolyLns]\n     * @private\n     */\n    IFVertexOffsetter.prototype._gcppClipping = function (polyLns, basePolyLn, offset, resPolyLns) {\n        var poln;\n        for (var i = 0; i < polyLns.length; ++i) {\n            poln = polyLns[i];\n\n            // Find GCPPs from each segment of basePolyLn to poln\n            var s1 = basePolyLn.head;\n            for (var j = 0; j < basePolyLn.count - 1; ++j) {\n                var s2 = poln.head;\n                for (var k = 0; k < poln.count - 1; ++k) {\n                    // TODO: implement (not critical for the first version)\n                    s2 = s2.next;\n                }\n                s1 = s1.next;\n            }\n            resPolyLns.push(poln);\n        }\n    };\n\n    /**\n     *\n     * @param {Array{IFVertexOffsetter.PolySegmentContainer}} [polyLns]\n     * @param {IFVertexOffsetter.PolySegmentContainer} [basePolyLn]\n     * @param {Number} offset\n     * @param {Array{IFVertexOffsetter.PolySegmentContainer}} [resPolyLns]\n     * @private\n     */\n    IFVertexOffsetter.prototype._gcppFilter = function (polyLns, basePolyLn, offset, tolerance, resPolyLns) {\n        var poln;\n        var sqrOffset = (offset - tolerance) * (offset - tolerance);\n        var sqrDst;\n        var dst;\n        var threshold = offset + tolerance;\n        var sqrTrsh = threshold * threshold;\n        for (var i = 0; i < polyLns.length; ++i) {\n            poln = polyLns[i];\n\n            // Find GCPPs from each segment of basePolyLn to poln\n            var s1 = basePolyLn.head;\n            sqrDst = sqrTrsh;\n            for (var j = 0; j < basePolyLn.count - 1 && sqrDst >= sqrOffset; ++j) {\n                var s2 = poln.head;\n                for (var k = 0; k < poln.count - 1 && sqrDst >= sqrOffset; ++k) {\n                    sqrDst = this._getPlSegmSqrDist(s1, s1.next.point, s2, s2.next.point, threshold);\n                    s2 = s2.next;\n                }\n                s1 = s1.next;\n            }\n            if (sqrDst >= sqrOffset) {\n                resPolyLns.push(poln);\n            }\n        }\n    };\n\n    IFVertexOffsetter.prototype._getPlSegmSqrDist = function (s1, pt12, s2, pt22, threshold) {\n        var res;\n        if (!s1.bulge && !s2.bulge) {\n            res = ifMath.getSegmToSegmSqrDist(s1.point, pt12, s2.point, pt22);\n        } else if (!s2.bulge) {\n            res = this._getSegmToArcSqrDist(s1.point, s1.bulge, s1.center, s1.radius, pt12, s2.point, pt22, threshold * threshold);\n        } else if (!s1.bulge) {\n            res = this._getSegmToArcSqrDist(s2.point, s2.bulge, s2.center, s2.radius, pt22, s1.point, pt12, threshold * threshold);\n        } else {\n            res = this._getArcToArcSqrDist(s1, pt12, s2, pt22, threshold);\n        }\n        return res;\n    };\n\n    IFVertexOffsetter.prototype._getSegmToArcSqrDist = function (apt1, bulge, cntr, rd, apt2, spt1, spt2, threshold) {\n        if (ifMath.isEqualEps(spt1.getX(), spt2.getX()) && ifMath.isEqualEps(spt1.getY(), spt2.getY())) {\n            return this._getPtToArcSqrDist(apt1, bulge, cntr, rd, apt2, spt1);\n        }\n\n        var res = threshold;\n        var dst;\n        var intRes = [null, null];\n        var dxL = spt2.getX() - spt1.getX();\n        var dyL = spt2.getY() - spt1.getY();\n        ifMath.circleLineIntersection(spt1.getX(), spt1.getY(), dxL, dyL, cntr.getX(), cntr.getY(), rd, intRes);\n        if (intRes[0] != null && intRes[1] == null) {\n            // Check if distance is 0\n            var ptBulge = this._calculateBulge(apt1.getX(), apt1.getY(), intRes[0].getX(), intRes[0].getY(),\n                cntr.getX(), cntr.getY(), bulge);\n\n            var dxL1 = intRes[1].getX() - spt1.getX();\n            var dyL1 = intRes[1].getY() - spt1.getY();\n            if ((dxL1 < 0 && dxL <= dxL1 || dxL1 >= 0 && dxL >= dxL1) &&\n                    (dyL1 < 0 && dyL <= dyL1 || dyL1 >= 0 && dyL >= dyL1)) {\n\n                // tangential point at segment => min dist 0 or at arc end\n                if (ptBulge < 0 && bulge <= ptBulge || ptBulge >= 0 && bulge >= ptBulge) {\n                    res = 0;\n                } else {\n                    res = ifMath.sqrSegmentDist(spt1.getX(), spt1.getY(), spt2.getX(), spt2.getY(),\n                        apt1.getX(), apt1.getY());\n\n                    dst = ifMath.sqrSegmentDist(spt1.getX(), spt1.getY(), spt2.getX(), spt2.getY(),\n                        apt2.getX(), apt2.getY());\n\n                    if (dst < res) {\n                        res = dst;\n                    }\n                }\n            } else {\n                // min dist at segment end\n                res = this._getPtToArcSqrDist(apt1, bulge, cntr, rd, apt2, spt1);\n                dst = this._getPtToArcSqrDist(apt1, bulge, cntr, rd, apt2, spt2);\n                if (dst < res) {\n                    res = dst;\n                }\n            }\n        } else {\n            if (intRes[0] == null) {\n                // Find a circle point at which tangential line is parallel to segment\n                var ptMin = [null];\n                dst = ifMath.sqrSegmentDist(spt1.getX(), spt1.getY(), spt2.getX(), spt2.getY(),\n                    cntr.getX(), cntr.getY(), ptMin);\n\n                if (ptMin[0] > 0 && ptMin < 1) {\n                    var mptX = spt1.getX() + ptMin[0] * (spt2.getX() - spt1.getX());\n                    var mptY = spt1.getY() + ptMin[0] * (spt2.getY() - spt1.getY());\n                    var tmp = rd / Math.sqrt(dst);\n                    var tptX = cntr.getX() + tmp * (mptX - cntr.getX());\n                    var tptY = cntr.getY() + tmp * (mptY - cntr.getY());\n                    var tptBulge = this._calculateBulge(apt1.getX(), apt1.getY(), tptX, tptY,\n                        cntr.getX(), cntr.getY(), bulge);\n\n                    if (tptBulge < 0 && bulge <= tptBulge || tptBulge >= 0 && bulge >= tptBulge) {\n                        res = ifMath.sqrSegmentDist(spt1.getX(), spt1.getY(), spt2.getX(), spt2.getY(),\n                            tptX, tptY);\n                    }\n                }\n            }\n            dst = ifMath.sqrSegmentDist(spt1.getX(), spt1.getY(), spt2.getX(), spt2.getY(),\n                apt1.getX(), apt1.getY());\n\n            if (dst < res) {\n                res = dst;\n            }\n\n            if (res > 0) {\n                dst = ifMath.sqrSegmentDist(spt1.getX(), spt1.getY(), spt2.getX(), spt2.getY(),\n                    apt2.getX(), apt2.getY());\n\n                if (dst < res) {\n                    res = dst;\n                }\n\n                if (res > 0) {\n                    dst = this._getPtToArcSqrDist(apt1, bulge, cntr, rd, apt2, spt1);\n                    if (dst < res) {\n                        res = dst;\n                    }\n\n                    if (res > 0) {\n                        dst = this._getPtToArcSqrDist(apt1, bulge, cntr, rd, apt2, spt2);\n                        if (dst < res) {\n                            res = dst;\n                        }\n                    }\n                }\n            }\n        }\n        return res;\n    };\n\n    IFVertexOffsetter.prototype._getPtToArcSqrDist = function (apt1, bulge, cntr, rd, apt2, pt) {\n        var res;\n        var sqrDst = ifMath.ptSqrDist(pt.getX(), pt.getY(), cntr.getX(), cntr.getY());\n        if (ifMath.isEqualEps(sqrDst, 0)) {\n            res = rd * rd;\n        } else {\n            var tmp = rd / Math.sqrt(sqrDst);\n            var tptX = cntr.getX() + tmp * (pt.getX() - cntr.getX());\n            var tptY = cntr.getY() + tmp * (pt.getY() - cntr.getY());\n            var tptBulge = this._calculateBulge(apt1.getX(), apt1.getY(), tptX, tptY,\n                cntr.getX(), cntr.getY(), bulge);\n\n            if (tptBulge < 0 && bulge <= tptBulge || tptBulge >= 0 && bulge >= tptBulge) {\n                res = ifMath.ptSqrDist(pt.getX(), pt.getY(), tptX, tptY);\n            } else {\n                res = ifMath.ptSqrDist(pt.getX(), pt.getY(), apt1.getX(), apt1.getY());\n                sqrDst = ifMath.ptSqrDist(pt.getX(), pt.getY(), apt2.getX(), apt2.getY());\n                if (sqrDst < res) {\n                    res = sqrDst;\n                }\n            }\n        }\n        return res;\n    };\n\n    IFVertexOffsetter.prototype._getArcToArcSqrDist = function (s1, pt12, s2, pt22, threshold) {\n        var c1x = s1.center.getX();\n        var c1y = s1.center.getY();\n        var c2x = s2.center.getX();\n        var c2y = s2.center.getY();\n        var tmp = s1.radius + s2.radius + threshold;\n        var sqrTrsh = threshold * threshold;\n\n        if (ifMath.ptSqrDist(c1x, c1y, c2x, c2y) > tmp * tmp) {\n            return sqrTrsh;\n        }\n\n        var res = null;\n        var pts1 = [s1.point, pt12];\n        var pts2 = [s2.point, pt22];\n        var intRes = [null, null];\n        ifMath.circleCircleIntersection(c1x, c1y, s1.radius, c2x, c2y, s2.radius, intRes);\n\n        var ptBulge;\n        var ata1;\n        var ata2;\n        for (var i = 0; i < 2 && intRes[i] != null && res === null; ++i) {\n            ptBulge = this._calculateBulge(s1.point.getX(), s1.point.getY(), intRes[i].getX(), intRes[i].getY(),\n                s1.center.getX(), s1.center.getY(), s1.bulge);\n\n            ata1 = ptBulge < 0 && s1.bulge <= ptBulge || ptBulge >= 0 && s1.bulge >= ptBulge;\n\n            ptBulge = this._calculateBulge(s2.point.getX(), s2.point.getY(), intRes[i].getX(), intRes[i].getY(),\n                s2.center.getX(), s2.center.getY(), s2.bulge);\n\n            ata2 = ptBulge < 0 && s2.bulge <= ptBulge || ptBulge >= 0 && s2.bulge >= ptBulge;\n\n            if (ata1 && ata2) {\n                res = 0;\n            } else if (ata1) {\n                pts1.push(intRes[i]);\n            } else if (ata2) {\n                pts2.push(intRes[i]);\n            }\n        }\n        if (!intRes[0] && (!ifMath.isEqualEps(c1x, c2x) || !ifMath.isEqualEps(c1y, c2y))){\n            var dxL = c2x - c1x;\n            var dyL = c2y - c1y;\n            var intLRes = [null, null];\n            ifMath.circleLineIntersection(c1x, c1y, dxL, dyL, c2x, c2y, s2.radius, intLRes);\n            var ptx;\n            var pty;\n            for (var i = 0; i < 2 && intLRes[i] != null; ++i) {\n                ptx = c1x + dxL * intLRes[i];\n                pty = c1y + dyL * intLRes[i];\n\n                ptBulge = this._calculateBulge(s2.point.getX(), s2.point.getY(), ptx, pty,\n                    s2.center.getX(), s2.center.getY(), s2.bulge);\n\n                ata2 = ptBulge < 0 && s2.bulge <= ptBulge || ptBulge >= 0 && s2.bulge >= ptBulge;\n\n                if (ata2) {\n                    pts2.push(new IFPoint(ptx, pty));\n                }\n            }\n            dxL = -dxL;\n            dyL = -dyL;\n            intLRes = [null, null];\n            ifMath.circleLineIntersection(c2x, c2y, dxL, dyL, c1x, c1y, s1.radius, intLRes);\n            for (var i = 0; i < 2 && intLRes[i] != null; ++i) {\n                ptx = c2x + dxL * intLRes[i];\n                pty = c2y + dyL * intLRes[i];\n\n                ptBulge = this._calculateBulge(s1.point.getX(), s1.point.getY(), ptx, pty,\n                    s1.center.getX(), s1.center.getY(), s1.bulge);\n\n                ata1 = ptBulge < 0 && s1.bulge <= ptBulge || ptBulge >= 0 && s1.bulge >= ptBulge;\n\n                if (ata1) {\n                    pts1.push(new IFPoint(ptx, pty));\n                }\n            }\n        }\n        if (res !== 0) {\n            res = sqrTrsh;\n            var dst;\n            for (var i = 0; i < pts1.length && res > 0; ++i) {\n                dst = this._getPtToArcSqrDist(s2.point, s2.bulge, s2.center, s2.radius, pt22, pts1[i]);\n                if (dst < res) {\n                    res = dst;\n                }\n            }\n            for (var i = 0; i < pts2.length && res > 0; ++i) {\n                dst = this._getPtToArcSqrDist(s1.point, s1.bulge, s1.center, s1.radius, pt12, pts2[i]);\n                if (dst < res) {\n                    res = dst;\n                }\n            }\n        }\n        return res;\n    };\n\n    IFVertexOffsetter.prototype._roundOut = function (num) {\n        var newNum = Math.round(num * this._tolRange) / this._tolRange;\n        return newNum;\n    };\n\n    IFVertexOffsetter.prototype._genCurves = function (polyLns, outset, tolerance) {\n        var poln;\n        for (var i = 0; i < polyLns.length; ++i) {\n            poln = polyLns[i];\n            var segm = poln.head;\n            var vertices = [];\n            var stPt = new IFPoint(this._roundOut(segm.point.getX()), this._roundOut(segm.point.getY()));\n            var endPt = stPt;\n            for (var j = 0; j < poln.count - 1; ++j) {\n                if (!segm.bulge) {\n                    vertices.push({\n                        c : IFVertex.Command.Line,\n                        x : this._roundOut(segm.next.point.getX()),\n                        y : this._roundOut(segm.next.point.getY())\n                    });\n                    if (j == poln.count - 2) {\n                        endPt = new IFPoint(this._roundOut(segm.next.point.getX()), this._roundOut(segm.next.point.getY()));\n                    }\n                } else {\n                    // Construct Bezier curves\n                    this._genBeziers(segm.point, segm.next.point, segm.bulge, segm.center,\n                        segm.radius, tolerance, vertices);\n\n                    if (j == poln.count - 2) {\n                        var vert = vertices[vertices.length - 3];\n                        endPt = new IFPoint(vert.x, vert.y);\n                    }\n                }\n                segm = segm.next;\n            }\n            var part = {stPt: stPt, endPt: endPt, vrt: vertices};\n            outset.push(part);\n        }\n    };\n\n    IFVertexOffsetter.prototype._genBeziers = function (\n            p1, p2, bulge, cntr, radius, tolerance, vertices) {\n\n        // Drawing an elliptical arc using polylines, quadratic or cubic Bezier curves\n        // L. Maisonobe, 2003\n\n        // bulge == tg(angleDelta / 4)\n        // 1. count number of cubic Bezier curves to satisfy tolerance\n        var alpha = Math.abs(Math.atan(bulge) * 4);\n        var n = Math.ceil(alpha * 2 / Math.PI);\n        alpha = alpha / n;\n        while (n <= 32 && this._getCubicBezierArcError(alpha, radius) > tolerance) {\n            alpha = alpha / 2;\n            n = n * 2;\n        }\n\n        // 2. Divide arc into n sub-arcs, and approximate each arc with the cubic Bezier curve\n        if (bulge > 0) {\n            alpha = -alpha;\n        }\n        var cosAlpha = Math.cos(alpha);\n        var sinAlpha = Math.sin(alpha);\n        //var tgHalfAlpha = sinAlpha / (cosAlpha + 1);\n        //var tgHalfAlpha = Math.sqrt((1- cosAlpha) / (1 + cosAlpha));\n        //var k = radius * sinAlpha * (Math.sqrt(4 + 3 * tgHalfAlpha * tgHalfAlpha) - 1) / 3;\n        var tgHalfAlphaSqr = (1- cosAlpha) / (1 + cosAlpha);\n        var k = radius * sinAlpha * (Math.sqrt(4 + 3 * tgHalfAlphaSqr) - 1) / 3;\n        var cosPhi2 = (p1.getX() - cntr.getX()) / radius;\n        var sinPhi2 = (p1.getY() - cntr.getY()) / radius;\n        var cosPhi, sinPhi;\n        var x3 = p1.getX();\n        var y3 = p1.getY();\n        var x0, y0, x1, y1, x2, y2;\n        for (var i = 0; i < n; ++i) {\n            x0 = x3;\n            y0 = y3;\n            /*if (i == n - 1) {\n                x3 = p2.getX();\n                y3 = p2.getY();\n            } else {*/\n                cosPhi = cosPhi2;\n                sinPhi = sinPhi2;\n                cosPhi2 = cosPhi * cosAlpha - sinPhi * sinAlpha;\n                sinPhi2 = sinPhi * cosAlpha + cosPhi * sinAlpha;\n                x3 = cntr.getX() + radius * cosPhi2;\n                y3 = cntr.getY() + radius * sinPhi2;\n            //}\n            x1 = x0 - k * sinPhi;\n            y1 = y0 + k * cosPhi;\n            x2 = x3 + k * sinPhi2;\n            y2 = y3 - k * cosPhi2;\n\n            vertices.push({\n                c : IFVertex.Command.Curve2,\n                x : this._roundOut(x3),\n                y : this._roundOut(y3)\n            });\n            vertices.push({\n                c : IFVertex.Command.Curve2,\n                x : this._roundOut(x1),\n                y : this._roundOut(y1)\n            });\n            vertices.push({\n                c : IFVertex.Command.Curve2,\n                x : this._roundOut(x2),\n                y : this._roundOut(y2)\n            });\n        }\n    };\n\n    IFVertexOffsetter.prototype._getCubicBezierArcError = function (alpha, radius) {\n        var k = 5.15347174 * radius;\n        var cosAlpha = Math.cos(alpha);\n        var cosAlphaSqr = cosAlpha * cosAlpha;\n        var cos2Alpha = 2 * cosAlphaSqr - 1;\n        var cos3Alpha = (4 * cosAlphaSqr - 3) * cosAlpha;\n        var c0 = -19.65763511 + 0.00022979 * cosAlpha + 0.00042715 * cos2Alpha + 0.00103256 * cos3Alpha;\n        var c1 = 9.92683097 + 0.00045907 * cosAlpha + 0.00174813 * cos2Alpha - 0.00034153 * cos3Alpha;\n        return k * Math.exp(c0 + c1 * alpha);\n    };\n\n    IFVertexOffsetter.prototype._rewindVertices = function () {\n        for (var i = 0; i < this._pieces.length; ++i) {\n            this._pieces[i].rewindVertices(0);\n        }\n    };\n\n    IFVertexOffsetter.prototype._readVertex = function (vertex) {\n        if (this._pieces[this._pieceIdx] && this._pieces[this._pieceIdx].readVertex(vertex)) {\n            return true;\n        } else {\n            ++this._pieceIdx;\n            return (this._pieces[this._pieceIdx] && this._pieces[this._pieceIdx].readVertex(vertex));\n        }\n    };\n\n    /** @override */\n    IFVertexOffsetter.prototype.toString = function () {\n        return \"[Object IFVertexOffsetter]\";\n    };\n\n    _.IFVertexOffsetter = IFVertexOffsetter;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertexpixelaligner.js",
    "content": "(function (_) {\n    /**\n     * Vertex converter that transforms the vertices so that they align with the pixel grid\n     * which basically is Math.floor(vertex) + 0.5\n     * @class IFVertexPixelAligner\n     * @extends IFVertexSource\n     * @param {IFVertexSource} source the underyling vertex source to work on\n     * @version 1.0\n     * @constructor\n     */\n    function IFVertexPixelAligner(source) {\n        this._source = source;\n    }\n\n    IFObject.inherit(IFVertexPixelAligner, IFVertexSource);\n\n    /**\n     * @type {IFVertexSource}\n     * @private\n     */\n    IFVertexPixelAligner.prototype._source = null;\n\n    /** @override */\n    IFVertexPixelAligner.prototype.rewindVertices = function (index) {\n        return this._source.rewindVertices(index);\n    };\n\n    /** override */\n    IFVertexPixelAligner.prototype.readVertex = function (vertex) {\n        if (this._source.readVertex(vertex)) {\n            if (vertex.command >= IFVertex.Command.Move && vertex.command < IFVertex.Command.Close) {\n                vertex.x = Math.floor(vertex.x) + 0.5;\n                vertex.y = Math.floor(vertex.y) + 0.5;\n            }\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFVertexPixelAligner.prototype.toString = function () {\n        return \"[Object IFVertexPixelAligner]\";\n    };\n\n    _.IFVertexPixelAligner = IFVertexPixelAligner;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertexsource.js",
    "content": "(function (_) {\n\n    /**\n     * A source of vertices\n     * @class IFVertexSource\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    function IFVertexSource() {\n    }\n\n    /**\n     * Rewind to a given index to read from there\n     * @param {Number} index the index to rewind to\n     * @return {Boolean} true if rewinded to the given index,\n     * false otherwise i.e. if index is out of range\n     * @version 1.0\n     */\n    IFVertexSource.prototype.rewindVertices = function (index) {\n        return false;\n    }\n\n    /**\n     * Read a vertex at the current index and increases the current index\n     * to go to the next vertex on the next read\n     * @param {IFVertex} vertex the vertex to read into\n     * @return {Boolean} true if a vertex could be read, false otherwise,\n     * i.e. if the end is already reached.\n     * @version 1.0\n     */\n    IFVertexSource.prototype.readVertex = function (vertex) {\n        return false;\n    }\n\n    /** @override */\n    IFVertexSource.prototype.toString = function () {\n        return \"[Object IFVertexSource]\";\n    }\n\n    _.IFVertexSource = IFVertexSource;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertextarget.js",
    "content": "(function (_) {\n\n    /**\n     * A target of vertices\n     * @class IFVertexTarget\n     * @mixin\n     * @constructor\n     * @version 1.0\n     */\n    function IFVertexTarget() {\n    }\n\n    /**\n     * Add a new vertex to the end of this target\n     * @param {Number} command the command of the vertex\n     * @param {Number} [x] x-coordinate of vertex, defaults to 0\n     * @param {Number} [y] y-coordinate of vertex, defaults to 0\n     */\n    IFVertexTarget.prototype.addVertex = function (command, x, y) {\n        throw new Error(\"Not Supported\");\n    }\n\n    /**\n     * Append another vertex source to this one\n     * @param {IFVertexSource} source the source to append to this one\n     * @param {Number} [index] optional index to start reading from source, defaults to 0\n     */\n    IFVertexTarget.prototype.appendVertices = function (source, index) {\n        if (source.rewindVertices(index ? index : 0)) {\n            var vertex = new IFVertex();\n            while (source.readVertex(vertex)) {\n                this.addVertex(vertex.command, vertex.x, vertex.y);\n            }\n        }\n    }\n\n    /**\n     * Clear all vertices in this target\n     * @version 1.0\n     */\n    IFVertexTarget.prototype.clearVertices = function () {\n        throw new Error('Not Supported.');\n    }\n\n    /** @override */\n    IFVertexTarget.prototype.toString = function () {\n        return \"[Object IFVertexTarget]\";\n    }\n\n    _.IFVertexTarget = IFVertexTarget;\n})(this);"
  },
  {
    "path": "src/infinity/vertex/vertextransformer.js",
    "content": "(function (_) {\n    /**\n     * Vertex converter that transforms the vertices with a given transformation\n     * @class IFVertexTransformer\n     * @extends IFVertexSource\n     * @param {IFVertexSource} source the underyling vertex source to work on\n     * @param {IFTransform} [transform] the transformation used to transform the vertices,\n     * may be null to set it later on or ignore it\n     * @version 1.0\n     * @constructor\n     */\n    function IFVertexTransformer(source, transform) {\n        this._source = source;\n        this._transform = transform;\n    }\n\n    IFObject.inherit(IFVertexTransformer, IFVertexSource);\n\n    IFVertexTransformer.transformVertex = function (vertex, transform) {\n        if (transform) {\n            switch (vertex.command) {\n                case IFVertex.Command.Move:\n                case IFVertex.Command.Line:\n                case IFVertex.Command.Curve:\n                case IFVertex.Command.Curve2:\n                    transform.map(vertex);\n                    break;\n                case IFVertex.Command.Close:\n                    break;\n                default:\n                    throw new Error(\"Unknown vertex command: \" + vertex.command.toString());\n            }\n        }\n    };\n\n    /**\n     * @type {IFVertexSource}\n     * @private\n     */\n    IFVertexTransformer.prototype._source = null;\n\n    /**\n     * @type {IFTransform}\n     * @private\n     */\n    IFVertexTransformer.prototype._transform = null;\n\n    /**\n     * Get the current transform\n     * @return {IFTransform}\n     * @version 1.0\n     */\n    IFVertexTransformer.prototype.getTransform = function () {\n        return this._transform;\n    };\n\n    /**\n     * Assign a transform\n     * @param {IFTransform} transform\n     * @version 1.0\n     */\n    IFVertexTransformer.prototype.setTransform = function (transform) {\n        this._transform = transform;\n    };\n\n    /** @override */\n    IFVertexTransformer.prototype.rewindVertices = function (index) {\n        return this._source.rewindVertices(index);\n    };\n\n    /** override */\n    IFVertexTransformer.prototype.readVertex = function (vertex) {\n        if (this._source.readVertex(vertex)) {\n            IFVertexTransformer.transformVertex(vertex, this._transform);\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFVertexTransformer.prototype.toString = function () {\n        return \"[Object IFVertexTransformer]\";\n    };\n\n    _.IFVertexTransformer = IFVertexTransformer;\n})(this);"
  },
  {
    "path": "src/infinity/view/scenestage.js",
    "content": "(function (_) {\n    /**\n     * The scene stage\n     * @param {IFView} view\n     * @class IFSceneStage\n     * @extends IFStage\n     * @constructor\n     */\n    function IFSceneStage(view) {\n        IFStage.call(this, view);\n        view.getScene().addEventListener(IFScene.InvalidationRequestEvent, this._sceneInvalidationRequest, this);\n    }\n    IFObject.inherit(IFSceneStage, IFStage);\n\n    /**\n     * @type {IFPaintCanvas}\n     * @private\n     */\n    IFSceneStage.prototype._pixelContentCanvas = null;\n\n    /** @override */\n    IFSceneStage.prototype.release = function () {\n        this._view.getScene().removeEventListener(IFScene.InvalidationRequestEvent, this._sceneInvalidationRequest, this);\n    };\n\n    /** @override */\n    IFSceneStage.prototype.resize = function (width, height) {\n        IFStage.prototype.resize.call(this, width, height);\n\n        // Resize pixel content canvas if any\n        if (this._pixelContentCanvas) {\n            this._pixelContentCanvas.resize(width, height);\n        }\n    };\n\n    /** @override */\n    IFSceneStage.prototype.paint = function (context) {\n        if (context.dirtyMatcher) {\n            context.dirtyMatcher.transform(this._view.getViewTransform());\n        }\n\n        // Handle rendering in pixel mode but only if we're not at 100%\n        if (this._view.getViewConfiguration().pixelMode && !ifMath.isEqualEps(this._view.getZoom(), 1.0)) {\n            // Create and size our pixel content canvas\n            if (!this._pixelContentCanvas) {\n                this._pixelContentCanvas = new IFPaintCanvas();\n                this._pixelContentCanvas.resize(context.canvas.getWidth(), context.canvas.getHeight());\n            }\n\n            // Pixel content canvas always renders at scale = 100%\n            var elemsBBox = this._view.getScene().getChildrenPaintBBox();\n            this._pixelContentCanvas.prepare([elemsBBox]);\n            var tl = elemsBBox.getSide(IFRect.Side.TOP_LEFT);\n            var width = elemsBBox.getWidth();\n            var height = elemsBBox.getHeight();\n            this._pixelContentCanvas.setTransform(new IFTransform(1, 0, 0, 1, -tl.getX(), -tl.getY()));\n            this._pixelContentCanvas.resize(width, height);\n\n            // Save source canvas, exchange it with pixel content canvas and paint the scene\n            var sourceCanvas = context.canvas;\n            context.canvas = this._pixelContentCanvas;\n            this._view.getScene().render(context);\n\n            // Now render our pixel content canvas at the given scale on our source canvas\n            sourceCanvas.setTransform(this._view.getWorldTransform());\n            sourceCanvas.drawImage(this._pixelContentCanvas, tl.getX(), tl.getY(), true);\n\n            // Finally reset our source canvas\n            this._pixelContentCanvas.finish();\n            context.canvas = sourceCanvas;\n        } else {\n            // Render regular vectors\n            this._pixelContentCanvas = null;\n            context.canvas.setOrigin(new IFPoint(this._view._scrollX, this._view._scrollY));\n            context.canvas.setScale(this._view._zoom);\n            this._view.getScene().render(context);\n        }\n    };\n\n    /**\n     * Event listener for scene's repaintRequest\n     * @param {IFScene.InvalidationRequestEvent} event the invalidation request event\n     * @private\n     */\n    IFSceneStage.prototype._sceneInvalidationRequest = function (event) {\n        var area = event.area;\n        if (area) {\n            // Ensure to map the scene area into view coordinates, first\n            // TODO : How to handle view margins!?\n            area = this._view.getWorldTransform().mapRect(area);\n        }\n        this.invalidate(area);\n    };\n\n    /** @override */\n    IFSceneStage.prototype.toString = function () {\n        return \"[Object IFSceneStage]\";\n    };\n\n    _.IFSceneStage = IFSceneStage;\n})(this);"
  },
  {
    "path": "src/infinity/view/stage.js",
    "content": "(function (_) {\n    /**\n     * A stage (layer) within a view\n     * @param {IFView} view\n     * @class IFStage\n     * @constructor\n     */\n    function IFStage(view) {\n        this._view = view;\n        this._canvas = new IFPaintCanvas();\n        this._paintContext = new IFPaintContext();\n        this._paintContext.configuration = view.getViewConfiguration() ?\n            view.getViewConfiguration() : new IFPaintConfiguration();\n        this._paintContext.canvas = this._canvas;\n        this._dirtyList = new IFDirtyList();\n    }\n\n    /**\n     * @type {IFView}\n     * @private\n     */\n    IFStage.prototype._view = null;\n\n    /**\n     * @type {IFPaintCanvas}\n     * @private\n     */\n    IFStage.prototype._canvas = null;\n\n    /**\n     * @type {IFPaintContext}\n     * @private\n     */\n    IFStage.prototype._paintContext = null;\n\n    /**\n     * @type IFDirtyList\n     * @private\n     */\n    IFStage.prototype._dirtyList = null;\n\n    /**\n     * Id of next frame for repainting\n     * @type {Number}\n     * @private\n     */\n    IFStage.prototype._repaintRequestFrameId = null;\n\n    IFStage.prototype.show = function () {\n        this._canvas._canvasContext.canvas.style.visibility = '';\n    };\n\n    IFStage.prototype.hide = function () {\n        this._canvas._canvasContext.canvas.style.visibility = 'hidden';\n    };\n\n    /**\n     * Called to release the stage\n     */\n    IFStage.prototype.release = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called to invalidate this paint widget or only a part of it\n     * @param {IFRect} [area] the area to invalidate. If null (default),\n     * then this clears the whole dirty areas and requests a full repaint\n     * @return {Boolean} true if an invalidation ocurred, false if not\n     * @version 1.0\n     */\n    IFStage.prototype.invalidate = function (area) {\n        if (!area || area.isEmpty()) {\n            // reset any previous dirty areas and add the whole view area\n            this._dirtyList.reset();\n            area = this._dirtyList.getArea();\n        }\n\n        if (area && this._dirtyList.dirty(area.getX(), area.getY(), area.getWidth(), area.getHeight())) {\n            // Request a repaint for the next frame\n            if (this._repaintRequestFrameId == null) {\n                this._repaintRequestFrameId = ifPlatform.scheduleFrame(this._repaint.bind(this));\n            }\n\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Called whenever this widget should paint itself. Note that the canvas'\n     * prepare / finish methods are automatically called and the clipping\n     * region of the canvas is already set correctly.\n     * @param {IFPaintContext} context the paint context to paint into\n     * @private\n     */\n    IFStage.prototype.paint = function (context) {\n        // NO-OP by default\n    };\n\n    /**\n     * Called to resize this layer\n     * @param {Number} width\n     * @param {Number} height\n     */\n    IFStage.prototype.resize = function (width, height) {\n        this._canvas.resize(width, height);\n        this.updateViewArea();\n    };\n\n    /**\n     * Called to update the view area\n     */\n    IFStage.prototype.updateViewArea = function () {\n        var viewArea = new IFRect(0, 0, this._view.getWidth(), this._view.getHeight());\n        if (!IFRect.equals(this._dirtyList.getArea(), viewArea)) {\n            this._dirtyList.setArea(viewArea);\n            this.invalidate();\n        }\n    };\n\n    /**\n     * Called to repaint all dirty regions\n     * @private\n     */\n    IFStage.prototype._repaint = function () {\n        // Get and flush existing dirty areas\n        var dirtyListMatcher = this._dirtyList.flush();\n        if (dirtyListMatcher != null) {\n            // Prepare our canvas with the dirty rectangles\n            this._canvas.prepare(dirtyListMatcher.getDirtyRectangles());\n\n            // Prepare our paint context\n            this._paintContext.dirtyMatcher = dirtyListMatcher;\n\n            // Call our paint routine if any\n            if (this.paint) {\n                this.paint.call(this, this._paintContext);\n            }\n\n            // Finish canvas\n            this._canvas.finish();\n        }\n\n        // Reset any repaint request id to free for the next call\n        this._repaintRequestFrameId = null;\n    };\n\n    /** @override */\n    IFStage.prototype.toString = function () {\n        return \"[Object IFStage]\";\n    };\n\n    _.IFStage = IFStage;\n})(this);"
  },
  {
    "path": "src/infinity/view/view.js",
    "content": "(function (_) {\n    /**\n     * IFView is a widget to render a scene\n     * @param {IFScene} [scene] the scene this view is bound too, defaults to null\n     * @class IFView\n     * @extends GUIWidget\n     * @constructor\n     */\n    function IFView(scene) {\n        this._updateViewTransforms(true);\n        GUIWidget.apply(this, arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : null);\n\n        this._scene = scene;\n\n        this._viewOffset = [0, 0, 0, 0];\n        this._viewMargin = [0, 0, 0, 0];\n        this._pageConfigurations = [];\n\n        // TODO : Move all transformation / view stuff into viewConfiguration!!\n        if (!this._viewConfiguration) {\n            this._viewConfiguration = new IFScenePaintConfiguration();\n        }\n\n        // Initialize our stages\n        this._initStages();\n\n        // Subscribe to some scene events\n        scene.addEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n        scene.addEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n        scene.addEventListener(IFNode.AfterRemoveEvent, this._afterRemove, this);\n    }\n\n    IFObject.inherit(IFView, GUIWidget);\n\n    /**\n     * Global view options\n     * @type {Object}\n     * @version 1.0\n     */\n    IFView.options = {\n        /**\n         * The smallest zoom factor allowed whereas 0 = 0% and 1.0 = 100%\n         * @type {Number}\n         * @version 1.0\n         */\n        minZoomFactor: 0.05,\n\n        /**\n         * The largest zoom factor allowed whereas 0 = 0% and 1.0 = 100%\n         * @type {Number}\n         * @version 1.0\n         */\n        maxZoomFactor: 512.0,\n\n        /**\n         * Either fit's the active page in screen (true)\n         * or just centers it at 100% when there's no\n         * saved view configuration for the page\n         */\n        defaultFitActivePage: false\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFView.TransformEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * An event whenever the view's transformation has changed\n     * @class IFView.TransformEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFView.TransformEvent = function () {\n    };\n    IFObject.inherit(IFView.TransformEvent, GEvent);\n\n    /** @override */\n    IFView.TransformEvent.prototype.toString = function () {\n        return \"[Object IFView.TransformEvent]\";\n    };\n\n    IFView.TRANSFORMEVENT = new IFView.TransformEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFView Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {IFScene}\n     * @private\n     */\n    IFView.prototype._scene = null;\n\n    /**\n     * An array of stages\n     * @type {Array<IFStage>}\n     * @private\n     */\n    IFView.prototype._stages = null;\n\n    /**\n     * Left, top, right, bottom offsets\n     * @type {Array<Number>}\n     * @private\n     */\n    IFView.prototype._viewOffset = null;\n\n    /**\n     * Left, top, right, bottom margins\n     * @type {Array<Number>}\n     * @private\n     */\n    IFView.prototype._viewMargin = null;\n\n    /**\n     * The current horizontal scroll of this view\n     * @type Number\n     * @private\n     */\n    IFView.prototype._scrollX = 0;\n\n    /**\n     * The current vertical scroll of this view\n     * @type Number\n     * @private\n     */\n    IFView.prototype._scrollY = 0;\n\n    /**\n     * The current zoom of this view\n     * @type Number\n     * @private\n     */\n    IFView.prototype._zoom = 1.0;\n\n    /**\n     * World to view transformation\n     * @type {IFTransform}\n     * @private\n     */\n    IFView.prototype._worldToViewTransform = null;\n\n    /**\n     * View to world transform\n     * @type {IFTransform}\n     * @private\n     */\n    IFView.prototype._viewToWorldTransform = null;\n\n    /**\n     * @type {IFScenePaintConfiguration}\n     * @private\n     */\n    IFView.prototype._viewConfiguration = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    IFView.prototype._pageConfigurations = null;\n\n    /** @override */\n    IFView.prototype.resize = function (width, height) {\n        GUIWidget.prototype.resize.call(this, width, height);\n\n        // Resize stages if any\n        if (this._stages) {\n            for (var i = 0; i < this._stages.length; ++i) {\n                this._stages[i].resize(this.getWidth(), this.getHeight());\n            }\n        }\n    };\n\n    /**\n     * Return the scene this view is rendering\n     * @returns {IFScene}\n     */\n    IFView.prototype.getScene = function () {\n        return this._scene;\n    };\n\n    /**\n     * @return {IFScenePaintConfiguration}\n     */\n    IFView.prototype.getViewConfiguration = function () {\n        return this._viewConfiguration;\n    };\n\n    /**\n     * Get the current view offset\n     * @return {Array<Number>} Left, top, right, bottom\n     */\n    IFView.prototype.getViewOffset = function () {\n        return this._viewOffset;\n    };\n\n    /**\n     * Set the current view offset\n     * @param {Array<Number>} Offset Left, top, right, bottom\n     */\n    IFView.prototype.setViewOffset = function (offset) {\n        this._viewOffset = [0, 0, 0, 0];\n        if (offset && offset.length > 0) {\n            for (var i = 0; i < Math.min(4, offset.length); ++i) {\n                this._viewOffset[i] = offset[i];\n            }\n\n            // Let each stage update it's view area\n            if (this._stages) {\n                for (var i = 0; i < this._stages.length; ++i) {\n                    this._stages[i].updateViewArea();\n                }\n            }\n        }\n    };\n\n    /**\n     * Get the current view margins\n     * @return {Array<Number>} Left, top, right, bottom\n     * @version 1.0\n     */\n    IFView.prototype.getViewMargin = function () {\n        return this._viewMargin;\n    };\n\n    /**\n     * Set the current view margins\n     * @param {Array<Number>} margin Left, top, right, bottom\n     * @version 1.0\n     */\n    IFView.prototype.setViewMargin = function (margin) {\n        this._viewMargin = [0, 0, 0, 0];\n        if (margin && margin.length > 0) {\n            for (var i = 0; i < Math.min(4, margin.length); ++i) {\n                this._viewMargin[i] = margin[i];\n                this.invalidate();\n            }\n        }\n    };\n\n    /**\n     * @return {Number} The current horizontal scroll position of this view\n     * @version 1.0\n     */\n    IFView.prototype.getScrollX = function () {\n        return this._scrollX;\n    };\n\n    /**\n     * @return {Number} The current vertical scroll position of this view\n     * @version 1.0\n     */\n    IFView.prototype.getScrollY = function () {\n        return this._scrollY;\n    };\n\n    /**\n     * @return {Number} The current zoom of this view\n     * @version 1.0\n     */\n    IFView.prototype.getZoom = function () {\n        return this._zoom;\n    };\n\n    /**\n     * Returns the current transformation used for transforming\n     * world coordinates into view coordinates\n     * @returns {IFTransform}\n     */\n    IFView.prototype.getWorldTransform = function () {\n        return this._worldToViewTransform;\n    };\n\n    /**\n     * Returns the current transformation used for transforming\n     * view coordinates into world coordinates\n     * @returns {IFTransform}\n     */\n    IFView.prototype.getViewTransform = function () {\n        return this._viewToWorldTransform;\n    };\n\n    /**\n     * Returns the actual viewBox honoring offset and optional margin\n     * @param {Boolean} [noMargin] whether to ignore margin or not,\n     * defaults to false (= include margin)\n     * @returns {IFRect}\n     */\n    IFView.prototype.getViewBox = function (noMargin) {\n        var xOffset = this._viewOffset[0] + (!noMargin ? this._viewMargin[0] : 0);\n        var yOffset = this._viewOffset[1] + (!noMargin ? this._viewMargin[1] : 0);\n        return new IFRect(\n            xOffset,\n            yOffset,\n            this.getWidth() - (this._viewOffset[2] + (!noMargin ? this._viewMargin[2] : 0) + xOffset),\n            this.getHeight() - (this._viewOffset[3] + (!noMargin ? this._viewMargin[3] : 0) + yOffset)\n        );\n    };\n\n    /**\n     * Transform the current view\n     * @param {Number} scrollX the horizontal scrolling\n     * @param {Number} scrollY the vertical scrolling\n     * @param {Number} zoom the zoom\n     */\n    IFView.prototype.transform = function (scrollX, scrollY, zoom) {\n        this._scrollX = scrollX;\n        this._scrollY = scrollY;\n        this._zoom = zoom;\n        this._updateViewTransforms();\n    };\n\n    /**\n     * Zoom and center to a given point\n     * @param {IFPoint} center the center point for the view in world coordinates\n     * which will become the new center point\n     * @param {Number} [zoom] the new zoom, defaults to current zoom\n     * @version 1.0\n     */\n    IFView.prototype.zoomAtCenter = function (center, zoom) {\n        zoom = zoom || this._zoom;\n        var viewCenter = this.getViewBox().getSide(IFRect.Side.CENTER);\n        var viewWorldCenter = this._worldToViewTransform.mapPoint(center);\n        var normalizedZoom = Math.min(IFView.options.maxZoomFactor, Math.max(zoom, IFView.options.minZoomFactor));\n        if (normalizedZoom == this._zoom && IFPoint.equals(viewWorldCenter, viewCenter)) {\n            return;\n        }\n\n        // Calculate new scroll position & zoom\n        var tmpTransform = new IFTransform()\n            .translated(-center.getX(), -center.getY())\n            .scaled(normalizedZoom, normalizedZoom)\n            .translated(viewCenter.getX(), viewCenter.getY());\n\n        var matrix = tmpTransform.getMatrix();\n        this._scrollX = -matrix[4];\n        this._scrollY = -matrix[5];\n        this._zoom = normalizedZoom;\n\n        this._updateViewTransforms();\n    };\n\n    /**\n     * Zoom at a specific point\n     * @param {IFPoint} pos the point to zoom at in world coordinates\n     * @param {Number} zoom the new zoom value\n     */\n    IFView.prototype.zoomAt = function (pos, zoom) {\n        var viewCenter = this.getViewBox().getSide(IFRect.Side.CENTER);\n        var viewWorldCenter = this._viewToWorldTransform.mapPoint(viewCenter);\n        var deltaPos = viewWorldCenter.subtract(pos);\n        var zoomDelta = zoom / this._zoom;\n        this.zoomAtCenter(new IFPoint(pos.getX() + (deltaPos.getX() / zoomDelta), pos.getY() + (deltaPos.getY() / zoomDelta)), zoom);\n    };\n\n    /**\n     * Zoom to fit all in a given rect whereas the center of the rect\n     * becomes the new center of the view\n     * @param {IFRect} rect\n     * @param {Boolean} [reverse] if set, the reverse action will be taken so\n     * that the view is zoomed out onto the given rect. Defaults to false\n     */\n    IFView.prototype.zoomAll = function (rect, reverse) {\n        var center = rect.getSide(IFRect.Side.CENTER);\n        var width = rect.getWidth();\n        var height = rect.getHeight();\n        var vbox = this.getViewBox();\n\n        if (reverse) {\n            var viewRect = this._worldToViewTransform.mapRect(new IFRect(center.getX() - width / 2, center.getY() - height / 2, width, height));\n            var invZoom = this._zoom * Math.min(1.0, Math.max(viewRect.getWidth() / vbox.getWidth(), viewRect.getHeight() / vbox.getHeight()));\n            this.zoomAtCenter(center, invZoom);\n        } else {\n            this.zoomAtCenter(center, 1.0 / Math.max(width / vbox.getWidth(), height / vbox.getHeight()));\n        }\n    };\n\n    /**\n     * Zoom to the active page if any. This will either reload\n     * a saved view configuration for the page or it will fit\n     * it into the screen depending on the options\n     */\n    IFView.prototype.zoomActivePage = function () {\n        var activePage = this._scene.getActivePage();\n        if (activePage) {\n            // Look for an existing configuration\n            var pageConfig = this._getOrCreatePageConfig(activePage, false);\n            if (pageConfig) {\n                // ok, restore and return\n                this.transform(pageConfig.scrollX, pageConfig.scrollY, pageConfig.zoom);\n            } else {\n                // Coming here means we'll do a default action\n                var pageBBox = activePage.getPaintBBox();\n                if (pageBBox && !pageBBox.isEmpty()) {\n                    if (IFView.options.defaultFitActivePage) {\n                        this.zoomAll(pageBBox, false);\n                    } else {\n                        this.zoomAtCenter(pageBBox.getSide(IFRect.Side.CENTER), 1.0);\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Scroll the view by a given subtract value\n     * @param {Number} dx horizontal subtract\n     * @param {Number} dy vertical subtract\n     * @version 1.0\n     */\n    IFView.prototype.scrollBy = function (dx, dy) {\n        if (dx != 0 || dy != 0) {\n            this._scrollX = this._scrollX + dx;\n            this._scrollY = this._scrollY + dy;\n            this._updateViewTransforms();\n        }\n    };\n\n    /**\n     * Called to invalidate all stages\n     * @param {IFRect} [area] the area to invalidate in view-\n     * coordinates. If null then this clears the whole dirty areas\n     * and requests a full repaint. Defaults to null.\n     * @return {Boolean} true if any invalidation ocurred, false if not\n     * @version 1.0\n     */\n    IFView.prototype.invalidate = function (area) {\n        var result = false;\n        if (this._stages) {\n            for (var i = 0; i < this._stages.length; ++i) {\n                result = this._stages[i].invalidate(area) || result;\n            }\n        }\n        return result;\n    };\n\n    /**\n     * Add a stage\n     * @param {IFStage} stage\n     * @returns {IFStage} the provided stage\n     * @private\n     */\n    IFView.prototype.addStage = function (stage) {\n        if (this._stages == null) {\n            this._stages = [];\n        }\n\n        this._stages.push(stage);\n\n        var stageElement = stage._canvas._canvasContext.canvas;\n        stageElement.style.position = 'absolute';\n        stageElement.style.cursor = 'inherit';\n        stage.resize(this.getWidth(), this.getHeight());\n        this._htmlElement.appendChild(stageElement);\n\n        return stage;\n    };\n\n    /**\n     * Retrieve a stage\n     * @param {IFStage} stageClass\n     * @returns {IFStage}\n     */\n    IFView.prototype.getStage = function (stageClass) {\n        if (this._stages) {\n            for (var i = 0; i < this._stages.length; ++i) {\n                if (stageClass.prototype.isPrototypeOf(this._stages[i])) {\n                    return this._stages[i];\n                }\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Called to release this view\n     */\n    IFView.prototype.release = function () {\n        this._scene.removeEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n        this._scene.removeEventListener(IFNode.AfterPropertiesChangeEvent, this._afterPropertiesChange, this);\n        this._scene.removeEventListener(IFNode.AfterRemoveEvent, this._afterRemove, this);\n\n        if (this._stages) {\n            for (var i = 0; i < this._stages.length; ++i) {\n                this._stages[i].release();\n            }\n        }\n    };\n\n    /**\n     * Update view transforms and update all other necessary things like\n     * scrollbars and virtual space as well as do a repaint if anything has changed\n     * @param {Boolean} [noEvent] optional, specifies whether to send an event or not\n     * @private\n     */\n    IFView.prototype._updateViewTransforms = function (noEvent) {\n        // Calculate new view/scene mapping transformations. Make sure to round scrolling values to avoid floating point issues\n        // TODO : Correct the zoom values to fixed values to avoid floating point errors during rendering!?\n        this._scrollX = Math.round(this._scrollX);\n        this._scrollY = Math.round(this._scrollY);\n\n        var worldToViewTransform = new IFTransform().scaled(this._zoom, this._zoom).translated(-this._scrollX, -this._scrollY);\n        if (!IFTransform.equals(worldToViewTransform, this._worldToViewTransform)) {\n            this._worldToViewTransform = worldToViewTransform;\n            this._viewToWorldTransform = worldToViewTransform.inverted();\n            // Invalidate everything\n            this.invalidate();\n\n            if (!noEvent && this.hasEventListeners(IFView.TransformEvent)) {\n                this.trigger(IFView.TRANSFORMEVENT);\n            }\n        }\n    };\n\n    /**\n     * Called to init/add all stages\n     * @private\n     */\n    IFView.prototype._initStages = function () {\n        this.addStage(new IFSceneStage(this));\n    };\n\n    /**\n     * @param page\n     * @param autoCreate\n     * @private\n     */\n    IFView.prototype._getOrCreatePageConfig = function (page, autoCreate) {\n        var result = null;\n        for (var i = 0; i < this._pageConfigurations.length; ++i) {\n            if (this._pageConfigurations[i].page === page) {\n                result = this._pageConfigurations[i];\n                break;\n            }\n        }\n\n        if (!result && autoCreate) {\n            result = {\n                page: page\n            };\n            this._pageConfigurations.push(result);\n        }\n\n        return result;\n    };\n\n    /**\n     * @param {IFNode.AfterFlagChangeEvent} event\n     * @private\n     */\n    IFView.prototype._afterFlagChange = function (event) {\n        // Handle single page mode and active page changing\n        if (this._scene.getProperty('singlePage')) {\n            if (event.node instanceof IFPage && event.flag === IFNode.Flag.Active) {\n                this.invalidate();\n\n                if (event.set) {\n                    this.zoomActivePage();\n                } else {\n                    // save existing page configuration before changing to another one\n                    var pageConfig = this._getOrCreatePageConfig(event.node, true);\n                    pageConfig.scrollX = this._scrollX;\n                    pageConfig.scrollY = this._scrollY;\n                    pageConfig.zoom = this._zoom;\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterPropertiesChangeEvent} event\n     * @private\n     */\n    IFView.prototype._afterPropertiesChange = function (event) {\n        // Handle single page mode change\n        if (event.node === this._scene && event.properties.indexOf('singlePage') >= 0) {\n            this.zoomActivePage();\n\n            // Invalidate all in any case\n            this.invalidate();\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterRemoveEvent} event\n     * @private\n     */\n    IFView.prototype._afterRemove = function (event) {\n        // Removing page must clear our page configuration for it\n        if (event.node instanceof IFPage) {\n            for (var i = 0; i < this._pageConfigurations.length; ++i) {\n                if (this._pageConfigurations[i].page === event.node) {\n                    this._pageConfigurations.splice(i, 1);\n                    break;\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFView.prototype.toString = function () {\n        return \"[Object IFView]\";\n    };\n\n    _.IFView = IFView;\n\n})(this);"
  },
  {
    "path": "src/infinity/view/widget.js",
    "content": "(function (_) {\n    /**\n     * The base class for all widgets. This will trigger most of the available\n     * input events like mouse or key events.\n     * @param {HTMLDivElement} [container] optional container to append this widget into\n     * @class GUIWidget\n     * @extends IFObject\n     * @mixes GEventTarget\n     * @constructor\n     * @version 1.0\n     */\n    function GUIWidget(container) {\n        this._htmlElement = this._createHTMLElement();\n\n        if (container != null) {\n            this._htmlElement.style.position = \"relative\";\n            container.appendChild(this._htmlElement);\n        }\n    }\n\n    IFObject.inheritAndMix(GUIWidget, IFObject, [GEventTarget]);\n\n    /**\n     * Convert a DOM-Mouse-Event client position to internal coordinates\n     * @param htmlElement\n     * @param mouseEvent\n     * @returns {IFPoint}\n     */\n    GUIWidget.convertClientPositionFromMousePosition = function (htmlElement, mouseEvent) {\n        var posX = null;\n        var posY = null;\n        if (mouseEvent.target == htmlElement) {\n            if (\"absolute\" === htmlElement.style.position) {\n                if (mouseEvent.hasOwnProperty(\"offsetX\")) {\n                    posX = mouseEvent.offsetX;\n                    posY = mouseEvent.offsetY;\n                }\n            } else {\n                posX = mouseEvent.clientX;\n                posY = mouseEvent.clientY;\n            }\n        }\n        if (posX == null || posY == null) {\n\n            var box = htmlElement.getBoundingClientRect();\n            posX = mouseEvent.pageX - (box.left + window.pageXOffset - document.documentElement.clientLeft);\n            posY = mouseEvent.pageY - (box.top + window.pageYOffset - document.documentElement.clientTop);\n        }\n\n        return new IFPoint(posX, posY);\n    };\n\n    /**\n     * The underyling html element\n     * @type {HTMLElement}\n     * @private\n     */\n    GUIWidget.prototype._htmlElement = null;\n\n    /**\n     * Internal cache of input events\n     * @type {Object}\n     * @private\n     */\n    GUIWidget.prototype._inputEventCache = null;\n\n    /**\n     * Counter of registered drag event listeners\n     * @type {Number}\n     * @private\n     */\n    GUIWidget.prototype._dragEventCounter = 0;\n\n    /**\n     * @type {String}\n     * @private\n     */\n    GUIWidget.prototype._id = null;\n\n    /**\n     * @type {GUIWidget}\n     * @private\n     */\n    GUIWidget.prototype._parent = null;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    GUIWidget.prototype._x = 0;\n\n\n    /**\n     * @type {number}\n     * @private\n     */\n    GUIWidget.prototype._y = 0;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    GUIWidget.prototype._width = 0;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    GUIWidget.prototype._height = 0;\n\n    /**\n     * @type {String}\n     * @private\n     */\n    GUIWidget.prototype._cursor = null;\n\n    /**\n     * Return the x-position of this widget\n     * @return {Number}\n     */\n    GUIWidget.prototype.getX = function () {\n        return this._x;\n    };\n\n    /**\n     * Return the y-position of this widget\n     * @return {Number}\n     */\n    GUIWidget.prototype.getY = function () {\n        return this._y;\n    };\n\n    /**\n     * Return the width of this widget\n     * @return {Number}\n     */\n    GUIWidget.prototype.getWidth = function () {\n        return this._htmlElement.offsetWidth ? this._htmlElement.offsetWidth : this._width;\n    };\n\n    /**\n     * Return the height of this widget\n     * @return {Number}\n     */\n    GUIWidget.prototype.getHeight = function () {\n        return this._htmlElement.offsetHeight ? this._htmlElement.offsetHeight : this._height;\n    };\n\n    /**\n     * Move the widget to a given position\n     * @param {Number} x new x-position\n     * @param {Number} y new y-position\n     */\n    GUIWidget.prototype.move = function (x, y) {\n        if (typeof x == \"number\") {\n            this._htmlElement.style.left = x.toString() + 'px';\n        } else {\n            this._htmlElement.style.left = \"\";\n        }\n        if (typeof y == \"number\") {\n            this._htmlElement.style.top = y.toString() + 'px';\n        } else {\n            this._htmlElement.style.top = \"\";\n        }\n\n        if (typeof x == \"number\" || typeof y == \"number\") {\n            this._htmlElement.style.position = \"absolute\";\n        } else {\n            this._htmlElement.style.position = \"\";\n        }\n\n        this._x = x;\n        this._y = y;\n    };\n\n    /**\n     * Resize the widget to a certain size\n     * @param {Number} width the new width\n     * @param {Number} height the new height\n     */\n    GUIWidget.prototype.resize = function (width, height) {\n        if (width) {\n            this._htmlElement.style.width = width.toString() + 'px';\n        } else {\n            this._htmlElement.style.width = \"\";\n        }\n        if (height) {\n            this._htmlElement.style.height = height.toString() + 'px';\n        } else {\n            this._htmlElement.style.height = \"\";\n        }\n\n        if (width) {\n            this._htmlElement.style.overflowX = \"hidden\";\n        } else {\n            this._htmlElement.style.overflowX = \"\";\n        }\n\n        if (height) {\n            this._htmlElement.style.overflowY = \"hidden\";\n        } else {\n            this._htmlElement.style.overflowY = \"\";\n        }\n\n        this._width = width;\n        this._height = height;\n    };\n\n    /**\n     * @return {String} the cursor in use\n     * @see IFCursor\n     */\n    GUIWidget.prototype.getCursor = function () {\n        return this._cursor;\n    };\n\n    /**\n     * Assign a new cursor to be used for this widget and it's\n     * children if any\n     * @param {String} cursor the cursor to use, null will inherit from parent\n     * @see IFCursor\n     */\n    GUIWidget.prototype.setCursor = function (cursor) {\n        if (this._cursor != cursor) {\n            if (this._cursor) {\n                this._removeCSSClass(\"g-cursor-\" + this._cursor, true);\n            }\n\n            this._cursor = cursor;\n\n            if (this._cursor) {\n                this._addCSSClass(\"g-cursor-\" + this._cursor, true);\n            }\n        }\n    };\n\n    /**\n     * Checks and returns whether the widget is enabled or not\n     * @return {Boolean} true if enabled, false if not\n     * @version 1.0\n     */\n    GUIWidget.prototype.isEnabled = function () {\n        return this._htmlElement.className == null || this._htmlElement.className.indexOf(\"g-disabled\") < 0;\n    };\n\n    /**\n     * Makes this widget enabled or disabled\n     * @param {Boolean} enabled true to make enabled, false to disable\n     * @version 1.0\n     */\n    GUIWidget.prototype.setEnabled = function (enabled) {\n        if (enabled != this.isEnabled()) {\n            if (enabled) {\n                this._removeCSSClass(\"g-disabled\", true);\n            } else {\n                this._addCSSClass(\"g-disabled\", true);\n            }\n        }\n    };\n\n    /**\n     * Checks and returns whether the widget is displayed or not\n     * @return {Boolean} true if displayed, false if not\n     * @version 1.0\n     */\n    GUIWidget.prototype.isDisplayed = function () {\n        return \"none\" != this._htmlElement.style.display;\n    };\n\n\n    /**\n     * Makes this widget displayed or not. Non-displayed widgets\n     * will be completely gone from rendering this will also not\n     * occupy any space in their parents.\n     * @param {Boolean} displayed true to make displayed, false to make none-displayed\n     * @version 1.0\n     */\n    GUIWidget.prototype.setDisplayed = function (displayed) {\n        this._htmlElement.style.display = displayed ? \"\" : \"none\";\n    };\n\n    /** @override */\n    GUIWidget.prototype.trigger = function (event) {\n        // Handle drag release before mouse release\n        if (this._dragEventCounter > 0 && event instanceof GUIMouseEvent.Release) {\n            this._dragMouseRelease(event);\n        }\n\n        // Call original event\n        GEventTarget.prototype.trigger.call(this, event);\n\n        // Handle all other drag events after regular event\n        if (this._dragEventCounter > 0) {\n            if (event instanceof GUIMouseEvent.Down) {\n                this._dragMouseDown(event);\n            } else if (event instanceof GUIMouseEvent.Move && this._dragStartPosition) {\n                this._dragMouseMove(event);\n            }\n        }\n    }\n\n    /** @override */\n    GUIWidget.prototype.addEventListener = function (eventClass, listener, target, args) {\n        GEventTarget.prototype.addEventListener.call(this, eventClass, listener, target, args);\n\n        if (GUIInputEvent.prototype.isPrototypeOf(eventClass.prototype)) {\n            this._registerInputEventListener(eventClass);\n\n            // If event is mouse drag event then register our drag listeners\n            if (GUIMouseEvent.isDragEvent(eventClass)) {\n                if (this._dragEventCounter == 0) {\n                    // First drag llistener so start listening for various events simulating the drag event(s)\n                    this._registerInputEventListener(GUIMouseEvent.Down);\n                    this._registerInputEventListener(GUIMouseEvent.Move);\n                    this._registerInputEventListener(GUIMouseEvent.Release);\n                }\n                this._dragEventCounter++;\n            }\n        }\n    };\n\n    /** @override */\n    GUIWidget.prototype.removeEventListener = function (eventClass, listener) {\n        GEventTarget.prototype.removeEventListener.call(this, eventClass, listener);\n\n        if (GUIInputEvent.prototype.isPrototypeOf(eventClass.prototype)) {\n            this._unregisterInputEventListener(eventClass);\n\n            // If event is mouse drag event then unregster our drag listeners if it is the last\n            if (GUIMouseEvent.isDragEvent(eventClass)) {\n                if (--this._dragEventCounter == 0) {\n                    // Last drag event so stop listening for various events simulating the drag event(s)\n                    this._unregisterInputEventListener(GUIMouseEvent.Down);\n                    this._unregisterInputEventListener(GUIMouseEvent.Move);\n                    this._unregisterInputEventListener(GUIMouseEvent.Release);\n                }\n            }\n        }\n    };\n\n    /**\n     * Called to focus this widget. Note that not all widgets\n     * do actually support focusing\n     * @return {Boolean} true if widget was focused, false if not\n     */\n    GUIWidget.prototype.focus = function () {\n        if (this.isDisplayed()) {\n            try {\n                this._htmlElement.focus();\n                return true;\n            } catch (e) {\n                return false;\n            }\n        }\n        return false;\n    };\n\n    /**\n     * @param {Function} eventClass\n     * @private\n     */\n    GUIWidget.prototype._registerInputEventListener = function (eventClass) {\n        // Check if event is a drag event\n        var isDragEvent = GUIMouseEvent.isDragEvent(eventClass);\n        var event_id = IFObject.getTypeId(eventClass);\n\n        if (!this._inputEventCache || !(event_id in this._inputEventCache)) {\n            if (!this._inputEventCache) {\n                this._inputEventCache = {};\n            }\n            this._inputEventCache[event_id] = {counter: 0, event: new eventClass()};\n\n            // Don't listen for drag events as they're handled transparently\n            if (!isDragEvent) {\n                this._startListeningInputEvent(eventClass);\n            }\n        } else if (this._inputEventCache && event_id in this._inputEventCache) {\n            this._inputEventCache[event_id].counter++;\n        }\n    }\n\n    /**\n     * @param {Function} eventClass\n     * @private\n     */\n    GUIWidget.prototype._unregisterInputEventListener = function (eventClass) {\n        // Check if event is a drag event\n        var isDragEvent = GUIMouseEvent.isDragEvent(eventClass);\n        var event_id = IFObject.getTypeId(eventClass);\n\n        if (this._inputEventCache && event_id in this._inputEventCache) {\n            if (--this._inputEventCache[event_id].counter == 0) {\n\n                // Don't stop listening for drag events as they're handled transparently\n                if (!isDragEvent) {\n                    this._stopListeningInputEvent(eventClass);\n                }\n\n                delete this._inputEventCache[event_id];\n                if (Object.keys(this._inputEventCache).length == 0) {\n                    this._inputEventCache = null;\n                }\n            }\n        }\n    }\n\n    /**\n     * Called to start listening on a specific input event class\n     * @param {Function} eventClass the input event class to start listening for\n     * @private\n     */\n    GUIWidget.prototype._startListeningInputEvent = function (eventClass) {\n        var event_id = IFObject.getTypeId(eventClass);\n\n        var domListener = function (event) {\n            this._updateAndTriggerInputEvent(event, eventClass);\n        }.bind(this);\n\n        if (domListener) {\n            this._inputEventCache[event_id].domListener = domListener;\n            var domEventName = this._getDomEventNameForEventClass(eventClass);\n            this._htmlElement.addEventListener(domEventName, domListener);\n        }\n    };\n\n    /**\n     * Called to stop listening on a specific input event class\n     * @param {*} eventClass the input event class to stop listening for\n     * @private\n     */\n    GUIWidget.prototype._stopListeningInputEvent = function (eventClass) {\n        var event_id = IFObject.getTypeId(eventClass);\n        var domEventName = this._getDomEventNameForEventClass(eventClass);\n        this._htmlElement.removeEventListener(domEventName, this._inputEventCache[event_id].domListener);\n        delete this._inputEventCache[event_id].domListener;\n    };\n\n    /**\n     * @param {GUIMouseEvent} event\n     * @private\n     */\n    GUIWidget.prototype._dragMouseDown = function (event) {\n        if (event.button == GUIMouseEvent.BUTTON_LEFT) {\n            this._dragStartPosition = event.client;\n            this._dragIsDragging = false;\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent} event\n     * @private\n     */\n    GUIWidget.prototype._dragMouseMove = function (event) {\n        if (this._dragStartPosition) {\n            // If not yet dragging, we need to fire an initial drag start event\n            if (!this._dragIsDragging) {\n                var clientStart = this._dragStartPosition;\n                if (Math.abs(clientStart.getX() - event.client.getX()) >= 1 || Math.abs(clientStart.getY() - event.client.getY()) >= 1) {\n\n                    this._dragIsDragging = true;\n                    this._dragPreviousPosition = this._dragStartPosition;\n\n                    // Fire drag start event\n                    if (this.hasEventListeners(GUIMouseEvent.DragStart)) {\n                        /** @type GUIMouseEvent */\n                        var cachedEvent = this._inputEventCache[IFObject.getTypeId(GUIMouseEvent.DragStart)].event;\n                        this._dragAssignMouseEvent(event, cachedEvent);\n\n                        // Ensure to use our source positions and not the current one\n                        cachedEvent.client = this._dragStartPosition;\n\n                        this.trigger(cachedEvent);\n                    }\n                }\n            }\n        }\n\n        if (this._dragIsDragging && this.hasEventListeners(GUIMouseEvent.Drag)) {\n            /** @type GUIMouseEvent.Drag */\n            var cachedEvent = this._inputEventCache[IFObject.getTypeId(GUIMouseEvent.Drag)].event;\n            this._dragAssignMouseEvent(event, cachedEvent);\n            this._dragAssignDragEvent(cachedEvent, event);\n            this.trigger(cachedEvent);\n\n            this._dragPreviousPosition = event.client;\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent} event\n     * @private\n     */\n    GUIWidget.prototype._dragMouseRelease = function (event) {\n        if (event.button == GUIMouseEvent.BUTTON_LEFT) {\n            if (this._dragIsDragging) {\n                /** @type GUIMouseEvent.DragEnd */\n                var cachedEvent = this._inputEventCache[IFObject.getTypeId(GUIMouseEvent.DragEnd)].event;\n                this._dragAssignMouseEvent(event, cachedEvent);\n                this._dragAssignDragEvent(cachedEvent, event);\n\n                this.trigger(cachedEvent);\n            }\n            delete this._dragStartPosition;\n            delete this._dragPreviousPosition;\n            delete this._dragIsDragging;\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent} sourceEvent\n     * @param {GUIMouseEvent} dragEvent\n     * @private\n     */\n    GUIWidget.prototype._dragAssignMouseEvent = function (sourceEvent, dragEvent) {\n        dragEvent.client = sourceEvent.client;\n        dragEvent.button = sourceEvent.button;\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} dragEvent\n     * @param {GUIMouseEvent} currentEvent\n     * @private\n     */\n    GUIWidget.prototype._dragAssignDragEvent = function (dragEvent, currentEvent) {\n        dragEvent.clientStart = this._dragStartPosition;\n        dragEvent.clientDelta = currentEvent.client.subtract(this._dragPreviousPosition);\n    };\n\n    /**\n     * @param {GUIWidget} parent\n     * @private\n     */\n    GUIWidget.prototype._setParent = function (parent) {\n        this._parent = parent;\n    };\n\n    /**\n     * @private\n     */\n    GUIWidget.prototype._updateLocale = function () {\n        var hint = null;\n        if (this._hint) {\n            hint = this._hint.asHtml();\n        }\n\n        if (!hint || hint.length == 0) {\n            this._htmlElement.removeAttribute(\"data-qhint\");\n        } else {\n            this._htmlElement.setAttribute(\"data-qhint\", qUtil.escape(hint));\n        }\n    };\n\n    /**\n     * Called to trigger a widget event from the dom\n     * @param {Event} domEvent dom source mouse event\n     * @param {GEvent} widgetEvent the widget event to trigger\n     * @param {Boolean} [ignoreTarget] if true, no check for the current target\n     * is made. Defaults to false\n     * @private\n     */\n    GUIWidget.prototype._triggerWidgetEventFromDom = function (domEvent, widgetEvent, ignoreTarget) {\n        // Handle capturing of mouse for down/release events\n        // TODO : Fix checking for left button and let triggered event result decide wether\n        // to capture other buttons than left one too\n        if (widgetEvent instanceof GUIMouseEvent.Down && widgetEvent.button === GUIMouseEvent.BUTTON_LEFT) {\n            this._setCapture();\n        } else if (widgetEvent instanceof GUIMouseEvent.Release) {\n            this._releaseCapture();\n        }\n\n        this.trigger(widgetEvent);\n    };\n\n    /**\n     * @private\n     */\n    GUIWidget.prototype._updateAndTriggerInputEvent = function (domEvent, eventClass) {\n        // Ignore this alltogether if we're actually disabled!\n        if (!this.isEnabled()) {\n            return;\n        }\n\n        // Prevent default action for certain events that may trigger browser default behaviors\n        if (domEvent.type === 'keydown') {\n            var key = ifKey.translateKey(domEvent.which || domEvent.keyCode);\n            switch (key) {\n                case IFKey.Constant.TAB:\n                    domEvent.preventDefault();\n                    break;\n            }\n        } else if (domEvent.type === 'mousedown') {\n            domEvent.preventDefault();\n        }\n\n        if (GUIMouseEvent.prototype.isPrototypeOf(eventClass.prototype)) {\n            this._updateAndTriggerMouseEvent(domEvent, IFObject.getTypeId(eventClass));\n        } else if (GUIKeyEvent.prototype.isPrototypeOf(eventClass.prototype)) {\n            this._updateAndTriggerKeyEvent(domEvent, IFObject.getTypeId(eventClass));\n        }\n    };\n\n    /**\n     * Update the cached mouse event and trigger it\n     * @param {MouseEvent} domEvent dom source mouse event\n     * @param {Number} event_id the id of the event\n     * @private\n     */\n    GUIWidget.prototype._updateAndTriggerMouseEvent = function (domEvent, event_id) {\n        /** @type GUIMouseEvent */\n        var cachedEvent = this._inputEventCache[event_id].event;\n        cachedEvent.client = GUIWidget.convertClientPositionFromMousePosition(this._htmlElement, domEvent);\n        cachedEvent.button = domEvent.button;\n        this._triggerWidgetEventFromDom(domEvent, cachedEvent);\n    };\n\n    /**\n     * Update the cached key event and trigger it\n     * @param {KeyboardEvent} domEvent dom source key event\n     * @param {Number} event_id the id of the event\n     * @private\n     */\n    GUIWidget.prototype._updateAndTriggerKeyEvent = function (domEvent, event_id) {\n        /** @type GUIKeyEvent */\n        var cachedEvent = this._inputEventCache[event_id].event;\n\n        cachedEvent.key = ifKey.translateKey(domEvent.which || domEvent.keyCode);\n\n        this._triggerWidgetEventFromDom(domEvent, cachedEvent);\n    };\n\n    /**\n     * Get the appropriate dom event name for a given event class\n     * @param {Function} eventClass the event class to get a name for\n     * @returns {String}\n     * @private\n     */\n    GUIWidget.prototype._getDomEventNameForEventClass = function (eventClass) {\n        switch (eventClass) {\n            case GUIMouseEvent.Move:\n                return \"mousemove\";\n            case GUIMouseEvent.Enter:\n                return \"mouseover\";\n            case GUIMouseEvent.Leave:\n                return \"mouseout\";\n            case GUIMouseEvent.Down:\n                return \"mousedown\";\n            case GUIMouseEvent.Release:\n                return \"mouseup\";\n            case GUIMouseEvent.Click:\n                return \"click\";\n            case GUIMouseEvent.DblClick:\n                return \"dblclick\";\n            case GUIKeyEvent.Down:\n                return \"keydown\";\n            case GUIKeyEvent.Release:\n                return \"keyup\";\n            case GUIKeyEvent.Press:\n                return \"keypress\";\n            default:\n                break;\n        }\n\n        // TODO : Touch & Key Event Support\n        throw new Error(\"Unknown DOMEvent name\");\n    };\n\n    var CAPTURE_EVENTS = [GUIMouseEvent.Move, GUIMouseEvent.Release, GUIKeyEvent.Down, GUIKeyEvent.Release, GUIKeyEvent.Press];\n\n    GUIWidget.prototype._setCapture = function () {\n        // Try the hand setCapture/releaseCapture combo, first\n        //if (this._htmlElement.setCapture && document.releaseCapture) {\n        //    this._htmlElement.setCapture(true);\n        //} else {\n            // The hard way: We'll register additional listeners for our capture-events\n            // within the document to properly trigger events for them as well\n            var self = this;\n\n            function addDocumentListener(eventClass) {\n                var domEventName = self._getDomEventNameForEventClass(eventClass);\n\n                if (!self._savedDocumentListeners) {\n                    self._savedDocumentListeners = {};\n                }\n\n                self._savedDocumentListeners[domEventName] = function (event) {\n                    if (event.target != this._htmlElement) {\n                        self._updateAndTriggerInputEvent(event, eventClass);\n\n                        // stop propagation to avoid double-trigger on element itself\n                        event.stopImmediatePropagation();\n                    }\n                }.bind(self);\n\n                document.addEventListener(domEventName, self._savedDocumentListeners[domEventName], true);\n            }\n\n            for (var i = 0; i < CAPTURE_EVENTS.length; ++i) {\n                var eventClass = CAPTURE_EVENTS[i];\n                if (this._inputEventCache[IFObject.getTypeId(eventClass)]) {\n                    addDocumentListener(eventClass);\n                }\n            }\n        //}\n    };\n\n    GUIWidget.prototype._releaseCapture = function () {\n        // Try the hand setCapture/releaseCapture combo, first\n        //if (this._htmlElement.setCapture && document.releaseCapture) {\n        //    document.releaseCapture();\n        //} else {\n            // The hard way: We'll remove our listeners from the document\n            // that were registered to catch mouse-up and mouse-move events\n            // outside the element's client area\n            if (this._savedDocumentListeners) {\n                for (var domEventName in this._savedDocumentListeners) {\n                    document.removeEventListener(domEventName, this._savedDocumentListeners[domEventName], true);\n                }\n                delete this._savedDocumentListeners;\n            }\n        //}\n    };\n\n    /**\n     * Add a css class to the underlying div container\n     * @param {String} cssClass the css class to add if not yet existent\n     * @param {Boolean} noPrefix if set, no prefix will be added, defaults to false\n     * @private\n     */\n    GUIWidget.prototype._addCSSClass = function (cssClass, noPrefix) {\n        if (!noPrefix && this._BASE_CSS_CLASS) {\n            cssClass = this._BASE_CSS_CLASS + \"-\" + cssClass;\n        }\n\n        var className = this._htmlElement.className;\n        if (!className || className.trim().length == 0) {\n            className = cssClass;\n        } else {\n            var assignClass = true;\n            var classes = className.trim().split(' ');\n            for (var i = 0; i < classes.length; ++i) {\n                var class_ = classes[i].trim();\n                if (class_ == cssClass) {\n                    assignClass = false;\n                    break;\n                }\n            }\n            if (assignClass) {\n                className += \" \" + cssClass;\n            }\n        }\n        this._htmlElement.className = className;\n    };\n\n    /**\n     * Remove a css class from the underlying div container\n     * @param {String} cssClass the css class to remove\n     * @param {Boolean} noPrefix if set, no prefix will be added, defaults to false\n     * @private\n     */\n    GUIWidget.prototype._removeCSSClass = function (cssClass, noPrefix) {\n        if (!noPrefix && this._BASE_CSS_CLASS) {\n            cssClass = this._BASE_CSS_CLASS + \"-\" + cssClass;\n        }\n\n        var className = this._htmlElement.className;\n        if (className && className.indexOf(cssClass) >= 0) {\n            var newClassName = \"\";\n            var classes = className.trim().split(' ');\n            for (var i = 0; i < classes.length; ++i) {\n                var class_ = classes[i].trim();\n                if (class_ != cssClass) {\n                    if (newClassName.length > 0) {\n                        newClassName += \" \";\n                    }\n                    newClassName += class_;\n                }\n            }\n            this._htmlElement.className = newClassName;\n        }\n    };\n\n    /**\n     * Called to create the underlying html element\n     * @private\n     */\n    GUIWidget.prototype._createHTMLElement = function () {\n        var result = document.createElement(\"div\");\n        result.setAttribute('tabindex', '0');\n        return result;\n    };\n\n    /** @override */\n    GUIWidget.prototype.toString = function () {\n        return \"[Object GUIWidget]\";\n    };\n\n    _.GUIWidget = GUIWidget;\n})(this);"
  },
  {
    "path": "src/infinity-editor/editor.js",
    "content": "(function (_) {\n    /**\n     * A graphic editor keeps track of all editing related stuff for a scene\n     * like handling selection, keeping undo/redo information and more.\n     * @param {IFScene} scene the scene this editor works on\n     * @class IFEditor\n     * @extend GEventTarget\n     * @constructor\n     */\n    function IFEditor(scene) {\n        this._scene = scene;\n        this._scene.__graphic_editor__ = this;\n        this._transactionStack = [];\n        this._undoStates = [];\n        this._redoStates = [];\n        this._guides = new IFGuides(this._scene);\n\n        // Subscribe to various scene changes\n        this._scene.addEventListener(IFNode.AfterInsertEvent, this._afterNodeInsert, this);\n        this._scene.addEventListener(IFNode.BeforeRemoveEvent, this._beforeNodeRemove, this);\n        this._scene.addEventListener(IFNode.BeforePropertiesChangeEvent, this._beforePropertiesChange, this);\n        this._scene.addEventListener(IFNode.BeforeFlagChangeEvent, this._beforeFlagChange, this);\n        this._scene.addEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange, this);\n        this._scene.addEventListener(IFElement.GeometryChangeEvent, this._geometryChange, this);\n\n        // Try to create internal selection for all selected nodes\n        var selectedNodes = this._scene.queryAll(\":selected\");\n        if (selectedNodes && selectedNodes.length) {\n            for (var i = 0; i < selectedNodes.length; ++i) {\n                this._tryAddToSelection(selectedNodes[i]);\n            }\n        }\n    };\n    IFObject.inherit(IFEditor, GEventTarget);\n\n    IFEditor.options = {\n        /** Maximum number of undo-steps */\n        maxUndoSteps: 20,\n        /**\n         * Specifies whether changing the exact properties will\n         * be merged into a previous undo step with the same\n         * properties. This will only work if the current and\n         * the previous undo steps do not include *any* other changes\n         * and when each step has the same action name\n         */\n        smartUndoPropertyMerge: true,\n\n        /**\n         * The default units to shift when cloning the selection\n         */\n        cloneShift: 10\n    };\n\n    /**\n     * Get the underlying graphic editor for a given scene\n     * @param {IFScene} scene\n     * @returns {IFEditor} a graphic editor for the scene\n     * or null if it has no such one\n     */\n    IFEditor.getEditor = function (scene) {\n        return scene.__graphic_editor__ ? scene.__graphic_editor__ : null;\n    };\n\n    /**\n     * Runs + commits a transaction on an editor. If there's no editor for a\n     * given source, the action will still be ran but without any\n     * transactions at all\n     * @param {IFNode} source the source to get an editor from\n     * @param {Function} action the actual action to be ran\n     * @param {String} name the name of the transaction when committed\n     */\n    IFEditor.tryRunTransaction = function (source, action, name) {\n        var editor = IFEditor.getEditor(source.getScene());\n        if (editor) {\n            editor.beginTransaction();\n        }\n\n        try {\n            action();\n        } finally {\n            if (editor) {\n                editor.commitTransaction(name);\n            }\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFEditor.SelectionChangedEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event whenever the selection has been changed\n     * @class IFEditor.SelectionChangedEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFEditor.SelectionChangedEvent = function () {\n    };\n    IFObject.inherit(IFEditor.SelectionChangedEvent, GEvent);\n\n    /** @override */\n    IFEditor.SelectionChangedEvent.prototype.toString = function () {\n        return \"[Event IFEditor.SelectionChangedEvent]\";\n    };\n\n    IFEditor.SELECTION_CHANGED_EVENT = new IFEditor.SelectionChangedEvent();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFEditor.InlineEditorEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event providing inline editor events\n     * @class IFEditor.InlineEditorEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFEditor.InlineEditorEvent = function (editor, type) {\n        this.editor = editor;\n        this.type = type;\n    };\n    IFObject.inherit(IFEditor.InlineEditorEvent, GEvent);\n\n    /**\n     * Enum of inline editor event types\n     * @enum\n     */\n    IFEditor.InlineEditorEvent.Type = {\n        /**\n         * Inline editor is about to be opened\n         */\n        BeforeOpen: 0,\n\n        /**\n         * Inline editor has been opened\n         */\n        AfterOpen: 1,\n\n        /**\n         * Inline editor is about to close\n         */\n        BeforeClose: 10,\n\n        /**\n         * Inline editor has been closed\n         */\n        AfterClose: 11,\n\n        /**\n         * Some selection in inline editor has been changed\n         */\n        SelectionChanged: 100\n    };\n\n    /**\n     * @type {IFElementEditor}\n     */\n    IFEditor.InlineEditorEvent.prototype.editor = null;\n\n    /**\n     * @type {IFEditor.InlineEditorEvent.Type}\n     */\n    IFEditor.InlineEditorEvent.prototype.type = null;\n\n    /** @override */\n    IFEditor.InlineEditorEvent.prototype.toString = function () {\n        return \"[Event IFEditor.InlineEditorEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFEditor.InvalidationRequestEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for an invalidation request event\n     * @param {IFElementEditor} editor the requesting editor\n     * @param {*} [args] optional arguments to be passed back to editor\n     * @class IFEditor.InvalidationRequestEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFEditor.InvalidationRequestEvent = function (editor, args) {\n        this.editor = editor;\n        this.args = args;\n    };\n    IFObject.inherit(IFEditor.InvalidationRequestEvent, GEvent);\n\n    /** @type {IFElementEditor} */\n    IFEditor.InvalidationRequestEvent.prototype.editor = null;\n    /** @type {*} */\n    IFEditor.InvalidationRequestEvent.prototype.args = null;\n\n    /** @override */\n    IFEditor.InvalidationRequestEvent.prototype.toString = function () {\n        return \"[Event IFEditor.InvalidationRequestEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFEditor Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {IFScene}\n     * @private\n     */\n    IFEditor.prototype._scene = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    IFEditor.prototype._selection = null;\n\n    /**\n     * @type {Array<IFElement>}\n     * @private\n     */\n    IFEditor.prototype._lastCloneSelection = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    IFEditor.prototype._storedSelection = null;\n\n    /**\n     * @type {Array<{{page: IFPage, selection: Array<*>}}>}\n     * @private\n     */\n    IFEditor.prototype._pageSelections = null;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    IFEditor.prototype._selectionUpdateCounter = 0;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    IFEditor.prototype._selectionDetail = false;\n\n    /**\n     * @type {Array<{{actions: Array<{action: Function, revert: Function}>, selection: Array<{element: IFElement, parts: Array<*>}>}}>}\n     * @private\n     */\n    IFEditor.prototype._transactionStack = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    IFEditor.prototype._undoStates = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    IFEditor.prototype._redoStates = null;\n\n    /**\n     * @type {IFGuides}\n     * @private\n     */\n    IFEditor.prototype._guides = null;\n\n    /**\n     * @type {IFNode}\n     * @private\n     */\n    IFEditor.prototype._currentInlineEditorNode = null;\n    /**\n     * @returns {IFScene}\n     */\n    IFEditor.prototype.getScene = function () {\n        return this._scene;\n    };\n\n    /**\n     * Return whether any selection is available or not\n     * @return {Boolean} true if a selection is available, false if not\n     * @version 1.0\n     */\n    IFEditor.prototype.hasSelection = function () {\n        return this._selection && this._selection.length > 0;\n    };\n\n    /**\n     * Return the united selection bounding box\n     * @param {Boolean} [geometryBBox] if true, uses geometry bboxes,\n     * otherwises uses paint bboxes. Defaults to false.\n     * @return {IFRect} the selection bbox or null for no selection\n     */\n    IFEditor.prototype.getSelectionBBox = function (geometryBBox) {\n        if (this.hasSelection()) {\n            var result = null;\n            for (var i = 0; i < this._selection.length; ++i) {\n                var bbox = geometryBBox ? this._selection[i].getGeometryBBox() : this._selection[i].getPaintBBox();\n                if (bbox && !bbox.isEmpty()) {\n                    result = result ? result.united(bbox) : new IFRect(bbox.getX(), bbox.getY(), bbox.getWidth(), bbox.getHeight());\n                }\n            }\n            return result;\n        }\n        return null;\n    };\n\n    /**\n     * Return the selection array\n     * @return {Array<IFElement>} the selection array or null for no selection\n     * @version 1.0\n     */\n    IFEditor.prototype.getSelection = function () {\n        return this._selection;\n    };\n\n    /**\n     * Return the copy of the selection array. Elements in this copy has canvas-relative positions.\n     * @return {Array<IFElement>} the selection array copy or null for no selection\n     */\n    IFEditor.prototype.getSelectionCopy = function () {\n        var selectionCopy = null;\n        if (this._selection && this._selection.length > 0) {\n            selectionCopy = [];\n\n            for (var i = 0; i < this._selection.length; ++i) {\n                var element = this._selection[i];\n                if (element instanceof IFBlock) {\n                    var page = element.getPage();\n                    var copyElem = element.clone();\n                    if (copyElem) {\n                        copyElem.transform(\n                            new IFTransform(1, 0, 0, 1, -page.getProperty('x'), -page.getProperty('y')));\n                        selectionCopy.push(copyElem);\n                    }\n                }\n            }\n\n            if (!selectionCopy.length) {\n                selectionCopy = null;\n            }\n        }\n        return selectionCopy;\n    };\n\n    /**\n     * Returns whether selection details are available or not\n     * @returns {boolean}\n     */\n    IFEditor.prototype.hasSelectionDetail = function () {\n        return this._selectionDetail;\n    };\n\n    /**\n     * Assigns whether selection details are available or not\n     * @param {Boolean} detail\n     */\n    IFEditor.prototype.setSelectionDetail = function (detail) {\n        if (detail !== this._selectionDetail) {\n            this._selectionDetail = detail;\n\n            // Re-flag selection if any\n            if (this._selection) {\n                for (var i = 0; i < this._selection.length; ++i) {\n                    var editor = IFElementEditor.getEditor(this._selection[i]);\n                    if (editor) {\n                        if (this._selectionDetail) {\n                            editor.setFlag(IFElementEditor.Flag.Detail);\n                        } else {\n                            editor.removeFlag(IFElementEditor.Flag.Detail);\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Return the editor's guides\n     * @returns {IFGuides}\n     */\n    IFEditor.prototype.getGuides = function () {\n        return this._guides;\n    };\n\n    /**\n     * Returns a reference to the selected path, if it is the only one selected,\n     * or null otherwise\n     * @return {IFPath} the selected path\n     */\n    IFEditor.prototype.getPathSelection = function () {\n        var pathRef = null;\n        var i;\n\n        if (this.hasSelection()) {\n            for (i = 0; i < this._selection.length; ++i) {\n                if (this._selection[i] instanceof IFPath) {\n                    if (pathRef) {\n                        pathRef = null;\n                        break;\n                    } else {\n                        pathRef = this._selection[i];\n                    }\n                } else {\n                    if (pathRef) {\n                        pathRef = null;\n                        break;\n                    }\n                }\n            }\n        }\n\n        return pathRef;\n    };\n\n    /**\n     * Called to release and detach this editor\n     */\n    IFEditor.prototype.release = function () {\n        delete this._scene.__graphic_editor__;\n\n        this._scene.removeEventListener(IFNode.AfterInsertEvent, this._afterNodeInsert);\n        this._scene.removeEventListener(IFNode.BeforeRemoveEvent, this._beforeNodeRemove);\n        this._scene.removeEventListener(IFNode.BeforePropertiesChangeEvent, this._beforePropertiesChange);\n        this._scene.removeEventListener(IFNode.BeforeFlagChangeEvent, this._beforeFlagChange);\n        this._scene.removeEventListener(IFNode.AfterFlagChangeEvent, this._afterFlagChange);\n        this._scene.removeEventListener(IFElement.GeometryChangeEvent, this._geometryChange);\n    };\n\n    /**\n     * Request the invalidation of an editor\n     * @param {IFElementEditor} editor the requesting editor\n     * @param {*} [args] optional arguments to be passed back to the editor\n     */\n    IFEditor.prototype.requestInvalidation = function (editor, args) {\n        if (this.hasEventListeners(IFEditor.InvalidationRequestEvent)) {\n            this.trigger(new IFEditor.InvalidationRequestEvent(editor, args));\n        }\n    };\n\n    /**\n     * Clone current selection (if any) and make it the new selection. Note that\n     * this will not create an undo step, this would have to be done manually.\n     * @param {Boolean} [shift] if true, shifts the new selection a bit from\n     * the original source\n     * @param {Boolean} [history] if set to true (defaults to false), will re-apply\n     * the transformation done on a previous cloned selection if the current selection\n     * is still the same as the previous one and has not been cleared in the meantime\n     * @return {Array<IFElement>} the array of clones or null for no clones\n     */\n    IFEditor.prototype.cloneSelection = function (shift, history) {\n        if (this._selection && this._selection.length > 0) {\n            /** Array<{{element: IFElement, transform: IFTransform}}> */\n            var elementsToClone = [];\n\n            for (var i = 0; i < this._selection.length; ++i) {\n                var element = this._selection[i];\n                if (element.hasMixin(IFNode.Store)) {\n                    elementsToClone.push({\n                        element: element,\n                        transform: shift ? new IFTransform(1, 0, 0, 1, IFEditor.options.cloneShift, IFEditor.options.cloneShift) : null\n                    });\n                }\n            }\n\n            var clonedSelection = [];\n\n            if (history) {\n                if (this._lastCloneSelection) {\n                    for (var i = 0; i < this._lastCloneSelection.length; ++i) {\n                        var source = this._lastCloneSelection[i];\n                        var target = elementsToClone[i].element;\n                        if (source.hasMixin(IFElement.Transform) && target.hasMixin(IFElement.Transform)) {\n                            var sourceTransform = source.getTransform();\n                            var targetTransform = target.getTransform();\n                            if (targetTransform) {\n                                var newTransform = sourceTransform ? targetTransform.preMultiplied(sourceTransform.inverted()) : targetTransform;\n                                if (!newTransform.isIdentity()) {\n                                    elementsToClone[i].transform = newTransform;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n\n            for (var i = 0; i < elementsToClone.length; ++i) {\n                var element = elementsToClone[i].element;\n                var transform = elementsToClone[i].transform;\n\n                var clone = element.clone();\n                if (clone) {\n                    // Append clone to parent of selected item\n                    element.getParent().appendChild(clone);\n\n                    // Transform clone if desired\n                    if (transform && clone.hasMixin(IFElement.Transform)) {\n                        clone.transform(transform);\n                    }\n\n                    // Add clone to new selection\n                    clonedSelection.push(clone);\n                }\n            }\n\n            // Update current selection if any\n            if (clonedSelection.length > 0) {\n                this.updateSelection(false, clonedSelection);\n            }\n\n            if (history) {\n                this._lastCloneSelection = [];\n                for (var i = 0; i < elementsToClone.length; ++i) {\n                    this._lastCloneSelection.push(elementsToClone[i].element);\n                }\n            }\n\n            return clonedSelection;\n        }\n        return null;\n    };\n\n    /**\n     * Delete current selection (if any). Note that this will only\n     * delete IFItem based classes so that layers and/or pages\n     * are not accidently deleted. Note also that this will not\n     * delete items that are locked\n     * @param {Boolean} [noTransaction] if true, will not create a\n     * transaction (undo/redo), defaults to false\n     */\n    IFEditor.prototype.deleteSelection = function (noTransaction) {\n        if (this._selection && this._selection.length > 0) {\n            if (!noTransaction) {\n                this.beginTransaction();\n            }\n\n            try {\n                // copy and order selection\n                var orderedSelection = IFNode.order(this._selection.slice(), true);\n\n                // clear selection before deleting it\n                this.clearSelection();\n\n                // now delete\n                for (var i = 0; i < orderedSelection.length; ++i) {\n                    var selElement = orderedSelection[i];\n                    if (selElement instanceof IFItem && !selElement.hasFlag(IFElement.Flag.Locked)) {\n                        selElement.getParent().removeChild(selElement);\n                    }\n                }\n            } finally {\n                if (!noTransaction) {\n                    // TODO : I18N\n                    this.commitTransaction('Delete Selection');\n                }\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Update the current selection\n     * @param {boolean} toggle if true then this will merge/united the\n     * current selection with the new one, otherwise the current selection\n     * will be replaced with the new one\n     * @param {Array<IFElement>} selection the new array of nodes to be selected\n     */\n    IFEditor.prototype.updateSelection = function (toggle, selection) {\n        this._beginSelectionUpdate();\n        try {\n            if (!toggle) {\n                // Select new selection if any\n                if (selection && selection.length > 0) {\n                    for (var i = 0; i < selection.length; ++i) {\n                        selection[i].setFlag(IFNode.Flag.Selected);\n                    }\n                }\n\n                // Clear selection except for the selected ones\n                this.clearSelection(selection);\n            } else {\n                // We do toggle the current selection here which\n                // means to either add to current selection or remove\n                // from it\n                if (selection && selection.length) {\n                    for (var i = 0; i < selection.length; ++i) {\n                        // Simply invert our selection flag at this point\n                        if (selection[i].hasFlag(IFNode.Flag.Selected)) {\n                            selection[i].removeFlag(IFNode.Flag.Selected);\n                        } else {\n                            selection[i].setFlag(IFNode.Flag.Selected);\n                        }\n                    }\n                }\n            }\n        } finally {\n            this._finishSelectionUpdate();\n        }\n    };\n\n    /**\n     * Clears the whole selection if any\n     * @param {Array<IFElement>} [exclusion] an array to exclude from removing\n     * from the selection or null for none\n     */\n    IFEditor.prototype.clearSelection = function (exclusion) {\n        if (ifUtil.equals(exclusion, this._selection)) {\n            return;\n        }\n\n        this._beginSelectionUpdate();\n        try {\n            var index = 0;\n            while (this._selection && index < this._selection.length) {\n                if (exclusion && exclusion.indexOf(this._selection[index]) >= 0) {\n                    index++;\n                    continue;\n                }\n                this._selection[index].removeFlag(IFNode.Flag.Selected);\n            }\n        } finally {\n            this._finishSelectionUpdate();\n        }\n    };\n\n    /**\n     * Temporarily store the current selection\n     */\n    IFEditor.prototype.storeSelection = function () {\n        if (this._scene.getProperty('singlePage')) {\n            this._savePageSelection(this._scene.getActivePage(), true/*no-overwrite*/);\n        } else {\n            this._storedSelection = this._saveSelection();\n        }\n    };\n\n    /**\n     * Restore a temporarily stored selection\n     */\n    IFEditor.prototype.restoreSelection = function () {\n        if (this._scene.getProperty('singlePage')) {\n            this._restorePageSelection(this._scene.getActivePage());\n        } else {\n            this._loadSelection(this._storedSelection);\n        }\n    };\n\n    /**\n     * Move the selection\n     * @param {IFPoint} delta the move delta\n     * @param {Boolean} align whether to automatically align or not\n     * @param {*} [partId] optional id of part that has started the transformation\n     * @param {*} [data] optional data of part that has started the transformation\n     * @param {IFPoint} startPos - movement start position, needed when align is true only\n     */\n    IFEditor.prototype.moveSelection = function (delta, align, partId, partData, startPos) {\n        var translation = delta;\n        if (align && startPos && this._selection.length == 1) {\n            var selBBox = IFElement.prototype.getGroupGeometryBBox(this._selection);\n            var side = selBBox.getClosestSideName(startPos);\n            var sidePos = selBBox.getSide(side);\n            var newSidePos = sidePos.add(delta);\n            this._guides.getShapeBoxGuide().useExclusions(this._selection);\n            this._guides.beginMap();\n            newSidePos = this._guides.mapPoint(newSidePos);\n            this._guides.finishMap();\n            translation = newSidePos.subtract(sidePos);\n        }\n\n        this.transformSelection(new IFTransform(1, 0, 0, 1, translation.getX(), translation.getY()), partId, partData);\n    };\n\n    /**\n     * Scale the selection\n     * @param {Number} sx horizontal scale factor\n     * @param {Number} sy vertical scale factor\n     * @param {Number} dx horizontal scale direction (-1 = left, 0 = both, 1 = right}\n     * @param {Number} dy vertical scale direction (-1 = top, 0 = both, 1 = bottom}\n     * @param {Boolean} align whether to automatically align or not\n     * @param {*} [partId] optional id of part that has started the transformation\n     * @param {*} [partData] optional data of part that has started the transformation\n     */\n    IFEditor.prototype.scaleSelection = function (sx, sy, dx, dy, align, partId, partData) {\n        var selBBox = IFElement.prototype.getGroupGeometryBBox(this._selection);\n        if (selBBox) {\n            // TODO : Align support\n            var tl = selBBox.getSide(IFRect.Side.TOP_LEFT);\n            var br = selBBox.getSide(IFRect.Side.BOTTOM_RIGHT);\n            var cnt = selBBox.getSide(IFRect.Side.CENTER);\n            var tx, ty;\n            if (dx < 0) {\n                tx = br.getX();\n            } else if (dx > 0) {\n                tx = tl.getX();\n            } else { // tx == 0\n                tx = cnt.getX();\n            }\n            if (dy < 0) {\n                ty = br.getY();\n            } else if (dy > 0) {\n                ty = tl.getY();\n            } else { // ty == 0\n                ty = cnt.getY();\n            }\n\n            var transform = new IFTransform(1, 0, 0, 1, -tx, -ty)\n                .multiplied(new IFTransform(sx, 0, 0, sy, 0, 0))\n                .multiplied(new IFTransform(1, 0, 0, 1, tx, ty));\n\n            this.transformSelection(transform, partId, partData);\n        }\n    };\n\n    /**\n     * Transform the selection\n     * @param {IFTransform} transform the transform to be used\n     * @param {*} [part] optional id of part that has started the transformation\n     * @param {*} [partId] optional data of part that has started the transformation\n     */\n    IFEditor.prototype.transformSelection = function (transform, partId, partData) {\n        if (this._selection && this._selection.length) {\n            for (var i = 0; i < this._selection.length; ++i) {\n                var item = this._selection[i];\n                var editor = IFElementEditor.getEditor(item);\n                if (editor) {\n                    editor.transform(transform, partId, partData);\n                }\n            }\n        }\n    };\n\n    /**\n     * Reset the transformation of the selection\n     */\n    IFEditor.prototype.resetSelectionTransform = function () {\n        if (this._selection && this._selection.length) {\n            for (var i = 0; i < this._selection.length; ++i) {\n                var item = this._selection[i];\n                var editor = IFElementEditor.getEditor(item);\n                if (editor) {\n                    editor.resetTransform();\n                }\n            }\n        }\n    };\n\n    /**\n     * Apply the current selection transformation. If clone is set\n     * to true then the current selection will be applied to a clone\n     * of the current selection and made selected whereas the original\n     * selection keeps untouched\n     * @param {Boolean} [cloneSelection] whether to apply to a clone or not,\n     * defaults to false if not provided\n     * @param {Boolean} [noTransaction] if true, will not create a\n     * transaction (undo/redo), defaults to false\n     */\n    IFEditor.prototype.applySelectionTransform = function (cloneSelection, noTransaction) {\n        if (this._selection && this._selection.length) {\n            // Filter selection by editors that can not be transformed\n            // and reset those instead here\n            var newSelection = [];\n            for (var i = 0; i < this._selection.length; ++i) {\n                var item = this._selection[i];\n                var editor = IFElementEditor.getEditor(item);\n                if (editor) {\n                    if (!editor.canApplyTransform()) {\n                        // Reset editor transformation\n                        editor.resetTransform();\n                    } else {\n                        // Push item to array of new selection\n                        newSelection.push(item);\n                    }\n                }\n            }\n\n            if (newSelection && newSelection.length > 0) {\n                if (!noTransaction) {\n                    this.beginTransaction();\n                }\n\n                try {\n                    var clonedSelection = [];\n                    for (var i = 0; i < newSelection.length; ++i) {\n                        var item = newSelection[i];\n                        var editor = IFElementEditor.getEditor(item);\n                        if (editor) {\n                            var selectionElement = newSelection[i];\n                            var elementToApplyTransform = selectionElement;\n\n                            if (cloneSelection) {\n                                if (selectionElement.hasMixin(IFNode.Store)) {\n                                    elementToApplyTransform = selectionElement.clone();\n\n                                    // Append clone to parent of selected item\n                                    selectionElement.getParent().appendChild(elementToApplyTransform);\n\n                                    // Push clone into new selection\n                                    clonedSelection.push(elementToApplyTransform);\n                                } else {\n                                    elementToApplyTransform = null;\n                                }\n                            } else {\n                                // Avoid transform when locked\n                                if (selectionElement.hasFlag(IFElement.Flag.Locked)) {\n                                    elementToApplyTransform = null;\n                                }\n                            }\n\n                            if (elementToApplyTransform) {\n                                editor.applyTransform(elementToApplyTransform);\n                            } else {\n                                editor.resetTransform();\n                            }\n                        }\n                    }\n\n                    // Update current selection if we cloned it\n                    if (clonedSelection.length > 0) {\n                        this.updateSelection(false, clonedSelection);\n                    }\n                } finally {\n                    if (!noTransaction) {\n                        // TODO : I18N\n                        this.commitTransaction(cloneSelection ? 'Transform & Clone Selection' : 'Transform Selection');\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Inserts one or more elements into the right target parent\n     * and selects the elements clearing any previous selection\n     * This is a shortcut for insertElements([element])\n     * @param {Array<IFElement>} elements the elements to be inserted\n     * @param {Boolean} noInitial if true, the editor will not be\n     * called to handle the newly inserted element to assign some defaults.\n     * Defaults to false.\n     * @param {Boolean} [noTransaction] if true, will not create a\n     * transaction (undo/redo), defaults to false\n     */\n    IFEditor.prototype.insertElements = function (elements, noInitial, noTransaction) {\n        // Our target is always the currently active layer\n        var target = this._scene.querySingle('page:active layer:active');\n        if (!target) {\n            throw new Error('No active page/layer.');\n        }\n\n        if (!noTransaction) {\n            this.beginTransaction();\n        }\n\n        try {\n            for (var i = 0; i < elements.length; ++i) {\n                var element = elements[i];\n\n                // Append new element\n                target.appendChild(element);\n\n                if (!noInitial) {\n                    // Create a temporary editor for the element to handle it's insertion\n                    var editor = IFElementEditor.createEditor(element);\n                    if (editor) {\n                        editor.initialSetup();\n                    }\n                }\n            }\n\n            // Select all inserted elements\n            this.updateSelection(false, elements);\n        } finally {\n            if (!noTransaction) {\n                // TODO : I18N\n                this.commitTransaction('Insert Element(s)');\n            }\n        }\n    };\n\n    /**\n     * Does various work when the mouse was pressed somewhere to update for\n     * example the currently active page. Does nothing on single page mode\n     * @param {IFPoint} position the mouse position\n     * @param {IFTransform} transform optional transformation for the position\n     */\n    IFEditor.prototype.updateByMousePosition = function (position, transformation) {\n        if (this._scene.getProperty('singlePage') === false) {\n            // TODO : Make this more efficient than hit-testing everything (aka iterate pages instead)\n            // Try to update the active page under mouse if any\n            var pageHits = this._scene.hitTest(position, transformation, function (hit) {\n                return hit instanceof IFPage;\n            }.bind(this), false, 1/*one level deep only*/);\n\n            if (pageHits && pageHits.length === 1) {\n                for (var child = this._scene.getFirstChild(); child !== null; child = child.getNext()) {\n                    if (child instanceof IFPage) {\n                        if (child === pageHits[0].element) {\n                            child.setFlag(IFNode.Flag.Active);\n                        } else {\n                            child.removeFlag(IFNode.Flag.Active);\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Begin a new transaction. This will catch all structural\n     * modifications including property changes to be replayed\n     * as undo / redo states.\n     */\n    IFEditor.prototype.beginTransaction = function () {\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        this._transactionStack.push({\n            actions: [],\n            selection: this._saveSelection(),\n            transformBoxCenter: sceneEditor ? sceneEditor.getTransformBoxCenter() : null\n        });\n    };\n\n    IFEditor.prototype._transactionRedo = function (data) {\n        for (var i = 0; i < data.actions.length; ++i) {\n            data.actions[i].action();\n        }\n\n        this._loadSelection(data.newSelection);\n\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (data.newTransformBoxCenter || sceneEditor && sceneEditor.isTransformBoxActive()) {\n            if (data.newTransformBoxCenter) {\n                sceneEditor.setTransformBoxActive(true, data.newTransformBoxCenter);\n            } else {\n                sceneEditor.setTransformBoxActive(false);\n            }\n        }\n    };\n\n    IFEditor.prototype._transactionUndo = function (data) {\n        // Revert needs to play the actions backwards\n        for (var i = data.actions.length - 1; i >= 0; --i) {\n            data.actions[i].revert();\n        }\n\n        this._loadSelection(data.selection);\n\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (data.transformBoxCenter || sceneEditor && sceneEditor.isTransformBoxActive()) {\n            if (data.transformBoxCenter) {\n                sceneEditor.setTransformBoxActive(true, data.transformBoxCenter);\n            } else {\n                sceneEditor.setTransformBoxActive(false);\n            }\n        }\n    };\n\n    IFEditor.prototype._transactionMerge = function (previousData, data) {\n        if (IFEditor.options.smartUndoPropertyMerge) {\n            if (data.actions.length === 1 && previousData.actions.length === 1) {\n                var action = data.actions[0];\n                var previousAction = previousData.actions[0];\n\n                if (action.isPropertyChangeAction &&\n                    previousAction.isPropertyChangeAction &&\n                    action.node === previousAction.node &&\n                    action.properties.length === previousAction.properties.length) {\n                    // If the properties are equal then we can merge\n                    var propertiesAreEqual = true;\n\n                    for (var i = 0; i < previousAction.properties.length; ++i) {\n                        var property = previousAction.properties[i];\n                        if (action.properties.indexOf(property) < 0) {\n                            propertiesAreEqual = false;\n                            break;\n                        }\n                    }\n\n                    if (propertiesAreEqual) {\n                        // Merge new values in their order\n                        for (var i = 0; i < action.properties.length; ++i) {\n                            var property = action.properties[i];\n                            previousAction.values[previousAction.properties.indexOf(property)] = action.values[i];\n                        }\n\n                        return true;\n                    }\n                }\n            }\n        }\n\n        return false;\n    };\n\n    /**\n     * Commit the current transaction. If the transaction doesn't\n     * include any changes, no undo/redo state will be committed.\n     * @param {String} name\n     */\n    IFEditor.prototype.commitTransaction = function (name) {\n        if (!this._transactionStack.length) {\n            throw new Error('Nothing to commit, transaction stack is empty.');\n        }\n\n        var transaction = this._transactionStack.pop();\n        if (transaction.actions.length > 0) {\n            var sceneEditor = IFElementEditor.getEditor(this._scene);\n            var data = {\n                actions: transaction.actions.slice(),\n                selection: transaction.selection ? transaction.selection.slice() : null,\n                newSelection: this._saveSelection(),\n                transformBoxCenter: transaction.transformBoxCenter,\n                newTransformBoxCenter: sceneEditor ? sceneEditor.getTransformBoxCenter() : null\n            };\n\n            this.pushState(name, this._transactionRedo.bind(this), this._transactionUndo.bind(this), data, this._transactionMerge.bind(this));\n        }\n    };\n\n    /**\n     * Manually push an undo state action\n     * @param {String} name a name for the state\n     * @param {Function(data)} action the action to be executed when executing (\"redo\")\n     * @param {Function(data)} revert the action to be executed when undoing\n     * @param {*} data data of the state that'll be pushed to the action and revert functions\n     * @param {Function(data, previousData)} [merge] the function to be called to merge the given\n     * undo state data with the previous steps' one. If this returns true, the previous undo\n     * state is assumed to be merged and the new one will be not added.\n     */\n    IFEditor.prototype.pushState = function (name, action, revert, data, merge) {\n        // Try a merge, first\n        if (merge && data && this._undoStates.length > 0) {\n            var lastUndoState = this._undoStates[this._undoStates.length - 1];\n            if (lastUndoState.data && lastUndoState.name === name) {\n                if (merge(lastUndoState.data, data)) {\n                    // Merged so return here\n                    return;\n                }\n            }\n        }\n\n        if (this._undoStates.length >= IFEditor.options.maxUndoSteps) {\n            // Cut undo list of when reaching our undo limit\n            this._undoStates.shift();\n        }\n\n        this._undoStates.push({\n            name: name ? name : \"\",\n            action: action,\n            revert: revert,\n            data: data\n        });\n\n        // Push a new undo state has to clear out all the redo steps\n        this._redoStates = [];\n    };\n\n    /**\n     * Returns whether at least one undo state is available or not\n     * @returns {boolean}\n     */\n    IFEditor.prototype.hasUndoState = function () {\n        return this._undoStates.length > 0;\n    };\n\n    /**\n     * Returns whether at least one redo state is available or not\n     * @returns {boolean}\n     */\n    IFEditor.prototype.hasRedoState = function () {\n        return this._redoStates.length > 0;\n    };\n\n    /**\n     * Returns the name of the last undo state if any or null for none\n     * @returns {String}\n     */\n    IFEditor.prototype.getUndoStateName = function () {\n        if (this._undoStates.length > 0) {\n            return this._undoStates[this._undoStates.length - 1].name;\n        }\n        return null;\n    };\n\n    /**\n     * Returns the name of the last redo state if any or null for none\n     * @returns {String}\n     */\n    IFEditor.prototype.getRedoStateName = function () {\n        if (this._redoStates.length > 0) {\n            return this._redoStates[this._redoStates.length - 1].name;\n        }\n        return null;\n    };\n\n    /**\n     * Undo the latest state if any\n     */\n    IFEditor.prototype.undoState = function () {\n        if (this._undoStates.length > 0) {\n            // Get state and shift it from undo list\n            var state = this._undoStates.pop();\n\n            // Move state into redo list\n            this._redoStates.push(state);\n\n            // Execute revert action of the state\n            state.revert(state.data);\n        }\n    };\n\n    /**\n     * Redo the latest state if any\n     */\n    IFEditor.prototype.redoState = function () {\n        if (this._redoStates.length > 0) {\n            // Get state and shift it from redo list\n            var state = this._redoStates.pop();\n\n            // Move state into undo list\n            this._undoStates.push(state);\n\n            // Execute action of the state\n            state.action(state.data);\n        }\n    };\n\n    /**\n     * Checks and returns if there's an active inline editing editor or not\n     * @returns {boolean}\n     */\n    IFEditor.prototype.isInlineEditing = function () {\n        return !!this._currentInlineEditorNode;\n    };\n\n    /**\n     * Called to open an inline editor for a given node and view\n     * @param {IFNode} node\n     * @param {IFEditorView} view\n     * @param {IFPoint} [position] optional position in screen cordinates,\n     * defaults to null\n     * @return {Boolean} true if an inline editor was opened, false if not\n     */\n    IFEditor.prototype.openInlineEditor = function (node, view, position) {\n        this.closeInlineEditor();\n\n        var editor = IFElementEditor.getEditor(node);\n        if (editor && editor.canInlineEdit()) {\n            if (this.hasEventListeners(IFEditor.InlineEditorEvent)) {\n                this.trigger(new IFEditor.InlineEditorEvent(editor, IFEditor.InlineEditorEvent.Type.BeforeOpen));\n            }\n\n            editor.beginInlineEdit(view, view._htmlElement);\n            editor.adjustInlineEditForView(view, position);\n\n            this._currentInlineEditorNode = node;\n\n            if (this.hasEventListeners(IFEditor.InlineEditorEvent)) {\n                this.trigger(new IFEditor.InlineEditorEvent(editor, IFEditor.InlineEditorEvent.Type.AfterOpen));\n            }\n\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Called to update any active inline editor for a given view\n     * @param {IFEditorView} view\n     */\n    IFEditor.prototype.updateInlineEditorForView = function (view) {\n        if (this._currentInlineEditorNode) {\n            var editor = IFElementEditor.getEditor(this._currentInlineEditorNode);\n            if (editor && editor.isInlineEdit()) {\n                editor.adjustInlineEditForView(view);\n            }\n        }\n    };\n\n    /**\n     * Called to close any active inline editor\n     * @return {Boolean} true if an inline editor was closed, false if not\n     */\n    IFEditor.prototype.closeInlineEditor = function () {\n        if (this._currentInlineEditorNode) {\n            return this._finishEditorInlineEdit(this._currentInlineEditorNode);\n        }\n        return false;\n    };\n\n    /**\n     * @param {IFNode.AfterInsertEvent} evt\n     * @private\n     */\n    IFEditor.prototype._afterNodeInsert = function (evt) {\n        // If we have an active transaction, we need to record the action\n        if (this._transactionStack.length) {\n            var node = evt.node;\n            var parent = node.getParent();\n            var next = node.getNext();\n\n            this._transactionStack[this._transactionStack.length - 1].actions.push({\n                action: function () {\n                    // Simply re-insert the node\n                    parent.insertChild(node, next);\n                },\n\n                revert: function () {\n                    // Simply remove the node\n                    parent.removeChild(node);\n                }\n            });\n        }\n        ;\n\n        // Try to add newly inserted node into internal selection\n        this._tryAddToSelection(evt.node);\n    };\n\n    /**\n     * @param {IFNode.BeforeRemoveEvent} evt\n     * @private\n     */\n    IFEditor.prototype._beforeNodeRemove = function (evt) {\n        // If we have an active transaction, we need to record the action\n        if (this._transactionStack.length) {\n            var node = evt.node;\n            var parent = node.getParent();\n            var next = node.getNext();\n\n            this._transactionStack[this._transactionStack.length - 1].actions.push({\n                action: function () {\n                    // Simply remove the node\n                    parent.removeChild(node);\n                },\n\n                revert: function () {\n                    // Simply re-insert the node\n                    parent.insertChild(node, next);\n                }\n            });\n        }\n\n        if (evt.node instanceof IFElement) {\n            // If element is in selection, unselect it, first\n            if (this._selection && this._selection.indexOf(evt.node) >= 0) {\n                evt.node.removeFlag(IFNode.Flag.Selected);\n            } else {\n                // Otherwise try to close any editors the node may have\n                this._closeEditor(evt.node);\n            }\n        }\n\n        if (evt.node instanceof IFPage && this._scene.getProperty('singlePage') === true) {\n            // Remove saved page selection when removing the page and singlePage mode is turned on\n            this._removePageSelection(evt.node);\n        }\n    };\n\n    /**\n     * @param {IFNode.BeforePropertiesChangeEvent} evt\n     * @private\n     */\n    IFEditor.prototype._beforePropertiesChange = function (evt) {\n        // If we have an active transaction, we need to record the action\n        if (this._transactionStack.length) {\n            var node = evt.node;\n            var properties = evt.properties;\n            var values = evt.values;\n            var oldValues = [];\n            for (var i = 0; i < evt.properties.length; ++i) {\n                oldValues.push(node.getProperty(evt.properties[i]));\n            }\n\n            this._transactionStack[this._transactionStack.length - 1].actions.push({\n                isPropertyChangeAction: true,\n                node: node,\n                properties: properties.slice(),\n                values: values.slice(),\n                oldValues: oldValues,\n\n                action: function () {\n                    // Simply assign the property values\n                    node.setProperties(this.properties, this.values);\n                },\n\n                revert: function () {\n                    // Simply assign the previous property values\n                    node.setProperties(this.properties, this.oldValues);\n                }\n            });\n        }\n    };\n\n    /**\n     * @param {IFNode.BeforeFlagChangeEvent} evt\n     * @private\n     */\n    IFEditor.prototype._beforeFlagChange = function (evt) {\n        if (evt.node instanceof IFElement) {\n            if (evt.flag === IFElement.Flag.Hidden) {\n                if (evt.set) {\n                    // Deselect elements getting hidden\n                    evt.node.removeFlag(IFNode.Flag.Selected);\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {IFNode.AfterFlagChangeEvent} evt\n     * @private\n     */\n    IFEditor.prototype._afterFlagChange = function (evt) {\n        if (evt.node instanceof IFElement) {\n            if (evt.flag === IFNode.Flag.Selected) {\n                if (evt.set) {\n                    // Try to add node to the internal selection\n                    this._tryAddToSelection(evt.node);\n                } else {\n                    // Try to remove node from the internal selection\n                    this._tryRemoveFromSelection(evt.node);\n                }\n            } else if (evt.flag == IFNode.Flag.Highlighted) {\n                if (evt.set) {\n                    var editor = IFElementEditor.openEditor(evt.node);\n                    if (editor) {\n                        editor.setFlag(IFElementEditor.Flag.Highlighted);\n                    }\n                } else {\n                    var editor = IFElementEditor.openEditor(evt.node);\n                    if (editor) {\n                        editor.removeFlag(IFElementEditor.Flag.Highlighted);\n                    }\n                    this._tryCloseEditor(evt.node);\n                }\n            } else if (evt.flag == IFNode.Flag.Active) {\n                // In single page mode we'll save & restore page selections\n                if (evt.node instanceof IFPage && this._scene.getProperty('singlePage') === true) {\n                    if (evt.set) {\n                        this._restorePageSelection(evt.node);\n                    } else {\n                        this._savePageSelection(evt.node, false, true/*check-overwrite*/);\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {IFElement.GeometryChangeEvent} evt\n     * @private\n     */\n    IFEditor.prototype._geometryChange = function (evt) {\n        if (this._selection && this._selection.indexOf(evt.element) >= 0) {\n            switch (evt.type) {\n                case IFElement.GeometryChangeEvent.Type.Before:\n                case IFElement.GeometryChangeEvent.Type.After:\n                case IFElement.GeometryChangeEvent.Type.Child:\n                    var editor = IFElementEditor.getEditor(evt.element);\n                    if (editor) {\n                        editor.requestInvalidation();\n                    }\n                    break;\n            }\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFEditor.prototype._beginSelectionUpdate = function () {\n        this._selectionUpdateCounter += 1;\n    };\n\n    /**\n     * @private\n     */\n    IFEditor.prototype._finishSelectionUpdate = function () {\n        if (--this._selectionUpdateCounter === 0) {\n            this._updatedSelection();\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFEditor.prototype._updatedSelection = function () {\n        if (this._selectionUpdateCounter === 0) {\n            // Clear last clone selection\n            this._lastCloneSelection = null;\n\n            // Trigger selection change event\n            if (this.hasEventListeners(IFEditor.SelectionChangedEvent)) {\n                this.trigger(IFEditor.SELECTION_CHANGED_EVENT);\n            }\n        }\n    };\n\n    /**\n     * Try to add a node to internal selection if it is selected\n     * @param {IFNode} node\n     * @private\n     */\n    IFEditor.prototype._tryAddToSelection = function (node) {\n        if (node instanceof IFElement) {\n            if (node.hasFlag(IFNode.Flag.Selected)) {\n                // Try to open an editor for the selected node\n                var editor = IFElementEditor.openEditor(node);\n                if (editor) {\n                    editor.setFlag(IFElementEditor.Flag.Selected);\n\n                    if (this._selectionDetail) {\n                        editor.setFlag(IFElementEditor.Flag.Detail);\n                    }\n                }\n\n                // Always add the node to our internal selection array\n                if (!this._selection) {\n                    this._selection = [];\n                }\n                this._selection.push(node);\n\n                this._updatedSelection();\n            }\n        }\n    };\n\n    /**\n     * Try to remove a node from the internal selection\n     * @param {IFNode} node\n     * @private\n     */\n    IFEditor.prototype._tryRemoveFromSelection = function (node) {\n        if (node instanceof IFElement) {\n            // Close the editor for the previously selected node if it has any\n            var editor = IFElementEditor.getEditor(node);\n            if (editor && editor.hasFlag(IFElementEditor.Flag.Selected)) {\n                editor.removeFlag(IFElementEditor.Flag.Selected);\n                this._tryCloseEditor(node);\n            }\n\n            // Always remove the node from our selection array if we find it\n            if (this._selection) {\n                var sameParentInSelection = false;\n                var removeIndex = -1;\n\n                // Iterate through selection\n                for (var i = 0; i < this._selection.length; ++i) {\n                    var selNode = this._selection[i];\n                    if (selNode === node) {\n                        removeIndex = i;\n                    } else if (selNode.getParent() === node.getParent()) {\n                        sameParentInSelection = true;\n                    }\n                }\n\n                // Remove from selection\n                this._selection.splice(removeIndex, 1);\n                if (this._selection.length == 0) {\n                    this._selection = null;\n                }\n                this._updatedSelection();\n            }\n        }\n    };\n\n    IFEditor.prototype._tryCloseEditor = function (node) {\n        var editor = IFElementEditor.getEditor(node);\n        if (!editor || editor.hasFlag(IFElementEditor.Flag.Selected) || editor.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            // can not close editor in this case(s)\n            return;\n        }\n\n        // Only close editor if it doesn't have any children\n        if (editor.getEditors() == null || editor.getEditors().length == 0) {\n            // Save our parent editor\n            var parentEditor = editor.getParentEditor();\n\n            // Close our editor now\n            this._closeEditor(node);\n\n            // If we have a parent editor, try to close it recursively as well\n            if (parentEditor) {\n                this._tryCloseEditor(parentEditor.getElement());\n            }\n        }\n    };\n\n    IFEditor.prototype._finishEditorInlineEdit = function (node) {\n        var editor = IFElementEditor.getEditor(node);\n        if (editor && editor.isInlineEdit()) {\n            if (this.hasEventListeners(IFEditor.InlineEditorEvent)) {\n                this.trigger(new IFEditor.InlineEditorEvent(editor, IFEditor.InlineEditorEvent.Type.BeforeClose));\n            }\n\n            var editText = null;\n            this.beginTransaction();\n            try {\n                editText = editor.finishInlineEdit();\n            } finally {\n                // TODO : I18N\n                this.commitTransaction(editText ? editText : 'Inline Editing');\n            }\n\n            if (node === this._currentInlineEditorNode) {\n                this._currentInlineEditorNode = null;\n            }\n\n            if (this.hasEventListeners(IFEditor.InlineEditorEvent)) {\n                this.trigger(new IFEditor.InlineEditorEvent(editor, IFEditor.InlineEditorEvent.Type.AfterClose));\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    IFEditor.prototype._closeEditor = function (node) {\n        this._finishEditorInlineEdit(node);\n        IFElementEditor.closeEditor(node);\n    };\n\n    /**\n     * Save the selection for a given page\n     * @param {IFPage} page\n     * @param {Boolean} [noOverwrite] if set, won't overwrite\n     * the saved selection for the page on page change\n     * @param {Boolean} [checkOverwrite] if set, will not store\n     * the page selection if it has the noOverwrite flag set to true\n     * @private\n     */\n    IFEditor.prototype._savePageSelection = function (page, noOverwrite, checkOverwrite) {\n        if (!this._pageSelections) {\n            this._pageSelections = [];\n        }\n\n        // Try to overwrite an existing selection\n        for (var i = 0; i < this._pageSelections.length; ++i) {\n            var sel = this._pageSelections[i];\n            if (sel.page === page) {\n                if (!checkOverwrite || !sel.noOverwrite) {\n                    sel.selection = this._saveSelection();\n                    sel.noOverwrite = noOverwrite;\n                }\n\n                // done here\n                return;\n            }\n        }\n\n        // Create new selection storage for page when coming here\n        this._pageSelections.push({\n            page: page,\n            selection: this._saveSelection()\n        });\n    };\n\n    /**\n     * Restore the selection for a given page\n     * @param {IFPage} page\n     * @private\n     */\n    IFEditor.prototype._restorePageSelection = function (page) {\n        if (this._pageSelections) {\n            for (var i = 0; i < this._pageSelections.length; ++i) {\n                var sel = this._pageSelections[i];\n                if (sel.page === page) {\n                    this._loadSelection(sel.selection);\n                    // done here\n                    return;\n                }\n            }\n        }\n\n        // No selection for page available so clear the current one\n        this.clearSelection();\n    };\n\n    /**\n     * Remove the stored selection for a given page\n     * @param {IFPage} page\n     * @private\n     */\n    IFEditor.prototype._removePageSelection = function (page) {\n        if (this._pageSelections) {\n            for (var i = 0; i < this._pageSelections.length; ++i) {\n                var sel = this._pageSelections[i];\n                if (sel.page === page) {\n                    this._pageSelections.splice(i, 1);\n                    break;\n                }\n            }\n        }\n    };\n\n    /**\n     * Saves and returns the current selection\n     * @return {Array<{element: IFElement, parts: Array<*>}>}\n     * @private\n     */\n    IFEditor.prototype._saveSelection = function () {\n        if (!this._selection || this._selection.length === 0) {\n            return null;\n        }\n\n        var result = [];\n        for (var i = 0; i < this._selection.length; ++i) {\n            var element = this._selection[i];\n            var editor = IFElementEditor.getEditor(element);\n            var parts = editor ? editor.getPartSelection() : null;\n            result.push({\n                element: element,\n                parts: parts ? parts.slice() : null\n            })\n        }\n\n        return result;\n    };\n\n    /**\n     * Loads a saved selection\n     * @param {Array<{element: IFElement, parts: Array<*>}>} selection\n     * @private\n     */\n    IFEditor.prototype._loadSelection = function (selection) {\n        if (!selection || selection.length === 0) {\n            this.clearSelection();\n        } else {\n            var newSelection = [];\n\n            for (var i = 0; i < selection.length; ++i) {\n                newSelection.push(selection[i].element);\n            }\n\n            this.updateSelection(false, newSelection);\n\n            // Iterate selection again and assign part selections if any\n            for (var i = 0; i < selection.length; ++i) {\n                if (selection[i].parts) {\n                    var editor = IFElementEditor.getEditor(selection[i].element);\n                    if (editor) {\n                        editor.updatePartSelection(false, selection[i].parts);\n                    }\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFEditor.prototype.toString = function () {\n        return \"[Object IFEditor]\";\n    };\n\n    _.IFEditor = IFEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/editorpaintconfiguration.js",
    "content": "(function (_) {\n    /**\n     * A paint configuration for editor painting\n     * @class IFEditorPaintConfiguration\n     * @constructor\n     * @extends IFScenePaintConfiguration\n     */\n    function IFEditorPaintConfiguration() {\n    }\n\n    IFObject.inherit(IFEditorPaintConfiguration, IFScenePaintConfiguration);\n\n    /**\n     * Whether to render pages or not\n     * @type {Boolean}\n     */\n    IFEditorPaintConfiguration.prototype.pagesVisible = true;\n\n    /**\n     * Whether to render the grid or not if it is active\n     * @type {Boolean}\n     */\n    IFEditorPaintConfiguration.prototype.gridVisible = true;\n\n    /** @override */\n    IFEditorPaintConfiguration.prototype.toString = function () {\n        return \"[Object IFEditorPaintConfiguration]\";\n    };\n\n    _.IFEditorPaintConfiguration = IFEditorPaintConfiguration;\n})(this);"
  },
  {
    "path": "src/infinity-editor/guide/gridguide.js",
    "content": "(function (_) {\n    /**\n     * The grid guide\n     * @param {IFGuides} guides\n     * @class IFGridGuide\n     * @extends IFGuide\n     * @mixes IFGuide.Visual\n     * @mixes IFGuide.Map\n     * @constructor\n     */\n    function IFGridGuide(guides) {\n        IFGuide.call(this, guides);\n    }\n\n    IFObject.inheritAndMix(IFGridGuide, IFGuide, [IFGuide.Visual, IFGuide.Map]);\n\n    IFGridGuide.MIN_CELL_SPACE = 10;\n\n    /** @override */\n    IFGridGuide.prototype.paint = function (transform, context) {\n        if (this._scene.getProperty('gridActive') && context.configuration.gridVisible) {\n            var cl = IFColor.parseCSSColor('rgba(0, 0, 0, 0.125)');\n\n            // Calculate optical cell-size\n            var scale  = transform.getScaleFactor();\n            var szWScene = this._scene.getProperty('gridSizeX');\n            var szHScene = this._scene.getProperty('gridSizeY');\n            var szW = szWScene * scale;\n            var szH = szHScene * scale;\n\n            // Limit mininum. grid size to be optically comfortable.\n            if (szW < IFGridGuide.MIN_CELL_SPACE) {\n                szW *= 1. + Math.floor(IFGridGuide.MIN_CELL_SPACE / szW);\n            }\n            if (szH < IFGridGuide.MIN_CELL_SPACE){\n                szH *= 1. + Math.floor(IFGridGuide.MIN_CELL_SPACE / szH);\n            }\n\n            szWScene = szW / scale;\n            szHScene = szH / scale;\n\n            var rects = context.dirtyMatcher.getDirtyRectangles();\n            for (var i = 0; i < rects.length; ++i) {\n                var rect = rects[i];\n                var tl = new IFPoint(rect.getX(), rect.getY());\n                var tlScene = transform.inverted().mapPoint(tl);\n                var startXScene = Math.ceil(tlScene.getX() / szWScene) * szWScene;\n                var startYScene = Math.ceil(tlScene.getY() / szHScene) * szHScene;\n                var tlGridScene = new IFPoint(startXScene, startYScene);\n                var tlGrid = transform.mapPoint(tlGridScene);\n                for (var x = tlGrid.getX(); x - rect.getX() < rect.getWidth(); x += szW) {\n                    context.canvas.fillRect(Math.round(x), rect.getY(), 1, rect.getHeight(), cl);\n                }\n                for (var y = tlGrid.getY(); y - rect.getY() < rect.getHeight(); y += szH) {\n                    context.canvas.fillRect(rect.getX(), Math.round(y), rect.getWidth(), 1, cl);\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFGridGuide.prototype.map = function (x, y) {\n        var result = null;\n\n        if (this._scene.getProperty('gridActive')) {\n            var gsx = this._scene.getProperty('gridSizeX');\n            var gsy = this._scene.getProperty('gridSizeY');\n            result = {\n                x: {value: Math.round(x / gsx) * gsx, guide: null},\n                y: {value: Math.round(y / gsy) * gsy, guide: null}};\n        }\n\n        return result;\n    };\n\n    /** @override */\n    IFGridGuide.prototype.isMappingAllowed = function () {\n        return !ifPlatform.modifiers.metaKey;\n    };\n\n    /** @override */\n    IFGridGuide.prototype.toString = function () {\n        return \"[Object IFGridGuide]\";\n    };\n\n    _.IFGridGuide = IFGridGuide;\n})(this);"
  },
  {
    "path": "src/infinity-editor/guide/guide.js",
    "content": "(function (_) {\n    /**\n     * Base for a guide\n     * @param {IFGuides} guides the owner guides\n     * @class IFGuide\n     * @constructor\n     */\n    function IFGuide(guides) {\n        this._guides = guides;\n        this._scene = guides._scene;\n    }\n\n    IFObject.inherit(IFGuide, IFObject);\n\n    /**\n     * @type {IFGuides}\n     * @private\n     */\n    IFGuide.prototype._guides = null;\n\n    /**\n     * @type {IFScene}\n     * @private\n     */\n    IFGuide.prototype._scene = null;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFGuide.Visual Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin marking a guide to be paintable\n     * @class IFGuide.Visual\n     * @constructor\n     * @mixin\n     */\n    IFGuide.Visual = function () {\n        \n    };\n    \n    /**\n     * Called whenever the guides should paint itself\n     * @param {IFTransform} transform the transformation of the scene\n     * @param {IFPaintContext} context\n     */\n    IFGuide.Visual.prototype.paint = function (transform, context) {\n        // NO-OP\n    };\n\n    /** @override */\n    IFGuide.Visual.prototype.toString = function () {\n        return \"[Mixin IFGuide.Visual]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFGuide.Map Mixin\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * A mixin marking a guide to be mappable\n     * @class IFGuide.Map\n     * @constructor\n     * @mixin\n     */\n    IFGuide.Map = function () {\n\n    };\n\n    /**\n     * Called to let this guide map horizontal and vertical coordinates\n     * @param {Number} x\n     * @param {Number} y\n     * @return {{x: {value: Number, guide: IFPoint|Array<IFPoint>}, y: {value: Number, guide: IFPoint|Array<IFPoint>}}}\n     */\n    IFGuide.Map.prototype.map = function (x, y) {\n        // NO-OP\n    };\n\n    /**\n     * Called to check for each guide if mapping is allowed at the current moment. It may be blocked due to\n     * key modifiers like CTRL, and so on.\n     * @returns {Boolean}\n     */\n    IFGuide.Map.prototype.isMappingAllowed = function () {\n        return true;\n    };\n\n    /** @override */\n    IFGuide.Map.prototype.toString = function () {\n        return \"[Mixin IFGuide.Map]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFGuide\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /** @override */\n    IFGuide.prototype.toString = function () {\n        return \"[Object IFGuide]\";\n    };\n\n    _.IFGuide = IFGuide;\n})(this);"
  },
  {
    "path": "src/infinity-editor/guide/guides.js",
    "content": "(function (_) {\n    /**\n     * The guide manager\n     * @param {IFScene} scene\n     * @class IFGuides\n     * @extend GEventTarget\n     * @constructor\n     */\n    function IFGuides(scene) {\n        this._scene = scene;\n        this._guides = [];\n        this._counter = 0;\n        this._visuals = [];\n\n        this._shapeBoxGuide = new IFShapeBoxGuide(this);\n\n        this._addGuide(this._shapeBoxGuide);\n        this._addGuide(new IFPageGuide(this));\n        this._addGuide(new IFGridGuide(this));\n        this._addGuide(new IFUnitGuide(this));\n    }\n\n    IFObject.inherit(IFGuides, GEventTarget);\n\n    /**\n     * The length of snap zone lines in pixels\n     * @type {Number}\n     */\n    IFGuides.VISUALS_LENGTH = 20;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFGuides.InvalidationRequestEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for an invalidation request event\n     * @param {IFRect} [area] the area to invalidate\n     * @class IFGuides.InvalidationRequestEvent\n     * @extends GEvent\n     * @constructor\n     */\n    IFGuides.InvalidationRequestEvent = function (area) {\n        this.area = area;\n    };\n    IFObject.inherit(IFGuides.InvalidationRequestEvent, GEvent);\n\n    /** @type {IFRect} */\n    IFGuides.InvalidationRequestEvent.prototype.area = null;\n\n    /** @override */\n    IFGuides.InvalidationRequestEvent.prototype.toString = function () {\n        return \"[Event IFGuides.InvalidationRequestEvent]\";\n    };\n\n    /**\n     * @type {IFScene}\n     * @private\n     */\n    IFGuides.prototype._scene = null;\n\n    /**\n     * @type {Array<IFGuide>}\n     * @private\n     */\n    IFGuides.prototype._guides = null;\n\n    /**\n     * @type {IFShapeBoxGuide}\n     * @private\n     */\n    IFGuides.prototype._shapeBoxGuide = null;\n\n    /**\n     * Internal counter of begin/endMap calls\n     * @type {number}\n     * @private\n     */\n    IFGuides.prototype._counter = 0;\n\n    /**\n     * An array of vusial guides' lines ends in scene coordinates\n     * @type {Array<Array<IFPoint>>}\n     * @private\n     */\n    IFGuides.prototype._visuals = null;\n\n    /**\n     * Stores the area in scene coordinates, where painting of visual guides occurs\n     * @type {IFRect}\n     * @private\n     */\n    IFGuides.prototype._area = null;\n\n    /**\n     * Call this if you want to start mapping. This needs\n     * to be followed by a closing call to finishMap. If\n     * you just want to map without any visual guides,\n     * you don't need to call this.\n     */\n    IFGuides.prototype.beginMap = function () {\n        if (this._counter == 0) {\n            this._visuals = [];\n            if (this._area && !this._area.isEmpty()) {\n                this.invalidate(this._area);\n            }\n            this._area = null;\n        }\n        ++this._counter;\n    };\n\n    /**\n     * Finish mapping. See beginMap description.\n     */\n    IFGuides.prototype.finishMap = function () {\n        if (this._counter > 0) {\n            --this._counter;\n            if (this._counter == 0 && this._visuals.length) {\n                var minx = null;\n                var miny = null;\n                var maxx = null;\n                var maxy = null;\n                var visLine;\n                for (var i = 0; i < this._visuals.length; ++i) {\n                    visLine = this._visuals[i];\n                    for (var j = 0; j < 2; ++j) {\n                        if (minx === null || minx > visLine[j].getX()) {\n                            minx = visLine[j].getX();\n                        }\n                        if (miny === null || miny > visLine[j].getY()) {\n                            miny = visLine[j].getY();\n                        }\n                        if (maxx === null || maxx < visLine[j].getX()) {\n                            maxx = visLine[j].getX();\n                        }\n                        if (maxy === null || maxy < visLine[j].getY()) {\n                            maxy = visLine[j].getY();\n                        }\n                    }\n                }\n                minx -= 1;\n                miny -= 1;\n                maxx += 1;\n                maxy += 1;\n\n                this._area = new IFRect(minx, miny, maxx - minx, maxy - miny);\n                this.invalidate(this._area);\n\n                this._shapeBoxGuide.cleanExclusions();\n            }\n        }\n    };\n\n    /**\n     * Map a point to the current snapping options\n     * @param {IFPoint} point the point to map\n     * @returns {IFPoint} a mapped point\n     */\n    IFGuides.prototype.mapPoint = function (point) {\n        var resX = null;\n        var resY = null;\n\n        var guide;\n        var res = null;\n        var targPts = [];\n        for (var i = 0; i < this._guides.length && (resX === null || resY === null); ++i) {\n            guide = this._guides[i];\n            if (guide.isMappingAllowed()) {\n                res = guide.map(point.getX(), point.getY());\n                if (res) {\n                    if (res.x && resX === null) {\n                        resX = res.x.value;\n                        if (this._visuals && res.x.guide) {\n                            if (res.x.guide instanceof IFPoint) {\n                                targPts.push(res.x.guide);\n                            } else {\n                                this._visuals.push(res.x.guide);\n                            }\n                        }\n                    }\n                    if (res.y && resY === null) {\n                        resY = res.y.value;\n                        if (this._visuals && res.y.guide) {\n                            if (res.y.guide instanceof IFPoint) {\n                                targPts.push(res.y.guide);\n                            } else {\n                                this._visuals.push(res.y.guide);\n                            }\n                        }\n                    }\n                }\n                res = null;\n            }\n        }\n\n        if (resX === null) {\n            resX = point.getX();\n        }\n\n        if (resY === null) {\n            resY = point.getY();\n        }\n        var resPt = new IFPoint(resX, resY);\n\n        var pt;\n        for (var i = 0; i < targPts.length; ++i) {\n            pt = targPts[i];\n            if (Math.abs(resX - pt.getX()) >= 2 || Math.abs(resY - pt.getY()) >= 2) {\n                this._visuals.push([resPt, pt]);\n            }\n        }\n\n        return resPt;\n    };\n\n    /**\n     * Called whenever the guides should paint itself\n     * @param {IFTransform} transform the transformation of the scene\n     * @param {IFPaintContext} context\n     */\n    IFGuides.prototype.paint = function (transform, context) {\n        var guide;\n        for (var i = 0; i < this._guides.length; ++i) {\n            guide = this._guides[i];\n            if (guide.hasMixin(IFGuide.Visual)) {\n                guide.paint(transform, context);\n            }\n        }\n\n        var visLine;\n        for (var i = 0; i < this._visuals.length; ++i) {\n            visLine = this._visuals[i];\n            var pt0 = transform.mapPoint(visLine[0]);\n            var pt1 = transform.mapPoint(visLine[1]);\n            context.canvas.strokeLine(Math.floor(pt0.getX()) + 0.5, Math.floor(pt0.getY()) + 0.5,\n                Math.floor(pt1.getX()) + 0.5, Math.floor(pt1.getY()) + 0.5, 1, context.guideOutlineColor);\n        }\n\n        this._visuals = [];\n    };\n\n    /**\n     * Triggers invalidation request of passed area\n     * @param {IFRect} area - an area to invalidate; if empty, last stored area painted with visuals is used\n     */\n    IFGuides.prototype.invalidate = function (area) {\n        if (this.hasEventListeners(IFGuides.InvalidationRequestEvent)) {\n            if (area && !area.isEmpty()) {\n                this.trigger(new IFGuides.InvalidationRequestEvent(area));\n            } else if (this._area && !this._area.isEmpty()) {\n                this.trigger(new IFGuides.InvalidationRequestEvent(this._area));\n                this._area = null;\n            }\n        }\n    };\n\n    /**\n     * Returns ShapeBoxGuide\n     * @returns {IFShapeBoxGuide}\n     */\n    IFGuides.prototype.getShapeBoxGuide = function () {\n        return this._shapeBoxGuide;\n    };\n\n    /**\n     * Calculates and return snap zone lines for a bbox and a location against the bbox.\n     * Everything is in scene coordinates\n     * @param {IFRect} bBox\n     * @param {IFPoint} location\n     * @return {Array<Array<IFPoint>>}\n     */\n    IFGuides.prototype.getBBoxSnapZones = function (bBox, location) {\n        var visLines = null;\n        var snapZonesAllowed = false;\n        for (var i = 0; i < this._guides.length && !snapZonesAllowed; ++i) {\n            var guide = this._guides[i];\n            if (guide.isMappingAllowed() && !(guide instanceof IFUnitGuide)) {\n                snapZonesAllowed = true;\n            }\n        }\n        var pDst = this._scene.getProperty('pickDist');\n        if (snapZonesAllowed && bBox && !bBox.isEmpty() && bBox.expanded(pDst, pDst, pDst, pDst).containsPoint(location)) {\n            visLines = [];\n            var side = bBox.getClosestSideName(location);\n            var sidePos = bBox.getSide(side);\n            var tl = bBox.getSide(IFRect.Side.TOP_LEFT);\n            var br = bBox.getSide(IFRect.Side.BOTTOM_RIGHT);\n            var shapeWidth = Math.abs(br.getX() - tl.getX());\n            var shapeHeight = Math.abs(br.getY() - tl.getY());\n            var vis1 = null;\n            var vis2 = null;\n\n            var horV;\n            if (shapeWidth > IFGuides.VISUALS_LENGTH * 2) {\n                horV = IFGuides.VISUALS_LENGTH;\n            } else if (shapeWidth > IFGuides.VISUALS_LENGTH) {\n                horV = shapeWidth / 2;\n            } else {\n                horV = shapeWidth;\n            }\n            var y1 = sidePos.getY();\n            var y2 = y1;\n            var x1 = tl.getX();\n            switch (side) {\n                case IFRect.Side.TOP_CENTER:\n                case IFRect.Side.CENTER:\n                case IFRect.Side.BOTTOM_CENTER:\n                    x1 = sidePos.getX() - horV / 2;\n                    break;\n                case IFRect.Side.TOP_RIGHT:\n                case IFRect.Side.RIGHT_CENTER:\n                case IFRect.Side.BOTTOM_RIGHT:\n                    x1 = sidePos.getX() - horV;\n                    break;\n            }\n            var x2 = x1 + horV;\n            visLines.push([new IFPoint(x1, y1), new IFPoint(x2, y2)]);\n\n            var vertV;\n            if (shapeHeight > IFGuides.VISUALS_LENGTH * 2) {\n                vertV = IFGuides.VISUALS_LENGTH;\n            } else if (shapeHeight > IFGuides.VISUALS_LENGTH) {\n                vertV = shapeHeight / 2;\n            } else {\n                vertV = shapeHeight;\n            }\n            x1 = sidePos.getX();\n            x2 = x1;\n            y1 = tl.getY();\n            switch (side) {\n                case IFRect.Side.LEFT_CENTER:\n                case IFRect.Side.CENTER:\n                case IFRect.Side.RIGHT_CENTER:\n                    y1 = sidePos.getY() - vertV / 2;\n                    break;\n                case IFRect.Side.BOTTOM_LEFT:\n                case IFRect.Side.BOTTOM_CENTER:\n                case IFRect.Side.BOTTOM_RIGHT:\n                    y1 = sidePos.getY() - vertV;\n                    break;\n            }\n            y2 = y1 + vertV;\n            visLines.push([new IFPoint(x1, y1), new IFPoint(x2, y2)]);\n        }\n\n        return visLines;\n    };\n\n    /**\n     * Add a guide to this manager\n     * @param {IFGuide} guide\n     */\n    IFGuides.prototype._addGuide = function (guide) {\n        this._guides.push(guide);\n    };\n\n    /** @override */\n    IFGuides.prototype.toString = function () {\n        return \"[Object IFGuides]\";\n    };\n\n    _.IFGuides = IFGuides;\n})(this);"
  },
  {
    "path": "src/infinity-editor/guide/pageguide.js",
    "content": "(function (_) {\n    /**\n     * The grid guide\n     * @param {IFGuides} guides\n     * @class IFPageGuide\n     * @extends IFGuide\n     * @mixes IFGuide.Visual\n     * @mixes IFGuide.Map\n     * @constructor\n     */\n    function IFPageGuide(guides) {\n        IFGuide.call(this, guides);\n    }\n\n    IFObject.inheritAndMix(IFPageGuide, IFGuide, [IFGuide.Map]);\n\n    /** @override */\n    IFPageGuide.prototype.map = function (x, y) {\n        var snapDistance = this._scene.getProperty('snapDist');\n        var resX = null;\n        var resY = null;\n        var guideX = null;\n        var guideY = null;\n        var result = null;\n\n        var _snap = function (page) {\n            var pageBBox = page.getGeometryBBox();\n            if (pageBBox && !pageBBox.isEmpty()) {\n                var tl = pageBBox.getSide(IFRect.Side.TOP_LEFT);\n                var br = pageBBox.getSide(IFRect.Side.BOTTOM_RIGHT);\n                var cntr = pageBBox.getSide(IFRect.Side.CENTER);\n                var pivots = [tl, br, cntr];\n                var sides = [IFRect.Side.TOP_LEFT, IFRect.Side.BOTTOM_RIGHT, IFRect.Side.CENTER];\n                for (var i = 0; i < sides.length; ++i) {\n                    var pivot = pivots[i];\n                    if (resX === null && Math.abs(x - pivot.getX()) <= snapDistance) {\n                        resX = pivot.getX();\n                        if (sides[i] == IFRect.Side.CENTER) {\n                            guideX = [new IFPoint(resX, tl.getY()), new IFPoint(resX, br.getY())];\n                        }\n                    }\n                    if (resY === null && Math.abs(y - pivot.getY()) <= snapDistance) {\n                        resY = pivot.getY();\n                        if (sides[i] == IFRect.Side.CENTER) {\n                            guideY = [new IFPoint(tl.getX(), resY), new IFPoint(br.getX(), resY)];\n                        }\n                    }\n                }\n            }\n        };\n\n        var page;\n        if (this._scene.getProperty('singlePage')) {\n            _snap(this._scene.getActivePage());\n        } else {\n            for (var child = this._scene.getFirstChild(); child !== null && (resX === null || resY === null);\n                    child = child.getNext()) {\n\n                // Snap to pages\n                if (child instanceof IFPage && !child.hasFlag(IFElement.Flag.Hidden)) {\n                    _snap(child);\n                }\n            }\n        }\n\n        if (resX !== null || resY !== null) {\n            result = {\n                x: resX !== null ? {value: resX, guide: guideX} : null,\n                y: resY !== null ? {value: resY, guide: guideY} : null};\n        }\n\n        return result;\n    };\n\n    /** @override */\n    IFPageGuide.prototype.isMappingAllowed = function () {\n        return !ifPlatform.modifiers.metaKey;\n    };\n\n    /** @override */\n    IFPageGuide.prototype.toString = function () {\n        return \"[Object IFPageGuide]\";\n    };\n\n    _.IFPageGuide = IFPageGuide;\n})(this);\n"
  },
  {
    "path": "src/infinity-editor/guide/shapeboxguide.js",
    "content": "(function (_) {\n    /**\n     * The grid guide\n     * @param {IFGuides} guides\n     * @class IFShapeBoxGuide\n     * @extends IFGuide\n     * @mixes IFGuide.Visual\n     * @mixes IFGuide.Map\n     * @constructor\n     */\n    function IFShapeBoxGuide(guides) {\n        IFGuide.call(this, guides);\n    }\n\n    IFObject.inheritAndMix(IFShapeBoxGuide, IFGuide, [IFGuide.Map]);\n\n    IFShapeBoxGuide.GUIDE_MARGIN = 20;\n\n    /**\n     * Array of elements, which should be excluded from snapping to them\n     * @type {Array}\n     * @private\n     */\n    IFShapeBoxGuide.prototype._exclusions = null;\n\n    /** @override */\n    IFShapeBoxGuide.prototype.map = function (x, y) {\n        var resX = null;\n        var resY = null;\n        var guideX = null;\n        var guideY = null;\n        var result = null;\n        if (this._scene.getProperty('singlePage')) {\n            var snapDistance = this._scene.getProperty('snapDist');\n\n            var _snap = function (shape) {\n                if (this._exclusions) {\n                    for (var i = 0; i < this._exclusions.length; ++i) {\n                        if (this._exclusions[i] == shape) {\n                            return;\n                        }\n                    }\n                }\n\n                var bBox = shape.getGeometryBBox();\n                if (bBox && !bBox.isEmpty()) {\n                    var tl = bBox.getSide(IFRect.Side.TOP_LEFT);\n                    var br = bBox.getSide(IFRect.Side.BOTTOM_RIGHT);\n                    var cntr = bBox.getSide(IFRect.Side.CENTER);\n                    var pivots = [tl, br, cntr];\n                    var sides = [IFRect.Side.TOP_LEFT, IFRect.Side.BOTTOM_RIGHT, IFRect.Side.CENTER];\n                    for (var i = 0; i < sides.length; ++i) {\n                        var pivot = pivots[i];\n                        if (resX === null && Math.abs(x - pivot.getX()) <= snapDistance) {\n                            resX = pivot.getX();\n                            if (y <= tl.getY()) {\n                                guideX = [new IFPoint(resX, y - IFShapeBoxGuide.GUIDE_MARGIN),\n                                    new IFPoint(resX, br.getY() + IFShapeBoxGuide.GUIDE_MARGIN)];\n                            } else if (tl.getY() < y && y < br.getY()) {\n                                guideX = [new IFPoint(resX, tl.getY() - IFShapeBoxGuide.GUIDE_MARGIN),\n                                    new IFPoint(resX, br.getY() + IFShapeBoxGuide.GUIDE_MARGIN)];\n                            } else {\n                                guideX = [new IFPoint(resX, tl.getY() - IFShapeBoxGuide.GUIDE_MARGIN),\n                                    new IFPoint(resX, y + IFShapeBoxGuide.GUIDE_MARGIN)];\n                            }\n                        }\n                        if (resY === null && Math.abs(y - pivot.getY()) <= snapDistance) {\n                            resY = pivot.getY();\n                            if (x <= tl.getX()) {\n                                guideY = [new IFPoint(x - IFShapeBoxGuide.GUIDE_MARGIN, resY),\n                                    new IFPoint(br.getX() + IFShapeBoxGuide.GUIDE_MARGIN, resY)];\n                            } else if (tl.getX() < x && x < br.getX()) {\n                                guideY = [new IFPoint(tl.getX() - IFShapeBoxGuide.GUIDE_MARGIN, resY),\n                                    new IFPoint(br.getX() + IFShapeBoxGuide.GUIDE_MARGIN, resY)];\n                            } else {\n                                guideY = [new IFPoint(tl.getX() - IFShapeBoxGuide.GUIDE_MARGIN, resY),\n                                    new IFPoint(x + IFShapeBoxGuide.GUIDE_MARGIN, resY)];\n                            }\n                        }\n                    }\n                }\n            }.bind(this);\n\n            var page = this._scene.getActivePage();\n\n            page.accept(function (node) {\n                if (node instanceof IFShape && node.getParent() instanceof IFLayer) {\n                    _snap(node);\n                }\n            });\n        }\n\n        if (resX !== null || resY !== null) {\n            result = {\n                x: resX !== null ? {value: resX, guide: guideX} : null,\n                y: resY !== null ? {value: resY, guide: guideY} : null};\n        }\n\n        return result;\n    };\n\n    /** @override */\n    IFShapeBoxGuide.prototype.isMappingAllowed = function () {\n        return !ifPlatform.modifiers.metaKey;\n    };\n\n    /**\n     * Use the passed list of elements as exclusions from snapping to them\n     * @param {Array} exclusions\n     */\n    IFShapeBoxGuide.prototype.useExclusions = function (exclusions) {\n        this._exclusions = exclusions;\n    };\n\n    /**\n     * Clean exclusions list\n     */\n    IFShapeBoxGuide.prototype.cleanExclusions = function () {\n        this._exclusions = null;\n    };\n\n    /** @override */\n    IFShapeBoxGuide.prototype.toString = function () {\n        return \"[Object IFShapeBoxGuide]\";\n    };\n\n    _.IFShapeBoxGuide = IFShapeBoxGuide;\n})(this);\n\n"
  },
  {
    "path": "src/infinity-editor/guide/unitguide.js",
    "content": "(function (_) {\n    /**\n     * The unit guide for snapping to units if desired\n     * @param {IFGuides} guides\n     * @class IFUnitGuide\n     * @extends IFGuide\n     * @mixes IFGuide.Map\n     * @constructor\n     */\n    function IFUnitGuide(guides) {\n        IFGuide.call(this, guides);\n    }\n\n    IFObject.inheritAndMix(IFUnitGuide, IFGuide, [IFGuide.Map]);\n\n    /** @override */\n    IFUnitGuide.prototype.map = function (x, y) {\n        var result = null;\n\n        // Snap to units if desired\n        switch (this._scene.getProperty('unitSnap')) {\n            case IFScene.UnitSnap.Full:\n                result = {\n                    x: {value: ifMath.round(x, true), guide: null},\n                    y: {value: ifMath.round(y, true), guide: null}};\n                break;\n            case IFScene.UnitSnap.Half:\n                result = {\n                    x: {value: ifMath.round(x, true) + 0.5, guide: null},\n                    y: {value: ifMath.round(y, true) + 0.5, guide: null}};\n                break;\n        }\n\n        return result;\n    };\n\n    /** @override */\n    IFUnitGuide.prototype.toString = function () {\n        return \"[Object IFUnitGuide]\";\n    };\n\n    _.IFUnitGuide = IFUnitGuide;\n})(this);"
  },
  {
    "path": "src/infinity-editor/i18n/i18n_de.js",
    "content": ""
  },
  {
    "path": "src/infinity-editor/i18n/i18n_en.js",
    "content": "// Editor\nifLocale.setValues(IFSceneEditor, IFLocale.Language.English, [\"action.insert\", \"action.remove\", \"action.properties\"], [\"Insert\", \"Remove\", \"Change Properties\"]);"
  },
  {
    "path": "src/infinity-editor/scene/blockeditor.js",
    "content": "(function (_) {\n    /**\n     * A base editor for shapes\n     * @param {IFBlock} block the block this editor works on\n     * @class IFBlockEditor\n     * @extends IFElementEditor\n     * @constructor\n     */\n    function IFBlockEditor(block) {\n        IFElementEditor.call(this, block);\n    };\n    IFObject.inherit(IFBlockEditor, IFElementEditor);\n\n    IFBlockEditor.Flag = {\n        /**\n         * The editor supports edge resize handles\n         * @type Number\n         */\n        ResizeEdges: 1 << 10,\n\n        /**\n         * The editor supports center resize handles\n         * @type Number\n         */\n        ResizeCenters: 1 << 11,\n\n        /**\n         * The editor supports all resize handles\n         * @type Number\n         */\n        ResizeAll: (1 << 10) | (1 << 11)\n    };\n\n    IFBlockEditor.RESIZE_HANDLE_PART_ID = ifUtil.uuid();\n\n    /** @override */\n    IFBlockEditor.prototype.getBBoxMargin = function () {\n        if (this._showResizeHandles()) {\n            return IFElementEditor.OPTIONS.annotationSizeSmall + 1;\n        }\n        return IFElementEditor.prototype.getBBoxMargin.call(this);\n    };\n\n    /** @override */\n    IFBlockEditor.prototype.movePart = function (partId, partData, position, viewToWorldTransform, guides, shift, option) {\n        IFElementEditor.prototype.movePart.call(this, partId, partData, position, viewToWorldTransform, guides, shift, option);\n\n        if (partId === IFBlockEditor.RESIZE_HANDLE_PART_ID) {\n            var newPos = viewToWorldTransform.mapPoint(position);\n            newPos = guides.mapPoint(newPos);\n            var delta = newPos.subtract(partData.point);\n            var sourceBBox = this._element.getGeometryBBox();\n            var transform = sourceBBox.getResizeTransform(partData.side, delta.getX(), delta.getY(), shift, option);\n            this.transform(transform);\n        }\n    };\n\n    /** @override */\n    IFBlockEditor.prototype.applyPartMove = function (partId, partData) {\n        if (partId === IFBlockEditor.RESIZE_HANDLE_PART_ID) {\n            this.applyTransform(this._element);\n        }\n        IFElementEditor.prototype.applyPartMove.call(this, partId, partData);\n    };\n\n    /** @override */\n    IFBlockEditor.prototype.paint = function (transform, context) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            var targetTransform = transform;\n\n            // Pre-multiply internal transformation if any\n            if (this._transform) {\n                targetTransform = this._transform.multiplied(transform);\n            }\n\n            // Let descendant classes do some pre-painting\n            this._prePaint(targetTransform, context);\n\n            // Paint resize handles if desired\n            if (this._showResizeHandles()) {\n                this._iterateResizeHandles(function (point, side) {\n                    this._paintAnnotation(context, transform, point, IFElementEditor.Annotation.Rectangle, false, true);\n                }.bind(this), transform);\n            }\n\n            // Let descendant classes do some post-painting\n            this._postPaint(targetTransform, context);\n        }\n\n        // Paint any children editors now\n        this._paintChildren(transform, context);\n    };\n\n    /** @override */\n    IFBlockEditor.prototype._getPartInfoAt = function (location, transform, tolerance) {\n        // Hit-Test our resize handles if any\n        if (this._showResizeHandles()) {\n            var result = null;\n            this._iterateResizeHandles(function (point, side) {\n                if (this._getAnnotationBBox(transform, point).containsPoint(location)) {\n                    result = new IFElementEditor.PartInfo(this, IFBlockEditor.RESIZE_HANDLE_PART_ID, {side: side, point: point}, true, false);\n                    return true;\n                }\n            }.bind(this), transform);\n\n            if (result) {\n                return result;\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Called for subclasses to do some custom painting beneath of the outline\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPaintContext} context the paint context to paint on\n     * @private\n     */\n    IFBlockEditor.prototype._prePaint = function (transform, context) {\n        // NO-OP\n    };\n\n    /**\n     * Called for subclasses to do some custom painting on top of the outline\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPaintContext} context the paint context to paint on\n     * @private\n     */\n    IFBlockEditor.prototype._postPaint = function (transform, context) {\n        // NO-OP\n    };\n\n    /**\n     * @returns {Boolean}\n     * @private\n     */\n    IFBlockEditor.prototype._showResizeHandles = function () {\n        return this._showAnnotations() && (this.hasFlag(IFBlockEditor.Flag.ResizeEdges) || this.hasFlag(IFBlockEditor.Flag.ResizeCenters));\n    };\n\n    /**\n     * Iterate all resize handles\n     * @param {Function(point: IFPoint, side: IFRect.Side)} iterator\n     * the iterator receiving the parameters. If this returns true then the iteration will be stopped.\n     * @param {IFTransform} transform - current view transformation to check that shape has enough space\n     * to show resize handles\n     */\n    IFBlockEditor.prototype._iterateResizeHandles = function (iterator, transform) {\n        var bbox = this.getPaintElement().getGeometryBBox();\n\n        if (bbox && !bbox.isEmpty()) {\n            var sides = [];\n\n            var transformedBBox = transform ? transform.mapRect(bbox) : bbox;\n\n            if (this.hasFlag(IFBlockEditor.Flag.ResizeEdges) &&\n                    transformedBBox.getHeight() > (IFElementEditor.OPTIONS.annotationSizeSmall + 2) * 2 &&\n                    transformedBBox.getWidth() > (IFElementEditor.OPTIONS.annotationSizeSmall + 2) * 2) {\n\n                sides = sides.concat([IFRect.Side.TOP_LEFT, IFRect.Side.TOP_RIGHT, IFRect.Side.BOTTOM_LEFT, IFRect.Side.BOTTOM_RIGHT]);\n            }\n\n            if (this.hasFlag(IFBlockEditor.Flag.ResizeCenters)) {\n                if (transformedBBox.getHeight() > (IFElementEditor.OPTIONS.annotationSizeSmall + 2) * 3) {\n                    sides = sides.concat([IFRect.Side.RIGHT_CENTER, IFRect.Side.LEFT_CENTER]);\n                }\n                if (transformedBBox.getWidth() > (IFElementEditor.OPTIONS.annotationSizeSmall + 2) * 3) {\n                    sides = sides.concat([IFRect.Side.TOP_CENTER, IFRect.Side.BOTTOM_CENTER]);\n                }\n            }\n\n            for (var i = 0; i < sides.length; ++i) {\n                var side = sides[i];\n                var point = bbox.getSide(side);\n                if (iterator(point, side) === true) {\n                    break;\n                }\n            }\n        }\n    };\n\n    /**\n     * Paint bbox outline of underlying element\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPaintContext} context the paint context to paint on\n     * @param {IFColor} [color] the color for the outline. If not provided,\n     * uses either selection or highlight color depending on the current state.\n     * @private\n     */\n    IFBlockEditor.prototype._paintBBoxOutline = function (transform, context, color) {\n        // Calculate transformed geometry bbox\n        var sourceRect = this._element.getGeometryBBox();\n        var transformedRect = transform.mapRect(sourceRect);\n\n        if (transformedRect && !transformedRect.isEmpty()) {\n            // Ensure to pixel-align the rect\n            var x = Math.floor(transformedRect.getX());\n            var y = Math.floor(transformedRect.getY());\n            var w = Math.ceil(transformedRect.getX() + transformedRect.getWidth()) - x;\n            var h = Math.ceil(transformedRect.getY() + transformedRect.getHeight()) - y;\n\n\n            if (!color) {\n                if (this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n                    color = context.highlightOutlineColor;\n                } else {\n                    color = context.selectionOutlineColor;\n                }\n            }\n\n            context.canvas.strokeRect(x + 0.5, y + 0.5, w, h, 1, color);\n        }\n    };\n\n    /** @override */\n    IFBlockEditor.prototype.toString = function () {\n        return \"[Object IFBlockEditor]\";\n    };\n\n    _.IFBlockEditor = IFBlockEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/elementeditor.js",
    "content": "(function (_) {\n    /**\n     * The base for an element editor\n     * @param {IFElement} element the element this editor works on\n     * @class IFElementEditor\n     * @extends IFObject\n     * @constructor\n     */\n    function IFElementEditor(element) {\n        this._element = element;\n    };\n    IFObject.inherit(IFElementEditor, IFObject);\n\n    IFElementEditor._Editors = {};\n\n    IFElementEditor.exports = function (editorClass, nodeClass) {\n        IFElementEditor._Editors[IFObject.getTypeId(nodeClass)] = editorClass;\n    };\n\n    /**\n     * Options for element editor\n     */\n    IFElementEditor.OPTIONS = {\n        /**\n         * The regular size of an annotation\n         * @type Number\n         */\n        annotationSizeRegular: 6,\n\n        /**\n         * The small size of an annotation\n         * @type Number\n         */\n        annotationSizeSmall: 4,\n\n        /**\n         * The size of the center cross\n         * @type Number\n         */\n        centerCrossSize: 4\n    };\n\n    IFElementEditor.Flag = {\n        /**\n         * The editor is in selected status\n         * @type Number\n         * @version 1.0\n         */\n        Selected: 1 << 0,\n\n        /**\n         * The editor is in highlighted status\n         * @type Number\n         * @version 1.0\n         */\n        Highlighted: 1 << 1,\n\n        /**\n         * The editor is in detail status\n         * @type Number\n         * @version 1.0\n         */\n        Detail: 1 << 2,\n\n        /**\n         * The editor is in outline status\n         * @type Number\n         * @version 1.0\n         */\n        Outline: 1 << 3\n    };\n\n    /**\n     * Type of an annotation\n     * TODO: remove this extra enum\n     * @enum\n     */\n    IFElementEditor.Annotation = {\n        Rectangle: ifAnnotation.AnnotType.Rectangle,\n        Circle: ifAnnotation.AnnotType.Circle,\n        Diamond: ifAnnotation.AnnotType.Diamond\n    };\n\n    /**\n     * Type of a drop\n     * @enum\n     */\n    IFElementEditor.DropType = {\n        /**\n         * A pattern is dropped, the type is IFPattern\n         */\n        Pattern: 0,\n\n        /**\n         * A text is dropped, the type is String\n         */\n        Text: 1,\n\n        /**\n         * A node is dropped, the type is IFNode\n         */\n        Node: 2\n    };\n\n    /**\n     * Returns any opened/attached editor on a element if it has any\n     * @param {IFElement} element the element to get an open editor for\n     * @returns {IFElementEditor} the editor opened on the element or null for none\n     * @version 1.0\n     */\n    IFElementEditor.getEditor = function (element) {\n        return element.__editor__ ? element.__editor__ : null;\n    };\n\n    /**\n     * Create and returns a new editor instance for a given element\n     * @param {IFElement} element the element to create an editor for\n     * @return {IFElementEditor} a newly created element editor or null for none\n     * @version 1.0\n     */\n    IFElementEditor.createEditor = function (element) {\n        var editorClass = IFElementEditor._Editors[IFObject.getTypeId(element)];\n        if (editorClass) {\n            return new editorClass(element);\n        }\n        return null;\n    };\n\n    /**\n     * Opens and attaches an editor to a given element. Note that this will\n     * also iterate up all parents and create their editors as well. Note\n     * that only registered editors are opened. If the element already has\n     * an editor, this call will be a NO-OP\n     * @param {IFElement} element the element to open an editor on\n     * @returns {IFElementEditor} the opened editor instance or null for none\n     * @version 1.0\n     */\n    IFElementEditor.openEditor = function (element) {\n        if (!element.isAttached()) {\n            throw new Error(\"Node is not attached to create an editor for.\");\n        }\n        if (IFElementEditor.getEditor(element) != null) {\n            // editor already attached\n            return IFElementEditor.getEditor(element);\n        }\n        var editor = IFElementEditor.createEditor(element);\n        if (!editor) {\n            return null;\n        }\n\n        // If we have a parent then create the parent's editor as well\n        // and attach our new editor to it. Note that we'll iterate our\n        // hierarchy up until we've found a valid editor parent. This\n        // might overjump nodes in tree that do not have an editor.\n        for (var parentNode = element.getParent(); parentNode !== null; parentNode = parentNode.getParent()) {\n            var parentEditor = IFElementEditor.getEditor(parentNode);\n            if (!parentEditor) {\n                parentEditor = IFElementEditor.openEditor(parentNode);\n            }\n            if (parentEditor) {\n                // Figure the right insertion point using element comparison\n                var referenceEditor = null;\n                for (var nextNode = element.getNext(); nextNode != null; nextNode = nextNode.getNext()) {\n                    var nextEditor = IFElementEditor.getEditor(nextNode);\n                    if (nextEditor) {\n                        referenceEditor = nextEditor;\n                        break;\n                    }\n                }\n\n                parentEditor.insertEditor(editor, referenceEditor);\n\n                // Done here, found a parent editor\n                break;\n            }\n        }\n\n        // Attach editor to element now and return it\n        editor._attach();\n        element.__editor__ = editor;\n\n        return editor;\n    };\n\n    /**\n     * Close an editor on a given element if it has any. Note that\n     * this will also correctly remove the editor instance from\n     * any parent editors the element may have as well as it will\n     * close all sub editors of the element. Note that only registered\n     * editors will be closed, others will be kept intact and require\n     * a manual close / removal.\n     * @param {IFElement} element the element to close the editor on\n     * @version 1.0\n     */\n    IFElementEditor.closeEditor = function (element) {\n        var elementEditor = IFElementEditor.getEditor(element);\n        if (elementEditor) {\n            // Return if editor is not registered\n            var editorClass = IFElementEditor._Editors[IFObject.getTypeId(element)];\n            if (!editorClass) {\n                return;\n            }\n\n            // Close all child editors if any, first\n            var editors = elementEditor.getEditors();\n            if (editors) {\n                for (var i = 0; i < editors.length; ++i) {\n                    IFElementEditor.closeEditor(editors[i].getElement());\n                }\n            }\n\n            // Remove from any parent editor now\n            if (elementEditor.getParentEditor()) {\n                elementEditor.getParentEditor().removeEditor(elementEditor);\n            }\n\n            // Let editor know about detachment\n            elementEditor._detach();\n\n            // Finally detach and be done\n            delete element.__editor__;\n        }\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElementEditor.PartInfo Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * Part of an editor\n     * @param {IFElementEditor} editor the owning editor of the part\n     * @param {*} id id of the part, specific to editor\n     * @param {*} [data] data of the part, specific to editor\n     * @param {Boolean} isolated whether the part is isolated or not\n     * @param {Boolean} selectable whether the part is selectable or not\n     * @constructor\n     * @class IFElementEditor.PartInfo\n     */\n    IFElementEditor.PartInfo = function (editor, id, data, isolated, selectable) {\n        this.editor = editor;\n        this.id = id;\n        this.data = data;\n        this.isolated = isolated;\n        this.selectable = selectable;\n    };\n\n    /**\n     * The id of the part, specific to editor\n     * @type {*}\n     */\n    IFElementEditor.PartInfo.prototype.id = null;\n\n    /**\n     * The data of the part, specific to editor\n     * @type {*}\n     */\n    IFElementEditor.PartInfo.prototype.data = null;\n\n    /**\n     * The owning editor of the part\n     * @type {IFElementEditor}\n     */\n    IFElementEditor.PartInfo.prototype.editor = null;\n\n    /**\n     * Whether the part is isolated or not\n     * @type {Boolean}\n     */\n    IFElementEditor.PartInfo.prototype.isolated = null;\n\n    /**\n     * Whether the part is selectable or not\n     * @type {Boolean}\n     */\n    IFElementEditor.PartInfo.prototype.selectable = null;\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFElementEditor Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @type {Number}\n     * @private\n     */\n    IFElementEditor.prototype._flags = 0;\n\n    /**\n     * @type {IFElement}\n     * @private\n     */\n    IFElementEditor.prototype._element = null;\n\n    /**\n     * @type {IFElement}\n     * @private\n     */\n    IFElementEditor.prototype._elementPreview = null;\n\n    /**\n     * Current transformation to be applied to the element in world coordinates\n     * @type {IFTransform}\n     * @private\n     */\n    IFElementEditor.prototype._transform = null;\n\n    /**\n     * @type {IFElementEditor}\n     * @private\n     */\n    IFElementEditor.prototype._parentEditor = null;\n\n    /**\n     * @type {Array<IFElementEditor>}\n     * @private\n     */\n    IFElementEditor.prototype._editors = null;\n\n    /**\n     * @type {Array<*>}\n     * @private\n     */\n    IFElementEditor.prototype._partSelection = null;\n\n    /**\n     * Checks whether this node editor has a certain flag setup\n     * @param {Number} flag\n     * @returns {Boolean}\n     * @see IFElementEditor.Flag\n     * @version 1.0\n     */\n    IFElementEditor.prototype.hasFlag = function (flag) {\n        return (this._flags & flag) != 0;\n    };\n\n    /**\n     * Set a flag on this node editor\n     * @param {Number} flag the flag to set\n     * @see IFElementEditor.Flag\n     * @version 1.0\n     */\n    IFElementEditor.prototype.setFlag = function (flag) {\n        if ((this._flags & flag) == 0) {\n            this.requestInvalidation();\n            this._flags = this._flags | flag;\n            this.requestInvalidation();\n        }\n    };\n\n    /**\n     * Remove a flag from this node editor\n     * @param {Number} flag the flag to remove\n     * @see IFElementEditor.Flag\n     * @version 1.0\n     */\n    IFElementEditor.prototype.removeFlag = function (flag) {\n        if ((this._flags & flag) != 0) {\n            this.requestInvalidation();\n            this._flags = this._flags & ~flag;\n            this.requestInvalidation();\n        }\n    };\n\n    /**\n     * Return the underlying element this editor is working on\n     * @returns {IFElement}\n     */\n    IFElementEditor.prototype.getElement = function () {\n        return this._element;\n    };\n\n    /**\n     * Return the underlying element this editor is painting\n     * @returns {IFElement}\n     */\n    IFElementEditor.prototype.getPaintElement = function () {\n        return this._elementPreview ? this._elementPreview : this._element;\n    };\n\n    /**\n     * Return the parent editor for this editor if any\n     * @returns {IFElementEditor}\n     * @version 1.0\n     */\n    IFElementEditor.prototype.getParentEditor = function () {\n        return this._parentEditor;\n    };\n\n    /**\n     * Return the sub editors if any\n     * @returns {Array<IFElementEditor>} the sub editors array or null for none\n     * @version 1.0\n     */\n    IFElementEditor.prototype.getEditors = function () {\n        return this._editors;\n    };\n\n    /**\n     * Called to append a sub editor to this one\n     * @param {IFElementEditor} editor the editor to append\n     * @version 1.0\n     */\n    IFElementEditor.prototype.appendEditor = function (editor) {\n        this.insertEditor(editor, null);\n    };\n\n    /**\n     * Called to insert a sub editor to this one\n     * @param {IFElementEditor} editor the editor to insert\n     * @param {IFElementEditor} referenceEditor the editor to insert before or\n     * null to append at the end\n     * @version 1.0\n     */\n    IFElementEditor.prototype.insertEditor = function (editor, referenceEditor) {\n        var index = this._editors ? this._editors.length : 0;\n        if (referenceEditor) {\n            index = this._editors.indexOf(referenceEditor);\n            if (index < 0) {\n                throw new Error(\"Unknown reference editor.\");\n            }\n        }\n\n        if (editor._parentEditor != null) {\n            throw new Error(\"Editor already appended.\");\n        }\n\n        if (!this._editors) {\n            this._editors = [];\n        }\n\n        if (index >= this._editors.length) {\n            this._editors.push(editor);\n        } else {\n            this._editors.splice(index, 0, editor);\n        }\n\n        editor._parentEditor = this;\n    };\n\n    /**\n     * Called to remove a sub editor from this one\n     * @param {IFElementEditor} editor the editor to remove\n     * @version 1.0\n     */\n    IFElementEditor.prototype.removeEditor = function (editor) {\n        var index = this._editors.indexOf(editor);\n        if (index < 0) {\n            throw new Error(\"Unknown editor.\");\n        }\n\n        this._editors.splice(index, 1);\n        editor._parentEditor = null;\n    };\n\n    /**\n     * Accept a visitor\n     * @param {Function} visitor a visitor function called for each visit retrieving the current\n     * node editor as first parameter. The function may return a boolean value indicating whether to\n     * return visiting (true) or whether to cancel visiting (false). Not returning anything or\n     * returning anything else than a Boolean will be ignored.\n     * This defaults to false.\n     * @return {Boolean} result of visiting (false = canceled, true = went through)\n     * @version 1.0\n     */\n    IFElementEditor.prototype.accept = function (visitor) {\n        if (visitor.call(null, this) === false) {\n            return false;\n        }\n\n        if (this._editors) {\n            for (var i = 0; i < this._editors.length; ++i) {\n                if (this._editors[i].accept(visitor) === false) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    };\n\n    /**\n     * Returns if a given part-id of this editor is selected or not\n     * @param {*} partId\n     * @return {Boolean}\n     */\n    IFElementEditor.prototype.isPartSelected = function (partId) {\n        return this._indexOfPartId(this._partSelection, partId) >= 0;\n    };\n\n    /**\n     * Get all selected parts\n     * @returns {Array<*>}\n     */\n    IFElementEditor.prototype.getPartSelection = function () {\n        return this._partSelection;\n    };\n\n    /**\n     * Update the selected parts\n     * @param {Boolean} toggle whether to toggle selection (true) or overwrite it (false)\n     * @param {Array<*>} selection the new part selection to be assigned\n     */\n    IFElementEditor.prototype.updatePartSelection = function (toggle, selection) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected)) {\n            var newSelection = null;\n\n            if (!toggle || !this._partSelection) {\n                newSelection = selection && selection.length > 0 ? selection.slice() : null;\n            } else {\n                if (selection) {\n                    newSelection = [];\n\n                    // Add all non-duplicates of previous selection\n                    for (var i = 0; i < this._partSelection.length; ++i) {\n                        if (this._indexOfPartId(selection, this._partSelection[i]) < 0) {\n                            newSelection.push(this._partSelection[i]);\n                        }\n                    }\n\n                    // Add all new ones\n                    for (var i = 0; i < selection.length; ++i) {\n                        if (this._indexOfPartId(this._partSelection, selection[i]) < 0) {\n                            newSelection.push(selection[i]);\n                        }\n                    }\n\n                    if (newSelection.length === 0) {\n                        newSelection = null;\n                    }\n                }\n            }\n\n            if (!ifUtil.equals(newSelection, this._partSelection, false)) {\n                this._updatePartSelection(newSelection);\n            }\n        }\n    };\n\n    /**\n     * Called whenever information about a part at a given location shall be returned\n     * @param {IFPoint} location the location to get a part for in view coordinates\n     * @param {IFTransform} transform the current transformation of the view\n     * @param {Function} [acceptor] optional callback function getting called\n     * for a part and receiving the current editor as it's only parameter.\n     * The function should return true to accept the editor or false for not.\n     * @param {Number} [tolerance] optional tolerance for testing the location.\n     * If not provided defaults to zero.\n     * @returns {IFElementEditor.PartInfo} null if no part is available or a valid part info\n     */\n    IFElementEditor.prototype.getPartInfoAt = function (location, transform, acceptor, tolerance) {\n        tolerance = tolerance || 0;\n\n        // Iterate sub editors, first\n        if (this._editors && this._editors.length) {\n            for (var i = this._editors.length - 1; i >= 0; --i) {\n                var result = this._editors[i].getPartInfoAt(location, transform, acceptor, tolerance);\n                if (result) {\n                    return result;\n                }\n            }\n        }\n\n        if (acceptor && acceptor.call(null, this) !== true) {\n            return null;\n        }\n\n        // Try to hit test our editor now\n        var bbox = this.getBBox(transform);\n        if (bbox && !bbox.isEmpty()) {\n            if (bbox.containsPoint(location)) {\n                var result = this._getPartInfoAt(location, transform, tolerance);\n                if (result) {\n                    return result;\n                }\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Called whenever this editor should paint itself\n     * @param {IFTransform} transform the transformation of the scene\n     * @param {IFPaintContext} context\n     */\n    IFElementEditor.prototype.paint = function (transform, context) {\n        // Paint children editors if any\n        this._paintChildren(transform, context);\n    };\n\n    /**\n     * Called whenever this editor should return it's bbox.\n     * Note that this should never return a compound bbox like\n     * unioning all children but only the bbox of this one\n     * specific editor. If the editor doesn't have a real bbox\n     * like a group, null should be returned. The return bbox includes\n     * the bbox margin already if any.\n     * @param {IFTransform} transform the transformation of the scene\n     * @return {IFRect} the bbox in view coordinates\n     */\n    IFElementEditor.prototype.getBBox = function (transform) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            var targetTransform = transform;\n\n            // Pre-multiply internal transformation if any\n            if (this._transform) {\n                targetTransform = this._transform.multiplied(transform);\n            }\n\n            var bbox = this.getPaintElement().getGeometryBBox();\n            if (bbox && !bbox.isEmpty()) {\n                var expand = this.getBBoxMargin();\n                bbox = targetTransform.mapRect(bbox)\n                    .expanded(expand, expand, expand, expand);\n\n                if (this.hasFlag(IFElementEditor.Flag.Detail)) {\n                    var customBBox = this.getCustomBBox(targetTransform, false);\n                    if (customBBox) {\n                        bbox = bbox.united(customBBox);\n                    }\n                }\n            }\n\n            return bbox;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Returns the bbox' margin added to each side to cover\n     * the entire editor area. Returns by default 1 for 1-pixel\n     * accuracy covering\n     * @return {Number}\n     */\n    IFElementEditor.prototype.getBBoxMargin = function () {\n        return 1;\n    };\n\n    /**\n     * Returns bbox based on visible additional elements like annotations or center cross\n     * @param {IFTransform} transform - the transformation to apply to points\n     * before calculating additional visible elements {usually world to view transformation}\n     * @param {Boolean} includeEditorTransform - shows if editor internal transformation should be applied\n     * @return {IFRect} the bbox in view coordinates\n     */\n    IFElementEditor.prototype.getCustomBBox = function (transform, includeEditorTransform) {\n        return null;\n    };\n\n    /**\n     * Called to request an invalidation of this editor.\n     * This will actually request an invalidation which will then\n     * return back to this editor and ask it for providing\n     * the actual invalidation area\n     * @param {*} [args] optional arguments which will be passed\n     * to this editor's invalidate callback.\n     * If no arguments are passed, the editor will by default\n     * return the bounding box of itself if it has any\n     * @see invalidate\n     */\n    IFElementEditor.prototype.requestInvalidation = function (args) {\n        IFEditor.getEditor(this._element.getScene()).requestInvalidation(this, args);\n    };\n\n    /**\n     * Callback after an invalidation request\n     * @param {IFTransform} transform the transformation of the scene\n     * @param {*} args optional args passed to the initial requestInvalidation\n     * call. Maybe null which indicates to return this editor's bbox if any\n     * @return {IFRect} the transformed area to be invalidated or null for none\n     */\n    IFElementEditor.prototype.invalidate = function (transform, args) {\n        // Default handling for no arguments\n        if (!args) {\n            return this.getBBox(transform);\n        }\n        return null;\n    };\n\n    /**\n     * Called whenever a part of this editor shell be moved\n     * @param {*} partId the id of the editor part to be moved\n     * @param {*} partData the data of the editor part to be moved\n     * @param {IFPoint} position the new position in view coordinates\n     * the part should be moved to\n     * @param {IFTransform} viewToWorldTransform - the transformation to apply to position\n     * @param {IFGuides} guides to snap is needed\n     * @param {Boolean} shift whether shift key is hold or not\n     * @param {Boolean} option whether option key is hold or not\n     */\n    IFElementEditor.prototype.movePart = function (partId, partData, position, viewToWorldTransform, guides, shift, option) {\n        // Set outline flag and/or invalidate by default for each move\n        if (!this.hasFlag(IFElementEditor.Flag.Outline)) {\n            this.setFlag(IFElementEditor.Flag.Outline);\n        } else {\n            this.requestInvalidation();\n        }\n    };\n    /**\n     * Called whenever a move of a part shell be reset\n     * @param {*} partId the id of the editor part that was moved\n     * @param {*} partData the data of the editor part that was moved\n     */\n    IFElementEditor.prototype.resetPartMove = function (partId, partData) {\n        // Some resets by default\n        this._elementPreview = null;\n        this.removeFlag(IFElementEditor.Flag.Outline);\n    };\n\n    /**\n     * Called whenever a move of a part shell be applied\n     * @param {*} partId the id of the editor part that was moved\n     * @param {*} partData the data of the editor part that was moved\n     */\n    IFElementEditor.prototype.applyPartMove = function (partId, partData) {\n        // Some resets by default\n        this._elementPreview = null;\n        this.removeFlag(IFElementEditor.Flag.Outline);\n    };\n\n    /**\n     * Called whenever this editor shell be transformed\n     * @param {IFTransform} transform the transformation to be used\n     * @param {*} [partId] optional id of part that initiated the transform\n     * @param {*} [partData] optional data of part that initialized the transform\n     */\n    IFElementEditor.prototype.transform = function (transform, partId, partData) {\n        this._setTransform(transform);\n    };\n\n    /**\n     * Called whenever the transformation of the editor shell be reset\n     */\n    IFElementEditor.prototype.resetTransform = function () {\n        this._elementPreview = null;\n\n        // Invalidate on reset no matter what\n        this.requestInvalidation();\n\n        this._transform = null;\n\n        // Remove outline\n        this.removeFlag(IFElementEditor.Flag.Outline);\n    };\n\n    /**\n     * Called to test whether the current transformation of this editor\n     * can be applied to the element\n     * @return {Boolean} true if the transformation can be applied,\n     * false if not\n     */\n    IFElementEditor.prototype.canApplyTransform = function () {\n        var element = this.getElement();\n\n        // By default, transformation can only be applied if it is valid,\n        // the element supports transforming and the element is not locked\n        return this._transform && !this._transform.isIdentity() &&\n            element.hasMixin(IFElement.Transform) && !element.hasFlag(IFElement.Flag.Locked);\n    };\n\n    /**\n     * Called whenever the transformation of the editor shell be applied.\n     * Note that the caller might decide that the transformation shall be\n     * applied to another element and not the one the editor is currently\n     * working on. However, it is guaranteed that in this case, the element\n     * to apply the transformation instead is an exact clone of the element\n     * this editor is currently working on.\n     * @param {IFElement} element the element to apply the transformation\n     * to which might be different than the one this editor works on. This\n     * will be never null.\n     */\n    IFElementEditor.prototype.applyTransform = function (element) {\n        if (!this._transform.isIdentity()) {\n            // By default we'll simply transfer the transformation to the element\n            element.transform(this._transform);\n        }\n        this.resetTransform();\n    };\n\n    /**\n     * Called whenever something has been dropped on this editor.\n     * If the editor is able to handle it, it should return true\n     * to prevent any further handling.\n     * @param {IFPoint} position the drop position in scene coordinates\n     * @param {IFElementEditor.DropType} type\n     * @param {*} source the drop source, the type depends on type\n     * @param {*} hitData the IFElement.HitResult.data that was gathered\n     * when hitting the element for this editor, might be null\n     */\n    IFElementEditor.prototype.acceptDrop = function (position, type, source, hitData) {\n        // By default, we'll ask all children editors, first\n        if (this._editors) {\n            for (var i = 0; i < this._editors.length; ++i) {\n                if (this._editors[i].acceptDrop(position, type, source, hitData) === true) {\n                    return true;\n                }\n            }\n        }\n\n        // Dropping a style on stylable elements will be handled as well\n        if (type === IFElementEditor.DropType.Node && source && source instanceof IFStyle) {\n            if (this._element.hasMixin(IFElement.Style)) {\n                var editor = IFEditor.getEditor(this._element.getScene());\n                editor.beginTransaction();\n                try {\n                    if (source instanceof IFSharedStyle) {\n                        var linkedStyle = new IFLinkedStyle();\n                        linkedStyle.setProperty('ref', source.getReferenceId());\n                        this._element.getStyleSet().appendChild(linkedStyle);\n                    } else {\n                        this._element.getStyleSet().appendChild(source);\n                    }\n                } finally {\n                    // TODO : I18N\n                    editor.commitTransaction('Drag Style');\n                }\n                return true;\n            }\n        }\n\n        return false;\n    };\n\n    /**\n     * Called whenever a newly inserted element should become\n     * some default setup\n     * @param {IFColor} fillColor the current default fill color\n     * @param {IFColor} strokeColor the current default stroke color\n     */\n    IFElementEditor.prototype.initialSetup = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called to check whether this editor can do some inline editing\n     * @returns {boolean}\n     */\n    IFElementEditor.prototype.canInlineEdit = function () {\n        return false;\n    };\n\n    /**\n     * Called to check whether this editor currently is in inline edit mode\n     * @returns {boolean}\n     */\n    IFElementEditor.prototype.isInlineEdit = function () {\n        return false;\n    };\n\n    /**\n     * Called to let the editor do some inline editing\n     * @param {IFEditorView} view the view the inline editing should\n     * take place within\n     * @param {HTMLElement} container the container any editor element\n     * should be attached to relative to the view\n     */\n    IFElementEditor.prototype.beginInlineEdit = function (view, container) {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Called whenever something in the view has changed and the inline\n     * editor should adjust itself. This will also called immediately\n     * after the beginInlineEdit call.\n     * @param {IFEditorView} view the view the inline editing takes place\n     * @param {IFPoint} [position] optional position in screen cordinates,\n     * defaults to null\n     */\n    IFElementEditor.prototype.adjustInlineEditForView = function (view, position) {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Called to finish inline editing. This is called within a transaction\n     * and should not only close any inline editor but also apply any changes.\n     * @return {String} optional human readable text of the editing action description\n     */\n    IFElementEditor.prototype.finishInlineEdit = function () {\n        throw new Error('Not Supported.');\n    };\n\n    /**\n     * Allow each editor to perform the needed actions when drag is started in SubSelect Tool\n     * @param {IFElementEditor.PartInfo} partInfo - the part info under mouse\n     * @returns {IFElementEditor.PartInfo} - updated part info under mouse\n     */\n    IFElementEditor.prototype.subSelectDragStartAction = function (partInfo) {\n        var newPartInfo = null;\n\n        // By default, we'll ask all children editors, first\n        if (this._editors) {\n            for (var i = 0; i < this._editors.length; ++i) {\n                newPartInfo = this._editors[i].subSelectDragStartAction(partInfo);\n                if (newPartInfo) {\n                    return newPartInfo;\n                }\n            }\n        }\n\n        if (partInfo.editor === this) {\n            newPartInfo = partInfo;\n        }\n\n        return newPartInfo;\n    };\n\n    /**\n     * Called when this editor is attached to the node\n     */\n    IFElementEditor.prototype._attach = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called when this editor is detached from the node\n     */\n    IFElementEditor.prototype._detach = function () {\n        // NO-OP\n    };\n\n    /**\n     * Paint all sub editors if any\n     * @param {IFPaintContext} context\n     * @private\n     */\n    IFElementEditor.prototype._paintChildren = function (transform, context) {\n        if (this._editors) {\n            for (var i = 0; i < this._editors.length; ++i) {\n                var editor = this._editors[i];\n                if (editor instanceof IFElementEditor) {\n                    editor.paint(transform, context);\n                }\n            }\n        }\n    };\n\n    /**\n     * Called whenever a part should be returned at a given location.\n     * Note that the caller is responsible for testing the bbox of this\n     * editor for faster lookup as well as the caller is responsible for\n     * iterating any sub editors as well.\n     * @param {IFPoint} location the location to get a part for in view coordinates\n     * @param {IFTransform} transform - the current transformation of the scene {worldToViewTransform}\n     * @param {Number} tolerance tolerance for testing the location\n     * @returns {*} null if no part is available or an editor-specific part\n     */\n    IFElementEditor.prototype._getPartInfoAt = function (location, transform, tolerance) {\n        return null;\n    };\n\n    /**\n     * Compare two part ids. If part ids of the editor are complex then\n     * the editor descendant should override this with a custom comparison.\n     * @param {*} a\n     * @param {*} b\n     * @returns {boolean}\n     * @private\n     */\n    IFElementEditor.prototype._partIdAreEqual = function (a, b) {\n        return a === b;\n    };\n\n    /**\n     * Get index of part-id within an array using the _partIdAreEqual function\n     * @param {Array<*>} array\n     * @param {*} partId\n     * @returns {Number}\n     * @private\n     */\n    IFElementEditor.prototype._indexOfPartId = function (array, partId) {\n        if (array && array.length > 0) {\n            for (var i = 0; i < array.length; ++i) {\n                if (this._partIdAreEqual(array[i], partId)) {\n                    return i;\n                }\n            }\n        }\n        return -1;\n    };\n\n    /**\n     * Called whenever the part selection should be udpated\n     * @param {Array<*>} selection the new part selection\n     * @private\n     */\n    IFElementEditor.prototype._updatePartSelection = function (selection) {\n        this.requestInvalidation();\n        this._partSelection = selection;\n        this.requestInvalidation();\n    };\n\n    /**\n     * Paint an annotation\n     * @param {IFPaintContext} context the paint context to paint on\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPoint} center the center point of the annotation\n     * @param {IFElementEditor.Annotation} annotation the annotation to be painted\n     * @param {Boolean} [selected] whether the annotation should be painted\n     * selected or not. Defaults to false.\n     * @param {Boolean} [small] if true, paints the annotation in small size,\n     * otherwise in default size\n     */\n    IFElementEditor.prototype._paintAnnotation = function (context, transform, center, annotation, selected, small) {\n        var size = small ? IFElementEditor.OPTIONS.annotationSizeSmall : IFElementEditor.OPTIONS.annotationSizeRegular;\n        ifAnnotation.paintAnnotation(context, transform, center, annotation, selected, size);\n    };\n\n    /**\n     * Get bbox of an annotation\n     * @param {IFTransform} transform the current transformation in use\n     * @param {IFPoint} center the center point of the annotation\n     * @param {Boolean} [small] whether to paint small annotation or not\n     */\n    IFElementEditor.prototype._getAnnotationBBox = function (transform, center, small) {\n        var size = small ? IFElementEditor.OPTIONS.annotationSizeSmall : IFElementEditor.OPTIONS.annotationSizeRegular;\n        return ifAnnotation.getAnnotationBBox(transform, center, size);\n    };\n\n    /**\n     * @returns {Boolean}\n     * @private\n     */\n    IFElementEditor.prototype._showAnnotations = function () {\n        return this.hasFlag(IFElementEditor.Flag.Selected) && !this.hasFlag(IFElementEditor.Flag.Outline);\n    };\n\n    /**\n     * Assign editor transformation and invalidate\n     * @param {IFTransform} transform\n     * @private\n     */\n    IFElementEditor.prototype._setTransform = function (transform) {\n        // By default we'll simply assign the transformation\n        if (!IFTransform.equals(this._transform, transform)) {\n            if (!this.hasFlag(IFElementEditor.Flag.Outline)) {\n                this.setFlag(IFElementEditor.Flag.Outline);\n            } else {\n                this.requestInvalidation();\n            }\n\n            this._transform = transform;\n            this.requestInvalidation();\n        }\n    };\n\n    /** @override */\n    IFElementEditor.prototype.toString = function () {\n        return \"[Object IFElementEditor]\";\n    };\n\n    _.IFElementEditor = IFElementEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/sceneeditor.js",
    "content": "(function (_) {\n    /**\n     * The base for a scene editor\n     * @param {IFScene} scene the scene this editor works on\n     * @class IFSceneEditor\n     * @extends IFElementEditor\n     * @constructor\n     */\n    function IFSceneEditor(scene) {\n        IFElementEditor.call(this, scene);\n    };\n    IFObject.inherit(IFSceneEditor, IFElementEditor);\n    IFElementEditor.exports(IFSceneEditor, IFScene);\n\n    /**\n     * @type {IFTransformBox}\n     * @private\n     */\n    IFSceneEditor.prototype._transformBox = null;\n\n    /**\n     * An array of vusial lines ends, which are used to show snap zones\n     * @type {Array<Array<IFPoint>>} - line ends in view coordinates\n     * @private\n     */\n    IFSceneEditor.prototype._visuals = null;\n\n    /**\n     * Area, which is used for painting and cleaning lines of snap zones\n     * @type {IFRect} - visuals area in world coordinates\n     * @private\n     */\n    IFSceneEditor.prototype._visualsArea = null;\n\n    /**\n     * The possible modes of transform box functionality\n     * @type {{NA: number, PASSIVE: number, TBOXMOVE: number, CNTRMOVE: number, ROTATE: number, RESIZE: number, SKEW: number}}\n     */\n    IFSceneEditor.TBoxMode = {\n        NA : 0,\n        PASSIVE: 1,\n        TBOXMOVE: 2,\n        CNTRMOVE: 3,\n        ROTATE: 4,\n        RESIZE: 5,\n        SKEW: 6\n    };\n\n    /**\n     * @type {IFSceneEditor.TBoxMode}\n     * @private\n     */\n    IFSceneEditor.prototype._tBoxMode = IFSceneEditor.TBoxMode.NA;\n\n    /**\n     * @type {IFElementEditor.PartInfo}\n     * @private\n     */\n    IFSceneEditor.prototype._tBoxData = null;\n\n    /**\n     * @type {IFElementEditor.PartInfo}\n     * @private\n     */\n    IFSceneEditor.prototype._mouseInfo = null;\n\n    /** override */\n    IFSceneEditor.prototype.paint = function (transform, context) {\n        IFElementEditor.prototype.paint.call(this, transform, context);\n        if (this._transformBox) {\n            this._transformBox.paint(transform, context);\n\n            if (this._visuals) {\n                var visLine;\n                for (var i = 0; i < this._visuals.length; ++i) {\n                    visLine = this._visuals[i];\n                    var pt0 = visLine[0];\n                    var pt1 = visLine[1];\n                    context.canvas.strokeLine(Math.floor(pt0.getX()) + 0.5, Math.floor(pt0.getY()) + 0.5,\n                        Math.floor(pt1.getX()) + 0.5, Math.floor(pt1.getY()) + 0.5, 1, context.highlightOutlineColor);\n                }\n\n                this._visuals = null;\n            }\n        }\n    };\n\n    /** override */\n    IFSceneEditor.prototype.getBBox = function (transform) {\n        var bbox = IFElementEditor.prototype.getBBox.call(this, transform);\n        if (this._transformBox) {\n            var transBBox = this._transformBox._calculateGeometryBBox();\n            if (transBBox && !transBBox.isEmpty()) {\n                transBBox = transform ? transform.mapRect(transBBox) : transBBox;\n                transBBox = transBBox.expanded(\n                    IFTransformBox.ANNOT_SIZE, IFTransformBox.ANNOT_SIZE, IFTransformBox.ANNOT_SIZE, IFTransformBox.ANNOT_SIZE);\n                bbox = bbox ? bbox.united(transBBox) : transBBox;\n            }\n        }\n        return bbox;\n    };\n\n    /** override */\n    IFSceneEditor.prototype._detach = function () {\n        if (this._transformBox) {\n            this.setTransformBoxActive(false);\n        }\n    };\n\n    /**\n     * Checks if the transform box is currently active\n     * @returns {Boolean}\n     */\n    IFSceneEditor.prototype.isTransformBoxActive = function () {\n        return (this._transformBox != null);\n    };\n\n    /**\n     * Activates or deactivates the transform box\n     * @param {Boolean} activate - when true or not set means activation is needed, when false - deactivation\n     * @param {IFPoint} center - transform box center to set\n     */\n    IFSceneEditor.prototype.setTransformBoxActive = function (activate, center) {\n        if (activate || activate === null) {\n            if (!this._transformBox) {\n                this._element.addEventListener(IFElement.GeometryChangeEvent, this._geometryChange, this);\n            }\n\n            this._updateSelectionTransformBox(center);\n        } else {\n            if (this._transformBox) {\n                this._element.removeEventListener(IFElement.GeometryChangeEvent, this._geometryChange, this);\n\n                this.requestInvalidation();\n                this._transformBox = null;\n                this.requestInvalidation();\n            }\n        }\n    };\n\n    IFSceneEditor.prototype.getTransformBox = function () {\n        return this._transformBox;\n    };\n\n    IFSceneEditor.prototype.requestInvalidation = function(args) {\n        this._getGraphicEditor().requestInvalidation(this, args);\n    };\n\n    IFSceneEditor.prototype.getTBoxMode = function () {\n        return this._tBoxMode;\n    };\n\n    IFSceneEditor.prototype._updateTBoxMode = function(mode) {\n        this._tBoxMode = mode;\n    };\n\n    IFSceneEditor.prototype.hideTransformBox = function () {\n        if (this._transformBox) {\n            this._transformBox.hide();\n        }\n        this.requestInvalidation();\n    };\n\n    IFSceneEditor.prototype.showTransformBox = function () {\n        if (this._transformBox) {\n            this._transformBox.show();\n        }\n        this.requestInvalidation();\n    };\n\n    IFSceneEditor.prototype.getTransformBoxCenter = function () {\n        if (this._transformBox) {\n            return new IFPoint(this._transformBox.cx, this._transformBox.cy);\n        }\n        return null;\n    };\n\n    IFSceneEditor.prototype._applyTBoxCenterTransform = function () {\n        if (this._transformBox && (this._transformBox.trf || this._transformBox.cTrf)) {\n            this._getGraphicEditor().beginTransaction();\n            try {\n                this._transformBox.applyCenterTransform();\n            } finally {\n                // TODO : I18N\n                this._getGraphicEditor().commitTransaction('Move');\n            }\n            this.requestInvalidation();\n        }\n    };\n\n    IFSceneEditor.prototype.getCursor = function (partInfo) {\n        var cursor = IFCursor.Select;\n\n        switch (partInfo.id) {\n            case IFTransformBox.INSIDE:\n                cursor = IFCursor.SelectCross;\n                break;\n            case IFTransformBox.OUTSIDE:\n                cursor = IFCursor.SelectRotate[partInfo.data];\n                break;\n            case IFTransformBox.OUTLINE:\n                cursor = partInfo.data ? IFCursor.SelectSkewHoriz : IFCursor.SelectSkewVert;\n                break;\n            case IFTransformBox.Handles.TOP_CENTER:\n            case IFTransformBox.Handles.BOTTOM_CENTER:\n                cursor = IFCursor.SelectResizeVert;\n                break;\n            case IFTransformBox.Handles.LEFT_CENTER:\n            case IFTransformBox.Handles.RIGHT_CENTER:\n                cursor = IFCursor.SelectResizeHoriz;\n                break;\n            case IFTransformBox.Handles.TOP_LEFT:\n            case IFTransformBox.Handles.BOTTOM_RIGHT:\n                cursor = IFCursor.SelectResizeUpLeftDownRight;\n                break;\n            case IFTransformBox.Handles.TOP_RIGHT:\n            case IFTransformBox.Handles.BOTTOM_LEFT:\n                cursor = IFCursor.SelectResizeUpRightDownLeft;\n                break;\n            case IFTransformBox.Handles.ROTATION_CENTER:\n                cursor = IFCursor.SelectArrowOnly;\n                break;\n        }\n\n        return cursor;\n    };\n\n    IFSceneEditor.prototype.updateTBoxUnderMouse = function (location, transform, view) {\n        var pInfo = null;\n        if (this._tBoxData) {\n            pInfo = new IFElementEditor.PartInfo(this._tBoxData.editor, this._tBoxData.id, this._tBoxData.data);\n            if (pInfo.id  == IFTransformBox.OUTSIDE) {\n                pInfo.data = this._transformBox.getRotationSegment(location, transform);\n            }\n        } else {\n            pInfo = this._transformBox.getPartInfoAt(location, transform, this._element.getProperty('pickDist'));\n        }\n\n        if (!this._mouseInfo || this._mouseInfo.id != pInfo.id || this._mouseInfo.data != pInfo.data) {\n            this._mouseInfo = pInfo;\n            view.setCursor(this.getCursor(this._mouseInfo));\n        }\n        var bBox = null;\n        this._visuals = null;\n        if (this._tBoxMode == IFSceneEditor.TBoxMode.PASSIVE && this._mouseInfo.id == IFTransformBox.INSIDE) {\n            var selection = this._getGraphicEditor().getSelection();\n            var selBBox = IFElement.prototype.getGroupGeometryBBox(selection);\n            if (selBBox && !selBBox.isEmpty()) {\n                bBox = transform.mapRect(selBBox);\n                var visuals = this._getGraphicEditor().getGuides().getBBoxSnapZones(bBox, location);\n                if (visuals && visuals.length) {\n                    this._visuals = visuals;\n                }\n            }\n        }\n\n        var visualsArea = this._visuals ? bBox.expanded(2, 2, 2, 2) : null;\n        visualsArea = visualsArea ? view.getViewTransform().mapRect(visualsArea) : null;\n        if (this._visualsArea || visualsArea) {\n            if (this._visualsArea) {\n                //this._element._invalidateArea(this._visualsArea);\n                //this.requestInvalidation();\n            }\n            if (visualsArea) {\n                //this._element._invalidateArea(visualsArea);\n                //this.requestInvalidation();\n            }\n            this.requestInvalidation();\n            this._visualsArea = visualsArea;\n            this.requestInvalidation();\n        }\n    };\n\n    IFSceneEditor.prototype.getTBoxPartInfoAt = function (location, transform, tolerance) {\n        return this._transformBox.getPartInfoAt(location, transform, tolerance);\n    };\n\n    IFSceneEditor.prototype.startTBoxTransform = function (partInfo) {\n        if (this._visualsArea) {\n            this.requestInvalidation();\n            //this._element._invalidateArea(this._visualsArea);\n            this._visualsArea = null;\n        }\n\n        this._tBoxData = new IFElementEditor.PartInfo(partInfo.editor, partInfo.id,\n            partInfo.data);\n\n        if (this._tBoxData.id  == IFTransformBox.OUTLINE) {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.SKEW);\n        } else if (this._tBoxData.id  == IFTransformBox.OUTSIDE) {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.ROTATE);\n        } else if (this._tBoxData.id >= 0 && this._tBoxData.id < IFTransformBox.Handles.ROTATION_CENTER) {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.RESIZE);\n        } else if (this._tBoxData.id == IFTransformBox.Handles.ROTATION_CENTER) {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.CNTRMOVE);\n        } else {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.TBOXMOVE);\n        }\n\n        this.hideTransformBox();\n    };\n\n    /**\n     * Calculates and makes the on-going transformation of the selection and transform box based on pre-set\n     * transform mode, start position of movement and the current position\n     * @param {IFPoint} startPos - the start position of movement\n     * @param {IFPoint} curPos - the current position\n     * @param {Boolean} option - when set and resizing, the resize is center-symmetric\n     * @param {Boolean} ratio - when set and rotate/skew - keep ratioStep, when resize - the scale for X and Y are the same\n     * @param {Number} ratioStep - when set and ratio, then this step is used for constraint\n     */\n    IFSceneEditor.prototype.transformTBox = function (startPos, curPos, option, ratio, ratioStep) {\n        if (this._tBoxMode != IFSceneEditor.TBoxMode.PASSIVE && this._tBoxMode != IFSceneEditor.TBoxMode.NA) {\n            var guides = this._getGraphicEditor().getGuides();\n            guides.getShapeBoxGuide().useExclusions(this._getGraphicEditor().getSelection());\n            guides.beginMap();\n            var rStep = ratioStep;\n            if (!rStep && this._tBoxMode == IFSceneEditor.TBoxMode.SKEW) {\n                rStep = this._element.getProperty('gridSizeX');\n            }\n            var transform = this._transformBox.calculateTransformation(this._tBoxData,\n                startPos, curPos, guides, option, ratio, rStep);\n\n            guides.finishMap();\n            this.requestInvalidation();\n            if (this._tBoxMode != IFSceneEditor.TBoxMode.CNTRMOVE) {\n                this._transformBox.setTransform(transform);\n                this._getGraphicEditor().transformSelection(transform, null, null);\n            } else {\n                this._transformBox.setCenterTransform(transform);\n                this.requestInvalidation();\n            }\n        }\n    };\n\n    IFSceneEditor.prototype.applyTBoxTransform = function (option) {\n        if (this._tBoxMode == IFSceneEditor.TBoxMode.CNTRMOVE) {\n            this._applyTBoxCenterTransform();\n            this.showTransformBox();\n        } else {\n            this._getGraphicEditor().applySelectionTransform(option);\n        }\n        this._updateTBoxMode(IFSceneEditor.TBoxMode.PASSIVE);\n        this._tBoxData = null;\n        this._mouseInfo = null;\n    };\n\n    IFSceneEditor.prototype._updateSelectionTransformBox = function (center) {\n        this.requestInvalidation();\n        var cx = null;\n        var cy = null;\n        if (center) {\n            cx = center.getX();\n            cy = center.getY();\n        } else if (this._transformBox) {\n            cx = this._transformBox.cx;\n            cy = this._transformBox.cy;\n        }\n        this._transformBox = null;\n        var selection = this._getGraphicEditor().getSelection();\n        var selBBox = IFElement.prototype.getGroupGeometryBBox(selection);\n        if (selBBox) {\n            this._transformBox = new IFTransformBox(selBBox, cx, cy);\n        }\n        this.requestInvalidation();\n\n        if (this._transformBox) {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.PASSIVE);\n        } else {\n            this._updateTBoxMode(IFSceneEditor.TBoxMode.NA);\n        }\n        this._tBoxData = null;\n        this._mouseInfo = null;\n        if (this._visualsArea) {\n            //this._element._invalidateArea(this._visualsArea);\n            this._visualsArea = null;\n        }\n    };\n\n    IFSceneEditor.prototype._geometryChange = function (evt) {\n        if (this._transformBox && evt.type == IFElement.GeometryChangeEvent.Type.After &&\n                evt.element.hasFlag(IFNode.Flag.Selected)) {\n\n            if (this._transformBox.trf || this._transformBox.cTrf) {\n                this._transformBox.applyCenterTransform();\n            }\n            this._updateSelectionTransformBox();\n        }\n    };\n\n    IFSceneEditor.prototype._getGraphicEditor = function () {\n        return this._element.__graphic_editor__;\n    };\n\n    /** @override */\n    IFSceneEditor.prototype.toString = function () {\n        return \"[Object IFSceneEditor]\";\n    };\n\n    _.IFSceneEditor = IFSceneEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/ellipseeditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for an ellipse\n     * @param {IFEllipse} ellipse the ellipse this editor works on\n     * @class IFEllipseEditor\n     * @extends IFPathBaseEditor\n     * @constructor\n     */\n    function IFEllipseEditor(ellipse) {\n        IFPathBaseEditor.call(this, ellipse);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFEllipseEditor, IFPathBaseEditor);\n    IFElementEditor.exports(IFEllipseEditor, IFEllipse);\n\n    IFEllipseEditor.START_ANGLE_PART_ID = ifUtil.uuid();\n    IFEllipseEditor.END_ANGLE_PART_ID = ifUtil.uuid();\n\n    /** @override */\n    IFEllipseEditor.prototype.getBBoxMargin = function () {\n        var source = IFPathBaseEditor.prototype.getBBoxMargin.call(this);\n        if (this._showSegmentDetails()) {\n            return Math.max(IFElementEditor.OPTIONS.annotationSizeRegular + 1, source);\n        }\n        return source;\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype.getCustomBBox = function (transform, includeEditorTransform) {\n        var bbox = null;\n        if (this.hasFlag(IFElementEditor.Flag.Selected) && this.hasFlag(IFElementEditor.Flag.Detail)) {\n            // Don't include individual annotations here,\n            // as they are added all together in getBBoxMargin(),\n            // but add center cross, as it may be outside of ellipse arc or chord\n            var trf = transform;\n            // Use internal transformation if required\n            if (includeEditorTransform && this._transform) {\n                trf = this._transform.multiplied(transform);\n            }\n\n            var center = this.getPaintElement().getCenter(true);\n            bbox = ifAnnotation.getAnnotationBBox(trf, center, IFElementEditor.OPTIONS.centerCrossSize * 2);\n        }\n        return bbox;\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype.movePart = function (partId, partData, position, viewToWorldTransform, guides, shift, option) {\n        IFPathBaseEditor.prototype.movePart.call(this, partId, partData, position, viewToWorldTransform, guides, shift, option);\n        if (partId === IFEllipseEditor.START_ANGLE_PART_ID || partId === IFEllipseEditor.END_ANGLE_PART_ID) {\n            var newPos = viewToWorldTransform.mapPoint(position);\n\n            if (!this._elementPreview) {\n                this._elementPreview = new IFEllipse();\n                this._elementPreview.transferProperties(this._element,\n                    [IFShape.GeometryProperties, IFEllipse.GeometryProperties], true);\n            }\n\n            var sourceTransform = this._element.getTransform();\n            if (sourceTransform) {\n                var sPosition = sourceTransform.inverted().mapPoint(newPos);\n            } else {\n                var sPosition = newPos;\n            }\n            var angle = Math.atan2(sPosition.getY(), sPosition.getX());\n            var sa = this._element.getProperty('sa');\n            var ea = this._element.getProperty('ea');\n            if (partId == IFEllipseEditor.START_ANGLE_PART_ID) {\n                var aDelta = angle - sa;\n            } else { // end angle\n                var aDelta = angle - ea;\n            }\n\n            var moveStart = this._partSelection.indexOf(IFEllipseEditor.START_ANGLE_PART_ID) >= 0;\n            var moveEnd = this._partSelection.indexOf(IFEllipseEditor.END_ANGLE_PART_ID) >= 0;\n\n            if (moveStart || moveEnd) {\n                this._elementPreview.setProperties(['sa', 'ea'],\n                    [moveStart ? ifMath.normalizeAngleRadians(sa + aDelta) : sa,\n                        moveEnd ? ifMath.normalizeAngleRadians(ea + aDelta) : ea]);\n\n                this.requestInvalidation();\n            }\n        }\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype.applyPartMove = function (partId, partData) {\n        if (partId === IFEllipseEditor.START_ANGLE_PART_ID || partId === IFEllipseEditor.END_ANGLE_PART_ID) {\n            var propertyValues = this._elementPreview.getProperties(['sa', 'ea']);\n            this.resetPartMove(partId, partData);\n            this._element.setProperties(['sa', 'ea'], propertyValues);\n        }\n        IFPathBaseEditor.prototype.applyPartMove.call(this, partId, partData);\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype.applyTransform = function (element) {\n        if (element && this._elementPreview) {\n            element.transferProperties(this._elementPreview, [IFShape.GeometryProperties, IFEllipse.GeometryProperties]);\n            this.resetTransform();\n        } else {\n            IFPathBaseEditor.prototype.applyTransform.call(this, element);\n        }\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype._postPaint = function (transform, context) {\n        IFPathBaseEditor.prototype._postPaint.call(this, transform, context);\n        // If we have segments then paint 'em\n        if (this._showSegmentDetails()) {\n            this._iterateArcEnds(true, function (args) {\n                var annotation = (args.id == IFEllipseEditor.START_ANGLE_PART_ID)\n                    ? IFElementEditor.Annotation.Diamond\n                    : IFElementEditor.Annotation.Circle;\n\n                var selected = (this._partSelection && this._partSelection.indexOf(args.id) >= 0);\n                this._paintAnnotation(context, transform, args.position, annotation, selected, false);\n                return false;\n            }.bind(this));\n        }\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype._getPartInfoAt = function (location, transform, tolerance) {\n        // If we have segment details then hit-test 'em\n        if (this._showSegmentDetails()) {\n            result = null;\n            this._iterateArcEnds(false, function (args) {\n                if (this._getAnnotationBBox(transform, args.position)\n                    .expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n                    result = new IFElementEditor.PartInfo(this, args.id, null, true, true);\n                    return true;\n                }\n                return false;\n            }.bind(this));\n\n            if (result) {\n                return result;\n            }\n        }\n\n        return IFShapeEditor.prototype._getPartInfoAt.call(this, location, transform, tolerance);\n    };\n\n    /**\n     * @returns {Boolean}\n     * @private\n     */\n    IFEllipseEditor.prototype._showSegmentDetails = function () {\n        return this._showAnnotations() && this.hasFlag(IFElementEditor.Flag.Detail) && !this._elementPreview;\n    };\n\n    IFEllipseEditor.prototype._iterateArcEnds = function (paintElement, iterator) {\n        var element = paintElement ? this.getPaintElement() : this._element;\n        var transform = element.getTransform();\n        var startA = element.getProperty('sa');\n        var endA = element.getProperty('ea');\n        transform = transform ? transform : new IFTransform(1, 0, 0, 1, 0, 0);\n        var itArgs = [\n            {id: IFEllipseEditor.START_ANGLE_PART_ID,\n                position: transform.mapPoint(new IFPoint(Math.cos(startA), Math.sin(startA)))},\n            {id: IFEllipseEditor.END_ANGLE_PART_ID,\n                position: transform.mapPoint(new IFPoint(Math.cos(endA), Math.sin(endA)))}\n        ];\n\n        for (var i = 0; i < itArgs.length; ++i) {\n            if (iterator(itArgs[i]) === true) {\n                break;\n            }\n        }\n    };\n\n    /** @override */\n    IFEllipseEditor.prototype.toString = function () {\n        return \"[Object IFEllipseEditor]\";\n    };\n\n    _.IFEllipseEditor = IFEllipseEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/imageeditor.js",
    "content": "(function (_) {\n    /**\n     * A base editor for an image\n     * @param {IFImage} image the image this editor works on\n     * @class IFImageEditor\n     * @extends IFShapeEditor\n     * @constructor\n     */\n    function IFImageEditor(image) {\n        IFShapeEditor.call(this, image);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFImageEditor, IFShapeEditor);\n    IFElementEditor.exports(IFImageEditor, IFImage);\n\n    /** @override */\n    IFImageEditor.prototype.initialSetup = function () {\n        // Add an empty style to images by default\n        this.getElement().getStyleSet().appendChild(new IFInlineStyle());\n    };\n\n    /** @override */\n    IFImageEditor.prototype.toString = function () {\n        return \"[Object IFImageEditor]\";\n    };\n\n    _.IFImageEditor = IFImageEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/pathbaseeditor.js",
    "content": "(function (_) {\n    /**\n     * A base editor for a base path\n     * @param {IFPathBase} path the path this editor works on\n     * @class IFPathBaseEditor\n     * @extends IFShapeEditor\n     * @constructor\n     */\n    function IFPathBaseEditor(path) {\n        IFShapeEditor.call(this, path);\n    };\n    IFObject.inherit(IFPathBaseEditor, IFShapeEditor);\n\n    /** @override */\n    IFPathBaseEditor.prototype.toString = function () {\n        return \"[Object IFPathBaseEditor]\";\n    };\n\n    _.IFPathBaseEditor = IFPathBaseEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/patheditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a path\n     * @param {IFPath} path the path this editor works on\n     * @class IFPathEditor\n     * @extends IFPathBaseEditor\n     * @constructor\n     */\n    function IFPathEditor(path) {\n        IFPathBaseEditor.call(this, path);\n\n        // Add all selected anchor points into our part selection if there're any\n        var selectedAnchorPoints = path.getAnchorPoints().queryAll(':selected');\n        for (var i = 0; i < selectedAnchorPoints.length; ++i) {\n            if (!this._partSelection) {\n                this._partSelection = [];\n            }\n            this._partSelection.push({type: IFPathEditor.PartType.Point, point: selectedAnchorPoints[i]});\n        }\n    };\n    IFObject.inherit(IFPathEditor, IFPathBaseEditor);\n    IFElementEditor.exports(IFPathEditor, IFPath);\n\n    /**\n     * Type of path an editor part\n     * @enum\n     */\n    IFPathEditor.PartType = {\n        Segment: 1,\n        Point: 2,\n        LeftHandle: 3,\n        RightHandle: 4,\n        LeftShoulder: 5,\n        RightShoulder: 6\n    };\n\n    /**\n     * Type of additional data of segment part\n     * @enum\n     */\n    IFPathEditor.SegmentData = {\n        HitRes: 1,\n        Handles: 2\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFPathEditor Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * Mapping of source point indices (key) to preview point indices (value)\n     * @type {*}\n     * @private\n     */\n    IFPathEditor.prototype._sourceIndexToPreviewIndex = null;\n\n    /**\n     * Indicates if path extension is expected to be continued by path tools\n     * @type {Boolean}\n     * @private\n     */\n    IFPathEditor.prototype._activeExtedingMode = false;\n\n    /**\n     * Returns if path editor is in path actively axtending mode\n     * @returns {Boolean}\n     */\n    IFPathEditor.prototype.isActiveExtendingMode = function () {\n        return this._activeExtedingMode;\n    };\n\n    /**\n     * Sets the value of _activeExtedingMode flag\n     * @param {Boolean} activeFlag - value to set\n     */\n    IFPathEditor.prototype.setActiveExtendingMode = function (activeFlag) {\n        this._activeExtedingMode = activeFlag;\n    };\n\n    /** @override */\n    IFPathEditor.prototype.getBBox = function (transform) {\n        var bbox = IFPathBaseEditor.prototype.getBBox.call(this, transform);\n        if (this._showAnnotations()) {\n\n            // Pre-multiply internal transformation if any\n            // (though it should not be set for path)\n            if (this._transform) {\n                transform = this._transform.multiplied(transform);\n            }\n\n            var _addToBBox = function (other) {\n                if (other && !other.isEmpty()) {\n                    bbox = bbox ? bbox.united(other) : other;\n                }\n            };\n\n            this._iteratePoints(true, function (args) {\n                // Handles\n                if (args.leftHandlePosition) {\n                    _addToBBox(this._getAnnotationBBox(transform, args.leftHandlePosition, true));\n                }\n                if (args.rightHandlePosition) {\n                    _addToBBox(this._getAnnotationBBox(transform, args.rightHandlePosition, true));\n                }\n\n                // Shoulders\n                if (args.leftShoulderPosition) {\n                    _addToBBox(this._getAnnotationBBox(transform, args.leftShoulderPosition, true));\n                }\n                if (args.rightShoulderPosition) {\n                    _addToBBox(this._getAnnotationBBox(transform, args.rightShoulderPosition, true));\n                }\n\n                // Point\n                _addToBBox(this._getAnnotationBBox(transform, args.position, true));\n            }.bind(this));\n\n            return bbox;\n        } else {\n            return bbox;\n        }\n    };\n\n\n    /** @override */\n    IFPathEditor.prototype.movePart = function (partId, partData, position, viewToWorldTransform, guides, shift, option) {\n        this.requestInvalidation();\n        this._createPathPreviewIfNecessary(partId.point);\n\n        switch (partId.type) {\n            case IFPathEditor.PartType.LeftHandle:\n                this._movePreviewPointCoordinates(partId.point, 'hlx', 'hly', position, viewToWorldTransform, shift, guides);\n                break;\n            case IFPathEditor.PartType.RightHandle:\n                this._movePreviewPointCoordinates(partId.point, 'hrx', 'hry', position, viewToWorldTransform, shift, guides);\n                break;\n            case IFPathEditor.PartType.LeftShoulder:\n            case IFPathEditor.PartType.RightShoulder:\n                var newPos = viewToWorldTransform.mapPoint(position);\n                this._movePreviewPointShoulders(partId, newPos, shift);\n                break;\n        }\n\n        this.requestInvalidation();\n    };\n\n    /** @override */\n    IFPathEditor.prototype.resetPartMove = function (partId, partData) {\n        this.releasePathPreview();\n        this.requestInvalidation();\n    };\n\n    /** @override */\n    IFPathEditor.prototype.applyPartMove = function (partId, partData) {\n        switch (partId.type) {\n            case IFPathEditor.PartType.LeftHandle:\n                this._assignPreviewPointPropertiesToSourcePoint(partId.point, ['hlx', 'hly', 'ah']);\n                break;\n            case IFPathEditor.PartType.RightHandle:\n                this._assignPreviewPointPropertiesToSourcePoint(partId.point, ['hrx', 'hry', 'ah']);\n                break;\n            case IFPathEditor.PartType.LeftShoulder:\n            case IFPathEditor.PartType.RightShoulder:\n                this._assignPreviewPointPropertiesToSourcePoint(partId.point, ['cl', 'cr']);\n                break;\n        }\n        this.resetPartMove(partId, partData);\n    };\n\n    /** @override */\n    IFPathEditor.prototype.transform = function (transform, partId, partData) {\n        if (this._partSelection && this._partSelection.length > 0) {\n            this.requestInvalidation();\n            this._createPathPreviewIfNecessary();\n\n            // If current partId is a segment, move segment and other selected points\n            // like freehand does, otherwise move all selected points\n            // including the ones from segments\n\n            // Iterate selection and transform all anchor points\n            for (var i = 0; i < this._partSelection.length; ++i) {\n                var selectedPartId = this._partSelection[i];\n\n                if (selectedPartId.type === IFPathEditor.PartType.Point) {\n                    var selectedPoint = selectedPartId.point;\n                    this._transformPreviewPointCoordinates(selectedPoint, 'x', 'y', transform);\n\n                    // Make sure to transform handles as well if not auto-handles are set\n                    if (!selectedPoint.getProperty('ah')) {\n                        if (selectedPoint.getProperty('hlx') != null && selectedPoint.getProperty('hly') != null) {\n                            this._transformPreviewPointCoordinates(selectedPoint, 'hlx', 'hly', transform);\n                        }\n                        if (selectedPoint.getProperty('hrx') != null && selectedPoint.getProperty('hry') != null) {\n                            this._transformPreviewPointCoordinates(selectedPoint, 'hrx', 'hry', transform);\n                        }\n                    }\n                } else if (selectedPartId.type === IFPathEditor.PartType.Segment && partId &&\n                    this._partIdAreEqual(selectedPartId, partId) &&\n                    partData.type == IFPathEditor.SegmentData.Handles) {\n\n                    var apLeftPreview = this.getPathPointPreview(selectedPartId.apLeft);\n                    var apRightPreview = this.getPathPointPreview(selectedPartId.apRight);\n                    var dPt = transform.getTranslation();\n                    var apL = new IFPoint(apLeftPreview.getProperty('x'), apLeftPreview.getProperty('y'));\n                    var apR = new IFPoint(apRightPreview.getProperty('x'), apRightPreview.getProperty('y'));\n\n                    if (!partData.fixedHDirLpt && !partData.fixedHDirRpt) {\n                        // TODO: honor internal path transform here\n                        var newTransform = transform.translated(\n                            -dPt.getX() + dPt.getX() * partData.cL, -dPt.getY() + dPt.getY() * partData.cL);\n\n                        this._transformPreviewPointCoordinates(\n                            selectedPartId.apLeft, 'hrx', 'hry', newTransform, partData.apLhr);\n\n                        var newTransform = transform.translated(\n                            -dPt.getX() + dPt.getX() * partData.cR, -dPt.getY() + dPt.getY() * partData.cR);\n\n                        this._transformPreviewPointCoordinates(\n                            selectedPartId.apRight, 'hlx', 'hly', newTransform, partData.apRhl);\n                    } else if (partData.fixedHDirLpt && partData.fixedHDirRpt) {\n                        var dx = dPt.getX();\n                        var dy = dPt.getY();\n\n                        var prPt = ifMath.getVectorProjection(apL.getX(), apL.getY(),\n                            partData.apLhr.getX(), partData.apLhr.getY(), apL.getX() + dx, apL.getY() + dy);\n\n                        var prDPt = prPt.subtract(apL);\n                        var newTransform = transform.translated(-dPt.getX() + prDPt.getX() * partData.cL,\n                            -dPt.getY() + prDPt.getY() * partData.cL);\n\n                        this._transformPreviewPointCoordinates(\n                            selectedPartId.apLeft, 'hrx', 'hry', newTransform, partData.apLhr);\n\n                        var prPt = ifMath.getVectorProjection(apR.getX(), apR.getY(),\n                            partData.apRhl.getX(), partData.apRhl.getY(), apR.getX() + dx, apR.getY() + dy);\n\n                        var prDPt = prPt.subtract(apR);\n                        var newTransform = transform.translated(-dPt.getX() + prDPt.getX() * partData.cR,\n                            -dPt.getY() + prDPt.getY() * partData.cR);\n\n                        this._transformPreviewPointCoordinates(\n                            selectedPartId.apRight, 'hlx', 'hly', newTransform, partData.apRhl);\n                    } else {\n                        // For one new handle and one existed:\n                        //      Exact policy of FreeHand looks to be buggy and is not defined, lets try this:\n                        // 1. Convert second-order Bezier curve into third-order Bezier curve so that zero\n                        //      zero movement don't change the curve :\n                        //      CP0 = QP0, CP1 = QP0 + 2/3*(QP1 - QP0), CP2 = QP2 - 2/3*(QP1 - QP2), CP3 = QP2\n                        // 2. Make the projection of movement into existing handle with the coefficient 1 / (a1 + a2)\n                        //       to the pre-existing handle (let's consider CP1)\n                        //       for curve CP = (1-t)^3*CP0 + 3*(1-t)^2*t*CP1 + 3*(1-t)*t^2*CP2 + t^3*CP3 =\n                        //       = a0*CP0 + a1*CP1 + a2*CP2 + a3*CP3\n                        //       CP1' = CP1 + 1/(a1+a2)*pr_CP1(dx, dy)\n                        // 3. Then the second handle should go into:\n                        //       CP2' = CP2 +\n                        //  + (1/a2 * dx - a1/(a2*(a1 + a2)) * pr_CP1x, 1/a2 * dy - a1/(a2*(a1 + a2)) * pr_CP1y)\n\n                        // Setting the described way CP1' and CP2' will make what is needed: CP' = CP + (dx, dy)\n\n                        var dx = dPt.getX();\n                        var dy = dPt.getY();\n                        var tmpC = 1 / (partData.cL + partData.cR);\n\n                        if (partData.fixedHDirLpt && !partData.fixedHDirRpt) {\n                            var prPt = ifMath.getVectorProjection(apL.getX(), apL.getY(),\n                                partData.apLhr.getX(), partData.apLhr.getY(),\n                                apL.getX() + dx, apL.getY() + dy);\n                            var prDPt = prPt.subtract(apL);\n\n                            var dh1x = tmpC * prDPt.getX();\n                            var dh1y = tmpC * prDPt.getY();\n                            var dh2x = dx / partData.cR - partData.cL / partData.cR * dh1x;\n                            var dh2y = dy / partData.cR - partData.cL / partData.cR * dh1y;\n                        } else { // !partData.fixedHDirLpt && partData.fixedHDirRpt\n                            var prPt = ifMath.getVectorProjection(apR.getX(), apR.getY(),\n                                partData.apRhl.getX(), partData.apRhl.getY(),\n                                apR.getX() + dx, apR.getY() + dy);\n                            var prDPt = prPt.subtract(apR);\n                            var dh2x = tmpC * prDPt.getX();\n                            var dh2y = tmpC * prDPt.getY();\n                            var dh1x = dx / partData.cL - partData.cR / partData.cL * dh2x;\n                            var dh1y = dy / partData.cL - partData.cR / partData.cL * dh2y;\n                        }\n                        var newTransform = transform.translated(-dPt.getX() + dh1x, -dPt.getY() + dh1y);\n\n                        this._transformPreviewPointCoordinates(\n                            selectedPartId.apLeft, 'hrx', 'hry', newTransform, partData.apLhr);\n\n                        var newTransform = transform.translated(-dPt.getX() + dh2x, -dPt.getY() + dh2y);\n\n                        this._transformPreviewPointCoordinates(\n                            selectedPartId.apRight, 'hlx', 'hly', newTransform, partData.apRhl);\n                    }\n                }\n            }\n\n            this.requestInvalidation();\n        } else {\n            IFPathBaseEditor.prototype.transform.call(this, transform, partId, partData);\n        }\n    };\n\n    /** @override */\n    IFPathEditor.prototype.resetTransform = function () {\n        this.releasePathPreview();\n        IFPathBaseEditor.prototype.resetTransform.call(this);\n    };\n\n    /** @override */\n    IFPathEditor.prototype.canApplyTransform = function () {\n        return this._partSelection && this._partSelection.length > 0 ||\n            this._transform && !this._transform.isIdentity();\n    };\n\n    /** @override */\n    IFPathEditor.prototype.applyTransform = function (element) {\n        if (this._partSelection && this._partSelection.length > 0) {\n            this._element._beginBlockEvents([IFElement.GeometryChangeEvent]);\n            var newSelection = [];\n            // Iterate selection and apply changes in preview anchor points\n            for (var i = 0; i < this._partSelection.length; ++i) {\n                var part = this._partSelection[i];\n                if (part.type === IFPathEditor.PartType.Point) {\n                    if (i == this._partSelection.length - 1) {\n                        this._element._endBlockEvents([IFElement.GeometryChangeEvent]);\n                    }\n                    this._transferPreviewProperties(part.point, element);\n                    newSelection.push(part);\n                } else if (part.type === IFPathEditor.PartType.Segment) {\n                    this._transferPreviewProperties(part.apLeft, element);\n                    if (i == this._partSelection.length - 1) {\n                        this._element._endBlockEvents([IFElement.GeometryChangeEvent]);\n                    }\n                    this._transferPreviewProperties(part.apRight, element);\n                    // Update now _partSelection to contain segment end points instead of segment itself\n                    newSelection.push({type: IFPathEditor.PartType.Point, point: part.apLeft});\n                    newSelection.push({type: IFPathEditor.PartType.Point, point: part.apRight});\n                }\n            }\n            this.requestInvalidation();\n            this.resetTransform();\n            this.updatePartSelection(false, newSelection);\n        } else {\n            IFPathBaseEditor.prototype.applyTransform.call(this, element);\n        }\n    };\n\n    /** @override */\n    IFPathEditor.prototype.subSelectDragStartAction = function (partInfo) {\n        if (partInfo.editor !== this) {\n            return null;\n        }\n\n        // When Path point is started to be moved with subselect, the options are:\n        // 1. If a point has styled corner type:\n        // a) User drags and cu is true -> both handles moved to the _same_ value\n        // b) User drags and cu is false -> move only the selected corner/shoulder length\n        // c) User drags and cu is false but user holds shift -> move both corner / shoulder lengths but NOT to\n        // the same value but instead, add delta value to both from original movement so their unit length stays the same.\n        // 2. Otherwise:\n        // a) if a point was not selected - it gets selected and drag it\n        // b) if a point was selected and didn't have right handle - create right handle\n        // c) if a point was selected and had the right handle, but not the left handle - create the left handle\n        // d) if a point was selected and had both handles - drag the point together with other selected points\n\n        var newPartInfo = partInfo;\n        if (!partInfo.isolated && partInfo.id.type == IFPathEditor.PartType.Point) {\n            var aPt = partInfo.id.point;\n            var idType = IFPathEditor.PartType.Point;\n            var aPtType = aPt.getProperty('tp');\n\n            if (IFPathBase.isCornerType(aPtType) &&\n                    this._element.getAnchorPoints().getPreviousPoint(aPt) != null &&\n                    this._element.getAnchorPoints().getNextPoint(aPt) != null) {\n\n                var cl = aPt.getProperty('cl');\n                var cr = aPt.getProperty('cr');\n\n                var pickDist = this._element.getScene().getProperty('pickDist');\n                if (cr == null || cr < pickDist * 2) {\n                    idType = IFPathEditor.PartType.RightShoulder;\n                } else if (cl == null || cl < pickDist * 2) {\n                    idType = IFPathEditor.PartType.LeftShoulder;\n                }\n            }\n\n            if (idType != IFPathEditor.PartType.Point) {\n                cl = cl != null ? cl : pickDist;\n                cr = cr != null ? cr : pickDist;\n                this.requestInvalidation();\n                this._createPathPreviewIfNecessary(aPt);\n                var previewPoint = this.getPathPointPreview(aPt);\n                if (!previewPoint) {   // might be some error\n                    newPartInfo = null;\n                } else {\n                    previewPoint.setProperties(['cl', 'cr'], [cl, cr]);\n\n                    var isolated = true; // all is isolated except points\n                    var selectable = false; // only point is selectable\n                    newPartInfo = new IFElementEditor.PartInfo(\n                        this, {type: idType, point: aPt}, null, isolated, selectable);\n                }\n            } else {\n                var hlx = aPt.getProperty('hlx');\n                var hly = aPt.getProperty('hly');\n                var hrx = aPt.getProperty('hrx');\n                var hry = aPt.getProperty('hry');\n                // check option a)\n                if (!partInfo.data.apSelected || !aPt.hasFlag(IFNode.Flag.Selected)) {\n                    // anchor point should be already selected, but it was not so at the moment of getting the part info\n\n                    if (!aPt.hasFlag(IFNode.Flag.Selected)) { // might be some error, select a point\n                        this.selectOnePoint(aPt);\n                    }\n                    newPartInfo = new IFElementEditor.PartInfo(\n                        this, {type: IFPathEditor.PartType.Point, point: aPt}, {apSelected: true}, isolated, selectable);\n                } else if (hlx === null || hly === null || hrx === null || hry === null) { // option b) or c)\n                    this.requestInvalidation();\n                    this._createPathPreviewIfNecessary(aPt);\n                    var previewPoint = this.getPathPointPreview(aPt);\n                    if (!previewPoint) {   // might be some error\n                        newPartInfo = null;\n                    } else {\n                        var partType = null;\n                        var isolated = true; // all is isolated except points\n                        var selectable = false; // only point is selectable\n\n                        if (hrx === null || hry === null) {\n                            // option b)\n                            partType = IFPathEditor.PartType.RightHandle;\n                            previewPoint.setProperties(\n                                ['ah', 'hrx', 'hry'], [false, aPt.getProperty('x'), aPt.getProperty('y')]);\n                        } else { // hlx === null || hly === null\n                            // option c)\n                            partType = IFPathEditor.PartType.LeftHandle;\n                            previewPoint.setProperties(\n                                ['ah', 'hlx', 'hly'], [false, aPt.getProperty('x'), aPt.getProperty('y')]);\n                        }\n\n                        newPartInfo = new IFElementEditor.PartInfo(\n                            this, {type: partType, point: aPt}, {apSelected: true}, isolated, selectable);\n\n                        this.updatePartSelection(true, [newPartInfo.id]);\n                    }\n                } // else option d) - NOOP\n            }\n        } else if (partInfo.id.type == IFPathEditor.PartType.Segment) {\n            var pathHitResult = partInfo.data.hitRes;\n            var apLeft = partInfo.id.apLeft;\n            var apRight = partInfo.id.apRight;\n            if (apLeft && apRight) {\n                this.requestInvalidation();\n                this._createPathPreviewIfNecessary();\n                var apLeftPreview = this.getPathPointPreview(apLeft);\n                var apRightPreview = this.getPathPointPreview(apRight);\n                if (!apLeftPreview || !apRightPreview) {   // might be some error\n                    newPartInfo = null;\n                } else {\n                    var apLeftX = apLeft.getProperty('x');\n                    var apLeftY = apLeft.getProperty('y');\n                    var apRightX = apRight.getProperty('x');\n                    var apRightY = apRight.getProperty('y');\n\n                    if ((apLeft.getProperty('hrx') === null || apLeft.getProperty('hry') === null) &&\n                        (apRight.getProperty('hlx') === null || apRight.getProperty('hly') === null)) {\n\n                        // When Path segment is drag with SubSelect Tool:\n                        // If handles are newly created:\n                        //      both handles should have the overall length 2/3 from segment length\n                        //      a mouse point should divide the distance between handle points in the same proportion as between segment ends\n                        //      after movement starts handle end points move synchronously\n                        //      after movement starts mouse position defines a point through which should go curve tangent line,\n                        // which oriented the same as original segment\n                        // To get newly created handles:\n                        //      for catch point between handles y position: hdy = dy (mouse) * 4 / 3\n                        //      for catch point between handles x position: hdx = dx * 4 / 3\n\n                        var handlesDx = (apRightX - apLeftX) / 3;\n                        var handlesDy = (apRightY - apLeftY) / 3;\n                        var leftHDx = handlesDx * pathHitResult.slope;\n                        var rightHDx = handlesDx - leftHDx;\n                        var leftHDy = handlesDy * pathHitResult.slope;\n                        var rightHDy = handlesDy - leftHDy;\n                        var hrx = pathHitResult.x - leftHDx;\n                        var hry = pathHitResult.y - leftHDy;\n\n                        apLeftPreview.setProperties(['ah', 'hrx', 'hry'],\n                            [false, pathHitResult.x - leftHDx, pathHitResult.y - leftHDy]);\n\n                        var hlx = pathHitResult.x + rightHDx;\n                        var hly = pathHitResult.y + rightHDy;\n                        apRightPreview.setProperties(['ah', 'hlx', 'hly'],\n                            [false, pathHitResult.x + rightHDx, pathHitResult.y + rightHDy]);\n                        this.requestInvalidation();\n\n                        newPartInfo = new IFElementEditor.PartInfo(\n                            this, {type: IFPathEditor.PartType.Segment, point: null, apLeft: apLeft, apRight: apRight},\n                            {type: IFPathEditor.SegmentData.Handles,\n                                cL: 4 / 3, apLhr: new IFPoint(hrx, hry), fixedHDirLpt: false,\n                                cR: 4 / 3, apRhl: new IFPoint(hlx, hly), fixedHDirRpt: false},\n                            null, false, true);\n\n                    } else if (apLeft.getProperty('hrx') === null || apLeft.getProperty('hry') === null) {\n                        // For one new handle and one existed:\n                        //      Exact policy of FreeHand looks to be buggy and is not defined, lets try this:\n                        // 1. Convert second-order Bezier curve into third-order Bezier curve so that zero\n                        //      zero movement don't change the curve :\n                        //      CP0 = QP0, CP1 = QP0 + 2/3*(QP1 - QP0), CP2 = QP2 + 2/3*(QP1 - QP2), CP3 = QP2\n                        // 2. Make the projection of movement into existing handle with the coefficient 1 / (a1 + a2)\n                        //       to the pre-existing handle (let's consider CP1)\n                        //       for curve CP = (1-t)^3*CP0 + 3*(1-t)^2*t*CP1 + 3*(1-t)*t^2*CP2 + t^3*CP3 =\n                        //       = a0*CP0 + a1*CP1 + a2*CP2 + a3*CP3\n                        //       CP1' = CP1 + 1/(a1+a2)*pr_CP1(dx, dy)\n                        // 3. Then the second handle should go into:\n                        //       CP2' = CP2 + (1/a2 * dx - a1/(a2*(a1 + a2)) * pr_CP1x, 1/a2 * dy - a1/(a2*(a1 + a2)) * pr_CP1y)\n                        // Setting the described way CP1' and CP2' will make what is needed: CP' = CP + (dx, dy)\n\n                        var hlx = apRightPreview.getProperty('hlx');\n                        var hly = apRightPreview.getProperty('hly');\n                        var hrx = apLeftX + 2 / 3 * (hlx - apLeftX);\n                        var hry = apLeftY + 2 / 3 * (hly - apLeftY);\n                        hlx = apRightX + 2 / 3 * (hlx - apRightX);\n                        hly = apRightY + 2 / 3 * (hly - apRightY);\n                        apLeftPreview.setProperties(['ah', 'hrx', 'hry'], [false, hrx, hry]);\n                        apRightPreview.setProperties(['ah', 'hlx', 'hly'], [false, hlx, hly]);\n                        this.requestInvalidation();\n\n                        newPartInfo = new IFElementEditor.PartInfo(\n                            this, {type: IFPathEditor.PartType.Segment, point: null, apLeft: apLeft, apRight: apRight},\n                            {type: IFPathEditor.SegmentData.Handles,\n                                cL: 3 * (1 - pathHitResult.slope) * (1 - pathHitResult.slope) * pathHitResult.slope,\n                                apLhr: new IFPoint(hrx, hry), fixedHDirLpt: false,\n                                cR: 3 * pathHitResult.slope * pathHitResult.slope * (1 - pathHitResult.slope),\n                                apRhl: new IFPoint(hlx, hly), fixedHDirRpt: true},\n                            false, true);\n                    } else if (apRight.getProperty('hlx') === null || apRight.getProperty('hly') === null) {\n                        var hrx = apLeftPreview.getProperty('hrx');\n                        var hry = apLeftPreview.getProperty('hry');\n                        var hlx = apRightX + 2 / 3 * (hrx - apRightX);\n                        var hly = apRightY + 2 / 3 * (hry - apRightY);\n                        hrx = apLeftX + 2 / 3 * (hrx - apLeftX);\n                        hry = apLeftY + 2 / 3 * (hry - apLeftY);\n                        apLeftPreview.setProperties(['ah', 'hrx', 'hry'], [false, hrx, hry]);\n                        apRightPreview.setProperties(['ah', 'hlx', 'hly'], [false, hlx, hly]);\n                        this.requestInvalidation();\n\n                        newPartInfo = new IFElementEditor.PartInfo(\n                            this, {type: IFPathEditor.PartType.Segment, point: null, apLeft: apLeft, apRight: apRight},\n                            {type: IFPathEditor.SegmentData.Handles,\n                                cL: 3 * (1 - pathHitResult.slope) * (1 - pathHitResult.slope) * pathHitResult.slope,\n                                apLhr: new IFPoint(hrx, hry), fixedHDirLpt: true,\n                                cR: 3 * pathHitResult.slope * pathHitResult.slope * (1 - pathHitResult.slope),\n                                apRhl: new IFPoint(hlx, hly), fixedHDirRpt: false},\n                            false, true);\n                    } else { // both handles exist\n                        // If both handles existed before, their orientation remains\n                        apLeftPreview.setProperty('ah', false);\n                        apRightPreview.setProperty('ah', false);\n                        this.requestInvalidation();\n                        var hrx = apLeftPreview.getProperty('hrx');\n                        var hry = apLeftPreview.getProperty('hry');\n                        var hlx = apRightPreview.getProperty('hlx');\n                        var hly = apRightPreview.getProperty('hly');\n\n                        newPartInfo = new IFElementEditor.PartInfo(\n                            this, {type: IFPathEditor.PartType.Segment, point: null, apLeft: apLeft, apRight: apRight},\n                            {type: IFPathEditor.SegmentData.Handles,\n                                cL: 3 * (1 - pathHitResult.slope),\n                                apLhr: new IFPoint(hrx, hry), fixedHDirLpt: true,\n                                cR: 3 * pathHitResult.slope,\n                                apRhl: new IFPoint(hlx, hly), fixedHDirRpt: true},\n                            false, true);\n                    }\n                }\n            } else {\n                newPartInfo = null;\n            }\n        }\n\n        return newPartInfo;\n    };\n\n    /** @override */\n    IFPathEditor.prototype._attach = function () {\n        var scene = this._element.getScene();\n        if (scene != null) {\n            scene.addEventListener(IFElement.GeometryChangeEvent, this._geometryChange, this);\n        }\n    };\n\n    /** @override */\n    IFPathEditor.prototype._detach = function () {\n        // Ensure to de-select all selected anchor points when detaching\n        for (var anchorPoint = this._element.getAnchorPoints().getFirstChild(); anchorPoint != null; anchorPoint = anchorPoint.getNext()) {\n            anchorPoint.removeFlag(IFNode.Flag.Selected);\n        }\n\n        var scene = this._element.getScene();\n        if (scene != null) {\n            scene.removeEventListener(IFElement.GeometryChangeEvent, this._geometryChange);\n        }\n\n        IFPathBaseEditor.prototype._detach.call(this);\n    };\n\n    /**\n     * Hit-test anchor point's annotation\n     * @param {IFPathBase.AnchorPoint} anchorPt - anchor point to hit-test\n     * @param {IFPoint} location\n     * @param {IFTransform} [transform] a transformation to apply to anchor point's coordinates before hit-testing,\n     * defaults to null\n     * @param {Number} [tolerance] optional tolerance for hit testing, defaults to zero\n     * @returns {boolean} the result of hit-test\n     */\n    IFPathEditor.prototype.hitAnchorPoint = function (anchorPt, location, transform, tolerance) {\n        if (anchorPt) {\n            var transformToApply = this._element.getTransform();\n            if (transform) {\n                transformToApply = transformToApply ? transformToApply.multiplied(transform) : transform;\n            }\n\n            return this._getAnnotationBBox(\n                    transformToApply, new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y')), true)\n                .expanded(tolerance, tolerance, tolerance, tolerance)\n                .containsPoint(location);\n        }\n        return false;\n    };\n\n    /**\n     * Calculates and returns IFPoint in scene coordinates, corresponding to the given anchor point\n     * @param {IFPathBase.AnchorPoint} anchorPt - the given anchor point\n     * @returns {IFPoint}\n     */\n    IFPathEditor.prototype.getPointCoord = function (anchorPt) {\n        var pt = null;\n\n        if (anchorPt.getPath() == this._element || this._elementPreview && anchorPt.getPath() == this._elementPreview) {\n            var element = this._element;\n            if (this._elementPreview && anchorPt.getPath() == this._elementPreview) {\n                element = this._elementPreview;\n            }\n            var xPos = anchorPt.getProperty('x');\n            var yPos = anchorPt.getProperty('y');\n            pt = new IFPoint(xPos, yPos);\n            var transform = element.getTransform();\n            if (transform) {\n                pt = transform.mapPoint(pt);\n            }\n        }\n\n        return pt;\n    };\n\n    /** @override */\n    IFPathEditor.prototype._getPartInfoAt = function (location, transform, tolerance) {\n        if (this._showAnnotations()) {\n            var _isInAnnotationBBox = function (position, smallAnnotation) {\n                if (position) {\n                    return this._getAnnotationBBox(transform, position, smallAnnotation)\n                        .expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location);\n                } else {\n                    return false;\n                }\n            }.bind(this);\n\n            var result = null;\n\n            this._iteratePoints(false, function (args) {\n                var partType = null;\n                var isolated = true; // all is isolated except points\n                var selectable = false; // only point is selectable\n\n                if (_isInAnnotationBBox(args.rightHandlePosition, true)) {\n                    partType = IFPathEditor.PartType.RightHandle;\n                } else if (_isInAnnotationBBox(args.leftHandlePosition, true)) {\n                    partType = IFPathEditor.PartType.LeftHandle;\n                } else if (_isInAnnotationBBox(args.rightShoulderPosition, true)) {\n                    partType = IFPathEditor.PartType.RightShoulder;\n                } else if (_isInAnnotationBBox(args.leftShoulderPosition, true)) {\n                    partType = IFPathEditor.PartType.LeftShoulder;\n                } else if (_isInAnnotationBBox(args.position, true)) {\n                    partType = IFPathEditor.PartType.Point;\n                    isolated = false;\n                    selectable = true;\n                }\n\n                if (partType) {\n                    result = new IFElementEditor.PartInfo(\n                        this, {type: partType, point: args.anchorPoint},\n                        {apSelected: args.anchorPoint.hasFlag(IFNode.Flag.Selected)}, isolated, selectable);\n                    return true;\n                }\n            }.bind(this));\n\n            if (result) {\n                return result;\n            } else if (this.hasFlag(IFElementEditor.Flag.Detail)) {\n                // In detail mode we're able to select segments so hit test for one here\n                var pathHitResult = this._element.pathHitTest(location, transform, false, this._element.getScene().getProperty('pickDist'));\n                if (pathHitResult) {\n                    var hitRes = pathHitResult.data;\n                    var apLeft = this._element.getAnchorPoints().getChildByIndex(hitRes.segment - 1);\n                    var apRight = apLeft ? this._element.getAnchorPoints().getNextPoint(apLeft) : null;\n                    return new IFElementEditor.PartInfo(\n                        this, {type: IFPathEditor.PartType.Segment, point: null, apLeft: apLeft, apRight: apRight},\n                        {type: IFPathEditor.SegmentData.HitRes, hitRes: pathHitResult.data}, false, true);\n                }\n                return null;\n            }\n        }\n\n        return null;\n    };\n\n    /** @override */\n    IFPathEditor.prototype._postPaint = function (transform, context) {\n        IFPathBaseEditor.prototype._postPaint.call(this, transform, context);\n        if (this._showAnnotations()) {\n            this._iteratePoints(true, function (args) {\n                // Paint handle(s)\n                if (args.leftHandlePosition) {\n                    this._paintHandle(transform, context, args.position, args.leftHandlePosition);\n                }\n                if (args.rightHandlePosition) {\n                    this._paintHandle(transform, context, args.position, args.rightHandlePosition);\n                }\n\n                // Paint shoulders\n                if (args.leftShoulderPosition) {\n                    this._paintAnnotation(context, transform, args.leftShoulderPosition, IFElementEditor.Annotation.Diamond, false, true);\n                }\n                if (args.rightShoulderPosition) {\n                    this._paintAnnotation(context, transform, args.rightShoulderPosition, IFElementEditor.Annotation.Diamond, false, true);\n                }\n\n                // Paint point annotation\n                this._paintAnnotation(context, transform, args.position, args.annotation, args.anchorPoint.hasFlag(IFNode.Flag.Selected), true);\n            }.bind(this));\n        }\n    };\n\n    /** @override */\n    IFPathEditor.prototype._partIdAreEqual = function (a, b) {\n        var eqs = (a.type === b.type);\n        if (eqs && a.type == IFPathEditor.PartType.Point) {\n            eqs = (a.point === b.point);\n        } else if (eqs && a.type == IFPathEditor.PartType.Segment) {\n            eqs = (a.apLeft === b.apLeft && a.apRight == b.apRight);\n        }\n        return eqs;\n    };\n\n    /** @override */\n    IFPathEditor.prototype._updatePartSelection = function (selection) {\n        this.requestInvalidation();\n\n        var newSelection = this._filterSelection(selection);\n\n        // Iterate existing selection if any and deselect all anchor points\n        // that are no longer in the new selection\n        if (this._partSelection) {\n            for (var i = 0; i < this._partSelection.length; ++i) {\n                var part = this._partSelection[i];\n                var isInNewSelection = false;\n\n                if (newSelection) {\n                    for (var k = 0; k < newSelection.length; ++k) {\n                        if (newSelection[k].point === part.point && part.point ||\n                            part.type == IFPathEditor.PartType.Segment && part.type == newSelection[k].type &&\n                                part.apLeft == newSelection[k].apLeft && part.apRight == newSelection[k].apRight) {\n                            isInNewSelection = true;\n                            break;\n                        }\n                    }\n                }\n\n                if (!isInNewSelection) {\n                    if (part.point) {\n                        part.point.removeFlag(IFNode.Flag.Selected);\n                    } else if (part.type == IFPathEditor.PartType.Segment) {\n                        part.apLeft.removeFlag(IFNode.Flag.Selected);\n                        part.apRight.removeFlag(IFNode.Flag.Selected);\n                    }\n                }\n            }\n        }\n\n        // Iterate new selection if any and select all anchor points\n        if (newSelection) {\n            for (var i = 0; i < newSelection.length; ++i) {\n                var part = newSelection[i];\n                if (part.point) {\n                    part.point.setFlag(IFNode.Flag.Selected);\n                } else if (part.type == IFPathEditor.PartType.Segment) {\n                    part.apLeft.setFlag(IFNode.Flag.Selected);\n                    part.apRight.setFlag(IFNode.Flag.Selected);\n                }\n            }\n        }\n\n        this._partSelection = newSelection;\n        this.requestInvalidation();\n    };\n\n    /**\n     * Paint a handle\n     * @param {IFTransform} transform\n     * @param {IFPaintContext} context\n     * @param {IFPoint} from\n     * @param {IFPoint} to\n     * @private\n     */\n    IFPathEditor.prototype._paintHandle = function (transform, context, from, to) {\n        var lineFrom = from;\n        var lineTo = to;\n        if (transform) {\n            lineFrom = transform.mapPoint(from);\n            lineTo = transform.mapPoint(to);\n        }\n        context.canvas.strokeLine(lineFrom.getX(), lineFrom.getY(), lineTo.getX(), lineTo.getY(), 1, context.selectionOutlineColor);\n        this._paintAnnotation(context, transform, to, IFElementEditor.Annotation.Circle, false, true);\n    };\n\n    /**\n     * Iterate all point annotations\n     * @param {Boolean} paintElement whether to take the paint element for iteration\n     * or not (which will then take the source element}\n     * @param {Function(args: {{type: IFPathBase.AnchorPoint.Type|IFPathBase.CornerType, anchorPoint: IFPathBase.AnchorPoint,\n     * position: IFPoint, annotation: IFElementEditor.Annotation, leftHandlePosition: IFPoint, rightHandlePosition: IFPoint,\n     * leftShoulderPosition: IFPoint, rightShoulderPosition: IFPoint)}})} iterator may return true for stopping iteration\n     * @private\n     */\n    IFPathEditor.prototype._iteratePoints = function (paintElement, iterator) {\n        var element = paintElement ? this.getPaintElement() : this._element;\n        var anchorPoints = element.getAnchorPoints();\n        var transform = element.getTransform();\n\n        for (var anchorPoint = anchorPoints.getFirstChild(); anchorPoint != null; anchorPoint = anchorPoint.getNext()) {\n            var previousPt = anchorPoints.getPreviousPoint(anchorPoint);\n            var nextPt = anchorPoints.getNextPoint(anchorPoint);\n            var type = anchorPoint.getProperty('tp');\n            var position = new IFPoint(anchorPoint.getProperty('x'), anchorPoint.getProperty('y'));\n\n            var itArgs = {\n                type: type,\n                anchorPoint: anchorPoint,\n                position: position,\n                annotation: IFElementEditor.Annotation.Rectangle,\n                leftHandlePosition: null,\n                rightHandlePosition: null,\n                leftShoulderPosition: null,\n                rightShoulderPosition: null\n            };\n\n            if (anchorPoint.hasFlag(IFNode.Flag.Selected)) {\n                if (type === IFPathBase.AnchorPoint.Type.Connector) {\n                    itArgs.annotation = IFElementEditor.Annotation.Diamond;\n                } else if (type === IFPathBase.AnchorPoint.Type.Symmetric || type === IFPathBase.AnchorPoint.Type.Mirror) {\n                    itArgs.annotation = IFElementEditor.Annotation.Circle;\n                }\n            }\n\n            if (anchorPoint.hasFlag(IFNode.Flag.Selected) || (previousPt && previousPt.hasFlag(IFNode.Flag.Selected))) {\n                var pt = new IFPoint(anchorPoint.getProperty('hlx'), anchorPoint.getProperty('hly'));\n                if (pt.getX() !== null && pt.getY() !== null) {\n                    itArgs.leftHandlePosition = pt;\n                }\n            }\n\n            if (anchorPoint.hasFlag(IFNode.Flag.Selected) || (nextPt && nextPt.hasFlag(IFNode.Flag.Selected))) {\n                var pt = new IFPoint(anchorPoint.getProperty('hrx'), anchorPoint.getProperty('hry'));\n                if (pt.getX() !== null && pt.getY() !== null) {\n                    itArgs.rightHandlePosition = pt;\n                }\n            }\n\n            if (anchorPoint.hasFlag(IFNode.Flag.Selected) &&\n                type !== IFPathBase.AnchorPoint.Type.Asymmetric &&\n                type !== IFPathBase.AnchorPoint.Type.Symmetric &&\n                type !== IFPathBase.AnchorPoint.Type.Mirror &&\n                type !== IFPathBase.AnchorPoint.Type.Connector) {\n\n                var cl = anchorPoint.getProperty('cl');\n                if (cl && previousPt) {\n                    var pt = anchorPoint.getLeftShoulderPoint(true);\n                    if (pt && pt.getX() !== null && pt.getY() !== null) {\n                        itArgs.leftShoulderPosition = pt;\n                    }\n                }\n\n                var cr = anchorPoint.getProperty('cr');\n                if (cr && nextPt) {\n                    var pt = anchorPoint.getRightShoulderPoint(true);\n                    if (pt && pt.getX() !== null && pt.getY() !== null) {\n                        itArgs.rightShoulderPosition = pt;\n                    }\n                }\n            }\n\n            if (transform) {\n                var newPosition = transform.mapPoint(itArgs.position);\n\n                if (itArgs.leftHandlePosition) {\n                    itArgs.leftHandlePosition = transform.mapPoint(itArgs.leftHandlePosition);\n                }\n\n                if (itArgs.rightHandlePosition) {\n                    itArgs.rightHandlePosition = transform.mapPoint(itArgs.rightHandlePosition);\n                }\n\n                // TODO: discuss\n                // We do not apply this transform to shoulders when generating vertices, so should not apply here\n                // directly, instead we should re-generate shoulders for modified anchor points,\n                // as when generating vertices.\n                // As the applied transform is an element's internal transform, which is the same for all points,\n                // let's use the following workaround here\n                if (itArgs.leftShoulderPosition) {\n                    itArgs.leftShoulderPosition =\n                        //transform.mapPoint(itArgs.leftShoulderPosition); // incorrect!\n                        //itArgs.leftShoulderPosition.subtract(itArgs.position).add(newPosition); // also incorrect!\n                        anchorPoint.getLeftShoulderPointTransformed(transform, true);\n                }\n\n                if (itArgs.rightShoulderPosition) {\n                    itArgs.rightShoulderPosition =\n                        //transform.mapPoint(itArgs.rightShoulderPosition);\n                        //itArgs.rightShoulderPosition.subtract(itArgs.position).add(newPosition);\n                        anchorPoint.getRightShoulderPointTransformed(transform, true);\n                }\n\n                itArgs.position = newPosition;\n            }\n\n            if (iterator(itArgs) === true) {\n                break;\n            }\n        }\n    };\n\n    /**\n     * Returns path preview\n     * @param {Boolean} full - indicates if full path preview is needed\n     * @param {IFPathBase.AnchorPoint} selectedAnchorPoint - the point for which preview is needed; may be null\n     * @returns {IFPath}\n     */\n    IFPathEditor.prototype.getPathPreview = function (full, selectedAnchorPoint) {\n        this.requestInvalidation();\n        if (full) {\n            this.extendPreviewToFull();\n        } else {\n            this._createPathPreviewIfNecessary(selectedAnchorPoint);\n        }\n        this.requestInvalidation();\n        return this._elementPreview;\n    };\n\n    /**\n     * Returns path reference\n     * @returns {IFPath}\n     */\n    IFPathEditor.prototype.getPath = function () {\n        return this._element;\n    };\n\n    /**\n     * Indicates how many points and which are selected\n     * @enum\n     */\n    IFPathEditor.PointsSelectionType = {\n        No: 'N',\n        First: 'F',\n        Last: 'L',\n        Middle: 'M',\n        Several: 'S'\n    };\n\n    /**\n     * Checks how many points and which are selected\n     * @returns {IFPathEditor.PointsSelectionType}\n     */\n    IFPathEditor.prototype.getPointsSelectionType = function () {\n        var selType = IFPathEditor.PointsSelectionType.No;\n        if (this._partSelection) {\n            if (this._partSelection.length > 1) {\n                selType = IFPathEditor.PointsSelectionType.Several;\n            } else if (this._partSelection[0].point.hasFlag(IFNode.Flag.Selected)) {\n                var pt = this._partSelection[0].point;\n                if (pt === this._element.getAnchorPoints().getLastChild()) {\n                    selType = IFPathEditor.PointsSelectionType.Last;\n                } else if (pt === this._element.getAnchorPoints().getFirstChild()) {\n                    selType = IFPathEditor.PointsSelectionType.First;\n                } else {\n                    selType = IFPathEditor.PointsSelectionType.Middle;\n                }\n            }\n        }\n\n        return selType;\n    };\n\n    /**\n     * Updates _partSelection with one selected point\n     * @param {IFPathBase.AnchorPoint} anchorPt - a point to select\n     */\n    IFPathEditor.prototype.selectOnePoint = function (anchorPt) {\n        this.updatePartSelection(false, [\n            {type: IFPathEditor.PartType.Point, point: anchorPt}\n        ]);\n    };\n\n    /**\n     * Changes indices of preview points to some value. Useful when new points are added into preview,\n     * when these points are not in main path yet\n     * @param {Number} shiftVal - preview indices shift value\n     * @param {Number} shiftFrom - update indices starting from shiftFrom source path index. May be null, then 0 is used\n     * @param {Number} shiftTo - update indices up to shiftTo source path index. May be null,\n     * then indices will be updated up to table end\n     */\n    IFPathEditor.prototype.shiftPreviewTable = function (shiftVal, shiftFrom, shiftTo) {\n        shiftFrom = shiftFrom != null ? shiftFrom : 0;\n        shiftTo = shiftTo != null ? shiftTo : this._sourceIndexToPreviewIndex.length - 1;\n        for (var i = shiftFrom; i < shiftTo; ++i) {\n            this._sourceIndexToPreviewIndex[i] += shiftVal;\n        }\n    };\n\n    /**\n     * Used to extend preview to full path, when partial preview is getting not enough in some cases\n     */\n    IFPathEditor.prototype.extendPreviewToFull = function () {\n        this._createPathPreviewIfNecessary();\n        var sourceAnchorPoints = this._element.getAnchorPoints();\n        var previewAnchorPoints = this._elementPreview.getAnchorPoints();\n        var firstPreviewPtOrig = previewAnchorPoints.getFirstChild();\n        var ap = sourceAnchorPoints.getFirstChild();\n        var idx = 0;\n        var hasPreview = (this._sourceIndexToPreviewIndex[idx] != null);\n        var previewIdx = hasPreview ? this._sourceIndexToPreviewIndex[idx] : 0;\n\n\n        previewAnchorPoints._beginBlockChanges([\n            IFNode._Change.BeforeChildInsert,\n            IFNode._Change.AfterChildInsert\n        ]);\n\n        try {\n            while (!hasPreview && ap) {\n                var previewAnchorPoint = new IFPathBase.AnchorPoint();\n                previewAnchorPoint.transferProperties(ap, [IFPathBase.AnchorPoint.GeometryProperties]);\n                if (ap.hasFlag(IFNode.Flag.Selected)) {\n                    previewAnchorPoint.setFlag(IFNode.Flag.Selected);\n                }\n\n                previewAnchorPoints.insertChild(previewAnchorPoint, firstPreviewPtOrig);\n                this._sourceIndexToPreviewIndex[idx] = previewIdx;\n                ap = ap.getNext();\n                ++idx;\n                ++previewIdx;\n                hasPreview = (this._sourceIndexToPreviewIndex[idx] != null);\n            }\n\n            var num = idx - 0;\n            while (hasPreview && ap) {\n                this._sourceIndexToPreviewIndex[idx] += num;\n                previewIdx = this._sourceIndexToPreviewIndex[idx];\n                ap = ap.getNext();\n                ++idx;\n                hasPreview = (this._sourceIndexToPreviewIndex[idx] != null);\n            }\n            ++previewIdx;\n\n            while (!hasPreview && ap) {\n                var previewAnchorPoint = new IFPathBase.AnchorPoint();\n                previewAnchorPoint.transferProperties(ap, [IFPathBase.AnchorPoint.GeometryProperties]);\n                if (ap.hasFlag(IFNode.Flag.Selected)) {\n                    previewAnchorPoint.setFlag(IFNode.Flag.Selected);\n                }\n\n                previewAnchorPoints.appendChild(previewAnchorPoint);\n                this._sourceIndexToPreviewIndex[idx] = previewIdx;\n                ap = ap.getNext();\n                ++idx;\n                ++previewIdx;\n                hasPreview = (this._sourceIndexToPreviewIndex[idx] != null);\n            }\n        } finally {\n            previewAnchorPoints._endBlockChanges([\n                IFNode._Change.BeforeChildInsert,\n                IFNode._Change.AfterChildInsert\n            ]);\n        }\n\n        // There may be one more hasPreview block, but it should not be updated in this case,\n        // as this is the beginning of preview\n        this._elementPreview.transferProperties(this._element, [IFShape.GeometryProperties, IFPath.GeometryProperties]);\n    };\n\n    /**\n     * Constrains position against base point with the step aliquot to 45% from scene constraint property\n     * @param {IFPoint} position - original position to be constrained in view coordinates\n     * @param {IFTransform} worldToViewTransform - current scene transformation\n     * @param sourcePoint - a base point\n     * @returns {IFPoint} - new constrained position\n     */\n    IFPathEditor.prototype.constrainPosition = function (position, worldToViewTransform, sourcePoint) {\n        var basePt = new IFPoint(sourcePoint.getProperty('x'), sourcePoint.getProperty('y'));\n        var transformToApply = this._element.getTransform();\n        transformToApply = transformToApply ? transformToApply.multiplied(worldToViewTransform) : worldToViewTransform;\n\n        basePt = transformToApply.mapPoint(basePt);\n        var constrPt = ifMath.convertToConstrain(\n            basePt.getX(), basePt.getY(), position.getX(), position.getY(),\n            this._element.getScene().getProperty('crConstraint'));\n\n        return constrPt;\n    };\n\n    /**\n     * Create path preview if not yet existent.\n     * @param {IFPathBase.AnchorPoint} [selectedAnchorPoint] if provided then this point\n     * will be taken as the only selected one, if this is not provided, the selected\n     * anchor points will be taken from the source path. Defaults to null if not provided.\n     * @return {IFPath} the path preview\n     * @private\n     */\n    IFPathEditor.prototype._createPathPreviewIfNecessary = function (selectedAnchorPoint) {\n        if (!this._elementPreview) {\n            this._sourceIndexToPreviewIndex = {};\n\n            this._elementPreview = new IFPath();\n            this._elementPreview.transferProperties(this._element, [IFShape.GeometryProperties, IFPath.GeometryProperties]);\n\n            var _anchorPointIsSelected = function (anchorPoint) {\n                return (selectedAnchorPoint && anchorPoint === selectedAnchorPoint) || (!selectedAnchorPoint && anchorPoint.hasFlag(IFNode.Flag.Selected));\n            };\n\n            var sourceAnchorPoints = this._element.getAnchorPoints();\n            var previewAnchorPoints = this._elementPreview.getAnchorPoints();\n\n            // Create our anchor points. We'll ensure to only create the piece of the path\n            // that includes selected anchor points so for most of the time we'll be working\n            // on an optimized path preview that doesn't require whole redrawing of the path\n            // TODO: make later on support for multiple pieces of the path as in FreeHand\n            var firstSelPoint = null;\n            var lastSelPoint = null;\n            var prevPt, nextPt;\n            var relPt;\n            for (var anchorPoint = sourceAnchorPoints.getFirstChild();\n                 anchorPoint != null && (!firstSelPoint || !lastSelPoint);\n                 anchorPoint = anchorPoint.getNext()) {\n\n                prevPt = sourceAnchorPoints.getPreviousPoint(anchorPoint);\n                nextPt = sourceAnchorPoints.getNextPoint(anchorPoint);\n\n                if (!firstSelPoint) {\n                    if (!prevPt && _anchorPointIsSelected(anchorPoint)) {\n                        firstSelPoint = anchorPoint;\n                    } else {\n                        if (!_anchorPointIsSelected(anchorPoint) && nextPt && _anchorPointIsSelected(nextPt)) {\n                            // relPt may be == anchorPoint or == prevPt depending on properties of these points\n                            relPt = sourceAnchorPoints.getFirstRelatedPoint(nextPt);\n                            if (!_anchorPointIsSelected(relPt) &&\n                                (!sourceAnchorPoints.getPreviousPoint(relPt) || !_anchorPointIsSelected(sourceAnchorPoints.getPreviousPoint(relPt)))) {\n                                firstSelPoint = relPt;\n                            }\n                        }\n                    }\n                }\n\n                if (!lastSelPoint) {\n                    if (!nextPt && _anchorPointIsSelected(anchorPoint)) {\n                        lastSelPoint = anchorPoint;\n                    } else {\n                        if (!_anchorPointIsSelected(anchorPoint) && prevPt && _anchorPointIsSelected(prevPt)) {\n                            // relPt may be == anchorPoint or == nextPt depending on properties of these points\n                            relPt = sourceAnchorPoints.getLastRelatedPoint(prevPt);\n                            if (!_anchorPointIsSelected(relPt) &&\n                                (!sourceAnchorPoints.getNextPoint(relPt) || !_anchorPointIsSelected(sourceAnchorPoints.getNextPoint(relPt)))) {\n\n                                lastSelPoint = relPt;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (firstSelPoint && !lastSelPoint ||\n                !firstSelPoint && lastSelPoint ||\n                firstSelPoint && lastSelPoint && firstSelPoint === lastSelPoint) {\n\n                firstSelPoint = null;\n                lastSelPoint = null;\n            }\n\n            // Ensure no selected points between lastSelPoint and firstSelPoint\n            if (firstSelPoint && lastSelPoint) {\n                var noSelected = true;\n                // we can start from lastSelPoint and continue until path end or firstSelPoint for both\n                // open and closed paths, as for open path there will be no selected points before the firstSelPoint\n                // due to the way how we calculated firstSelPoint\n                for (var anchorPoint = sourceAnchorPoints.getNextPoint(lastSelPoint);\n                     anchorPoint && anchorPoint != firstSelPoint && noSelected;\n                     anchorPoint = sourceAnchorPoints.getNextPoint(anchorPoint)) {\n                    if (_anchorPointIsSelected(anchorPoint)) {\n                        noSelected = false;\n                        firstSelPoint = null;\n                        lastSelPoint = null;\n                    }\n                }\n            }\n\n            // If there're no valid selection points then take the whole path instead\n            firstSelPoint = firstSelPoint ? firstSelPoint : sourceAnchorPoints.getFirstChild();\n            var finished = false;\n            var anchorPoint = firstSelPoint;\n\n            previewAnchorPoints._beginBlockChanges([\n                IFNode._Change.BeforeChildInsert,\n                IFNode._Change.AfterChildInsert\n            ]);\n            try {\n                while (!finished) {\n                    var previewAnchorPoint = new IFPathBase.AnchorPoint();\n                    previewAnchorPoint.transferProperties(anchorPoint, [IFPathBase.AnchorPoint.GeometryProperties]);\n                    if (_anchorPointIsSelected(anchorPoint)) {\n                        previewAnchorPoint.setFlag(IFNode.Flag.Selected);\n                    }\n\n                    previewAnchorPoints.appendChild(previewAnchorPoint);\n\n                    // Add index mappings\n                    var sourceIndex = sourceAnchorPoints.getIndexOfChild(anchorPoint);\n                    var previewIndex = previewAnchorPoints.getIndexOfChild(previewAnchorPoint);\n                    this._sourceIndexToPreviewIndex[sourceIndex] = previewIndex;\n\n                    if (anchorPoint == lastSelPoint) {\n                        finished = true;\n                    }\n                    anchorPoint = sourceAnchorPoints.getNextPoint(anchorPoint);\n                    if (!anchorPoint || anchorPoint == firstSelPoint) {\n                        finished = true;\n                    }\n                }\n            } finally {\n                previewAnchorPoints._endBlockChanges([\n                    IFNode._Change.BeforeChildInsert,\n                    IFNode._Change.AfterChildInsert\n                ]);\n            }\n\n            this._elementPreview.transferProperties(this._element, [IFShape.GeometryProperties, IFPath.GeometryProperties]);\n            if (firstSelPoint.getProperty('ah') || lastSelPoint && lastSelPoint.getProperty('ah')) {\n                this.extendPreviewToFull();\n            } else {\n                // Don't make the path closed if we've created a partial preview only\n                if (this._elementPreview.getProperty('closed') && lastSelPoint) {\n                    this._elementPreview.setProperty('closed', false);\n                }\n            }\n        }\n        return this._elementPreview;\n    };\n\n    /**\n     * Release a path preview if there was any\n     * @private\n     */\n    IFPathEditor.prototype.releasePathPreview = function () {\n        this._elementPreview = null;\n        this._sourceIndexToPreviewIndex = null;\n    };\n\n    /**\n     * Returns a mapping of a source point to it's preview point\n     * @param {IFPathBase.AnchorPoint} sourcePoint\n     */\n    IFPathEditor.prototype.getPathPointPreview = function (sourcePoint) {\n        var sourceIndex = sourcePoint.getParent().getIndexOfChild(sourcePoint);\n        if (!this._sourceIndexToPreviewIndex) {\n            this.extendPreviewToFull();\n        } else if (this._sourceIndexToPreviewIndex[sourceIndex] == null) {\n            this._createPathPreviewIfNecessary(sourcePoint);\n        }\n        this.requestInvalidation();\n        var previewIndex = this._sourceIndexToPreviewIndex[sourceIndex];\n        return this._elementPreview.getAnchorPoints().getChildByIndex(previewIndex);\n    };\n\n    /**\n     * Returns the combined transformation of the path internal transformation with the supplied\n     * @param {IFTransform}transform\n     * @returns {IFTransform}\n     */\n    IFPathEditor.prototype.getTransformFromNative = function (transform) {\n        var transformToNewPos = this._element.getTransform();\n        if (transform) {\n            transformToNewPos = transformToNewPos ? transformToNewPos.multiplied(transform) : transform;\n        }\n        if (!transformToNewPos) {\n            transformToNewPos = new IFTransform();\n        }\n        return transformToNewPos;\n    };\n\n    /**\n     * Moves single anchor point to a new position. The anchor point should not necessary have source point.\n     * This function may be used for both preview or original path points. If the original path has a transform,\n     * then it is used without any concern, if preview or original path point is moving.\n     * @param {IFPathBase.AnchorPoint} anchorPoint - an anchor point to move to new position\n     * @param {IFPoint} newPosition - new point's position\n     * @param {IFTransform} transform - transformation to be applied to path points to make their coordinate system\n     * the same in which new position is specified (usually worldToViewTransform)\n     * @param {IFPathBase.AnchorPoint} origPoint - if present, this anchor point is used as a source point instead of\n     * anchor point itself. Useful when dragging an existing point to not lose it's handles accuracy.\n     */\n    IFPathEditor.prototype.movePoint = function (anchorPoint, newPosition, transform, origPoint) {\n        var transformToNewPos = this.getTransformFromNative(transform);\n        var transformToNative = transformToNewPos.inverted();\n\n        var newNativePos = transformToNative.mapPoint(newPosition);\n\n        if (anchorPoint.getProperty('ah')) {\n            anchorPoint.setProperties(['x', 'y'], [newNativePos.getX(), newNativePos.getY()]);\n        } else {\n            var srcPt = origPoint ? origPoint : anchorPoint;\n            var hlx = srcPt.getProperty('hlx');\n            var hly = srcPt.getProperty('hly');\n            var hrx = srcPt.getProperty('hrx');\n            var hry = srcPt.getProperty('hry');\n            if (hlx != null && hly != null || hrx != null && hry != null) {\n                var origPos = transformToNewPos.mapPoint(\n                    new IFPoint(srcPt.getProperty('x'), srcPt.getProperty('y')));\n                var dx = newPosition.getX() - origPos.getX();\n                var dy = newPosition.getY() - origPos.getY();\n\n                if (hlx != null && hly != null) {\n                    var pt = transformToNative.mapPoint(\n                        transformToNewPos.mapPoint(new IFPoint(hlx, hly)).translated(dx, dy));\n                    hlx = pt.getX();\n                    hly = pt.getY();\n                }\n                if (hrx != null && hry != null) {\n                    var pt = transformToNative.mapPoint(\n                        transformToNewPos.mapPoint(new IFPoint(hrx, hry)).translated(dx, dy));\n                    hrx = pt.getX();\n                    hry = pt.getY();\n                }\n            }\n            anchorPoint.setProperties(['x', 'y', 'hlx', 'hly', 'hrx', 'hry'],\n                [newNativePos.getX(), newNativePos.getY(), hlx, hly, hrx, hry]);\n        }\n    };\n\n    /**\n     * Move coordinate properties of a preview point\n     * @param {IFPathBase.AnchorPoint} sourcePoint\n     * @param {String} xProperty\n     * @param {String} yProperty\n     * @param {IFPoint} position - a destination position in view coordinates\n     * @param {IFTransform} viewToWorldTransform - the transformation to apply to destination position\n     * @param {Boolean} ratio\n     * @private\n     */\n    IFPathEditor.prototype._movePreviewPointCoordinates = function (sourcePoint, xProperty, yProperty,\n                                                                    position, viewToWorldTransform, ratio, guides) {\n        var newPos = position;\n        if (ratio) {\n            var worldToViewTransform = viewToWorldTransform.inverted();\n            newPos = this.constrainPosition(position, worldToViewTransform, sourcePoint);\n        }\n        newPos = viewToWorldTransform.mapPoint(newPos);\n        // Don't perform handles mapping for now\n        /*\n        guides.beginMap();\n        newPos = guides.mapPoint(newPos);\n        */\n        var pathTransform = this._element.getTransform();\n        var sourcePosition = new IFPoint(sourcePoint.getProperty(xProperty), sourcePoint.getProperty(yProperty));\n\n        if (pathTransform) {\n            sourcePosition = pathTransform.mapPoint(sourcePosition);\n        }\n\n        this._transformPreviewPointCoordinates(sourcePoint, xProperty, yProperty,\n            new IFTransform(1, 0, 0, 1, newPos.getX() - sourcePosition.getX(), newPos.getY() - sourcePosition.getY()));\n\n        //guides.finishMap();\n    };\n\n    /**\n     * Transform coordinate properties of a preview point\n     * @param {IFPathBase.AnchorPoint} sourcePoint\n     * @param {String} xProperty\n     * @param {String} yProperty\n     * @param {IFTransform} transform\n     * @param {IFPoint} sourcePos if present, used for source position\n     * @private\n     */\n    IFPathEditor.prototype._transformPreviewPointCoordinates = function (sourcePoint, xProperty, yProperty, transform, sourcePos) {\n        var pathTransform = this._element.getTransform();\n\n        var previewPoint = this.getPathPointPreview(sourcePoint);\n        if (previewPoint) {\n            if (sourcePos) {\n                var sourcePosition = sourcePos;\n            } else {\n                // Map source point with transformation and apply it to preview point\n                var sourcePosition = new IFPoint(sourcePoint.getProperty(xProperty), sourcePoint.getProperty(yProperty));\n            }\n\n            var transformToApply = transform;\n            if (pathTransform) {\n                transformToApply = transform.multiplied(pathTransform.inverted());\n                transformToApply = pathTransform.multiplied(transformToApply);\n            }\n            var previewPosition = transformToApply.mapPoint(sourcePosition);\n\n            var propertiesToSet = [xProperty, yProperty];\n            var valuesToSet = [previewPosition.getX(), previewPosition.getY()];\n\n            // If we're modifying handle coordinates then set auto-handles to false\n            if (xProperty === 'hlx' || xProperty === 'hrx' || yProperty === 'hly' || yProperty === 'hry') {\n                propertiesToSet.push('ah');\n                valuesToSet.push(false);\n            }\n\n            // Assign properties now\n            previewPoint.setProperties(propertiesToSet, valuesToSet);\n        }\n    };\n\n    /**\n     * Calculates and set the new values of shoulders making the projection of new mouse position to shoulder vector\n     * @param {{type: partType, point: args.anchorPoint}} partId\n     * @param {IFPoint} position - destination position\n     * @param {Boolean} ratio - if true, modify both shoulders the same way\n     * @private\n     */\n    IFPathEditor.prototype._movePreviewPointShoulders = function (partId, position, ratio) {\n        var pathTransform = this._element.getTransform();\n        var sourcePosition = new IFPoint(partId.point.getProperty('x'), partId.point.getProperty('y'));\n\n        var shoulderLimitPt;\n        if (partId.type == IFPathEditor.PartType.LeftShoulder) {\n            shoulderLimitPt = partId.point.getLeftShoulderLimitPoint();\n        } else { // right shoulder\n            shoulderLimitPt = partId.point.getRightShoulderLimitPoint();\n        }\n\n        if (pathTransform) {\n            sourcePosition = pathTransform.mapPoint(sourcePosition);\n            shoulderLimitPt = pathTransform.mapPoint(shoulderLimitPt);\n        }\n\n        var newShoulderPt = ifMath.getVectorProjection(sourcePosition.getX(), sourcePosition.getY(),\n            shoulderLimitPt.getX(), shoulderLimitPt.getY(), position.getX(), position.getY(), true);\n\n        var newVal = ifMath.ptDist(newShoulderPt.getX(), newShoulderPt.getY(),\n            sourcePosition.getX(), sourcePosition.getY());\n\n        var previewPoint = this.getPathPointPreview(partId.point);\n\n        // We do not apply pathTransform to shoulders when generating vertices,\n        // assign new value directly to previewPoint without any further transforms\n        if (ratio) {\n            if (this.hasFlag(IFElementEditor.Flag.Detail) && previewPoint.getProperty('cu') != true) {\n                var oldLVal = partId.point.getProperty('cl');\n                oldLVal = oldLVal != null ? oldLVal : 0;\n                var oldRVal = partId.point.getProperty('cr');\n                oldRVal = oldRVal != null ? oldLVal : 0;\n                if (partId.type == IFPathEditor.PartType.LeftShoulder) {\n                    var delta = newVal - oldLVal;\n                    var newRVal = oldRVal - delta;\n                    newRVal = newRVal > 0 ? newRVal : 0;\n                    previewPoint.setProperties(['cl', 'cr'], [newVal, newRVal]);\n                } else { // right shoulder\n                    var delta = newVal - oldRVal;\n                    var newLVal = oldLVal - delta;\n                    newLVal = newLVal > 0 ? newLVal : 0;\n                    previewPoint.setProperties(['cl', 'cr'], [newLVal, newVal]);\n                }\n            } else {\n                previewPoint.setProperties(['cl', 'cr'], [newVal, newVal]);\n            }\n        } else if (partId.type == IFPathEditor.PartType.LeftShoulder) {\n            previewPoint.setProperty('cl', newVal);\n        } else { // right shoulder\n            previewPoint.setProperty('cr', newVal);\n        }\n    };\n\n    /**\n     * Assign a given set of preview point to source point\n     * @param {IFPathBase.AnchorPoint} sourcePoint\n     * @param {Array<String>} properties\n     * @private\n     */\n    IFPathEditor.prototype._assignPreviewPointPropertiesToSourcePoint = function (sourcePoint, properties) {\n        var previewPoint = this.getPathPointPreview(sourcePoint);\n        if (previewPoint) {\n            // Simply assign preview position back to source\n            sourcePoint.setProperties(properties, previewPoint.getProperties(properties));\n        }\n    };\n\n    /**\n     * Assign all geometry properties of preview point to corresponding point of an element\n     * @param {IFPathBase.AnchorPoint} point - a point to use for finding preview point\n     * @param {IFElement} element the element to which point to apply the transformation,\n     * might be different than the one this editor works on. This will be never null.\n     * @private\n     */\n    IFPathEditor.prototype._transferPreviewProperties = function (point, element) {\n        // Work with indices as element might not be ourself\n        var mySourceIndex = this._element.getAnchorPoints().getIndexOfChild(point);\n        var elSourcePoint = element.getAnchorPoints().getChildByIndex(mySourceIndex);\n        var previewPoint = this.getPathPointPreview(elSourcePoint);\n        if (previewPoint) {\n            elSourcePoint.transferProperties(previewPoint, [IFPathBase.AnchorPoint.GeometryProperties]);\n        }\n    };\n\n    /**\n     * Filters selection to not include separatly points, which are already included as some segment end-points\n     * @param {Array<*>} selection the part selection to be filtered\n     * @returns {Array<*>} the new filtered selection\n     * @private\n     */\n    IFPathEditor.prototype._filterSelection = function (selection) {\n        if (!selection) {\n            return null;\n        }\n        var newSelection = [];\n        var isInNewSelection;\n        for (var i = 0; i < selection.length; ++i) {\n            if (selection[i].type != IFPathEditor.PartType.Point) {\n                newSelection.push(selection[i]);\n            } else {\n                isInNewSelection = true;\n                for (var k = 0; k < selection.length; ++k) {\n                    if (selection[k].type == IFPathEditor.PartType.Segment &&\n                        (selection[i].point == selection[k].apLeft || selection[i].point == selection[k].apRight)) {\n\n                        isInNewSelection = false;\n                        break;\n                    }\n                }\n                if (isInNewSelection) {\n                    newSelection.push(selection[i]);\n                }\n            }\n        }\n        return newSelection;\n    };\n\n    /**\n     * If the path is updated (may be way around of this path editor), handle this by updating preview\n     * @param {IFElement.GeometryChangeEvent} evt\n     * @private\n     */\n    IFPathEditor.prototype._geometryChange = function (evt) {\n        if (evt.type == IFElement.GeometryChangeEvent.Type.After && evt.element == this._element) {\n            if (this._elementPreview) {\n                this.releasePathPreview();\n                this.requestInvalidation();\n            }\n        }\n    };\n\n    /** @override */\n    IFPathEditor.prototype.toString = function () {\n        return \"[Object IFPathEditor]\";\n    };\n\n    _.IFPathEditor = IFPathEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/polygoneditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a polygon\n     * @param {IFPolygon} polygon the polygon this editor works on\n     * @class IFPolygonEditor\n     * @extends IFPathBaseEditor\n     * @constructor\n     */\n    function IFPolygonEditor(polygon) {\n        IFPathBaseEditor.call(this, polygon);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFPolygonEditor, IFPathBaseEditor);\n    IFElementEditor.exports(IFPolygonEditor, IFPolygon);\n\n    IFPolygonEditor.INSIDE_PART_ID = ifUtil.uuid();\n    IFPolygonEditor.OUTSIDE_PART_ID = ifUtil.uuid();\n\n    /** @override */\n    IFPolygonEditor.prototype.getBBoxMargin = function () {\n        // Don't include annotations when in showSegmentDetails mode here, as they are added in getAnnotBBox\n        return IFPathBaseEditor.prototype.getBBoxMargin.call(this);\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype.getCustomBBox = function (transform, includeEditorTransform) {\n        var bbox = null;\n        if (this._showSegmentDetails()) {\n            var trf = transform;\n            // Use internal transformation if required\n            if (includeEditorTransform && this._transform) {\n                trf = this._transform.multiplied(transform);\n            }\n\n            var _addToBBox = function (other) {\n                if (other && !other.isEmpty()) {\n                    bbox = bbox ? bbox.united(other) : other;\n                }\n            };\n            this.getPaintElement().iterateSegments(function (point, inside, angle) {\n                _addToBBox(this._getAnnotationBBox(trf, point));\n            }.bind(this), true);\n        }\n        return bbox;\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype.movePart = function (partId, partData, position, viewToWorldTransform, guides, shift, option) {\n        IFPathBaseEditor.prototype.movePart.call(this, partId, partData, position, viewToWorldTransform, guides, shift, option);\n\n        if (partId === IFPolygonEditor.INSIDE_PART_ID || partId === IFPolygonEditor.OUTSIDE_PART_ID) {\n            var newPos = viewToWorldTransform.mapPoint(position);\n            newPos = guides.mapPoint(newPos);\n            var trf = this._element.getProperty('trf');\n            if (trf) {\n                newPos = trf.inverted().mapPoint(newPos);\n            }\n\n            if (!this._elementPreview) {\n                this._elementPreview = new IFPolygon();\n                this._elementPreview.transferProperties(this._element,\n                    [IFShape.GeometryProperties, IFPolygon.GeometryProperties], true);\n            }\n\n            var center = this._element.getCenter(false);\n            var angle = Math.atan2(newPos.getY() - center.getY(), newPos.getX() - center.getX()) - partData;\n            var distance = ifMath.ptDist(newPos.getX(), newPos.getY(), center.getX(), center.getY());\n\n            var oa = this._element.getProperty('oa');\n            var or = this._element.getProperty('or');\n            var ia = this._element.getProperty('ia');\n            var ir = this._element.getProperty('ir');\n            var ia_new = ia;\n            var ir_new = ir;\n            var oa_new = oa;\n            var or_new = or;\n\n            var moveInner = this._partSelection.indexOf(IFPolygonEditor.INSIDE_PART_ID) >= 0;\n            var moveOuter = this._partSelection.indexOf(IFPolygonEditor.OUTSIDE_PART_ID) >= 0;\n\n            if (this._partSelection.length == 1) {\n                if (moveInner) {\n                    if (!shift) {\n                        ia_new = ifMath.normalizeAngleRadians(angle + ia);\n                    }\n                    ir_new = distance;\n                }\n\n                if (moveOuter) {\n                    if (!shift) {\n                        oa_new = ifMath.normalizeAngleRadians(angle + oa);\n                    }\n                    or_new = distance;\n                }\n            } else if (moveInner && moveOuter) {\n                if (partId == IFPolygonEditor.INSIDE_PART_ID) {\n                    if (!shift) {\n                        ia_new = ifMath.normalizeAngleRadians(angle + ia);\n                    }\n                    ir_new = distance;\n                    var moveX = ir_new * Math.cos(ia_new) - ir * Math.cos(ia);\n                    var moveY = ir_new * Math.sin(ia_new) - ir * Math.sin(ia);\n                    var oPt_new = new IFPoint(or * Math.cos(oa) + moveX, or * Math.sin(oa) + moveY);\n                    oa_new = Math.atan2(oPt_new.getY(), oPt_new.getX());\n                    or_new = ifMath.ptDist(oPt_new.getX(), oPt_new.getY(), 0, 0);\n                } else if (partId == IFPolygonEditor.OUTSIDE_PART_ID) {\n                    if (!shift) {\n                        oa_new = ifMath.normalizeAngleRadians(angle + oa);\n                    }\n                    or_new = distance;\n                    var moveX = or_new * Math.cos(oa_new) - or * Math.cos(oa);\n                    var moveY = or_new * Math.sin(oa_new) - or * Math.sin(oa);\n                    var iPt_new = new IFPoint(ir * Math.cos(ia) + moveX, ir * Math.sin(ia) + moveY);\n                    ia_new = Math.atan2(iPt_new.getY(), iPt_new.getX());\n                    ir_new = ifMath.ptDist(iPt_new.getX(), iPt_new.getY(), 0, 0);\n                }\n            }\n\n            this._elementPreview.setProperties(['oa', 'or', 'ia', 'ir'], [oa_new, or_new, ia_new, ir_new]);\n            this.requestInvalidation();\n        }\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype.applyPartMove = function (partId, partData) {\n        if (partId === IFPolygonEditor.INSIDE_PART_ID || partId === IFPolygonEditor.OUTSIDE_PART_ID) {\n            var propertyValues = this._elementPreview.getProperties(['oa', 'or', 'ia', 'ir']);\n            this.resetPartMove(partId, partData);\n            this._element.setProperties(['oa', 'or', 'ia', 'ir'], propertyValues);\n        }\n        IFPathBaseEditor.prototype.applyPartMove.call(this, partId, partData);\n    };\n\n\n    /** @override */\n    IFPolygonEditor.prototype.applyTransform = function (element) {\n        if (element && this._elementPreview) {\n            element.transferProperties(this._elementPreview, [IFShape.GeometryProperties, IFPolygon.GeometryProperties]);\n            this.resetTransform();\n        } else {\n            IFPathBaseEditor.prototype.applyTransform.call(this, element);\n        }\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype._postPaint = function (transform, context) {\n        IFPathBaseEditor.prototype._postPaint.call(this, transform, context);\n        // If we have segments then paint 'em\n        if (this._showSegmentDetails()) {\n            var element = this.getPaintElement();\n            element.iterateSegments(function (point, inside, angle) {\n                var annotation = inside ? IFElementEditor.Annotation.Circle : IFElementEditor.Annotation.Diamond;\n                var partId = inside ? IFPolygonEditor.INSIDE_PART_ID : IFPolygonEditor.OUTSIDE_PART_ID;\n                this._paintAnnotation(context, transform, point, annotation, this._partSelection && this._partSelection.indexOf(partId) >= 0, false);\n            }.bind(this), true);\n        }\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype._getPartInfoAt = function (location, transform, tolerance) {\n        // If we have segment details then hit-test 'em first\n        if (this._showSegmentDetails()) {\n            var result = null;\n            this._element.iterateSegments(function (point, inside, angle) {\n                if (this._getAnnotationBBox(transform, point).expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n                    var partId = inside ? IFPolygonEditor.INSIDE_PART_ID : IFPolygonEditor.OUTSIDE_PART_ID;\n                    result = new IFElementEditor.PartInfo(this, partId, angle, true, true);\n                    return true;\n                }\n            }.bind(this), true);\n\n            if (result) {\n                return result;\n            }\n        }\n\n        return IFShapeEditor.prototype._getPartInfoAt.call(this, location, transform, tolerance);\n    };\n\n    /**\n     * @returns {Boolean}\n     * @private\n     */\n    IFPolygonEditor.prototype._showSegmentDetails = function () {\n        return this._showAnnotations() && this.hasFlag(IFElementEditor.Flag.Detail) && !this._elementPreview;\n    };\n\n    /** @override */\n    IFPolygonEditor.prototype.toString = function () {\n        return \"[Object IFPolygonEditor]\";\n    };\n\n    _.IFPolygonEditor = IFPolygonEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/rectangleeditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for an rectangle\n     * @param {IFRectangle} rectangle the rectangle this editor works on\n     * @class IFRectangleEditor\n     * @extends IFPathBaseEditor\n     * @constructor\n     */\n    function IFRectangleEditor(rectangle) {\n        IFPathBaseEditor.call(this, rectangle);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFRectangleEditor, IFPathBaseEditor);\n    IFElementEditor.exports(IFRectangleEditor, IFRectangle);\n\n    IFRectangleEditor.LEFT_SHOULDER_PART_ID = ifUtil.uuid();\n    IFRectangleEditor.RIGHT_SHOULDER_PART_ID = ifUtil.uuid();\n    IFRectangleEditor.ANY_SHOULDER_PART_ID = ifUtil.uuid();\n\n    /** @override */\n    IFEllipseEditor.prototype.getBBoxMargin = function () {\n        var source = IFPathBaseEditor.prototype.getBBoxMargin.call(this);\n        if (this._showSegmentDetails()) {\n            return Math.max(IFElementEditor.OPTIONS.annotationSizeRegular + 1, source);\n        }\n        return source;\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype.movePart = function (partId, partData, position, viewToWorldTransform, guides, shift, option) {\n        IFPathBaseEditor.prototype.movePart.call(this, partId, partData, position, viewToWorldTransform, guides, shift, option);\n\n        if (partId.id === IFRectangleEditor.LEFT_SHOULDER_PART_ID ||\n                partId.id === IFRectangleEditor.RIGHT_SHOULDER_PART_ID ||\n                partId.id === IFRectangleEditor.ANY_SHOULDER_PART_ID) {\n\n            var newPos = viewToWorldTransform.mapPoint(position);\n\n            if (!this._elementPreview) {\n                this._elementPreview = new IFRectangle();\n                this._elementPreview.transferProperties(this._element,\n                    [IFShape.GeometryProperties, IFRectangle.GeometryProperties], true);\n            }\n\n            var sourceTransform = this._element.getTransform();\n            var sourcePosition = new IFPoint(partId.ap.getProperty('x'), partId.ap.getProperty('y'));\n            if (sourceTransform) {\n                sourcePosition = sourceTransform.mapPoint(sourcePosition);\n            }\n            var newLVal = null;\n            var newRVal = null;\n\n            if (partId.id == IFRectangleEditor.LEFT_SHOULDER_PART_ID ||\n                    partId.id === IFRectangleEditor.ANY_SHOULDER_PART_ID) {\n\n                var nearPt = this._element.getAnchorPoints().getPreviousPoint(partId.ap);\n                var nearLPosition = new IFPoint(nearPt.getProperty('x'), nearPt.getProperty('y'));\n                nearLPosition = sourceTransform ? sourceTransform.mapPoint(nearLPosition) : nearLPosition;\n\n                var newLShoulderPt = ifMath.getVectorProjection(sourcePosition.getX(), sourcePosition.getY(),\n                    nearLPosition.getX(), nearLPosition.getY(), newPos.getX(), newPos.getY(), true);\n\n                newLVal = ifMath.ptDist(newLShoulderPt.getX(), newLShoulderPt.getY(),\n                    sourcePosition.getX(), sourcePosition.getY());\n            }\n            if (partId.id === IFRectangleEditor.RIGHT_SHOULDER_PART_ID ||\n                    partId.id === IFRectangleEditor.ANY_SHOULDER_PART_ID) {\n\n                var nearPt = this._element.getAnchorPoints().getNextPoint(partId.ap);\n                var nearRPosition = new IFPoint(nearPt.getProperty('x'), nearPt.getProperty('y'));\n                nearRPosition = sourceTransform ? sourceTransform.mapPoint(nearRPosition) : nearRPosition;\n\n                var newRShoulderPt = ifMath.getVectorProjection(sourcePosition.getX(), sourcePosition.getY(),\n                    nearRPosition.getX(), nearRPosition.getY(), newPos.getX(), newPos.getY(), true);\n\n                newRVal = ifMath.ptDist(newRShoulderPt.getX(), newRShoulderPt.getY(),\n                    sourcePosition.getX(), sourcePosition.getY());\n            }\n\n            var newVal;\n            if (newRVal !== null && newLVal !== null) {\n                if (newRVal > newLVal) {\n                    newVal = newRVal;\n                } else {\n                    newVal = newLVal;\n                }\n            } else if (newRVal !== null) {\n                newVal = newRVal;\n            } else {\n                newVal = newLVal;\n            }\n\n            var element = this.getPaintElement();\n            // We do not apply element's transform to shoulders when generating vertices,\n            // assign new value directly to preview corner shoulder without any further transforms\n            var prefix = IFRectangle.getGeometryPropertiesSidePrefix(partId.side);\n            if (shift) {\n                this.getPaintElement().setProperties([prefix + '_sx', prefix + '_sy'], [newVal, newVal]);\n            } else if (partId.id == IFRectangleEditor.LEFT_SHOULDER_PART_ID ||\n                    partId.id === IFRectangleEditor.ANY_SHOULDER_PART_ID && newVal == newLVal) {\n\n                this.getPaintElement().setProperty(prefix + '_sx', newVal);\n            } else { // right shoulder\n                this.getPaintElement().setProperty(prefix + '_sy', newVal);\n            }\n\n            this.requestInvalidation();\n        }\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype.applyPartMove = function (partId, partData) {\n        if (partId.id === IFRectangleEditor.LEFT_SHOULDER_PART_ID ||\n                partId.id === IFRectangleEditor.RIGHT_SHOULDER_PART_ID ||\n                partId.id === IFRectangleEditor.ANY_SHOULDER_PART_ID) {\n\n            this._element.transferProperties(this._elementPreview, [IFRectangle.GeometryProperties]);\n        }\n        IFPathBaseEditor.prototype.applyPartMove.call(this, partId, partData);\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype.applyTransform = function (element) {\n        if (element && this._elementPreview) {\n            element.transferProperties(this._elementPreview, [IFShape.GeometryProperties, IFRectangle.GeometryProperties]);\n            this.resetTransform();\n        } else {\n            IFPathBaseEditor.prototype.applyTransform.call(this, element);\n        }\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype._postPaint = function (transform, context) {\n        IFPathBaseEditor.prototype._postPaint.call(this, transform, context);\n        // If we have segments then paint 'em\n        if (this._showSegmentDetails()) {\n            this.getPaintElement().iterateSegments(function (point, side, ct, sl, sr, idx) {\n                var element = this.getPaintElement();\n                var leftPartId = {id: IFRectangleEditor.LEFT_SHOULDER_PART_ID, side: side};\n                var rightPartId = {id: IFRectangleEditor.RIGHT_SHOULDER_PART_ID, side: side};\n                var anyPartId = {id: IFRectangleEditor.ANY_SHOULDER_PART_ID, side: side};\n\n                if (sl != 0 || sr != 0) {\n                    var anchorPt = element.getAnchorPoints().getChildByIndex(idx);\n                    var sourceTransform = element.getTransform();\n                    var leftShoulder = sourceTransform ?\n                        anchorPt.getLeftShoulderPointTransformed(sourceTransform, true) :\n                        anchorPt.getLeftShoulderPoint(true);\n\n                    if (!leftShoulder) {\n                        leftShoulder = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n                        leftShoulder = sourceTransform ? sourceTransform.mapPoint(leftShoulder) : leftShoulder;\n                    }\n\n                    this._paintAnnotation(context, transform, leftShoulder, IFElementEditor.Annotation.Diamond,\n                        this.isPartSelected(leftPartId), false);\n\n                    var rightShoulder = sourceTransform ?\n                        anchorPt.getRightShoulderPointTransformed(sourceTransform, true) :\n                        anchorPt.getRightShoulderPoint(true);\n\n                    if (!rightShoulder) {\n                        rightShoulder = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n                        rightShoulder = sourceTransform ? sourceTransform.mapPoint(rightShoulder) : rightShoulder;\n                    }\n\n                    this._paintAnnotation(context, transform, rightShoulder, IFElementEditor.Annotation.Diamond,\n                        this.isPartSelected(rightPartId), false);\n                } else {\n                    this._paintAnnotation(context, transform, point, IFElementEditor.Annotation.Diamond,\n                        this.isPartSelected(leftPartId) || this.isPartSelected(rightPartId) ||\n                            this.isPartSelected(anyPartId), false);\n                }\n            }.bind(this), true);\n        }\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype._partIdAreEqual = function (a, b) {\n        var eqs = (a === b) || (a.id === b.id);\n        if (eqs && a.id) {\n            eqs = (a.side === b.side);\n        }\n        return eqs;\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype._getPartInfoAt = function (location, transform, tolerance) {\n        // If we have segment details then hit-test 'em first\n        if (this._showSegmentDetails()) {\n            var result = null;\n            this.getPaintElement().iterateSegments(function (point, side, ct, sl, sr, idx) {\n                var element = this.getPaintElement();\n                var anchorPt = element.getAnchorPoints().getChildByIndex(idx);\n                if (sl != 0 || sr != 0) {\n                    var sourceTransform = element.getTransform();\n                    var leftShoulder = sourceTransform ?\n                        anchorPt.getLeftShoulderPointTransformed(sourceTransform, true) :\n                        anchorPt.getLeftShoulderPoint(true);\n\n                    if (!leftShoulder) {\n                        leftShoulder = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n                        leftShoulder = sourceTransform ? sourceTransform.mapPoint(leftShoulder) : leftShoulder;\n                    }\n\n                    if (this._getAnnotationBBox(transform, leftShoulder)\n                        .expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n                        result = new IFElementEditor.PartInfo(this,\n                            {id: IFRectangleEditor.LEFT_SHOULDER_PART_ID, side: side,\n                                ap: anchorPt, point: leftShoulder},\n                            null, true, true);\n                        return true;\n                    }\n\n                    var rightShoulder = sourceTransform ?\n                        anchorPt.getRightShoulderPointTransformed(sourceTransform, true) :\n                        anchorPt.getRightShoulderPoint(true);\n\n                    if (!rightShoulder) {\n                        rightShoulder = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n                        rightShoulder = sourceTransform ? sourceTransform.mapPoint(rightShoulder) : rightShoulder;\n                    }\n\n                    if (this._getAnnotationBBox(transform, rightShoulder)\n                        .expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n                        result = new IFElementEditor.PartInfo(this,\n                            {id: IFRectangleEditor.RIGHT_SHOULDER_PART_ID, side: side,\n                                ap: anchorPt, point: rightShoulder},\n                            null, true, true);\n                        return true;\n                    }\n                } else {\n                    if (this._getAnnotationBBox(transform, point, true)\n                        .expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n\n                        result = new IFElementEditor.PartInfo(this,\n                            {id: IFRectangleEditor.ANY_SHOULDER_PART_ID, side: side, ap: anchorPt, point: point},\n                            null, true, true);\n                        return true;\n                    }\n                }\n            }.bind(this), true);\n\n            if (result) {\n                return result;\n            }\n        }\n\n        return IFPathBaseEditor.prototype._getPartInfoAt.call(this, location, transform, tolerance);\n    };\n\n    /**\n     * @returns {Boolean}\n     * @private\n     */\n    IFRectangleEditor.prototype._showSegmentDetails = function () {\n        return this._showAnnotations() && this.hasFlag(IFElementEditor.Flag.Detail) && !this._elementPreview;\n    };\n\n    /** @override */\n    IFRectangleEditor.prototype.toString = function () {\n        return \"[Object IFRectangleEditor]\";\n    };\n\n    _.IFRectangleEditor = IFRectangleEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/shapeeditor.js",
    "content": "(function (_) {\n    /**\n     * A base editor for shapes\n     * @param {IFShape} shape the shape this editor works on\n     * @extends IFBlockEditor\n     * @constructor\n     */\n    function IFShapeEditor(shape) {\n        IFBlockEditor.call(this, shape);\n    };\n    IFObject.inherit(IFShapeEditor, IFBlockEditor);\n\n    /** @override */\n    IFShapeEditor.prototype.acceptDrop = function (position, type, source, hitData) {\n        if (IFElementEditor.prototype.acceptDrop.call(this, position, type, source, hitData) === false) {\n            // Support dropping colors, gradients and swatches\n            // TODO : Support dropping IFTexture as well\n            if (hitData instanceof IFStyle.HitResult && hitData.entry instanceof IFPatternPaint) {\n                if (source instanceof IFPattern) {\n                    var editor = IFEditor.getEditor(this.getElement().getScene());\n                    editor.beginTransaction();\n                    try {\n                        hitData.entry.setProperty('pat', source);\n                    } finally {\n                        editor.commitTransaction('Drop Pattern');\n                    }\n                }\n            }\n            // NO-OP\n            return false;\n        }\n        return true;\n    };\n\n    /** @override */\n    IFShapeEditor.prototype.initialSetup = function () {\n        // Add a default style with a default fill\n        var style = new IFInlineStyle();\n        style.appendChild(new IFStrokePaint());\n        this.getElement().getStyleSet().appendChild(style);\n    };\n\n    /**\n     * Called to check whether a center cross should be painted or not\n     * @return {Boolean} true if a center cross should be painted, false if not (default)\n     * @private\n     */\n    IFShapeEditor.prototype._hasCenterCross = function () {\n        return false;\n    };\n\n    /** @override */\n    IFShapeEditor.prototype._prePaint = function (transform, context) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            var element = this.getPaintElement();\n\n            // Work in transformed coordinates to avoid scaling outline\n            var transformer = new IFVertexTransformer(element, transform);\n            context.canvas.putVertices(new IFVertexPixelAligner(transformer));\n\n            // Paint either outlined or highlighted (highlighted has a higher precedence)\n            context.canvas.strokeVertices(this.hasFlag(IFElementEditor.Flag.Highlighted) ? context.highlightOutlineColor : context.selectionOutlineColor, 1);\n        }\n    };\n\n    /** @override */\n    IFShapeEditor.prototype._postPaint = function (transform, context) {\n        // Paint center cross if desired + selected + in detail mode\n        if (this.hasFlag(IFElementEditor.Flag.Selected) && this.hasFlag(IFElementEditor.Flag.Detail) && this._hasCenterCross()) {\n            var element = this.getPaintElement();\n            var sourceTransform = element.getTransform();\n            var targetTransform = sourceTransform ? sourceTransform : new IFTransform(1, 0, 0, 1, 0, 0);\n            targetTransform = transform ? targetTransform.multiplied(transform) : targetTransform;\n            var crossHalfSizeMax = IFElementEditor.OPTIONS.centerCrossSize * 2;\n            var tMatrix = targetTransform.getMatrix();\n\n            if (Math.abs(tMatrix[0]) * element.getOrigHalfWidth() > crossHalfSizeMax &&\n                Math.abs(tMatrix[3]) * element.getOrigHalfHeight() > crossHalfSizeMax) {\n\n                var center = targetTransform.mapPoint(element.getCenter(false));\n                var cx = Math.floor(center.getX()) + 0.5;\n                var cy = Math.floor(center.getY()) + 0.5;\n                var cs = IFElementEditor.OPTIONS.centerCrossSize / 2;\n                context.canvas.strokeLine(cx - cs, cy - cs, cx + cs, cy + cs, 1, context.selectionOutlineColor);\n                context.canvas.strokeLine(cx + cs, cy - cs, cx - cs, cy + cs, 1, context.selectionOutlineColor);\n            }\n        }\n    };\n\n    /** @override */\n    IFShapeEditor.prototype.toString = function () {\n        return \"[Object IFShapeEditor]\";\n    };\n\n    _.IFShapeEditor = IFShapeEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/shapeseteditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a shapeSet\n     * @param {IFShapeSet} set the set this editor works on\n     * @class IFShapeSetEditor\n     * @extends IFBlockEditor\n     * @constructor\n     */\n    function IFShapeSetEditor(set) {\n        IFBlockEditor.call(this, set);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFShapeSetEditor, IFBlockEditor);\n    IFElementEditor.exports(IFShapeSetEditor, IFShapeSet);\n\n    /** @override */\n    IFShapeSetEditor.prototype._prePaint = function (transform, context) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            this._paintBBoxOutline(transform, context);\n        }\n        IFBlockEditor.prototype._prePaint.call(this, transform, context);\n    };\n\n    /** @override */\n    IFShapeSetEditor.prototype.toString = function () {\n        return \"[Object IFShapeSetEditor]\";\n    };\n\n    _.IFShapeSetEditor = IFShapeSetEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/shape/texteditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a text\n     * @param {IFText} text the text this editor works on\n     * @class IFTextEditor\n     * @extends IFShapeEditor\n     * @constructor\n     */\n    function IFTextEditor(rectangle) {\n        IFShapeEditor.call(this, rectangle);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFTextEditor, IFShapeEditor);\n    IFElementEditor.exports(IFTextEditor, IFText);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFTextEditor Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {HTMLDivElement}\n     * @private\n     */\n    IFTextEditor.prototype._inlineEditor = null;\n\n    /**\n     * Get a property value\n     * @param {String} property the property to get a value for\n     * @param {Boolean} [computed] whether to use computed value (defaults to false)\n     * @returns {*}\n     */\n    IFTextEditor.prototype.getProperty = function (property, computed) {\n        if (IFText.GeometryProperties.hasOwnProperty(property)) {\n            return this.getElement().getProperty(property);\n        } else if (this.isInlineEdit()) {\n            var activeParagraph = null;\n            var activeSpan = null;\n\n            var sel = rangy.getSelection();\n            if (sel.rangeCount) {\n                var range = sel.getRangeAt(0);\n                var nodes = range.collapsed ? [range.startContainer] : range.getNodes();\n                for (var i = 0; i < nodes.length; ++i) {\n                    var node = nodes[i];\n                    if (node.nodeType === 3) {\n                        for (var parent = node.parentNode; parent !== null; parent = parent.parentNode) {\n                            if (parent.nodeType === 1) {\n                                if (parent.nodeName.toLowerCase() === 'p') {\n                                    if (!activeParagraph) {\n                                        activeParagraph = parent;\n                                    }\n                                } else if (parent.nodeName.toLowerCase() === 'span') {\n                                    if (!activeSpan && !range.collapsed) {\n                                        activeSpan = parent;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (IFText.Block.Properties.hasOwnProperty(property)) {\n                if (activeSpan) {\n                    return IFText.Block.cssToProperty(property, computed ? window.getComputedStyle(activeSpan) : activeSpan.style);\n                } else if (activeParagraph) {\n                    return IFText.Block.cssToProperty(property, computed ? window.getComputedStyle(activeParagraph) : activeParagraph.style);\n                } else {\n                    return this.getElement().getContent().getProperty(property);\n                }\n            } else if (IFText.Paragraph.Properties.hasOwnProperty(property)) {\n                if (activeParagraph) {\n                    return IFText.Paragraph.cssToProperty(property, computed ? window.getComputedStyle(activeParagraph) : activeParagraph.style);\n                } else {\n                    return this.getElement().getContent().getProperty(property);\n                }\n            }\n        } else {\n            return this.getElement().getContent().getProperty(property);\n        }\n    };\n\n    IFTextEditor.prototype.setProperties = function (properties, values) {\n        var textProperties = [];\n        var textValues = [];\n        var blockProperties = [];\n        var blockValues = [];\n        var paragraphProperties = [];\n        var paragraphValues = [];\n\n        // Separate text, block and paragraph properties\n        for (var i = 0; i < properties.length; ++i) {\n            if (IFText.GeometryProperties.hasOwnProperty(properties[i])) {\n                textProperties.push(properties[i]);\n                textValues.push(values[i]);\n            } else if (IFText.Block.Properties.hasOwnProperty(properties[i])) {\n                blockProperties.push(properties[i]);\n                blockValues.push(values[i]);\n            } else {\n                paragraphProperties.push(properties[i]);\n                paragraphValues.push(values[i]);\n            }\n        }\n\n        if (this.isInlineEdit()) {\n            setTimeout(function () {\n                var blockCSS = {};\n                for (var i = 0; i < blockProperties.length; ++i) {\n                    IFText.Block.propertyToCss(blockProperties[i], blockValues[i], blockCSS);\n                }\n\n                var paragraphCSS = {};\n                for (var i = 0; i < paragraphProperties.length; ++i) {\n                    IFText.Paragraph.propertyToCss(paragraphProperties[i], paragraphValues[i], paragraphCSS);\n                }\n\n                this._inlineEditor.focus();\n                if (this._savedSelection) {\n                    rangy.restoreSelection(this._savedSelection);\n                    this._savedSelection = rangy.saveSelection();\n                }\n\n                var sel = rangy.getSelection();\n                if (sel.rangeCount) {\n                    var range = sel.getRangeAt(0);\n                    var nodes = range.collapsed ? [range.startContainer] : range.getNodes();\n                    for (var i = 0; i < nodes.length; ++i) {\n                        var node = nodes[i];\n                        if (node.nodeType === 3) {\n                            // Find topmost paragraph\n                            for (var parent = node.parentNode; parent !== null; parent = parent.parentNode) {\n                                if (parent.nodeType === 1 && parent.nodeName.toLowerCase() === 'p') {\n                                    // Assign paragraph properties\n                                    for (var prop in paragraphCSS) {\n                                        parent.style[prop] = paragraphCSS[prop];\n                                    }\n\n                                    // Assign block properties if selection is collapsed\n                                    if (sel.isCollapsed) {\n                                        for (var prop in blockCSS) {\n                                            parent.style[prop] = blockCSS[prop];\n                                        }\n                                    }\n\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                }\n\n                // Create / Remove block style if selection is not collapsed\n                if (!sel.isCollapsed) {\n                    // TODO !!!!\n                }\n\n                //var cssApplier = rangy.createCssClassApplier(\"dummy\", {normalize: true}, ['span', 'p']);\n                //cssApplier.toggleSelection();\n\n                // Trigger selection changed event to update everything\n                this._triggerSelectionChanged();\n            }.bind(this), 0);\n        } else {\n            // Apply to outer element\n            this.getElement().getContent().setProperties(blockProperties, blockValues);\n            this.getElement().getContent().setProperties(paragraphProperties, paragraphValues);\n        }\n\n        // Apply text properties if any\n        if (textProperties.length > 0) {\n            var oldAutoWidth = this.getElement().getProperty('aw');\n            var oldAutoHeight = this.getElement().getProperty('ah');\n\n            this.getElement().setProperties(textProperties, textValues);\n\n            // Hack: For changing height/width settings we\n            // need to re-calculate the transformation\n            var awIdx = textProperties.indexOf('aw');\n            var ahIdx = textProperties.indexOf('ah');\n\n            if (awIdx >= 0 || ahIdx >= 0) {\n                var newHeight = false;\n                var newWidth = false;\n\n                if (awIdx >= 0 && textValues[awIdx] === false && oldAutoWidth === true) {\n                    newWidth = true;\n                }\n                if (ahIdx >= 0 && textValues[ahIdx] === false && oldAutoHeight === true) {\n                    newHeight = true;\n                }\n\n                if (newWidth || newHeight) {\n                    var bbox = this.getElement().getGeometryBBox();\n                    var cbox = this.getElement().getContentBBox();\n\n                    if (bbox && cbox) {\n                        var transform = new IFTransform()\n                            .translated(-bbox.getX(), -bbox.getY())\n                            .scaled(newWidth ? cbox.getWidth() / bbox.getWidth() : 1, newHeight ? cbox.getHeight() / bbox.getHeight() : 1)\n                            .translated(bbox.getX(), bbox.getY());\n\n                        this.getElement().transform(transform);\n                    }\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFTextEditor.prototype.initialSetup = function () {\n        // Add a default style with a default fill\n        var style = new IFInlineStyle();\n        style.appendChild(new IFFillPaint());\n        this.getElement().getStyleSet().appendChild(style);\n    };\n\n    /** @override */\n    IFTextEditor.prototype.canInlineEdit = function () {\n        return true;\n    };\n\n    /** @override */\n    IFTextEditor.prototype.isInlineEdit = function () {\n        return this._inlineEditor !== null;\n    };\n\n    /** @override */\n    IFTextEditor.prototype.beginInlineEdit = function (view, container) {\n        // Remove size handles and hide our text element\n        this.removeFlag(IFBlockEditor.Flag.ResizeAll);\n        this.getElement().setFlag(IFElement.Flag.NoPaint);\n\n        var html = this.getElement().asHtml();\n\n        this._inlineEditor = $($('<div></div>'))\n            .css(this.getElement().getContent().propertiesToCss({}))\n            .css({\n                'position': 'absolute',\n                'background': 'transparent',\n                'transform-origin': '0% 0%',\n                '-webkit-transform-origin': '0% 0%',\n                'min-width': '1em',\n                'min-height': '1em'\n            })\n            .attr('contenteditable', 'true')\n            .on('mousedown', function (evt) {\n                evt.stopPropagation();\n            })\n            .on('mouseup', function (evt) {\n                evt.stopPropagation();\n                if (this._savedSelection) {\n                    rangy.removeMarkers(this._savedSelection);\n                }\n                this._savedSelection = rangy.saveSelection();\n\n                this._activeParagraphElement = null;\n                var sel = rangy.getSelection();\n                if (sel.rangeCount) {\n                    var range = sel.getRangeAt(0);\n                    var nodes = range.collapsed ? [range.endContainer] : range.getNodes();\n                    for (var i = 0; i < nodes.length; ++i) {\n                        var node = nodes[i];\n                        if (node.nodeType === 3) {\n                            var blockElement = null;\n                            for (var parent = node.parentNode; parent !== null; parent = parent.parentNode) {\n                                if (parent.nodeType === 1 && parent.nodeName.toLowerCase() === 'p') {\n                                    blockElement = parent;\n                                    break;\n                                }\n                            }\n\n                            if (blockElement) {\n                                this._activeParagraphElement = blockElement;\n                            }\n                        }\n                    }\n                }\n\n                this._triggerSelectionChanged();\n            }.bind(this))\n            .on('click', function (evt) {\n                evt.stopPropagation();\n            })\n            .on('dblclick', function (evt) {\n                evt.stopPropagation();\n            })\n            .on('keydown', function (evt) {\n                evt.stopPropagation();\n            })\n            .on('keyup', function (evt) {\n                evt.stopPropagation();\n                if (this._savedSelection) {\n                    rangy.removeMarkers(this._savedSelection);\n                }\n                this._savedSelection = rangy.saveSelection();\n            }.bind(this))\n            //.html('<style type=\"text/css\">.dummy{font-size: 30px}</style>' + html)\n            .html(html)\n            .appendTo(container);\n\n        this._inlineEditor.focus();\n\n        if (html === \"\") {\n            var pTag = document.createElement('p');\n            $(pTag).text('Your Text Here');\n            this._inlineEditor.append(pTag);\n\n            var range = rangy.createRange();\n            range.selectNodeContents(pTag);\n            var sel = rangy.getSelection();\n            sel.setSingleRange(range);\n        }\n    };\n\n    /** @override */\n    IFTextEditor.prototype.adjustInlineEditForView = function (view, position) {\n        var sceneBBox = this.getElement().getGeometryBBox();\n        if (!sceneBBox) {\n            sceneBBox = IFRect.fromPoints(new IFPoint(0, 0), new IFPoint(1, 1));\n            var transform = this.getElement().getTransform();\n            if (transform) {\n                sceneBBox = transform.mapRect(sceneBBox);\n            }\n        }\n\n        var viewBBox = view.getWorldTransform().mapRect(sceneBBox);\n        var left = viewBBox.getX();\n        var top = Math.floor(viewBBox.getY()) + 1;\n\n        var width = '';\n        var height = '';\n        if (this.getElement().getProperty('aw') === false && sceneBBox.getWidth() > 0) {\n            width = sceneBBox.getWidth() + 'px';\n        }\n        if (this.getElement().getProperty('ah') === false && sceneBBox.getHeight() > 0) {\n            height = sceneBBox.getHeight() + 'px';\n        }\n\n        this._inlineEditor\n            .css({\n                'width': width,\n                'height': height,\n                'transform': 'scale(' + view.getZoom() + ')',\n                '-webkit-transform': 'scale(' + view.getZoom() + ')'\n            })\n            .offset({top: top, left: left});\n\n        if (position) {\n            this.createSelectionFromPosition(position);\n        }\n    };\n\n    /**\n     * Creates a selection and/or sets the caret position by given screen coordinates\n     * @param {IFPoint} startPos the start position in screen coordinates\n     * @param {IFPoint} [endPos] the end position in screen coordinates. If not provided\n     * will not create a selection but set the caret position only. Defaults to null.\n     */\n    IFTextEditor.prototype.createSelectionFromPosition = function (startPos, endPos) {\n        var doc = document;\n        var range = null;\n        if (typeof doc.caretPositionFromPoint != \"undefined\") {\n            range = doc.createRange();\n            var start = doc.caretPositionFromPoint(startPos.getX(), startPos.getY());\n            range.setStart(start.offsetNode, start.offset);\n\n            if (endPos) {\n                var end = doc.caretPositionFromPoint(endPos.getX(), endPos.getY());\n                range.setEnd(end.offsetNode, end.offset);\n            }\n        } else if (typeof doc.caretRangeFromPoint != \"undefined\") {\n            range = doc.createRange();\n            var start = doc.caretRangeFromPoint(startPos.getX(), startPos.getY());\n            range.setStart(start.startContainer, start.startOffset);\n\n            if (endPos) {\n                var end = doc.caretRangeFromPoint(endX, endY);\n                range.setEnd(endPos.getX(), endPos.getY());\n            }\n        }\n\n        if (range !== null && typeof window.getSelection != \"undefined\") {\n            var sel = window.getSelection();\n            sel.removeAllRanges();\n            sel.addRange(range);\n        } else if (typeof doc.body.createTextRange != \"undefined\") {\n            range = doc.body.createTextRange();\n            range.moveToPoint(startPos.getX(), startPos.getY());\n\n            if (endPos) {\n                var endRange = range.duplicate();\n                endRange.moveToPoint(endPos.getX(), endPos.getY());\n                range.setEndPoint(\"EndToEnd\", endRange);\n            }\n            range.select();\n        }\n    };\n\n    /** @override */\n    IFTextEditor.prototype.finishInlineEdit = function () {\n        if (this._savedSelection) {\n            rangy.removeMarkers(this._savedSelection);\n            this._savedSelection = null;\n        }\n\n        var html = this._inlineEditor.html();\n\n        this.getElement().fromHtml(html);\n        this._inlineEditor.remove();\n        this._inlineEditor = null;\n\n        // Show size handles and our text element\n        this.setFlag(IFBlockEditor.Flag.ResizeAll);\n        this.getElement().removeFlag(IFElement.Flag.NoPaint);\n\n        // TODO : I18N\n        return 'Modify Text Content';\n    };\n\n    /** @override */\n    IFTextEditor.prototype._prePaint = function (transform, context) {\n        if ((this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) && !this.isInlineEdit()) {\n            // Paint textbox outline instead of glyphs\n            var textRect = this._element.getGeometryBBox();\n            if (textRect) {\n                var transformedRect = transform.mapRect(textRect);\n\n                // Ensure to pixel-align the rect\n                var x = Math.floor(transformedRect.getX());\n                var y = Math.floor(transformedRect.getY());\n                var w = Math.ceil(transformedRect.getX() + transformedRect.getWidth()) - x;\n                var h = Math.ceil(transformedRect.getY() + transformedRect.getHeight()) - y;\n\n                context.canvas.strokeRect(x + 0.5, y + 0.5, w, h, 1, this.hasFlag(IFElementEditor.Flag.Highlighted) ? context.highlightOutlineColor : context.selectionOutlineColor);\n            }\n        }\n    };\n\n    /** @private */\n    IFTextEditor.prototype._triggerSelectionChanged = function () {\n        var editor = IFEditor.getEditor(this.getElement().getScene());\n        if (editor.hasEventListeners(IFEditor.InlineEditorEvent)) {\n            editor.trigger(new IFEditor.InlineEditorEvent(this, IFEditor.InlineEditorEvent.Type.SelectionChanged));\n        }\n    };\n\n    /** @override */\n    IFTextEditor.prototype.toString = function () {\n        return \"[Object IFTextEditor]\";\n    };\n\n    _.IFTextEditor = IFTextEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/structure/layereditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a layer\n     * @param {IFLayer} layer the layer this editor works on\n     * @class IFLayerEditor\n     * @extends IFBlockEditor\n     * @constructor\n     */\n    function IFLayerEditor(layer) {\n        IFBlockEditor.call(this, layer);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFLayerEditor, IFBlockEditor);\n    IFElementEditor.exports(IFLayerEditor, IFLayer);\n\n    /** @override */\n    IFLayerEditor.prototype.paint = function (transform, context) {\n        // Setup outline colors if we have a color\n        var oldSelOutlineColor = context.selectionOutlineColor;\n        var layerColor = this._element.getProperty('cls');\n        context.selectionOutlineColor = layerColor;\n\n        // Call super\n        IFBlockEditor.prototype.paint.call(this, transform, context);\n\n        // Reset outline colors if set\n        context.selectionOutlineColor = oldSelOutlineColor;\n    };\n\n    /** @override */\n    IFLayerEditor.prototype._prePaint = function (transform, context) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            this._paintBBoxOutline(transform, context);\n        }\n        IFBlockEditor.prototype._prePaint.call(this, transform, context);\n    };\n\n    /** @override */\n    IFLayerEditor.prototype.toString = function () {\n        return \"[Object IFLayerEditor]\";\n    };\n\n    _.IFLayerEditor = IFLayerEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/structure/pageeditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a page\n     * @param {IFShapeSet} group the group this editor works on\n     * @class IFPageEditor\n     * @extends IFBlockEditor\n     * @constructor\n     */\n    function IFPageEditor(group) {\n        IFBlockEditor.call(this, group);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFPageEditor, IFBlockEditor);\n    IFPageEditor.exports(IFPageEditor, IFPage);\n\n    /** @override */\n    IFPageEditor.prototype.canApplyTransform = function () {\n        // Page transforms can be applied only if the page doesn't\n        // intersect with any other page\n        if (this._transform && !this._transform.isIdentity() && !this.getElement().hasFlag(IFElement.Flag.Locked)) {\n            var pageRect = this._transform.mapRect(new IFRect(\n                this._element.getProperty('x'), this._element.getProperty('y'),\n                this._element.getProperty('w'), this._element.getProperty('h')));\n\n            if (this._element.getScene().willPageIntersectWithOthers(this._element, pageRect)) {\n                return false;\n            }\n\n            return true;\n        }\n        return false;\n    };\n\n    /** @override */\n    IFPageEditor.prototype.applyTransform = function () {\n        if (this._transform && !this._transform.isIdentity()) {\n            var pageRect = this._transform.mapRect(new IFRect(\n                this._element.getProperty('x'), this._element.getProperty('y'),\n                this._element.getProperty('w'), this._element.getProperty('h')));\n            this._element.setProperties(['x', 'y', 'w', 'h'], [pageRect.getX(), pageRect.getY(), pageRect.getWidth(), pageRect.getHeight()]);\n            this._transform = null;\n        }\n        this.resetTransform();\n    };\n\n    /** @override */\n    IFPageEditor.prototype.acceptDrop = function (position, type, source, hitData) {\n        if (IFBlockEditor.prototype.acceptDrop.call(this, position, type, source, hitData) === false) {\n            // TODO : Make optional as most of the time this sucks\n            /*\n             // We can handle colors so check for a color\n             if (type === IFElementEditor.DropType.Color) {\n             this.getElement().setProperty('color', source ? source.asString() : null);\n             return true;\n             }\n             */\n        }\n        return true;\n    };\n\n    /** @override */\n    IFPageEditor.prototype._prePaint = function (transform, context) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            this._paintBBoxOutline(transform, context);\n        }\n        IFBlockEditor.prototype._prePaint.call(this, transform, context);\n    };\n\n    /** @override */\n    IFPageEditor.prototype.toString = function () {\n        return \"[Object IFPageEditor]\";\n    };\n\n    _.IFPageEditor = IFPageEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/structure/sliceeditor.js",
    "content": "(function (_) {\n    /**\n     * An editor for a slice\n     * @param {IFSlice} slice the slice this editor works on\n     * @class IFSliceEditor\n     * @extends IFBlockEditor\n     * @constructor\n     */\n    function IFSliceEditor(slice) {\n        IFBlockEditor.call(this, slice);\n        this._flags |= IFBlockEditor.Flag.ResizeAll;\n    };\n    IFObject.inherit(IFSliceEditor, IFBlockEditor);\n    IFElementEditor.exports(IFSliceEditor, IFSlice);\n\n    /** @override */\n    IFSliceEditor.prototype._prePaint = function (transform, context) {\n        if (this.hasFlag(IFElementEditor.Flag.Selected) || this.hasFlag(IFElementEditor.Flag.Highlighted)) {\n            this._paintBBoxOutline(transform, context);\n        }\n        IFBlockEditor.prototype._prePaint.call(this, transform, context);\n    };\n\n    /** @override */\n    IFSliceEditor.prototype.toString = function () {\n        return \"[Object IFSliceEditor]\";\n    };\n\n    _.IFSliceEditor = IFSliceEditor;\n})(this);"
  },
  {
    "path": "src/infinity-editor/scene/transformbox.js",
    "content": "(function (_) {\n\n    /**\n     * The transform box to transform multiple elements\n     * @param {IFRect} bbox - selection bounding box\n     * @param {Number} cx - the x coordinate of the transform bbox center (optional)\n     * @param {Number} cy - the y coordinate of the transform bbox center (optional)\n     * @class IFTransformBox\n     * @extends IFElement\n     * @mixes IFElement.Transform\n     * @mixes IFVertexSource\n     * @constructor\n     */\n    function IFTransformBox(bbox, cx, cy) {\n        var tl = bbox.getSide(IFRect.Side.TOP_LEFT);\n        this.tlx = tl.getX();\n        this.tly = tl.getY();\n        var tr = bbox.getSide(IFRect.Side.TOP_RIGHT);\n        this.trx = tr.getX();\n        this.try = tr.getY();\n        var br = bbox.getSide(IFRect.Side.BOTTOM_RIGHT);\n        this.brx = br.getX();\n        this.bry = br.getY();\n        var bl = bbox.getSide(IFRect.Side.BOTTOM_LEFT);\n        this.blx = bl.getX();\n        this.bly = bl.getY();\n        this._vertices = new IFVertexContainer();\n        this.cx = cx ? cx : (this.tlx + this.brx) / 2;\n        this.cy = cy ? cy : (this.tly + this.bry) / 2;\n    }\n\n    /**\n     * The size of the transform box annotation\n     * @type {Number}\n     */\n    IFTransformBox.ANNOT_SIZE = 6;\n\n    /**\n     * The margin at which the painted box located from exact transform box around selection\n     * @type {Number}\n     */\n    IFTransformBox.TRANSFORM_MARGIN = 0;\n\n    /**\n     * The identifiers of transform box handles\n     * @enum\n     */\n    IFTransformBox.Handles = {\n        TOP_LEFT: 0,\n        TOP_CENTER: 1,\n        TOP_RIGHT: 2,\n        RIGHT_CENTER: 3,\n        BOTTOM_RIGHT: 4,\n        BOTTOM_CENTER: 5,\n        BOTTOM_LEFT: 6,\n        LEFT_CENTER: 7,\n        ROTATION_CENTER: 8\n    };\n\n    /**\n     * The identifiers of the locations relatively to transform box\n     */\n    IFTransformBox.OUTLINE = ifUtil.uuid();\n    IFTransformBox.INSIDE = ifUtil.uuid();\n    IFTransformBox.OUTSIDE = ifUtil.uuid();\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFTransformBox Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * The geometry properties of a shape with their default values\n     */\n    IFTransformBox.prototype.tlx = null;\n    IFTransformBox.prototype.tly = null;\n    IFTransformBox.prototype.trx = null;\n    IFTransformBox.prototype.try = null;\n    IFTransformBox.prototype.brx = null;\n    IFTransformBox.prototype.bry = null;\n    IFTransformBox.prototype.blx = null;\n    IFTransformBox.prototype.bly = null;\n    IFTransformBox.prototype.cx = null;\n    IFTransformBox.prototype.cy = null;\n    IFTransformBox.prototype.trf = null;\n    IFTransformBox.prototype.cTrf = null;\n\n    /**\n     * @type {IFVertexContainer}\n     * @private\n     */\n    IFTransformBox.prototype._vertices = null;\n\n    /**\n     * Contains transform, which should be applied to transform box vertices before expanding it to TRANSFORM_MARGIN\n     * and vertices generation\n     * @type {IFTransform}\n     * @private\n     */\n    IFTransformBox.prototype._extTransform = null;\n\n    IFTransformBox.prototype.getTransform = function () {\n        return this.trf;\n    };\n\n    IFTransformBox.prototype.setTransform = function (transform) {\n        this.trf = transform;\n    };\n\n    IFTransformBox.prototype.transform = function (transform) {\n        if (transform && !transform.isIdentity()) {\n            this.trf = this.trf ? this.trf.multiplied(transform) : transform;\n        }\n    };\n\n    /** override */\n    IFTransformBox.prototype.rewindVertices = function (index) {\n        if (this._vertices == null || this._verticesDirty || this._vertices.getCount() == 0) {\n            this._vertices.clearVertices();\n            this._generateVertices();\n            this._verticesDirty = false;\n        }\n        return this._vertices.rewindVertices(index);\n    };\n\n    /** override */\n    IFTransformBox.prototype.readVertex = function (vertex) {\n        return this._vertices.readVertex(vertex);\n    };\n\n    /** @override */\n    IFTransformBox.prototype._calculateGeometryBBox = function () {\n        var ct = this._getPoint(IFTransformBox.Handles.ROTATION_CENTER);\n        var xMin = ct.getX();\n        var xMax = xMin;\n        var yMin = ct.getY();\n        var yMax = yMin;\n        var edges = [IFTransformBox.Handles.TOP_LEFT, IFTransformBox.Handles.TOP_RIGHT,\n            IFTransformBox.Handles.BOTTOM_RIGHT, IFTransformBox.Handles.BOTTOM_LEFT];\n        for (var i = 0; i < edges.length; ++i) {\n            var pt = this._getPoint(edges[i]);\n            if (xMin > pt.getX()) {\n                xMin = pt.getX();\n            }\n            if (xMax < pt.getX()) {\n                xMax = pt.getX();\n            }\n            if (yMin > pt.getY()) {\n                yMin = pt.getY();\n            }\n            if (yMax < pt.getY()) {\n                yMax = pt.getY();\n            }\n        }\n        return new IFRect(xMin, yMin, xMax - xMin, yMax - yMin);\n    };\n\n    /** @override */\n    IFTransformBox.prototype._calculatePaintBBox = function () {\n        var bbox = this._calculateGeometryBBox();\n        if (bbox) {\n            bbox = bbox.expanded(IFTransformBox.ANNOT_SIZE, IFTransformBox.ANNOT_SIZE,\n                IFTransformBox.ANNOT_SIZE, IFTransformBox.ANNOT_SIZE);\n\n            /*var annotBBox = ifAnnotation.getAnnotationBBox(null, this._getPoint(IFTransformBox.Handles.ROTATION_CENTER),\n                IFTransformBox.ANNOT_SIZE);\n            if (annotBBox) {\n                bbox = bbox.united(annotBBox);\n            }   */\n\n            return bbox;\n        }\n\n        return null;\n    };\n\n    /**\n     * Paints the transform box and it's handles\n     * @param {IFTransform} transform\n     * @param context\n     */\n    IFTransformBox.prototype.paint = function (transform, context) {\n        // Outline is painted with non-transformed stroke\n        // so we reset transform, transform the vertices\n        // ourself and then re-apply the transformation\n        var canvasTransform = context.canvas.resetTransform();\n        this._extTransform = transform ? canvasTransform.multiplied(transform) : canvasTransform;\n        this._verticesDirty = true;\n\n        if (!this._centerOnly) {\n            if (!this.rewindVertices(0)) {\n                return;\n            }\n\n            //context.canvas.setLineDash([5]);\n            // TODO: draw dashed line\n            context.canvas.putVertices(new IFVertexPixelAligner(this));\n            context.canvas.strokeVertices(IFColor.BLACK, 1);\n\n            var sides = this._collectResizeHandles(transform);\n            for (var i = 0; i < sides.length; ++i) {\n                var pt = this._getPoint(sides[i]);\n                ifAnnotation.paintAnnotation(context, null, pt, ifAnnotation.AnnotType.Rectangle,\n                    false, IFTransformBox.ANNOT_SIZE, IFColor.WHITE, IFColor.BLACK);\n            }\n        }\n        ifAnnotation.paintAnnotation(context, null, this._getPoint(IFTransformBox.Handles.ROTATION_CENTER),\n            ifAnnotation.AnnotType.Circle, false, IFTransformBox.ANNOT_SIZE, IFColor.WHITE, IFColor.BLACK);\n        context.canvas.setTransform(canvasTransform);\n\n        this._extTransform = null;\n    };\n\n    /**\n     * Sets options to not paint the full transform box, just it's center during painting\n     */\n    IFTransformBox.prototype.hide = function () {\n        this._centerOnly = true;\n    };\n\n    /**\n     * Sets options to paint the full transform box if it was hided before\n     */\n    IFTransformBox.prototype.show = function () {\n        this._centerOnly = false;\n    };\n\n    /**\n     * Sets the transformation for transform box center only\n     * @param {IFTransform} transform\n     */\n    IFTransformBox.prototype.setCenterTransform = function (transform) {\n        this.cTrf = transform;\n    };\n\n    /**\n     * Called whenever information about a part at a given location shall be returned\n     * @param {IFPoint} location the location to get a part for in view coordinates\n     * @param {IFTransform} transform the current transformation of the view\n     * @param {Number} [tolerance] optional tolerance for testing the location.\n     * If not provided defaults to zero.\n     * @returns {IFElementEditor.PartInfo} null if no part is available or a valid part info\n     */\n    IFTransformBox.prototype.getPartInfoAt = function (location, transform, tolerance) {\n        var result = null;\n\n        if (transform) {\n            this._extTransform = transform;\n            this._verticesDirty = true;\n        }\n\n        // test handles and center\n        var sides = this._collectResizeHandles(transform);\n        sides.push(IFTransformBox.Handles.ROTATION_CENTER);\n        for (var i = 0; i < sides.length; ++i) {\n            var handle = this._getPoint(sides[i]);\n            if (ifAnnotation.getAnnotationBBox(null, handle, IFTransformBox.ANNOT_SIZE)\n                    .expanded(tolerance, tolerance, tolerance, tolerance).containsPoint(location)) {\n                result = new IFElementEditor.PartInfo(null, sides[i], handle);\n                break;\n            }\n        }\n\n        // test outline and inside\n        if (!result) {\n            var hitRes = new IFVertexInfo.HitResult();\n            if (ifVertexInfo.hitTest(location.getX(), location.getY(), this,\n                    tolerance, true, hitRes)) {\n\n                if (hitRes.outline) {\n                    var edgeType = hitRes.segment % 2;\n                    result = new IFElementEditor.PartInfo(null, IFTransformBox.OUTLINE, edgeType);\n                } else {\n                    result = new IFElementEditor.PartInfo(null, IFTransformBox.INSIDE, null);\n                }\n            } else {\n                var rotSegm = this.getRotationSegment(location, transform);\n                result = new IFElementEditor.PartInfo(null, IFTransformBox.OUTSIDE, rotSegm);\n            }\n        }\n\n        this._extTransform = null;\n        return result;\n    };\n\n    /**\n     * Called whenever information about a circle sector at a given location shall be returned\n     * @param {IFPoint} location the location to get a sector for in view coordinates\n     * @param {IFTransform} transform the current transformation of the view\n     * @returns {Number} the number of the rotation sector from 8 equal sectors, starting from top left\n     */\n    IFTransformBox.prototype.getRotationSegment = function (location, transform) {\n        var rotSegm = 0;\n        var cntr = transform.mapPoint(new IFPoint(this.cx, this.cy));\n        var angle = Math.atan2(location.getY() - cntr.getY(), location.getX() - cntr.getX()) + Math.PI * 7 / 8;\n        if (angle < 0) {\n            angle += ifMath.PI2;\n        }\n        rotSegm = Math.floor(angle / (Math.PI / 4));\n        if (rotSegm < 0 || rotSegm > 7) {\n            rotSegm = 7;\n        }\n        return rotSegm;\n    };\n\n    /**\n     * Calculate the transformation, which should be applied to the selection\n     * based on the movement of transform box or it's handles\n     * @param {IFElementEditor.PartInfo} partInfo - transform box part information, which is moved\n     * @param {IFPoint} startPtTr - movement start point\n     * @param {IFPoint} endPtTr - movement end point\n     * @param {IFGuides} guides to be used for snapping\n     * @param {Boolean} option - if true and one of resize handles is moved,\n     * update transform box symmetrically to center\n     * @param {Boolean} ratio - if true and one of resize handles is moved, make equal scaling for width and height\n     * @param {Number} ratioStep\n     * @returns {IFTransform}\n     */\n    IFTransformBox.prototype.calculateTransformation = function (partInfo, startPtTr, endPtTr, guides, option, ratio,\n                                                                 ratioStep) {\n        var deltaTr = endPtTr.subtract(startPtTr);\n        var dx = deltaTr.getX();\n        var dy = deltaTr.getY();\n\n        var _snap = function (x, y, snapX, snapY) {\n            var pt = guides.mapPoint(new IFPoint(x + dx, y + dy));\n            if (snapX) {\n                dx = pt.getX() - x;\n            }\n            if (snapY) {\n                dy = pt.getY() - y;\n            }\n        }.bind(this);\n\n        if (partInfo.id < 8) {\n            var sides = [IFRect.Side.TOP_LEFT, IFRect.Side.TOP_CENTER, IFRect.Side.TOP_RIGHT, IFRect.Side.RIGHT_CENTER,\n                IFRect.Side.BOTTOM_RIGHT, IFRect.Side.BOTTOM_CENTER, IFRect.Side.BOTTOM_LEFT, IFRect.Side.LEFT_CENTER];\n\n            var tBoxRect = new IFRect(this.tlx, this.tly, this.brx - this.tlx, this.bry - this.tly);\n            var rectSide = sides[partInfo.id];\n            var handlePt = tBoxRect.getSide(rectSide);\n            _snap(handlePt.getX(), handlePt.getY(), true, true);\n\n            return tBoxRect.getResizeTransform(rectSide, dx, dy, ratio, option);\n        } else if (partInfo.id == IFTransformBox.Handles.ROTATION_CENTER) {\n            _snap(this.cx, this.cy, true, true);\n            return new IFTransform(1, 0, 0, 1, dx, dy);\n        } else if (partInfo.id == IFTransformBox.OUTSIDE) {\n            transform1 = new IFTransform(1, 0, 0, 1, -this.cx, -this.cy);\n            transform3 = new IFTransform(1, 0, 0, 1, this.cx, this.cy);\n            var angle1 = Math.atan2(startPtTr.getY() - this.cy, startPtTr.getX() - this.cx);\n            var angle2 = Math.atan2(endPtTr.getY() - this.cy, endPtTr.getX() - this.cx);\n            var angleDelta = angle1 - angle2;\n            // Lock angle to 15° if desired\n            if (ratio) {\n                var step = ratioStep ? ratioStep : Math.PI / 12;\n                angleDelta = Math.round(angleDelta / step) * step;\n            }\n            var cosA = Math.cos(angleDelta);\n            var sinA = Math.sin(angleDelta);\n            var transform2 = new IFTransform(cosA, -sinA, sinA, cosA, 0, 0);\n            return transform1.multiplied(transform2).multiplied(transform3);\n        } else if (partInfo.id == IFTransformBox.OUTLINE) {\n            transform1 = new IFTransform(1, 0, 0, 1, -this.cx, -this.cy);\n            transform3 = new IFTransform(1, 0, 0, 1, this.cx, this.cy);\n\n            if (ratio && ratioStep) {\n                var step = ratioStep ? ratioStep : 20;\n                dx = Math.round(dx / step) * step;\n                dy = Math.round(dy / step) * step;\n            }\n\n            var transform2 = new IFTransform(\n                1, dy * 2 / (this.brx - this.tlx), -dx * 2 / (this.bry - this.tly), 1, 0, 0);\n\n            return transform1.multiplied(transform2).multiplied(transform3);\n        } else {\n            var width3 = (this.brx - this.tlx) / 3.0;\n            var height3 = (this.bry - this.tly) / 3.0;\n            var handleX = this.cx;\n            var handleY = this.cy;\n\n            if (startPtTr.getX() <= this.tlx + width3) {\n                handleX = this.tlx;\n            } else if (startPtTr.getX() >= this.tlx + width3 * 2) {\n                handleX = this.brx;\n            }\n            if (startPtTr.getY() <= this.tly + height3) {\n                handleY = this.tly;\n            } else if (startPtTr.getY() >= this.tly + height3 * 2) {\n                handleY = this.bry;\n            }\n\n            _snap(handleX, handleY, true, true);\n            return new IFTransform(1, 0, 0, 1, dx, dy);\n        }\n    };\n\n    /**\n     * Permanently applies transform from trf or cTrf property to the transform box center\n     */\n    IFTransformBox.prototype.applyCenterTransform = function () {\n        // Transform is applied to center only, as transform box itself should always stay rectangular.\n        // So the transform box itself should be recalculated after transformation is applied to the selection\n        if (this.trf || this.cTrf) {\n            var trf = this.trf ? this.trf : this.cTrf;\n            var cntr = trf.mapPoint(new IFPoint(this.cx, this.cy));\n            this.cTrf = null;\n            this.trf = null;\n            this.cx = cntr.getX();\n            this.cy = cntr.getY();\n        }\n    };\n\n    /**\n     * Generates vertices of the transform box rectangle\n     * @private\n     */\n    IFTransformBox.prototype._generateVertices = function () {\n        if (!this._vertices || this._vertices.getCount() != 5) {\n            this._vertices = new IFVertexContainer();\n        } else {\n            this._vertices.rewindVertices(0);\n        }\n\n        var tl = this._getPoint(IFTransformBox.Handles.TOP_LEFT);\n        var tr = this._getPoint(IFTransformBox.Handles.TOP_RIGHT);\n        var br = this._getPoint(IFTransformBox.Handles.BOTTOM_RIGHT);\n        var bl = this._getPoint(IFTransformBox.Handles.BOTTOM_LEFT);\n\n        this._vertices.addVertex(IFVertex.Command.Move, tl.getX(), tl.getY());\n        this._vertices.addVertex(IFVertex.Command.Line, tr.getX(), tr.getY());\n        this._vertices.addVertex(IFVertex.Command.Line, br.getX(), br.getY());\n        this._vertices.addVertex(IFVertex.Command.Line, bl.getX(), bl.getY());\n        this._vertices.addVertex(IFVertex.Command.Close);\n    };\n\n    /**\n     * Returns a center point of the needed transform box handle with all transformations applied (in view coordinates)\n     * @param {IFTransformBox.Handles} side - the needed transform box handle center\n     * @param {Boolean} noTransform - if true, do not apply internal transformation,\n     * and return the original transform box point\n     * @returns {IFPoint} - a center point of the needed transform box handle\n     * @private\n     */\n    IFTransformBox.prototype._getPoint = function (side, noTransform) {\n        var pt = null;\n\n        var _transform = function (pt, trans) {\n            var objTrans = trans ? trans : this.trf;\n            var targTrans = this._extTransform;\n            if (objTrans && !noTransform) {\n                targTrans = targTrans ? objTrans.multiplied(targTrans) : objTrans;\n            }\n\n            if (targTrans && pt) {\n                pt = targTrans.mapPoint(pt);\n            }\n\n            return pt;\n        }.bind(this);\n\n        switch (side) {\n            case IFTransformBox.Handles.TOP_LEFT:\n                pt = _transform(new IFPoint(this.tlx, this.tly));\n                pt = new IFPoint(pt.getX() - IFTransformBox.TRANSFORM_MARGIN, pt.getY() - IFTransformBox.TRANSFORM_MARGIN);\n                break;\n            case IFTransformBox.Handles.TOP_CENTER:\n                pt = _transform(new IFPoint((this.tlx + this.trx) / 2, (this.tly + this.try) / 2));\n                pt = new IFPoint(pt.getX(), pt.getY() - IFTransformBox.TRANSFORM_MARGIN);\n                break;\n            case IFTransformBox.Handles.TOP_RIGHT:\n                pt = _transform(new IFPoint(this.trx, this.try));\n                pt = new IFPoint(pt.getX() + IFTransformBox.TRANSFORM_MARGIN, pt.getY() - IFTransformBox.TRANSFORM_MARGIN);\n                break;\n            case IFTransformBox.Handles.RIGHT_CENTER:\n                pt = _transform(new IFPoint((this.trx + this.brx) / 2, (this.try + this.bry) / 2));\n                pt = new IFPoint(pt.getX() + IFTransformBox.TRANSFORM_MARGIN, pt.getY());\n                break;\n            case IFTransformBox.Handles.BOTTOM_RIGHT:\n                pt = _transform(new IFPoint(this.brx, this.bry));\n                pt = new IFPoint(pt.getX() + IFTransformBox.TRANSFORM_MARGIN, pt.getY() + IFTransformBox.TRANSFORM_MARGIN);\n                break;\n            case IFTransformBox.Handles.BOTTOM_CENTER:\n                pt = _transform(new IFPoint((this.blx + this.brx) / 2, (this.bly + this.bry) / 2));\n                pt = new IFPoint(pt.getX(), pt.getY() + IFTransformBox.TRANSFORM_MARGIN);\n                break;\n            case IFTransformBox.Handles.BOTTOM_LEFT:\n                pt = _transform(new IFPoint(this.blx, this.bly));\n                pt = new IFPoint(pt.getX() - IFTransformBox.TRANSFORM_MARGIN, pt.getY() + IFTransformBox.TRANSFORM_MARGIN);\n                break;\n            case IFTransformBox.Handles.LEFT_CENTER:\n                pt = _transform(new IFPoint((this.tlx + this.blx) / 2, (this.tly + this.bly) / 2));\n                pt = new IFPoint(pt.getX() - IFTransformBox.TRANSFORM_MARGIN, pt.getY());\n                break;\n            case IFTransformBox.Handles.ROTATION_CENTER:\n                pt = _transform(new IFPoint(this.cx, this.cy), this.cTrf);\n                break;\n        }\n\n        return pt;\n    };\n\n    /**\n     * Defines and return which resize handles should be painted and hit tested based on transform box size\n     * @param {IFTransform} transform\n     * @returns {Array<IFTransformBox.Handles>}\n     * @private\n     */\n    IFTransformBox.prototype._collectResizeHandles = function (transform) {\n        var bbox = new IFRect(this.tlx, this.tly, this.brx - this.tlx, this.bry - this.tly);\n        bbox = this.trf ? this.trf.mapRect(bbox) : bbox;\n        var transformedBBox = transform ? transform.mapRect(bbox) : bbox;\n        var sides = [];\n        if (transformedBBox.getHeight() > (IFTransformBox.ANNOT_SIZE + 2) * 2 &&\n            transformedBBox.getWidth() > (IFTransformBox.ANNOT_SIZE + 2) * 2) {\n\n            sides = sides.concat([IFTransformBox.Handles.TOP_LEFT, IFTransformBox.Handles.TOP_RIGHT,\n                IFTransformBox.Handles.BOTTOM_LEFT, IFTransformBox.Handles.BOTTOM_RIGHT]);\n        }\n        if (transformedBBox.getHeight() > (IFTransformBox.ANNOT_SIZE + 2) * 3) {\n            sides = sides.concat([IFTransformBox.Handles.RIGHT_CENTER, IFTransformBox.Handles.LEFT_CENTER]);\n        }\n        if (transformedBBox.getWidth() > (IFTransformBox.ANNOT_SIZE + 2) * 3) {\n            sides = sides.concat([IFTransformBox.Handles.TOP_CENTER, IFTransformBox.Handles.BOTTOM_CENTER]);\n        }\n        return sides;\n    };\n\n    /** @override */\n    IFTransformBox.prototype.toString = function () {\n        return \"[IFTransformBox]\";\n    };\n\n    _.IFTransformBox = IFTransformBox;\n})(this);\n"
  },
  {
    "path": "src/infinity-editor/tool/bezigontool.js",
    "content": "(function (_) {\n    /**\n     * The bezigon tool\n     * @class IFBezigonTool\n     * @extends IFPathTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFBezigonTool() {\n        IFPathTool.call(this);\n    }\n\n    IFObject.inherit(IFBezigonTool, IFPathTool);\n\n    /** @override */\n    IFBezigonTool.prototype.activate = function (view) {\n        IFPathTool.prototype.activate.call(this, view);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.Move, this._mouseMove, this);\n        this._checkMode();\n    };\n\n    /** @override */\n    IFBezigonTool.prototype.deactivate = function (view) {\n        IFPathTool.prototype.deactivate.call(this, view);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.Move, this._mouseMove);\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFBezigonTool.prototype._mouseDown = function (event) {\n        var tm = new Date().getTime();\n        if (tm - this._mDownTime < IFPathTool.DBLCLICKTM) {\n            // Double-click\n            this._mouseDblClick(event);\n            return;\n        }\n\n        this._mDownTime = tm;\n        this._lastMouseEvent = event;\n        var anchorPt = null;\n        var clickPt;\n        this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n        this._dragStarted = false;\n        this._dragStartPt = null;\n        this._newPoint = null;\n        this._editPt = null;\n\n        if (event.button == GUIMouseEvent.BUTTON_LEFT ||\n            event.button == GUIMouseEvent.BUTTON_RIGHT && ifPlatform.modifiers.optionKey) {\n            this._released = false;\n\n            this._blockDeactivation();\n            this._checkMode();\n            this._renewPreviewLink();\n\n            if (this._mode == IFPathTool.Mode.Edit) {\n                var customizer = function(anchorPt) {\n                    if (ifPlatform.modifiers.optionKey &&\n                            anchorPt.getProperty('tp') != IFPathBase.AnchorPoint.Type.Connector) {\n\n                        anchorPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Symmetric);\n                    }\n                }\n                this._mouseDownOnEdit(event, customizer);\n            }\n\n            if (this._mode != IFPathTool.Mode.Edit) {\n                clickPt = this._constrainIfNeeded(event.client, this._view.getWorldTransform(), this._pathRef);\n                var otherPt;\n                if (this._pathEditor) {\n                    if (this._mode == IFPathTool.Mode.Append) {\n                        otherPt = this._pathRef.getAnchorPoints().getFirstChild();\n                    } else { // this._mode == IFPathTool.Mode.Prepend\n                        otherPt = this._pathRef.getAnchorPoints().getLastChild();\n                    }\n                }\n\n                if (otherPt && this._pathEditor.hitAnchorPoint(otherPt, clickPt, this._view.getWorldTransform(), this._scene.getProperty('pickDist'))) {\n                    this._setCursorForPosition(IFCursor.PenEnd);\n                    this._startTransaction(IFPathTool.Transaction.ModifyPathProperties);\n                    // Close path\n                    this._pathRef.setProperty('closed', true);\n                    this._makePointMajor(otherPt);\n                    this._pathEditor.setActiveExtendingMode(false);\n                    this._mode = IFPathTool.Mode.Edit;\n                    this._editPt = this._pathEditor.getPathPointPreview(otherPt);\n                    this._pathEditor.requestInvalidation();\n                } else {\n                    this._setCursorForPosition(IFCursor.Pen);\n                    var prevPt;\n                    if (this._pathEditor) {\n                        if (this._mode == IFPathTool.Mode.Append) {\n                            prevPt = this._pathRef.getAnchorPoints().getLastChild();\n                        } else { // this._mode == IFPathTool.Mode.Prepend\n                            prevPt = this._pathRef.getAnchorPoints().getFirstChild();\n                        }\n                    }\n                    if (prevPt && this._pathEditor.hitAnchorPoint(prevPt, clickPt, this._view.getWorldTransform(), this._scene.getProperty('pickDist'))) {\n                        this._makePointMajor(prevPt);\n                        this._editPt = this._pathEditor.getPathPointPreview(prevPt);\n                        this._pathEditor.requestInvalidation();\n                    } else {\n                        // add new point\n                        var pt = this._view.getViewTransform().mapPoint(clickPt);\n                        this._editor.getGuides().beginMap();\n                        pt = this._editor.getGuides().mapPoint(pt);\n                        this._editor.getGuides().finishMap();\n                        anchorPt = this._constructNewPoint(event, pt);\n                        this._addPoint(anchorPt, true, false);\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Move} event\n     * @private\n     */\n    IFBezigonTool.prototype._mouseMove = function (event) {\n        if (!this._released) {\n            if (event.button == GUIMouseEvent.BUTTON_RIGHT && ifPlatform.modifiers.optionKey) {\n                this._mouseDrag(event);\n            }\n            return;\n        }\n\n        this._lastMouseEvent = event;\n        this._setCursorForPosition(null, event.client);\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag | GUIMouseEvent.Move} event\n     * @private\n     */\n    IFBezigonTool.prototype._mouseDrag = function (event) {\n        if (this._refPt && !this._released) {\n            this._makePointMajor(this._refPt);\n            this._editPt = this._pathEditor.getPathPointPreview(this._refPt);\n            this._dragStartPt = this._refPt;\n            this._pathEditor.requestInvalidation();\n            this._refPt = null;\n        }\n        if (this._editPt && !this._released) {\n            this._lastMouseEvent = event;\n            this._dragStarted = true;\n            this._pathEditor.requestInvalidation();\n            var newPos = this._updatePoint(event.client);\n            var otherPt;\n            if (this._newPoint ||\n                this._pathRef.getAnchorPoints().getFirstChild() != this._pathRef.getAnchorPoints().getLastChild()) {\n\n                if (this._editPt == this._dpathRef.getAnchorPoints().getLastChild()) {\n                    otherPt = this._pathRef.getAnchorPoints().getFirstChild();\n                } else if (this._editPt == this._dpathRef.getAnchorPoints().getFirstChild()) {\n                    otherPt = this._pathRef.getAnchorPoints().getLastChild();\n                }\n\n                if (otherPt && this._pathEditor.hitAnchorPoint(otherPt, newPos, this._view.getWorldTransform(), this._scene.getProperty('pickDist'))) {\n                    this._setCursorForPosition(IFCursor.PenEnd);\n                } else {\n                    this._setCursorForPosition(IFCursor.Pen);\n                }\n            } else {\n                this._setCursorForPosition(IFCursor.Pen);\n            }\n\n            this._pathEditor.requestInvalidation();\n        }\n        //this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    /**\n     * Constructs new point, specific to Bezigon Tool, with the given position\n     * @param {GUIMouseEvent} event used to define pressed button\n     * @param {IFPoint} pt - coordinates to be used for new position in world system\n     * @returns {IFPath.AnchorPoint} newly created anchor point\n     * @private\n     */\n    IFBezigonTool.prototype._constructNewPoint = function (event, pt) {\n        var anchorPt = new IFPath.AnchorPoint();\n        anchorPt.setProperties(['x', 'y', 'ah'], [pt.getX(), pt.getY(), true]);\n\n        if (event.button == GUIMouseEvent.BUTTON_LEFT) {\n            if (ifPlatform.modifiers.optionKey) {\n                anchorPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Symmetric);\n            } else {\n                anchorPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Asymmetric);\n            }\n        } else { // BUTTON_RIGHT && this._AltDown\n            anchorPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Connector);\n        }\n\n        return anchorPt;\n    };\n\n    /**\n     * For Append and Prepend mode checks if a point, newly added to preview, is the path other end point.\n     * And if so, closes the path specific for Bezigon Tool way, and removes that extra point from preview.\n     * @private\n     */\n    IFBezigonTool.prototype._closeIfNeeded = function () {\n        if (this._pathRef &&\n            (this._newPoint ||\n                this._pathRef.getAnchorPoints().getFirstChild() != this._pathRef.getAnchorPoints().getLastChild()) &&\n            (this._mode == IFPathTool.Mode.Append || this._mode == IFPathTool.Mode.Prepend)) {\n\n            var anchorPt;\n            var otherPt;\n            if (this._mode == IFPathTool.Mode.Append) {\n                anchorPt = this._dpathRef.getAnchorPoints().getLastChild();\n                otherPt = this._pathRef.getAnchorPoints().getFirstChild();\n            } else { // this._mode == IFPathTool.Mode.Prepend\n                anchorPt = this._dpathRef.getAnchorPoints().getFirstChild();\n                otherPt = this._pathRef.getAnchorPoints().getLastChild();\n            }\n\n            var location = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n            var transform = this._pathRef.getTransform();\n            location = transform ? transform.mapPoint(location) : location;\n\n            if (otherPt && this._pathEditor.hitAnchorPoint(otherPt, location, null, this._scene.getProperty('pickDist')) ) {\n                if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                    this._startTransaction(IFPathTool.Transaction.ModifyPathProperties);\n                } else {\n                    this._transactionType = IFPathTool.Transaction.ModifyPathProperties;\n                }\n                // Close path\n                this._pathRef.beginUpdate();\n                this._pathEditor.selectOnePoint(otherPt);\n                if (ifPlatform.modifiers.optionKey) {\n                    otherPt.setProperties(['ah', 'tp'], [false, IFPathBase.AnchorPoint.Type.Asymmetric]);\n                }\n                if (!otherPt.getProperty('ah')) {\n                    otherPt.setProperties(['hlx', 'hly'], [anchorPt.getProperty('hlx'), anchorPt.getProperty('hly')]);\n                }\n                this._dpathRef.getAnchorPoints().removeChild(anchorPt);\n                if (!this._newPoint) {\n                    if (this._mode == IFPathTool.Mode.Append) {\n                        anchorPt = this._pathRef.getAnchorPoints().getLastChild();\n                    } else { // this._mode == IFPathTool.Mode.Prepend\n                        anchorPt = this._pathRef.getAnchorPoints().getFirstChild();\n                    }\n                    this._pathRef.getAnchorPoints().removeChild(anchorPt);\n                }\n                this._dpathRef.setProperty('closed', true);\n                this._pathRef.setProperty('closed', true);\n                this._pathRef.endUpdate();\n                this._pathEditor.requestInvalidation();\n                this._pathEditor.setActiveExtendingMode(false);\n                this._newPoint = false;\n            }\n        }\n    };\n\n    /** @override */\n    IFBezigonTool.prototype._mouseRelease = function (event) {\n        if (!this._released) {\n            try {\n                this._released = true;\n                //this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n                if (this._mode == IFPathTool.Mode.Append || this._mode == IFPathTool.Mode.Prepend) {\n                    var newPos = this._updatePoint(event.client);\n                    this._closeIfNeeded();\n                    if (this._pathRef.getProperty('closed')) {\n                        this._setCursorForPosition(IFCursor.PenMinus);\n                        this._mode = IFPathTool.Mode.Edit;\n                    } else if (this._newPoint) {\n                        this._addPoint(this._editPt, false, true);\n                        this._setCursorForPosition(IFCursor.Pen);\n                    } else if (this._editPt) {\n                        if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                            this._startTransaction(IFPathTool.Transaction.MovePoint);\n                        }\n                        this._pathEditor.applyTransform(this._pathRef);\n                        this._setCursorForPosition(IFCursor.PenEnd);\n                    }\n                    this._commitChanges();\n                    // hit test result becomes invalid if any;\n                    //this._lastHitTest = new IFPathTool.LastHitTest();\n                } else if (this._mode == IFPathTool.Mode.Edit && (this._editPt || this._refPt)) {\n                    if (this._dragStarted && this._editPt) {\n                        var newPos = this._updatePoint(event.client);\n                        if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                            this._startTransaction(IFPathTool.Transaction.MovePoint);\n                        }\n                        this._pathEditor.applyTransform(this._pathRef);\n                        this._setCursorForPosition(null, newPos);\n                        this._commitChanges();\n                        // hit test result becomes invalid if any;\n                        //this._lastHitTest = new IFPathTool.LastHitTest();\n                    } else {\n                        if (this._editPt) { // The case when path has just been closed on mouseDown\n                            this._commitChanges();\n                        } else { // this._refPt\n                            this._mouseNoDragReleaseOnEdit(event.client);\n                        }\n                    }\n                }\n                this._dragStarted = false;\n                this._dragStartPt = null;\n            } finally {\n                this._finishTransaction();\n            }\n        }\n        this._lastMouseEvent = null;\n\n        this._allowDeactivation();\n    };\n\n    /** override */\n    IFBezigonTool.prototype.toString = function () {\n        return \"[Object IFBezigonTool]\";\n    };\n\n    _.IFBezigonTool = IFBezigonTool;\n})(this);\n"
  },
  {
    "path": "src/infinity-editor/tool/ellipsetool.js",
    "content": "(function (_) {\n    /**\n     * The ellipse tool\n     * @class IFEllipseTool\n     * @extends IFShapeTool\n     * @constructor\n     */\n    function IFEllipseTool() {\n        IFShapeTool.call(this, true, true);\n    }\n\n    IFObject.inherit(IFEllipseTool, IFShapeTool);\n\n    /** @override */\n    IFEllipseTool.prototype._createShape = function () {\n        return new IFEllipse();\n    };\n\n    /** @override */\n    IFEllipseTool.prototype._updateShape = function (shape, area, line) {\n        // Original shape is a circle with coordinates x,y: [-1, 1]. Transform it to fit into the area:\n        shape.setProperty('trf',\n            new IFTransform(area.getWidth() / 2, 0, 0, area.getHeight() / 2,\n                area.getX() + area.getWidth() / 2, area.getY() + area.getHeight() / 2));\n    };\n\n    /** @override */\n    IFEllipseTool.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** override */\n    IFEllipseTool.prototype.toString = function () {\n        return \"[Object IFEllipseTool]\";\n    };\n\n    _.IFEllipseTool = IFEllipseTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/handtool.js",
    "content": "(function (_) {\n    /**\n     * The pan tool\n     * @class IFHandTool\n     * @extends IFTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFHandTool() {\n        IFTool.call(this);\n    }\n\n    IFObject.inherit(IFHandTool, IFTool);\n\n    /**\n     * @type {Boolean}\n     * @private\n     */\n    IFHandTool.prototype._panning = false;\n\n    /** @override */\n    IFHandTool.prototype.getCursor = function () {\n        return this._panning ? IFCursor.HandClosed : IFCursor.HandOpen;\n    };\n\n    /** @override */\n    IFHandTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        view.addEventListener(GUIMouseEvent.DragStart, this._mouseDragStart, this);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd, this);\n    };\n\n    /** @override */\n    IFHandTool.prototype.deactivate = function (view) {\n        IFTool.prototype.deactivate.call(this, view);\n\n        view.removeEventListener(GUIMouseEvent.DragStart, this._mouseDragStart);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd);\n    };\n\n    /** @override */\n    IFHandTool.prototype.isDeactivatable = function () {\n        // cannot deactivate while dragging\n        return this._panning ? false : true;\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragStart} event\n     * @private\n     */\n    IFHandTool.prototype._mouseDragStart = function (event) {\n        this._panning = true;\n        this.updateCursor();\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} event\n     * @private\n     */\n    IFHandTool.prototype._mouseDrag = function (event) {\n        if (this._panning) {\n            this._view.scrollBy(-event.clientDelta.getX(), -event.clientDelta.getY());\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragEnd} event\n     * @private\n     */\n    IFHandTool.prototype._mouseDragEnd = function (event) {\n        if (this._panning) {\n            this._panning = false;\n            this.updateCursor();\n        }\n    };\n\n    /** override */\n    IFHandTool.prototype.toString = function () {\n        return \"[Object IFHandTool]\";\n    };\n\n    _.IFHandTool = IFHandTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/lassotool.js",
    "content": "(function (_) {\n    /**\n     * The lasso select tool\n     * @class IFLassoTool\n     * @extends IFMarqueeTool\n     * @constructor\n     */\n    function IFLassoTool() {\n        IFMarqueeTool.call(this, new IFLassoTool._AreaSelector());\n    };\n\n    IFObject.inherit(IFLassoTool, IFMarqueeTool);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFLassoTool._AreaSelector Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFLassoTool._AreaSelector\n     * @extends IFMarqueeTool._AreaSelector\n     * @private\n     */\n    IFLassoTool._AreaSelector = function () {\n        IFMarqueeTool._AreaSelector.call(this);\n    };\n    IFObject.inherit(IFLassoTool._AreaSelector, IFMarqueeTool._AreaSelector);\n\n    /**\n     * @type {IFPoint}\n     * @private\n     */\n    IFLassoTool._AreaSelector.prototype._current = null;\n\n    /** @override */\n    IFLassoTool._AreaSelector.prototype.start = function (pos) {\n        this._current = null;\n    };\n\n    /** @override */\n    IFLassoTool._AreaSelector.prototype.move = function (pos) {\n        if (this._current == null || Math.abs(pos.getX() - this._current.getX()) >= 3 || Math.abs(pos.getY() - this._current.getY()) >= 3) {\n            this._vertexContainer.addVertex(this._vertexContainer.getCount() == 0 ? IFVertex.Command.Move : IFVertex.Command.Line, pos.getX(), pos.getY());\n            this._current = pos;\n        }\n    };\n\n    /** @override */\n    IFLassoTool.prototype.getCursor = function () {\n        return IFCursor.Lasso;\n    };\n\n    /** override */\n    IFLassoTool.prototype.toString = function () {\n        return \"[Object IFLassoTool]\";\n    };\n\n    _.IFLassoTool = IFLassoTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/layertool.js",
    "content": "(function (_) {\n    /**\n     * The layer tool\n     * @class IFLayerTool\n     * @extends IFSelectTool\n     * @constructor\n     */\n    function IFLayerTool() {\n        IFSelectTool.call(this);\n    };\n\n    IFObject.inherit(IFLayerTool, IFSelectTool);\n\n    /** @override */\n    IFLayerTool.prototype.activate = function (view) {\n        IFSelectTool.prototype.activate.call(this, view);\n\n        // Store current selection & select active layer\n        this._editor.storeSelection();\n\n        var activeLayer = this._scene.getActiveLayer();\n        if (activeLayer) {\n            this._editor.updateSelection(false, [activeLayer])\n        } else {\n            this._editor.clearSelection();\n        }\n    };\n\n    /** @override */\n    IFLayerTool.prototype.deactivate = function (view) {\n        // Restore previous selection\n        this._editor.restoreSelection();\n\n        IFSelectTool.prototype.deactivate.call(this, view);\n    };\n\n    /** @override */\n    IFLayerTool.prototype._getSelectableElement = function (element) {\n        for (var p = element; p !== null; p = p.getParent()) {\n            if (p instanceof IFLayer) {\n                return p;\n            }\n        }\n\n        return null;\n    };\n\n    /** override */\n    IFLayerTool.prototype.toString = function () {\n        return \"[Object IFLayerTool]\";\n    };\n\n    _.IFLayerTool = IFLayerTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/linetool.js",
    "content": "(function (_) {\n    /**\n     * The line tool\n     * @class IFLineTool\n     * @extends IFShapeTool\n     * @constructor\n     */\n    function IFLineTool() {\n        IFShapeTool.call(this, true, true);\n    }\n\n    IFObject.inherit(IFLineTool, IFShapeTool);\n\n    /** @override */\n    IFLineTool.prototype._createShape = function () {\n        var path = new IFPath();\n        path.getAnchorPoints().appendChild(new IFPathBase.AnchorPoint());\n        path.getAnchorPoints().appendChild(new IFPathBase.AnchorPoint());\n        return path;\n    };\n\n    /** @override */\n    IFLineTool.prototype._updateShape = function (shape, area, line) {\n        shape.getAnchorPoints().getChildByIndex(0).setProperties(['x', 'y'], [line[0].getX(), line[0].getY()]);\n        shape.getAnchorPoints().getChildByIndex(1).setProperties(['x', 'y'], [line[1].getX(), line[1].getY()]);\n    };\n\n    /** override */\n    IFLineTool.prototype.toString = function () {\n        return \"[Object IFLineTool]\";\n    };\n\n    _.IFLineTool = IFLineTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/marqueetool.js",
    "content": "(function (_) {\n    /**\n     * The base marquee select tool\n     * @param {IFMarqueeTool._AreaSelector} areaSelector\n     * @class IFMarqueeTool\n     * @extends IFTool\n     * @constructor\n     */\n    function IFMarqueeTool(areaSelector) {\n        IFTool.call(this);\n        this._areaSelector = areaSelector;\n    };\n\n    IFObject.inherit(IFMarqueeTool, IFTool);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFMarqueeTool._AreaSelector Class\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * @class IFMarqueeTool._AreaSelector\n     * @private\n     */\n    IFMarqueeTool._AreaSelector = function () {\n        this._vertexContainer = new IFVertexContainer();\n        this._pixelTransformer = new IFVertexPixelAligner(this._vertexContainer);\n    };\n\n    /**\n     * @type {IFVertexContainer}\n     * @private\n     */\n    IFMarqueeTool._AreaSelector.prototype._vertexContainer = null;\n\n    /**\n     * @type {IFVertexPixelAligner}\n     * @private\n     */\n    IFMarqueeTool._AreaSelector.prototype._pixelTransformer = null;\n\n    /**\n     * Called when this selector should return it's selection area bounds\n     * @return {IFRect} the area bounds\n     */\n    IFMarqueeTool._AreaSelector.prototype.getAreaBounds = function () {\n        return ifVertexInfo.calculateBounds(this._pixelTransformer, false);\n    };\n\n    /**\n     * Called when this selector should begin selecting\n     */\n    IFMarqueeTool._AreaSelector.prototype.begin = function () {\n        this._vertexContainer.clearVertices();\n    };\n\n    /**\n     * Called when this selector should finish selecting\n     */\n    IFMarqueeTool._AreaSelector.prototype.finish = function () {\n        // NO-OP\n    };\n\n    /**\n     * Called when this selector should start on a given position\n     * @param {IFPoint} pos the current position\n     */\n    IFMarqueeTool._AreaSelector.prototype.start = function (pos) {\n        // NO-OP\n    };\n\n    /**\n     * Called when this selector should move on a given position\n     * @param {IFPoint} pos the current position\n     */\n    IFMarqueeTool._AreaSelector.prototype.move = function (pos) {\n        // NO-OP\n    };\n\n    /**\n     * Called when this selector should paint itself\n     * @param {IFPaintContext} context\n     */\n    IFMarqueeTool._AreaSelector.prototype.paint = function (context) {\n        context.canvas.putVertices(this._pixelTransformer);\n        context.canvas.strokeVertices(IFColor.BLACK);\n    };\n\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFMarqueeTool Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * The current Area-Selector\n     * @type {IFMarqueeTool._AreaSelector}\n     * @private\n     */\n    IFMarqueeTool.prototype._areaSelector = null;\n\n    /**\n     * The current area selector bounds\n     * @type {IFRect}\n     * @private\n     */\n    IFMarqueeTool.prototype._areaBounds = null;\n\n    /** @override */\n    IFMarqueeTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        view.addEventListener(GUIMouseEvent.DragStart, this._mouseDragStart, this);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd, this);\n        view.addEventListener(GUIMouseEvent.Down, this._mouseDown, this);\n        view.addEventListener(GUIMouseEvent.Release, this._mouseRelease, this);\n\n        ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n    };\n\n    /** @override */\n    IFMarqueeTool.prototype.deactivate = function (view) {\n        IFTool.prototype.deactivate.call(this, view);\n\n        view.removeEventListener(GUIMouseEvent.DragStart, this._mouseDragStart);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd);\n        view.removeEventListener(GUIMouseEvent.Down, this._mouseDown);\n        view.removeEventListener(GUIMouseEvent.Release, this._mouseRelease);\n\n        ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n    };\n\n    /** @override */\n    IFMarqueeTool.prototype.isDeactivatable = function () {\n        // cannot deactivate while dragging\n        return !this._areaBounds;\n    };\n\n    /** @override */\n    IFMarqueeTool.prototype.paint = function (context) {\n        if (this._areaBounds) {\n            this._areaSelector.paint(context);\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFMarqueeTool.prototype._mouseDown = function (event) {\n        // Quit if not hitting the left-mouse-button\n        if (event.button !== GUIMouseEvent.BUTTON_LEFT) {\n            return;\n        }\n\n        // Let editor do some work for mouse position\n        this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFMarqueeTool.prototype._mouseRelease = function (event) {\n        if (!this._areaBounds || this._areaBounds.isEmpty()) {\n            this._editor.clearSelection();\n        } else if (this._areaBounds && !this._areaBounds.isEmpty()) {\n            // Invalidate to remove area selector's paint region\n            var bounds = this._areaBounds;\n            this._areaBounds = null; // reset to prevent repainting\n            this.invalidateArea(bounds);\n        } else {\n            this._areaBounds = null;\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragStart} event\n     * @private\n     */\n    IFMarqueeTool.prototype._mouseDragStart = function (event) {\n        this._areaSelector.begin();\n        this._areaSelector.start(event.client);\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} event\n     * @private\n     */\n    IFMarqueeTool.prototype._mouseDrag = function (event) {\n        if (this._areaBounds) {\n            this.invalidateArea(this._areaBounds);\n        }\n\n        this._areaSelector.move(event.client);\n        this._updateAreaBoundsAndInvalidate();\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragEnd} event\n     * @private\n     */\n    IFMarqueeTool.prototype._mouseDragEnd = function (event) {\n        if (this._areaBounds) {\n            // our area selector selected something\n            var collisionArea = new IFVertexTransformer(this._areaSelector._pixelTransformer, this._view.getViewTransform());\n            var collisions = this._scene.getCollisions(collisionArea, IFElement.CollisionFlag.GeometryBBox);\n\n            this._editor.updateSelection(ifPlatform.modifiers.shiftKey, collisions);\n        }\n        this._areaSelector.finish();\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFMarqueeTool.prototype._modifiersChanged = function (event) {\n        // TODO\n    };\n\n    /**\n     * @private\n     */\n    IFMarqueeTool.prototype._updateAreaBoundsAndInvalidate = function () {\n        this._areaBounds = this._areaSelector.getAreaBounds();\n        if (this._areaBounds && this._areaBounds.isEmpty()) {\n            this._areaBounds = null;\n        }\n\n        if (this._areaBounds) {\n            // Accreditate for 1px tolerance (AA)\n            this._areaBounds = this._areaBounds.expanded(1, 1, 1, 1);\n\n            this.invalidateArea(this._areaBounds);\n        }\n    };\n\n    /** override */\n    IFMarqueeTool.prototype.toString = function () {\n        return \"[Object IFMarqueeTool]\";\n    };\n\n    _.IFMarqueeTool = IFMarqueeTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/pagetool.js",
    "content": "(function (_) {\n    /**\n     * The page tool\n     * @class IFPageTool\n     * @extends IFSelectTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFPageTool() {\n        IFSelectTool.call(this);\n    };\n\n    IFObject.inherit(IFPageTool, IFSelectTool);\n\n    /** @override */\n    IFPageTool.prototype.activate = function (view) {\n        IFSelectTool.prototype.activate.call(this, view);\n\n        // Store current selection & select active page\n        this._editor.storeSelection();\n\n        var activePage = this._scene.getActivePage();\n        if (activePage) {\n            this._editor.updateSelection(false, [activePage])\n        } else {\n            this._editor.clearSelection();\n        }\n    };\n\n    /** @override */\n    IFPageTool.prototype.deactivate = function (view) {\n        // Restore previous selection\n        this._editor.restoreSelection();\n\n        IFSelectTool.prototype.deactivate.call(this, view);\n    };\n\n    /** @override */\n    IFPageTool.prototype._getSelectableElement = function (element) {\n        for (var p = element; p !== null; p = p.getParent()) {\n            if (p instanceof IFPage) {\n                return p;\n            }\n        }\n\n        return null;\n    };\n\n    /** override */\n    IFPageTool.prototype.toString = function () {\n        return \"[Object IFPageTool]\";\n    };\n\n    _.IFPageTool = IFPageTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/pathtool.js",
    "content": "(function (_) {\n    /**\n     * The base tool for path creating tools\n     * @class IFPathTool\n     * @extends IFTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFPathTool() {\n        IFTool.call(this);\n    }\n\n    IFObject.inherit(IFPathTool, IFTool);\n\n    /**\n     * Reference to the edited path\n     * @type {IFPath}\n     * @private\n     */\n    IFPathTool.prototype._pathRef = null;\n\n    /**\n     * Reference to the edited path preview\n     * @type {IFPath}\n     * @private\n     */\n    IFPathTool.prototype._dpathRef = null;\n\n    /**\n     * Indicates if a new point is created for this._editPt\n     * @type {Boolean}\n     * @private\n     */\n    IFPathTool.prototype._newPoint = null;\n\n    /**\n     * Contains reference to preview anchor point to edit\n     * @type {IFPathBase.AnchorPoint}\n     * @private\n     */\n    IFPathTool.prototype._editPt = null;\n\n    /**\n     * Contains reference to original path anchor point to edit in place\n     * @type {IFPathBase.AnchorPoint}\n     * @private\n     */\n    IFPathTool.prototype._refPt = null;\n\n    /**\n     * Contains reference to an editor of the currently edited path\n     * @type {IFPathEditor}\n     * @private\n     */\n    IFPathTool.prototype._pathEditor = null;\n\n    /**\n     * Indicates if the mouse released (all buttons)\n     * @type {boolean}\n     * @private\n     */\n    IFPathTool.prototype._released = true;\n\n    /**\n     * Indicates if the mouse drag started (all buttons)\n     * @type {boolean}\n     * @private\n     */\n    IFPathTool.prototype._dragStarted = false;\n\n    /**\n     * Contains reference to original path anchor point (if exists) for the case when it's preview is moving\n     * @type {IFPathBase.AnchorPoint}\n     * @private\n     */\n    IFPathTool.prototype._dragStartPt = null;\n\n    /**\n     * Indicates if option key is pressed the first time with current mouse down.\n     * This makes difference when updating point's existing handles with the pen tool\n     * @type {boolean}\n     * @private\n     */\n    IFPathTool.prototype._firstAlt = false;\n\n    /**\n     * Possible transaction types\n     * @enum\n     */\n    IFPathTool.Transaction = {\n        NoTransaction: 0,\n        InsertPoint: 1,\n        AppendPoint: 2,\n        MovePoint: 3,\n        DeletePoint: 4,\n        ModifyPointProperties: 5,\n        ModifyPathProperties: 6,\n        InsertElement: 7\n    };\n\n    /**\n     * Stores transaction type between transaction begin and end, or indicates that no transaction is started\n     * @type {IFPathTool.Transaction}\n     * @private\n     */\n    IFPathTool.prototype._transactionType = IFPathTool.Transaction.NoTransaction;\n\n    /**\n     * Possible working modes of Path Tool\n     * @type {{Append: number, Prepend: number, Edit: number}}\n     */\n    IFPathTool.Mode = {\n        Append: 0,\n        Prepend: 1,\n        Edit: 2\n    };\n\n    /**\n     * The current working mode\n     * @type {IFPathTool.Mode}\n     * @private\n     */\n    IFPathTool.prototype._mode = IFPathTool.Mode.Append;\n\n    /**\n     * Time in milliseconds of the last mouse down event since 1 Jan 1970.\n     * Used to support properly double-clicks\n     * @type {number}\n     * @private\n     */\n    IFPathTool.prototype._mDownTime = 0;\n\n    /**\n     * Time in milliseconds, which is used to distinguish two single clicks from double-click\n     * @type {number}\n     */\n    IFPathTool.DBLCLICKTM = 300;\n\n    /**\n     * Current active cursor\n     * @type {IFCursor}\n     * @private\n     */\n    IFPathTool.prototype._cursor = null;\n\n    /**\n     * Stores the details of the last mouse event, which leaves tool in the state, when it may be needed to\n     * update point's properties is Shift key goes down or up\n     * @type {GUIMouseEvent}\n     * @private\n     */\n    IFPathTool.prototype._lastMouseEvent = null;\n\n    /**\n     * Indicates if deactivation will not break internal tool's logic\n     * Deactivation is not allowed while mouse is pressed.\n     * @type {boolean}\n     * @private\n     */\n    IFPathTool.prototype._deactivationAllowed = true;\n\n    /** @override */\n    IFPathTool.prototype.getCursor = function () {\n        return this._cursor;\n    };\n\n    /** @override */\n    IFPathTool.prototype.catchesContextMenu = function () {\n        return true;\n    };\n\n    /** @override */\n    IFPathTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        view.addEventListener(GUIMouseEvent.Down, this._mouseDown, this);\n        view.addEventListener(GUIMouseEvent.Release, this._mouseRelease, this);\n        view.addEventListener(GUIKeyEvent.Down, this._keyDown, this);\n        ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n\n        this._cursor = IFCursor.PenStart;\n        this._transactionType = IFPathTool.Transaction.NoTransaction;\n        this._initialSelectCorrection();\n    };\n\n    /** @override */\n    IFPathTool.prototype.deactivate = function (view) {\n        if (this._newPoint || this._dpathRef) {\n            this._pathEditor.requestInvalidation();\n            this._pathEditor.releasePathPreview();\n            this._pathEditor.requestInvalidation();\n        }\n        this._finishTransaction();\n        this._allowDeactivation();\n        this._reset();\n        IFTool.prototype.deactivate.call(this, view);\n\n        view.removeEventListener(GUIMouseEvent.Down, this._mouseDown);\n        view.removeEventListener(GUIMouseEvent.Release, this._mouseRelease);\n        view.removeEventListener(GUIKeyEvent.Down, this._keyDown);\n        ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n    };\n\n    /** @override */\n    IFPathTool.prototype.isDeactivatable = function () {\n        return this._deactivationAllowed;\n    };\n\n    /**\n     * Remove deactivation blocking flag if any\n     * @private\n     */\n    IFPathTool.prototype._allowDeactivation = function () {\n        this._deactivationAllowed = true;\n    };\n\n    /**\n     * Mark that deactivation should be blocked\n     * @private\n     */\n    IFPathTool.prototype._blockDeactivation = function () {\n        this._deactivationAllowed = false;\n    };\n\n    /**\n     * Stores a reference to an editor of the selected path, if any\n     * @private\n     */\n    IFPathTool.prototype._checkPathEditor = function () {\n        var path = this._editor.getPathSelection();\n        if (path) {\n            this._pathEditor = IFElementEditor.openEditor(path);\n            this._pathEditor.setFlag(IFElementEditor.Flag.Detail);\n        }\n    };\n\n    /**\n     * Defines current working mode\n     * @private\n     */\n    IFPathTool.prototype._checkMode = function () {\n        this._checkPathEditor();\n        if (!this._pathEditor) {\n            this._mode = IFPathTool.Mode.Append;\n            this._pathRef = null;\n        } else {\n            this._pathRef = this._pathEditor.getPath();\n            if (this._pathRef.getProperty('closed')) {\n                this._mode = IFPathTool.Mode.Edit;\n            } else {\n                var selType = this._pathEditor.getPointsSelectionType();\n                if (selType == IFPathEditor.PointsSelectionType.No ||\n                    selType == IFPathEditor.PointsSelectionType.Several ||\n                    selType == IFPathEditor.PointsSelectionType.Middle) {\n\n                    this._mode = IFPathTool.Mode.Edit;\n                } else if (selType == IFPathEditor.PointsSelectionType.Last) {\n                    this._mode = IFPathTool.Mode.Append;\n                } else if (selType == IFPathEditor.PointsSelectionType.First) {\n                    this._mode = IFPathTool.Mode.Prepend;\n                }\n            }\n        }\n    };\n\n    /**\n     * Reset selected path points if needed and set selection to the last point,\n     * if selection was changed by temporary tool, and the path continued extension is indicated in path editor\n     * @private\n     */\n    IFPathTool.prototype._initialSelectCorrection = function () {\n        this._checkPathEditor();\n        if (this._pathEditor) {\n            this._pathRef = this._pathEditor.getPath();\n            if (this._pathRef.getProperty('closed')) {\n                this._pathEditor.setActiveExtendingMode(false);\n            } else if (this._pathEditor.isActiveExtendingMode()) {\n                var selType = this._pathEditor.getPointsSelectionType();\n                if (selType != IFPathEditor.PointsSelectionType.Last &&\n                        selType != IFPathEditor.PointsSelectionType.First) {\n\n                    this._pathEditor.selectOnePoint(this._pathRef.getAnchorPoints().getLastChild());\n                }\n                this._cursor = IFCursor.Pen;\n            }\n        }\n    };\n\n    /**\n     * Updates internal links to path preview to be consistent with currently edited path\n     * @private\n     */\n    IFPathTool.prototype._renewPreviewLink = function () {\n        if (!this._pathEditor) {\n            this._dpathRef = null;\n        } else {\n            this._dpathRef = this._pathEditor.getPathPreview();\n        }\n    };\n\n    /**\n     * Updates position of edited point, takes into account shiftKey and mode\n     * @param {IFPoint} clickPt - coordinates to be used for new position in view system\n     * @private\n     */\n    IFPathTool.prototype._updatePoint = function (clickPt) {\n        var newPos = null;\n        if (this._pathRef && this._editPt) {\n            if (this._mode != IFPathTool.Mode.Edit) {\n                newPos = this._constrainIfNeeded(clickPt, this._view.getWorldTransform(), this._pathRef);\n            } else {\n                newPos = this._constrainIfNeeded(clickPt, this._view.getWorldTransform(),\n                    this._pathRef, this._dpathRef.getAnchorPoints().getPreviousPoint(this._editPt));\n            }\n            this._editor.getGuides().beginMap();\n\n            newPos = this._view.getWorldTransform().mapPoint(\n                this._editor.getGuides().mapPoint(\n                    this._view.getViewTransform().mapPoint(newPos)));\n\n            this._editor.getGuides().finishMap();\n            this._pathEditor.movePoint(this._editPt, newPos, this._view.getWorldTransform(), this._dragStartPt);\n        }\n        return newPos;\n    };\n\n    /**\n     * Adds new anchor point to the end of edited path. Creates a new path with one point,\n     * if no path is selected for editing\n     * @param {IFPathBase.AnchorPoint} anchorPt - new anchor point to add into path in scene or path native coordinates\n     * @param {Boolean} draft - indicates if the path itself or path preview should be used for point insertion\n     * @param {Boolean} nativeCoord - indicates if the new point already in path native coordinates\n     * @param {Boolean} oldPreviewSelection - if set, don't update previous preview point\n     * @private\n     */\n    IFPathTool.prototype._addPoint = function (anchorPt, draft, nativeCoord, oldPreviewSelection) {\n        if (!oldPreviewSelection) {\n            anchorPt.setFlag(IFNode.Flag.Selected);\n        }\n        if (this._pathEditor && !nativeCoord) {\n            var transform = this._pathRef.getTransform();\n            if (transform) {\n                var location = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n                location = transform.inverted().mapPoint(location);\n                anchorPt.setProperties(['x', 'y'], [location.getX(), location.getY()]);\n            }\n        }\n        if (draft) {\n            if (!this._pathEditor) {\n                this._startTransaction(IFPathTool.Transaction.InsertElement);\n                this._createAndAppendPath(anchorPt);\n                this._pathEditor.selectOnePoint(anchorPt);\n                this._checkMode();\n                this._renewPreviewLink();\n                this._editPt = this._dpathRef.getAnchorPoints().getLastChild();\n                this._pathEditor.requestInvalidation();\n                this._pathEditor.setActiveExtendingMode(true);\n            } else {\n                this._pathEditor.requestInvalidation();\n                if (this._mode == IFPathTool.Mode.Append) {\n                    if (!oldPreviewSelection) {\n                        this._dpathRef.getAnchorPoints().getLastChild().removeFlag(IFNode.Flag.Selected);\n                    }\n                    this._dpathRef.getAnchorPoints().appendChild(anchorPt);\n                    this._editPt = this._dpathRef.getAnchorPoints().getLastChild();\n                    this._newPoint = true;\n                    this._pathEditor.setActiveExtendingMode(true);\n                } else if (this._mode == IFPathTool.Mode.Prepend) {\n                    if (!oldPreviewSelection) {\n                        this._dpathRef.getAnchorPoints().getFirstChild().removeFlag(IFNode.Flag.Selected);\n                    }\n                    this._dpathRef.getAnchorPoints().insertChild(anchorPt, this._dpathRef.getAnchorPoints().getFirstChild());\n                    this._pathEditor.shiftPreviewTable(1);\n                    this._editPt = this._dpathRef.getAnchorPoints().getFirstChild();\n                    this._newPoint = true;\n                    this._pathEditor.setActiveExtendingMode(true);\n                }\n                this._pathEditor.requestInvalidation();\n            }\n        } else {\n            if (!this._pathEditor) {\n                this._startTransaction(IFPathTool.Transaction.InsertElement);\n                this._createAndAppendPath(anchorPt);\n                this._pathEditor.selectOnePoint(anchorPt);\n                this._checkMode();\n                this._renewPreviewLink();\n                this._pathEditor.requestInvalidation();\n                this._pathEditor.setActiveExtendingMode(true);\n            } else {\n                this._pathEditor.requestInvalidation();\n                if (this._mode == IFPathTool.Mode.Append) {\n                    this._pathEditor.releasePathPreview(); // we release preview here, as base path will be modified\n                    this._pathEditor.requestInvalidation();\n                    this._startTransaction(IFPathTool.Transaction.AppendPoint);\n                    this._pathRef.getAnchorPoints().appendChild(anchorPt);\n                    this._pathEditor.selectOnePoint(anchorPt);\n                    this._pathEditor.setActiveExtendingMode(true);\n                } else if (this._mode == IFPathTool.Mode.Prepend) {\n                    this._pathEditor.releasePathPreview(); // we release preview here, as base path will be modified\n                    this._pathEditor.requestInvalidation();\n                    this._startTransaction(IFPathTool.Transaction.AppendPoint);\n                    this._pathRef.getAnchorPoints().insertChild(anchorPt, this._pathRef.getAnchorPoints().getFirstChild());\n\n                    this._pathEditor.selectOnePoint(anchorPt);\n                    this._pathEditor.setActiveExtendingMode(true);\n                }\n                this._pathEditor.requestInvalidation();\n            }\n        }\n    };\n\n    /**\n     * Used at the end of any of edit action. Releases path preview, invalidates area\n     * and cleans all the saved data relevant to edited path\n     * @private\n     */\n    IFPathTool.prototype._commitChanges = function () {\n        this._pathEditor.requestInvalidation();\n        this._pathEditor.releasePathPreview();\n        this._pathEditor.requestInvalidation();\n        this._reset();\n    };\n\n    /**\n     * Create a path shape with one point, and adds it for rendering\n     * @param {IFPathBase.AnchorPoint} apt - new anchor point to create path from\n     * @private\n     */\n    IFPathTool.prototype._createAndAppendPath = function (apt) {\n        var path = new IFPath();\n        path.getAnchorPoints().appendChild(apt);\n        apt.setFlag(IFNode.Flag.Selected);\n        path.setFlag(IFNode.Flag.Selected);\n        this._editor.insertElements([path], false, true);\n        this._checkPathEditor();\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFPathTool.prototype._mouseDown = function (event) {\n        this._released = false;\n    };\n\n    /**\n     * @param {GUIMouseEvent.DblClick} event\n     * @private\n     */\n    IFPathTool.prototype._mouseDblClick = function (event) {\n        this._lastMouseEvent = null;\n        this._checkMode();\n        if (this._pathEditor) {\n            this._pathEditor.updatePartSelection(false);\n            this._pathEditor.setActiveExtendingMode(false);\n            this._commitChanges();\n        }\n        this._mode = IFPathTool.Mode.Edit;\n        this._setCursorForPosition(null, event.client);\n        //this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFPathTool.prototype._mouseRelease = function (event) {\n        this._released = true;\n        this._dragStarted = false;\n        this._dragStartPt = null;\n    };\n\n    /**\n     * Reset the tool i.e. when done or canceling\n     * @private\n     */\n    IFPathTool.prototype._reset = function () {\n        if (this._pathEditor) {\n            this._pathEditor.removeFlag(IFElementEditor.Flag.Detail);\n        }\n        this._dpathRef = null;\n        this._pathRef = null;\n        this._pathEditor = null;\n        this._newPoint = false;\n        this._editPt = null;\n        this._dragStartPt = null;\n        this._refPt = null;\n    };\n\n    /**\n     * @param {GUIKeyEvent} event\n     * @private\n     */\n    IFPathTool.prototype._keyDown = function (event) {\n        if (event.key === IFKey.Constant.TAB) {\n            this._lastMouseEvent = null;\n            this._tabAction();\n        }\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFPathTool.prototype._modifiersChanged = function (event) {\n        if (event.changed.shiftKey && this._lastMouseEvent) {\n            if (!this._released) {\n                this._mouseDrag(this._lastMouseEvent);\n            } else {\n                this._mouseMove(this._lastMouseEvent);\n            }\n        }\n        if (event.changed.optionKey) {\n            this._firstAlt = false;\n            if (!this._released) {\n                if (ifPlatform.modifiers.optionKey) {\n                    this._firstAlt = !this._dragStarted;\n                }\n                this._mouseDrag(this._lastMouseEvent);\n            }\n        }\n    };\n\n    /**\n     * Finish path editing and deselect a path if TAB is pressed\n     * @private\n     */\n    IFPathTool.prototype._tabAction = function () {\n        // Action should be taken only if mouse released\n        if (this._released) {\n            this._checkMode();\n            if (this._pathEditor) {\n                this._pathEditor.updatePartSelection(false);\n                this._pathEditor.setActiveExtendingMode(false);\n                this._pathRef.removeFlag(IFNode.Flag.Selected);\n                this._commitChanges();\n            }\n            this._setCursorForPosition(IFCursor.PenStart);\n        }\n    };\n\n    /**\n     * If Shift key is pressed, finds the point, which should be used as a base to constrain location with,\n     * and calculates a new location\n     * @param {IFPoint} pt - original point\n     * @param {IFTransform} transform - a transformation to apply to base point before using it for constraining\n     * @param {IFPath} path - a path to look for base point; used only if no orientation point is passed\n     * @param {IFPathBase.AnchorPoint} orientPt - orientation anchor point to be used as a base to constrain location with,\n     * may be null\n     * @returns {IFPoint} - original or newly created bounded point\n     * @private\n     */\n    IFPathTool.prototype._constrainIfNeeded = function (pt, transform, path, orientPt) {\n        var constrPt = pt;\n\n        if (ifPlatform.modifiers.shiftKey) {\n            var otherPt = null;\n            if (orientPt) {\n                otherPt = orientPt;\n            } else if (path) {\n                if (this._mode == IFPathTool.Mode.Append) {\n                    otherPt = path.getAnchorPoints().getLastChild();\n                } else if (this._mode == IFPathTool.Mode.Prepend) {\n                    otherPt = path.getAnchorPoints().getFirstChild();\n                }\n            }\n\n            if (otherPt) {\n                constrPt = this._pathEditor.constrainPosition(pt, transform, otherPt);\n            }\n        }\n        return constrPt;\n    };\n\n    /**\n     * Makes a point the only selected and updates preview accordingly\n     * @param {IFPathBase.AnchorPoint} anchorPt - anchor point, which should be made major\n     * @private\n     */\n    IFPathTool.prototype._makePointMajor = function (anchorPt) {\n        this._pathEditor.selectOnePoint(anchorPt);\n        this._dpathRef = null;\n        this._pathEditor.releasePathPreview();\n        this._pathEditor.requestInvalidation();\n        this._dpathRef = this._pathEditor.getPathPreview(false, anchorPt);\n    };\n\n    /**\n     * Starts transaction, if it was not started earlier, updates this._transactionType\n     * @param {IFPathTool.Transaction} transactionType - transaction type of the current transaction to be set\n     * @private\n     */\n    IFPathTool.prototype._startTransaction = function (transactionType) {\n        if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n            this._editor.beginTransaction();\n        }\n        this._transactionType = transactionType;\n    };\n\n    /**\n     * Commit transaction if it was started, sets this._transactionType to IFPathTool.Transaction.NoTransaction\n     * @private\n     */\n    IFPathTool.prototype._finishTransaction = function () {\n        try {\n            switch (this._transactionType) {\n                case IFPathTool.Transaction.AppendPoint:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Append Point');\n                    break;\n                case IFPathTool.Transaction.InsertElement:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Insert Element(s)');\n                    break;\n                case IFPathTool.Transaction.InsertPoint:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Insert Point');\n                    break;\n                case IFPathTool.Transaction.MovePoint:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Move Point');\n                    break;\n                case IFPathTool.Transaction.DeletePoint:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Delete Point');\n                    break;\n                case IFPathTool.Transaction.ModifyPointProperties:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Modify Point Properties');\n                    break;\n                case IFPathTool.Transaction.ModifyPathProperties:\n                    // TODO : I18N\n                    this._editor.commitTransaction('Modify Path Properties');\n                    break;\n            }\n        } finally {\n            this._transactionType = IFPathTool.Transaction.NoTransaction;\n        }\n    };\n\n    /**\n     * In Edit mode hit-tests the path, and then takes appropriate action for mouse down:\n     * selects a point for editing or creates a new one, or just updates the working mode\n     * @param {GUIMouseEvent.Down} event\n     * @param {Function} customizer - a function to make tool-specific actions after new point has been created,\n     * accepts (IFPathBase.AnchorPoint) a new point as a parameter\n     * @private\n     */\n    IFPathTool.prototype._mouseDownOnEdit = function (event, customizer) {\n        var eventPt = event.client;\n        this._pathEditor.requestInvalidation();\n        this._pathEditor.releasePathPreview();\n        this._pathEditor.requestInvalidation();\n\n        var partInfo = this._pathEditor.getPartInfoAt(eventPt, this._view.getWorldTransform(), null, this._scene.getProperty('pickDist'));\n        if (partInfo && partInfo.id.type == IFPathEditor.PartType.Point) {\n            var anchorPt = partInfo.id.point;\n            if (!this._pathRef.getProperty('closed') && anchorPt === this._pathRef.getAnchorPoints().getLastChild()) {\n                this._mode = IFPathTool.Mode.Append;\n                this._makePointMajor(anchorPt);\n            } else if (!this._pathRef.getProperty('closed') && anchorPt === this._pathRef.getAnchorPoints().getFirstChild()) {\n                this._mode = IFPathTool.Mode.Prepend;\n                this._makePointMajor(anchorPt);\n            } else { // middlePoint\n                this._refPt = anchorPt;\n                if (this._refPt.getProperty('hlx') !== null && this._refPt.getProperty('hly') !== null ||\n                    this._refPt.getProperty('hrx') !== null && this._refPt.getProperty('hry') !== null) {\n\n                    this._setCursorForPosition(IFCursor.PenModify);\n                } else {\n                    this._setCursorForPosition(IFCursor.PenMinus);\n                }\n            }\n        } else if (partInfo && partInfo.id.type == IFPathEditor.PartType.Segment &&\n                partInfo.data.type == IFPathEditor.SegmentData.HitRes) {\n\n            this._setCursorForPosition(IFCursor.PenPlus);\n            this._startTransaction(IFPathTool.Transaction.InsertPoint);\n            var anchorPt = this._pathRef.insertHitPoint(partInfo.data.hitRes);\n            if (anchorPt) {\n                if (event.button == GUIMouseEvent.BUTTON_RIGHT && ifPlatform.modifiers.optionKey) {\n                    var tp = anchorPt.getProperty('tp');\n                    if (tp == IFPathBase.AnchorPoint.Type.Asymmetric) {\n                        anchorPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Connector);\n                    }\n                }\n                if (customizer) {\n                    customizer(anchorPt);\n                }\n                this._makePointMajor(anchorPt);\n                this._refPt = anchorPt;\n                this._editPt = this._pathEditor.getPathPointPreview(anchorPt);\n                this._pathEditor.requestInvalidation();\n                this._mode = IFPathTool.Mode.Edit;\n            } else {\n                this._finishTransaction();\n                this._reset();\n                this._mode = IFPathTool.Mode.Append;\n            }\n        } else { // no path hit\n            this._setCursorForPosition(IFCursor.PenStart);\n            this._pathEditor.updatePartSelection(false);\n            this._commitChanges();\n            this._mode = IFPathTool.Mode.Append;\n        }\n    };\n\n    /**\n     * Called when mouse is released in Edit mode and no mouse drag was started.\n     * Removes handles of the hit anchor point, or the point itself, if it doesn't have handles\n     * @private\n     */\n    IFPathTool.prototype._mouseNoDragReleaseOnEdit = function (clickPt) {\n        if (!this._refPt) {\n            return;\n        }\n        // remove handles or point itself\n        if (this._refPt.getProperty('hlx') != null ||\n            this._refPt.getProperty('hly') != null ||\n            this._refPt.getProperty('hrx') != null ||\n            this._refPt.getProperty('hry') != null) {\n\n            if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                this._startTransaction(IFPathTool.Transaction.ModifyPointProperties);\n            }\n            this._refPt.setProperties(['ah', 'hlx', 'hly', 'hrx', 'hry'], [false, null, null, null, null]);\n            this._makePointMajor(this._refPt);\n            this._setCursorForPosition(IFCursor.PenMinus);\n        } else {\n            if (this._pathRef.getAnchorPoints().getFirstChild() != this._pathRef.getAnchorPoints().getLastChild()) {\n                if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                    this._startTransaction(IFPathTool.Transaction.DeletePoint);\n                } else {\n                    this._transactionType = IFPathTool.Transaction.DeletePoint;\n                }\n                this._pathRef.getAnchorPoints().removeChild(this._refPt);\n            }\n            this._setCursorForPosition(null, clickPt);\n        }\n        this._refPt = null;\n        this._commitChanges();\n    };\n\n    IFPathTool.prototype._setCursorForPosition = function (cursor, clickPt) {\n        if (cursor !== null) {\n            this._cursor = cursor;\n        } else if (clickPt) {\n            if (!this._pathEditor) {\n                this._checkPathEditor();\n            }\n            if (this._pathEditor) {\n                var partInfo = this._pathEditor.getPartInfoAt(clickPt, this._view.getWorldTransform(), null, this._scene.getProperty('pickDist'));\n                if (partInfo && partInfo.id.type == IFPathEditor.PartType.Point) {\n                    var anchorPt = partInfo.id.point;\n                    var pathRef = this._pathEditor.getPath();\n                    if (!pathRef.getProperty('closed') &&\n                        (anchorPt === pathRef.getAnchorPoints().getFirstChild() ||\n                            anchorPt === pathRef.getAnchorPoints().getLastChild())) {\n\n                        if (this._mode == IFPathTool.Mode.Append &&\n                            anchorPt === pathRef.getAnchorPoints().getFirstChild() ||\n                            this._mode == IFPathTool.Mode.Prepend &&\n                                anchorPt === pathRef.getAnchorPoints().getLastChild()) {\n\n                            this._cursor = IFCursor.PenEnd;\n                        } else {\n                            this._cursor = IFCursor.Pen;\n                        }\n                    } else { // middlePoint\n                        if (this._mode == IFPathTool.Mode.Edit) {\n                            if (anchorPt.getProperty('hlx') !== null && anchorPt.getProperty('hly') !== null ||\n                                anchorPt.getProperty('hrx') !== null && anchorPt.getProperty('hry') !== null) {\n\n                                this._cursor = IFCursor.PenModify;\n                            } else {\n                                this._cursor = IFCursor.PenMinus;\n                            }\n                        } else {\n                            this._cursor = IFCursor.Pen;\n                        }\n                    }\n                } else if (this._mode == IFPathTool.Mode.Edit) {\n                    if (partInfo && partInfo.id.type == IFPathEditor.PartType.Segment) {\n                        this._cursor = IFCursor.PenPlus;\n                    } else { // no path hit\n                        this._cursor = IFCursor.PenStart;\n                    }\n                } else {\n                    this._cursor = IFCursor.Pen;\n                }\n            } else {\n                this._cursor = IFCursor.PenStart;\n            }\n        } else {\n            this._cursor = IFCursor.PenStart;\n        }\n\n        this.updateCursor();\n    };\n\n    /** override */\n    IFPathTool.prototype.toString = function () {\n        return \"[Object IFPathTool]\";\n    };\n\n    _.IFPathTool = IFPathTool;\n})(this);\n"
  },
  {
    "path": "src/infinity-editor/tool/pentool.js",
    "content": "(function (_) {\n    /**\n     * The pen tool\n     * @class IFPenTool\n     * @extends IFPathTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFPenTool() {\n        IFPathTool.call(this);\n    }\n\n    IFObject.inherit(IFPenTool, IFPathTool);\n\n    /** @override */\n    IFPenTool.prototype.activate = function (view) {\n        IFPathTool.prototype.activate.call(this, view);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.Move, this._mouseMove, this);\n    };\n\n    /** @override */\n    IFPenTool.prototype.deactivate = function (view) {\n        IFPathTool.prototype.deactivate.call(this, view);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.Move, this._mouseMove);\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFPenTool.prototype._mouseDown = function (event) {\n        var tm = new Date().getTime();\n        if (tm - this._mDownTime < IFPathTool.DBLCLICKTM) {\n            // Double-click\n            this._mouseDblClick(event);\n            return;\n        }\n\n        var anchorPt = null;\n\n        //this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n        this._lastMouseEvent = event;\n        this._dragStarted = false;\n        this._dragStartPt = null;\n        this._mouseMove(event);\n\n        this._mDownTime = tm;\n        this._released = false;\n        if (ifPlatform.modifiers.optionKey) {\n            this._firstAlt = true;\n        }\n        this._blockDeactivation();\n        this._checkMode();\n        this._renewPreviewLink();\n\n        if (this._mode == IFPathTool.Mode.Edit) {\n            this._mouseDownOnEdit(event);\n        }\n\n        if (this._mode != IFPathTool.Mode.Edit) {\n            if (this._newPoint && this._pathEditor) {\n                this._updatePoint(event.client);\n                if (this._mode == IFPathTool.Mode.Append) {\n                    var prevPt = this._editPt.getPrevious();\n                    if (prevPt) {\n                        prevPt.removeFlag(IFNode.Flag.Selected);\n                        this._editPt.setFlag(IFNode.Flag.Selected);\n                    }\n                } else { // mode == Prepend\n                    var nextPt = this._editPt.getNext();\n                    if (nextPt) {\n                        nextPt.removeFlag(IFNode.Flag.Selected);\n                        this._editPt.setFlag(IFNode.Flag.Selected);\n                    }\n                }\n                this._pathEditor.requestInvalidation();\n                if (event.button == GUIMouseEvent.BUTTON_RIGHT) {\n                    if (ifPlatform.modifiers.optionKey) {\n                        this._editPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Connector);\n                    } else {\n                        this._editPt.setProperties(['tp', 'cu'], [IFPathBase.CornerType.Rounded, true]);\n                    }\n                } else if (!ifPlatform.modifiers.optionKey){\n                    this._closePreviewIfNeeded();\n                }\n                if (!this._dpathRef.getProperty('closed')) {\n                    //TODO: remove handles if clicked to previous point\n                } else {\n                    if (this._mode == IFPathTool.Mode.Append) {\n                        this._refPt = this._pathRef.getAnchorPoints().getFirstChild();\n                    } else { // this._mode == IFPathTool.Mode.Prepend\n                        this._refPt = this._pathRef.getAnchorPoints().getLastChild();\n                    }\n                }\n                this._pathEditor.requestInvalidation();\n            } else if (this._pathEditor) { // We just switched from Edit mode, end point was clicked\n                if (this._mode == IFPathTool.Mode.Append) {\n                    this._refPt = this._pathRef.getAnchorPoints().getLastChild();\n                } else { // this._mode == IFPathTool.Mode.Prepend\n                    this._refPt = this._pathRef.getAnchorPoints().getFirstChild();\n                }\n            } else {\n                // add new point\n                var pt = this._view.getViewTransform().mapPoint(event.client);\n                this._editor.getGuides().beginMap();\n                pt = this._editor.getGuides().mapPoint(pt);\n                this._editor.getGuides().finishMap();\n                anchorPt = this._constructNewPoint(event, pt);\n                if (event.button == GUIMouseEvent.BUTTON_RIGHT) {\n                    if (ifPlatform.modifiers.optionKey) {\n                        anchorPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Connector);\n                    } else {\n                        anchorPt.setProperties(['tp', 'cu'], [IFPathBase.CornerType.Rounded, true]);\n                    }\n                }\n                this._addPoint(anchorPt, true, false);\n            }\n        }\n\n        this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    /** overwrite */\n    IFPenTool.prototype._renewPreviewLink = function () {\n        if (!this._pathEditor) {\n            this._editPt = null;\n            this._newPoint = false;\n            this._dpathRef = null;\n        } else {\n            var newDPathRef = this._pathEditor.getPathPreview(true);\n            if (this._editPt) {\n                var checkPt;\n                if (this._mode == IFPathTool.Mode.Append) {\n                    checkPt = newDPathRef.getAnchorPoints().getLastChild();\n                } else { // this._mode == IFPathTool.Mode.Prepend\n                    checkPt = newDPathRef.getAnchorPoints().getFirstChild();\n                }\n                if (this._editPt != checkPt) {\n                    this._newPoint = false;\n                    this._editPt = null;\n                }\n            }\n            this._dpathRef = newDPathRef;\n        }\n    };\n\n    IFPenTool.prototype._closePreviewIfNeeded = function () {\n        if (this._pathRef && this._newPoint &&\n            (this._mode == IFPathTool.Mode.Append || this._mode == IFPathTool.Mode.Prepend)) {\n\n            var anchorPt;\n            var otherPt;\n            if (this._mode == IFPathTool.Mode.Append) {\n                anchorPt = this._dpathRef.getAnchorPoints().getLastChild();\n                otherPt = this._dpathRef.getAnchorPoints().getFirstChild();\n            } else { // this._mode == IFPathTool.Mode.Prepend\n                anchorPt = this._dpathRef.getAnchorPoints().getFirstChild();\n                otherPt = this._dpathRef.getAnchorPoints().getLastChild();\n            }\n\n            var location = new IFPoint(anchorPt.getProperty('x'), anchorPt.getProperty('y'));\n            var transform = this._pathRef.getTransform();\n            location = transform ? transform.mapPoint(location) : location;\n\n            if (otherPt && this._pathEditor.hitAnchorPoint(otherPt, location, null, this._scene.getProperty('pickDist')) ) {\n                // Close preview path\n                this._dpathRef = this._pathEditor.getPathPreview(true);\n                if (this._mode == IFPathTool.Mode.Append) {\n                    this._editPt = this._dpathRef.getAnchorPoints().getFirstChild();\n                } else { // this._mode == IFPathTool.Mode.Prepend\n                    this._editPt = this._dpathRef.getAnchorPoints().getLastChild();\n                }\n                var tp = this._editPt.getProperty('tp');\n                if (!IFPathBase.isCornerType(tp)) {\n                    this._editPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Asymmetric);\n                }\n                this._editPt.setProperties(['hlx', 'hly'], [null, null]);\n                // It is significant to remove auto-handles in separate command here if set\n                this._editPt.setProperty('ah', false);\n                this._dpathRef.getAnchorPoints().removeChild(anchorPt);\n                this._dpathRef.setProperty('closed', true);\n                this._pathEditor.requestInvalidation();\n                this._editPt.setFlag(IFNode.Flag.Selected);\n                this._pathEditor.requestInvalidation();\n                this._newPoint = false;\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Move} event\n     * @private\n     */\n    IFPenTool.prototype._mouseMove = function (event) {\n        var tm = new Date().getTime();\n        if (tm - this._mDownTime < IFPathTool.DBLCLICKTM) {\n            // Double-click\n            return;\n        }\n\n        var curPt;\n        var prevPt = null;\n        var anchorPt;\n\n        if (!this._released) {\n            if (event.button == GUIMouseEvent.BUTTON_RIGHT) {\n                this._mouseDrag(event);\n            }\n            return;\n        }\n\n        this._lastMouseEvent = event;\n        this._checkMode();\n        this._renewPreviewLink();\n        if (this._mode == IFPathTool.Mode.Edit) {\n            this._setCursorForPosition(null, event.client);\n        } else { // _mode == Append || Prepend\n            var newPos = event.client;\n            if (!this._newPoint && this._pathEditor) {\n                newPos = this._constrainIfNeeded(event.client, this._view.getWorldTransform(), this._pathRef);\n                // add new point\n                var clickPt = this._view.getViewTransform().mapPoint(newPos);\n                this._editor.getGuides().beginMap();\n                clickPt = this._editor.getGuides().mapPoint(clickPt);\n                this._editor.getGuides().finishMap();\n                newPos = this._view.getWorldTransform().mapPoint(clickPt);\n                anchorPt = this._constructNewPoint(event, clickPt);\n                this._addPoint(anchorPt, true, false, true);\n            } else if (this._editPt) {\n                this._pathEditor.requestInvalidation();\n                newPos = this._updatePoint(event.client);\n                this._pathEditor.requestInvalidation();\n            }\n            if (this._editPt) {\n                var otherPt;\n                if (this._mode == IFPathTool.Mode.Append) {\n                    otherPt = this._pathRef.getAnchorPoints().getFirstChild();\n                } else { // this._mode == IFPathTool.Mode.Prepend\n                    otherPt = this._pathRef.getAnchorPoints().getLastChild();\n                }\n                if (this._pathEditor.hitAnchorPoint(otherPt, newPos, this._view.getWorldTransform(), this._scene.getProperty('pickDist'))) {\n                    this._setCursorForPosition(IFCursor.PenEnd);\n                } else {\n                    this._setCursorForPosition(IFCursor.Pen);\n                }\n            } else {\n                this._setCursorForPosition(null, event.client);\n            }\n        }\n        //this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    IFPenTool.prototype._updateHandles = function (newPos) {\n        var tp = this._editPt.getProperty('tp');\n        var ptx = this._editPt.getProperty('x');\n        var pty = this._editPt.getProperty('y');\n        var hlx, hly, hrx, hry;\n        if (this._pathEditor.hitAnchorPoint(this._editPt, newPos, this._view.getWorldTransform(), 0) && !this._firstAlt) {\n            if (this._mode != IFPathTool.Mode.Edit) {\n                if (this._mode == IFPathTool.Mode.Append) {\n                    if (this._editPt.getProperty('hlx') !== null && this._editPt.getProperty('hly') !== null) {\n                        this._editPt.setProperties(['tp', 'hrx', 'hry'], [IFPathBase.AnchorPoint.Type.Symmetric, null, null]);\n                    } else {\n                        this._editPt.setProperties(['tp', 'hrx', 'hry'], [IFPathBase.AnchorPoint.Type.Asymmetric, null, null]);\n                    }\n                } else { // _mode == Prepend\n                    if (this._editPt.getProperty('hrx') !== null && this._editPt.getProperty('hry') !== null) {\n                        this._editPt.setProperties(['tp', 'hlx', 'hly'], [IFPathBase.AnchorPoint.Type.Symmetric, null, null]);\n                    } else {\n                        this._editPt.setProperties(['tp', 'hlx', 'hly'], [IFPathBase.AnchorPoint.Type.Asymmetric, null, null]);\n                    }\n                }\n            } else {\n                if (!ifPlatform.modifiers.optionKey) {\n                    this._editPt.setProperties(['tp', 'hlx', 'hly', 'hrx', 'hry'], [IFPathBase.AnchorPoint.Type.Asymmetric, null, null, null, null]);\n                } else {\n                    this._editPt.setProperties(['tp', 'hrx', 'hry'], [IFPathBase.AnchorPoint.Type.Asymmetric, null, null]);\n                }\n            }\n        } else {\n            var transformToNewPos = this._pathEditor.getTransformFromNative(this._view.getWorldTransform());\n            var transformToNative = transformToNewPos.inverted();\n            var newNativePos = transformToNative.mapPoint(newPos);\n\n            if (!this._newPoint && ifPlatform.modifiers.optionKey && this._firstAlt &&\n                    tp != IFPathBase.AnchorPoint.Type.Connector &&\n                    !(this._editPt.getPrevious() == null && this._editPt.getNext() == null)) {\n\n                var dx = newNativePos.getX() - ptx;\n                var dy = newNativePos.getY() - pty;\n                this._editPt.setProperty('ah', false);\n                var hrxOrig = this._dragStartPt.getProperty('hrx');\n                hrx = hrxOrig != null ? hrxOrig + dx : newNativePos.getX();\n                var hryOrig = this._dragStartPt.getProperty('hry');\n                hry = hryOrig != null ? hryOrig + dy : newNativePos.getY();\n                this._editPt.setProperty('ah', false);\n                this._editPt.setProperties(['tp', 'hrx', 'hry'], [IFPathBase.AnchorPoint.Type.Asymmetric, hrx, hry]);\n\n            } else if (tp != IFPathBase.AnchorPoint.Type.Connector) {\n                this._editPt.setProperty('ah', false);\n                var h1x = newNativePos.getX();\n                var h1y = newNativePos.getY();\n                if (ifPlatform.modifiers.optionKey) {\n                    if (this._mode == IFPathTool.Mode.Prepend) {\n                        this._editPt.setProperties(['tp', 'hlx', 'hly'],\n                            [IFPathBase.AnchorPoint.Type.Asymmetric, h1x, h1y]);\n                    } else { // mode == Append || mode == Edit\n                        this._editPt.setProperties(['tp', 'hrx', 'hry'],\n                            [IFPathBase.AnchorPoint.Type.Asymmetric, h1x, h1y]);\n                    }\n                } else {\n                    var newTp = IFPathBase.AnchorPoint.Type.Symmetric;\n                    if (this._mode != IFPathTool.Mode.Edit && !this._newPoint &&\n                        !this._dpathRef.getProperty('closed') &&\n                        (this._editPt.getPrevious() == null && this._editPt.getNext() != null ||\n                            this._editPt.getPrevious() != null && this._editPt.getNext() == null)) {\n\n                        if (this._mode == IFPathTool.Mode.Prepend) {\n                            this._editPt.setProperties(['tp', 'hlx', 'hly'], [newTp, h1x, h1y]);\n                        } else { // mode == Append\n                            this._editPt.setProperties(['tp', 'hrx', 'hry'], [newTp, h1x, h1y]);\n                        }\n                    } else {\n                        var h2x = ptx + ptx - h1x;\n                        var h2y = pty + pty - h1y;\n                        if (this._mode == IFPathTool.Mode.Prepend) {\n                            this._editPt.setProperties(['tp', 'hrx', 'hry', 'hlx', 'hly'], [newTp, h2x, h2y, h1x, h1y]);\n                        } else {\n                            this._editPt.setProperties(['tp', 'hrx', 'hry', 'hlx', 'hly'], [newTp, h1x, h1y, h2x, h2y]);\n                        }\n                    }\n                }\n            } else { // tp == IFPathBase.AnchorPoint.Type.Connector\n                if (this._mode == IFPathTool.Mode.Append ||\n                        this._mode == IFPathTool.Mode.Edit && ifPlatform.modifiers.optionKey) {\n\n                    hlx = null;\n                    hly = null;\n\n                    // calculate right handle to be projection of click point to the vector,\n                    // connecting previous point and this one\n                    var prevPt = this._editPt.getPrevious();\n                    if (prevPt) {\n                        var prevX = prevPt.getProperty('x');\n                        var prevY = prevPt.getProperty('y');\n                        var dirLen = Math.sqrt(ifMath.ptSqrDist(ptx, pty, prevX, prevY));\n                        if (!ifMath.isEqualEps(dirLen, 0)) {\n                            var ex = (ptx - prevX) / dirLen;\n                            var ey = (pty - prevY) / dirLen;\n                            var hLen = ifMath.vDotProduct(ex, ey, newNativePos.getX() - ptx, newNativePos.getY() - pty);\n                            if (hLen > 0) {\n                                hrx = ptx + ex * hLen;\n                                hry = pty + ey * hLen;\n                            } else {\n                                hrx = null;\n                                hry = null;\n                            }\n                        } else {\n                            hrx = newNativePos.getX();\n                            hry = newNativePos.getY();\n                        }\n                    } else {\n                        hrx = newNativePos.getX();\n                        hry = newNativePos.getY();\n                    }\n                    this._editPt.setProperties(['hlx', 'hly', 'hrx', 'hry'], [hlx, hly, hrx, hry]);\n                } else if (this._mode == IFPathTool.Mode.Prepend) {\n                    hrx = null;\n                    hry = null;\n\n                    // calculate the left handle to be projection of click point to the vector,\n                    // connecting the next point and this one\n                    var nextPt = this._editPt.getNext();\n                    if (nextPt) {\n                        var nextX = nextPt.getProperty('x');\n                        var nextY = nextPt.getProperty('y');\n                        var dirLen = Math.sqrt(ifMath.ptSqrDist(ptx, pty, nextX, nextY));\n                        if (!ifMath.isEqualEps(dirLen, 0)) {\n                            var ex = (ptx - nextX) / dirLen;\n                            var ey = (pty - nextY) / dirLen;\n                            var hLen = ifMath.vDotProduct(ex, ey, newNativePos.getX() - ptx, newNativePos.getY() - pty);\n                            if (hLen > 0) {\n                                hlx = ptx + ex * hLen;\n                                hly = pty + ey * hLen;\n                            } else {\n                                hlx = null;\n                                hly = null;\n                            }\n                        } else {\n                            hlx = newNativePos.getX();\n                            hly = newNativePos.getY();\n                        }\n                    } else {\n                        hlx = newNativePos.getX();\n                        hly = newNativePos.getY();\n                    }\n                    this._editPt.setProperties(['hlx', 'hly', 'hrx', 'hry'], [hlx, hly, hrx, hry]);\n                }\n            }\n        }\n        this._pathEditor.requestInvalidation();\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag | GUIMouseEvent.Move} event\n     * @private\n     */\n    IFPenTool.prototype._mouseDrag = function (event) {\n        if (this._refPt && !this._editPt && !this._released) {\n            this._makePointMajor(this._refPt);\n            this._editPt = this._pathEditor.getPathPointPreview(this._refPt);\n            this._dragStartPt = this._refPt;\n            if (event.button == GUIMouseEvent.BUTTON_LEFT) {\n                this._editPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Symmetric);\n            }\n            this._pathEditor.requestInvalidation();\n        }\n        if (!this._released && this._editPt) {\n            this._lastMouseEvent = event;\n            this._setCursorForPosition(IFCursor.PenDrag);\n            if (!this._dragStartPt) {\n                this._dragStartPt = this._refPt ? this._refPt : this._editPt;\n                if (event.button == GUIMouseEvent.BUTTON_LEFT && this._editPt.getProperty('tp') != IFPathBase.AnchorPoint.Type.Connector) {\n                    this._editPt.setProperty('tp', IFPathBase.AnchorPoint.Type.Symmetric);\n                }\n            }\n            this._dragStarted = true;\n            this._updatePointProperties(event.client);\n        }\n    };\n\n    /**\n     * Constructs new point, specific to Pen Tool, with the given position\n     * @param {GUIMouseEvent} event used to define pressed button\n     * @param {IFPoint} pt - coordinates to be used for new position in world system\n     * @returns {IFPath.AnchorPoint} newly created anchor point\n     * @private\n     */\n    IFPenTool.prototype._constructNewPoint = function (event, pt) {\n        var anchorPt = new IFPath.AnchorPoint();\n        anchorPt.setProperties(['x', 'y'], [pt.getX(), pt.getY()]);\n\n        return anchorPt;\n    };\n\n    /** @override */\n    IFPenTool.prototype._mouseRelease = function (event) {\n        if (!this._released) {\n            try {\n                var anchorPt;\n\n                this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n                this._released = true;\n                if (this._pathEditor && this._mode == IFPathTool.Mode.Edit) {\n                    if (!this._dragStarted && this._refPt && !this._editPt) {\n                        this._mouseNoDragReleaseOnEdit(event.client);\n                    } else if (this._dragStarted) {\n                        this._updatePointProperties(event.client);\n                        if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                            this._startTransaction(IFPathTool.Transaction.ModifyPointProperties);\n                        }\n                        this._pathEditor.applyTransform(this._pathRef);\n                        this._commitChanges();\n                        this._setCursorForPosition(null, event.client);\n                    } else {\n                        // NOOP on release\n                        this._commitChanges();\n                        this._setCursorForPosition(null, event.client);\n                    }\n                } else if (this._dpathRef) {\n                    var newPos = event.client;\n                    if (this._dragStarted) {\n                        newPos = this._updatePointProperties(event.client);\n                    }\n                    if (!this._dpathRef.getProperty('closed')) {\n                        if (this._newPoint) {\n                            this._addPoint(this._editPt, false, true);\n                            this._pathEditor.requestInvalidation();\n                        }\n                        var otherPt;\n                        if (this._mode == IFPathTool.Mode.Append) {\n                            this._refPt = this._pathRef.getAnchorPoints().getLastChild();\n                            otherPt = this._pathRef.getAnchorPoints().getFirstChild();\n                        } else { // this._mode == IFPathTool.Mode.Prepend\n                            this._refPt = this._pathRef.getAnchorPoints().getFirstChild();\n                            otherPt = this._pathRef.getAnchorPoints().getLastChild();\n                        }\n                        if (!this._newPoint) {\n                            if (this._transactionType == IFPathTool.Transaction.NoTransaction) {\n                                this._startTransaction(IFPathTool.Transaction.ModifyPointProperties);\n                            }\n                            this._pathEditor.selectOnePoint(this._refPt);\n                            this._pathEditor.applyTransform(this._pathRef);\n                        }\n                        //this._makePointMajor(this._refPt);\n                        if (otherPt && otherPt != this._refPt &&\n                            this._pathEditor.hitAnchorPoint(otherPt, newPos, this._view.getWorldTransform(), this._scene.getProperty('pickDist'))) {\n\n                            this._setCursorForPosition(IFCursor.PenEnd);\n                        } else {\n                            this._setCursorForPosition(IFCursor.Pen);\n                        }\n                        this._commitChanges();\n                    } else {\n                        if (this._refPt) {\n                            this._startTransaction(IFPathTool.Transaction.ModifyPathProperties);\n                            this._pathEditor.selectOnePoint(this._refPt);\n                            this._pathEditor.applyTransform(this._pathRef);\n                            this._pathEditor.requestInvalidation();\n                            this._pathRef.setProperty('closed', true);\n                            this._pathEditor.setActiveExtendingMode(false);\n                        }\n                        this._commitChanges();\n                        this._mode = IFPathTool.Mode.Edit;\n                        this._setCursorForPosition(null, event.client);\n                    }\n                    this._refPt = null;\n                }\n            } finally {\n                this._finishTransaction();\n            }\n        }\n        this._dragStarted = false;\n        this._dragStartPt = null;\n        this._lastMouseEvent = null;\n        this._firstAlt = false;\n\n        this._allowDeactivation();\n    };\n\n    /**\n     * Sets shoulder length for styled corners equal to the distance between anchor point's position and passed position\n     * @param {IFPoint} newPos - position, which should be used for shoulder length calculation in view coordinates\n     * @private\n     */\n    IFPenTool.prototype._updateShoulders = function(newPos) {\n        if (this._mode != IFPathTool.Mode.Append && this._mode != IFPathTool.Mode.Prepend || !this._editPt) {\n            return;\n        }\n        if (this._pathEditor.hitAnchorPoint(this._editPt, newPos, this._view.getWorldTransform(), 0)) {\n            if (this._mode == IFPathTool.Mode.Append) {\n                this._editPt.setProperty('cr', null);\n            } else if (this._mode == IFPathTool.Mode.Prepend) {\n                this._editPt.setProperty('cl', null);\n            }\n        } else {\n            var transformToNewPos = this._pathEditor.getTransformFromNative(this._view.getWorldTransform());\n            var sourcePos = new IFPoint(this._editPt.getProperty('x'), this._editPt.getProperty('y'));\n            sourcePos = transformToNewPos.mapPoint(sourcePos);\n            var newVal = ifMath.ptDist(sourcePos.getX(), sourcePos.getY(), newPos.getX(), newPos.getY());\n\n            if (this._mode == IFPathTool.Mode.Append) {\n                this._editPt.setProperty('cr', newVal);\n            } else if (this._mode == IFPathTool.Mode.Prepend) {\n                this._editPt.setProperty('cl', newVal);\n            }\n        }\n    };\n\n    /**\n     * This function should be called only if mouse dragging of a point is started.\n     * It updates edited point's handles or shoulders to correspond to new position.\n     * Position is constrained and snapped to guides if needed.\n     * @param {IFPoint} clickPt - new position\n     * @returns {IFPoint} - modified new position, if it was constrained or snapped to guides\n     * @private\n     */\n    IFPenTool.prototype._updatePointProperties = function(clickPt) {\n        var newPos = clickPt;\n\n        // No need to check _pathEditor and _editPt for null here,\n        // as this function is called only when dragging is started, and they are already checked\n        this._pathEditor.requestInvalidation();\n        if (this._editPt.getProperty('tp') == IFPathBase.CornerType.Rounded) {\n            this._updateShoulders(clickPt);\n        } else {\n            var newPos = this._constrainIfNeeded(\n                clickPt, this._view.getWorldTransform(), this._pathRef, this._dragStartPt);\n\n            // Don't perform handles mapping for now\n            /*\n            this._editor.getGuides().beginMap();\n\n            newPos = this._view.getWorldTransform().mapPoint(\n                this._editor.getGuides().mapPoint(\n                    this._view.getViewTransform().mapPoint(newPos)));\n            */\n            this._updateHandles(newPos);\n            //this._editor.getGuides().finishMap();\n        }\n\n        return newPos;\n    };\n\n    /** override */\n    IFPenTool.prototype.toString = function () {\n        return \"[Object IFPenTool]\";\n    };\n\n    _.IFPenTool = IFPenTool;\n})(this);\n"
  },
  {
    "path": "src/infinity-editor/tool/pointertool.js",
    "content": "(function (_) {\n    /**\n     * The pointer selection tool\n     * @class IFPointerTool\n     * @extends IFSelectTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFPointerTool() {\n        IFSelectTool.call(this);\n    };\n\n    IFObject.inherit(IFPointerTool, IFSelectTool);\n\n    /** override */\n    IFPointerTool.prototype.toString = function () {\n        return \"[Object IFPointerTool]\";\n    };\n\n    _.IFPointerTool = IFPointerTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/polygontool.js",
    "content": "(function (_) {\n    /**\n     * The polygon tool\n     * @class IFPolygonTool\n     * @extends IFShapeTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFPolygonTool() {\n        IFShapeTool.call(this, false, false);\n    }\n\n    IFObject.inherit(IFPolygonTool, IFShapeTool);\n\n    /**\n     * @type {number}\n     * @private\n     */\n    IFPolygonTool.prototype._numberOfPoints = 6;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    IFPolygonTool.prototype._innerRadiusFactor = 0.5;\n\n    /** @override */\n    IFPolygonTool.prototype._modifiersChanged = function (event) {\n        if (event.changed.shiftKey || event.changed.optionKey) {\n            this._invalidateShape();\n        }\n        IFShapeTool.prototype._modifiersChanged.call(this, event);\n    };\n\n    /** @override */\n    IFPolygonTool.prototype._createShape = function () {\n        return new IFPolygon();\n    };\n\n    /** @override */\n    IFPolygonTool.prototype._updateShape = function (shape, area, line) {\n        var deltaX = line[1].getX() - line[0].getX();\n        var deltaY = line[1].getY() - line[0].getY();\n        var angle = ifMath.normalizeAngleRadians(Math.atan2(deltaY, deltaX));\n        var distance = ifMath.ptDist(line[1].getX(), line[1].getY(), line[0].getX(), line[0].getY());\n\n        // Lock angle to 15° if desired\n        if (ifPlatform.modifiers.shiftKey) {\n            angle = Math.round(angle * 12 / Math.PI) * Math.PI / 12;\n        }\n\n        var outerAngle = angle;\n        var innerAngle = ifMath.normalizeAngleRadians(angle + Math.PI / this._numberOfPoints);\n\n        var outerRadius = distance;\n        var innerRadius = distance * Math.cos(Math.PI / this._numberOfPoints);\n\n        if (ifPlatform.modifiers.optionKey) {\n            innerRadius = distance * this._innerRadiusFactor;\n        }\n\n        shape.setProperties(['pts', 'cx', 'cy', 'ir', 'or', 'ia', 'oa'],\n            [this._numberOfPoints, line[0].getX(), line[0].getY(), innerRadius, outerRadius, innerAngle, outerAngle]);\n    };\n\n    /** @override */\n    IFPolygonTool.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** override */\n    IFPolygonTool.prototype.toString = function () {\n        return \"[Object IFPolygonTool]\";\n    };\n\n    _.IFPolygonTool = IFPolygonTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/rectangletool.js",
    "content": "(function (_) {\n    /**\n     * The rectangle tool\n     * @class IFRectangleTool\n     * @extends IFShapeTool\n     * @constructor\n     */\n    function IFRectangleTool() {\n        IFShapeTool.call(this, true, true);\n    }\n\n    IFObject.inherit(IFRectangleTool, IFShapeTool);\n\n    /** @override */\n    IFRectangleTool.prototype._createShape = function () {\n        return new IFRectangle();\n    };\n\n    /** @override */\n    IFRectangleTool.prototype._updateShape = function (shape, area, line) {\n        // Original shape is a rectangle with coordinates x,y: [-1, 1]. Transform it to fit into the area:\n        shape.setProperty('trf',\n            new IFTransform(area.getWidth() / 2, 0, 0, area.getHeight() / 2,\n                area.getX() + area.getWidth() / 2, area.getY() + area.getHeight() / 2));\n    };\n\n    /** @override */\n    IFRectangleTool.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** override */\n    IFRectangleTool.prototype.toString = function () {\n        return \"[Object IFRectangleTool]\";\n    };\n\n    _.IFRectangleTool = IFRectangleTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/selecttool.js",
    "content": "(function (_) {\n    /**\n     * The mighty (base) selection tool\n     * @class IFSelectTool\n     * @extends IFTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFSelectTool() {\n        IFTool.call(this);\n    };\n\n    IFObject.inherit(IFSelectTool, IFTool);\n\n    /**\n     * @enum\n     * @private\n     */\n    IFSelectTool._Mode = {\n        /** Selecting something */\n        Select: 1,\n        /** Prepared for moving */\n        Move: 2,\n        /** Actually moving something */\n        Moving: 3,\n        /** Transforming via transform box */\n        Transforming: 4\n    };\n\n    /**\n     * The current selection area\n     * @type {IFRect}\n     * @private\n     */\n    IFSelectTool.prototype._selectArea = null;\n\n    /**\n     * The current mode\n     * @type {Number}\n     * @see IFSelectTool._Mode\n     * @private\n     */\n    IFSelectTool.prototype._mode = null;\n\n    /**\n     * An element that was hit when the the mouse was down\n     * and no editor part has been hit. This will not be cleared\n     * before the next mouse down signal.\n     * @type {IFElement}\n     * @private\n     */\n    IFSelectTool.prototype._elementUnderMouse = null;\n\n    /**\n     * An editor part that is under mouse if not moving / dragging\n     * @type {*}\n     * @private\n     */\n    IFSelectTool.prototype._editorUnderMouseInfo = null;\n\n    /**\n     * An editor part that triggered a move\n     * @type {*}\n     * @private\n     */\n    IFSelectTool.prototype._editorMovePartInfo = null;\n\n    /**\n     * The current key delta\n     * @type {IFPoint}\n     * @private\n     */\n    IFSelectTool.prototype._keyDelta = null;\n\n    /**\n     * The start position of moving\n     * @type {IFPoint}\n     * @private\n     */\n    IFSelectTool.prototype._moveStart = null;\n    IFSelectTool.prototype._moveStartTransformed = null;\n\n    /**\n     * The current position of moving\n     * @type {IFPoint}\n     * @private\n     */\n    IFSelectTool.prototype._moveCurrent = null;\n\n    /**\n     * An array of vusial lines ends, which are used to show snap zones\n     * @type {Array<Array<IFPoint>>} - line ends in view coordinates\n     * @private\n     */\n    IFSelectTool.prototype._visuals = null;\n\n    /**\n     * Area, which is used for painting and cleaning lines of snap zones\n     * @type {IFRect} - visuals area in view coordinates\n     * @private\n     */\n    IFSelectTool.prototype._visualsArea = null;\n\n    /** @override */\n    IFSelectTool.prototype.getCursor = function () {\n        return this._editorUnderMouseInfo ? IFCursor.SelectDot : IFCursor.Select;\n    };\n\n    /** @override */\n    IFSelectTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        view.addEventListener(GUIMouseEvent.DragStart, this._mouseDragStart, this);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd, this);\n        view.addEventListener(GUIMouseEvent.Down, this._mouseDown, this);\n        view.addEventListener(GUIMouseEvent.Release, this._mouseRelease, this);\n        view.addEventListener(GUIMouseEvent.Move, this._mouseMove, this);\n        view.addEventListener(GUIMouseEvent.DblClick, this._mouseDblClick, this);\n        view.addEventListener(GUIKeyEvent.Down, this._keyDown, this);\n        view.addEventListener(GUIKeyEvent.Release, this._keyRelease, this);\n\n        ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n    };\n\n    /** @override */\n    IFSelectTool.prototype.deactivate = function (view) {\n        if (this._visualsArea) {\n            this.invalidateArea(this._visualsArea);\n            this._visualsArea = null;\n        }\n\n        if (this._mode === IFSelectTool._Mode.Transforming) {\n            this._closeTransformBox();\n        }\n\n        view.removeEventListener(GUIMouseEvent.DragStart, this._mouseDragStart);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd);\n        view.removeEventListener(GUIMouseEvent.Down, this._mouseDown);\n        view.removeEventListener(GUIMouseEvent.Release, this._mouseRelease);\n        view.removeEventListener(GUIMouseEvent.Move, this._mouseMove);\n        view.removeEventListener(GUIMouseEvent.DblClick, this._mouseDblClick);\n        view.removeEventListener(GUIKeyEvent.Down, this._keyDown);\n        view.removeEventListener(GUIKeyEvent.Release, this._keyRelease);\n\n        ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n\n        IFTool.prototype.deactivate.call(this, view);\n    };\n\n    /** @override */\n    IFSelectTool.prototype.isDeactivatable = function () {\n        // cannot deactivate while having any mode set except\n        // if in transforming mode which will de-activate the transform mode\n        // in our deactivate event\n        return !this._mode || this._mode === IFSelectTool._Mode.Transforming;\n    };\n\n    /** @override */\n    IFSelectTool.prototype.paint = function (context) {\n        if (this._mode == IFSelectTool._Mode.Select && this._hasSelectArea()) {\n            var x = Math.floor(this._selectArea.getX()) + 0.5;\n            var y = Math.floor(this._selectArea.getY()) + 0.5;\n            var w = Math.ceil(this._selectArea.getWidth()) - 1.0;\n            var h = Math.ceil(this._selectArea.getHeight()) - 1.0;\n            context.canvas.strokeRect(x, y, w, h, 1, context.selectionOutlineColor);\n        }\n        if (this._visuals) {\n            var visLine;\n            for (var i = 0; i < this._visuals.length; ++i) {\n                visLine = this._visuals[i];\n                var pt0 = visLine[0];\n                var pt1 = visLine[1];\n                context.canvas.strokeLine(Math.floor(pt0.getX()) + 0.5, Math.floor(pt0.getY()) + 0.5,\n                    Math.floor(pt1.getX()) + 0.5, Math.floor(pt1.getY()) + 0.5, 1, context.highlightOutlineColor);\n            }\n\n            this._visuals = null;\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Move} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseMove = function (event) {\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n            this._updateMode(IFSelectTool._Mode.Transforming);\n        }\n        this._updateEditorUnderMouse(event.client);\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseDown = function (event) {\n        // Quit if not hitting the left-mouse-button\n        if (event.button !== GUIMouseEvent.BUTTON_LEFT) {\n            return;\n        }\n\n        // If we have an inline editor, close it and be done with\n        // it here to keep the original selection\n        if (this._editor.closeInlineEditor()) {\n            return;\n        }\n\n        this._elementUnderMouse = null;\n\n        // Let editor do some work for mouse position\n        this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n            if (this._mode != IFSelectTool._Mode.Transforming) {\n                this._updateMode(IFSelectTool._Mode.Transforming);\n            }\n            // Transform box always returns non-null partInfo\n            this._editorMovePartInfo = sceneEditor.getTBoxPartInfoAt(event.client,\n                this._view.getWorldTransform(), this._scene.getProperty('pickDist'));\n        } else {\n            // Reset to select mode here\n            this._updateMode(IFSelectTool._Mode.Select);\n\n            // We're doing a stacked hit-test when the meta is key is hold down and\n            // when our manager has no temporary tool as in such case, we've been\n            // activated temporarily with the meta key and should ignore the meta key.\n            // When this is the case, we'll ignore hit-testing the editor(s) at all\n            // and instead, go straight to hit-testing elements instead\n            var stacked = ifPlatform.modifiers.metaKey && this._manager.getTemporaryActiveTool() == null;\n\n            if (!stacked) {\n                // Try to get a part of an editor, first\n                var docEditor = IFElementEditor.getEditor(this._scene);\n                if (docEditor) {\n                    var partInfo = docEditor.getPartInfoAt(event.client, this._view.getWorldTransform(), function (editor) {\n                        // Ensure to allow selected editors for part, only\n                        return editor.hasFlag(IFElementEditor.Flag.Selected);\n                    }.bind(this), this._scene.getProperty('pickDist'));\n\n                    if (partInfo) {\n                        var editor = partInfo.editor;\n                        var partId = partInfo.id;\n                        var selectable = partInfo.selectable;\n\n                        // Only update part selection if we're either holding shift\n                        // or when we didn't actually retreieve an already selected part\n                        if (ifPlatform.modifiers.shiftKey || (!editor.isPartSelected(partId) && selectable)) {\n                            editor.updatePartSelection(ifPlatform.modifiers.shiftKey, [partId]);\n                        }\n\n                        // Save the editor part that initiated the movement\n                        if (!selectable || editor.isPartSelected(partId)) {\n                            this._editorMovePartInfo = partInfo;\n                        }\n\n                        // Set mode to move\n                        this._updateMode(IFSelectTool._Mode.Move);\n                    }\n                }\n            }\n        }\n\n        // If we didn't receive an editor part then do our regular stuff here\n        if (this._mode === IFSelectTool._Mode.Select) {\n            // Test selection at first, and if hit, leave it as is\n            var selection = this._editor.getSelection();\n            var selectableElements = [];\n            var element;\n            var hitRes = null;\n            if (selection && selection.length && !stacked) {\n                for (var i = 0; i < selection.length && !hitRes; ++i) {\n                    if (selection[i] instanceof IFElement) {\n                        element = selection[i];\n                        hitRes = element.hitTest(event.client, this._view.getWorldTransform(), null,\n                            stacked, -1, this._scene.getProperty('pickDist'), true);\n                    }\n                }\n            }\n            if (hitRes) {\n                selectableElements.push(element);\n            } else {\n                var elementHits = this._scene.hitTest(event.client, this._view.getWorldTransform(), null,\n                    stacked, -1, this._scene.getProperty('pickDist'));\n\n                // Convert element hits if any into an array of pure elements\n                // and gather the selectable elements from it\n                if (elementHits) {\n                    var elements = [];\n                    for (var i = 0; i < elementHits.length; ++i) {\n                        elements.push(elementHits[i].element);\n                    }\n                    selectableElements = this._getSelectableElements(elements);\n                }\n            }\n\n            if (selectableElements.length > 0) {\n                // The element hit array can only contain more than one hit\n                // if we're in stacked mode, otherwise it will always contain\n                // approximately one (the topmost) hit element so it is safe\n                // to check for the length here and act differently\n                if (selectableElements.length > 1) {\n                    // Iterate all of our hits and select either one deeper than\n                    // than the current selection or start from the beginning\n                    var lastSelIndex = null;\n                    for (var i = 0; i < selectableElements.length; ++i) {\n                        if (selectableElements[i].hasFlag(IFNode.Flag.Selected)) {\n                            lastSelIndex = i;\n                        }\n                    }\n\n                    if (lastSelIndex == null || lastSelIndex + 1 >= selectableElements.length) {\n                        // Start from the beginning\n                        this._editor.updateSelection(ifPlatform.modifiers.shiftKey, [selectableElements[0]]);\n                    } else {\n                        // Select next in order\n                        this._editor.updateSelection(ifPlatform.modifiers.shiftKey, [selectableElements[lastSelIndex + 1]]);\n                    }\n\n                } else {\n                    this._elementUnderMouse = selectableElements[0];\n\n                    if (ifPlatform.modifiers.shiftKey || !this._elementUnderMouse.hasFlag(IFNode.Flag.Selected)) {\n                        // Only update selection if we're either holding shift\n                        // or when we didn't actually hit an already selected node\n                        this._editor.updateSelection(ifPlatform.modifiers.shiftKey, [this._elementUnderMouse]);\n                    } else if (this._elementUnderMouse.hasFlag(IFNode.Flag.Selected)) {\n                        // As element is already selected we need to ensure to properly\n                        // clear all selected parts as that is the default behavior\n                        var editor = IFElementEditor.getEditor(this._elementUnderMouse);\n                        if (editor) {\n                            editor.updatePartSelection(false, null);\n                        }\n                    }\n\n                    // Switch to move mode if there's any selection in editor\n                    selection = this._editor.getSelection();\n                    if (selection && selection.length > 0) {\n                        this._updateMode(IFSelectTool._Mode.Move);\n                    }\n                }\n            } else {\n                // No hit at all so update without any nodes\n                this._editor.updateSelection(ifPlatform.modifiers.shiftKey, []);\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseRelease = function (event) {\n        // Reset some stuff in any case\n        this._editorMovePartInfo = null;\n        this._moveStart = null;\n        this._moveStartTransformed = null;\n        this._moveCurrent = null;\n        if (this._mode != IFSelectTool._Mode.Transforming) {\n            this._updateMode(null);\n        }\n        this._updateEditorUnderMouse(event.client);\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragStart} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseDragStart = function (event) {\n        if (this._visualsArea) {\n            this.invalidateArea(this._visualsArea);\n            this._visualsArea = null;\n        }\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n            if (this._mode != IFSelectTool._Mode.Transforming) {\n                sceneEditor.setTransformBoxActive(false);\n                this._updateMode(null);\n            }\n        } else if (this._mode == IFSelectTool._Mode.Transforming) {\n            this._updateMode(null);\n        }\n\n        if (this._mode == IFSelectTool._Mode.Move) {\n            // Save start\n            this._moveStart = event.client;\n            this._moveStartTransformed = this._view.getViewTransform().mapPoint(this._moveStart);\n\n            // Switch to moving mode\n            this._updateMode(IFSelectTool._Mode.Moving);\n        } else if (this._mode == IFSelectTool._Mode.Transforming) {\n            this._moveStart = event.client;\n            this._moveStartTransformed = this._view.getViewTransform().mapPoint(this._moveStart);\n            sceneEditor.startTBoxTransform(this._editorMovePartInfo);\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseDrag = function (event) {\n        if (this._mode == IFSelectTool._Mode.Transforming) {\n            var sceneEditor = IFElementEditor.getEditor(this._scene);\n            if (!sceneEditor || !sceneEditor.isTransformBoxActive()) {\n                this._updateMode(null);\n            }\n        }\n\n        if (this._mode == IFSelectTool._Mode.Moving || this._mode == IFSelectTool._Mode.Transforming) {\n            // Save current\n            this._moveCurrent = event.client;\n\n            // Update transform\n            this._updateSelectionTransform();\n        } else if (this._mode == IFSelectTool._Mode.Select) {\n            if (this._hasSelectArea()) {\n                this.invalidateArea(this._selectArea);\n            }\n\n            this._selectArea = IFRect.fromPoints(event.clientStart, event.client);\n\n            if (this._hasSelectArea()) {\n                this.invalidateArea(this._selectArea);\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragEnd} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseDragEnd = function (event) {\n        if (this._mode == IFSelectTool._Mode.Moving) {\n            if (this._editorMovePartInfo && this._editorMovePartInfo.isolated) {\n                this._editor.beginTransaction();\n                try {\n                    this._editorMovePartInfo.editor.applyPartMove(this._editorMovePartInfo.id, this._editorMovePartInfo.data);\n                } finally {\n                    var nodeNameTranslated = this._editorMovePartInfo.editor.getElement().getNodeNameTranslated();\n\n                    // TODO : I18N\n                    if (!nodeNameTranslated) {\n                        nodeNameTranslated = 'Element';\n                    }\n                    this._editor.commitTransaction('Modify ' + nodeNameTranslated);\n                }\n            } else {\n                // Holding option key when we've transformed the whole selection\n                // will actually clone the current selection and apply the transformation\n                // to the new selection so we'll do that here\n                this._editor.applySelectionTransform(ifPlatform.modifiers.optionKey);\n            }\n        } else if (this._mode == IFSelectTool._Mode.Select) {\n            // Check if we've selected an area\n            if (this._hasSelectArea()) {\n                // our area selector selected something\n                var mappedSelectArea = this._view.getViewTransform().mapRect(this._selectArea);\n                var x0 = mappedSelectArea.getX(), y0 = mappedSelectArea.getY();\n                var x2 = x0 + mappedSelectArea.getWidth(), y2 = y0 + mappedSelectArea.getHeight();\n                var collisionArea = new IFVertexContainer();\n                collisionArea.addVertex(IFVertex.Command.Move, x0, y0);\n                collisionArea.addVertex(IFVertex.Command.Line, x2, y0);\n                collisionArea.addVertex(IFVertex.Command.Line, x2, y2);\n                collisionArea.addVertex(IFVertex.Command.Line, x0, y2);\n                collisionArea.addVertex(IFVertex.Command.Close, 0, 0);\n                var collisions = this._scene.getCollisions(collisionArea, IFElement.CollisionFlag.GeometryBBox);\n                var selectableElements = this._getSelectableElements(collisions);\n\n                this._editor.updateSelection(ifPlatform.modifiers.shiftKey, selectableElements);\n\n                // Invalidate to remove area selector's paint region\n                var selectArea = this._selectArea;\n                this._selectArea = null;\n                this.invalidateArea(selectArea);\n            } else {\n                this._selectArea = null;\n            }\n        } else if (this._mode == IFSelectTool._Mode.Transforming) {\n            var sceneEditor = IFElementEditor.getEditor(this._scene);\n            if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n                sceneEditor.applyTBoxTransform(ifPlatform.modifiers.optionKey);\n                this.invalidateArea();\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.DblClick} event\n     * @private\n     */\n    IFSelectTool.prototype._mouseDblClick = function (event) {\n        // Close an existing transform box, first\n        if (!this._closeTransformBox()) {\n            var openTransformBox = true;\n\n            // Check whether to start inline editing\n            if (this._elementUnderMouse) {\n                if (this._editor.openInlineEditor(this._elementUnderMouse, this._view, event.client)) {\n                    openTransformBox = false;\n                }\n            }\n\n            if (openTransformBox) {\n                this._openTransformBox();\n            }\n        }\n    };\n\n    /**\n     * @param {GUIKeyEvent} evt\n     * @private\n     */\n    IFSelectTool.prototype._keyDown = function (evt) {\n        if (evt.key === IFKey.Constant.UP || evt.key === IFKey.Constant.DOWN ||\n            evt.key === IFKey.Constant.LEFT || evt.key === IFKey.Constant.RIGHT) {\n\n            // Shift selection if any\n            if (this._editor.hasSelection() && (!this._mode || this._mode === IFSelectTool._Mode.Moving)) {\n                if (this._mode !== IFSelectTool._Mode.Moving) {\n                    this._updateMode(IFSelectTool._Mode.Moving);\n                }\n\n                var crDistance = ifPlatform.modifiers.shiftKey ?\n                    this._scene.getProperty('crDistBig') : this._scene.getProperty('crDistSmall');\n\n                var dx = 0;\n                var dy = 0;\n                switch (evt.key) {\n                    case IFKey.Constant.UP:\n                        dy -= crDistance;\n                        break;\n                    case IFKey.Constant.DOWN:\n                        dy += crDistance;\n                        break;\n                    case IFKey.Constant.LEFT:\n                        dx -= crDistance;\n                        break;\n                    case IFKey.Constant.RIGHT:\n                        dx += crDistance;\n                        break;\n                    default:\n                        break;\n                }\n\n                this._keyDelta = this._keyDelta ? this._keyDelta.add(new IFPoint(dx, dy)) : new IFPoint(dx, dy);\n                this._editor.moveSelection(this._keyDelta, false);\n            }\n        }\n    };\n\n    /**\n     * @param {GUIKeyEvent} evt\n     * @private\n     */\n    IFSelectTool.prototype._keyRelease = function (evt) {\n        if (evt.key === IFKey.Constant.UP || evt.key === IFKey.Constant.DOWN ||\n            evt.key === IFKey.Constant.LEFT || evt.key === IFKey.Constant.RIGHT) {\n\n            // Apply transformation applied through keys if any and reset it\n            if (this._keyDelta) {\n                this._editor.applySelectionTransform();\n                this._keyDelta = null;\n                this._updateMode(null);\n            }\n        }\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFSelectTool.prototype._modifiersChanged = function (event) {\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n            if (this._mode != IFSelectTool._Mode.Transforming) {\n                this._updateMode(IFSelectTool._Mode.Transforming);\n            }\n        } else if (this._mode == IFSelectTool._Mode.Transforming) {\n            this._updateMode(null);\n        }\n\n        if ((event.changed.shiftKey || event.changed.optionKey || event.changed.metaKey) &&\n            (this._mode === IFSelectTool._Mode.Moving || this._mode == IFSelectTool._Mode.Transforming)) {\n\n            this._updateSelectionTransform();\n        }\n    };\n\n    /**\n     * Close the transform box if it is open\n     * @return {Boolean} true if a transform box was opened and got\n     * closed, false if not\n     * @private\n     */\n    IFSelectTool.prototype._closeTransformBox = function () {\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n            sceneEditor.setTransformBoxActive(false);\n            this._updateMode(null);\n            this.invalidateArea();\n            this.updateCursor();\n            return true;\n        }\n        return false;\n    };\n\n    /**\n     * Open the transform box if it is not yet open\n     * @private\n     */\n    IFSelectTool.prototype._openTransformBox = function () {\n        var sceneEditor = IFElementEditor.getEditor(this._scene);\n        sceneEditor = sceneEditor ? sceneEditor : IFElementEditor.openEditor(this._scene);\n        sceneEditor.setTransformBoxActive(true);\n        if (sceneEditor.isTransformBoxActive()) {\n            // Switch to transformation mode\n            this._updateMode(IFSelectTool._Mode.Transforming);\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFSelectTool.prototype._updateSelectionTransform = function () {\n        if (this._mode == IFSelectTool._Mode.Moving) {\n            var position = this._moveCurrent;\n            if (this._editorMovePartInfo && this._editorMovePartInfo.isolated) {\n                this._editor.getGuides().getShapeBoxGuide().useExclusions(this._editor.getSelection());\n                this._editor.getGuides().beginMap();\n                this._editorMovePartInfo.editor.movePart(this._editorMovePartInfo.id, this._editorMovePartInfo.data,\n                    position, this._view.getViewTransform(), this._editor.getGuides(), ifPlatform.modifiers.shiftKey, ifPlatform.modifiers.optionKey);\n                this._editor.getGuides().finishMap();\n            } else {\n                if (ifPlatform.modifiers.shiftKey) {\n                    // Calculate move delta by locking our vector to 45° steps starting with constraint\n                    var crConstraint = this._scene.getProperty('crConstraint');\n                    position = ifMath.convertToConstrain(this._moveStart.getX(), this._moveStart.getY(),\n                        position.getX(), position.getY(), crConstraint);\n                }\n\n                position = this._view.getViewTransform().mapPoint(position);\n                if (this._editorMovePartInfo && this._editorMovePartInfo.id &&\n                    (this._editorMovePartInfo.id.type == IFPathEditor.PartType.Point ||\n                        this._editorMovePartInfo.id.type == IFPathEditor.PartType.Segment)) {\n\n                    this._editor.getGuides().beginMap();\n                    position = this._editor.getGuides().mapPoint(position);\n                    this._editor.getGuides().finishMap();\n\n                    var moveDelta = position.subtract(this._moveStartTransformed);\n                    if (this._editorMovePartInfo.id.type == IFPathEditor.PartType.Point) {\n                        var moveStart = this._editorMovePartInfo.editor.getPointCoord(this._editorMovePartInfo.id.point);\n                        moveDelta = position.subtract(moveStart);\n                    }\n                    this._editor.moveSelection(moveDelta, false,\n                        this._editorMovePartInfo ? this._editorMovePartInfo.id : null, this._editorMovePartInfo ? this._editorMovePartInfo.data : null);\n\n                } else {\n                    var moveDelta = position.subtract(this._moveStartTransformed);\n                    this._editor.moveSelection(moveDelta, true,\n                        this._editorMovePartInfo ? this._editorMovePartInfo.id : null,\n                        this._editorMovePartInfo ? this._editorMovePartInfo.data : null,\n                        this._moveStartTransformed);\n                }\n            }\n        } else if (this._mode == IFSelectTool._Mode.Transforming) {\n            var sceneEditor = IFElementEditor.getEditor(this._scene);\n            if (sceneEditor && sceneEditor.isTransformBoxActive() && this._moveStart) {\n                var moveCurrentTransformed = this._view.getViewTransform().mapPoint(this._moveCurrent);\n                sceneEditor.transformTBox(this._moveStartTransformed, moveCurrentTransformed,\n                    ifPlatform.modifiers.optionKey, ifPlatform.modifiers.shiftKey);\n\n                this.invalidateArea();\n            }\n        }\n    };\n\n    /**\n     * Called to update the current mode\n     * @param {IFSelectTool._Mode} mode\n     * @private\n     */\n    IFSelectTool.prototype._updateMode = function (mode) {\n        if (mode !== this._mode) {\n            this._mode = mode;\n        }\n    };\n\n    /**\n     * Updates the editor under given mouse client coordinates\n     * @param {IFPoint} mouse mouse client coordinates\n     * @private\n     */\n    IFSelectTool.prototype._updateEditorUnderMouse = function (mouse) {\n        var hasEditorInfoUnderMouse = false;\n        this._visuals = null;\n\n        if (this._mode == IFSelectTool._Mode.Transforming) {\n            var sceneEditor = IFElementEditor.getEditor(this._scene);\n            if (sceneEditor && sceneEditor.isTransformBoxActive()) {\n                if (this._editorUnderMouseInfo) {\n                    this._editorUnderMouseInfo = null;\n                }\n                sceneEditor.updateTBoxUnderMouse(mouse, this._view.getWorldTransform(), this._view);\n                hasEditorInfoUnderMouse = true;\n            } else {\n                this._updateMode(null);\n            }\n        }\n\n        // Hit-Test editor under mouse if not in any mode\n        var partInfo = null;\n        if (!this._mode) {\n            var docEditor = IFElementEditor.getEditor(this._scene);\n            if (docEditor) {\n                partInfo = docEditor.getPartInfoAt(mouse, this._view.getWorldTransform(), function (editor) {\n                    // Ensure to allow selected editors for part, only\n                    return editor.hasFlag(IFElementEditor.Flag.Selected);\n                }.bind(this), this._scene.getProperty('pickDist'));\n\n                if (partInfo !== this._editorUnderMouseInfo) {\n                    this._editorUnderMouseInfo = partInfo;\n                    hasEditorInfoUnderMouse = true;\n                    this.updateCursor();\n                }\n            }\n        }\n\n        var bBox = null;\n        this._visuals = null;\n        if (!this._mode && !partInfo || this._mode == IFSelectTool._Mode.Select) {\n            var selection = this._editor.getSelection();\n            var selectableElements = [];\n            var item;\n            var hitRes = null;\n            var stacked = false;\n            if (selection && selection.length == 1 && selection[0] instanceof IFItem) {\n                hitRes = selection[0].hitTest(mouse, this._view.getWorldTransform(), null,\n                    stacked, -1, this._scene.getProperty('pickDist'), true);\n                if (hitRes) {\n                    item = selection[0];\n                }\n            }\n            if (!item) {\n                var elementHits = this._scene.hitTest(mouse, this._view.getWorldTransform(), null,\n                    stacked, -1, this._scene.getProperty('pickDist'));\n\n                if (elementHits && elementHits.length) {\n                    for (var i = 0; i < elementHits.length && !item; ++i) {\n                        if (elementHits[i].element instanceof IFItem && !elementHits[i].element.hasFlag(IFNode.Flag.Selected)) {\n                            item = elementHits[i].element;\n                        }\n                    }\n                }\n            }\n            if (item) {\n                bBox = item.getGeometryBBox();\n                if (bBox && !bBox.isEmpty()) {\n                    bBox = this._view.getWorldTransform().mapRect(bBox);\n                    var visuals = this._editor.getGuides().getBBoxSnapZones(bBox, mouse);\n                    if (visuals && visuals.length) {\n                        this._visuals = visuals;\n                    }\n                }\n            }\n        }\n\n        if (!hasEditorInfoUnderMouse && this._editorUnderMouseInfo) {\n            this._editorUnderMouseInfo = null;\n            this.updateCursor();\n        }\n\n        var visualsArea = this._visuals ? bBox.expanded(2, 2, 2, 2) : null;\n        if (this._visualsArea || visualsArea) {\n            if (this._visualsArea) {\n                this.invalidateArea(this._visualsArea);\n            }\n            if (visualsArea) {\n                this.invalidateArea(visualsArea);\n            }\n            this._visualsArea = visualsArea;\n        }\n    };\n\n    /**\n     * Iterate and returns an array of selectable elements from\n     * an source array of elements in their original order\n     * @param {Array<IFElement>} elements source array of elements\n     * @returns {Array<IFElement>} array of selectable elements or\n     * an empty array for none\n     * @private\n     */\n    IFSelectTool.prototype._getSelectableElements = function (elements) {\n        var selectableElements = [];\n        for (var i = 0; i < elements.length; ++i) {\n            var selectableElement = this._getSelectableElement(elements[i]);\n            if (selectableElement && selectableElements.indexOf(selectableElement) < 0) {\n                selectableElements.push(selectableElement);\n            }\n        }\n        return selectableElements;\n    };\n\n    /**\n     * Returns the selectable element out of an given one or null\n     * if the given one is not selectable at all.\n     * @param {IFElement} element\n     * @return {IFElement}\n     * @private\n     */\n    IFSelectTool.prototype._getSelectableElement = function (element) {\n        // By default, we allow only items to be selected.\n        // Furthermore, we'll iterate up until we'll find the root\n        // item residing within anything else than another item\n        for (var p = element; p !== null; p = p.getParent()) {\n            if (p instanceof IFItem && (!p.getParent() || !(p.getParent() instanceof IFItem))) {\n                return p;\n            }\n        }\n\n        return null;\n    };\n\n    /** @private **/\n    IFSelectTool.prototype._hasSelectArea = function () {\n        return (this._selectArea && (this._selectArea.getHeight() > 0 || this._selectArea.getWidth() > 0));\n    };\n\n    /** override */\n    IFSelectTool.prototype.toString = function () {\n        return \"[Object IFSelectTool]\";\n    };\n\n    _.IFSelectTool = IFSelectTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/shapetool.js",
    "content": "(function (_) {\n    /**\n     * The base tool for simple shapes based on IFShape\n     * @param {Boolean} keepRatio if true, the ratio\n     * on width/height will be kept if user holds shift-modifier key\n     * @param {Boolean} allowFromCenter if true, the drag\n     * area will be calculated from center and goes into each\n     * direction if user holds option-modifier key\n     * @class IFShapeTool\n     * @extends IFTool\n     * @constructor\n     */\n    function IFShapeTool(keepRatio, fromCenter) {\n        IFTool.call(this);\n        this._keepRatio = keepRatio;\n        this._fromCenter = fromCenter;\n    }\n\n    IFObject.inherit(IFShapeTool, IFTool);\n\n    /**\n     * Options for shape tools\n     * @version 1.0\n     */\n    IFShapeTool.options = {\n        /**\n         * The size of the center cross if any,\n         * should be an even number\n         * @type Number\n         * @version 1.0\n         */\n        centerCrossSize: 4\n    };\n\n    /**\n     * Dragging start position in scene coordinates\n     * @type {IFPoint}\n     * @private\n     */\n    IFShapeTool.prototype._dragStart = null;\n\n    /**\n     * Dragging current position in scene coordinates\n     * @type {IFPoint}\n     * @private\n     */\n    IFShapeTool.prototype._dragCurrent = null;\n\n    /**\n     * Whether to keep ratio or not\n     * @type {Boolean}\n     * @private\n     */\n    IFShapeTool.prototype._keepRatio = false;\n\n    /**\n     * Whether to calculate from center or not\n     * @type {Boolean}\n     * @private\n     */\n    IFShapeTool.prototype._fromCenter = false;\n\n    /**\n     * @type {IFShape}\n     * @private\n     */\n    IFShapeTool.prototype._shape = null;\n\n    /**\n     * Current drag area in scene coordinates\n     * @type {IFRect}\n     * @private\n     */\n    IFShapeTool.prototype._dragArea = null;\n\n    /**\n     * Current drag line in scene coordinates\n     * @type {Array<IFPoint>}\n     * @private\n     */\n    IFShapeTool.prototype._dragLine = null;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    IFShapeTool.prototype._hasCreatedShape = false;\n\n    /** @override */\n    IFShapeTool.prototype.getCursor = function () {\n        return IFCursor.Cross;\n    };\n\n    /** @override */\n    IFShapeTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        view.addEventListener(GUIMouseEvent.Move, this._mouseMove, this);\n        view.addEventListener(GUIMouseEvent.DragStart, this._mouseDragStart, this);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd, this);\n        view.addEventListener(GUIMouseEvent.Down, this._mouseDown, this);\n        view.addEventListener(GUIMouseEvent.Release, this._mouseRelease, this);\n\n        ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n    };\n\n    /** @override */\n    IFShapeTool.prototype.deactivate = function (view) {\n        IFTool.prototype.deactivate.call(this, view);\n\n        view.removeEventListener(GUIMouseEvent.Move, this._mouseMove, this);\n        view.removeEventListener(GUIMouseEvent.DragStart, this._mouseDragStart);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd);\n        view.removeEventListener(GUIMouseEvent.Down, this._mouseDown);\n        view.removeEventListener(GUIMouseEvent.Release, this._mouseRelease);\n\n        ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n    };\n\n    /** @override */\n    IFShapeTool.prototype.isDeactivatable = function () {\n        // cannot deactivate while dragging\n        return this._dragStart ? false : true;\n    };\n\n    /** @override */\n    IFShapeTool.prototype.paint = function (context) {\n        if (this._shape) {\n            // Alignment here affects ellipses and handles of curves contained in ellipses,\n            // but this is not noticeable, as it is a shape creation and line is just 1 pt width at any zoom\n            this._paintOutline(context);\n\n            // Paint center cross if desired\n            if (this._hasCenterCross()) {\n                var geometryBBox = this._shape.getGeometryBBox();\n                var crossSizeMax = IFShapeTool.options.centerCrossSize * 4;\n\n                if (geometryBBox && !geometryBBox.isEmpty() &&\n                    geometryBBox.getWidth() > crossSizeMax && geometryBBox.getHeight() > crossSizeMax) {\n                    var cs = IFShapeTool.options.centerCrossSize / 2 + 0.5;\n                    var cp = geometryBBox.getSide(IFRect.Side.CENTER);\n                    var cx = Math.floor(cp.getX()) + 0.5;\n                    var cy = Math.floor(cp.getY()) + 0.5;\n\n                    context.canvas.strokeLine(cx - cs, cy - cs, cx + cs, cy + cs, 1, context.selectionOutlineColor);\n                    context.canvas.strokeLine(cx + cs, cy - cs, cx - cs, cy + cs, 1, context.selectionOutlineColor);\n                }\n            }\n        }\n    };\n\n    /** @private */\n    IFShapeTool.prototype._paintOutline = function (context) {\n        context.canvas.putVertices(new IFVertexPixelAligner(this._shape));\n        context.canvas.strokeVertices(context.selectionOutlineColor);\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFShapeTool.prototype._mouseDown = function (event) {\n        // Quit if not hitting the left-mouse-button\n        if (event.button !== GUIMouseEvent.BUTTON_LEFT) {\n            return;\n        }\n\n        // Let editor do some work for mouse position\n        this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFShapeTool.prototype._mouseRelease = function (event) {\n        if (!this._hasCreatedShape) {\n            var position = this._view.getViewTransform().mapPoint(event.client);\n            position = this._editor.getGuides().mapPoint(position);\n            this._createShapeManually(position);\n        }\n        this._hasCreatedShape = false;\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragStart} event\n     * @private\n     */\n    IFShapeTool.prototype._mouseDragStart = function (event) {\n        this._hasCreatedShape = false;\n        this._dragStart = this._view.getViewTransform().mapPoint(event.client);\n        this._editor.getGuides().beginMap();\n        this._dragStart = this._editor.getGuides().mapPoint(this._dragStart);\n        this._editor.getGuides().finishMap();\n\n        // Create our shape when user started dragging\n        this._shape = this._createShape();\n        this._invalidateShape();\n\n        this.updateCursor();\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} event\n     * @private\n     */\n    IFShapeTool.prototype._mouseDrag = function (event) {\n        this._dragCurrent = this._view.getViewTransform().mapPoint(event.client);\n        this._invalidateShape();\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragEnd} event\n     * @private\n     */\n    IFShapeTool.prototype._mouseDragEnd = function (event) {\n        // Reset shape and repaint\n        var shape = this._shape;\n        this._shape = null;\n        this._invalidateShapeArea(shape);\n\n        // Prepare shape for appending\n        this._prepareShapeForAppend(shape);\n\n        // Clear our stuff\n        this._dragStart = null;\n        this._dragCurrent = null;\n        this._shape = null;\n        this._dragArea = null;\n        this._dragLine = null;\n\n        this.updateCursor();\n\n        // Finally insert our shape\n        this._insertShape(shape);\n        this._hasCreatedShape = true;\n    };\n\n    /**\n     * @param {GUIMouseEvent.Move} event\n     * @private\n     */\n    IFShapeTool.prototype._mouseMove = function (event) {\n        // NO-OP\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFShapeTool.prototype._modifiersChanged = function (event) {\n        if ((this._keepRatio && event.changed.shiftKey) ||\n                (this._fromCenter && event.changed.optionKey) ||\n                event.changed.metaKey) {\n\n            this._invalidateShape();\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFShapeTool.prototype._invalidateShape = function () {\n        if (this._dragStart && this._dragCurrent) {\n            this._editor.getGuides().beginMap();\n            var dragCurrent = this._editor.getGuides().mapPoint(this._dragCurrent);\n            this._editor.getGuides().finishMap();\n            if (IFPoint.equals(this._dragStart, dragCurrent)) {\n                this._invalidateShapeArea();\n            } else {\n                var x0 = this._dragStart.getX();\n                var y0 = this._dragStart.getY();\n                var x1 = dragCurrent.getX();\n                var y1 = dragCurrent.getY();\n                var x2 = x1; // for line\n                var y2 = y1; // for line\n\n                if (this._keepRatio && ifPlatform.modifiers.shiftKey) {\n                    var w = Math.abs(x1 - x0);\n                    var h = Math.abs(y1 - y0);\n                    var wSign = x1 < x0 ? -1 : 1;\n                    var hSign = y1 < y0 ? -1 : 1;\n\n                    if (w >= h) {\n                        x1 = x0 + w * wSign;\n                        y1 = y0 + w * hSign;\n                        y2 = (w < 2.0 * h) ? y1 : y0;\n                    } else {\n                        x1 = x0 + h * wSign;\n                        y1 = y0 + h * hSign;\n                        x2 = (h < 2.0 * w) ? x1 : x0;\n                    }\n                }\n\n                /** @type IFRect */\n                var dragArea = null;\n                /** @type Array<IFPoint> */\n                var dragLine = null;\n\n                if (this._fromCenter && ifPlatform.modifiers.optionKey) {\n                    dragArea = IFRect.fromPoints(new IFPoint(x0 - (x1 - x0), y0 - (y1 - y0)), new IFPoint(x0 + (x1 - x0), y0 + (y1 - y0)));\n                    dragLine = [new IFPoint(x0 - (x2 - x0), y0 - (y2 - y0)), new IFPoint(x0 + (x2 - x0), y0 + (y2 - y0))];\n                }\n                else {\n                    dragArea = IFRect.fromPoints(new IFPoint(x0, y0), new IFPoint(x1, y1));\n                    dragLine = [new IFPoint(x0, y0), new IFPoint(x2, y2)];\n                }\n\n                // Assign area and line in scene coordinates\n                this._dragArea = dragArea;\n                this._dragLine = dragLine;\n\n                // Convert area and line into view coordinates before updating the shape\n                var worldTransform = this._view.getWorldTransform();\n                var dragAreaView = worldTransform.mapRect(dragArea);\n                var dragLineView = [worldTransform.mapPoint(dragLine[0]), worldTransform.mapPoint(dragLine[1])];\n\n                this._invalidateShapeArea();\n                this._updateShape(this._shape, dragAreaView, dragLineView, false);\n                this._invalidateShapeArea();\n            }\n        }\n    };\n\n    /**\n     * Called to prepare a shape for appending\n     * @param {IFShape} shape\n     * @private\n     */\n    IFShapeTool.prototype._prepareShapeForAppend = function (shape) {\n        // Update shape with scene coordinates before appending\n        this._updateShape(shape, this._dragArea, this._dragLine, true);\n    };\n\n    /**\n     * Called to insert a given shape\n     * @param {IFShape} shape\n     * @private\n     */\n    IFShapeTool.prototype._insertShape = function (shape) {\n        // Call editor for new insertion\n        this._editor.insertElements([shape]);\n    };\n\n    /**\n     * @param {IFShape} [shape] the shape to invalidate,\n     * if not provided defaults to current shape if any\n     * @private\n     */\n    IFShapeTool.prototype._invalidateShapeArea = function (shape) {\n        shape = shape || this._shape;\n        if (shape) {\n            var geometryBBox = shape.getGeometryBBox();\n            if (geometryBBox && (geometryBBox.getWidth() > 0 || geometryBBox.getHeight() > 0)) {\n                this.invalidateArea(geometryBBox.expanded(1, 1, 1, 1));\n            }\n        }\n    };\n\n    /**\n     * Called to create a shape manually as it has not yet been created via drag\n     * @param {IFPoint} position the position to create the shape at in scene coordinates\n     * @private\n     */\n    IFShapeTool.prototype._createShapeManually = function (position) {\n        // NO-OP\n    };\n\n    /**\n     * Called to create an instance of the shape for this tool\n     * @return {IFShape}\n     * @private\n     */\n    IFShapeTool.prototype._createShape = function () {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to update the shape of this tool\n     * @param {IFShape} shape the shape to update\n     * @param {IFRect} area the shape area\n     * @param {Array<IFPoint>} line the shape line\n     * @param {Boolean} scene true if coordinates are in scene coordinates,\n     * this usually is only the case before the shape gets appended, otherwise\n     * if false, the coordinates are in view coordinates\n     * @private\n     */\n    IFShapeTool.prototype._updateShape = function (shape, area, line, scene) {\n        throw new Error(\"Not Supported.\");\n    };\n\n    /**\n     * Called to check whether a center cross should be painted or not\n     * @return {Boolean} true if a center cross should be painted, false if not (default)\n     * @private\n     */\n    IFShapeTool.prototype._hasCenterCross = function () {\n        return false;\n    };\n\n    /** override */\n    IFShapeTool.prototype.toString = function () {\n        return \"[Object IFShapeTool]\";\n    };\n\n    _.IFShapeTool = IFShapeTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/slicetool.js",
    "content": "(function (_) {\n    /**\n     * The slice tool\n     * @class IFSliceTool\n     * @extends IFTool\n     * @constructor\n     */\n    function IFSliceTool() {\n        IFTool.call(this);\n    }\n\n    IFObject.inherit(IFSliceTool, IFTool);\n\n    /**\n     * Dragging start position in scene coordinates\n     * @type {IFPoint}\n     * @private\n     */\n    IFSliceTool.prototype._dragStart = null;\n\n    /**\n     * Dragging current position in scene coordinates\n     * @type {IFPoint}\n     * @private\n     */\n    IFSliceTool.prototype._dragCurrent = null;\n\n    /**\n     * @type {IFSlice}\n     * @private\n     */\n    IFSliceTool.prototype._slice = null;\n\n    /**\n     * Current drag area in scene coordinates\n     * @type {IFRect}\n     * @private\n     */\n    IFSliceTool.prototype._dragArea = null;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    IFSliceTool.prototype._hasCreatedSlice = false;\n\n    /** @override */\n    IFSliceTool.prototype.getCursor = function () {\n        return IFCursor.Cross;\n    };\n\n    /** @override */\n    IFSliceTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        view.addEventListener(GUIMouseEvent.DragStart, this._mouseDragStart, this);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd, this);\n        view.addEventListener(GUIMouseEvent.Down, this._mouseDown, this);\n        view.addEventListener(GUIMouseEvent.Release, this._mouseRelease, this);\n\n        ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n    };\n\n    /** @override */\n    IFSliceTool.prototype.deactivate = function (view) {\n        IFTool.prototype.deactivate.call(this, view);\n\n        view.removeEventListener(GUIMouseEvent.DragStart, this._mouseDragStart);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd);\n        view.removeEventListener(GUIMouseEvent.Down, this._mouseDown);\n        view.removeEventListener(GUIMouseEvent.Release, this._mouseRelease);\n\n        ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n    };\n\n    /** @override */\n    IFSliceTool.prototype.isDeactivatable = function () {\n        // cannot deactivate while dragging\n        return this._dragStart ? false : true;\n    };\n\n    /** @override */\n    IFSliceTool.prototype.paint = function (context) {\n        if (this._slice) {\n            var sliceBBox = this._slice.getGeometryBBox();\n            sliceBBox = this._view.getWorldTransform().mapRect(sliceBBox);\n            var x = Math.floor(sliceBBox.getX()) + 0.5;\n            var y = Math.floor(sliceBBox.getY()) + 0.5;\n\n            context.canvas.strokeRect(x, y, sliceBBox.getWidth(), sliceBBox.getHeight(), 1, context.selectionOutlineColor);\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Down} event\n     * @private\n     */\n    IFSliceTool.prototype._mouseDown = function (event) {\n        // Quit if not hitting the left-mouse-button\n        if (event.button !== GUIMouseEvent.BUTTON_LEFT) {\n            return;\n        }\n\n        // Let editor do some work for mouse position\n        this._editor.updateByMousePosition(event.client, this._view.getWorldTransform());\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFSliceTool.prototype._mouseRelease = function (event) {\n        if (!this._hasCreatedSlice) {\n            var position = this._view.getViewTransform().mapPoint(event.client);\n            position = this._editor.getGuides().mapPoint(position);\n            \n            // TODO : Create slice via dialog manually at [position] ?\n        }\n        this._hasCreatedSlice = false;\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragStart} event\n     * @private\n     */\n    IFSliceTool.prototype._mouseDragStart = function (event) {\n        this._hasCreatedSlice = false;\n        this._dragStart = this._view.getViewTransform().mapPoint(event.client);\n        this._editor.getGuides().beginMap();\n        this._dragStart = this._editor.getGuides().mapPoint(this._dragStart);\n        this._editor.getGuides().finishMap();\n\n        // Create our slice when user started dragging\n        this._slice = new IFSlice();\n        this._invalidateSlice();\n\n        this.updateCursor();\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} event\n     * @private\n     */\n    IFSliceTool.prototype._mouseDrag = function (event) {\n        this._dragCurrent = this._view.getViewTransform().mapPoint(event.client);\n        this._invalidateSlice();\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragEnd} event\n     * @private\n     */\n    IFSliceTool.prototype._mouseDragEnd = function (event) {\n        // Reset slice and repaint\n        var slice = this._slice;\n        this._slice = null;\n        this._invalidateSliceArea(slice);\n\n        // Update slice with scene coordinates before appending\n        this._updateSlice(slice, this._dragArea);\n\n        // Clear our stuff\n        this._dragStart = null;\n        this._dragCurrent = null;\n        this._slice = null;\n        this._dragArea = null;\n\n        this.updateCursor();\n\n        // Finally insert our slice\n        this._editor.insertElements([slice]);\n        this._hasCreatedSlice = true;\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFSliceTool.prototype._modifiersChanged = function (event) {\n        if (event.changed.shiftKey || event.changed.optionKey || event.changed.metaKey) {\n            this._invalidateSlice();\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFSliceTool.prototype._invalidateSlice = function () {\n        if (this._dragStart && this._dragCurrent) {\n            this._editor.getGuides().beginMap();\n            var dragCurrent = this._editor.getGuides().mapPoint(this._dragCurrent);\n            this._editor.getGuides().finishMap();\n            if (IFPoint.equals(this._dragStart, dragCurrent)) {\n                this._invalidateSliceArea();\n            } else {\n                var x0 = this._dragStart.getX();\n                var y0 = this._dragStart.getY();\n                var x1 = dragCurrent.getX();\n                var y1 = dragCurrent.getY();\n\n                if (ifPlatform.modifiers.shiftKey) {\n                    var w = Math.abs(x1 - x0);\n                    var h = Math.abs(y1 - y0);\n                    var wSign = x1 < x0 ? -1 : 1;\n                    var hSign = y1 < y0 ? -1 : 1;\n\n                    if (w >= h) {\n                        x1 = x0 + w * wSign;\n                        y1 = y0 + w * hSign;\n                    } else {\n                        x1 = x0 + h * wSign;\n                        y1 = y0 + h * hSign;\n                    }\n                }\n\n                /** @type IFRect */\n                var dragArea = null;\n\n                if (ifPlatform.modifiers.optionKey) {\n                    dragArea = IFRect.fromPoints(new IFPoint(x0 - (x1 - x0), y0 - (y1 - y0)), new IFPoint(x0 + (x1 - x0), y0 + (y1 - y0)));\n                } else {\n                    dragArea = IFRect.fromPoints(new IFPoint(x0, y0), new IFPoint(x1, y1));\n                }\n\n                // Assign area in scene coordinates\n                this._dragArea = dragArea;\n\n                this._invalidateSliceArea();\n                this._updateSlice(this._slice, dragArea);\n                this._invalidateSliceArea();\n            }\n        }\n    };\n    \n    /**\n     * @param {IFSlice} [slice] the slice to invalidate,\n     * if not provided defaults to current slice if any\n     * @private\n     */\n    IFSliceTool.prototype._invalidateSliceArea = function (slice) {\n        slice = slice || this._slice;\n        if (slice) {\n            var geometryBBox = this._view.getWorldTransform().mapRect(slice.getGeometryBBox());\n            if (geometryBBox && (geometryBBox.getWidth() > 0 || geometryBBox.getHeight() > 0)) {\n                this.invalidateArea(geometryBBox.expanded(1, 1, 1, 1));\n            }\n        }\n    };\n\n    /**\n     * Called to update the slice of this tool\n     * @param {IFSlice} slice the slice to update\n     * @param {IFRect} area the slice area in scene coordinates\n     * @private\n     */\n    IFSliceTool.prototype._updateSlice = function (slice, area) {\n        // Original slice is a in coordinates x,y: [-1, 1]. Transform it to fit into the area:\n        slice.setProperty('trf',\n            new IFTransform(area.getWidth() / 2, 0, 0, area.getHeight() / 2,\n                area.getX() + area.getWidth() / 2, area.getY() + area.getHeight() / 2));\n    };\n\n    /** override */\n    IFSliceTool.prototype.toString = function () {\n        return \"[Object IFSliceTool]\";\n    };\n\n    _.IFSliceTool = IFSliceTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/subselecttool.js",
    "content": "(function (_) {\n    /**\n     * The sub selection tool\n     * @class IFSubSelectTool\n     * @extends IFSelectTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFSubSelectTool() {\n        IFSelectTool.call(this);\n    };\n\n    IFObject.inherit(IFSubSelectTool, IFSelectTool);\n\n    /** @override */\n    IFSubSelectTool.prototype.getCursor = function () {\n        var result = IFSelectTool.prototype.getCursor.call(this);\n        if (result === IFCursor.Select) {\n            return IFCursor.SelectInverse;\n        } else if (result === IFCursor.SelectDot) {\n            return IFCursor.SelectDotInverse;\n        } else {\n            return result;\n        }\n    };\n\n    /** @override */\n    IFSubSelectTool.prototype.activate = function (view) {\n        IFSelectTool.prototype.activate.call(this, view);\n\n        // Set detail mode for selection for sub-select tool\n        this._editor.setSelectionDetail(true);\n    };\n\n    /** @override */\n    IFSubSelectTool.prototype.deactivate = function (view) {\n        // Remove detail mode for selection for sub-select tool\n        this._editor.setSelectionDetail(false);\n\n        IFSelectTool.prototype.deactivate.call(this, view);\n    };\n\n    /** @override */\n    IFSubSelectTool.prototype._mouseDragStart = function (event) {\n        if (this._mode == IFSelectTool._Mode.Move) {\n            // Save start\n            this._moveStart = event.client;\n            this._moveStartTransformed = this._view.getViewTransform().mapPoint(this._moveStart);\n\n            // Switch to moving mode\n            this._updateMode(IFSelectTool._Mode.Moving);\n\n            if (this._editorMovePartInfo) {\n                if (this._editorMovePartInfo.isolated) {\n                    this._editorMovePartInfo =\n                        this._editorMovePartInfo.editor.subSelectDragStartAction(this._editorMovePartInfo);\n                } else {\n                    var selection = this._editor.getSelection();\n                    if (selection && selection.length) {\n                        for (var i = 0; i < selection.length; ++i) {\n                            var editor = IFElementEditor.getEditor(selection[i]);\n                            if (editor) {\n                                var partInfo = editor.subSelectDragStartAction(this._editorMovePartInfo);\n                                if (partInfo) {\n                                    this._editorMovePartInfo = partInfo;\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        } else {\n            IFSelectTool.prototype._mouseDragStart.call(this, event);\n        }\n    };\n\n    /** @override */\n    IFSubSelectTool.prototype._getSelectableElement = function (element) {\n        return element instanceof IFShape ? element : null;\n    };\n\n    /** override */\n    IFSubSelectTool.prototype.toString = function () {\n        return \"[Object IFSubSelectTool]\";\n    };\n\n    _.IFSubSelectTool = IFSubSelectTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/texttool.js",
    "content": "(function (_) {\n    /**\n     * The text tool\n     * @class IFTextTool\n     * @extends IFShapeTool\n     * @constructor\n     */\n    function IFTextTool() {\n        IFShapeTool.call(this, true, true);\n    }\n\n    IFObject.inherit(IFTextTool, IFShapeTool);\n\n    /**\n     * @type {IFText}\n     * @private\n     */\n    IFTextTool.prototype._textUnderMouse = null;\n\n    /** @override */\n    IFTextTool.prototype.getCursor = function () {\n        if (this._textUnderMouse) {\n            // TODO : Figure a better cursor to indicate editing\n            return IFCursor.SelectDot;\n        } else if (!this._shape) {\n            return IFCursor.Text;\n        } else {\n            return IFShapeTool.prototype.getCursor.call(this);\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFTextTool.prototype._mouseRelease = function (event) {\n        if (this._textUnderMouse) {\n\n            // Save as this will be lost after switching tool\n            var editor = this._editor;\n            var view = this._view;\n\n            // Switch to select tool\n            this._manager.activateTool(IFPointerTool);\n\n            // open inline editor\n            editor.openInlineEditor(this._textUnderMouse, view, event.client)\n        } else {\n            IFShapeTool.prototype._mouseRelease.call(this, event);\n        }\n    };\n\n    /** @override */\n    IFTextTool.prototype._mouseMove = function (event) {\n        IFShapeTool.prototype._mouseMove.call(this, event);\n\n        if (this._textUnderMouse) {\n            this._textUnderMouse = null;\n            this.updateCursor();\n        }\n\n        if (!this._shape) {\n            var elementHits = this._scene.hitTest(event.client, this._view.getWorldTransform(), null,\n                false, -1, this._scene.getProperty('pickDist'));\n\n            if (elementHits && elementHits.length && elementHits[0].element instanceof IFText) {\n                this._textUnderMouse = elementHits[0].element;\n                this.updateCursor();\n            }\n        }\n    };\n\n    /** @override */\n    IFTextTool.prototype._createShape = function () {\n        return new IFRectangle();\n    };\n\n    /** @override */\n    IFTextTool.prototype._updateShape = function (shape, area, line, scene) {\n        if (scene) {\n            shape.setProperty('trf', new IFTransform(area.getWidth(), 0, 0, area.getHeight(), area.getX(), area.getY()));\n        } else {\n            shape.setProperty('trf',\n                new IFTransform(area.getWidth() / 2, 0, 0, area.getHeight() / 2,\n                    area.getX() + area.getWidth() / 2, area.getY() + area.getHeight() / 2));\n        }\n    };\n\n    /** @override */\n    IFTextTool.prototype._insertShape = function (shape) {\n        // Create our text out of our rectangle here\n        var text = new IFText();\n        text.setProperties(['aw', 'ah', 'trf'], [false, false, shape.getProperty('trf')]);\n\n        this._insertText(text);\n    };\n\n    /** @override */\n    IFTextTool.prototype._hasCenterCross = function () {\n        return true;\n    };\n\n    /** @override */\n    IFTextTool.prototype._createShapeManually = function (position) {\n        var text = new IFText();\n        text.setProperty('trf', new IFTransform(1, 0, 0, 1, position.getX(), position.getY()));\n        this._insertText(text);\n    };\n\n    /** @private */\n    IFTextTool.prototype._insertText = function (text) {\n        // Insert text, first\n        IFShapeTool.prototype._insertShape.call(this, text);\n\n        // Save as this will be lost after switching tool\n        var editor = this._editor;\n        var view = this._view;\n\n        // Switch to select tool\n        this._manager.activateTool(IFPointerTool);\n\n        // Open inline editor for text\n        editor.openInlineEditor(text, view);\n    };\n\n    /** override */\n    IFTextTool.prototype.toString = function () {\n        return \"[Object IFTextTool]\";\n    };\n\n    _.IFTextTool = IFTextTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/tool.js",
    "content": "(function (_) {\n    /**\n     * The base for a tool\n     * @class IFTool\n     * @extends IFObject\n     * @constructor\n     * @version 1.0\n     */\n    function IFTool() {\n    }\n\n    IFObject.inherit(IFTool, IFObject);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFTool Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * The manager creating and owning this tool\n     * @type {IFToolManager}\n     * @private\n     */\n    IFTool.prototype._manager = null;\n\n    /**\n     * The current docuument the tool is activated on, may be null for none\n     * @type {IFScene}\n     * @private\n     */\n    IFTool.prototype._scene = null;\n\n    /**\n     * The current editor view the tool is activated on, may be null for none\n     * @type {IFEditorView}\n     * @private\n     */\n    IFTool.prototype._view = null;\n\n    /**\n     * The current graphic editor the tool is activated on, may be null for none\n     * @type {IFEditor}\n     * @private\n     */\n    IFTool.prototype._editor = null;\n\n    /**\n     * Should return the current cursor for this tool.\n     * If you need to update the cursor, simply call updateCursor()\n     * @returns {String}\n     * @see IFCursor\n     * @version 1.0\n     */\n    IFTool.prototype.getCursor = function () {\n        return IFCursor.Default;\n    };\n\n    /**\n     * Called when this tool got activated for a given view\n     * @param {IFEditorView} view the editor view the tool got activated for\n     */\n    IFTool.prototype.activate = function (view) {\n        this._scene = view ? view.getScene() : null;\n        this._view = view;\n        this._editor = view.getEditor();\n    };\n\n    /**\n     * Called when this tool got deactivated for it's current view\n     * @param {IFEditorView} view the editor view the tool got deactivated for\n     */\n    IFTool.prototype.deactivate = function (view) {\n        if (view.getScene() != this._scene || view != this._view) {\n            throw new Error(\"Not supposed to happen\");\n        }\n        this._scene = null;\n        this._view = null;\n        this._editor = null;\n    };\n\n    /**\n     * Should return whether the tool can currently be\n     * safely deactivated by calling it's deactivate()\n     * function or not (i.e. while drawing)\n     * @return {Boolean}\n     * @version 1.0\n     */\n    IFTool.prototype.isDeactivatable = function () {\n        // Always deactivable by default\n        return true;\n    };\n\n    /**\n     * Called when this tool should paint itself.\n     * @param {IFPaintContext} context\n     * @version 1.0\n     */\n    IFTool.prototype.paint = function (context) {\n        // NO-OP\n    };\n\n    /**\n     * Descendant classes should call this to update their cursor\n     * @version 1.0\n     */\n    IFTool.prototype.updateCursor = function () {\n        if (this._manager && this == this._manager.getActiveTool()) {\n            this._manager._updateActiveToolCursor();\n        }\n    };\n\n    /**\n     * Descendant classes should call this to invalidate and\n     * request a repaint of a certain area\n     * @param {IFRect} [area] the area of invalidation, if not provided\n     * or null, invalidates the whole area\n     * @version 1.0\n     */\n    IFTool.prototype.invalidateArea = function (area) {\n        if (this._manager && this == this._manager.getActiveTool()) {\n            this._manager._invalidateActiveToolArea(area);\n        }\n    };\n\n    /**\n     * This may return to supress context menu because\n     * the tool handles right clicking differently\n     */\n    IFTool.prototype.catchesContextMenu = function () {\n        return false;\n    };\n\n    /** override */\n    IFTool.prototype.toString = function () {\n        return \"[Object IFTool]\";\n    };\n\n    _.IFTool = IFTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/toolmanager.js",
    "content": "(function (_) {\n    /**\n     * The manager for tools\n     * @class IFToolManager\n     * @extends IFObject\n     * @mixes GEventTarget\n     * @constructor\n     * @version 1.0\n     */\n    function IFToolManager() {\n        this._tools = [];\n        this._typeIdToIndexMap = {};\n        this._paintLink = this._paint.bind(this);\n    }\n\n    IFObject.inheritAndMix(IFToolManager, IFObject, [GEventTarget]);\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFToolManager.ToolChangedEvent Event\n    // -----------------------------------------------------------------------------------------------------------------\n    /**\n     * An event for tool activation/deactivation\n     * @param {IFTool} previousTool previous tool instance, may be null for no previous tool\n     * @param {IFTool} newTool new tool instance, may be null for deactivation only\n     * @class IFToolManager.ToolChangedEvent\n     * @extends GEvent\n     * @constructor\n     * @version 1.0\n     */\n    IFToolManager.ToolChangedEvent = function (previousTool, newTool) {\n        this.previousTool = previousTool;\n        this.newTool = newTool;\n    };\n    IFObject.inherit(IFToolManager.ToolChangedEvent, GEvent);\n\n    /** @type IFTool */\n    IFToolManager.ToolChangedEvent.prototype.previousTool = null;\n    /** @type IFTool */\n    IFToolManager.ToolChangedEvent.prototype.newTool = null;\n\n    /** @override */\n    IFToolManager.ToolChangedEvent.prototype.toString = function () {\n        return \"[Event IFToolManager.ToolChangedEvent]\";\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFToolManager Class\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * @type {Array<IFTool>}\n     * @private\n     */\n    IFToolManager.prototype._tools = null;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    IFToolManager.prototype._typeIdToIndexMap = null;\n\n    /**\n     * @type {IFTool}\n     * @private\n     */\n    IFToolManager.prototype._activeTool = null;\n\n    /**\n     * @type {IFEditorView}\n     * @private\n     */\n    IFToolManager.prototype._view = null;\n\n    /**\n     * @type {IFStage}\n     * @private\n     */\n    IFToolManager.prototype._viewStage = null;\n\n    /**\n     * @type {IFTool}\n     * @private\n     */\n    IFToolManager.prototype._temporaryActiveTool = null;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    IFToolManager.prototype._temporarySubselect = false;\n\n    /**\n     * Add a new tool at the end of this manager. Note that the tool\n     * will automatically be activated if the manager does not yet have an active one.\n     * @param {IFTool} tool the tool to add\n     * @version 1.0\n     */\n    IFToolManager.prototype.addTool = function (tool) {\n        if (tool._manager) {\n            throw new Error('Tool is already registered');\n        }\n\n        this._tools.push(tool);\n\n        tool._manager = this;\n\n        // Invalidate type index map\n        this._typeIdToIndexMap = {};\n        for (var i = 0; i < this._tools.length; ++i) {\n            var tool = this._tools[i];\n            this._typeIdToIndexMap[IFObject.getTypeId(tool)] = i;\n        }\n\n        if (!this._activeTool) {\n            this.activateTool(tool);\n        }\n    };\n\n    /**\n     * Checks whether the manager has a certain tool class available\n     * @param {Function} tool the tool class to check for\n     * @return {Boolean} true if available, false if not\n     * @version 1.0\n     */\n    IFToolManager.prototype.hasTool = function (tool) {\n        return this._typeIdToIndexMap.hasOwnProperty(IFObject.getTypeId(tool));\n    };\n\n    /**\n     * @returns {Number} the total count of tools in this manager\n     */\n    IFToolManager.prototype.getToolCount = function () {\n        return this._tools.length;\n    };\n\n    /**\n     * @param {Function} tool the tool class to get an index for\n     * @returns {Number} the index of the tool class or -1 if there's none\n     */\n    IFToolManager.prototype.indexOf = function (tool) {\n        return this._typeIdToIndexMap.hasOwnProperty(IFObject.getTypeId(tool)) ?\n            this._typeIdToIndexMap[IFObject.getTypeId(tool)] : -1;\n    };\n\n    /**\n     * @param {Number} index the tool-index to get an instance for\n     * @returns {IFTool} the tool or null if index is out of range\n     */\n    IFToolManager.prototype.getTool = function (index) {\n        return index >= 0 && index < this._tools.length ? this._tools[index] : null;\n    };\n\n    /**\n     * @return {IFTool} the active tool or null for none\n     */\n    IFToolManager.prototype.getActiveTool = function () {\n        return this._activeTool;\n    };\n\n    /**\n     * @returns {IFTool} the temporary active tool if any\n     */\n    IFToolManager.prototype.getTemporaryActiveTool = function () {\n        return this._temporaryActiveTool;\n    };\n\n    /**\n     * Activate a tool\n     * @param {Function|IFTool} tool the tool class or instance to get activate\n     * @return {Boolean} true if activated, false if not\n     */\n    IFToolManager.prototype.activateTool = function (tool) {\n        if (!this._temporaryActiveTool) {\n            return this._activateTool(tool);\n        }\n        return false;\n    };\n\n    /**\n     * Assign the view this tool manager is operating on\n     * @param {IFEditorView} view the editor view this tool manager\n     * is operating on, may also be null to remove all views\n     */\n    IFToolManager.prototype.setView = function (view) {\n        if (view != this._view) {\n\n            if (this._view) {\n                // Remove active tool\n                this._removeActiveToolFromView();\n                // Remove ourself from the view tool layer's paint\n                this._viewStage.paint = null;\n                // Unregister ourself from global modifiers change event\n                ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n            }\n\n            this._view = view;\n\n            this._viewStage = view ? view.getToolStage() : null;\n\n            if (this._view) {\n                // Add active tool\n                this._addActiveToolToView();\n                // Assign ourself to the view tool layer's paint\n                this._viewStage.paint = this._paintLink;\n                // Register ourself to global modifiers change event\n                ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n            }\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFToolManager.prototype._activateTool = function (tool) {\n        // Stop here if current tool is not deactivatable\n        if (this._activeTool && !this._activeTool.isDeactivatable()) {\n            return false;\n        }\n\n        if (!(tool instanceof IFTool)) {\n            tool = this.getTool(this.indexOf(tool));\n        }\n\n        if (tool != this._activeTool) {\n            this._removeActiveToolFromView();\n\n            var oldTool = this._activeTool;\n            this._activeTool = tool;\n\n            if (this.hasEventListeners(IFToolManager.ToolChangedEvent)) {\n                this.trigger(new IFToolManager.ToolChangedEvent(oldTool, tool));\n            }\n\n            this._addActiveToolToView();\n\n            return true;\n        }\n        return false;\n    };\n\n    /**\n     * @private\n     */\n    IFToolManager.prototype._addActiveToolToView = function () {\n        if (this._activeTool && this._view) {\n            // Let tool activate on the view\n            this._activeTool.activate(this._view);\n\n            // Update view's cursor\n            this._updateActiveToolCursor();\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFToolManager.prototype._removeActiveToolFromView = function () {\n        if (this._activeTool && this._view) {\n            // Let tool deactivate on the view\n            this._activeTool.deactivate(this._view);\n\n            // remove any cursor from the view\n            this._view.setCursor(null);\n\n            // Let editor on view if any finish inline editing\n            this._view.getEditor().closeInlineEditor();\n        }\n    };\n\n    /**\n     * Enforce a cursor update for the current view and tool.\n     * This is usually called from the tools\n     * @private\n     */\n    IFToolManager.prototype._updateActiveToolCursor = function () {\n        if (this._activeTool && this._view) {\n            this._view.setCursor(this._activeTool.getCursor());\n        }\n    };\n\n    /**\n     * Invalidate and request a repaint of active tool area\n     * @param {IFRect} [area] the area of invalidation, if not provided\n     * or null, invalidates the whole area\n     * @private\n     */\n    IFToolManager.prototype._invalidateActiveToolArea = function (area) {\n        if (this._activeTool && this._view) {\n            this._viewStage.invalidate(area);\n        }\n    };\n\n    /**\n     * Called when this toolmanager should paint itself.\n     * @param {IFPaintContext} context\n     * @version 1.0\n     */\n    IFToolManager.prototype._paint = function (context) {\n        if (this._activeTool) {\n            this._activeTool.paint(context);\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFToolManager.prototype._updateTemporaryTool = function () {\n        // Don't allow temporary tool switching when our editor is in inline editor mode\n        if (this._view.getEditor().isInlineEditing()) {\n            return;\n        }\n\n        var pointerToolInstance = this.getTool(this.indexOf(IFPointerTool));\n        var subselectToolInstance = this.getTool(this.indexOf(IFSubSelectTool));\n        var handToolInstance = this.getTool(this.indexOf(IFHandTool));\n        var zoomToolInstance = this.getTool(this.indexOf(IFZoomTool));\n\n        var temporaryTool = null;\n\n        //\n        // Pointer Tool is active when:\n        // .) Meta-Key is hold\n        // .) Space-Key is *not* hold\n        // .) The active tool is not the pointer tool\n        // .) The temporary tool is not the pointer tool\n        //\n        if (ifPlatform.modifiers.metaKey && !ifPlatform.modifiers.spaceKey &&\n            this._activeTool !== pointerToolInstance && this._temporaryActiveTool !== pointerToolInstance) {\n            // Meta key switches to pointer tool\n            temporaryTool = pointerToolInstance;\n        }\n\n        //\n        // Subselect Tool is active when:\n        // .) Option Key is hold\n        // .) The active tool is the pointer tool or the temporaryTool is the pointer tool or the temporary active tool is the pointer tool\n        //\n        if (ifPlatform.modifiers.optionKey && (temporaryTool === pointerToolInstance || this._activeTool instanceof IFPointerTool || this._temporaryActiveTool === pointerToolInstance)) {\n            temporaryTool = subselectToolInstance;\n        }\n\n        //\n        // Hand Tool is active when:\n        //\n        // .) Space Key is hold\n        // .) The active tool may be and may be not the hand tool as the _updateTemporaryTool may be called due to other\n        // modifiers\n        // .) The temporary tool is not the hand tool\n        //\n        if (ifPlatform.modifiers.spaceKey && this._temporaryActiveTool !== handToolInstance) {\n            temporaryTool = handToolInstance;\n        }\n\n        //\n        // Zoom Tool is active when:\n        // .) Meta Key is hold\n        // .) The active tool is the hand tool or the temporaryTool is the hand tool\n        //\n        if (ifPlatform.modifiers.metaKey && (temporaryTool === handToolInstance || this._activeTool instanceof IFHandTool)) {\n            temporaryTool = zoomToolInstance;\n        }\n\n        // If not having a temporary tool then activte previous tool if any\n        if (!temporaryTool && this._temporaryActiveTool) {\n            if (this._activateTool(this._temporaryActiveTool)) {\n                this._temporaryActiveTool = null;\n            }\n        } else if (temporaryTool && temporaryTool !== this._activeTool) {\n            var previousActiveTool = this._activeTool;\n            if (this._activateTool(temporaryTool)) {\n                if (!this._temporaryActiveTool) {\n                    this._temporaryActiveTool = previousActiveTool;\n                }\n            }\n        }\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFToolManager.prototype._modifiersChanged = function (event) {\n        // Update temporary tool\n        this._updateTemporaryTool();\n    };\n\n    /** override */\n    IFToolManager.prototype.toString = function () {\n        return \"[Object IFToolManager]\";\n    };\n\n    _.IFToolManager = IFToolManager;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/transformtool.js",
    "content": "(function (_) {\n    /**\n     * The transform tool\n     * @class IFTransformTool\n     * @extends IFSelectTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFTransformTool() {\n        IFSelectTool.call(this);\n    };\n\n    IFObject.inherit(IFTransformTool, IFSelectTool);\n\n    /** @override */\n    IFTransformTool.prototype.activate = function (view) {\n        IFSelectTool.prototype.activate.call(this, view);\n\n        // If there's no available selection, select the pointer tool instead\n        var selection = view.getEditor().getSelection();\n        if (!selection || selection.length === 0) {\n            this._manager.activateTool(IFPointerTool);\n        } else {\n            this._openTransformBox();\n        }\n    };\n\n    /** @override */\n    IFTransformTool.prototype._mouseDblClick = function () {\n        // no-op, just disallow any actions on double click as this would\n        // do things we don't want in transform mode\n    };\n\n    /** override */\n    IFTransformTool.prototype.toString = function () {\n        return \"[Object IFTransformTool]\";\n    };\n\n    _.IFTransformTool = IFTransformTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/tool/zoomtool.js",
    "content": "(function (_) {\n    /**\n     * The zoom tool\n     * @class IFZoomTool\n     * @extends IFTool\n     * @constructor\n     * @version 1.0\n     */\n    function IFZoomTool() {\n        IFTool.call(this);\n    }\n\n    IFObject.inherit(IFZoomTool, IFTool);\n\n    /**\n     * Global zoom tool options\n     * @type {Object}\n     * @version 1.0\n     */\n    IFZoomTool.options = {\n        /**\n         * The zoom step for zooming in/out. For example,\n         * a value of 2.0 doubles the current zoom for each zoom-in\n         * and halfs the current zoom for each zoom-out\n         * @type {Number}\n         * @version 1.0\n         */\n        zoomStep: 2.0\n    };\n\n    // -----------------------------------------------------------------------------------------------------------------\n    // IFZoomTool\n    // -----------------------------------------------------------------------------------------------------------------\n\n    /**\n     * -2 = zoom out max, -1 = zoom out, 0 = no zoom, +1 = zoom in, +2 = zoom in max\n     * @type {Number}\n     * @private\n     */\n    IFZoomTool.prototype._zoomMode = false;\n\n    /**\n     * @type {IFRect}\n     * @private\n     */\n    IFZoomTool.prototype._dragArea = null;\n\n    /** @override */\n    IFZoomTool.prototype.getCursor = function () {\n        switch (this._zoomMode) {\n            case -2:\n            case -1:\n                return IFCursor.ZoomMinus;\n            case +1:\n            case +2:\n                return IFCursor.ZoomPlus;\n            default:\n                return IFCursor.ZoomNone;\n        }\n    };\n\n    /** @override */\n    IFZoomTool.prototype.activate = function (view) {\n        IFTool.prototype.activate.call(this, view);\n\n        this._updateMode();\n\n        view.addEventListener(GUIMouseEvent.DragStart, this._mouseDragStart, this);\n        view.addEventListener(GUIMouseEvent.Drag, this._mouseDrag, this);\n        view.addEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd, this);\n        view.addEventListener(GUIMouseEvent.Release, this._mouseRelease, this);\n\n        ifPlatform.addEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged, this);\n    };\n\n    /** @override */\n    IFZoomTool.prototype.deactivate = function (view) {\n        IFTool.prototype.deactivate.call(this, view);\n\n        view.removeEventListener(GUIMouseEvent.DragStart, this._mouseDragStart);\n        view.removeEventListener(GUIMouseEvent.Drag, this._mouseDrag);\n        view.removeEventListener(GUIMouseEvent.DragEnd, this._mouseDragEnd);\n        view.removeEventListener(GUIMouseEvent.Release, this._mouseRelease);\n\n        ifPlatform.removeEventListener(GUIPlatform.ModifiersChangedEvent, this._modifiersChanged);\n    };\n\n    /** @override */\n    IFZoomTool.prototype.isDeactivatable = function () {\n        // cannot deactivate while dragging\n        return this._dragArea ? false : true;\n    };\n\n    /** @override */\n    IFZoomTool.prototype.paint = function (context) {\n        if (this._hasDragArea()) {\n            var x = Math.floor(this._dragArea.getX()) + 0.5;\n            var y = Math.floor(this._dragArea.getY()) + 0.5;\n            var w = Math.ceil(this._dragArea.getWidth()) - 1.0;\n            var h = Math.ceil(this._dragArea.getHeight()) - 1.0;\n            context.canvas.strokeRect(x, y, w, h);\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragStart} event\n     * @private\n     */\n    IFZoomTool.prototype._mouseDragStart = function (event) {\n        // NO-OP\n    };\n\n    /**\n     * @param {GUIMouseEvent.Drag} event\n     * @private\n     */\n    IFZoomTool.prototype._mouseDrag = function (event) {\n        if (this._zoomMode != 0) {\n            if (this._hasDragArea()) {\n                this.invalidateArea(this._dragArea);\n            }\n\n            this._dragArea = IFRect.fromPoints(event.clientStart, event.client);\n\n            if (this._hasDragArea()) {\n                this.invalidateArea(this._dragArea);\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.DragEnd} event\n     * @private\n     */\n    IFZoomTool.prototype._mouseDragEnd = function (event) {\n        if (this._zoomMode != 0) {\n            if (this._dragArea && !this._dragArea.isEmpty()) {\n                // No need for additional invalidation as we're about to zoom which invalidates everything anyway\n                var zoomRect = this._view.getViewTransform().mapRect(this._dragArea);\n                this._view.zoomAll(zoomRect, this._zoomMode < 0 /*reverse*/);\n                this._updateMode();\n            } else if (this._hasDragArea()) {\n                this.invalidateArea(this._dragArea);\n            }\n        }\n    };\n\n    /**\n     * @param {GUIMouseEvent.Release} event\n     * @private\n     */\n    IFZoomTool.prototype._mouseRelease = function (event) {\n        if (!this._dragArea || (this._dragArea && this._dragArea.isEmpty())) {\n            var newZoom = null;\n            switch (this._zoomMode) {\n                case -2:\n                    newZoom = IFView.options.minZoomFactor;\n                    break;\n                case -1:\n                    newZoom = this._view.getZoom() / IFZoomTool.options.zoomStep;\n                    break;\n                case +1:\n                    newZoom = this._view.getZoom() * IFZoomTool.options.zoomStep;\n                    break;\n                case +2:\n                    newZoom = IFView.options.maxZoomFactor;\n                    break;\n                default:\n                    break;\n            }\n            if (newZoom != null) {\n                var zoomPoint = this._view.getViewTransform().mapPoint(event.client);\n                this._view.zoomAt(zoomPoint, newZoom);\n                this._updateMode();\n            }\n        }\n        this._dragArea = null;\n    };\n\n    /**\n     * @param {GUIPlatform.ModifiersChangedEvent} event\n     * @private\n     */\n    IFZoomTool.prototype._modifiersChanged = function (event) {\n        this._updateMode();\n    };\n\n    IFZoomTool.prototype._updateMode = function () {\n        var newMode = 0;\n        if (ifPlatform.modifiers.optionKey) {\n            newMode = -1;\n            if (ifPlatform.modifiers.shiftKey) {\n                newMode = -2;\n            }\n        } else {\n            newMode = +1;\n            if (ifPlatform.modifiers.shiftKey) {\n                newMode = +2;\n            }\n        }\n\n        // Normalize zoom mode\n        if (newMode < 0 && this._view.getZoom() <= IFView.options.minZoomFactor) {\n            newMode = 0;\n        } else if (newMode > 0 && this._view.getZoom() >= IFView.options.maxZoomFactor) {\n            newMode = 0;\n        }\n\n        if (newMode != this._zoomMode) {\n            this._zoomMode = newMode;\n            this.updateCursor();\n        }\n    };\n\n    /**\n     * @private\n     */\n    IFZoomTool.prototype._hasDragArea = function () {\n        return (this._dragArea && (this._dragArea.getHeight() > 0 || this._dragArea.getWidth() > 0));\n    };\n\n    /** override */\n    IFZoomTool.prototype.toString = function () {\n        return \"[Object IFZoomTool]\";\n    };\n\n    _.IFZoomTool = IFZoomTool;\n})(this);"
  },
  {
    "path": "src/infinity-editor/view/editorbackstage.js",
    "content": "(function (_) {\n    var PAGE_CHESSBOARD_FILL = null;\n\n    /**\n     * A stage for rendering the editor background\n     * @param {IFView} view\n     * @class IFEditorBackStage\n     * @extends IFStage\n     * @constructor\n     */\n    function IFEditorBackStage(view) {\n        IFStage.call(this, view);\n        view.getScene().addEventListener(IFScene.InvalidationRequestEvent, this._sceneInvalidationRequest, this);\n    }\n\n    IFObject.inherit(IFEditorBackStage, IFStage);\n\n    /** @override */\n    IFEditorBackStage.prototype.release = function () {\n        this._view.getScene().removeEventListener(IFScene.InvalidationRequestEvent, this._sceneInvalidationRequest, this);\n    };\n\n    /** @override */\n    IFEditorBackStage.prototype.paint = function (context) {\n        // View painting\n\n        //\n        // Scene painting\n        //\n\n        // Transform dirty areas into scene\n        if (context.dirtyMatcher) {\n            context.dirtyMatcher.transform(this._view.getViewTransform());\n        }\n\n        if (context.configuration.pagesVisible) {\n            this._renderPages(context);\n        }\n    };\n\n    /**\n     * Event listener for scene's repaintRequest\n     * @param {IFScene.InvalidationRequestEvent} event the invalidation request event\n     * @private\n     */\n    IFEditorBackStage.prototype._sceneInvalidationRequest = function (event) {\n        var area = event.area;\n        if (area) {\n            // Ensure to map the scene area into view coordinates, first\n            // TODO : How to handle view margins!?\n            area = this._view.getWorldTransform().mapRect(area);\n        }\n        this.invalidate(area);\n    };\n\n    /**\n     * @param context\n     * @private\n     */\n    IFEditorBackStage.prototype._renderPages = function (context) {\n        // We'll leave our canvas in view coordinates for the background\n        var singlePage = this._view.getScene().getProperty('singlePage');\n        var transform = this._view.getWorldTransform();\n        for (var node = this._view.getScene().getFirstChild(); node !== null; node = node.getNext()) {\n            if (node instanceof IFPage && node.isRenderable(context) && (!singlePage || node.hasFlag(IFNode.Flag.Active))) {\n                this._renderPage(context, transform, node);\n            }\n        }\n    };\n\n    /**\n     * @param context\n     * @param transform\n     * @param page\n     * @private\n     */\n    IFEditorBackStage.prototype._renderPage = function (context, transform, page) {\n        // Get page rectangle and transform it into world space\n        var pageRect = new IFRect(page.getProperty('x'), page.getProperty('y'), page.getProperty('w'), page.getProperty('h'));\n        var marginRect = pageRect.expanded(-page.getProperty('ml'), -page.getProperty('mt'), -page.getProperty('mr'), -page.getProperty('mb'));\n        var transformedPageRect = transform.mapRect(pageRect).toAlignedRect();\n        var transformedMarginRect = transform.mapRect(marginRect).toAlignedRect();\n        var x = transformedPageRect.getX(), y = transformedPageRect.getY(), w = transformedPageRect.getWidth(), h = transformedPageRect.getHeight();\n        var mx = transformedMarginRect.getX(), my = transformedMarginRect.getY(), mw = transformedMarginRect.getWidth(), mh = transformedMarginRect.getHeight();\n\n        // Paint page color or chessboard if transparent\n        if (!PAGE_CHESSBOARD_FILL) {\n            PAGE_CHESSBOARD_FILL = IFPaintCanvas.createChessboard(8, 'white', 'rgb(205, 205, 205)');\n        }\n        var chessFill = context.canvas.createTexture(PAGE_CHESSBOARD_FILL);\n\n        context.canvas.setTransform(new IFTransform(1, 0, 0, 1, x, y));\n        context.canvas.fillRect(0, 0, w, h, chessFill);\n        var pageColor = page.getProperty('cls');\n        if (pageColor) {\n            context.canvas.fillRect(0, 0, w, h, pageColor);\n        }\n        context.canvas.resetTransform();\n\n        // Paint margin rect\n        if (!IFRect.equals(pageRect, marginRect)) {\n            context.canvas.strokeRect(mx + 0.5, my + 0.5, mw, mh, 1, IFColor.MARGIN_OUTLINE);\n        }\n    };\n\n    /** @override */\n    IFEditorBackStage.prototype.toString = function () {\n        return \"[Object IFEditorBackStage]\";\n    };\n\n    _.IFEditorBackStage = IFEditorBackStage;\n})(this);"
  },
  {
    "path": "src/infinity-editor/view/editorfrontstage.js",
    "content": "(function (_) {\n    /**\n     * A stage for rendering the editor foreground\n     * @param {IFView} view\n     * @class IFEditorFrontStage\n     * @extends IFStage\n     * @constructor\n     */\n    function IFEditorFrontStage(view) {\n        IFStage.call(this, view);\n        view.getScene().addEventListener(IFNode.AfterPropertiesChangeEvent, this._sceneAfterPropertiesChanged, this);\n        view.addEventListener(GUIMouseEvent.Release, this._cleanGuides, this);\n        view.getEditor().getGuides().addEventListener(IFGuides.InvalidationRequestEvent, this._guidesInvalidationRequest, this);\n        //view.getScene().addEventListener(IFScene.InvalidationRequestEvent, this._sceneInvalidationRequest, this);\n    }\n    IFObject.inherit(IFEditorFrontStage, IFStage);\n\n    /** @override */\n    IFEditorFrontStage.prototype.release = function () {\n        this._view.getScene().removeEventListener(IFNode.AfterPropertiesChangeEvent, this._sceneAfterPropertiesChanged, this);\n        this._view.getEditor().removeEventListener(IFGuides.InvalidationRequestEvent, this._guidesInvalidationRequest, this);\n        //this._view.getScene().removeEventListener(IFScene.InvalidationRequestEvent, this._sceneInvalidationRequest, this);\n        this._view.removeEventListener(GUIMouseEvent.Release, this._cleanGuides, this);\n    };\n\n    /** @override */\n    IFEditorFrontStage.prototype.paint = function (context) {\n        this._view.getEditor().getGuides().paint(this._view.getWorldTransform(), context);\n        //var sceneEditor = IFElementEditor.getEditor(this._view.getScene());\n        //if (sceneEditor) {\n           // sceneEditor.paint(this._view.getWorldTransform(), context);\n        //}\n    };\n\n    IFEditorFrontStage.prototype._sceneAfterPropertiesChanged = function (event) {\n        if (event.properties.indexOf('gridSizeX') >= 0 || event.properties.indexOf('gridSizeY') >= 0 ||\n            event.properties.indexOf('gridActive') >= 0) {\n            this.invalidate();\n        }\n    };\n\n    IFEditorFrontStage.prototype._guidesInvalidationRequest = function (event) {\n        if (event.area) {\n            var area = this._view.getWorldTransform().mapRect(event.area);\n            this.invalidate(area);\n        }\n    };\n\n    IFEditorFrontStage.prototype._sceneInvalidationRequest = function (event) {\n        if (event.area) {\n            var area = this._view.getWorldTransform().mapRect(event.area);\n            this.invalidate(area);\n        }\n    };\n\n    IFEditorFrontStage.prototype._cleanGuides = function (event) {\n        this._view.getEditor().getGuides().invalidate();\n    };\n\n    /** @override */\n    IFEditorFrontStage.prototype.toString = function () {\n        return \"[Object IFEditorFrontStage]\";\n    };\n\n    _.IFEditorFrontStage = IFEditorFrontStage;\n})(this);"
  },
  {
    "path": "src/infinity-editor/view/editorscenestage.js",
    "content": "(function (_) {\n    /**\n     * A stage for rendering the scene editors\n     * @param {IFEditorView} view\n     * @class IFEditorSceneStage\n     * @extends IFStage\n     * @constructor\n     */\n    function IFEditorSceneStage(view) {\n        IFStage.call(this, view);\n        view.getEditor().addEventListener(IFEditor.InvalidationRequestEvent, this._editorInvalidationRequest, this);\n    }\n    IFObject.inherit(IFEditorSceneStage, IFStage);\n\n    /** @override */\n    IFEditorSceneStage.prototype.release = function () {\n        this._view.getEditor().removeEventListener(IFEditor.InvalidationRequestEvent, this._editorInvalidationRequest, this);\n    };\n\n    /** @override */\n    IFEditorSceneStage.prototype.paint = function (context) {\n        var sceneEditor = IFElementEditor.getEditor(this._view.getScene());\n        if (sceneEditor) {\n            sceneEditor.paint(this._view.getWorldTransform(), context);\n        }\n    };\n\n    /**\n     * Event listener for editor's repaintRequest\n     * @param {IFEditor.InvalidationRequestEvent} event the invalidation request event\n     * @private\n     */\n    IFEditorSceneStage.prototype._editorInvalidationRequest = function (event) {\n        if (event.editor) {\n            var area = event.editor.invalidate(this._view.getWorldTransform(), event.args);\n            if (area) {\n                this.invalidate(area);\n            }\n        }\n    };\n\n    /** @override */\n    IFEditorSceneStage.prototype.toString = function () {\n        return \"[Object IFEditorSceneStage]\";\n    };\n\n    _.IFEditorSceneStage = IFEditorSceneStage;\n})(this);"
  },
  {
    "path": "src/infinity-editor/view/editortoolstage.js",
    "content": "(function (_) {\n    /**\n     * A stage for rendering the tools\n     * @param {IFEditorView} view\n     * @class IFEditorToolStage\n     * @extends IFStage\n     * @constructor\n     */\n    function IFEditorToolStage(view) {\n        IFStage.call(this, view);\n    }\n    IFObject.inherit(IFEditorToolStage, IFStage);\n\n    /** @override */\n    IFEditorToolStage.prototype.toString = function () {\n        return \"[Object IFEditorToolStage]\";\n    };\n\n    _.IFEditorToolStage = IFEditorToolStage;\n})(this);"
  },
  {
    "path": "src/infinity-editor/view/editorview.js",
    "content": "(function (_) {\n    /**\n     * IFEditorView is a widget to render and edit a scene\n     * @param {IFEditor} [editor] the editor this view is bound too, defaults to null\n     * @class IFEditorView\n     * @extends IFView\n     * @constructor\n     * @version 1.0\n     */\n    function IFEditorView(editor) {\n        var args = Array.prototype.slice.call(arguments);\n        args[0] = editor.getScene();\n        this._editor = editor;\n        this._viewConfiguration = new IFEditorPaintConfiguration(); // !!overwrite\n\n        IFView.apply(this, args);\n\n        // Register drop events on our view\n        $(this._htmlElement)\n            .on('dragenter', function (evt) {\n                var event = evt.originalEvent;\n                event.preventDefault();\n                event.stopPropagation();\n            })\n            .on('dragover', function (evt) {\n                var event = evt.originalEvent;\n                event.preventDefault();\n                event.stopPropagation();\n                evt.originalEvent.dataTransfer.dropEffect = 'move';\n            })\n            .on('drop', function (evt) {\n                var event = evt.originalEvent;\n                event.preventDefault();\n                event.stopPropagation();\n                var client = GUIWidget.convertClientPositionFromMousePosition(this._htmlElement, event);\n                this._handleDrop(client, event.dataTransfer);\n                return false;\n            }.bind(this));\n    }\n\n    IFObject.inherit(IFEditorView, IFView);\n\n    /**\n     * @type {IFEditor}\n     * @private\n     */\n    IFEditorView.prototype._editor = null;\n\n    /**\n     * @type {IFEditorToolStage}\n     * @private\n     */\n    IFEditorView.prototype._toolStage = null;\n\n    /**\n     * Return the editor this view is rendering\n     * @returns {IFEditor}\n     */\n    IFEditorView.prototype.getEditor = function () {\n        return this._editor;\n    };\n\n    /**\n     * Return the editor's tool stage\n     * @returns {IFEditorToolStage}\n     */\n    IFEditorView.prototype.getToolStage = function () {\n        return this._toolStage;\n    };\n\n    /** @override */\n    IFEditorView.prototype._initStages = function () {\n        this.addStage(new IFEditorBackStage(this));\n        this.addStage(new IFSceneStage(this));\n        this.addStage(new IFEditorFrontStage(this));\n        this.addStage(new IFEditorSceneStage(this));\n        this._toolStage = this.addStage(new IFEditorToolStage(this));\n    };\n\n    /** @override */\n    IFEditorView.prototype._updateViewTransforms = function () {\n        IFView.prototype._updateViewTransforms.call(this);\n        this._editor.updateInlineEditorForView(this);\n    };\n\n    /**\n     * Handle a drop on the editor\n     * @param {IFPoint} position screen coordinates position\n     * @param {DataTransfer} dataTransfer the dataTransfer object\n     * @private\n     */\n    IFEditorView.prototype._handleDrop = function (position, dataTransfer) {\n        // Convert position into scene coordinates\n        var scenePosition = this.getViewTransform().mapPoint(position);\n\n        // First we'll check for a file-drop\n        if (dataTransfer.files && dataTransfer.files.length > 0) {\n            var imageType = /image.*/;\n\n            for (var i = 0; i < dataTransfer.files.length; ++i) {\n                var file = dataTransfer.files[i];\n                var name = file.name;\n                if (name.lastIndexOf('.') > 0) {\n                    name = name.substr(0, name.lastIndexOf('.'));\n                }\n\n                // Check for image files\n                if (file.type.match(imageType)) {\n                    var reader = new FileReader();\n                    reader.onload = function (event) {\n                        var image = new IFImage();\n                        image.setProperties(['name', 'url', 'transform'],\n                            [name, event.target.result, new IFTransform(1, 0, 0, 1, scenePosition.getX(), scenePosition.getY())]);\n                        this._editor.insertElements([image]);\n                    }.bind(this)\n                    reader.readAsDataURL(file);\n                }\n\n                // TODO : Check for infinity files and other types?\n            }\n        } else if (dataTransfer.items && dataTransfer.items.length > 0) {\n            // Iterate items and find an appropriate drag type\n            for (var i = 0; i < dataTransfer.items.length; ++i) {\n                var item = dataTransfer.items[i];\n                var type = null;\n                var source = null;\n\n                if (item.type === IFPattern.MIME_TYPE) {\n                    type = IFElementEditor.DropType.Pattern;\n                    source = dataTransfer.getData(IFPattern.MIME_TYPE);\n                    source = source && source !== \"\" ? IFPattern.parsePattern(source) : null;\n                } else if (item.type === IFNode.MIME_TYPE) {\n                    type = IFElementEditor.DropType.Node;\n                    source = dataTransfer.getData(IFNode.MIME_TYPE);\n                    source = source && source !== \"\" ? IFNode.deserialize(source) : null;\n                } else if (item.type === 'text/plain') {\n                    type = IFElementEditor.DropType.Text;\n                    source = dataTransfer.getData('text/plain');\n                }\n\n                // If we've extracted a type, then try to let an editor handle it now\n                if (type !== null) {\n                    // Try to gather a stacked hit list underneath drop position\n                    var stackedHits = this._scene.hitTest(position, this.getWorldTransform(), null, true, -1, this._scene.getProperty('pickDist'), true);\n\n                    // If we had have one or more hits, iterate them\n                    var acceptedDrop = false;\n                    if (stackedHits && stackedHits.length > 0) {\n                        for (var j = 0; j < stackedHits.length; ++j) {\n                            var hit = stackedHits[j];\n                            // Create a temporary editor for the hit element which gets not attached\n                            var editor = IFElementEditor.createEditor(hit.element);\n                            if (editor && editor.acceptDrop(scenePosition, type, source, hit.data)) {\n                                // Drop was accepted so we're done here\n                                acceptedDrop = true;\n                                break;\n                            }\n                        }\n                    }\n\n                    // If drop was not yet accepted, try to do some custom handling here depending on type\n                    if (!acceptedDrop) {\n                        if (type === IFElementEditor.DropType.Node && source instanceof IFElement) {\n                            // Move the element to the drop-position\n                            var elBBox = source.getGeometryBBox();\n                            source.transform(new IFTransform(1, 0, 0, 1,\n                                scenePosition.getX() - (elBBox ? elBBox.getX() : 0), scenePosition.getY() - (elBBox ? elBBox.getY() : 0)))\n\n                            // Insert element and select it\n                            this._editor.insertElements([source]);\n                            acceptedDrop = true;\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    /** @override */\n    IFEditorView.prototype.toString = function () {\n        return \"[Object IFEditorView]\";\n    };\n\n    _.IFEditorView = IFEditorView;\n\n})(this);"
  },
  {
    "path": "src/package.json",
    "content": "{\n    \"name\": \"Gravit\",\n    \"main\": \"http://127.0.0.1:8999/\",\n    \"window\": {\n        \"toolbar\": true,\n        \"resizable\": true,\n        \"show_in_taskbar\": true,\n        \"frame\": true,\n        \"width\": 1024,\n        \"height\": 786,\n        \"show\": false\n    },\n    \"node-remote\": \"*\"\n}"
  },
  {
    "path": "style/_base.scss",
    "content": "@import 'variables';\n\nbody, html {\n  margin: 0px;\n  padding: 0px;\n  height: 100%;\n  width: 100%;\n  overflow: hidden;\n  /** Prevent double-tap = zoom on windows mobile */\n  -ms-content-zooming: none;\n\n  &, * {\n    font: $font;\n    line-height: $baseline;\n    vertical-align: middle;\n  }\n\n  *.fa {\n    font-size: 14px;\n  }\n\n  button, input {\n    // Removes inner padding and border in FF3+\n    // www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/\n    &::-moz-focus-inner {\n      border: 0;\n      padding: 0;\n    }\n  }\n\n  * {\n    /* Disable long-press callouts. */\n    -webkit-touch-callout: none;\n    /* Disable highlighting of links. */\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n    /* Prevent auto-resizing. */\n    -webkit-text-size-adjust: none;\n  }\n\n  /** No focus and selection outline except for input fields */\n  :focus {\n    outline: none;\n  }\n\n  /**No selection except for input fields */\n  :not(input):not(select):not(textArea) {\n    @include user-select(none);\n    cursor: default;\n  }\n\n  // Give dividers some base styling\n  hr {\n    height: 1px;\n    padding: 0px;\n    border: none;\n    margin: 5px 0px;\n    border-bottom: 1px solid $frameBorderColor;\n  }\n\n  // Add special header divider\n  h1.g-divider {\n    text-align: center;\n    line-height: 0 !important;\n    border-bottom: 1px dotted $frameBorderColor;\n    margin: 10px 0px 5px 0px;\n    color: $frameBorderColor;\n    text-transform: uppercase;\n    text-shadow: 0px 1px 0px $frame3DLightColor;\n\n    &:first-line {\n      background-color: $frameColor;\n    }\n    &:before {\n      content: \"\\a0\\a0\";\n    }\n    &:after {\n      content: \"\\a0\\a0\";\n    }\n  }\n}"
  },
  {
    "path": "style/_contenteditable.scss",
    "content": "[contenteditable='true'], .contenteditable {\n\n  &:focus {\n    outline: rgba(0, 0, 0, 0) solid 1px;\n  }\n\n  &, * {\n    @include user-select(all);\n    cursor: auto;\n  }\n\n  * {\n    // reset most stuff for content\n    margin: inherit;\n    padding: inherit;\n    font: inherit;\n    font-family: inherit;\n    font-size: inherit;\n    font-weight: inherit;\n    font-style: inherit;\n    text-decoration: inherit;\n    word-spacing: inherit;\n    letter-spacing: inherit;\n    color: inherit;\n    background: inherit;\n    line-height: inherit;\n    text-indent: inherit;\n    text-align: inherit;\n    white-space: inherit;\n    word-break: inherit;\n    vertical-align: inherit;\n  }\n}"
  },
  {
    "path": "style/_cursors.scss",
    "content": "@mixin g-cursor($cursor) {\n  cursor: url('cursor/#{$cursor}.cur'), auto !important;\n}\n\n.g-cursor-select {\n  @include g-cursor(select);\n}\n\n.g-cursor-select-inverse {\n  @include g-cursor(select-inverse);\n}\n\n.g-cursor-select-dot {\n  @include g-cursor(select-dot);\n}\n\n.g-cursor-select-dot-inverse {\n  @include g-cursor(select-dot-inverse);\n}\n\n.g-cursor-select-arrow-only {\n  @include g-cursor(select-arrow-only);\n}\n\n.g-cursor-select-cross {\n  @include g-cursor(select-cross);\n}\n\n.g-cursor-select-resize-vert {\n  @include g-cursor(select-resize-vert);\n}\n\n.g-cursor-select-resize-horiz {\n  @include g-cursor(select-resize-horiz);\n}\n\n.g-cursor-select-upleft-downright {\n  @include g-cursor(select-upleft-downright);\n}\n\n.g-cursor-select-upright-downleft {\n  @include g-cursor(select-upright-downleft);\n}\n\n.g-cursor-select-skew-vert {\n  @include g-cursor(select-skew-vert);\n}\n\n.g-cursor-select-skew-horiz {\n  @include g-cursor(select-skew-horiz);\n}\n\n.g-cursor-select-rot-tl {\n  @include g-cursor(select-rot-tl);\n}\n\n.g-cursor-select-rot-tc {\n  @include g-cursor(select-rot-tc);\n}\n\n.g-cursor-select-rot-tr {\n  @include g-cursor(select-rot-tr);\n}\n\n.g-cursor-select-rot-rc {\n  @include g-cursor(select-rot-rc);\n}\n\n.g-cursor-select-rot-br {\n  @include g-cursor(select-rot-br);\n}\n\n.g-cursor-select-rot-bc {\n  @include g-cursor(select-rot-bc);\n}\n\n.g-cursor-select-rot-bl {\n  @include g-cursor(select-rot-bl);\n}\n\n.g-cursor-select-rot-lc {\n  @include g-cursor(select-rot-lc);\n}\n\n.g-cursor-zoom-plus {\n  @include g-cursor(zoom-plus);\n}\n\n.g-cursor-zoom-minus {\n  @include g-cursor(zoom-minus);\n}\n\n.g-cursor-zoom-none {\n  @include g-cursor(zoom-none);\n}\n\n.g-cursor-hand-open {\n  @include g-cursor(hand-open);\n}\n\n.g-cursor-hand-closed {\n  @include g-cursor(hand-closed);\n}\n\n.g-cursor-cross {\n  @include g-cursor(cross);\n}\n\n.g-cursor-pen {\n  @include g-cursor(pen);\n}\n\n.g-cursor-pen-start {\n  @include g-cursor(pen-start);\n}\n\n.g-cursor-pen-end {\n  @include g-cursor(pen-end);\n}\n\n.g-cursor-pen-plus {\n  @include g-cursor(pen-plus);\n}\n\n.g-cursor-pen-minus {\n  @include g-cursor(pen-minus);\n}\n\n.g-cursor-pen-modify {\n  @include g-cursor(pen-modify);\n}\n\n.g-cursor-pen-drag {\n  @include g-cursor(pen-drag);\n}\n\n.g-cursor-lasso {\n  @include g-cursor(lasso);\n}\n\n.g-cursor-pipette {\n  @include g-cursor(pipette);\n}\n\n.g-cursor-text {\n  cursor: text !important;\n}"
  },
  {
    "path": "style/_fonts.scss",
    "content": "// FontAwesome import\n$fa-font-path: 'font';\n@import '../bower_components/font-awesome/scss/font-awesome.scss';"
  },
  {
    "path": "style/_input.scss",
    "content": "@import 'variables';\n\nbutton, .g-button, input, textArea, select, .g-input {\n  appearance: none;\n  -moz-appearance: none;\n  -webkit-appearance: none;\n  -ms-appearance: none;\n  @include box-sizing(border-box);\n  margin: 0px;\n  padding: 0px 3px;\n  vertical-align: middle;\n  background: $frameColor;\n  color: $textColor;\n  height: $baseline;\n  line-height: $baseline - 2px;\n\n  &:not(:last-child) {\n    margin-right: 3px;\n  }\n}\n\nbutton, .g-button {\n  border: 1px solid $frameDarkColor;\n\n  &, * {\n    vertical-align: middle;\n    text-align: center;\n    color: $textColor;\n  }\n\n  svg {\n    fill: $textColor;\n    stroke: $textColor;\n  }\n\n  &:active, &.g-active {\n    background: $activeColor;\n\n    &, * {\n      color: $activeTextColor;\n    }\n\n    svg {\n      fill: $activeTextColor;\n      stroke: $activeTextColor;\n    }\n  }\n\n  &.g-flat {\n    border: none;\n\n    &:active, &.g-active {\n      background: transparent;\n\n      &, * {\n        color: $selectedColor;\n      }\n\n      svg {\n        fill: $selectedColor;\n        stroke: $selectedColor;\n      }\n    }\n  }\n\n  &:disabled {\n    &, * {\n      color: $disabledTextColor !important;\n    }\n\n    svg {\n      fill: $disabledTextColor !important;\n      stroke: $disabledTextColor !important;\n    }\n  }\n\n  span:not(:last-child) {\n    padding-right: 5px;\n  }\n}\n\nselect, input, textArea, .g-input {\n  border: 1px solid $frameDarkColor;\n  border-radius: 0px;\n\n  &:disabled {\n    background: transparent !important;\n    color: $disabledTextColor !important;\n  }\n\n  &:focus {\n    outline: none;\n    border: 1px solid $selectedColor;\n  }\n}\n\nselect {\n  text-indent: 0.01px;\n  text-overflow: '';\n  background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNCcgaGVpZ2h0PSc1Jz4NCjxwb2x5Z29uIHBvaW50cz0iMCwwIDEwLDAgNSw1IiBmaWxsPSJyZ2IoMTk5LCAxOTksIDE5OSkiLz4NCjwvc3ZnPg==\");\n  background-repeat: no-repeat;\n  background-position: right center;\n  padding-right: 20px;\n}\n\ninput[type=\"range\"] {\n  padding: 2px;\n  height: auto !important;\n\n  &::-moz-range-track {\n    border: none;\n    background: none;\n  }\n\n  &::-moz-range-thumb {\n    background: $textColor;\n    border: 1px solid $frameBorderColor;\n    width: 8px;\n    height: 8px;\n    border-radius: 100px;\n    padding: 0px;\n    margin: 0px;\n  }\n\n  &::-webkit-slider-thumb {\n    -webkit-appearance: none;\n    background: $textColor;\n    border: 1px solid $frameBorderColor;\n    width: 9px;\n    height: 9px;\n    border-radius: 100px;\n    padding: 0px;\n    margin: 0px;\n  }\n}\n\ninput[type=checkbox], input[type=radio] {\n  width: 1em;\n  height: 1em;\n  vertical-align: middle;\n  position: relative;\n  bottom: 1px;\n\n  &:checked {\n    background: $selectedColor;\n  }\n}\n\ninput[type=radio] {\n  border-radius: 2em;\n  bottom: 2px;\n}\n\n\n/** Switch */\n.g-switch {\n  position: relative;\n  display: inline-block;\n  border: 1px solid $frameDarkColor;\n\n  &:not(:last-child) {\n    margin-right: 3px;\n  }\n\n  &, * {\n    cursor: pointer;\n  }\n\n  input[type=\"checkbox\"] {\n    position: absolute;\n    opacity: 0;\n  }\n\n  label {\n    display: block;\n    overflow: hidden;\n    cursor: pointer;\n  }\n\n  .switch {\n    display: block;\n    width: 200%;\n    margin-left: -100%;\n    -moz-transition: margin 0.3s ease-in 0s;\n    -webkit-transition: margin 0.3s ease-in 0s;\n    -o-transition: margin 0.3s ease-in 0s;\n    transition: margin 0.3s ease-in 0s;\n  }\n\n  .switch:before,\n  .switch:after {\n    display: block;\n    float: left;\n    width: 50%;\n    margin: 0px;\n    padding: 4px;\n    color: $textColor;\n    line-height: 1em;\n    vertical-align: middle;\n    text-align: center;\n    -moz-box-sizing: border-box;\n    -webkit-box-sizing: border-box;\n    box-sizing: border-box;\n  }\n\n  .switch:before {\n    content: attr(data-on);\n    background-color: $frameDarkColor;\n  }\n\n  .switch:after {\n    content: attr(data-off);\n    background: $frameColor;\n  }\n\n  input[type=\"checkbox\"]:checked + .switch {\n    margin-left: 0;\n  }\n\n  input[type=\"checkbox\"]:disabled + .switch:before,\n  input[type=\"checkbox\"]:disabled + .switch:after {\n    background: $frameColor !important;\n    color: $disabledTextColor !important;\n  }\n}"
  },
  {
    "path": "style/_variables.scss",
    "content": "$baseline: 20px;\n$font: 12px 'Source Sans Pro', sans-serif;\n$menuFont: 12px 'Open Sans', sans-serif;\n\n$frameColor: rgb(77, 80, 82);\n$frameDarkColor: rgb(57, 57, 57);\n$frameInputColor: rgb(87, 91, 92);\n$frameBorderColor: rgb(46, 49, 50);\n$frame3DLightColor: rgb(100, 102, 104);\n$frame3DShadowColor: rgb(49, 52, 53);\n\n$textColor: rgb(199, 199, 199);\n$disabledTextColor: rgba(255, 255, 255, 0.25);\n\n$selectedColor: rgb(31, 141, 214);\n$selectedTextColor: white;\n\n$activeColor: rgb(90, 102, 118);\n$activeTextColor: white;\n\n$dragColor: maroon;\n$dragTextColor: white;\n\n/*\n\n\n$light_0: rgb(240, 240, 240);\n$light_1: rgb(199, 199, 199);\n$light_2: rgb(158, 158, 158);\n$light_3: rgb(100, 102, 104);\n\n$shade_0: rgb(49, 51, 53);\n$shade_1: rgb(57, 57, 57);\n$shade_2: rgb(64, 67, 69);\n$shade_3: rgb(77, 80, 82);\n\n\n$bg_1: rgb(77, 80, 82);\n$bgRegular: rgb(57, 57, 57);\n$bgDark: rgb(57, 57, 57);\n\n$windowColor1: rgb(57, 57, 57);\n\n$darkGreen: rgb(159, 180, 0);\n$lightGreen: rgb(246, 245, 164);\n$yellow: rgb(255, 255, 0);\n$magentaColor: rgb(230, 0, 99);\n\n$windowHeaderColor: $darkGreen;\n$windowHeaderTextColor: $yellow;\n\n$highlightColor: rgb(31, 141, 214);\n$highlightTextColor: white;\n*/"
  },
  {
    "path": "style/component/_colorpanel.scss",
    "content": "@import '../variables';\n\n.g-color-panel {\n  width: 275px;\n\n  .toolbar {\n    width: 100%;\n    margin-bottom: 5px;\n\n    > div {\n      display: table-cell;\n      vertical-align: middle;\n      white-space: nowrap;\n\n      &.section-center {\n        text-align: center;\n        width: 100%;\n      }\n\n      &.section-end {\n        text-align: right;\n      }\n    }\n  }\n\n  .color-view {\n    margin-bottom: 5px;\n  }\n\n  .color-components {\n    margin-bottom: 5px;\n\n    > .color-component {\n      display: table;\n      width: 100%;\n      margin-bottom: 3px;\n\n      > div {\n        display: table-cell;\n        vertical-align: middle;\n      }\n\n      > .color-label {\n        min-width: 1.5em;\n        max-width: 1.5em;\n      }\n\n      > .color-range {\n        width: 100%;\n        padding-right: 5px;\n\n        > input {\n          width: 100%;\n        }\n      }\n\n      > .color-value {\n        min-width: 3em;\n        max-width: 3em;\n        padding-right: 7px;\n\n        > input {\n          width: 100%;\n          text-align: center;\n        }\n      }\n\n      > .color-unit {\n        min-width: 1em;\n        max-width: 1em;\n        text-align: left;\n      }\n    }\n  }\n\n  .color {\n    padding-top: 3px;\n    margin-bottom: 5px;\n\n    > div {\n      display: table-cell;\n      vertical-align: middle;\n      white-space: nowrap;\n    }\n\n    > div:last-child {\n      text-align: right;\n      width: 100%;\n    }\n\n    .previous-color, .current-color {\n      display: inline-block;\n      width: 3em;\n    }\n\n    .previous-color {\n      margin-right: 0px;\n      border-right: none;\n    }\n\n    .current-color {\n      border-left: none;\n    }\n\n    .color-difference {\n      display: inline-block;\n      width: 2em;\n      border: none;\n      text-align: center;\n    }\n\n    .color-input {\n      width: 5.5em;\n    }\n\n    .matcher-select {\n      width: 100px;\n    }\n  }\n\n  .matcher-palette {\n    width: 100%;\n    height: 27px;\n    border: 1px solid $frameBorderColor;\n\n    > div {\n      @include box-sizing(border-box);\n      display: inline-block;\n      height: 100%;\n    }\n\n    > div:not(:last-child) {\n      border-right: 1px solid $frameBorderColor;\n    }\n  }\n\n  [data-view=\"palette\"] {\n    @include g-cursor(pipette);\n    border-collapse: separate;\n    border-spacing: 1px;\n\n    .swatch {\n      @include g-cursor(pipette);\n      border: 1px solid $frameDarkColor;\n      width: 8px;\n      height: 8px;\n      padding: 1px;\n\n      &:hover {\n        border: 1px solid aquamarine;\n      }\n    }\n  }\n\n  [data-view=\"swatches\"] {\n    padding: 0px;\n\n    .swatch-block {\n      @include g-cursor(pipette);\n\n      .swatch-preview {\n        padding: 0px;\n        border: 1px solid $frameDarkColor;\n\n        > div {\n          box-shadow: none;\n        }\n      }\n\n      &:hover .swatch-preview {\n        border: 1px solid aquamarine;\n      }\n\n      &.swatch-null {\n        cursor: pointer !important;\n\n        .swatch-preview {\n          border: 1px solid $frameColor;\n        }\n\n        &:hover .swatch-preview {\n          border: 1px solid $frameColor;\n        }\n      }\n    }\n  }\n\n  [data-view=\"trends\"] {\n    > .color-trend-label {\n      margin-bottom: 5px;\n    }\n\n    > .color-trend {\n      display: table;\n      width: 100%;\n      padding-bottom: 7px;\n\n      > div, > span {\n        display: table-cell;\n        vertical-align: middle;\n      }\n\n      > .color-palette {\n        width: 100%;\n        padding-right: 7px;\n\n        > div {\n          width: 100%;\n          border: 1px solid $frameBorderColor;\n\n          > div {\n            display: inline-block;\n            height: 100%;\n            margin: 0px;\n            padding-left: 0px;\n            padding-right: 0px;\n            border: none;\n            @include box-sizing(border-box);\n          }\n\n          > div:last-child {\n            border-left: 3px solid $frameBorderColor;\n          }\n        }\n      }\n\n      > .color-trend-value {\n        min-width: 3em;\n        max-width: 3em;\n        padding-right: 8px;\n\n        > input {\n          width: 100%;\n          text-align: center;\n        }\n      }\n    }\n  }\n\n  [data-view=\"image\"] {\n    .image-panel {\n      height: 150px;\n      line-height: 150px;\n      text-align: center;\n      background-size: contain;\n      background-position: center center;\n      background-repeat: no-repeat;\n      margin: 5px 0px;\n      background-color: #FFF;\n      border: 5px solid #FFF;\n    }\n\n    .image-palette {\n      width: 100%;\n      height: 27px;\n      border: 1px solid $frameBorderColor;\n\n      > div {\n        @include box-sizing(border-box);\n        display: inline-block;\n        height: 100%;\n        width: 12.5%;\n      }\n\n      > div:not(:last-child) {\n        border-right: 1px solid $frameBorderColor;\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/component/_colorswatch.scss",
    "content": "@import '../variables';\n\n.g-color-swatches {\n  @include g-cursor(pipette);\n  border-collapse: separate;\n  border-spacing: 1px;\n\n  .swatch {\n    @include g-cursor(pipette);\n    border: 1px solid $frameDarkColor;\n    width: 8px;\n    height: 8px;\n\n    &:hover {\n      border: 1px solid aquamarine;\n    }\n  }\n}\n\n.g-color-swatch {\n  width: 1em;\n  height: 1em;\n}\n\ndiv.g-color-swatch {\n  display: inline-block;\n}"
  },
  {
    "path": "style/component/_form.scss",
    "content": "@import '../variables';\n\ntable.g-form {\n  td {\n    padding-bottom: 5px;\n  }\n\n  tr:last-child td {\n    padding-bottom: 0px;\n  }\n\n  td.label {\n    padding-right: 5px;\n    text-align: right;\n  }\n\n  td.label:not(:first-child) {\n    padding-left: 10px;\n  }\n\n  td > hr {\n    margin: 1px 0px 2px 0px;\n  }\n}\n\ndiv.g-form {\n  //display: table;\n\n  > div {\n    //display: table-row;\n\n    > div {\n      display: table-cell;\n      vertical-align: middle;\n      white-space: nowrap;\n\n      &:not(:last-child) {\n        padding-right: 5px;\n      }\n\n      > label {\n        &:first-child, &:last-child {\n          display: block;\n          text-align: center;\n        }\n\n        &:first-child {\n          padding-bottom: 5px;\n        }\n\n        &:last-child {\n          padding-top: 5px;\n        }\n      }\n    }\n\n    &:not(:first-child) > div {\n      > label:first-child {\n        padding-top: 5px;\n      }\n    }\n\n    &:not(:last-child) > div {\n      padding-bottom: 5px;\n\n      > label:last-child {\n        padding-bottom: 5px;\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/component/_gradienteditor.scss",
    "content": "@import '../variables';\n\n.g-gradient-editor {\n\n  > .container {\n    display: table;\n    width: 100%;\n\n    > div {\n      display: table-cell;\n      vertical-align: top;\n    }\n\n    > .editor {\n      width: 100%;\n\n      > .gradient {\n        height: 12px;\n      }\n\n      > .stops {\n        position: relative;\n        height: 12px;\n        margin: 0px 5px 0px 0px;\n\n        > .stop {\n          position: absolute;\n          z-index: 1;\n          margin-left: -5px;\n\n          &, * {\n            @include g-cursor(select-dot);\n          }\n\n          > .stop-color {\n            background: $textColor;\n            border: 1px solid $frameBorderColor;\n            width: 8px;\n            height: 8px;\n            border-radius: 100px;\n            padding: 0px;\n            margin: 0px;\n            margin-top: 1px;\n\n            &::before {\n              border-color: transparent transparent $frameBorderColor transparent;\n              border-style: solid;\n              border-width: 5px;\n              width: 0;\n              height: 0;\n              position: absolute;\n              top: -10px;\n              left: 0px;\n              content: '';\n            }\n          }\n\n          &.g-active {\n            > .stop-color {\n              border: 2px solid black;\n              margin-left: -1px;\n\n              &::before {\n                border-color: transparent transparent black transparent;\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n\n}"
  },
  {
    "path": "style/component/_menu.scss",
    "content": "@import '../variables';\n\n/** Base styling for ul menu */\n.g-menu {\n  margin: 0px;\n  padding: 0px;\n\n  &, * {\n    /** Make everything based on border-box model */\n    *, *:before, *:after {\n      @include box-sizing(border-box);\n    }\n  }\n}\n\n/** Styling for a menu ul if it is not the root */\n.g-menu:not(.g-menu-root) {\n  position: absolute;\n  z-index: 100;\n  border: 1px solid $frameBorderColor;\n  background: $frameDarkColor;\n  color: $textColor;\n  padding: 4px 0px;\n  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.50);\n}\n\n/** Clear border-radius depending on direction */\n.g-menu:not(.g-menu-root).g-menu-top {\n  border-bottom-left-radius: 0px;\n  border-bottom-right-radius: 0px;\n}\n.g-menu:not(.g-menu-root).g-menu-bottom {\n  border-top-left-radius: 0px;\n  border-top-right-radius: 0px;\n}\n.g-menu:not(.g-menu-root).g-menu-left {\n  border-top-right-radius: 0px;\n  border-bottom-right-radius: 0px;\n}\n.g-menu:not(.g-menu-root).g-menu-right {\n  border-top-left-radius: 0px;\n  border-bottom-left-radius: 0px;\n}\n\n/** Styling for a menu item li */\n.g-menu-item {\n  list-style-type: none;\n  display: table;\n  margin: 0px;\n  white-space: nowrap;\n  vertical-align: middle;\n\n  &, * {\n    font: $menuFont;\n  }\n}\n\n/** Set to full width and reduce font-size if not on root */\n.g-menu:not(.g-menu-root) > .g-menu-item {\n  width: 100%;\n  padding: 1px 10px 1px 20px;\n}\n\n/* Styling for each span within a menu item */\n.g-menu-item > span {\n  display: table-cell;\n  cursor: default;\n}\n\n/** Fix line-height for sub menu items */\n.g-menu:not(.g-menu-root) > .g-menu-item > span {\n  line-height: 20px;\n}\n\n/** Change tail styling as we might be adding an arrow */\n.g-menu-item-menu > span.g-menu-item-tail {\n  text-align: right;\n  font-family: FontAwesome !important;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n/** Tail padding for root and submenu are different */\n.g-menu:not(.g-menu-root) > .g-menu-item-menu > span.g-menu-item-tail {\n  padding-left: 20px;\n}\n.g-menu.g-menu-root > .g-menu-item-menu > span.g-menu-item-tail {\n  padding-left: 5px;\n}\n\n/** For root menu items */\n.g-menu:not(.g-menu-root) > .g-menu-item > span {\n  line-height: 20px;\n}\n\n/** Add tail arrow indicator to right and spacing if sub-menu and not root */\n.g-menu:not(.g-menu-root) > .g-menu-item-menu > span.g-menu-item-tail:before {\n  content:$fa-var-caret-right;\n}\n\n/** Icon needs fixed width */\n.g-menu-item > span.g-menu-item-icon {\n  width: 16px;\n  font-size: 14px;\n}\n\n/** Right align shortcut and give some spacing as well on the left side */\n.g-menu-item > span.g-menu-item-shortcut {\n  text-align: right;\n  padding-left: 20px;\n  color: gray;\n}\n\n/** Define styling of a special \"divider\" li menu item */\n.g-menu-item-divider {\n  background: $frameBorderColor;\n  margin-top: 5px;\n  margin-bottom: 5px;\n  height: 1px;\n  padding: 0px !important;\n}\n\n/** Hide Divider if it is the first- or last-child */\n.g-menu-item-divider:first-child,\n.g-menu-item-divider:last-child {\n  display: none;\n}\n\n/** Make opacity for disabled items */\n.g-menu-item.g-disabled > span {\n  color: $disabledTextColor;\n}\n\n/** Set active/hover color if not disabled */\n.g-menu:not(.g-menu-root) > .g-menu-item.g-hover:not(.g-disabled),\n.g-menu:not(.g-menu-root) > .g-menu-item.g-hover:not(.g-disabled) > span,\n.g-menu > .g-menu-item.g-active:not(.g-disabled),\n.g-menu > .g-menu-item.g-active:not(.g-disabled) > span,\n.g-menu-root > .g-menu-item:active:not(.g-disabled),\n.g-menu-root > .g-menu-item:active:not(.g-disabled) > span {\n  background: $activeColor;\n  color: $activeTextColor;\n}\n\n/** Release left-padding for checked items to have our checkmark fit */\n.g-menu:not(.g-menu-root) > .g-menu-item.g-menu-item-checked {\n  padding-left: 4px;\n}\n\n/** Replace icon with checkmark for checked icons */\n.g-menu-item.g-menu-item-checked > span.g-menu-item-icon {\n  display: table-cell !important;\n  text-align: left;\n  font-size: 12px;\n}\n\n.g-menu-item.g-menu-item-checked > span.g-menu-item-icon:before {\n  font-family:  FontAwesome !important;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  content:$fa-var-check;\n}\n\n/** Adjustments for menu bar */\n.g-menu-bar > .g-menu {\n  height: 100%;\n  display: inline-block;\n}\n\n.g-menu-bar > .g-menu > .g-menu-item {\n  float: left;\n  height: 100%;\n  vertical-align: middle;\n}\n\n.g-menu-bar > .g-menu > .g-menu-item > span {\n  vertical-align: middle;\n}\n\n.g-menu-bar > .g-menu > .g-menu-item {\n  padding: 0px 5px;\n}\n\n.g-menu-bar > .g-menu > .g-menu-item > span.g-menu-item-tail {\n  padding-left: 0px;\n}"
  },
  {
    "path": "style/component/_overlay.scss",
    "content": "@import '../variables';\n\n.g-modal-background {\n  position: absolute;\n  top: 0px;\n  left: 0px;\n  width: 100%;\n  height: 100%;\n  background: transparent;\n}\n\n.g-overlay {\n  background: $frameColor;\n  color: $textColor;\n  border: 1px solid $frameBorderColor;\n  padding: 0px;\n  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.50);\n  z-index: 10;\n}"
  },
  {
    "path": "style/component/_panel.scss",
    "content": "@import '../variables';\n\n.g-panel {\n  > .header {\n    @include box-sizing(border-box);\n    display: table;\n    width: 100%;\n    padding: 0px 5px;\n    height: 25px;\n    background: $frameBorderColor;\n    margin-bottom: 1px;\n\n    > div {\n      display: table-cell;\n      vertical-align: middle;\n    }\n\n    > .title {\n      width: 100%;\n\n      > i.fa:first-child {\n        padding-right: 3px;\n        width: 9px;\n        text-align: center;\n      }\n    }\n\n    > .controls {\n      text-align: right;\n      white-space: nowrap;\n\n      input, button, .g-button, select {\n        border: none;\n        background: transparent !important;\n        box-shadow: none;\n        margin: 0px;\n      }\n\n      button, .g-button {\n        &.g-active {\n          &, * {\n            color: $selectedColor;\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/component/_pivot.scss",
    "content": "@import '../variables';\n\n$pivotButtonSize: 6px;\n$pivotButtonSpace: 3px;\n\n.g-pivot {\n  position: relative;\n  width: $pivotButtonSize * 3 + $pivotButtonSpace * 2;\n  height: $pivotButtonSize * 3 + $pivotButtonSpace * 2;\n\n  > .borderline {\n    position: absolute;\n    top: $pivotButtonSize / 2;\n    left: $pivotButtonSize / 2;\n    right: $pivotButtonSize / 2;\n    bottom: $pivotButtonSize / 2;\n    border: 1px solid $frameDarkColor;\n  }\n\n  > .side {\n    @include box-sizing(border-box);\n    position: absolute;\n    width: $pivotButtonSize;\n    height: $pivotButtonSize;\n    border: 1px solid $frameDarkColor;\n    background: white;\n    top: 0px;\n\n    &[data-side=\"tl\"], &[data-side=\"lc\"], &[data-side=\"bl\"] {\n      left: 0px;\n    }\n\n    &[data-side=\"tc\"], &[data-side=\"cc\"], &[data-side=\"bc\"] {\n      left: $pivotButtonSize + $pivotButtonSpace;\n    }\n\n    &[data-side=\"tr\"], &[data-side=\"rc\"], &[data-side=\"br\"] {\n      left: $pivotButtonSize * 2 + $pivotButtonSpace * 2;\n    }\n\n    &[data-side=\"lc\"], &[data-side=\"cc\"], &[data-side=\"rc\"] {\n      top: $pivotButtonSize + $pivotButtonSpace;\n    }\n\n    &[data-side=\"bl\"], &[data-side=\"bc\"], &[data-side=\"br\"] {\n      top: $pivotButtonSize * 2 + $pivotButtonSpace * 2;\n    }\n\n    &.g-active {\n      background: $selectedColor;\n    }\n  }\n}"
  },
  {
    "path": "style/component/_stylepanel.scss",
    "content": "@import '../variables';\n\n.g-style-panel {\n  .placeholder {\n    padding: 4px;\n  }\n\n  .style-block {\n    display: inline-block;\n    position: relative;\n    padding: 2px;\n\n    &.selected {\n      background: $selectedColor;\n      color: $selectedTextColor;\n    }\n\n    &.drop {\n      background: $dragColor;\n      color: $dragTextColor;\n    }\n\n    .style-preview {\n      padding: 2px;\n      text-align: center;\n      vertical-align: middle;\n\n      img {\n        display: block;\n        padding: 1px;\n        background: #FFF;\n        box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 0.5);\n      }\n    }\n\n    .style-name {\n      display: none;\n      font: $font;\n    }\n\n    * {\n      pointer-events: none;\n    }\n  }\n\n  &.g-style-list {\n    .style-block {\n      display: block;\n\n      .style-content {\n        display: table-row;\n        width: 100%;\n\n        > div {\n          display: table-cell;\n          vertical-align: middle;\n        }\n\n        .style-name {\n          width: 100%;\n          padding: 0px 5px;\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/component/_swatchpanel.scss",
    "content": "@import '../variables';\n\n.g-swatch-panel {\n  .placeholder {\n    padding: 4px;\n  }\n\n  .swatch-block {\n    display: inline-block;\n    position: relative;\n    padding: 2px;\n\n    &.selected {\n      background: $selectedColor;\n      color: $selectedTextColor;\n    }\n\n    &.drop {\n      background: $dragColor;\n      color: $dragTextColor;\n    }\n\n    .swatch-preview {\n      padding: 2px;\n\n      > div {\n        display: inline-block;\n        box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 0.5);\n        text-align: center;\n        vertical-align: middle;\n      }\n    }\n\n    .swatch-name {\n      display: none;\n      font: $font;\n    }\n\n    * {\n      pointer-events: none;\n    }\n  }\n\n  &.g-swatch-list {\n    .swatch-block {\n      display: block;\n\n      .swatch-content {\n        display: table-row;\n        width: 100%;\n\n        > div {\n          display: table-cell;\n          vertical-align: middle;\n        }\n\n        .swatch-name {\n          width: 100%;\n          padding: 0px 5px;\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/component/_tree.scss",
    "content": "@import '../variables';\n\nul.jqtree-tree,\nul.jqtree-tree ul.jqtree_common {\n  list-style: none outside;\n  margin-bottom: 0;\n  margin-top: 0px;\n  padding: 0;\n\n  &, * {\n    line-height: 1 !important;\n  }\n}\n\nul.jqtree-tree ul.jqtree_common {\n  display: block;\n  margin-left: 15px;\n  margin-right: 0;\n}\n\nul.jqtree-tree li.jqtree-closed > ul.jqtree_common {\n  display: none;\n}\n\nul.jqtree-tree li.jqtree_common {\n  clear: both;\n  list-style-type: none;\n}\n\nul.jqtree-tree .jqtree-toggler {\n  vertical-align: middle;\n  padding-right: 3px;\n}\n\nul.jqtree-tree .jqtree-element {\n  margin: 0px;\n  padding: 0px 3px 3px 3px;\n}\n\nul.jqtree-tree .jqtree-title {\n  vertical-align: middle;\n}\n\nul.jqtree-tree li.jqtree-folder .jqtree-title {\n  margin-left: 0;\n}\n\nul.jqtree-tree .jqtree-toggler.jqtree-closed {\n  background-position: 0 0;\n}\n\nspan.jqtree-dragging {\n  color: #fff;\n  background: #000;\n  opacity: 0.6;\n  cursor: pointer;\n  padding: 5px 8px;\n}\n\nul.jqtree-tree li.jqtree-ghost {\n  position: relative;\n  z-index: 10;\n  margin-right: 10px;\n}\n\nul.jqtree-tree li.jqtree-ghost span {\n  display: block;\n}\n\nul.jqtree-tree li.jqtree-ghost span.jqtree-circle {\n  border-radius: 9999px;\n  background: $dragColor;\n  border: 1px solid white;\n  height: 8px;\n  width: 8px;\n  position: absolute;\n  top: -5px;\n  left: 0px;\n}\n\nul.jqtree-tree li.jqtree-ghost span.jqtree-line {\n  background-color: $dragColor;\n  height: 2px;\n  padding: 0;\n  position: absolute;\n  top: -1px;\n  left: 10px;\n  width: 100%;\n}\n\nul.jqtree-tree li.jqtree-ghost.jqtree-inside {\n  margin-left: 48px;\n}\n\nul.jqtree-tree span.jqtree-border {\n  position: absolute;\n  display: block;\n  left: 0px;\n  top: 0;\n  width: 100% !important;\n  height: 100% !important;\n  background: rgba( $dragColor, 0.5);\n  margin: 0;\n}\n\nul.jqtree-tree .jqtree-element {\n  width: 100%;\n  *width: auto;\n  position: relative;\n}\n\nul.jqtree-tree li.jqtree-selected > .jqtree-element,\nul.jqtree-tree li.jqtree-selected > .jqtree-element:hover {\n  background: $selectedColor;\n  color: $selectedTextColor;\n}\n\n"
  },
  {
    "path": "style/gravit.scss",
    "content": "@import \"compass/css3/user-interface\";\n@import \"compass/css3/box-sizing\";\n@import \"compass/reset\";\n\n@import 'fonts';\n@import 'base';\n@import 'contenteditable';\n@import 'cursors';\n@import 'input';\n\n@import 'component/form';\n@import 'component/menu';\n@import 'component/tree';\n@import 'component/overlay';\n@import 'component/panel';\n@import 'component/colorswatch';\n@import 'component/colorpanel';\n@import 'component/gradienteditor';\n@import 'component/pivot';\n@import 'component/stylepanel';\n@import 'component/swatchpanel';\n\n@import 'workspace/workspace';\n@import 'workspace/header';\n@import 'workspace/toolbar';\n@import 'workspace/panels';\n@import 'workspace/sidebars';\n@import 'workspace/windows';\n@import 'workspace/palettes';\n\n// Gravit Module\n\n@import 'module/sidebar/pageslayerssidebar';\n\n@import 'module/palette/export';\n@import 'module/palette/style';\n\n@import 'module/panel/properties';\n@import 'module/panel/transform';"
  },
  {
    "path": "style/module/palette/_export.scss",
    "content": "@import '../../variables';\n\n.palette-export {\n  padding: 5px;\n\n  > .title {\n    padding-bottom: 5px;\n    text-align: center;\n  }\n\n  > .export-table {\n    > .export-row {\n      padding: 5px 0px;\n\n      &:not(:last-child) {\n        border-bottom: 1px solid $frameBorderColor;\n      }\n\n      > .export-cell {\n        display: table-cell;\n        white-space: nowrap;\n\n        &:first-child {\n          width: 100%;\n        }\n      }\n    }\n  }\n\n  > .controls {\n    padding-top: 5px;\n    text-align: right;\n  }\n}"
  },
  {
    "path": "style/module/palette/_style.scss",
    "content": "@import '../../variables';\n\n.palette-style {\n  padding: 0px;\n\n  .style-selector {\n    padding: 5px 5px 0px 5px;\n  }\n\n  .style-settings {\n    width: 100%;\n    padding: 5px 0px;\n\n    > div {\n      display: table-cell;\n      vertical-align: middle;\n\n      &.visibility {\n        padding-left: 5px;\n        padding-right: 7px;\n        text-align: center;\n\n        > span {\n          cursor: pointer;\n        }\n      }\n\n      &:last-child {\n        padding-right: 5px;\n      }\n    }\n  }\n\n  .style-entries-panel {\n    > .style-entries-panel-table {\n      width: 100%;\n\n      > div {\n        position: relative;\n        padding: 5px 0px;\n        background: $frameColor;\n\n        &:not(:last-child) {\n          border-bottom: 1px solid $frame3DShadowColor;\n        }\n\n        &:not(:first-child) {\n          border-top: 1px solid $frame3DLightColor;\n        }\n\n        &.drag {\n          opacity: 0.5 !important;\n          cursor: pointer;\n        }\n\n        &.drop {\n            background: $dragColor;\n            &, * {\n              color: $dragTextColor;\n          }\n        }\n\n        > .drag-overlay {\n          position: absolute;\n          top: 0px;\n          left: 0px;\n          right: 0px;\n          bottom: 0px;\n        }\n\n        > div:not(.drag-overlay) {\n          display: table-cell;\n\n          vertical-align: middle;\n\n          &.visibility {\n            padding-left: 5px;\n            padding-right: 7px;\n            text-align: center;\n\n            > span {\n              cursor: pointer;\n            }\n          }\n\n          &.contents {\n            padding-right: 5px;\n            width: 100%;\n\n            > :first-child {\n              width: 100%;\n            }\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/module/panel/_properties.scss",
    "content": "@import '../../variables';\n\n.panel-properties {\n  padding: 0px;\n\n  .properties-panels {\n    height: 100%;\n\n    > .properties-panel-content {\n      overflow: scroll;\n      position: relative;\n      height: 100%;\n      float: left;\n      border-right: 1px solid $frameBorderColor;\n    }\n  }\n}"
  },
  {
    "path": "style/module/panel/_transform.scss",
    "content": "@import '../../variables';\n\n.panel-transform {\n  padding: 0px;\n\n  .transform-panels {\n    height: 100%;\n\n    > .transform-panel-content {\n      overflow: scroll;\n      position: relative;\n      height: 100%;\n      float: left;\n      border-right: 1px solid $frameBorderColor;\n    }\n  }\n}"
  },
  {
    "path": "style/module/sidebar/_pageslayerssidebar.scss",
    "content": "@import '../../variables';\n\n.sidebar-pages-layers {\n  .pages {\n    .page-block {\n      position: relative;\n      width: 100%;\n\n      &, * {\n        line-height: 1 !important;\n      }\n\n      &.g-active {\n        background: $activeColor;\n\n        &, * {\n          color: $activeTextColor;\n        }\n      }\n\n      &.g-selected {\n        background: $selectedColor;\n\n        &, * {\n          color: $selectedTextColor;\n        }\n      }\n\n      &.drop {\n        background: $dragColor;\n\n        &, * {\n          color: $dragTextColor;\n        }\n      }\n\n      &:not(:last-child) > div {\n        border-bottom: 1px solid $frame3DShadowColor;\n      }\n\n      > div:not(.drag-overlay) {\n        display: table-cell;\n        vertical-align: middle;\n        padding: 4px 0px;\n\n        &.page-visibility, &.page-lock {\n          border-right: 1px solid $frame3DShadowColor;\n          min-width: 21px;\n          max-width: 21px;\n          text-align: center;\n\n          &.page-default * {\n            color: $disabledTextColor;\n          }\n\n          &, * {\n            cursor: pointer;\n          }\n        }\n\n        &.page-name {\n          width: 100%;\n          padding-left: 3px;\n        }\n      }\n\n      > .drag-overlay {\n        position: absolute;\n        top: 0px;\n        left: 0px;\n        right: 0px;\n        bottom: 0px;\n      }\n    }\n  }\n\n  .layers {\n    div.jqtree-element {\n      padding: 0px;\n      border-bottom: 1px solid $frame3DShadowColor;\n\n      &.g-active {\n        background: $activeColor;\n\n        &, * {\n          color: $activeTextColor;\n        }\n      }\n\n      &.g-selected {\n        background: $selectedColor;\n\n        &, * {\n          color: $selectedTextColor;\n        }\n      }\n\n      > *:not(.jqtree-border) {\n        display: table-cell;\n        vertical-align: middle;\n        padding: 4px 0px;\n\n        &.layer-visibility, &.layer-lock, &.layer-outline {\n          border-right: 1px solid $frame3DShadowColor;\n          min-width: 21px;\n          max-width: 21px;\n          text-align: center;\n\n          &.layer-default {\n            color: $disabledTextColor;\n          }\n\n          &, * {\n            cursor: pointer;\n          }\n        }\n\n        &.layer-icon {\n          padding-left: 5px;\n        }\n\n        &.layer-color {\n          min-width: 8px;\n          max-width: 8px;\n        }\n\n        &.jqtree-toggler, &.layer-spacer {\n          min-width: 8px;\n          max-width: 8px;\n          padding-left: 5px;\n        }\n\n        &.jqtree-title {\n          width: 100%;\n          padding-left: 5px;\n        }\n      }\n    }\n\n    ul.jqtree_common {\n      margin-left: 0px;\n    }\n  }\n}"
  },
  {
    "path": "style/workspace/_header.scss",
    "content": "@import '../variables';\n\n#header {\n  position: absolute;\n  width: 100%;\n  background: $frameColor;\n\n  > * {\n    height: 2em !important;\n    padding: 2px 0px;\n  }\n}"
  },
  {
    "path": "style/workspace/_palettes.scss",
    "content": "@import '../variables';\n\n#palettes {\n  @include box-sizing(border-box);\n  position: absolute;\n  right: 0px;\n  width: 260px;\n  background: $frameColor;\n  border-left: 1px solid $frameBorderColor;\n\n  .palette-group {\n    overflow: hidden;\n\n    &:last-child, &.collapsed-palette {\n      border-bottom: none;\n    }\n\n    > .palette-group-header {\n      display: table;\n      padding-top: 2px;\n      height: 25px;\n      width: 100%;\n      //background: #CED7E0 linear-gradient(to top, $frameDarkColor, $frameColor);\n      //border-top: 1px solid $frame3DLightColor;\n      //border-bottom: 1px solid $frame3DShadowColor;\n      background: $frameDarkColor;\n      border-bottom: 1px solid $frame3DShadowColor;\n\n      > * {\n        display: table-cell;\n        height: 100%;\n        vertical-align: middle;\n        white-space: nowrap;\n      }\n\n      button {\n        background: $frameDarkColor;\n        border: none;\n        margin: 0px;\n      }\n\n      > .palette-group-collapse > button {\n        padding: 0px;\n      }\n\n      > .palette-group-tabs {\n        width: 100%;\n\n        > button {\n          //padding-right: 5px;\n          //border-left: 1px solid $frameBorderColor;\n          //padding-left: 5px;\n          //font-weight: 600;\n          padding-left: 5px;\n          padding-right: 5px;\n          text-transform: uppercase;\n          //color: $selectedColor;\n\n          &:active, &.g-active {\n            background: $activeColor;\n\n            &, * {\n              color: $activeTextColor;\n            }\n\n            svg {\n              fill: $activeTextColor;\n              stroke: $activeTextColor;\n            }\n          }\n        }\n      }\n\n      > :last-child {\n        padding-right: 5px;\n      }\n    }\n\n    .palette-panel {\n      position: relative;\n\n      .fa {\n        font-size: 14px;\n      }\n\n      > .panel-disabled-overlay {\n        position: absolute;\n        width: 100%;\n        height: 100%;\n        top: 0px;\n        left: 0px;\n        background: rgba(0, 0, 0, 0.5);\n      }\n    }\n  }\n}"
  },
  {
    "path": "style/workspace/_panels.scss",
    "content": "@import '../variables';\n\n#panels {\n  @include box-sizing(border-box);\n  position: absolute;\n  bottom: 0px;\n  height: 146px;\n  padding: 0px;\n  border-top: 1px solid $frameBorderColor;\n  border-left: 2px solid $frameDarkColor;\n  border-right: 2px solid $frameDarkColor;\n  background: $frameColor;\n\n  .panels-tabs {\n    height: 21px;\n    background: $frameDarkColor;\n\n    > button {\n      background: $frameDarkColor;\n      padding-left: 7px;\n      padding-right: 7px;\n      text-transform: uppercase;\n      border: none;\n\n      &:active, &.g-active {\n        background: $frameColor;\n\n        &, * {\n          color: $textColor;\n        }\n      }\n    }\n  }\n\n  .panels-frame {\n    width: 100%;\n    height: 125px;\n\n    .panel-container {\n      width: 100%;\n      height: 100%;\n      position: relative;\n    }\n  }\n}"
  },
  {
    "path": "style/workspace/_sidebars.scss",
    "content": "@import '../variables';\n\n#sidebars {\n  @include box-sizing(border-box);\n  position: absolute;\n  top: 0px;\n  left: 0px;\n  width: 200px;\n  height: 100%;\n  padding: 0px;\n  border-left: 2px solid $frameDarkColor;\n  border-right: 1px solid $frameBorderColor;\n  background: $frameColor;\n\n  .sidebar-container {\n    width: 100%;\n    height: 100%;\n  }\n}"
  },
  {
    "path": "style/workspace/_toolbar.scss",
    "content": "@import '../variables';\n\n#toolbar {\n  @include box-sizing(border-box);\n  position: absolute;\n  width: 61px; // + border size\n  background: $frameColor;\n  border-right: 1px solid $frame3DShadowColor;\n  border-top: 3px solid $frameDarkColor;\n\n  > div.section {\n    padding: 0px 2px;\n\n    > button {\n      position: relative;\n      padding: 0px;\n      margin: 1px 0px;\n      width: 28px;\n      height: 28px;\n      border: none;\n\n      > .fa-caret-down {\n        position: absolute;\n        bottom: 0.5px;\n        right: 0.5px;\n        font-size: 10px;\n        transform: rotate(-45deg);\n      }\n    }\n\n    > .divider {\n      width: 100%;\n      padding: 2px 0px;\n      text-align: center;\n      color: $frameBorderColor;\n      text-transform: uppercase;\n      text-shadow: 0px 1px 0px $frame3DLightColor;\n\n      &:not(:first-child) {\n        margin-top: 3px;\n        border-top: 1px dotted $frameBorderColor;\n      }\n    }\n\n    &.sidebars {\n      border-bottom: 3px solid $frameDarkColor;\n    }\n\n    &.toolpanel {\n      > button {\n        border: none;\n      }\n\n      > .zoom {\n        position: relative;\n\n        > button {\n          position: absolute;\n          top: 0px;\n          height: 100%;\n          font-size: 10px !important;\n          border: none;\n\n          &:first-child {\n            left: 0px;\n          }\n\n          &:last-child {\n            right: 0px;\n          }\n        }\n\n        > input {\n          width: 100%;\n          text-align: center;\n          font-size: smaller;\n        }\n      }\n    }\n  }\n}\n\n.toolbar-tool-button {\n  display: table-cell;\n  width: 100%;\n  text-align: left;\n  padding: 5px;\n  height: 28px;\n  border: none;\n\n  &.g-hover {\n    background: $activeColor;\n\n    &, * {\n      color: $activeTextColor;\n    }\n\n    svg {\n      fill: $activeTextColor;\n      stroke: $activeTextColor;\n    }\n  }\n}"
  },
  {
    "path": "style/workspace/_windows.scss",
    "content": "@import '../variables';\n\n#windows {\n  position: absolute;\n  top: 0px;\n  left: 0px;\n  width: 100%;\n  height: 100%;\n  background: $frameDarkColor;\n}"
  },
  {
    "path": "style/workspace/_workspace.scss",
    "content": "@import '../variables';\n\n#workspace {\n  width: 100%;\n  height: 100%;\n  position: relative;\n  overflow: hidden;\n  font: $font;\n  background: $frameColor;\n  color: $textColor;\n}"
  },
  {
    "path": "test/index.html",
    "content": "<!doctype html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <title>Mocha Spec Runner</title>\n    <link rel=\"stylesheet\" href=\"lib/mocha/mocha.css\">\n</head>\n<body>\n    <div id=\"mocha\"></div>\n    <script src=\"lib/mocha/mocha.js\"></script>\n    <script>mocha.setup('bdd')</script>\n    <!-- assertion framework -->\n    <script src=\"lib/chai.js\"></script>\n    <script>var expect = chai.expect</script>\n\n    <!-- include source files here... -->\n    <script src=\"../lib/bower_components/appkit/dist/scripts/appkit.js\"></script>\n\n    <script src=\"../lib/scripts/graphics/core/color.js\"></script>\n    <script src=\"../lib/scripts/graphics/core/dirtylist.js\"></script>\n    <script src=\"../lib/scripts/graphics/core/math.js\"></script>\n    <script src=\"../lib/scripts/graphics/core/point.js\"></script>\n    <script src=\"../lib/scripts/graphics/core/rect.js\"></script>\n    <script src=\"../lib/scripts/graphics/core/transform.js\"></script>\n    <script src=\"../lib/scripts/graphics/core/unit.js\"></script>\n    <!-- Storage -->\n    <script src=\"../lib/scripts/graphics/storage/storable.js\"></script>\n    <script src=\"../lib/scripts/graphics/storage/storage.js\"></script>\n    <script src=\"../lib/scripts/graphics/storage/memorystorage.js\"></script>\n    <!-- Vertex -->\n    <script src=\"../lib/scripts/graphics/vertex/vertex.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/vertexsource.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/vertextarget.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/vertexcontainer.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/vertexinfo.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/vertextransformer.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/vertexpixelaligner.js\"></script>\n    <script src=\"../lib/scripts/graphics/vertex/arcvertexgenerator.js\"></script>\n    <!-- Model -->\n    <script src=\"../lib/scripts/graphics/model/selector.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/node.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/element.js\"></script>\n    <!-- Model/Shape -->\n    <script src=\"../lib/scripts/graphics/model/shape/shape.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/shape/arcshape.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/shape/ellipse.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/shape/polygon.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/shape/path.js\"></script>\n    <!-- Model/Structure -->\n    <script src=\"../lib/scripts/graphics/model/structure/group.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/structure/layer.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/structure/page.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/structure/document.js\"></script>\n    <!-- Paint -->\n    <script src=\"../lib/scripts/graphics/paint/canvas.js\"></script>\n    <script src=\"../lib/scripts/graphics/paint/htmlcanvas.js\"></script>\n    <script src=\"../lib/scripts/graphics/paint/paintcontext.js\"></script>\n    <!-- Widget -->\n    <script src=\"../lib/scripts/graphics/widget/paintwidget.js\"></script>\n    <script src=\"../lib/scripts/graphics/widget/panel.js\"></script>\n    <script src=\"../lib/scripts/graphics/widget/view.js\"></script>\n    <!-- Root -->\n    <script src=\"../lib/scripts/graphics/graphicview.js\"></script>\n    <!-- I18N -->\n    <script src=\"../lib/scripts/graphics/i18n/i18n_en.js\"></script>\n    <script src=\"../lib/scripts/graphics/i18n/i18n_de.js\"></script>\n    <script src=\"../lib/scripts/graphics/model/shape/path.js\"></script>\n\n    <!-- include spec files here... -->\n    <!-- <script src=\"spec/test.js\"></script> -->\n    <script src=\"spec/pathmodel.js\"></script>\n\n    <script>mocha.run()</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/lib/chai.js",
    "content": "!function (name, context, definition) {\n  if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {\n    module.exports = definition();\n  } else if (typeof define === 'function' && typeof define.amd  === 'object') {\n    define(function () {\n      return definition();\n    });\n  } else {\n    context[name] = definition();\n  }\n}('chai', this, function () {\n\n  function require(p) {\n    var path = require.resolve(p)\n      , mod = require.modules[path];\n    if (!mod) throw new Error('failed to require \"' + p + '\"');\n    if (!mod.exports) {\n      mod.exports = {};\n      mod.call(mod.exports, mod, mod.exports, require.relative(path));\n    }\n    return mod.exports;\n  }\n\n  require.modules = {};\n\n  require.resolve = function (path) {\n    var orig = path\n      , reg = path + '.js'\n      , index = path + '/index.js';\n    return require.modules[reg] && reg\n      || require.modules[index] && index\n      || orig;\n  };\n\n  require.register = function (path, fn) {\n    require.modules[path] = fn;\n  };\n\n  require.relative = function (parent) {\n    return function(p){\n      if ('.' != p.charAt(0)) return require(p);\n\n      var path = parent.split('/')\n        , segs = p.split('/');\n      path.pop();\n\n      for (var i = 0; i < segs.length; i++) {\n        var seg = segs[i];\n        if ('..' == seg) path.pop();\n        else if ('.' != seg) path.push(seg);\n      }\n\n      return require(path.join('/'));\n    };\n  };\n\n  require.alias = function (from, to) {\n    var fn = require.modules[from];\n    require.modules[to] = fn;\n  };\n\n\n  require.register(\"chai.js\", function(module, exports, require){\n    /*!\n     * chai\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    var used = []\n      , exports = module.exports = {};\n\n    /*!\n     * Chai version\n     */\n\n    exports.version = '1.4.2';\n\n    /*!\n     * Primary `Assertion` prototype\n     */\n\n    exports.Assertion = require('./chai/assertion');\n\n    /*!\n     * Assertion Error\n     */\n\n    exports.AssertionError = require('./chai/error');\n\n    /*!\n     * Utils for plugins (not exported)\n     */\n\n    var util = require('./chai/utils');\n\n    /**\n     * # .use(function)\n     *\n     * Provides a way to extend the internals of Chai\n     *\n     * @param {Function}\n     * @returns {this} for chaining\n     * @api public\n     */\n\n    exports.use = function (fn) {\n      if (!~used.indexOf(fn)) {\n        fn(this, util);\n        used.push(fn);\n      }\n\n      return this;\n    };\n\n    /*!\n     * Core Assertions\n     */\n\n    var core = require('./chai/core/assertions');\n    exports.use(core);\n\n    /*!\n     * Expect interface\n     */\n\n    var expect = require('./chai/interface/expect');\n    exports.use(expect);\n\n    /*!\n     * Should interface\n     */\n\n    var should = require('./chai/interface/should');\n    exports.use(should);\n\n    /*!\n     * Assert interface\n     */\n\n    var assert = require('./chai/interface/assert');\n    exports.use(assert);\n\n  }); // module: chai.js\n\n  require.register(\"chai/assertion.js\", function(module, exports, require){\n    /*!\n     * chai\n     * http://chaijs.com\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Module dependencies.\n     */\n\n    var AssertionError = require('./error')\n      , util = require('./utils')\n      , flag = util.flag;\n\n    /*!\n     * Module export.\n     */\n\n    module.exports = Assertion;\n\n\n    /*!\n     * Assertion Constructor\n     *\n     * Creates object for chaining.\n     *\n     * @api private\n     */\n\n    function Assertion (obj, msg, stack) {\n      flag(this, 'ssfi', stack || arguments.callee);\n      flag(this, 'object', obj);\n      flag(this, 'message', msg);\n    }\n\n    /*!\n      * ### Assertion.includeStack\n      *\n      * User configurable property, influences whether stack trace\n      * is included in Assertion error message. Default of false\n      * suppresses stack trace in the error message\n      *\n      *     Assertion.includeStack = true;  // enable stack on error\n      *\n      * @api public\n      */\n\n    Assertion.includeStack = false;\n\n    Assertion.addProperty = function (name, fn) {\n      util.addProperty(this.prototype, name, fn);\n    };\n\n    Assertion.addMethod = function (name, fn) {\n      util.addMethod(this.prototype, name, fn);\n    };\n\n    Assertion.addChainableMethod = function (name, fn, chainingBehavior) {\n      util.addChainableMethod(this.prototype, name, fn, chainingBehavior);\n    };\n\n    Assertion.overwriteProperty = function (name, fn) {\n      util.overwriteProperty(this.prototype, name, fn);\n    };\n\n    Assertion.overwriteMethod = function (name, fn) {\n      util.overwriteMethod(this.prototype, name, fn);\n    };\n\n    /*!\n     * ### .assert(expression, message, negateMessage, expected, actual)\n     *\n     * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass.\n     *\n     * @name assert\n     * @param {Philosophical} expression to be tested\n     * @param {String} message to display if fails\n     * @param {String} negatedMessage to display if negated expression fails\n     * @param {Mixed} expected value (remember to check for negation)\n     * @param {Mixed} actual (optional) will default to `this.obj`\n     * @api private\n     */\n\n    Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) {\n      var ok = util.test(this, arguments);\n      if (true !== showDiff) showDiff = false;\n\n      if (!ok) {\n        var msg = util.getMessage(this, arguments)\n          , actual = util.getActual(this, arguments);\n        throw new AssertionError({\n            message: msg\n          , actual: actual\n          , expected: expected\n          , stackStartFunction: (Assertion.includeStack) ? this.assert : flag(this, 'ssfi')\n          , showDiff: showDiff\n        });\n      }\n    };\n\n    /*!\n     * ### ._obj\n     *\n     * Quick reference to stored `actual` value for plugin developers.\n     *\n     * @api private\n     */\n\n    Object.defineProperty(Assertion.prototype, '_obj',\n      { get: function () {\n          return flag(this, 'object');\n        }\n      , set: function (val) {\n          flag(this, 'object', val);\n        }\n    });\n\n  }); // module: chai/assertion.js\n\n  require.register(\"chai/core/assertions.js\", function(module, exports, require){\n    /*!\n     * chai\n     * http://chaijs.com\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    module.exports = function (chai, _) {\n      var Assertion = chai.Assertion\n        , toString = Object.prototype.toString\n        , flag = _.flag;\n\n      /**\n       * ### Language Chains\n       *\n       * The following are provide as chainable getters to\n       * improve the readability of your assertions. They\n       * do not provide an testing capability unless they\n       * have been overwritten by a plugin.\n       *\n       * **Chains**\n       *\n       * - to\n       * - be\n       * - been\n       * - is\n       * - that\n       * - and\n       * - have\n       * - with\n       * - at\n       * - of\n       *\n       * @name language chains\n       * @api public\n       */\n\n      [ 'to', 'be', 'been'\n      , 'is', 'and', 'have'\n      , 'with', 'that', 'at'\n      , 'of' ].forEach(function (chain) {\n        Assertion.addProperty(chain, function () {\n          return this;\n        });\n      });\n\n      /**\n       * ### .not\n       *\n       * Negates any of assertions following in the chain.\n       *\n       *     expect(foo).to.not.equal('bar');\n       *     expect(goodFn).to.not.throw(Error);\n       *     expect({ foo: 'baz' }).to.have.property('foo')\n       *       .and.not.equal('bar');\n       *\n       * @name not\n       * @api public\n       */\n\n      Assertion.addProperty('not', function () {\n        flag(this, 'negate', true);\n      });\n\n      /**\n       * ### .deep\n       *\n       * Sets the `deep` flag, later used by the `equal` and\n       * `property` assertions.\n       *\n       *     expect(foo).to.deep.equal({ bar: 'baz' });\n       *     expect({ foo: { bar: { baz: 'quux' } } })\n       *       .to.have.deep.property('foo.bar.baz', 'quux');\n       *\n       * @name deep\n       * @api public\n       */\n\n      Assertion.addProperty('deep', function () {\n        flag(this, 'deep', true);\n      });\n\n      /**\n       * ### .a(type)\n       *\n       * The `a` and `an` assertions are aliases that can be\n       * used either as language chains or to assert a value's\n       * type (as revealed by `Object.prototype.toString`).\n       *\n       *     // typeof\n       *     expect('test').to.be.a('string');\n       *     expect({ foo: 'bar' }).to.be.an('object');\n       *     expect(null).to.be.a('null');\n       *     expect(undefined).to.be.an('undefined');\n       *\n       *     // language chain\n       *     expect(foo).to.be.an.instanceof(Foo);\n       *\n       * @name a\n       * @alias an\n       * @param {String} type\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function an(type, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object')\n          , klassStart = type.charAt(0).toUpperCase()\n          , klass = klassStart + type.slice(1)\n          , article = ~[ 'A', 'E', 'I', 'O', 'U' ].indexOf(klassStart) ? 'an ' : 'a ';\n\n        this.assert(\n            '[object ' + klass + ']' === toString.call(obj)\n          , 'expected #{this} to be ' + article + type\n          , 'expected #{this} not to be ' + article + type\n        );\n      }\n\n      Assertion.addChainableMethod('an', an);\n      Assertion.addChainableMethod('a', an);\n\n      /**\n       * ### .include(value)\n       *\n       * The `include` and `contain` assertions can be used as either property\n       * based language chains or as methods to assert the inclusion of an object\n       * in an array or a substring in a string. When used as language chains,\n       * they toggle the `contain` flag for the `keys` assertion.\n       *\n       *     expect([1,2,3]).to.include(2);\n       *     expect('foobar').to.contain('foo');\n       *     expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');\n       *\n       * @name include\n       * @alias contain\n       * @param {Object|String|Number} obj\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function includeChainingBehavior () {\n        flag(this, 'contains', true);\n      }\n\n      function include (val, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object')\n        this.assert(\n            ~obj.indexOf(val)\n          , 'expected #{this} to include ' + _.inspect(val)\n          , 'expected #{this} to not include ' + _.inspect(val));\n      }\n\n      Assertion.addChainableMethod('include', include, includeChainingBehavior);\n      Assertion.addChainableMethod('contain', include, includeChainingBehavior);\n\n      /**\n       * ### .ok\n       *\n       * Asserts that the target is truthy.\n       *\n       *     expect('everthing').to.be.ok;\n       *     expect(1).to.be.ok;\n       *     expect(false).to.not.be.ok;\n       *     expect(undefined).to.not.be.ok;\n       *     expect(null).to.not.be.ok;\n       *\n       * @name ok\n       * @api public\n       */\n\n      Assertion.addProperty('ok', function () {\n        this.assert(\n            flag(this, 'object')\n          , 'expected #{this} to be truthy'\n          , 'expected #{this} to be falsy');\n      });\n\n      /**\n       * ### .true\n       *\n       * Asserts that the target is `true`.\n       *\n       *     expect(true).to.be.true;\n       *     expect(1).to.not.be.true;\n       *\n       * @name true\n       * @api public\n       */\n\n      Assertion.addProperty('true', function () {\n        this.assert(\n            true === flag(this, 'object')\n          , 'expected #{this} to be true'\n          , 'expected #{this} to be false'\n          , this.negate ? false : true\n        );\n      });\n\n      /**\n       * ### .false\n       *\n       * Asserts that the target is `false`.\n       *\n       *     expect(false).to.be.false;\n       *     expect(0).to.not.be.false;\n       *\n       * @name false\n       * @api public\n       */\n\n      Assertion.addProperty('false', function () {\n        this.assert(\n            false === flag(this, 'object')\n          , 'expected #{this} to be false'\n          , 'expected #{this} to be true'\n          , this.negate ? true : false\n        );\n      });\n\n      /**\n       * ### .null\n       *\n       * Asserts that the target is `null`.\n       *\n       *     expect(null).to.be.null;\n       *     expect(undefined).not.to.be.null;\n       *\n       * @name null\n       * @api public\n       */\n\n      Assertion.addProperty('null', function () {\n        this.assert(\n            null === flag(this, 'object')\n          , 'expected #{this} to be null'\n          , 'expected #{this} not to be null'\n        );\n      });\n\n      /**\n       * ### .undefined\n       *\n       * Asserts that the target is `undefined`.\n       *\n       *      expect(undefined).to.be.undefined;\n       *      expect(null).to.not.be.undefined;\n       *\n       * @name undefined\n       * @api public\n       */\n\n      Assertion.addProperty('undefined', function () {\n        this.assert(\n            undefined === flag(this, 'object')\n          , 'expected #{this} to be undefined'\n          , 'expected #{this} not to be undefined'\n        );\n      });\n\n      /**\n       * ### .exist\n       *\n       * Asserts that the target is neither `null` nor `undefined`.\n       *\n       *     var foo = 'hi'\n       *       , bar = null\n       *       , baz;\n       *\n       *     expect(foo).to.exist;\n       *     expect(bar).to.not.exist;\n       *     expect(baz).to.not.exist;\n       *\n       * @name exist\n       * @api public\n       */\n\n      Assertion.addProperty('exist', function () {\n        this.assert(\n            null != flag(this, 'object')\n          , 'expected #{this} to exist'\n          , 'expected #{this} to not exist'\n        );\n      });\n\n\n      /**\n       * ### .empty\n       *\n       * Asserts that the target's length is `0`. For arrays, it checks\n       * the `length` property. For objects, it gets the count of\n       * enumerable keys.\n       *\n       *     expect([]).to.be.empty;\n       *     expect('').to.be.empty;\n       *     expect({}).to.be.empty;\n       *\n       * @name empty\n       * @api public\n       */\n\n      Assertion.addProperty('empty', function () {\n        var obj = flag(this, 'object')\n          , expected = obj;\n\n        if (Array.isArray(obj) || 'string' === typeof object) {\n          expected = obj.length;\n        } else if (typeof obj === 'object') {\n          expected = Object.keys(obj).length;\n        }\n\n        this.assert(\n            !expected\n          , 'expected #{this} to be empty'\n          , 'expected #{this} not to be empty'\n        );\n      });\n\n      /**\n       * ### .arguments\n       *\n       * Asserts that the target is an arguments object.\n       *\n       *     function test () {\n       *       expect(arguments).to.be.arguments;\n       *     }\n       *\n       * @name arguments\n       * @alias Arguments\n       * @api public\n       */\n\n      function checkArguments () {\n        var obj = flag(this, 'object')\n          , type = Object.prototype.toString.call(obj);\n        this.assert(\n            '[object Arguments]' === type\n          , 'expected #{this} to be arguments but got ' + type\n          , 'expected #{this} to not be arguments'\n        );\n      }\n\n      Assertion.addProperty('arguments', checkArguments);\n      Assertion.addProperty('Arguments', checkArguments);\n\n      /**\n       * ### .equal(value)\n       *\n       * Asserts that the target is strictly equal (`===`) to `value`.\n       * Alternately, if the `deep` flag is set, asserts that\n       * the target is deeply equal to `value`.\n       *\n       *     expect('hello').to.equal('hello');\n       *     expect(42).to.equal(42);\n       *     expect(1).to.not.equal(true);\n       *     expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });\n       *     expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });\n       *\n       * @name equal\n       * @alias equals\n       * @alias eq\n       * @alias deep.equal\n       * @param {Mixed} value\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertEqual (val, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        if (flag(this, 'deep')) {\n          return this.eql(val);\n        } else {\n          this.assert(\n              val === obj\n            , 'expected #{this} to equal #{exp}'\n            , 'expected #{this} to not equal #{exp}'\n            , val\n            , this._obj\n            , true\n          );\n        }\n      }\n\n      Assertion.addMethod('equal', assertEqual);\n      Assertion.addMethod('equals', assertEqual);\n      Assertion.addMethod('eq', assertEqual);\n\n      /**\n       * ### .eql(value)\n       *\n       * Asserts that the target is deeply equal to `value`.\n       *\n       *     expect({ foo: 'bar' }).to.eql({ foo: 'bar' });\n       *     expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);\n       *\n       * @name eql\n       * @param {Mixed} value\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('eql', function (obj, msg) {\n        if (msg) flag(this, 'message', msg);\n        this.assert(\n            _.eql(obj, flag(this, 'object'))\n          , 'expected #{this} to deeply equal #{exp}'\n          , 'expected #{this} to not deeply equal #{exp}'\n          , obj\n          , this._obj\n          , true\n        );\n      });\n\n      /**\n       * ### .above(value)\n       *\n       * Asserts that the target is greater than `value`.\n       *\n       *     expect(10).to.be.above(5);\n       *\n       * Can also be used in conjunction with `length` to\n       * assert a minimum length. The benefit being a\n       * more informative error message than if the length\n       * was supplied directly.\n       *\n       *     expect('foo').to.have.length.above(2);\n       *     expect([ 1, 2, 3 ]).to.have.length.above(2);\n       *\n       * @name above\n       * @alias gt\n       * @alias greaterThan\n       * @param {Number} value\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertAbove (n, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        if (flag(this, 'doLength')) {\n          new Assertion(obj, msg).to.have.property('length');\n          var len = obj.length;\n          this.assert(\n              len > n\n            , 'expected #{this} to have a length above #{exp} but got #{act}'\n            , 'expected #{this} to not have a length above #{exp}'\n            , n\n            , len\n          );\n        } else {\n          this.assert(\n              obj > n\n            , 'expected #{this} to be above ' + n\n            , 'expected #{this} to be at most ' + n\n          );\n        }\n      }\n\n      Assertion.addMethod('above', assertAbove);\n      Assertion.addMethod('gt', assertAbove);\n      Assertion.addMethod('greaterThan', assertAbove);\n\n      /**\n       * ### .least(value)\n       *\n       * Asserts that the target is greater than or equal to `value`.\n       *\n       *     expect(10).to.be.at.least(10);\n       *\n       * Can also be used in conjunction with `length` to\n       * assert a minimum length. The benefit being a\n       * more informative error message than if the length\n       * was supplied directly.\n       *\n       *     expect('foo').to.have.length.of.at.least(2);\n       *     expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);\n       *\n       * @name least\n       * @alias gte\n       * @param {Number} value\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertLeast (n, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        if (flag(this, 'doLength')) {\n          new Assertion(obj, msg).to.have.property('length');\n          var len = obj.length;\n          this.assert(\n              len >= n\n            , 'expected #{this} to have a length at least #{exp} but got #{act}'\n            , 'expected #{this} to not have a length below #{exp}'\n            , n\n            , len\n          );\n        } else {\n          this.assert(\n              obj >= n\n            , 'expected #{this} to be at least ' + n\n            , 'expected #{this} to be below ' + n\n          );\n        }\n      }\n\n      Assertion.addMethod('least', assertLeast);\n      Assertion.addMethod('gte', assertLeast);\n\n      /**\n       * ### .below(value)\n       *\n       * Asserts that the target is less than `value`.\n       *\n       *     expect(5).to.be.below(10);\n       *\n       * Can also be used in conjunction with `length` to\n       * assert a maximum length. The benefit being a\n       * more informative error message than if the length\n       * was supplied directly.\n       *\n       *     expect('foo').to.have.length.below(4);\n       *     expect([ 1, 2, 3 ]).to.have.length.below(4);\n       *\n       * @name below\n       * @alias lt\n       * @alias lessThan\n       * @param {Number} value\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertBelow (n, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        if (flag(this, 'doLength')) {\n          new Assertion(obj, msg).to.have.property('length');\n          var len = obj.length;\n          this.assert(\n              len < n\n            , 'expected #{this} to have a length below #{exp} but got #{act}'\n            , 'expected #{this} to not have a length below #{exp}'\n            , n\n            , len\n          );\n        } else {\n          this.assert(\n              obj < n\n            , 'expected #{this} to be below ' + n\n            , 'expected #{this} to be at least ' + n\n          );\n        }\n      }\n\n      Assertion.addMethod('below', assertBelow);\n      Assertion.addMethod('lt', assertBelow);\n      Assertion.addMethod('lessThan', assertBelow);\n\n      /**\n       * ### .most(value)\n       *\n       * Asserts that the target is less than or equal to `value`.\n       *\n       *     expect(5).to.be.at.most(5);\n       *\n       * Can also be used in conjunction with `length` to\n       * assert a maximum length. The benefit being a\n       * more informative error message than if the length\n       * was supplied directly.\n       *\n       *     expect('foo').to.have.length.of.at.most(4);\n       *     expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);\n       *\n       * @name most\n       * @alias lte\n       * @param {Number} value\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertMost (n, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        if (flag(this, 'doLength')) {\n          new Assertion(obj, msg).to.have.property('length');\n          var len = obj.length;\n          this.assert(\n              len <= n\n            , 'expected #{this} to have a length at most #{exp} but got #{act}'\n            , 'expected #{this} to not have a length above #{exp}'\n            , n\n            , len\n          );\n        } else {\n          this.assert(\n              obj <= n\n            , 'expected #{this} to be at most ' + n\n            , 'expected #{this} to be above ' + n\n          );\n        }\n      }\n\n      Assertion.addMethod('most', assertMost);\n      Assertion.addMethod('lte', assertMost);\n\n      /**\n       * ### .within(start, finish)\n       *\n       * Asserts that the target is within a range.\n       *\n       *     expect(7).to.be.within(5,10);\n       *\n       * Can also be used in conjunction with `length` to\n       * assert a length range. The benefit being a\n       * more informative error message than if the length\n       * was supplied directly.\n       *\n       *     expect('foo').to.have.length.within(2,4);\n       *     expect([ 1, 2, 3 ]).to.have.length.within(2,4);\n       *\n       * @name within\n       * @param {Number} start lowerbound inclusive\n       * @param {Number} finish upperbound inclusive\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('within', function (start, finish, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object')\n          , range = start + '..' + finish;\n        if (flag(this, 'doLength')) {\n          new Assertion(obj, msg).to.have.property('length');\n          var len = obj.length;\n          this.assert(\n              len >= start && len <= finish\n            , 'expected #{this} to have a length within ' + range\n            , 'expected #{this} to not have a length within ' + range\n          );\n        } else {\n          this.assert(\n              obj >= start && obj <= finish\n            , 'expected #{this} to be within ' + range\n            , 'expected #{this} to not be within ' + range\n          );\n        }\n      });\n\n      /**\n       * ### .instanceof(constructor)\n       *\n       * Asserts that the target is an instance of `constructor`.\n       *\n       *     var Tea = function (name) { this.name = name; }\n       *       , Chai = new Tea('chai');\n       *\n       *     expect(Chai).to.be.an.instanceof(Tea);\n       *     expect([ 1, 2, 3 ]).to.be.instanceof(Array);\n       *\n       * @name instanceof\n       * @param {Constructor} constructor\n       * @param {String} message _optional_\n       * @alias instanceOf\n       * @api public\n       */\n\n      function assertInstanceOf (constructor, msg) {\n        if (msg) flag(this, 'message', msg);\n        var name = _.getName(constructor);\n        this.assert(\n            flag(this, 'object') instanceof constructor\n          , 'expected #{this} to be an instance of ' + name\n          , 'expected #{this} to not be an instance of ' + name\n        );\n      };\n\n      Assertion.addMethod('instanceof', assertInstanceOf);\n      Assertion.addMethod('instanceOf', assertInstanceOf);\n\n      /**\n       * ### .property(name, [value])\n       *\n       * Asserts that the target has a property `name`, optionally asserting that\n       * the value of that property is strictly equal to  `value`.\n       * If the `deep` flag is set, you can use dot- and bracket-notation for deep\n       * references into objects and arrays.\n       *\n       *     // simple referencing\n       *     var obj = { foo: 'bar' };\n       *     expect(obj).to.have.property('foo');\n       *     expect(obj).to.have.property('foo', 'bar');\n       *\n       *     // deep referencing\n       *     var deepObj = {\n       *         green: { tea: 'matcha' }\n       *       , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]\n       *     };\n\n       *     expect(deepObj).to.have.deep.property('green.tea', 'matcha');\n       *     expect(deepObj).to.have.deep.property('teas[1]', 'matcha');\n       *     expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');\n       *\n       * You can also use an array as the starting point of a `deep.property`\n       * assertion, or traverse nested arrays.\n       *\n       *     var arr = [\n       *         [ 'chai', 'matcha', 'konacha' ]\n       *       , [ { tea: 'chai' }\n       *         , { tea: 'matcha' }\n       *         , { tea: 'konacha' } ]\n       *     ];\n       *\n       *     expect(arr).to.have.deep.property('[0][1]', 'matcha');\n       *     expect(arr).to.have.deep.property('[1][2].tea', 'konacha');\n       *\n       * Furthermore, `property` changes the subject of the assertion\n       * to be the value of that property from the original object. This\n       * permits for further chainable assertions on that property.\n       *\n       *     expect(obj).to.have.property('foo')\n       *       .that.is.a('string');\n       *     expect(deepObj).to.have.property('green')\n       *       .that.is.an('object')\n       *       .that.deep.equals({ tea: 'matcha' });\n       *     expect(deepObj).to.have.property('teas')\n       *       .that.is.an('array')\n       *       .with.deep.property('[2]')\n       *         .that.deep.equals({ tea: 'konacha' });\n       *\n       * @name property\n       * @alias deep.property\n       * @param {String} name\n       * @param {Mixed} value (optional)\n       * @param {String} message _optional_\n       * @returns value of property for chaining\n       * @api public\n       */\n\n      Assertion.addMethod('property', function (name, val, msg) {\n        if (msg) flag(this, 'message', msg);\n\n        var descriptor = flag(this, 'deep') ? 'deep property ' : 'property '\n          , negate = flag(this, 'negate')\n          , obj = flag(this, 'object')\n          , value = flag(this, 'deep')\n            ? _.getPathValue(name, obj)\n            : obj[name];\n\n        if (negate && undefined !== val) {\n          if (undefined === value) {\n            msg = (msg != null) ? msg + ': ' : '';\n            throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));\n          }\n        } else {\n          this.assert(\n              undefined !== value\n            , 'expected #{this} to have a ' + descriptor + _.inspect(name)\n            , 'expected #{this} to not have ' + descriptor + _.inspect(name));\n        }\n\n        if (undefined !== val) {\n          this.assert(\n              val === value\n            , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'\n            , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'\n            , val\n            , value\n          );\n        }\n\n        flag(this, 'object', value);\n      });\n\n\n      /**\n       * ### .ownProperty(name)\n       *\n       * Asserts that the target has an own property `name`.\n       *\n       *     expect('test').to.have.ownProperty('length');\n       *\n       * @name ownProperty\n       * @alias haveOwnProperty\n       * @param {String} name\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertOwnProperty (name, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        this.assert(\n            obj.hasOwnProperty(name)\n          , 'expected #{this} to have own property ' + _.inspect(name)\n          , 'expected #{this} to not have own property ' + _.inspect(name)\n        );\n      }\n\n      Assertion.addMethod('ownProperty', assertOwnProperty);\n      Assertion.addMethod('haveOwnProperty', assertOwnProperty);\n\n      /**\n       * ### .length(value)\n       *\n       * Asserts that the target's `length` property has\n       * the expected value.\n       *\n       *     expect([ 1, 2, 3]).to.have.length(3);\n       *     expect('foobar').to.have.length(6);\n       *\n       * Can also be used as a chain precursor to a value\n       * comparison for the length property.\n       *\n       *     expect('foo').to.have.length.above(2);\n       *     expect([ 1, 2, 3 ]).to.have.length.above(2);\n       *     expect('foo').to.have.length.below(4);\n       *     expect([ 1, 2, 3 ]).to.have.length.below(4);\n       *     expect('foo').to.have.length.within(2,4);\n       *     expect([ 1, 2, 3 ]).to.have.length.within(2,4);\n       *\n       * @name length\n       * @alias lengthOf\n       * @param {Number} length\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      function assertLengthChain () {\n        flag(this, 'doLength', true);\n      }\n\n      function assertLength (n, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        new Assertion(obj, msg).to.have.property('length');\n        var len = obj.length;\n\n        this.assert(\n            len == n\n          , 'expected #{this} to have a length of #{exp} but got #{act}'\n          , 'expected #{this} to not have a length of #{act}'\n          , n\n          , len\n        );\n      }\n\n      Assertion.addChainableMethod('length', assertLength, assertLengthChain);\n      Assertion.addMethod('lengthOf', assertLength, assertLengthChain);\n\n      /**\n       * ### .match(regexp)\n       *\n       * Asserts that the target matches a regular expression.\n       *\n       *     expect('foobar').to.match(/^foo/);\n       *\n       * @name match\n       * @param {RegExp} RegularExpression\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('match', function (re, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        this.assert(\n            re.exec(obj)\n          , 'expected #{this} to match ' + re\n          , 'expected #{this} not to match ' + re\n        );\n      });\n\n      /**\n       * ### .string(string)\n       *\n       * Asserts that the string target contains another string.\n       *\n       *     expect('foobar').to.have.string('bar');\n       *\n       * @name string\n       * @param {String} string\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('string', function (str, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        new Assertion(obj, msg).is.a('string');\n\n        this.assert(\n            ~obj.indexOf(str)\n          , 'expected #{this} to contain ' + _.inspect(str)\n          , 'expected #{this} to not contain ' + _.inspect(str)\n        );\n      });\n\n\n      /**\n       * ### .keys(key1, [key2], [...])\n       *\n       * Asserts that the target has exactly the given keys, or\n       * asserts the inclusion of some keys when using the\n       * `include` or `contain` modifiers.\n       *\n       *     expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);\n       *     expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');\n       *\n       * @name keys\n       * @alias key\n       * @param {String...|Array} keys\n       * @api public\n       */\n\n      function assertKeys (keys) {\n        var obj = flag(this, 'object')\n          , str\n          , ok = true;\n\n        keys = keys instanceof Array\n          ? keys\n          : Array.prototype.slice.call(arguments);\n\n        if (!keys.length) throw new Error('keys required');\n\n        var actual = Object.keys(obj)\n          , len = keys.length;\n\n        // Inclusion\n        ok = keys.every(function(key){\n          return ~actual.indexOf(key);\n        });\n\n        // Strict\n        if (!flag(this, 'negate') && !flag(this, 'contains')) {\n          ok = ok && keys.length == actual.length;\n        }\n\n        // Key string\n        if (len > 1) {\n          keys = keys.map(function(key){\n            return _.inspect(key);\n          });\n          var last = keys.pop();\n          str = keys.join(', ') + ', and ' + last;\n        } else {\n          str = _.inspect(keys[0]);\n        }\n\n        // Form\n        str = (len > 1 ? 'keys ' : 'key ') + str;\n\n        // Have / include\n        str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;\n\n        // Assertion\n        this.assert(\n            ok\n          , 'expected #{this} to ' + str\n          , 'expected #{this} to not ' + str\n        );\n      }\n\n      Assertion.addMethod('keys', assertKeys);\n      Assertion.addMethod('key', assertKeys);\n\n      /**\n       * ### .throw(constructor)\n       *\n       * Asserts that the function target will throw a specific error, or specific type of error\n       * (as determined using `instanceof`), optionally with a RegExp or string inclusion test\n       * for the error's message.\n       *\n       *     var err = new ReferenceError('This is a bad function.');\n       *     var fn = function () { throw err; }\n       *     expect(fn).to.throw(ReferenceError);\n       *     expect(fn).to.throw(Error);\n       *     expect(fn).to.throw(/bad function/);\n       *     expect(fn).to.not.throw('good function');\n       *     expect(fn).to.throw(ReferenceError, /bad function/);\n       *     expect(fn).to.throw(err);\n       *     expect(fn).to.not.throw(new RangeError('Out of range.'));\n       *\n       * Please note that when a throw expectation is negated, it will check each\n       * parameter independently, starting with error constructor type. The appropriate way\n       * to check for the existence of a type of error but for a message that does not match\n       * is to use `and`.\n       *\n       *     expect(fn).to.throw(ReferenceError)\n       *        .and.not.throw(/good function/);\n       *\n       * @name throw\n       * @alias throws\n       * @alias Throw\n       * @param {ErrorConstructor} constructor\n       * @param {String|RegExp} expected error message\n       * @param {String} message _optional_\n       * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n       * @api public\n       */\n\n      function assertThrows (constructor, errMsg, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        new Assertion(obj, msg).is.a('function');\n\n        var thrown = false\n          , desiredError = null\n          , name = null\n          , thrownError = null;\n\n        if (arguments.length === 0) {\n          errMsg = null;\n          constructor = null;\n        } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {\n          errMsg = constructor;\n          constructor = null;\n        } else if (constructor && constructor instanceof Error) {\n          desiredError = constructor;\n          constructor = null;\n          errMsg = null;\n        } else if (typeof constructor === 'function') {\n          name = (new constructor()).name;\n        } else {\n          constructor = null;\n        }\n\n        try {\n          obj();\n        } catch (err) {\n          // first, check desired error\n          if (desiredError) {\n            this.assert(\n                err === desiredError\n              , 'expected #{this} to throw ' + _.inspect(desiredError) + ' but ' + _.inspect(err) + ' was thrown'\n              , 'expected #{this} to not throw ' + _.inspect(desiredError)\n            );\n            return this;\n          }\n          // next, check constructor\n          if (constructor) {\n            this.assert(\n                err instanceof constructor\n              , 'expected #{this} to throw ' + name + ' but ' + _.inspect(err) + ' was thrown'\n              , 'expected #{this} to not throw ' + name + ' but ' + _.inspect(err) + ' was thrown');\n            if (!errMsg) return this;\n          }\n          // next, check message\n          if (err.message && errMsg && errMsg instanceof RegExp) {\n            this.assert(\n                errMsg.exec(err.message)\n              , 'expected #{this} to throw error matching ' + errMsg + ' but got ' + _.inspect(err.message)\n              , 'expected #{this} to throw error not matching ' + errMsg\n            );\n            return this;\n          } else if (err.message && errMsg && 'string' === typeof errMsg) {\n            this.assert(\n                ~err.message.indexOf(errMsg)\n              , 'expected #{this} to throw error including #{exp} but got #{act}'\n              , 'expected #{this} to throw error not including #{act}'\n              , errMsg\n              , err.message\n            );\n            return this;\n          } else {\n            thrown = true;\n            thrownError = err;\n          }\n        }\n\n        var expectedThrown = name ? name : desiredError ? _.inspect(desiredError) : 'an error';\n        var actuallyGot = ''\n        if (thrown) {\n          actuallyGot = ' but ' + _.inspect(thrownError) + ' was thrown'\n        }\n\n        this.assert(\n            thrown === true\n          , 'expected #{this} to throw ' + expectedThrown + actuallyGot\n          , 'expected #{this} to not throw ' + expectedThrown + actuallyGot\n        );\n      };\n\n      Assertion.addMethod('throw', assertThrows);\n      Assertion.addMethod('throws', assertThrows);\n      Assertion.addMethod('Throw', assertThrows);\n\n      /**\n       * ### .respondTo(method)\n       *\n       * Asserts that the object or class target will respond to a method.\n       *\n       *     Klass.prototype.bar = function(){};\n       *     expect(Klass).to.respondTo('bar');\n       *     expect(obj).to.respondTo('bar');\n       *\n       * To check if a constructor will respond to a static function,\n       * set the `itself` flag.\n       *\n       *    Klass.baz = function(){};\n       *    expect(Klass).itself.to.respondTo('baz');\n       *\n       * @name respondTo\n       * @param {String} method\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('respondTo', function (method, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object')\n          , itself = flag(this, 'itself')\n          , context = ('function' === typeof obj && !itself)\n            ? obj.prototype[method]\n            : obj[method];\n\n        this.assert(\n            'function' === typeof context\n          , 'expected #{this} to respond to ' + _.inspect(method)\n          , 'expected #{this} to not respond to ' + _.inspect(method)\n        );\n      });\n\n      /**\n       * ### .itself\n       *\n       * Sets the `itself` flag, later used by the `respondTo` assertion.\n       *\n       *    function Foo() {}\n       *    Foo.bar = function() {}\n       *    Foo.prototype.baz = function() {}\n       *\n       *    expect(Foo).itself.to.respondTo('bar');\n       *    expect(Foo).itself.not.to.respondTo('baz');\n       *\n       * @name itself\n       * @api public\n       */\n\n      Assertion.addProperty('itself', function () {\n        flag(this, 'itself', true);\n      });\n\n      /**\n       * ### .satisfy(method)\n       *\n       * Asserts that the target passes a given truth test.\n       *\n       *     expect(1).to.satisfy(function(num) { return num > 0; });\n       *\n       * @name satisfy\n       * @param {Function} matcher\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('satisfy', function (matcher, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        this.assert(\n            matcher(obj)\n          , 'expected #{this} to satisfy ' + _.inspect(matcher)\n          , 'expected #{this} to not satisfy' + _.inspect(matcher)\n          , this.negate ? false : true\n          , matcher(obj)\n        );\n      });\n\n      /**\n       * ### .closeTo(expected, delta)\n       *\n       * Asserts that the target is equal `expected`, to within a +/- `delta` range.\n       *\n       *     expect(1.5).to.be.closeTo(1, 0.5);\n       *\n       * @name closeTo\n       * @param {Number} expected\n       * @param {Number} delta\n       * @param {String} message _optional_\n       * @api public\n       */\n\n      Assertion.addMethod('closeTo', function (expected, delta, msg) {\n        if (msg) flag(this, 'message', msg);\n        var obj = flag(this, 'object');\n        this.assert(\n            Math.abs(obj - expected) <= delta\n          , 'expected #{this} to be close to ' + expected + ' +/- ' + delta\n          , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta\n        );\n      });\n\n    };\n\n  }); // module: chai/core/assertions.js\n\n  require.register(\"chai/error.js\", function(module, exports, require){\n    /*!\n     * chai\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Main export\n     */\n\n    module.exports = AssertionError;\n\n    /**\n     * # AssertionError (constructor)\n     *\n     * Create a new assertion error based on the Javascript\n     * `Error` prototype.\n     *\n     * **Options**\n     * - message\n     * - actual\n     * - expected\n     * - operator\n     * - startStackFunction\n     *\n     * @param {Object} options\n     * @api public\n     */\n\n    function AssertionError (options) {\n      options = options || {};\n      this.message = options.message;\n      this.actual = options.actual;\n      this.expected = options.expected;\n      this.operator = options.operator;\n      this.showDiff = options.showDiff;\n\n      if (options.stackStartFunction && Error.captureStackTrace) {\n        var stackStartFunction = options.stackStartFunction;\n        Error.captureStackTrace(this, stackStartFunction);\n      }\n    }\n\n    /*!\n     * Inherit from Error\n     */\n\n    AssertionError.prototype = Object.create(Error.prototype);\n    AssertionError.prototype.name = 'AssertionError';\n    AssertionError.prototype.constructor = AssertionError;\n\n    /**\n     * # toString()\n     *\n     * Override default to string method\n     */\n\n    AssertionError.prototype.toString = function() {\n      return this.message;\n    };\n\n  }); // module: chai/error.js\n\n  require.register(\"chai/interface/assert.js\", function(module, exports, require){\n    /*!\n     * chai\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n\n    module.exports = function (chai, util) {\n\n      /*!\n       * Chai dependencies.\n       */\n\n      var Assertion = chai.Assertion\n        , flag = util.flag;\n\n      /*!\n       * Module export.\n       */\n\n      /**\n       * ### assert(expression, message)\n       *\n       * Write your own test expressions.\n       *\n       *     assert('foo' !== 'bar', 'foo is not bar');\n       *     assert(Array.isArray([]), 'empty arrays are arrays');\n       *\n       * @param {Mixed} expression to test for truthiness\n       * @param {String} message to display on error\n       * @name assert\n       * @api public\n       */\n\n      var assert = chai.assert = function (express, errmsg) {\n        var test = new Assertion(null);\n        test.assert(\n            express\n          , errmsg\n          , '[ negation message unavailable ]'\n        );\n      };\n\n      /**\n       * ### .fail(actual, expected, [message], [operator])\n       *\n       * Throw a failure. Node.js `assert` module-compatible.\n       *\n       * @name fail\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @param {String} operator\n       * @api public\n       */\n\n      assert.fail = function (actual, expected, message, operator) {\n        throw new chai.AssertionError({\n            actual: actual\n          , expected: expected\n          , message: message\n          , operator: operator\n          , stackStartFunction: assert.fail\n        });\n      };\n\n      /**\n       * ### .ok(object, [message])\n       *\n       * Asserts that `object` is truthy.\n       *\n       *     assert.ok('everything', 'everything is ok');\n       *     assert.ok(false, 'this will fail');\n       *\n       * @name ok\n       * @param {Mixed} object to test\n       * @param {String} message\n       * @api public\n       */\n\n      assert.ok = function (val, msg) {\n        new Assertion(val, msg).is.ok;\n      };\n\n      /**\n       * ### .equal(actual, expected, [message])\n       *\n       * Asserts non-strict equality (`==`) of `actual` and `expected`.\n       *\n       *     assert.equal(3, '3', '== coerces values to strings');\n       *\n       * @name equal\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @api public\n       */\n\n      assert.equal = function (act, exp, msg) {\n        var test = new Assertion(act, msg);\n\n        test.assert(\n            exp == flag(test, 'object')\n          , 'expected #{this} to equal #{exp}'\n          , 'expected #{this} to not equal #{act}'\n          , exp\n          , act\n        );\n      };\n\n      /**\n       * ### .notEqual(actual, expected, [message])\n       *\n       * Asserts non-strict inequality (`!=`) of `actual` and `expected`.\n       *\n       *     assert.notEqual(3, 4, 'these numbers are not equal');\n       *\n       * @name notEqual\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notEqual = function (act, exp, msg) {\n        var test = new Assertion(act, msg);\n\n        test.assert(\n            exp != flag(test, 'object')\n          , 'expected #{this} to not equal #{exp}'\n          , 'expected #{this} to equal #{act}'\n          , exp\n          , act\n        );\n      };\n\n      /**\n       * ### .strictEqual(actual, expected, [message])\n       *\n       * Asserts strict equality (`===`) of `actual` and `expected`.\n       *\n       *     assert.strictEqual(true, true, 'these booleans are strictly equal');\n       *\n       * @name strictEqual\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @api public\n       */\n\n      assert.strictEqual = function (act, exp, msg) {\n        new Assertion(act, msg).to.equal(exp);\n      };\n\n      /**\n       * ### .notStrictEqual(actual, expected, [message])\n       *\n       * Asserts strict inequality (`!==`) of `actual` and `expected`.\n       *\n       *     assert.notStrictEqual(3, '3', 'no coercion for strict equality');\n       *\n       * @name notStrictEqual\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notStrictEqual = function (act, exp, msg) {\n        new Assertion(act, msg).to.not.equal(exp);\n      };\n\n      /**\n       * ### .deepEqual(actual, expected, [message])\n       *\n       * Asserts that `actual` is deeply equal to `expected`.\n       *\n       *     assert.deepEqual({ tea: 'green' }, { tea: 'green' });\n       *\n       * @name deepEqual\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @api public\n       */\n\n      assert.deepEqual = function (act, exp, msg) {\n        new Assertion(act, msg).to.eql(exp);\n      };\n\n      /**\n       * ### .notDeepEqual(actual, expected, [message])\n       *\n       * Assert that `actual` is not deeply equal to `expected`.\n       *\n       *     assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' });\n       *\n       * @name notDeepEqual\n       * @param {Mixed} actual\n       * @param {Mixed} expected\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notDeepEqual = function (act, exp, msg) {\n        new Assertion(act, msg).to.not.eql(exp);\n      };\n\n      /**\n       * ### .isTrue(value, [message])\n       *\n       * Asserts that `value` is true.\n       *\n       *     var teaServed = true;\n       *     assert.isTrue(teaServed, 'the tea has been served');\n       *\n       * @name isTrue\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isTrue = function (val, msg) {\n        new Assertion(val, msg).is['true'];\n      };\n\n      /**\n       * ### .isFalse(value, [message])\n       *\n       * Asserts that `value` is false.\n       *\n       *     var teaServed = false;\n       *     assert.isFalse(teaServed, 'no tea yet? hmm...');\n       *\n       * @name isFalse\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isFalse = function (val, msg) {\n        new Assertion(val, msg).is['false'];\n      };\n\n      /**\n       * ### .isNull(value, [message])\n       *\n       * Asserts that `value` is null.\n       *\n       *     assert.isNull(err, 'there was no error');\n       *\n       * @name isNull\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNull = function (val, msg) {\n        new Assertion(val, msg).to.equal(null);\n      };\n\n      /**\n       * ### .isNotNull(value, [message])\n       *\n       * Asserts that `value` is not null.\n       *\n       *     var tea = 'tasty chai';\n       *     assert.isNotNull(tea, 'great, time for tea!');\n       *\n       * @name isNotNull\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotNull = function (val, msg) {\n        new Assertion(val, msg).to.not.equal(null);\n      };\n\n      /**\n       * ### .isUndefined(value, [message])\n       *\n       * Asserts that `value` is `undefined`.\n       *\n       *     var tea;\n       *     assert.isUndefined(tea, 'no tea defined');\n       *\n       * @name isUndefined\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isUndefined = function (val, msg) {\n        new Assertion(val, msg).to.equal(undefined);\n      };\n\n      /**\n       * ### .isDefined(value, [message])\n       *\n       * Asserts that `value` is not `undefined`.\n       *\n       *     var tea = 'cup of chai';\n       *     assert.isDefined(tea, 'tea has been defined');\n       *\n       * @name isUndefined\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isDefined = function (val, msg) {\n        new Assertion(val, msg).to.not.equal(undefined);\n      };\n\n      /**\n       * ### .isFunction(value, [message])\n       *\n       * Asserts that `value` is a function.\n       *\n       *     function serveTea() { return 'cup of tea'; };\n       *     assert.isFunction(serveTea, 'great, we can have tea now');\n       *\n       * @name isFunction\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isFunction = function (val, msg) {\n        new Assertion(val, msg).to.be.a('function');\n      };\n\n      /**\n       * ### .isNotFunction(value, [message])\n       *\n       * Asserts that `value` is _not_ a function.\n       *\n       *     var serveTea = [ 'heat', 'pour', 'sip' ];\n       *     assert.isNotFunction(serveTea, 'great, we have listed the steps');\n       *\n       * @name isNotFunction\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotFunction = function (val, msg) {\n        new Assertion(val, msg).to.not.be.a('function');\n      };\n\n      /**\n       * ### .isObject(value, [message])\n       *\n       * Asserts that `value` is an object (as revealed by\n       * `Object.prototype.toString`).\n       *\n       *     var selection = { name: 'Chai', serve: 'with spices' };\n       *     assert.isObject(selection, 'tea selection is an object');\n       *\n       * @name isObject\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isObject = function (val, msg) {\n        new Assertion(val, msg).to.be.a('object');\n      };\n\n      /**\n       * ### .isNotObject(value, [message])\n       *\n       * Asserts that `value` is _not_ an object.\n       *\n       *     var selection = 'chai'\n       *     assert.isObject(selection, 'tea selection is not an object');\n       *     assert.isObject(null, 'null is not an object');\n       *\n       * @name isNotObject\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotObject = function (val, msg) {\n        new Assertion(val, msg).to.not.be.a('object');\n      };\n\n      /**\n       * ### .isArray(value, [message])\n       *\n       * Asserts that `value` is an array.\n       *\n       *     var menu = [ 'green', 'chai', 'oolong' ];\n       *     assert.isArray(menu, 'what kind of tea do we want?');\n       *\n       * @name isArray\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isArray = function (val, msg) {\n        new Assertion(val, msg).to.be.an('array');\n      };\n\n      /**\n       * ### .isNotArray(value, [message])\n       *\n       * Asserts that `value` is _not_ an array.\n       *\n       *     var menu = 'green|chai|oolong';\n       *     assert.isNotArray(menu, 'what kind of tea do we want?');\n       *\n       * @name isNotArray\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotArray = function (val, msg) {\n        new Assertion(val, msg).to.not.be.an('array');\n      };\n\n      /**\n       * ### .isString(value, [message])\n       *\n       * Asserts that `value` is a string.\n       *\n       *     var teaOrder = 'chai';\n       *     assert.isString(teaOrder, 'order placed');\n       *\n       * @name isString\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isString = function (val, msg) {\n        new Assertion(val, msg).to.be.a('string');\n      };\n\n      /**\n       * ### .isNotString(value, [message])\n       *\n       * Asserts that `value` is _not_ a string.\n       *\n       *     var teaOrder = 4;\n       *     assert.isNotString(teaOrder, 'order placed');\n       *\n       * @name isNotString\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotString = function (val, msg) {\n        new Assertion(val, msg).to.not.be.a('string');\n      };\n\n      /**\n       * ### .isNumber(value, [message])\n       *\n       * Asserts that `value` is a number.\n       *\n       *     var cups = 2;\n       *     assert.isNumber(cups, 'how many cups');\n       *\n       * @name isNumber\n       * @param {Number} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNumber = function (val, msg) {\n        new Assertion(val, msg).to.be.a('number');\n      };\n\n      /**\n       * ### .isNotNumber(value, [message])\n       *\n       * Asserts that `value` is _not_ a number.\n       *\n       *     var cups = '2 cups please';\n       *     assert.isNotNumber(cups, 'how many cups');\n       *\n       * @name isNotNumber\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotNumber = function (val, msg) {\n        new Assertion(val, msg).to.not.be.a('number');\n      };\n\n      /**\n       * ### .isBoolean(value, [message])\n       *\n       * Asserts that `value` is a boolean.\n       *\n       *     var teaReady = true\n       *       , teaServed = false;\n       *\n       *     assert.isBoolean(teaReady, 'is the tea ready');\n       *     assert.isBoolean(teaServed, 'has tea been served');\n       *\n       * @name isBoolean\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isBoolean = function (val, msg) {\n        new Assertion(val, msg).to.be.a('boolean');\n      };\n\n      /**\n       * ### .isNotBoolean(value, [message])\n       *\n       * Asserts that `value` is _not_ a boolean.\n       *\n       *     var teaReady = 'yep'\n       *       , teaServed = 'nope';\n       *\n       *     assert.isNotBoolean(teaReady, 'is the tea ready');\n       *     assert.isNotBoolean(teaServed, 'has tea been served');\n       *\n       * @name isNotBoolean\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.isNotBoolean = function (val, msg) {\n        new Assertion(val, msg).to.not.be.a('boolean');\n      };\n\n      /**\n       * ### .typeOf(value, name, [message])\n       *\n       * Asserts that `value`'s type is `name`, as determined by\n       * `Object.prototype.toString`.\n       *\n       *     assert.typeOf({ tea: 'chai' }, 'object', 'we have an object');\n       *     assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array');\n       *     assert.typeOf('tea', 'string', 'we have a string');\n       *     assert.typeOf(/tea/, 'regexp', 'we have a regular expression');\n       *     assert.typeOf(null, 'null', 'we have a null');\n       *     assert.typeOf(undefined, 'undefined', 'we have an undefined');\n       *\n       * @name typeOf\n       * @param {Mixed} value\n       * @param {String} name\n       * @param {String} message\n       * @api public\n       */\n\n      assert.typeOf = function (val, type, msg) {\n        new Assertion(val, msg).to.be.a(type);\n      };\n\n      /**\n       * ### .notTypeOf(value, name, [message])\n       *\n       * Asserts that `value`'s type is _not_ `name`, as determined by\n       * `Object.prototype.toString`.\n       *\n       *     assert.notTypeOf('tea', 'number', 'strings are not numbers');\n       *\n       * @name notTypeOf\n       * @param {Mixed} value\n       * @param {String} typeof name\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notTypeOf = function (val, type, msg) {\n        new Assertion(val, msg).to.not.be.a(type);\n      };\n\n      /**\n       * ### .instanceOf(object, constructor, [message])\n       *\n       * Asserts that `value` is an instance of `constructor`.\n       *\n       *     var Tea = function (name) { this.name = name; }\n       *       , chai = new Tea('chai');\n       *\n       *     assert.instanceOf(chai, Tea, 'chai is an instance of tea');\n       *\n       * @name instanceOf\n       * @param {Object} object\n       * @param {Constructor} constructor\n       * @param {String} message\n       * @api public\n       */\n\n      assert.instanceOf = function (val, type, msg) {\n        new Assertion(val, msg).to.be.instanceOf(type);\n      };\n\n      /**\n       * ### .notInstanceOf(object, constructor, [message])\n       *\n       * Asserts `value` is not an instance of `constructor`.\n       *\n       *     var Tea = function (name) { this.name = name; }\n       *       , chai = new String('chai');\n       *\n       *     assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea');\n       *\n       * @name notInstanceOf\n       * @param {Object} object\n       * @param {Constructor} constructor\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notInstanceOf = function (val, type, msg) {\n        new Assertion(val, msg).to.not.be.instanceOf(type);\n      };\n\n      /**\n       * ### .include(haystack, needle, [message])\n       *\n       * Asserts that `haystack` includes `needle`. Works\n       * for strings and arrays.\n       *\n       *     assert.include('foobar', 'bar', 'foobar contains string \"bar\"');\n       *     assert.include([ 1, 2, 3 ], 3, 'array contains value');\n       *\n       * @name include\n       * @param {Array|String} haystack\n       * @param {Mixed} needle\n       * @param {String} message\n       * @api public\n       */\n\n      assert.include = function (exp, inc, msg) {\n        var obj = new Assertion(exp, msg);\n\n        if (Array.isArray(exp)) {\n          obj.to.include(inc);\n        } else if ('string' === typeof exp) {\n          obj.to.contain.string(inc);\n        }\n      };\n\n      /**\n       * ### .match(value, regexp, [message])\n       *\n       * Asserts that `value` matches the regular expression `regexp`.\n       *\n       *     assert.match('foobar', /^foo/, 'regexp matches');\n       *\n       * @name match\n       * @param {Mixed} value\n       * @param {RegExp} regexp\n       * @param {String} message\n       * @api public\n       */\n\n      assert.match = function (exp, re, msg) {\n        new Assertion(exp, msg).to.match(re);\n      };\n\n      /**\n       * ### .notMatch(value, regexp, [message])\n       *\n       * Asserts that `value` does not match the regular expression `regexp`.\n       *\n       *     assert.notMatch('foobar', /^foo/, 'regexp does not match');\n       *\n       * @name notMatch\n       * @param {Mixed} value\n       * @param {RegExp} regexp\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notMatch = function (exp, re, msg) {\n        new Assertion(exp, msg).to.not.match(re);\n      };\n\n      /**\n       * ### .property(object, property, [message])\n       *\n       * Asserts that `object` has a property named by `property`.\n       *\n       *     assert.property({ tea: { green: 'matcha' }}, 'tea');\n       *\n       * @name property\n       * @param {Object} object\n       * @param {String} property\n       * @param {String} message\n       * @api public\n       */\n\n      assert.property = function (obj, prop, msg) {\n        new Assertion(obj, msg).to.have.property(prop);\n      };\n\n      /**\n       * ### .notProperty(object, property, [message])\n       *\n       * Asserts that `object` does _not_ have a property named by `property`.\n       *\n       *     assert.notProperty({ tea: { green: 'matcha' }}, 'coffee');\n       *\n       * @name notProperty\n       * @param {Object} object\n       * @param {String} property\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notProperty = function (obj, prop, msg) {\n        new Assertion(obj, msg).to.not.have.property(prop);\n      };\n\n      /**\n       * ### .deepProperty(object, property, [message])\n       *\n       * Asserts that `object` has a property named by `property`, which can be a\n       * string using dot- and bracket-notation for deep reference.\n       *\n       *     assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green');\n       *\n       * @name deepProperty\n       * @param {Object} object\n       * @param {String} property\n       * @param {String} message\n       * @api public\n       */\n\n      assert.deepProperty = function (obj, prop, msg) {\n        new Assertion(obj, msg).to.have.deep.property(prop);\n      };\n\n      /**\n       * ### .notDeepProperty(object, property, [message])\n       *\n       * Asserts that `object` does _not_ have a property named by `property`, which\n       * can be a string using dot- and bracket-notation for deep reference.\n       *\n       *     assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong');\n       *\n       * @name notDeepProperty\n       * @param {Object} object\n       * @param {String} property\n       * @param {String} message\n       * @api public\n       */\n\n      assert.notDeepProperty = function (obj, prop, msg) {\n        new Assertion(obj, msg).to.not.have.deep.property(prop);\n      };\n\n      /**\n       * ### .propertyVal(object, property, value, [message])\n       *\n       * Asserts that `object` has a property named by `property` with value given\n       * by `value`.\n       *\n       *     assert.propertyVal({ tea: 'is good' }, 'tea', 'is good');\n       *\n       * @name propertyVal\n       * @param {Object} object\n       * @param {String} property\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.propertyVal = function (obj, prop, val, msg) {\n        new Assertion(obj, msg).to.have.property(prop, val);\n      };\n\n      /**\n       * ### .propertyNotVal(object, property, value, [message])\n       *\n       * Asserts that `object` has a property named by `property`, but with a value\n       * different from that given by `value`.\n       *\n       *     assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad');\n       *\n       * @name propertyNotVal\n       * @param {Object} object\n       * @param {String} property\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.propertyNotVal = function (obj, prop, val, msg) {\n        new Assertion(obj, msg).to.not.have.property(prop, val);\n      };\n\n      /**\n       * ### .deepPropertyVal(object, property, value, [message])\n       *\n       * Asserts that `object` has a property named by `property` with value given\n       * by `value`. `property` can use dot- and bracket-notation for deep\n       * reference.\n       *\n       *     assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha');\n       *\n       * @name deepPropertyVal\n       * @param {Object} object\n       * @param {String} property\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.deepPropertyVal = function (obj, prop, val, msg) {\n        new Assertion(obj, msg).to.have.deep.property(prop, val);\n      };\n\n      /**\n       * ### .deepPropertyNotVal(object, property, value, [message])\n       *\n       * Asserts that `object` has a property named by `property`, but with a value\n       * different from that given by `value`. `property` can use dot- and\n       * bracket-notation for deep reference.\n       *\n       *     assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');\n       *\n       * @name deepPropertyNotVal\n       * @param {Object} object\n       * @param {String} property\n       * @param {Mixed} value\n       * @param {String} message\n       * @api public\n       */\n\n      assert.deepPropertyNotVal = function (obj, prop, val, msg) {\n        new Assertion(obj, msg).to.not.have.deep.property(prop, val);\n      };\n\n      /**\n       * ### .lengthOf(object, length, [message])\n       *\n       * Asserts that `object` has a `length` property with the expected value.\n       *\n       *     assert.lengthOf([1,2,3], 3, 'array has length of 3');\n       *     assert.lengthOf('foobar', 5, 'string has length of 6');\n       *\n       * @name lengthOf\n       * @param {Mixed} object\n       * @param {Number} length\n       * @param {String} message\n       * @api public\n       */\n\n      assert.lengthOf = function (exp, len, msg) {\n        new Assertion(exp, msg).to.have.length(len);\n      };\n\n      /**\n       * ### .throws(function, [constructor/string/regexp], [string/regexp], [message])\n       *\n       * Asserts that `function` will throw an error that is an instance of\n       * `constructor`, or alternately that it will throw an error with message\n       * matching `regexp`.\n       *\n       *     assert.throw(fn, 'function throws a reference error');\n       *     assert.throw(fn, /function throws a reference error/);\n       *     assert.throw(fn, ReferenceError);\n       *     assert.throw(fn, ReferenceError, 'function throws a reference error');\n       *     assert.throw(fn, ReferenceError, /function throws a reference error/);\n       *\n       * @name throws\n       * @alias throw\n       * @alias Throw\n       * @param {Function} function\n       * @param {ErrorConstructor} constructor\n       * @param {RegExp} regexp\n       * @param {String} message\n       * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n       * @api public\n       */\n\n      assert.Throw = function (fn, errt, errs, msg) {\n        if ('string' === typeof errt || errt instanceof RegExp) {\n          errs = errt;\n          errt = null;\n        }\n\n        new Assertion(fn, msg).to.Throw(errt, errs);\n      };\n\n      /**\n       * ### .doesNotThrow(function, [constructor/regexp], [message])\n       *\n       * Asserts that `function` will _not_ throw an error that is an instance of\n       * `constructor`, or alternately that it will not throw an error with message\n       * matching `regexp`.\n       *\n       *     assert.doesNotThrow(fn, Error, 'function does not throw');\n       *\n       * @name doesNotThrow\n       * @param {Function} function\n       * @param {ErrorConstructor} constructor\n       * @param {RegExp} regexp\n       * @param {String} message\n       * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n       * @api public\n       */\n\n      assert.doesNotThrow = function (fn, type, msg) {\n        if ('string' === typeof type) {\n          msg = type;\n          type = null;\n        }\n\n        new Assertion(fn, msg).to.not.Throw(type);\n      };\n\n      /**\n       * ### .operator(val1, operator, val2, [message])\n       *\n       * Compares two values using `operator`.\n       *\n       *     assert.operator(1, '<', 2, 'everything is ok');\n       *     assert.operator(1, '>', 2, 'this will fail');\n       *\n       * @name operator\n       * @param {Mixed} val1\n       * @param {String} operator\n       * @param {Mixed} val2\n       * @param {String} message\n       * @api public\n       */\n\n      assert.operator = function (val, operator, val2, msg) {\n        if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) {\n          throw new Error('Invalid operator \"' + operator + '\"');\n        }\n        var test = new Assertion(eval(val + operator + val2), msg);\n        test.assert(\n            true === flag(test, 'object')\n          , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2)\n          , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) );\n      };\n\n      /**\n       * ### .closeTo(actual, expected, delta, [message])\n       *\n       * Asserts that the target is equal `expected`, to within a +/- `delta` range.\n       *\n       *     assert.closeTo(1.5, 1, 0.5, 'numbers are close');\n       *\n       * @name closeTo\n       * @param {Number} actual\n       * @param {Number} expected\n       * @param {Number} delta\n       * @param {String} message\n       * @api public\n       */\n\n      assert.closeTo = function (act, exp, delta, msg) {\n        new Assertion(act, msg).to.be.closeTo(exp, delta);\n      };\n\n      /*!\n       * Undocumented / untested\n       */\n\n      assert.ifError = function (val, msg) {\n        new Assertion(val, msg).to.not.be.ok;\n      };\n\n      /*!\n       * Aliases.\n       */\n\n      (function alias(name, as){\n        assert[as] = assert[name];\n        return alias;\n      })\n      ('Throw', 'throw')\n      ('Throw', 'throws');\n    };\n\n  }); // module: chai/interface/assert.js\n\n  require.register(\"chai/interface/expect.js\", function(module, exports, require){\n    /*!\n     * chai\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    module.exports = function (chai, util) {\n      chai.expect = function (val, message) {\n        return new chai.Assertion(val, message);\n      };\n    };\n\n\n  }); // module: chai/interface/expect.js\n\n  require.register(\"chai/interface/should.js\", function(module, exports, require){\n    /*!\n     * chai\n     * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    module.exports = function (chai, util) {\n      var Assertion = chai.Assertion;\n\n      function loadShould () {\n        // modify Object.prototype to have `should`\n        Object.defineProperty(Object.prototype, 'should',\n          {\n            set: function (value) {\n              // See https://github.com/chaijs/chai/issues/86: this makes\n              // `whatever.should = someValue` actually set `someValue`, which is\n              // especially useful for `global.should = require('chai').should()`.\n              //\n              // Note that we have to use [[DefineProperty]] instead of [[Put]]\n              // since otherwise we would trigger this very setter!\n              Object.defineProperty(this, 'should', {\n                value: value,\n                enumerable: true,\n                configurable: true,\n                writable: true\n              });\n            }\n          , get: function(){\n              if (this instanceof String || this instanceof Number) {\n                return new Assertion(this.constructor(this));\n              } else if (this instanceof Boolean) {\n                return new Assertion(this == true);\n              }\n              return new Assertion(this);\n            }\n          , configurable: true\n        });\n\n        var should = {};\n\n        should.equal = function (val1, val2, msg) {\n          new Assertion(val1, msg).to.equal(val2);\n        };\n\n        should.Throw = function (fn, errt, errs, msg) {\n          new Assertion(fn, msg).to.Throw(errt, errs);\n        };\n\n        should.exist = function (val, msg) {\n          new Assertion(val, msg).to.exist;\n        }\n\n        // negation\n        should.not = {}\n\n        should.not.equal = function (val1, val2, msg) {\n          new Assertion(val1, msg).to.not.equal(val2);\n        };\n\n        should.not.Throw = function (fn, errt, errs, msg) {\n          new Assertion(fn, msg).to.not.Throw(errt, errs);\n        };\n\n        should.not.exist = function (val, msg) {\n          new Assertion(val, msg).to.not.exist;\n        }\n\n        should['throw'] = should['Throw'];\n        should.not['throw'] = should.not['Throw'];\n\n        return should;\n      };\n\n      chai.should = loadShould;\n      chai.Should = loadShould;\n    };\n\n  }); // module: chai/interface/should.js\n\n  require.register(\"chai/utils/addChainableMethod.js\", function(module, exports, require){\n    /*!\n     * Chai - addChainingMethod utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Module dependencies\n     */\n\n    var transferFlags = require('./transferFlags');\n\n    /**\n     * ### addChainableMethod (ctx, name, method, chainingBehavior)\n     *\n     * Adds a method to an object, such that the method can also be chained.\n     *\n     *     utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) {\n     *       var obj = utils.flag(this, 'object');\n     *       new chai.Assertion(obj).to.be.equal(str);\n     *     });\n     *\n     * Can also be accessed directly from `chai.Assertion`.\n     *\n     *     chai.Assertion.addChainableMethod('foo', fn, chainingBehavior);\n     *\n     * The result can then be used as both a method assertion, executing both `method` and\n     * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`.\n     *\n     *     expect(fooStr).to.be.foo('bar');\n     *     expect(fooStr).to.be.foo.equal('foo');\n     *\n     * @param {Object} ctx object to which the method is added\n     * @param {String} name of method to add\n     * @param {Function} method function to be used for `name`, when called\n     * @param {Function} chainingBehavior function to be called every time the property is accessed\n     * @name addChainableMethod\n     * @api public\n     */\n\n    module.exports = function (ctx, name, method, chainingBehavior) {\n      if (typeof chainingBehavior !== 'function')\n        chainingBehavior = function () { };\n\n      Object.defineProperty(ctx, name,\n        { get: function () {\n            chainingBehavior.call(this);\n\n            var assert = function () {\n              var result = method.apply(this, arguments);\n              return result === undefined ? this : result;\n            };\n\n            // Re-enumerate every time to better accomodate plugins.\n            var asserterNames = Object.getOwnPropertyNames(ctx);\n            asserterNames.forEach(function (asserterName) {\n              var pd = Object.getOwnPropertyDescriptor(ctx, asserterName)\n                , functionProtoPD = Object.getOwnPropertyDescriptor(Function.prototype, asserterName);\n              // Avoid trying to overwrite things that we can't, like `length` and `arguments`.\n              if (functionProtoPD && !functionProtoPD.configurable) return;\n              if (asserterName === 'arguments') return; // @see chaijs/chai/issues/69\n              Object.defineProperty(assert, asserterName, pd);\n            });\n\n            transferFlags(this, assert);\n            return assert;\n          }\n        , configurable: true\n      });\n    };\n\n  }); // module: chai/utils/addChainableMethod.js\n\n  require.register(\"chai/utils/addMethod.js\", function(module, exports, require){\n    /*!\n     * Chai - addMethod utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * ### .addMethod (ctx, name, method)\n     *\n     * Adds a method to the prototype of an object.\n     *\n     *     utils.addMethod(chai.Assertion.prototype, 'foo', function (str) {\n     *       var obj = utils.flag(this, 'object');\n     *       new chai.Assertion(obj).to.be.equal(str);\n     *     });\n     *\n     * Can also be accessed directly from `chai.Assertion`.\n     *\n     *     chai.Assertion.addMethod('foo', fn);\n     *\n     * Then can be used as any other assertion.\n     *\n     *     expect(fooStr).to.be.foo('bar');\n     *\n     * @param {Object} ctx object to which the method is added\n     * @param {String} name of method to add\n     * @param {Function} method function to be used for name\n     * @name addMethod\n     * @api public\n     */\n\n    module.exports = function (ctx, name, method) {\n      ctx[name] = function () {\n        var result = method.apply(this, arguments);\n        return result === undefined ? this : result;\n      };\n    };\n\n  }); // module: chai/utils/addMethod.js\n\n  require.register(\"chai/utils/addProperty.js\", function(module, exports, require){\n    /*!\n     * Chai - addProperty utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * ### addProperty (ctx, name, getter)\n     *\n     * Adds a property to the prototype of an object.\n     *\n     *     utils.addProperty(chai.Assertion.prototype, 'foo', function () {\n     *       var obj = utils.flag(this, 'object');\n     *       new chai.Assertion(obj).to.be.instanceof(Foo);\n     *     });\n     *\n     * Can also be accessed directly from `chai.Assertion`.\n     *\n     *     chai.Assertion.addProperty('foo', fn);\n     *\n     * Then can be used as any other assertion.\n     *\n     *     expect(myFoo).to.be.foo;\n     *\n     * @param {Object} ctx object to which the property is added\n     * @param {String} name of property to add\n     * @param {Function} getter function to be used for name\n     * @name addProperty\n     * @api public\n     */\n\n    module.exports = function (ctx, name, getter) {\n      Object.defineProperty(ctx, name,\n        { get: function () {\n            var result = getter.call(this);\n            return result === undefined ? this : result;\n          }\n        , configurable: true\n      });\n    };\n\n  }); // module: chai/utils/addProperty.js\n\n  require.register(\"chai/utils/eql.js\", function(module, exports, require){\n    // This is (almost) directly from Node.js assert\n    // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js\n\n    module.exports = _deepEqual;\n\n    // for the browser\n    var Buffer;\n    try {\n      Buffer = require('buffer').Buffer;\n    } catch (ex) {\n      Buffer = {\n        isBuffer: function () { return false; }\n      };\n    }\n\n    function _deepEqual(actual, expected, memos) {\n\n      // 7.1. All identical values are equivalent, as determined by ===.\n      if (actual === expected) {\n        return true;\n\n      } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {\n        if (actual.length != expected.length) return false;\n\n        for (var i = 0; i < actual.length; i++) {\n          if (actual[i] !== expected[i]) return false;\n        }\n\n        return true;\n\n      // 7.2. If the expected value is a Date object, the actual value is\n      // equivalent if it is also a Date object that refers to the same time.\n      } else if (actual instanceof Date && expected instanceof Date) {\n        return actual.getTime() === expected.getTime();\n\n      // 7.3. Other pairs that do not both pass typeof value == 'object',\n      // equivalence is determined by ==.\n      } else if (typeof actual != 'object' && typeof expected != 'object') {\n        return actual === expected;\n\n      // 7.4. For all other Object pairs, including Array objects, equivalence is\n      // determined by having the same number of owned properties (as verified\n      // with Object.prototype.hasOwnProperty.call), the same set of keys\n      // (although not necessarily the same order), equivalent values for every\n      // corresponding key, and an identical 'prototype' property. Note: this\n      // accounts for both named and indexed properties on Arrays.\n      } else {\n        return objEquiv(actual, expected, memos);\n      }\n    }\n\n    function isUndefinedOrNull(value) {\n      return value === null || value === undefined;\n    }\n\n    function isArguments(object) {\n      return Object.prototype.toString.call(object) == '[object Arguments]';\n    }\n\n    function objEquiv(a, b, memos) {\n      if (isUndefinedOrNull(a) || isUndefinedOrNull(b))\n        return false;\n\n      // an identical 'prototype' property.\n      if (a.prototype !== b.prototype) return false;\n\n      // check if we have already compared a and b\n      var i;\n      if (memos) {\n        for(i = 0; i < memos.length; i++) {\n          if ((memos[i][0] === a && memos[i][1] === b) ||\n              (memos[i][0] === b && memos[i][1] === a))\n            return true;\n        }\n      } else {\n        memos = [];\n      }\n\n      //~~~I've managed to break Object.keys through screwy arguments passing.\n      //   Converting to array solves the problem.\n      if (isArguments(a)) {\n        if (!isArguments(b)) {\n          return false;\n        }\n        a = pSlice.call(a);\n        b = pSlice.call(b);\n        return _deepEqual(a, b, memos);\n      }\n      try {\n        var ka = Object.keys(a),\n            kb = Object.keys(b),\n            key;\n      } catch (e) {//happens when one is a string literal and the other isn't\n        return false;\n      }\n\n      // having the same number of owned properties (keys incorporates\n      // hasOwnProperty)\n      if (ka.length != kb.length)\n        return false;\n\n      //the same set of keys (although not necessarily the same order),\n      ka.sort();\n      kb.sort();\n      //~~~cheap key test\n      for (i = ka.length - 1; i >= 0; i--) {\n        if (ka[i] != kb[i])\n          return false;\n      }\n\n      // remember objects we have compared to guard against circular references\n      memos.push([ a, b ]);\n\n      //equivalent values for every corresponding key, and\n      //~~~possibly expensive deep test\n      for (i = ka.length - 1; i >= 0; i--) {\n        key = ka[i];\n        if (!_deepEqual(a[key], b[key], memos)) return false;\n      }\n\n      return true;\n    }\n\n  }); // module: chai/utils/eql.js\n\n  require.register(\"chai/utils/flag.js\", function(module, exports, require){\n    /*!\n     * Chai - flag utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * ### flag(object ,key, [value])\n     *\n     * Get or set a flag value on an object. If a\n     * value is provided it will be set, else it will\n     * return the currently set value or `undefined` if\n     * the value is not set.\n     *\n     *     utils.flag(this, 'foo', 'bar'); // setter\n     *     utils.flag(this, 'foo'); // getter, returns `bar`\n     *\n     * @param {Object} object (constructed Assertion\n     * @param {String} key\n     * @param {Mixed} value (optional)\n     * @name flag\n     * @api private\n     */\n\n    module.exports = function (obj, key, value) {\n      var flags = obj.__flags || (obj.__flags = Object.create(null));\n      if (arguments.length === 3) {\n        flags[key] = value;\n      } else {\n        return flags[key];\n      }\n    };\n\n  }); // module: chai/utils/flag.js\n\n  require.register(\"chai/utils/getActual.js\", function(module, exports, require){\n    /*!\n     * Chai - getActual utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * # getActual(object, [actual])\n     *\n     * Returns the `actual` value for an Assertion\n     *\n     * @param {Object} object (constructed Assertion)\n     * @param {Arguments} chai.Assertion.prototype.assert arguments\n     */\n\n    module.exports = function (obj, args) {\n      var actual = args[4];\n      return 'undefined' !== typeof actual ? actual : obj._obj;\n    };\n\n  }); // module: chai/utils/getActual.js\n\n  require.register(\"chai/utils/getMessage.js\", function(module, exports, require){\n    /*!\n     * Chai - message composition utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Module dependancies\n     */\n\n    var flag = require('./flag')\n      , getActual = require('./getActual')\n      , inspect = require('./inspect')\n      , objDisplay = require('./objDisplay');\n\n    /**\n     * ### .getMessage(object, message, negateMessage)\n     *\n     * Construct the error message based on flags\n     * and template tags. Template tags will return\n     * a stringified inspection of the object referenced.\n     *\n     * Messsage template tags:\n     * - `#{this}` current asserted object\n     * - `#{act}` actual value\n     * - `#{exp}` expected value\n     *\n     * @param {Object} object (constructed Assertion)\n     * @param {Arguments} chai.Assertion.prototype.assert arguments\n     * @name getMessage\n     * @api public\n     */\n\n    module.exports = function (obj, args) {\n      var negate = flag(obj, 'negate')\n        , val = flag(obj, 'object')\n        , expected = args[3]\n        , actual = getActual(obj, args)\n        , msg = negate ? args[2] : args[1]\n        , flagMsg = flag(obj, 'message');\n\n      msg = msg || '';\n      msg = msg\n        .replace(/#{this}/g, objDisplay(val))\n        .replace(/#{act}/g, objDisplay(actual))\n        .replace(/#{exp}/g, objDisplay(expected));\n\n      return flagMsg ? flagMsg + ': ' + msg : msg;\n    };\n\n  }); // module: chai/utils/getMessage.js\n\n  require.register(\"chai/utils/getName.js\", function(module, exports, require){\n    /*!\n     * Chai - getName utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * # getName(func)\n     *\n     * Gets the name of a function, in a cross-browser way.\n     *\n     * @param {Function} a function (usually a constructor)\n     */\n\n    module.exports = function (func) {\n      if (func.name) return func.name;\n\n      var match = /^\\s?function ([^(]*)\\(/.exec(func);\n      return match && match[1] ? match[1] : \"\";\n    };\n\n  }); // module: chai/utils/getName.js\n\n  require.register(\"chai/utils/getPathValue.js\", function(module, exports, require){\n    /*!\n     * Chai - getPathValue utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * @see https://github.com/logicalparadox/filtr\n     * MIT Licensed\n     */\n\n    /**\n     * ### .getPathValue(path, object)\n     *\n     * This allows the retrieval of values in an\n     * object given a string path.\n     *\n     *     var obj = {\n     *         prop1: {\n     *             arr: ['a', 'b', 'c']\n     *           , str: 'Hello'\n     *         }\n     *       , prop2: {\n     *             arr: [ { nested: 'Universe' } ]\n     *           , str: 'Hello again!'\n     *         }\n     *     }\n     *\n     * The following would be the results.\n     *\n     *     getPathValue('prop1.str', obj); // Hello\n     *     getPathValue('prop1.att[2]', obj); // b\n     *     getPathValue('prop2.arr[0].nested', obj); // Universe\n     *\n     * @param {String} path\n     * @param {Object} object\n     * @returns {Object} value or `undefined`\n     * @name getPathValue\n     * @api public\n     */\n\n    var getPathValue = module.exports = function (path, obj) {\n      var parsed = parsePath(path);\n      return _getPathValue(parsed, obj);\n    };\n\n    /*!\n     * ## parsePath(path)\n     *\n     * Helper function used to parse string object\n     * paths. Use in conjunction with `_getPathValue`.\n     *\n     *      var parsed = parsePath('myobject.property.subprop');\n     *\n     * ### Paths:\n     *\n     * * Can be as near infinitely deep and nested\n     * * Arrays are also valid using the formal `myobject.document[3].property`.\n     *\n     * @param {String} path\n     * @returns {Object} parsed\n     * @api private\n     */\n\n    function parsePath (path) {\n      var str = path.replace(/\\[/g, '.[')\n        , parts = str.match(/(\\\\\\.|[^.]+?)+/g);\n      return parts.map(function (value) {\n        var re = /\\[(\\d+)\\]$/\n          , mArr = re.exec(value)\n        if (mArr) return { i: parseFloat(mArr[1]) };\n        else return { p: value };\n      });\n    };\n\n    /*!\n     * ## _getPathValue(parsed, obj)\n     *\n     * Helper companion function for `.parsePath` that returns\n     * the value located at the parsed address.\n     *\n     *      var value = getPathValue(parsed, obj);\n     *\n     * @param {Object} parsed definition from `parsePath`.\n     * @param {Object} object to search against\n     * @returns {Object|Undefined} value\n     * @api private\n     */\n\n    function _getPathValue (parsed, obj) {\n      var tmp = obj\n        , res;\n      for (var i = 0, l = parsed.length; i < l; i++) {\n        var part = parsed[i];\n        if (tmp) {\n          if ('undefined' !== typeof part.p)\n            tmp = tmp[part.p];\n          else if ('undefined' !== typeof part.i)\n            tmp = tmp[part.i];\n          if (i == (l - 1)) res = tmp;\n        } else {\n          res = undefined;\n        }\n      }\n      return res;\n    };\n\n  }); // module: chai/utils/getPathValue.js\n\n  require.register(\"chai/utils/index.js\", function(module, exports, require){\n    /*!\n     * chai\n     * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Main exports\n     */\n\n    var exports = module.exports = {};\n\n    /*!\n     * test utility\n     */\n\n    exports.test = require('./test');\n\n    /*!\n     * message utility\n     */\n\n    exports.getMessage = require('./getMessage');\n\n    /*!\n     * actual utility\n     */\n\n    exports.getActual = require('./getActual');\n\n    /*!\n     * Inspect util\n     */\n\n    exports.inspect = require('./inspect');\n\n    /*!\n     * Object Display util\n     */\n\n    exports.objDisplay = require('./objDisplay');\n\n    /*!\n     * Flag utility\n     */\n\n    exports.flag = require('./flag');\n\n    /*!\n     * Flag transferring utility\n     */\n\n    exports.transferFlags = require('./transferFlags');\n\n    /*!\n     * Deep equal utility\n     */\n\n    exports.eql = require('./eql');\n\n    /*!\n     * Deep path value\n     */\n\n    exports.getPathValue = require('./getPathValue');\n\n    /*!\n     * Function name\n     */\n\n    exports.getName = require('./getName');\n\n    /*!\n     * add Property\n     */\n\n    exports.addProperty = require('./addProperty');\n\n    /*!\n     * add Method\n     */\n\n    exports.addMethod = require('./addMethod');\n\n    /*!\n     * overwrite Property\n     */\n\n    exports.overwriteProperty = require('./overwriteProperty');\n\n    /*!\n     * overwrite Method\n     */\n\n    exports.overwriteMethod = require('./overwriteMethod');\n\n    /*!\n     * Add a chainable method\n     */\n\n    exports.addChainableMethod = require('./addChainableMethod');\n\n\n  }); // module: chai/utils/index.js\n\n  require.register(\"chai/utils/inspect.js\", function(module, exports, require){\n    // This is (almost) directly from Node.js utils\n    // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js\n\n    var getName = require('./getName');\n\n    module.exports = inspect;\n\n    /**\n     * Echos the value of a value. Trys to print the value out\n     * in the best way possible given the different types.\n     *\n     * @param {Object} obj The object to print out.\n     * @param {Boolean} showHidden Flag that shows hidden (not enumerable)\n     *    properties of objects.\n     * @param {Number} depth Depth in which to descend in object. Default is 2.\n     * @param {Boolean} colors Flag to turn on ANSI escape codes to color the\n     *    output. Default is false (no coloring).\n     */\n    function inspect(obj, showHidden, depth, colors) {\n      var ctx = {\n        showHidden: showHidden,\n        seen: [],\n        stylize: function (str) { return str; }\n      };\n      return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth));\n    }\n\n    // https://gist.github.com/1044128/\n    var getOuterHTML = function(element) {\n      if ('outerHTML' in element) return element.outerHTML;\n      var ns = \"http://www.w3.org/1999/xhtml\";\n      var container = document.createElementNS(ns, '_');\n      var elemProto = (window.HTMLElement || window.Element).prototype;\n      var xmlSerializer = new XMLSerializer();\n      var html;\n      if (document.xmlVersion) {\n        return xmlSerializer.serializeToString(element);\n      } else {\n        container.appendChild(element.cloneNode(false));\n        html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');\n        container.innerHTML = '';\n        return html;\n      }\n    };\n      \n    // Returns true if object is a DOM element.\n    var isDOMElement = function (object) {\n      if (typeof HTMLElement === 'object') {\n        return object instanceof HTMLElement;\n      } else {\n        return object &&\n          typeof object === 'object' &&\n          object.nodeType === 1 &&\n          typeof object.nodeName === 'string';\n      }\n    };\n\n    function formatValue(ctx, value, recurseTimes) {\n      // Provide a hook for user-specified inspect functions.\n      // Check that value is an object with an inspect function on it\n      if (value && typeof value.inspect === 'function' &&\n          // Filter out the util module, it's inspect function is special\n          value.inspect !== exports.inspect &&\n          // Also filter out any prototype objects using the circular check.\n          !(value.constructor && value.constructor.prototype === value)) {\n        return value.inspect(recurseTimes);\n      }\n\n      // Primitive types cannot have properties\n      var primitive = formatPrimitive(ctx, value);\n      if (primitive) {\n        return primitive;\n      }\n\n      // If it's DOM elem, get outer HTML.\n      if (isDOMElement(value)) {\n        return getOuterHTML(value);\n      }\n\n      // Look up the keys of the object.\n      var visibleKeys = Object.keys(value);\n      var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys;\n\n      // Some type of object without properties can be shortcutted.\n      // In IE, errors have a single `stack` property, or if they are vanilla `Error`,\n      // a `stack` plus `description` property; ignore those for consistency.\n      if (keys.length === 0 || (isError(value) && (\n          (keys.length === 1 && keys[0] === 'stack') ||\n          (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack')\n         ))) {\n        if (typeof value === 'function') {\n          var name = getName(value);\n          var nameSuffix = name ? ': ' + name : '';\n          return ctx.stylize('[Function' + nameSuffix + ']', 'special');\n        }\n        if (isRegExp(value)) {\n          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n        }\n        if (isDate(value)) {\n          return ctx.stylize(Date.prototype.toUTCString.call(value), 'date');\n        }\n        if (isError(value)) {\n          return formatError(value);\n        }\n      }\n\n      var base = '', array = false, braces = ['{', '}'];\n\n      // Make Array say that they are Array\n      if (isArray(value)) {\n        array = true;\n        braces = ['[', ']'];\n      }\n\n      // Make functions say that they are functions\n      if (typeof value === 'function') {\n        var name = getName(value);\n        var nameSuffix = name ? ': ' + name : '';\n        base = ' [Function' + nameSuffix + ']';\n      }\n\n      // Make RegExps say that they are RegExps\n      if (isRegExp(value)) {\n        base = ' ' + RegExp.prototype.toString.call(value);\n      }\n\n      // Make dates with properties first say the date\n      if (isDate(value)) {\n        base = ' ' + Date.prototype.toUTCString.call(value);\n      }\n\n      // Make error with message first say the error\n      if (isError(value)) {\n        return formatError(value);\n      }\n\n      if (keys.length === 0 && (!array || value.length == 0)) {\n        return braces[0] + base + braces[1];\n      }\n\n      if (recurseTimes < 0) {\n        if (isRegExp(value)) {\n          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n        } else {\n          return ctx.stylize('[Object]', 'special');\n        }\n      }\n\n      ctx.seen.push(value);\n\n      var output;\n      if (array) {\n        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);\n      } else {\n        output = keys.map(function(key) {\n          return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);\n        });\n      }\n\n      ctx.seen.pop();\n\n      return reduceToSingleString(output, base, braces);\n    }\n\n\n    function formatPrimitive(ctx, value) {\n      switch (typeof value) {\n        case 'undefined':\n          return ctx.stylize('undefined', 'undefined');\n\n        case 'string':\n          var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '')\n                                                   .replace(/'/g, \"\\\\'\")\n                                                   .replace(/\\\\\"/g, '\"') + '\\'';\n          return ctx.stylize(simple, 'string');\n\n        case 'number':\n          return ctx.stylize('' + value, 'number');\n\n        case 'boolean':\n          return ctx.stylize('' + value, 'boolean');\n      }\n      // For some reason typeof null is \"object\", so special case here.\n      if (value === null) {\n        return ctx.stylize('null', 'null');\n      }\n    }\n\n\n    function formatError(value) {\n      return '[' + Error.prototype.toString.call(value) + ']';\n    }\n\n\n    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {\n      var output = [];\n      for (var i = 0, l = value.length; i < l; ++i) {\n        if (Object.prototype.hasOwnProperty.call(value, String(i))) {\n          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n              String(i), true));\n        } else {\n          output.push('');\n        }\n      }\n      keys.forEach(function(key) {\n        if (!key.match(/^\\d+$/)) {\n          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n              key, true));\n        }\n      });\n      return output;\n    }\n\n\n    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {\n      var name, str;\n      if (value.__lookupGetter__) {\n        if (value.__lookupGetter__(key)) {\n          if (value.__lookupSetter__(key)) {\n            str = ctx.stylize('[Getter/Setter]', 'special');\n          } else {\n            str = ctx.stylize('[Getter]', 'special');\n          }\n        } else {\n          if (value.__lookupSetter__(key)) {\n            str = ctx.stylize('[Setter]', 'special');\n          }\n        }\n      }\n      if (visibleKeys.indexOf(key) < 0) {\n        name = '[' + key + ']';\n      }\n      if (!str) {\n        if (ctx.seen.indexOf(value[key]) < 0) {\n          if (recurseTimes === null) {\n            str = formatValue(ctx, value[key], null);\n          } else {\n            str = formatValue(ctx, value[key], recurseTimes - 1);\n          }\n          if (str.indexOf('\\n') > -1) {\n            if (array) {\n              str = str.split('\\n').map(function(line) {\n                return '  ' + line;\n              }).join('\\n').substr(2);\n            } else {\n              str = '\\n' + str.split('\\n').map(function(line) {\n                return '   ' + line;\n              }).join('\\n');\n            }\n          }\n        } else {\n          str = ctx.stylize('[Circular]', 'special');\n        }\n      }\n      if (typeof name === 'undefined') {\n        if (array && key.match(/^\\d+$/)) {\n          return str;\n        }\n        name = JSON.stringify('' + key);\n        if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n          name = name.substr(1, name.length - 2);\n          name = ctx.stylize(name, 'name');\n        } else {\n          name = name.replace(/'/g, \"\\\\'\")\n                     .replace(/\\\\\"/g, '\"')\n                     .replace(/(^\"|\"$)/g, \"'\");\n          name = ctx.stylize(name, 'string');\n        }\n      }\n\n      return name + ': ' + str;\n    }\n\n\n    function reduceToSingleString(output, base, braces) {\n      var numLinesEst = 0;\n      var length = output.reduce(function(prev, cur) {\n        numLinesEst++;\n        if (cur.indexOf('\\n') >= 0) numLinesEst++;\n        return prev + cur.length + 1;\n      }, 0);\n\n      if (length > 60) {\n        return braces[0] +\n               (base === '' ? '' : base + '\\n ') +\n               ' ' +\n               output.join(',\\n  ') +\n               ' ' +\n               braces[1];\n      }\n\n      return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n    }\n\n    function isArray(ar) {\n      return Array.isArray(ar) ||\n             (typeof ar === 'object' && objectToString(ar) === '[object Array]');\n    }\n\n    function isRegExp(re) {\n      return typeof re === 'object' && objectToString(re) === '[object RegExp]';\n    }\n\n    function isDate(d) {\n      return typeof d === 'object' && objectToString(d) === '[object Date]';\n    }\n\n    function isError(e) {\n      return typeof e === 'object' && objectToString(e) === '[object Error]';\n    }\n\n    function objectToString(o) {\n      return Object.prototype.toString.call(o);\n    }\n\n  }); // module: chai/utils/inspect.js\n\n  require.register(\"chai/utils/objDisplay.js\", function(module, exports, require){\n    /*!\n     * Chai - flag utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Module dependancies\n     */\n\n    var inspect = require('./inspect');\n\n    /**\n     * ### .objDisplay (object)\n     *\n     * Determines if an object or an array matches\n     * criteria to be inspected in-line for error\n     * messages or should be truncated.\n     *\n     * @param {Mixed} javascript object to inspect\n     * @name objDisplay\n     * @api public\n     */\n\n    module.exports = function (obj) {\n      var str = inspect(obj)\n        , type = Object.prototype.toString.call(obj);\n\n      if (str.length >= 40) {\n        if (type === '[object Array]') {\n          return '[ Array(' + obj.length + ') ]';\n        } else if (type === '[object Object]') {\n          var keys = Object.keys(obj)\n            , kstr = keys.length > 2\n              ? keys.splice(0, 2).join(', ') + ', ...'\n              : keys.join(', ');\n          return '{ Object (' + kstr + ') }';\n        } else {\n          return str;\n        }\n      } else {\n        return str;\n      }\n    };\n\n  }); // module: chai/utils/objDisplay.js\n\n  require.register(\"chai/utils/overwriteMethod.js\", function(module, exports, require){\n    /*!\n     * Chai - overwriteMethod utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * ### overwriteMethod (ctx, name, fn)\n     *\n     * Overwites an already existing method and provides\n     * access to previous function. Must return function\n     * to be used for name.\n     *\n     *     utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) {\n     *       return function (str) {\n     *         var obj = utils.flag(this, 'object');\n     *         if (obj instanceof Foo) {\n     *           new chai.Assertion(obj.value).to.equal(str);\n     *         } else {\n     *           _super.apply(this, arguments);\n     *         }\n     *       }\n     *     });\n     *\n     * Can also be accessed directly from `chai.Assertion`.\n     *\n     *     chai.Assertion.overwriteMethod('foo', fn);\n     *\n     * Then can be used as any other assertion.\n     *\n     *     expect(myFoo).to.equal('bar');\n     *\n     * @param {Object} ctx object whose method is to be overwritten\n     * @param {String} name of method to overwrite\n     * @param {Function} method function that returns a function to be used for name\n     * @name overwriteMethod\n     * @api public\n     */\n\n    module.exports = function (ctx, name, method) {\n      var _method = ctx[name]\n        , _super = function () { return this; };\n\n      if (_method && 'function' === typeof _method)\n        _super = _method;\n\n      ctx[name] = function () {\n        var result = method(_super).apply(this, arguments);\n        return result === undefined ? this : result;\n      }\n    };\n\n  }); // module: chai/utils/overwriteMethod.js\n\n  require.register(\"chai/utils/overwriteProperty.js\", function(module, exports, require){\n    /*!\n     * Chai - overwriteProperty utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * ### overwriteProperty (ctx, name, fn)\n     *\n     * Overwites an already existing property getter and provides\n     * access to previous value. Must return function to use as getter.\n     *\n     *     utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) {\n     *       return function () {\n     *         var obj = utils.flag(this, 'object');\n     *         if (obj instanceof Foo) {\n     *           new chai.Assertion(obj.name).to.equal('bar');\n     *         } else {\n     *           _super.call(this);\n     *         }\n     *       }\n     *     });\n     *\n     *\n     * Can also be accessed directly from `chai.Assertion`.\n     *\n     *     chai.Assertion.overwriteProperty('foo', fn);\n     *\n     * Then can be used as any other assertion.\n     *\n     *     expect(myFoo).to.be.ok;\n     *\n     * @param {Object} ctx object whose property is to be overwritten\n     * @param {String} name of property to overwrite\n     * @param {Function} getter function that returns a getter function to be used for name\n     * @name overwriteProperty\n     * @api public\n     */\n\n    module.exports = function (ctx, name, getter) {\n      var _get = Object.getOwnPropertyDescriptor(ctx, name)\n        , _super = function () {};\n\n      if (_get && 'function' === typeof _get.get)\n        _super = _get.get\n\n      Object.defineProperty(ctx, name,\n        { get: function () {\n            var result = getter(_super).call(this);\n            return result === undefined ? this : result;\n          }\n        , configurable: true\n      });\n    };\n\n  }); // module: chai/utils/overwriteProperty.js\n\n  require.register(\"chai/utils/test.js\", function(module, exports, require){\n    /*!\n     * Chai - test utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /*!\n     * Module dependancies\n     */\n\n    var flag = require('./flag');\n\n    /**\n     * # test(object, expression)\n     *\n     * Test and object for expression.\n     *\n     * @param {Object} object (constructed Assertion)\n     * @param {Arguments} chai.Assertion.prototype.assert arguments\n     */\n\n    module.exports = function (obj, args) {\n      var negate = flag(obj, 'negate')\n        , expr = args[0];\n      return negate ? !expr : expr;\n    };\n\n  }); // module: chai/utils/test.js\n\n  require.register(\"chai/utils/transferFlags.js\", function(module, exports, require){\n    /*!\n     * Chai - transferFlags utility\n     * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>\n     * MIT Licensed\n     */\n\n    /**\n     * ### transferFlags(assertion, object, includeAll = true)\n     *\n     * Transfer all the flags for `assertion` to `object`. If\n     * `includeAll` is set to `false`, then the base Chai\n     * assertion flags (namely `object`, `ssfi`, and `message`)\n     * will not be transferred.\n     *\n     *\n     *     var newAssertion = new Assertion();\n     *     utils.transferFlags(assertion, newAssertion);\n     *\n     *     var anotherAsseriton = new Assertion(myObj);\n     *     utils.transferFlags(assertion, anotherAssertion, false);\n     *\n     * @param {Assertion} assertion the assertion to transfer the flags from\n     * @param {Object} object the object to transfer the flags too; usually a new assertion\n     * @param {Boolean} includeAll\n     * @name getAllFlags\n     * @api private\n     */\n\n    module.exports = function (assertion, object, includeAll) {\n      var flags = assertion.__flags || (assertion.__flags = Object.create(null));\n\n      if (!object.__flags) {\n        object.__flags = Object.create(null);\n      }\n\n      includeAll = arguments.length === 3 ? includeAll : true;\n\n      for (var flag in flags) {\n        if (includeAll ||\n            (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) {\n          object.__flags[flag] = flags[flag];\n        }\n      }\n    };\n\n  }); // module: chai/utils/transferFlags.js\n\n  require.alias(\"./chai.js\", \"chai\");\n\n  return require('chai');\n});"
  },
  {
    "path": "test/lib/expect.js",
    "content": "/*!\n * chai\n * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, util) {\n  chai.expect = function (val, message) {\n    return new chai.Assertion(val, message);\n  };\n};\n\n"
  },
  {
    "path": "test/lib/mocha/mocha.css",
    "content": "@charset \"utf-8\";\n\nbody {\n  font: 20px/1.5 \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  padding: 60px 50px;\n}\n\n#mocha ul, #mocha li {\n  margin: 0;\n  padding: 0;\n}\n\n#mocha ul {\n  list-style: none;\n}\n\n#mocha h1, #mocha h2 {\n  margin: 0;\n}\n\n#mocha h1 {\n  margin-top: 15px;\n  font-size: 1em;\n  font-weight: 200;\n}\n\n#mocha h1 a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha h1 a:hover {\n  text-decoration: underline;\n}\n\n#mocha .suite .suite h1 {\n  margin-top: 0;\n  font-size: .8em;\n}\n\n.hidden {\n  display: none;\n}\n\n#mocha h2 {\n  font-size: 12px;\n  font-weight: normal;\n  cursor: pointer;\n}\n\n#mocha .suite {\n  margin-left: 15px;\n}\n\n#mocha .test {\n  margin-left: 15px;\n  overflow: hidden;\n}\n\n#mocha .test.pending:hover h2::after {\n  content: '(pending)';\n  font-family: arial;\n}\n\n#mocha .test.pass.medium .duration {\n  background: #C09853;\n}\n\n#mocha .test.pass.slow .duration {\n  background: #B94A48;\n}\n\n#mocha .test.pass::before {\n  content: '✓';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #00d6b2;\n}\n\n#mocha .test.pass .duration {\n  font-size: 9px;\n  margin-left: 5px;\n  padding: 2px 5px;\n  color: white;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n  -ms-border-radius: 5px;\n  -o-border-radius: 5px;\n  border-radius: 5px;\n}\n\n#mocha .test.pass.fast .duration {\n  display: none;\n}\n\n#mocha .test.pending {\n  color: #0b97c4;\n}\n\n#mocha .test.pending::before {\n  content: '◦';\n  color: #0b97c4;\n}\n\n#mocha .test.fail {\n  color: #c00;\n}\n\n#mocha .test.fail pre {\n  color: black;\n}\n\n#mocha .test.fail::before {\n  content: '✖';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #c00;\n}\n\n#mocha .test pre.error {\n  color: #c00;\n  max-height: 300px;\n  overflow: auto;\n}\n\n#mocha .test pre {\n  display: block;\n  float: left;\n  clear: left;\n  font: 12px/1.5 monaco, monospace;\n  margin: 5px;\n  padding: 15px;\n  border: 1px solid #eee;\n  border-bottom-color: #ddd;\n  -webkit-border-radius: 3px;\n  -webkit-box-shadow: 0 1px 3px #eee;\n  -moz-border-radius: 3px;\n  -moz-box-shadow: 0 1px 3px #eee;\n}\n\n#mocha .test h2 {\n  position: relative;\n}\n\n#mocha .test a.replay {\n  position: absolute;\n  top: 3px;\n  right: 0;\n  text-decoration: none;\n  vertical-align: middle;\n  display: block;\n  width: 15px;\n  height: 15px;\n  line-height: 15px;\n  text-align: center;\n  background: #eee;\n  font-size: 15px;\n  -moz-border-radius: 15px;\n  border-radius: 15px;\n  -webkit-transition: opacity 200ms;\n  -moz-transition: opacity 200ms;\n  transition: opacity 200ms;\n  opacity: 0.3;\n  color: #888;\n}\n\n#mocha .test:hover a.replay {\n  opacity: 1;\n}\n\n#mocha-report.pass .test.fail {\n  display: none;\n}\n\n#mocha-report.fail .test.pass {\n  display: none;\n}\n\n#mocha-error {\n  color: #c00;\n  font-size: 1.5  em;\n  font-weight: 100;\n  letter-spacing: 1px;\n}\n\n#mocha-stats {\n  position: fixed;\n  top: 15px;\n  right: 10px;\n  font-size: 12px;\n  margin: 0;\n  color: #888;\n}\n\n#mocha-stats .progress {\n  float: right;\n  padding-top: 0;\n}\n\n#mocha-stats em {\n  color: black;\n}\n\n#mocha-stats a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha-stats a:hover {\n  border-bottom: 1px solid #eee;\n}\n\n#mocha-stats li {\n  display: inline-block;\n  margin: 0 5px;\n  list-style: none;\n  padding-top: 11px;\n}\n\ncode .comment { color: #ddd }\ncode .init { color: #2F6FAD }\ncode .string { color: #5890AD }\ncode .keyword { color: #8A6343 }\ncode .number { color: #2F6FAD }\n"
  },
  {
    "path": "test/lib/mocha/mocha.js",
    "content": ";(function(){\n\n\n// CommonJS require()\n\nfunction require(p){\n    var path = require.resolve(p)\n      , mod = require.modules[path];\n    if (!mod) throw new Error('failed to require \"' + p + '\"');\n    if (!mod.exports) {\n      mod.exports = {};\n      mod.call(mod.exports, mod, mod.exports, require.relative(path));\n    }\n    return mod.exports;\n  }\n\nrequire.modules = {};\n\nrequire.resolve = function (path){\n    var orig = path\n      , reg = path + '.js'\n      , index = path + '/index.js';\n    return require.modules[reg] && reg\n      || require.modules[index] && index\n      || orig;\n  };\n\nrequire.register = function (path, fn){\n    require.modules[path] = fn;\n  };\n\nrequire.relative = function (parent) {\n    return function(p){\n      if ('.' != p.charAt(0)) return require(p);\n      \n      var path = parent.split('/')\n        , segs = p.split('/');\n      path.pop();\n      \n      for (var i = 0; i < segs.length; i++) {\n        var seg = segs[i];\n        if ('..' == seg) path.pop();\n        else if ('.' != seg) path.push(seg);\n      }\n\n      return require(path.join('/'));\n    };\n  };\n\n\nrequire.register(\"browser/debug.js\", function(module, exports, require){\n\nmodule.exports = function(type){\n  return function(){\n    \n  }\n};\n}); // module: browser/debug.js\n\nrequire.register(\"browser/diff.js\", function(module, exports, require){\n/* See license.txt for terms of usage */\n\n/*\n * Text diff implementation.\n * \n * This library supports the following APIS:\n * JsDiff.diffChars: Character by character diff\n * JsDiff.diffWords: Word (as defined by \\b regex) diff which ignores whitespace\n * JsDiff.diffLines: Line based diff\n * \n * JsDiff.diffCss: Diff targeted at CSS content\n * \n * These methods are based on the implementation proposed in\n * \"An O(ND) Difference Algorithm and its Variations\" (Myers, 1986).\n * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927\n */\nvar JsDiff = (function() {\n  function clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n  }\n  function removeEmpty(array) {\n    var ret = [];\n    for (var i = 0; i < array.length; i++) {\n      if (array[i]) {\n        ret.push(array[i]);\n      }\n    }\n    return ret;\n  }\n  function escapeHTML(s) {\n    var n = s;\n    n = n.replace(/&/g, \"&amp;\");\n    n = n.replace(/</g, \"&lt;\");\n    n = n.replace(/>/g, \"&gt;\");\n    n = n.replace(/\"/g, \"&quot;\");\n\n    return n;\n  }\n\n\n  var fbDiff = function(ignoreWhitespace) {\n    this.ignoreWhitespace = ignoreWhitespace;\n  };\n  fbDiff.prototype = {\n      diff: function(oldString, newString) {\n        // Handle the identity case (this is due to unrolling editLength == 0\n        if (newString == oldString) {\n          return [{ value: newString }];\n        }\n        if (!newString) {\n          return [{ value: oldString, removed: true }];\n        }\n        if (!oldString) {\n          return [{ value: newString, added: true }];\n        }\n\n        newString = this.tokenize(newString);\n        oldString = this.tokenize(oldString);\n\n        var newLen = newString.length, oldLen = oldString.length;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0\n        var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);\n        if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {\n          return bestPath[0].components;\n        }\n\n        for (var editLength = 1; editLength <= maxEditLength; editLength++) {\n          for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {\n            var basePath;\n            var addPath = bestPath[diagonalPath-1],\n                removePath = bestPath[diagonalPath+1];\n            oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n            if (addPath) {\n              // No one else is going to attempt to use this value, clear it\n              bestPath[diagonalPath-1] = undefined;\n            }\n\n            var canAdd = addPath && addPath.newPos+1 < newLen;\n            var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n            if (!canAdd && !canRemove) {\n              bestPath[diagonalPath] = undefined;\n              continue;\n            }\n\n            // Select the diagonal that we want to branch from. We select the prior\n            // path whose position in the new string is the farthest from the origin\n            // and does not pass the bounds of the diff graph\n            if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n              basePath = clonePath(removePath);\n              this.pushComponent(basePath.components, oldString[oldPos], undefined, true);\n            } else {\n              basePath = clonePath(addPath);\n              basePath.newPos++;\n              this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);\n            }\n\n            var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);\n\n            if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {\n              return basePath.components;\n            } else {\n              bestPath[diagonalPath] = basePath;\n            }\n          }\n        }\n      },\n\n      pushComponent: function(components, value, added, removed) {\n        var last = components[components.length-1];\n        if (last && last.added === added && last.removed === removed) {\n          // We need to clone here as the component clone operation is just\n          // as shallow array clone\n          components[components.length-1] =\n            {value: this.join(last.value, value), added: added, removed: removed };\n        } else {\n          components.push({value: value, added: added, removed: removed });\n        }\n      },\n      extractCommon: function(basePath, newString, oldString, diagonalPath) {\n        var newLen = newString.length,\n            oldLen = oldString.length,\n            newPos = basePath.newPos,\n            oldPos = newPos - diagonalPath;\n        while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {\n          newPos++;\n          oldPos++;\n          \n          this.pushComponent(basePath.components, newString[newPos], undefined, undefined);\n        }\n        basePath.newPos = newPos;\n        return oldPos;\n      },\n\n      equals: function(left, right) {\n        var reWhitespace = /\\S/;\n        if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {\n          return true;\n        } else {\n          return left == right;\n        }\n      },\n      join: function(left, right) {\n        return left + right;\n      },\n      tokenize: function(value) {\n        return value;\n      }\n  };\n  \n  var CharDiff = new fbDiff();\n  \n  var WordDiff = new fbDiff(true);\n  WordDiff.tokenize = function(value) {\n    return removeEmpty(value.split(/(\\s+|\\b)/));\n  };\n  \n  var CssDiff = new fbDiff(true);\n  CssDiff.tokenize = function(value) {\n    return removeEmpty(value.split(/([{}:;,]|\\s+)/));\n  };\n  \n  var LineDiff = new fbDiff();\n  LineDiff.tokenize = function(value) {\n    return value.split(/^/m);\n  };\n  \n  return {\n    diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },\n    diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },\n    diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },\n\n    diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },\n\n    createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {\n      var ret = [];\n\n      ret.push(\"Index: \" + fileName);\n      ret.push(\"===================================================================\");\n      ret.push(\"--- \" + fileName + (typeof oldHeader === \"undefined\" ? \"\" : \"\\t\" + oldHeader));\n      ret.push(\"+++ \" + fileName + (typeof newHeader === \"undefined\" ? \"\" : \"\\t\" + newHeader));\n\n      var diff = LineDiff.diff(oldStr, newStr);\n      if (!diff[diff.length-1].value) {\n        diff.pop();   // Remove trailing newline add\n      }\n      diff.push({value: \"\", lines: []});   // Append an empty value to make cleanup easier\n\n      function contextLines(lines) {\n        return lines.map(function(entry) { return ' ' + entry; });\n      }\n      function eofNL(curRange, i, current) {\n        var last = diff[diff.length-2],\n            isLast = i === diff.length-2,\n            isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);\n\n        // Figure out if this is the last line for the given file and missing NL\n        if (!/\\n$/.test(current.value) && (isLast || isLastOfType)) {\n          curRange.push('\\\\ No newline at end of file');\n        }\n      }\n\n      var oldRangeStart = 0, newRangeStart = 0, curRange = [],\n          oldLine = 1, newLine = 1;\n      for (var i = 0; i < diff.length; i++) {\n        var current = diff[i],\n            lines = current.lines || current.value.replace(/\\n$/, \"\").split(\"\\n\");\n        current.lines = lines;\n\n        if (current.added || current.removed) {\n          if (!oldRangeStart) {\n            var prev = diff[i-1];\n            oldRangeStart = oldLine;\n            newRangeStart = newLine;\n            \n            if (prev) {\n              curRange = contextLines(prev.lines.slice(-4));\n              oldRangeStart -= curRange.length;\n              newRangeStart -= curRange.length;\n            }\n          }\n          curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?\"+\":\"-\") + entry; }));\n          eofNL(curRange, i, current);\n\n          if (current.added) {\n            newLine += lines.length;\n          } else {\n            oldLine += lines.length;\n          }\n        } else {\n          if (oldRangeStart) {\n            // Close out any changes that have been output (or join overlapping)\n            if (lines.length <= 8 && i < diff.length-2) {\n              // Overlapping\n              curRange.push.apply(curRange, contextLines(lines));\n            } else {\n              // end the range and output\n              var contextSize = Math.min(lines.length, 4);\n              ret.push(\n                  \"@@ -\" + oldRangeStart + \",\" + (oldLine-oldRangeStart+contextSize)\n                  + \" +\" + newRangeStart + \",\" + (newLine-newRangeStart+contextSize)\n                  + \" @@\");\n              ret.push.apply(ret, curRange);\n              ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));\n              if (lines.length <= 4) {\n                eofNL(ret, i, current);\n              }\n\n              oldRangeStart = 0;  newRangeStart = 0; curRange = [];\n            }\n          }\n          oldLine += lines.length;\n          newLine += lines.length;\n        }\n      }\n\n      return ret.join('\\n') + '\\n';\n    },\n\n    convertChangesToXML: function(changes){\n      var ret = [];\n      for ( var i = 0; i < changes.length; i++) {\n        var change = changes[i];\n        if (change.added) {\n          ret.push(\"<ins>\");\n        } else if (change.removed) {\n          ret.push(\"<del>\");\n        }\n\n        ret.push(escapeHTML(change.value));\n\n        if (change.added) {\n          ret.push(\"</ins>\");\n        } else if (change.removed) {\n          ret.push(\"</del>\");\n        }\n      }\n      return ret.join(\"\");\n    }\n  };\n})();\n\nif (typeof module !== \"undefined\") {\n    module.exports = JsDiff;\n}\n\n}); // module: browser/diff.js\n\nrequire.register(\"browser/events.js\", function(module, exports, require){\n\n/**\n * Module exports.\n */\n\nexports.EventEmitter = EventEmitter;\n\n/**\n * Check if `obj` is an array.\n */\n\nfunction isArray(obj) {\n  return '[object Array]' == {}.toString.call(obj);\n}\n\n/**\n * Event emitter constructor.\n *\n * @api public\n */\n\nfunction EventEmitter(){};\n\n/**\n * Adds a listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.on = function (name, fn) {\n  if (!this.$events) {\n    this.$events = {};\n  }\n\n  if (!this.$events[name]) {\n    this.$events[name] = fn;\n  } else if (isArray(this.$events[name])) {\n    this.$events[name].push(fn);\n  } else {\n    this.$events[name] = [this.$events[name], fn];\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n/**\n * Adds a volatile listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.once = function (name, fn) {\n  var self = this;\n\n  function on () {\n    self.removeListener(name, on);\n    fn.apply(this, arguments);\n  };\n\n  on.listener = fn;\n  this.on(name, on);\n\n  return this;\n};\n\n/**\n * Removes a listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.removeListener = function (name, fn) {\n  if (this.$events && this.$events[name]) {\n    var list = this.$events[name];\n\n    if (isArray(list)) {\n      var pos = -1;\n\n      for (var i = 0, l = list.length; i < l; i++) {\n        if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {\n          pos = i;\n          break;\n        }\n      }\n\n      if (pos < 0) {\n        return this;\n      }\n\n      list.splice(pos, 1);\n\n      if (!list.length) {\n        delete this.$events[name];\n      }\n    } else if (list === fn || (list.listener && list.listener === fn)) {\n      delete this.$events[name];\n    }\n  }\n\n  return this;\n};\n\n/**\n * Removes all listeners for an event.\n *\n * @api public\n */\n\nEventEmitter.prototype.removeAllListeners = function (name) {\n  if (name === undefined) {\n    this.$events = {};\n    return this;\n  }\n\n  if (this.$events && this.$events[name]) {\n    this.$events[name] = null;\n  }\n\n  return this;\n};\n\n/**\n * Gets all listeners for a certain event.\n *\n * @api public\n */\n\nEventEmitter.prototype.listeners = function (name) {\n  if (!this.$events) {\n    this.$events = {};\n  }\n\n  if (!this.$events[name]) {\n    this.$events[name] = [];\n  }\n\n  if (!isArray(this.$events[name])) {\n    this.$events[name] = [this.$events[name]];\n  }\n\n  return this.$events[name];\n};\n\n/**\n * Emits an event.\n *\n * @api public\n */\n\nEventEmitter.prototype.emit = function (name) {\n  if (!this.$events) {\n    return false;\n  }\n\n  var handler = this.$events[name];\n\n  if (!handler) {\n    return false;\n  }\n\n  var args = [].slice.call(arguments, 1);\n\n  if ('function' == typeof handler) {\n    handler.apply(this, args);\n  } else if (isArray(handler)) {\n    var listeners = handler.slice();\n\n    for (var i = 0, l = listeners.length; i < l; i++) {\n      listeners[i].apply(this, args);\n    }\n  } else {\n    return false;\n  }\n\n  return true;\n};\n}); // module: browser/events.js\n\nrequire.register(\"browser/fs.js\", function(module, exports, require){\n\n}); // module: browser/fs.js\n\nrequire.register(\"browser/path.js\", function(module, exports, require){\n\n}); // module: browser/path.js\n\nrequire.register(\"browser/progress.js\", function(module, exports, require){\n\n/**\n * Expose `Progress`.\n */\n\nmodule.exports = Progress;\n\n/**\n * Initialize a new `Progress` indicator.\n */\n\nfunction Progress() {\n  this.percent = 0;\n  this.size(0);\n  this.fontSize(11);\n  this.font('helvetica, arial, sans-serif');\n}\n\n/**\n * Set progress size to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.size = function(n){\n  this._size = n;\n  return this;\n};\n\n/**\n * Set text to `str`.\n *\n * @param {String} str\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.text = function(str){\n  this._text = str;\n  return this;\n};\n\n/**\n * Set font size to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.fontSize = function(n){\n  this._fontSize = n;\n  return this;\n};\n\n/**\n * Set font `family`.\n *\n * @param {String} family\n * @return {Progress} for chaining\n */\n\nProgress.prototype.font = function(family){\n  this._font = family;\n  return this;\n};\n\n/**\n * Update percentage to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n */\n\nProgress.prototype.update = function(n){\n  this.percent = n;\n  return this;\n};\n\n/**\n * Draw on `ctx`.\n *\n * @param {CanvasRenderingContext2d} ctx\n * @return {Progress} for chaining\n */\n\nProgress.prototype.draw = function(ctx){\n  var percent = Math.min(this.percent, 100)\n    , size = this._size\n    , half = size / 2\n    , x = half\n    , y = half\n    , rad = half - 1\n    , fontSize = this._fontSize;\n\n  ctx.font = fontSize + 'px ' + this._font;\n\n  var angle = Math.PI * 2 * (percent / 100);\n  ctx.clearRect(0, 0, size, size);\n\n  // outer circle\n  ctx.strokeStyle = '#9f9f9f';\n  ctx.beginPath();\n  ctx.arc(x, y, rad, 0, angle, false);\n  ctx.stroke();\n\n  // inner circle\n  ctx.strokeStyle = '#eee';\n  ctx.beginPath();\n  ctx.arc(x, y, rad - 1, 0, angle, true);\n  ctx.stroke();\n\n  // text\n  var text = this._text || (percent | 0) + '%'\n    , w = ctx.measureText(text).width;\n\n  ctx.fillText(\n      text\n    , x - w / 2 + 1\n    , y + fontSize / 2 - 1);\n\n  return this;\n};\n\n}); // module: browser/progress.js\n\nrequire.register(\"browser/tty.js\", function(module, exports, require){\n\nexports.isatty = function(){\n  return true;\n};\n\nexports.getWindowSize = function(){\n  return [window.innerHeight, window.innerWidth];\n};\n}); // module: browser/tty.js\n\nrequire.register(\"context.js\", function(module, exports, require){\n\n/**\n * Expose `Context`.\n */\n\nmodule.exports = Context;\n\n/**\n * Initialize a new `Context`.\n *\n * @api private\n */\n\nfunction Context(){}\n\n/**\n * Set or get the context `Runnable` to `runnable`.\n *\n * @param {Runnable} runnable\n * @return {Context}\n * @api private\n */\n\nContext.prototype.runnable = function(runnable){\n  if (0 == arguments.length) return this._runnable;\n  this.test = this._runnable = runnable;\n  return this;\n};\n\n/**\n * Set test timeout `ms`.\n *\n * @param {Number} ms\n * @return {Context} self\n * @api private\n */\n\nContext.prototype.timeout = function(ms){\n  this.runnable().timeout(ms);\n  return this;\n};\n\n/**\n * Set test slowness threshold `ms`.\n *\n * @param {Number} ms\n * @return {Context} self\n * @api private\n */\n\nContext.prototype.slow = function(ms){\n  this.runnable().slow(ms);\n  return this;\n};\n\n/**\n * Inspect the context void of `._runnable`.\n *\n * @return {String}\n * @api private\n */\n\nContext.prototype.inspect = function(){\n  return JSON.stringify(this, function(key, val){\n    if ('_runnable' == key) return;\n    if ('test' == key) return;\n    return val;\n  }, 2);\n};\n\n}); // module: context.js\n\nrequire.register(\"hook.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Runnable = require('./runnable');\n\n/**\n * Expose `Hook`.\n */\n\nmodule.exports = Hook;\n\n/**\n * Initialize a new `Hook` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Hook(title, fn) {\n  Runnable.call(this, title, fn);\n  this.type = 'hook';\n}\n\n/**\n * Inherit from `Runnable.prototype`.\n */\n\nfunction F(){};\nF.prototype = Runnable.prototype;\nHook.prototype = new F;\nHook.prototype.constructor = Hook;\n\n\n/**\n * Get or set the test `err`.\n *\n * @param {Error} err\n * @return {Error}\n * @api public\n */\n\nHook.prototype.error = function(err){\n  if (0 == arguments.length) {\n    var err = this._error;\n    this._error = null;\n    return err;\n  }\n\n  this._error = err;\n};\n\n\n}); // module: hook.js\n\nrequire.register(\"interfaces/bdd.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * BDD-style interface:\n * \n *      describe('Array', function(){\n *        describe('#indexOf()', function(){\n *          it('should return -1 when not present', function(){\n *\n *          });\n *\n *          it('should return the index when present', function(){\n *\n *          });\n *        });\n *      });\n * \n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context, file, mocha){\n\n    /**\n     * Execute before running tests.\n     */\n\n    context.before = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after running tests.\n     */\n\n    context.after = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.beforeEach = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.afterEach = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`\n     * and callback `fn` containing nested suites\n     * and/or tests.\n     */\n  \n    context.describe = context.context = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n      fn.call(suite);\n      suites.shift();\n      return suite;\n    };\n\n    /**\n     * Pending describe.\n     */\n\n    context.xdescribe =\n    context.xcontext =\n    context.describe.skip = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suite.pending = true;\n      suites.unshift(suite);\n      fn.call(suite);\n      suites.shift();\n    };\n\n    /**\n     * Exclusive suite.\n     */\n\n    context.describe.only = function(title, fn){\n      var suite = context.describe(title, fn);\n      mocha.grep(suite.fullTitle());\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.it = context.specify = function(title, fn){\n      var suite = suites[0];\n      if (suite.pending) var fn = null;\n      var test = new Test(title, fn);\n      suite.addTest(test);\n      return test;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.it.only = function(title, fn){\n      var test = context.it(title, fn);\n      mocha.grep(test.fullTitle());\n    };\n\n    /**\n     * Pending test case.\n     */\n\n    context.xit =\n    context.xspecify =\n    context.it.skip = function(title){\n      context.it(title);\n    };\n  });\n};\n\n}); // module: interfaces/bdd.js\n\nrequire.register(\"interfaces/exports.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * TDD-style interface:\n * \n *     exports.Array = {\n *       '#indexOf()': {\n *         'should return -1 when the value is not present': function(){\n *           \n *         },\n *\n *         'should return the correct index when the value is present': function(){\n *           \n *         }\n *       }\n *     };\n * \n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('require', visit);\n\n  function visit(obj) {\n    var suite;\n    for (var key in obj) {\n      if ('function' == typeof obj[key]) {\n        var fn = obj[key];\n        switch (key) {\n          case 'before':\n            suites[0].beforeAll(fn);\n            break;\n          case 'after':\n            suites[0].afterAll(fn);\n            break;\n          case 'beforeEach':\n            suites[0].beforeEach(fn);\n            break;\n          case 'afterEach':\n            suites[0].afterEach(fn);\n            break;\n          default:\n            suites[0].addTest(new Test(key, fn));\n        }\n      } else {\n        var suite = Suite.create(suites[0], key);\n        suites.unshift(suite);\n        visit(obj[key]);\n        suites.shift();\n      }\n    }\n  }\n};\n}); // module: interfaces/exports.js\n\nrequire.register(\"interfaces/index.js\", function(module, exports, require){\n\nexports.bdd = require('./bdd');\nexports.tdd = require('./tdd');\nexports.qunit = require('./qunit');\nexports.exports = require('./exports');\n\n}); // module: interfaces/index.js\n\nrequire.register(\"interfaces/qunit.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * QUnit-style interface:\n * \n *     suite('Array');\n *     \n *     test('#length', function(){\n *       var arr = [1,2,3];\n *       ok(arr.length == 3);\n *     });\n *     \n *     test('#indexOf()', function(){\n *       var arr = [1,2,3];\n *       ok(arr.indexOf(1) == 0);\n *       ok(arr.indexOf(2) == 1);\n *       ok(arr.indexOf(3) == 2);\n *     });\n *     \n *     suite('String');\n *     \n *     test('#length', function(){\n *       ok('foo'.length == 3);\n *     });\n * \n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context){\n\n    /**\n     * Execute before running tests.\n     */\n\n    context.before = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after running tests.\n     */\n\n    context.after = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.beforeEach = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.afterEach = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`.\n     */\n  \n    context.suite = function(title){\n      if (suites.length > 1) suites.shift();\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.test = function(title, fn){\n      suites[0].addTest(new Test(title, fn));\n    };\n  });\n};\n\n}); // module: interfaces/qunit.js\n\nrequire.register(\"interfaces/tdd.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * TDD-style interface:\n *\n *      suite('Array', function(){\n *        suite('#indexOf()', function(){\n *          suiteSetup(function(){\n *\n *          });\n *          \n *          test('should return -1 when not present', function(){\n *\n *          });\n *\n *          test('should return the index when present', function(){\n *\n *          });\n *\n *          suiteTeardown(function(){\n *\n *          });\n *        });\n *      });\n *\n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context, file, mocha){\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.setup = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.teardown = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Execute before the suite.\n     */\n\n    context.suiteSetup = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after the suite.\n     */\n\n    context.suiteTeardown = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`\n     * and callback `fn` containing nested suites\n     * and/or tests.\n     */\n\n    context.suite = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n      fn.call(suite);\n      suites.shift();\n      return suite;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.suite.only = function(title, fn){\n      var suite = context.suite(title, fn);\n      mocha.grep(suite.fullTitle());\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.test = function(title, fn){\n      var test = new Test(title, fn);\n      suites[0].addTest(test);\n      return test;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.test.only = function(title, fn){\n      var test = context.test(title, fn);\n      mocha.grep(test.fullTitle());\n    };\n\n    /**\n     * Pending test case.\n     */\n\n    context.test.skip = function(title){\n      context.test(title);\n    };\n  });\n};\n\n}); // module: interfaces/tdd.js\n\nrequire.register(\"mocha.js\", function(module, exports, require){\n/*!\n * mocha\n * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar path = require('browser/path')\n  , utils = require('./utils');\n\n/**\n * Expose `Mocha`.\n */\n\nexports = module.exports = Mocha;\n\n/**\n * Expose internals.\n */\n\nexports.utils = utils;\nexports.interfaces = require('./interfaces');\nexports.reporters = require('./reporters');\nexports.Runnable = require('./runnable');\nexports.Context = require('./context');\nexports.Runner = require('./runner');\nexports.Suite = require('./suite');\nexports.Hook = require('./hook');\nexports.Test = require('./test');\n\n/**\n * Return image `name` path.\n *\n * @param {String} name\n * @return {String}\n * @api private\n */\n\nfunction image(name) {\n  return __dirname + '/../images/' + name + '.png';\n}\n\n/**\n * Setup mocha with `options`.\n *\n * Options:\n *\n *   - `ui` name \"bdd\", \"tdd\", \"exports\" etc\n *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`\n *   - `globals` array of accepted globals\n *   - `timeout` timeout in milliseconds\n *   - `bail` bail on the first test failure\n *   - `slow` milliseconds to wait before considering a test slow\n *   - `ignoreLeaks` ignore global leaks\n *   - `grep` string or regexp to filter tests with\n *\n * @param {Object} options\n * @api public\n */\n\nfunction Mocha(options) {\n  options = options || {};\n  this.files = [];\n  this.options = options;\n  this.grep(options.grep);\n  this.suite = new exports.Suite('', new exports.Context);\n  this.ui(options.ui);\n  this.bail(options.bail);\n  this.reporter(options.reporter);\n  if (options.timeout) this.timeout(options.timeout);\n  if (options.slow) this.slow(options.slow);\n}\n\n/**\n * Enable or disable bailing on the first failure.\n *\n * @param {Boolean} [bail]\n * @api public\n */\n\nMocha.prototype.bail = function(bail){\n  if (null == bail) bail = true;\n  this.suite.bail(bail);\n  return this;\n};\n\n/**\n * Add test `file`.\n *\n * @param {String} file\n * @api public\n */\n\nMocha.prototype.addFile = function(file){\n  this.files.push(file);\n  return this;\n};\n\n/**\n * Set reporter to `reporter`, defaults to \"dot\".\n *\n * @param {String|Function} reporter name or constructor\n * @api public\n */\n\nMocha.prototype.reporter = function(reporter){\n  if ('function' == typeof reporter) {\n    this._reporter = reporter;\n  } else {\n    reporter = reporter || 'dot';\n    try {\n      this._reporter = require('./reporters/' + reporter);\n    } catch (err) {\n      this._reporter = require(reporter);\n    }\n    if (!this._reporter) throw new Error('invalid reporter \"' + reporter + '\"');\n  }\n  return this;\n};\n\n/**\n * Set test UI `name`, defaults to \"bdd\".\n *\n * @param {String} bdd\n * @api public\n */\n\nMocha.prototype.ui = function(name){\n  name = name || 'bdd';\n  this._ui = exports.interfaces[name];\n  if (!this._ui) throw new Error('invalid interface \"' + name + '\"');\n  this._ui = this._ui(this.suite);\n  return this;\n};\n\n/**\n * Load registered files.\n *\n * @api private\n */\n\nMocha.prototype.loadFiles = function(fn){\n  var self = this;\n  var suite = this.suite;\n  var pending = this.files.length;\n  this.files.forEach(function(file){\n    file = path.resolve(file);\n    suite.emit('pre-require', global, file, self);\n    suite.emit('require', require(file), file, self);\n    suite.emit('post-require', global, file, self);\n    --pending || (fn && fn());\n  });\n};\n\n/**\n * Enable growl support.\n *\n * @api private\n */\n\nMocha.prototype._growl = function(runner, reporter) {\n  var notify = require('growl');\n\n  runner.on('end', function(){\n    var stats = reporter.stats;\n    if (stats.failures) {\n      var msg = stats.failures + ' of ' + runner.total + ' tests failed';\n      notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });\n    } else {\n      notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {\n          name: 'mocha'\n        , title: 'Passed'\n        , image: image('ok')\n      });\n    }\n  });\n};\n\n/**\n * Add regexp to grep, if `re` is a string it is escaped.\n *\n * @param {RegExp|String} re\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.grep = function(re){\n  this.options.grep = 'string' == typeof re\n    ? new RegExp(utils.escapeRegexp(re))\n    : re;\n  return this;\n};\n\n/**\n * Invert `.grep()` matches.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.invert = function(){\n  this.options.invert = true;\n  return this;\n};\n\n/**\n * Ignore global leaks.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.ignoreLeaks = function(){\n  this.options.ignoreLeaks = true;\n  return this;\n};\n\n/**\n * Enable global leak checking.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.checkLeaks = function(){\n  this.options.ignoreLeaks = false;\n  return this;\n};\n\n/**\n * Enable growl support.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.growl = function(){\n  this.options.growl = true;\n  return this;\n};\n\n/**\n * Ignore `globals` array or string.\n *\n * @param {Array|String} globals\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.globals = function(globals){\n  this.options.globals = (this.options.globals || []).concat(globals);\n  return this;\n};\n\n/**\n * Set the timeout in milliseconds.\n *\n * @param {Number} timeout\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.timeout = function(timeout){\n  this.suite.timeout(timeout);\n  return this;\n};\n\n/**\n * Set slowness threshold in milliseconds.\n *\n * @param {Number} slow\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.slow = function(slow){\n  this.suite.slow(slow);\n  return this;\n};\n\n/**\n * Makes all tests async (accepting a callback)\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.asyncOnly = function(){\n  this.options.asyncOnly = true;\n  return this;\n};\n\n/**\n * Run tests and invoke `fn()` when complete.\n *\n * @param {Function} fn\n * @return {Runner}\n * @api public\n */\n\nMocha.prototype.run = function(fn){\n  if (this.files.length) this.loadFiles();\n  var suite = this.suite;\n  var options = this.options;\n  var runner = new exports.Runner(suite);\n  var reporter = new this._reporter(runner);\n  runner.ignoreLeaks = options.ignoreLeaks;\n  runner.asyncOnly = options.asyncOnly;\n  if (options.grep) runner.grep(options.grep, options.invert);\n  if (options.globals) runner.globals(options.globals);\n  if (options.growl) this._growl(runner, reporter);\n  return runner.run(fn);\n};\n\n}); // module: mocha.js\n\nrequire.register(\"ms.js\", function(module, exports, require){\n\n/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\n\n/**\n * Parse or format the given `val`.\n *\n * @param {String|Number} val\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function(val){\n  if ('string' == typeof val) return parse(val);\n  return format(val);\n}\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n  var m = /^((?:\\d+)?\\.?\\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);\n  if (!m) return;\n  var n = parseFloat(m[1]);\n  var type = (m[2] || 'ms').toLowerCase();\n  switch (type) {\n    case 'years':\n    case 'year':\n    case 'y':\n      return n * 31557600000;\n    case 'days':\n    case 'day':\n    case 'd':\n      return n * 86400000;\n    case 'hours':\n    case 'hour':\n    case 'h':\n      return n * 3600000;\n    case 'minutes':\n    case 'minute':\n    case 'm':\n      return n * 60000;\n    case 'seconds':\n    case 'second':\n    case 's':\n      return n * 1000;\n    case 'ms':\n      return n;\n  }\n}\n\n/**\n * Format the given `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api public\n */\n\nfunction format(ms) {\n  if (ms == d) return Math.round(ms / d) + ' day';\n  if (ms > d) return Math.round(ms / d) + ' days';\n  if (ms == h) return Math.round(ms / h) + ' hour';\n  if (ms > h) return Math.round(ms / h) + ' hours';\n  if (ms == m) return Math.round(ms / m) + ' minute';\n  if (ms > m) return Math.round(ms / m) + ' minutes';\n  if (ms == s) return Math.round(ms / s) + ' second';\n  if (ms > s) return Math.round(ms / s) + ' seconds';\n  return ms + ' ms';\n}\n}); // module: ms.js\n\nrequire.register(\"reporters/base.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar tty = require('browser/tty')\n  , diff = require('browser/diff')\n  , ms = require('../ms');\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Check if both stdio streams are associated with a tty.\n */\n\nvar isatty = tty.isatty(1) && tty.isatty(2);\n\n/**\n * Expose `Base`.\n */\n\nexports = module.exports = Base;\n\n/**\n * Enable coloring by default.\n */\n\nexports.useColors = isatty;\n\n/**\n * Default color map.\n */\n\nexports.colors = {\n    'pass': 90\n  , 'fail': 31\n  , 'bright pass': 92\n  , 'bright fail': 91\n  , 'bright yellow': 93\n  , 'pending': 36\n  , 'suite': 0\n  , 'error title': 0\n  , 'error message': 31\n  , 'error stack': 90\n  , 'checkmark': 32\n  , 'fast': 90\n  , 'medium': 33\n  , 'slow': 31\n  , 'green': 32\n  , 'light': 90\n  , 'diff gutter': 90\n  , 'diff added': 42\n  , 'diff removed': 41\n};\n\n/**\n * Default symbol map.\n */\n \nexports.symbols = {\n  ok: '✓',\n  err: '✖',\n  dot: '․'\n};\n\n// With node.js on Windows: use symbols available in terminal default fonts\nif ('win32' == process.platform) {\n  exports.symbols.ok = '\\u221A';\n  exports.symbols.err = '\\u00D7';\n  exports.symbols.dot = '.';\n}\n\n/**\n * Color `str` with the given `type`,\n * allowing colors to be disabled,\n * as well as user-defined color\n * schemes.\n *\n * @param {String} type\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nvar color = exports.color = function(type, str) {\n  if (!exports.useColors) return str;\n  return '\\u001b[' + exports.colors[type] + 'm' + str + '\\u001b[0m';\n};\n\n/**\n * Expose term window size, with some\n * defaults for when stderr is not a tty.\n */\n\nexports.window = {\n  width: isatty\n    ? process.stdout.getWindowSize\n      ? process.stdout.getWindowSize(1)[0]\n      : tty.getWindowSize()[1]\n    : 75\n};\n\n/**\n * Expose some basic cursor interactions\n * that are common among reporters.\n */\n\nexports.cursor = {\n  hide: function(){\n    process.stdout.write('\\u001b[?25l');\n  },\n\n  show: function(){\n    process.stdout.write('\\u001b[?25h');\n  },\n\n  deleteLine: function(){\n    process.stdout.write('\\u001b[2K');\n  },\n\n  beginningOfLine: function(){\n    process.stdout.write('\\u001b[0G');\n  },\n\n  CR: function(){\n    exports.cursor.deleteLine();\n    exports.cursor.beginningOfLine();\n  }\n};\n\n/**\n * Outut the given `failures` as a list.\n *\n * @param {Array} failures\n * @api public\n */\n\nexports.list = function(failures){\n  console.error();\n  failures.forEach(function(test, i){\n    // format\n    var fmt = color('error title', '  %s) %s:\\n')\n      + color('error message', '     %s')\n      + color('error stack', '\\n%s\\n');\n\n    // msg\n    var err = test.err\n      , message = err.message || ''\n      , stack = err.stack || message\n      , index = stack.indexOf(message) + message.length\n      , msg = stack.slice(0, index)\n      , actual = err.actual\n      , expected = err.expected\n      , escape = true;\n\n    // explicitly show diff\n    if (err.showDiff) {\n      escape = false;\n      err.actual = actual = JSON.stringify(actual, null, 2);\n      err.expected = expected = JSON.stringify(expected, null, 2);\n    }\n\n    // actual / expected diff\n    if ('string' == typeof actual && 'string' == typeof expected) {\n      var len = Math.max(actual.length, expected.length);\n\n      if (len < 20) msg = errorDiff(err, 'Chars', escape);\n      else msg = errorDiff(err, 'Words', escape);\n\n      // linenos\n      var lines = msg.split('\\n');\n      if (lines.length > 4) {\n        var width = String(lines.length).length;\n        msg = lines.map(function(str, i){\n          return pad(++i, width) + ' |' + ' ' + str;\n        }).join('\\n');\n      }\n\n      // legend\n      msg = '\\n'\n        + color('diff removed', 'actual')\n        + ' '\n        + color('diff added', 'expected')\n        + '\\n\\n'\n        + msg\n        + '\\n';\n\n      // indent\n      msg = msg.replace(/^/gm, '      ');\n\n      fmt = color('error title', '  %s) %s:\\n%s')\n        + color('error stack', '\\n%s\\n');\n    }\n\n    // indent stack trace without msg\n    stack = stack.slice(index ? index + 1 : index)\n      .replace(/^/gm, '  ');\n\n    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);\n  });\n};\n\n/**\n * Initialize a new `Base` reporter.\n *\n * All other reporters generally\n * inherit from this reporter, providing\n * stats such as test duration, number\n * of tests passed / failed etc.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Base(runner) {\n  var self = this\n    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }\n    , failures = this.failures = [];\n\n  if (!runner) return;\n  this.runner = runner;\n\n  runner.stats = stats;\n\n  runner.on('start', function(){\n    stats.start = new Date;\n  });\n\n  runner.on('suite', function(suite){\n    stats.suites = stats.suites || 0;\n    suite.root || stats.suites++;\n  });\n\n  runner.on('test end', function(test){\n    stats.tests = stats.tests || 0;\n    stats.tests++;\n  });\n\n  runner.on('pass', function(test){\n    stats.passes = stats.passes || 0;\n\n    var medium = test.slow() / 2;\n    test.speed = test.duration > test.slow()\n      ? 'slow'\n      : test.duration > medium\n        ? 'medium'\n        : 'fast';\n\n    stats.passes++;\n  });\n\n  runner.on('fail', function(test, err){\n    stats.failures = stats.failures || 0;\n    stats.failures++;\n    test.err = err;\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    stats.end = new Date;\n    stats.duration = new Date - stats.start;\n  });\n\n  runner.on('pending', function(){\n    stats.pending++;\n  });\n}\n\n/**\n * Output common epilogue used by many of\n * the bundled reporters.\n *\n * @api public\n */\n\nBase.prototype.epilogue = function(){\n  var stats = this.stats\n    , fmt\n    , tests;\n\n  console.log();\n\n  function pluralize(n) {\n    return 1 == n ? 'test' : 'tests';\n  }\n\n  // failure\n  if (stats.failures) {\n    fmt = color('bright fail', '  ' + exports.symbols.err)\n      + color('fail', ' %d of %d %s failed')\n      + color('light', ':')\n\n    console.error(fmt,\n      stats.failures,\n      this.runner.total,\n      pluralize(this.runner.total));\n\n    Base.list(this.failures);\n    console.error();\n    return;\n  }\n\n  // pass\n  fmt = color('bright pass', ' ')\n    + color('green', ' %d %s complete')\n    + color('light', ' (%s)');\n\n  console.log(fmt,\n    stats.tests || 0,\n    pluralize(stats.tests),\n    ms(stats.duration));\n\n  // pending\n  if (stats.pending) {\n    fmt = color('pending', ' ')\n      + color('pending', ' %d %s pending');\n\n    console.log(fmt, stats.pending, pluralize(stats.pending));\n  }\n\n  console.log();\n};\n\n/**\n * Pad the given `str` to `len`.\n *\n * @param {String} str\n * @param {String} len\n * @return {String}\n * @api private\n */\n\nfunction pad(str, len) {\n  str = String(str);\n  return Array(len - str.length + 1).join(' ') + str;\n}\n\n/**\n * Return a character diff for `err`.\n *\n * @param {Error} err\n * @return {String}\n * @api private\n */\n\nfunction errorDiff(err, type, escape) {\n  return diff['diff' + type](err.actual, err.expected).map(function(str){\n    if (escape) {\n      str.value = str.value\n        .replace(/\\t/g, '<tab>')\n        .replace(/\\r/g, '<CR>')\n        .replace(/\\n/g, '<LF>\\n');\n    }\n    if (str.added) return colorLines('diff added', str.value);\n    if (str.removed) return colorLines('diff removed', str.value);\n    return str.value;\n  }).join('');\n}\n\n/**\n * Color lines for `str`, using the color `name`.\n *\n * @param {String} name\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nfunction colorLines(name, str) {\n  return str.split('\\n').map(function(str){\n    return color(name, str);\n  }).join('\\n');\n}\n\n}); // module: reporters/base.js\n\nrequire.register(\"reporters/doc.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils');\n\n/**\n * Expose `Doc`.\n */\n\nexports = module.exports = Doc;\n\n/**\n * Initialize a new `Doc` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Doc(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , indents = 2;\n\n  function indent() {\n    return Array(indents).join('  ');\n  }\n\n  runner.on('suite', function(suite){\n    if (suite.root) return;\n    ++indents;\n    console.log('%s<section class=\"suite\">', indent());\n    ++indents;\n    console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));\n    console.log('%s<dl>', indent());\n  });\n\n  runner.on('suite end', function(suite){\n    if (suite.root) return;\n    console.log('%s</dl>', indent());\n    --indents;\n    console.log('%s</section>', indent());\n    --indents;\n  });\n\n  runner.on('pass', function(test){\n    console.log('%s  <dt>%s</dt>', indent(), utils.escape(test.title));\n    var code = utils.escape(utils.clean(test.fn.toString()));\n    console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);\n  });\n}\n\n}); // module: reporters/doc.js\n\nrequire.register(\"reporters/dot.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `Dot`.\n */\n\nexports = module.exports = Dot;\n\n/**\n * Initialize a new `Dot` matrix test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Dot(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , n = 0;\n\n  runner.on('start', function(){\n    process.stdout.write('\\n  ');\n  });\n\n  runner.on('pending', function(test){\n    process.stdout.write(color('pending', Base.symbols.dot));\n  });\n\n  runner.on('pass', function(test){\n    if (++n % width == 0) process.stdout.write('\\n  ');\n    if ('slow' == test.speed) {\n      process.stdout.write(color('bright yellow', Base.symbols.dot));\n    } else {\n      process.stdout.write(color(test.speed, Base.symbols.dot));\n    }\n  });\n\n  runner.on('fail', function(test, err){\n    if (++n % width == 0) process.stdout.write('\\n  ');\n    process.stdout.write(color('fail', Base.symbols.dot));\n  });\n\n  runner.on('end', function(){\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nDot.prototype = new F;\nDot.prototype.constructor = Dot;\n\n}); // module: reporters/dot.js\n\nrequire.register(\"reporters/html-cov.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar JSONCov = require('./json-cov')\n  , fs = require('browser/fs');\n\n/**\n * Expose `HTMLCov`.\n */\n\nexports = module.exports = HTMLCov;\n\n/**\n * Initialize a new `JsCoverage` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction HTMLCov(runner) {\n  var jade = require('jade')\n    , file = __dirname + '/templates/coverage.jade'\n    , str = fs.readFileSync(file, 'utf8')\n    , fn = jade.compile(str, { filename: file })\n    , self = this;\n\n  JSONCov.call(this, runner, false);\n\n  runner.on('end', function(){\n    process.stdout.write(fn({\n        cov: self.cov\n      , coverageClass: coverageClass\n    }));\n  });\n}\n\n/**\n * Return coverage class for `n`.\n *\n * @return {String}\n * @api private\n */\n\nfunction coverageClass(n) {\n  if (n >= 75) return 'high';\n  if (n >= 50) return 'medium';\n  if (n >= 25) return 'low';\n  return 'terrible';\n}\n}); // module: reporters/html-cov.js\n\nrequire.register(\"reporters/html.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils')\n  , Progress = require('../browser/progress')\n  , escape = utils.escape;\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `Doc`.\n */\n\nexports = module.exports = HTML;\n\n/**\n * Stats template.\n */\n\nvar statsTemplate = '<ul id=\"mocha-stats\">'\n  + '<li class=\"progress\"><canvas width=\"40\" height=\"40\"></canvas></li>'\n  + '<li class=\"passes\"><a href=\"#\">passes:</a> <em>0</em></li>'\n  + '<li class=\"failures\"><a href=\"#\">failures:</a> <em>0</em></li>'\n  + '<li class=\"duration\">duration: <em>0</em>s</li>'\n  + '</ul>';\n\n/**\n * Initialize a new `Doc` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction HTML(runner, root) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , stat = fragment(statsTemplate)\n    , items = stat.getElementsByTagName('li')\n    , passes = items[1].getElementsByTagName('em')[0]\n    , passesLink = items[1].getElementsByTagName('a')[0]\n    , failures = items[2].getElementsByTagName('em')[0]\n    , failuresLink = items[2].getElementsByTagName('a')[0]\n    , duration = items[3].getElementsByTagName('em')[0]\n    , canvas = stat.getElementsByTagName('canvas')[0]\n    , report = fragment('<ul id=\"mocha-report\"></ul>')\n    , stack = [report]\n    , progress\n    , ctx\n\n  root = root || document.getElementById('mocha');\n\n  if (canvas.getContext) {\n    var ratio = window.devicePixelRatio || 1;\n    canvas.style.width = canvas.width;\n    canvas.style.height = canvas.height;\n    canvas.width *= ratio;\n    canvas.height *= ratio;\n    ctx = canvas.getContext('2d');\n    ctx.scale(ratio, ratio);\n    progress = new Progress;\n  }\n\n  if (!root) return error('#mocha div missing, add it to your document');\n\n  // pass toggle\n  on(passesLink, 'click', function(){\n    unhide();\n    var name = /pass/.test(report.className) ? '' : ' pass';\n    report.className = report.className.replace(/fail|pass/g, '') + name;\n    if (report.className.trim()) hideSuitesWithout('test pass');\n  });\n\n  // failure toggle\n  on(failuresLink, 'click', function(){\n    unhide();\n    var name = /fail/.test(report.className) ? '' : ' fail';\n    report.className = report.className.replace(/fail|pass/g, '') + name;\n    if (report.className.trim()) hideSuitesWithout('test fail');\n  });\n\n  root.appendChild(stat);\n  root.appendChild(report);\n\n  if (progress) progress.size(40);\n\n  runner.on('suite', function(suite){\n    if (suite.root) return;\n\n    // suite\n    var url = '?grep=' + encodeURIComponent(suite.fullTitle());\n    var el = fragment('<li class=\"suite\"><h1><a href=\"%s\">%s</a></h1></li>', url, escape(suite.title));\n\n    // container\n    stack[0].appendChild(el);\n    stack.unshift(document.createElement('ul'));\n    el.appendChild(stack[0]);\n  });\n\n  runner.on('suite end', function(suite){\n    if (suite.root) return;\n    stack.shift();\n  });\n\n  runner.on('fail', function(test, err){\n    if ('hook' == test.type) runner.emit('test end', test);\n  });\n\n  runner.on('test end', function(test){\n    window.scrollTo(0, document.body.scrollHeight);\n\n    // TODO: add to stats\n    var percent = stats.tests / this.total * 100 | 0;\n    if (progress) progress.update(percent).draw(ctx);\n\n    // update stats\n    var ms = new Date - stats.start;\n    text(passes, stats.passes);\n    text(failures, stats.failures);\n    text(duration, (ms / 1000).toFixed(2));\n\n    // test\n    if ('passed' == test.state) {\n      var el = fragment('<li class=\"test pass %e\"><h2>%e<span class=\"duration\">%ems</span> <a href=\"?grep=%e\" class=\"replay\">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));\n    } else if (test.pending) {\n      var el = fragment('<li class=\"test pass pending\"><h2>%e</h2></li>', test.title);\n    } else {\n      var el = fragment('<li class=\"test fail\"><h2>%e <a href=\"?grep=%e\" class=\"replay\">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));\n      var str = test.err.stack || test.err.toString();\n\n      // FF / Opera do not add the message\n      if (!~str.indexOf(test.err.message)) {\n        str = test.err.message + '\\n' + str;\n      }\n\n      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we\n      // check for the result of the stringifying.\n      if ('[object Error]' == str) str = test.err.message;\n\n      // Safari doesn't give you a stack. Let's at least provide a source line.\n      if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {\n        str += \"\\n(\" + test.err.sourceURL + \":\" + test.err.line + \")\";\n      }\n\n      el.appendChild(fragment('<pre class=\"error\">%e</pre>', str));\n    }\n\n    // toggle code\n    // TODO: defer\n    if (!test.pending) {\n      var h2 = el.getElementsByTagName('h2')[0];\n\n      on(h2, 'click', function(){\n        pre.style.display = 'none' == pre.style.display\n          ? 'block'\n          : 'none';\n      });\n\n      var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));\n      el.appendChild(pre);\n      pre.style.display = 'none';\n    }\n\n    // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.\n    if (stack[0]) stack[0].appendChild(el);\n  });\n}\n\n/**\n * Display error `msg`.\n */\n\nfunction error(msg) {\n  document.body.appendChild(fragment('<div id=\"mocha-error\">%s</div>', msg));\n}\n\n/**\n * Return a DOM fragment from `html`.\n */\n\nfunction fragment(html) {\n  var args = arguments\n    , div = document.createElement('div')\n    , i = 1;\n\n  div.innerHTML = html.replace(/%([se])/g, function(_, type){\n    switch (type) {\n      case 's': return String(args[i++]);\n      case 'e': return escape(args[i++]);\n    }\n  });\n\n  return div.firstChild;\n}\n\n/**\n * Check for suites that do not have elements\n * with `classname`, and hide them.\n */\n\nfunction hideSuitesWithout(classname) {\n  var suites = document.getElementsByClassName('suite');\n  for (var i = 0; i < suites.length; i++) {\n    var els = suites[i].getElementsByClassName(classname);\n    if (0 == els.length) suites[i].className += ' hidden';\n  }\n}\n\n/**\n * Unhide .hidden suites.\n */\n\nfunction unhide() {\n  var els = document.getElementsByClassName('suite hidden');\n  for (var i = 0; i < els.length; ++i) {\n    els[i].className = els[i].className.replace('suite hidden', 'suite');\n  }\n}\n\n/**\n * Set `el` text to `str`.\n */\n\nfunction text(el, str) {\n  if (el.textContent) {\n    el.textContent = str;\n  } else {\n    el.innerText = str;\n  }\n}\n\n/**\n * Listen on `event` with callback `fn`.\n */\n\nfunction on(el, event, fn) {\n  if (el.addEventListener) {\n    el.addEventListener(event, fn, false);\n  } else {\n    el.attachEvent('on' + event, fn);\n  }\n}\n\n}); // module: reporters/html.js\n\nrequire.register(\"reporters/index.js\", function(module, exports, require){\n\nexports.Base = require('./base');\nexports.Dot = require('./dot');\nexports.Doc = require('./doc');\nexports.TAP = require('./tap');\nexports.JSON = require('./json');\nexports.HTML = require('./html');\nexports.List = require('./list');\nexports.Min = require('./min');\nexports.Spec = require('./spec');\nexports.Nyan = require('./nyan');\nexports.XUnit = require('./xunit');\nexports.Markdown = require('./markdown');\nexports.Progress = require('./progress');\nexports.Landing = require('./landing');\nexports.JSONCov = require('./json-cov');\nexports.HTMLCov = require('./html-cov');\nexports.JSONStream = require('./json-stream');\nexports.Teamcity = require('./teamcity');\n\n}); // module: reporters/index.js\n\nrequire.register(\"reporters/json-cov.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `JSONCov`.\n */\n\nexports = module.exports = JSONCov;\n\n/**\n * Initialize a new `JsCoverage` reporter.\n *\n * @param {Runner} runner\n * @param {Boolean} output\n * @api public\n */\n\nfunction JSONCov(runner, output) {\n  var self = this\n    , output = 1 == arguments.length ? true : output;\n\n  Base.call(this, runner);\n\n  var tests = []\n    , failures = []\n    , passes = [];\n\n  runner.on('test end', function(test){\n    tests.push(test);\n  });\n\n  runner.on('pass', function(test){\n    passes.push(test);\n  });\n\n  runner.on('fail', function(test){\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    var cov = global._$jscoverage || {};\n    var result = self.cov = map(cov);\n    result.stats = self.stats;\n    result.tests = tests.map(clean);\n    result.failures = failures.map(clean);\n    result.passes = passes.map(clean);\n    if (!output) return;\n    process.stdout.write(JSON.stringify(result, null, 2 ));\n  });\n}\n\n/**\n * Map jscoverage data to a JSON structure\n * suitable for reporting.\n *\n * @param {Object} cov\n * @return {Object}\n * @api private\n */\n\nfunction map(cov) {\n  var ret = {\n      instrumentation: 'node-jscoverage'\n    , sloc: 0\n    , hits: 0\n    , misses: 0\n    , coverage: 0\n    , files: []\n  };\n\n  for (var filename in cov) {\n    var data = coverage(filename, cov[filename]);\n    ret.files.push(data);\n    ret.hits += data.hits;\n    ret.misses += data.misses;\n    ret.sloc += data.sloc;\n  }\n\n  ret.files.sort(function(a, b) {\n    return a.filename.localeCompare(b.filename);\n  });\n\n  if (ret.sloc > 0) {\n    ret.coverage = (ret.hits / ret.sloc) * 100;\n  }\n\n  return ret;\n};\n\n/**\n * Map jscoverage data for a single source file\n * to a JSON structure suitable for reporting.\n *\n * @param {String} filename name of the source file\n * @param {Object} data jscoverage coverage data\n * @return {Object}\n * @api private\n */\n\nfunction coverage(filename, data) {\n  var ret = {\n    filename: filename,\n    coverage: 0,\n    hits: 0,\n    misses: 0,\n    sloc: 0,\n    source: {}\n  };\n\n  data.source.forEach(function(line, num){\n    num++;\n\n    if (data[num] === 0) {\n      ret.misses++;\n      ret.sloc++;\n    } else if (data[num] !== undefined) {\n      ret.hits++;\n      ret.sloc++;\n    }\n\n    ret.source[num] = {\n        source: line\n      , coverage: data[num] === undefined\n        ? ''\n        : data[num]\n    };\n  });\n\n  ret.coverage = ret.hits / ret.sloc * 100;\n\n  return ret;\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n\n}); // module: reporters/json-cov.js\n\nrequire.register(\"reporters/json-stream.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `List`.\n */\n\nexports = module.exports = List;\n\n/**\n * Initialize a new `List` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction List(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total;\n\n  runner.on('start', function(){\n    console.log(JSON.stringify(['start', { total: total }]));\n  });\n\n  runner.on('pass', function(test){\n    console.log(JSON.stringify(['pass', clean(test)]));\n  });\n\n  runner.on('fail', function(test, err){\n    console.log(JSON.stringify(['fail', clean(test)]));\n  });\n\n  runner.on('end', function(){\n    process.stdout.write(JSON.stringify(['end', self.stats]));\n  });\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n}); // module: reporters/json-stream.js\n\nrequire.register(\"reporters/json.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `JSON`.\n */\n\nexports = module.exports = JSONReporter;\n\n/**\n * Initialize a new `JSON` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction JSONReporter(runner) {\n  var self = this;\n  Base.call(this, runner);\n\n  var tests = []\n    , failures = []\n    , passes = [];\n\n  runner.on('test end', function(test){\n    tests.push(test);\n  });\n\n  runner.on('pass', function(test){\n    passes.push(test);\n  });\n\n  runner.on('fail', function(test){\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    var obj = {\n        stats: self.stats\n      , tests: tests.map(clean)\n      , failures: failures.map(clean)\n      , passes: passes.map(clean)\n    };\n\n    process.stdout.write(JSON.stringify(obj, null, 2));\n  });\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n}); // module: reporters/json.js\n\nrequire.register(\"reporters/landing.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Landing`.\n */\n\nexports = module.exports = Landing;\n\n/**\n * Airplane color.\n */\n\nBase.colors.plane = 0;\n\n/**\n * Airplane crash color.\n */\n\nBase.colors['plane crash'] = 31;\n\n/**\n * Runway color.\n */\n\nBase.colors.runway = 90;\n\n/**\n * Initialize a new `Landing` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Landing(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , total = runner.total\n    , stream = process.stdout\n    , plane = color('plane', '✈')\n    , crashed = -1\n    , n = 0;\n\n  function runway() {\n    var buf = Array(width).join('-');\n    return '  ' + color('runway', buf);\n  }\n\n  runner.on('start', function(){\n    stream.write('\\n  ');\n    cursor.hide();\n  });\n\n  runner.on('test end', function(test){\n    // check if the plane crashed\n    var col = -1 == crashed\n      ? width * ++n / total | 0\n      : crashed;\n\n    // show the crash\n    if ('failed' == test.state) {\n      plane = color('plane crash', '✈');\n      crashed = col;\n    }\n\n    // render landing strip\n    stream.write('\\u001b[4F\\n\\n');\n    stream.write(runway());\n    stream.write('\\n  ');\n    stream.write(color('runway', Array(col).join('⋅')));\n    stream.write(plane)\n    stream.write(color('runway', Array(width - col).join('⋅') + '\\n'));\n    stream.write(runway());\n    stream.write('\\u001b[0m');\n  });\n\n  runner.on('end', function(){\n    cursor.show();\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nLanding.prototype = new F;\nLanding.prototype.constructor = Landing;\n\n}); // module: reporters/landing.js\n\nrequire.register(\"reporters/list.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `List`.\n */\n\nexports = module.exports = List;\n\n/**\n * Initialize a new `List` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction List(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , n = 0;\n\n  runner.on('start', function(){\n    console.log();\n  });\n\n  runner.on('test', function(test){\n    process.stdout.write(color('pass', '    ' + test.fullTitle() + ': '));\n  });\n\n  runner.on('pending', function(test){\n    var fmt = color('checkmark', '  -')\n      + color('pending', ' %s');\n    console.log(fmt, test.fullTitle());\n  });\n\n  runner.on('pass', function(test){\n    var fmt = color('checkmark', '  '+Base.symbols.dot)\n      + color('pass', ' %s: ')\n      + color(test.speed, '%dms');\n    cursor.CR();\n    console.log(fmt, test.fullTitle(), test.duration);\n  });\n\n  runner.on('fail', function(test, err){\n    cursor.CR();\n    console.log(color('fail', '  %d) %s'), ++n, test.fullTitle());\n  });\n\n  runner.on('end', self.epilogue.bind(self));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nList.prototype = new F;\nList.prototype.constructor = List;\n\n\n}); // module: reporters/list.js\n\nrequire.register(\"reporters/markdown.js\", function(module, exports, require){\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils');\n\n/**\n * Expose `Markdown`.\n */\n\nexports = module.exports = Markdown;\n\n/**\n * Initialize a new `Markdown` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Markdown(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , level = 0\n    , buf = '';\n\n  function title(str) {\n    return Array(level).join('#') + ' ' + str;\n  }\n\n  function indent() {\n    return Array(level).join('  ');\n  }\n\n  function mapTOC(suite, obj) {\n    var ret = obj;\n    obj = obj[suite.title] = obj[suite.title] || { suite: suite };\n    suite.suites.forEach(function(suite){\n      mapTOC(suite, obj);\n    });\n    return ret;\n  }\n\n  function stringifyTOC(obj, level) {\n    ++level;\n    var buf = '';\n    var link;\n    for (var key in obj) {\n      if ('suite' == key) continue;\n      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\\n';\n      if (key) buf += Array(level).join('  ') + link;\n      buf += stringifyTOC(obj[key], level);\n    }\n    --level;\n    return buf;\n  }\n\n  function generateTOC(suite) {\n    var obj = mapTOC(suite, {});\n    return stringifyTOC(obj, 0);\n  }\n\n  generateTOC(runner.suite);\n\n  runner.on('suite', function(suite){\n    ++level;\n    var slug = utils.slug(suite.fullTitle());\n    buf += '<a name=\"' + slug + '\"></a>' + '\\n';\n    buf += title(suite.title) + '\\n';\n  });\n\n  runner.on('suite end', function(suite){\n    --level;\n  });\n\n  runner.on('pass', function(test){\n    var code = utils.clean(test.fn.toString());\n    buf += test.title + '.\\n';\n    buf += '\\n```js\\n';\n    buf += code + '\\n';\n    buf += '```\\n\\n';\n  });\n\n  runner.on('end', function(){\n    process.stdout.write('# TOC\\n');\n    process.stdout.write(generateTOC(runner.suite));\n    process.stdout.write(buf);\n  });\n}\n}); // module: reporters/markdown.js\n\nrequire.register(\"reporters/min.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `Min`.\n */\n\nexports = module.exports = Min;\n\n/**\n * Initialize a new `Min` minimal test reporter (best used with --watch).\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Min(runner) {\n  Base.call(this, runner);\n  \n  runner.on('start', function(){\n    // clear screen\n    process.stdout.write('\\u001b[2J');\n    // set cursor position\n    process.stdout.write('\\u001b[1;3H');\n  });\n\n  runner.on('end', this.epilogue.bind(this));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nMin.prototype = new F;\nMin.prototype.constructor = Min;\n\n}); // module: reporters/min.js\n\nrequire.register(\"reporters/nyan.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `Dot`.\n */\n\nexports = module.exports = NyanCat;\n\n/**\n * Initialize a new `Dot` matrix test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction NyanCat(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , rainbowColors = this.rainbowColors = self.generateColors()\n    , colorIndex = this.colorIndex = 0\n    , numerOfLines = this.numberOfLines = 4\n    , trajectories = this.trajectories = [[], [], [], []]\n    , nyanCatWidth = this.nyanCatWidth = 11\n    , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)\n    , scoreboardWidth = this.scoreboardWidth = 5\n    , tick = this.tick = 0\n    , n = 0;\n\n  runner.on('start', function(){\n    Base.cursor.hide();\n    self.draw('start');\n  });\n\n  runner.on('pending', function(test){\n    self.draw('pending');\n  });\n\n  runner.on('pass', function(test){\n    self.draw('pass');\n  });\n\n  runner.on('fail', function(test, err){\n    self.draw('fail');\n  });\n\n  runner.on('end', function(){\n    Base.cursor.show();\n    for (var i = 0; i < self.numberOfLines; i++) write('\\n');\n    self.epilogue();\n  });\n}\n\n/**\n * Draw the nyan cat with runner `status`.\n *\n * @param {String} status\n * @api private\n */\n\nNyanCat.prototype.draw = function(status){\n  this.appendRainbow();\n  this.drawScoreboard();\n  this.drawRainbow();\n  this.drawNyanCat(status);\n  this.tick = !this.tick;\n};\n\n/**\n * Draw the \"scoreboard\" showing the number\n * of passes, failures and pending tests.\n *\n * @api private\n */\n\nNyanCat.prototype.drawScoreboard = function(){\n  var stats = this.stats;\n  var colors = Base.colors;\n\n  function draw(color, n) {\n    write(' ');\n    write('\\u001b[' + color + 'm' + n + '\\u001b[0m');\n    write('\\n');\n  }\n\n  draw(colors.green, stats.passes);\n  draw(colors.fail, stats.failures);\n  draw(colors.pending, stats.pending);\n  write('\\n');\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Append the rainbow.\n *\n * @api private\n */\n\nNyanCat.prototype.appendRainbow = function(){\n  var segment = this.tick ? '_' : '-';\n  var rainbowified = this.rainbowify(segment);\n\n  for (var index = 0; index < this.numberOfLines; index++) {\n    var trajectory = this.trajectories[index];\n    if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();\n    trajectory.push(rainbowified);\n  }\n};\n\n/**\n * Draw the rainbow.\n *\n * @api private\n */\n\nNyanCat.prototype.drawRainbow = function(){\n  var self = this;\n\n  this.trajectories.forEach(function(line, index) {\n    write('\\u001b[' + self.scoreboardWidth + 'C');\n    write(line.join(''));\n    write('\\n');\n  });\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Draw the nyan cat with `status`.\n *\n * @param {String} status\n * @api private\n */\n\nNyanCat.prototype.drawNyanCat = function(status) {\n  var self = this;\n  var startWidth = this.scoreboardWidth + this.trajectories[0].length;\n\n  [0, 1, 2, 3].forEach(function(index) {\n    write('\\u001b[' + startWidth + 'C');\n\n    switch (index) {\n      case 0:\n        write('_,------,');\n        write('\\n');\n        break;\n      case 1:\n        var padding = self.tick ? '  ' : '   ';\n        write('_|' + padding + '/\\\\_/\\\\ ');\n        write('\\n');\n        break;\n      case 2:\n        var padding = self.tick ? '_' : '__';\n        var tail = self.tick ? '~' : '^';\n        var face;\n        switch (status) {\n          case 'pass':\n            face = '( ^ .^)';\n            break;\n          case 'fail':\n            face = '( o .o)';\n            break;\n          default:\n            face = '( - .-)';\n        }\n        write(tail + '|' + padding + face + ' ');\n        write('\\n');\n        break;\n      case 3:\n        var padding = self.tick ? ' ' : '  ';\n        write(padding + '\"\"  \"\" ');\n        write('\\n');\n        break;\n    }\n  });\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Move cursor up `n`.\n *\n * @param {Number} n\n * @api private\n */\n\nNyanCat.prototype.cursorUp = function(n) {\n  write('\\u001b[' + n + 'A');\n};\n\n/**\n * Move cursor down `n`.\n *\n * @param {Number} n\n * @api private\n */\n\nNyanCat.prototype.cursorDown = function(n) {\n  write('\\u001b[' + n + 'B');\n};\n\n/**\n * Generate rainbow colors.\n *\n * @return {Array}\n * @api private\n */\n\nNyanCat.prototype.generateColors = function(){\n  var colors = [];\n\n  for (var i = 0; i < (6 * 7); i++) {\n    var pi3 = Math.floor(Math.PI / 3);\n    var n = (i * (1.0 / 6));\n    var r = Math.floor(3 * Math.sin(n) + 3);\n    var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);\n    var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);\n    colors.push(36 * r + 6 * g + b + 16);\n  }\n\n  return colors;\n};\n\n/**\n * Apply rainbow to the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nNyanCat.prototype.rainbowify = function(str){\n  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];\n  this.colorIndex += 1;\n  return '\\u001b[38;5;' + color + 'm' + str + '\\u001b[0m';\n};\n\n/**\n * Stdout helper.\n */\n\nfunction write(string) {\n  process.stdout.write(string);\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nNyanCat.prototype = new F;\nNyanCat.prototype.constructor = NyanCat;\n\n\n}); // module: reporters/nyan.js\n\nrequire.register(\"reporters/progress.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Progress`.\n */\n\nexports = module.exports = Progress;\n\n/**\n * General progress bar color.\n */\n\nBase.colors.progress = 90;\n\n/**\n * Initialize a new `Progress` bar test reporter.\n *\n * @param {Runner} runner\n * @param {Object} options\n * @api public\n */\n\nfunction Progress(runner, options) {\n  Base.call(this, runner);\n\n  var self = this\n    , options = options || {}\n    , stats = this.stats\n    , width = Base.window.width * .50 | 0\n    , total = runner.total\n    , complete = 0\n    , max = Math.max;\n\n  // default chars\n  options.open = options.open || '[';\n  options.complete = options.complete || '▬';\n  options.incomplete = options.incomplete || Base.symbols.dot;\n  options.close = options.close || ']';\n  options.verbose = false;\n\n  // tests started\n  runner.on('start', function(){\n    console.log();\n    cursor.hide();\n  });\n\n  // tests complete\n  runner.on('test end', function(){\n    complete++;\n    var incomplete = total - complete\n      , percent = complete / total\n      , n = width * percent | 0\n      , i = width - n;\n\n    cursor.CR();\n    process.stdout.write('\\u001b[J');\n    process.stdout.write(color('progress', '  ' + options.open));\n    process.stdout.write(Array(n).join(options.complete));\n    process.stdout.write(Array(i).join(options.incomplete));\n    process.stdout.write(color('progress', options.close));\n    if (options.verbose) {\n      process.stdout.write(color('progress', ' ' + complete + ' of ' + total));\n    }\n  });\n\n  // tests are complete, output some stats\n  // and the failures if any\n  runner.on('end', function(){\n    cursor.show();\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nProgress.prototype = new F;\nProgress.prototype.constructor = Progress;\n\n\n}); // module: reporters/progress.js\n\nrequire.register(\"reporters/spec.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Spec`.\n */\n\nexports = module.exports = Spec;\n\n/**\n * Initialize a new `Spec` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Spec(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , indents = 0\n    , n = 0;\n\n  function indent() {\n    return Array(indents).join('  ')\n  }\n\n  runner.on('start', function(){\n    console.log();\n  });\n\n  runner.on('suite', function(suite){\n    ++indents;\n    console.log(color('suite', '%s%s'), indent(), suite.title);\n  });\n\n  runner.on('suite end', function(suite){\n    --indents;\n    if (1 == indents) console.log();\n  });\n\n  runner.on('test', function(test){\n    process.stdout.write(indent() + color('pass', '  ◦ ' + test.title + ': '));\n  });\n\n  runner.on('pending', function(test){\n    var fmt = indent() + color('pending', '  - %s');\n    console.log(fmt, test.title);\n  });\n\n  runner.on('pass', function(test){\n    if ('fast' == test.speed) {\n      var fmt = indent()\n        + color('checkmark', '  ' + Base.symbols.ok)\n        + color('pass', ' %s ');\n      cursor.CR();\n      console.log(fmt, test.title);\n    } else {\n      var fmt = indent()\n        + color('checkmark', '  ' + Base.symbols.ok)\n        + color('pass', ' %s ')\n        + color(test.speed, '(%dms)');\n      cursor.CR();\n      console.log(fmt, test.title, test.duration);\n    }\n  });\n\n  runner.on('fail', function(test, err){\n    cursor.CR();\n    console.log(indent() + color('fail', '  %d) %s'), ++n, test.title);\n  });\n\n  runner.on('end', self.epilogue.bind(self));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nSpec.prototype = new F;\nSpec.prototype.constructor = Spec;\n\n\n}); // module: reporters/spec.js\n\nrequire.register(\"reporters/tap.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `TAP`.\n */\n\nexports = module.exports = TAP;\n\n/**\n * Initialize a new `TAP` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction TAP(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , n = 1\n    , passes = 0\n    , failures = 0;\n\n  runner.on('start', function(){\n    var total = runner.grepTotal(runner.suite);\n    console.log('%d..%d', 1, total);\n  });\n\n  runner.on('test end', function(){\n    ++n;\n  });\n\n  runner.on('pending', function(test){\n    console.log('ok %d %s # SKIP -', n, title(test));\n  });\n\n  runner.on('pass', function(test){\n    passes++;\n    console.log('ok %d %s', n, title(test));\n  });\n\n  runner.on('fail', function(test, err){\n    failures++;\n    console.log('not ok %d %s', n, title(test));\n    if (err.stack) console.log(err.stack.replace(/^/gm, '  '));\n  });\n\n  runner.on('end', function(){\n    console.log('# tests ' + (passes + failures));\n    console.log('# pass ' + passes);\n    console.log('# fail ' + failures);\n  });\n}\n\n/**\n * Return a TAP-safe title of `test`\n *\n * @param {Object} test\n * @return {String}\n * @api private\n */\n\nfunction title(test) {\n  return test.fullTitle().replace(/#/g, '');\n}\n\n}); // module: reporters/tap.js\n\nrequire.register(\"reporters/teamcity.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `Teamcity`.\n */\n\nexports = module.exports = Teamcity;\n\n/**\n * Initialize a new `Teamcity` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Teamcity(runner) {\n  Base.call(this, runner);\n  var stats = this.stats;\n\n  runner.on('start', function() {\n    console.log(\"##teamcity[testSuiteStarted name='mocha.suite']\");\n  });\n\n  runner.on('test', function(test) {\n    console.log(\"##teamcity[testStarted name='\" + escape(test.fullTitle()) + \"']\");\n  });\n\n  runner.on('fail', function(test, err) {\n    console.log(\"##teamcity[testFailed name='\" + escape(test.fullTitle()) + \"' message='\" + escape(err.message) + \"']\");\n  });\n\n  runner.on('pending', function(test) {\n    console.log(\"##teamcity[testIgnored name='\" + escape(test.fullTitle()) + \"' message='pending']\");\n  });\n\n  runner.on('test end', function(test) {\n    console.log(\"##teamcity[testFinished name='\" + escape(test.fullTitle()) + \"' duration='\" + test.duration + \"']\");\n  });\n\n  runner.on('end', function() {\n    console.log(\"##teamcity[testSuiteFinished name='mocha.suite' duration='\" + stats.duration + \"']\");\n  });\n}\n\n/**\n * Escape the given `str`.\n */\n\nfunction escape(str) {\n  return str\n    .replace(/\\|/g, \"||\")\n    .replace(/\\n/g, \"|n\")\n    .replace(/\\r/g, \"|r\")\n    .replace(/\\[/g, \"|[\")\n    .replace(/\\]/g, \"|]\")\n    .replace(/\\u0085/g, \"|x\")\n    .replace(/\\u2028/g, \"|l\")\n    .replace(/\\u2029/g, \"|p\")\n    .replace(/'/g, \"|'\");\n}\n\n}); // module: reporters/teamcity.js\n\nrequire.register(\"reporters/xunit.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils')\n  , escape = utils.escape;\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `XUnit`.\n */\n\nexports = module.exports = XUnit;\n\n/**\n * Initialize a new `XUnit` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction XUnit(runner) {\n  Base.call(this, runner);\n  var stats = this.stats\n    , tests = []\n    , self = this;\n\n  runner.on('pass', function(test){\n    tests.push(test);\n  });\n  \n  runner.on('fail', function(test){\n    tests.push(test);\n  });\n\n  runner.on('end', function(){\n    console.log(tag('testsuite', {\n        name: 'Mocha Tests'\n      , tests: stats.tests\n      , failures: stats.failures\n      , errors: stats.failures\n      , skip: stats.tests - stats.failures - stats.passes\n      , timestamp: (new Date).toUTCString()\n      , time: stats.duration / 1000\n    }, false));\n\n    tests.forEach(test);\n    console.log('</testsuite>');    \n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nXUnit.prototype = new F;\nXUnit.prototype.constructor = XUnit;\n\n\n/**\n * Output tag for the given `test.`\n */\n\nfunction test(test) {\n  var attrs = {\n      classname: test.parent.fullTitle()\n    , name: test.title\n    , time: test.duration / 1000\n  };\n\n  if ('failed' == test.state) {\n    var err = test.err;\n    attrs.message = escape(err.message);\n    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));\n  } else if (test.pending) {\n    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));\n  } else {\n    console.log(tag('testcase', attrs, true) );\n  }\n}\n\n/**\n * HTML tag helper.\n */\n\nfunction tag(name, attrs, close, content) {\n  var end = close ? '/>' : '>'\n    , pairs = []\n    , tag;\n\n  for (var key in attrs) {\n    pairs.push(key + '=\"' + escape(attrs[key]) + '\"');\n  }\n\n  tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;\n  if (content) tag += content + '</' + name + end;\n  return tag;\n}\n\n/**\n * Return cdata escaped CDATA `str`.\n */\n\nfunction cdata(str) {\n  return '<![CDATA[' + escape(str) + ']]>';\n}\n\n}); // module: reporters/xunit.js\n\nrequire.register(\"runnable.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:runnable')\n  , milliseconds = require('./ms');\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Object#toString().\n */\n\nvar toString = Object.prototype.toString;\n\n/**\n * Expose `Runnable`.\n */\n\nmodule.exports = Runnable;\n\n/**\n * Initialize a new `Runnable` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Runnable(title, fn) {\n  this.title = title;\n  this.fn = fn;\n  this.async = fn && fn.length;\n  this.sync = ! this.async;\n  this._timeout = 2000;\n  this._slow = 75;\n  this.timedOut = false;\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nfunction F(){};\nF.prototype = EventEmitter.prototype;\nRunnable.prototype = new F;\nRunnable.prototype.constructor = Runnable;\n\n\n/**\n * Set & get timeout `ms`.\n *\n * @param {Number|String} ms\n * @return {Runnable|Number} ms or self\n * @api private\n */\n\nRunnable.prototype.timeout = function(ms){\n  if (0 == arguments.length) return this._timeout;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._timeout = ms;\n  if (this.timer) this.resetTimeout();\n  return this;\n};\n\n/**\n * Set & get slow `ms`.\n *\n * @param {Number|String} ms\n * @return {Runnable|Number} ms or self\n * @api private\n */\n\nRunnable.prototype.slow = function(ms){\n  if (0 === arguments.length) return this._slow;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._slow = ms;\n  return this;\n};\n\n/**\n * Return the full title generated by recursively\n * concatenating the parent's full title.\n *\n * @return {String}\n * @api public\n */\n\nRunnable.prototype.fullTitle = function(){\n  return this.parent.fullTitle() + ' ' + this.title;\n};\n\n/**\n * Clear the timeout.\n *\n * @api private\n */\n\nRunnable.prototype.clearTimeout = function(){\n  clearTimeout(this.timer);\n};\n\n/**\n * Inspect the runnable void of private properties.\n *\n * @return {String}\n * @api private\n */\n\nRunnable.prototype.inspect = function(){\n  return JSON.stringify(this, function(key, val){\n    if ('_' == key[0]) return;\n    if ('parent' == key) return '#<Suite>';\n    if ('ctx' == key) return '#<Context>';\n    return val;\n  }, 2);\n};\n\n/**\n * Reset the timeout.\n *\n * @api private\n */\n\nRunnable.prototype.resetTimeout = function(){\n  var self = this\n    , ms = this.timeout();\n\n  this.clearTimeout();\n  if (ms) {\n    this.timer = setTimeout(function(){\n      self.callback(new Error('timeout of ' + ms + 'ms exceeded'));\n      self.timedOut = true;\n    }, ms);\n  }\n};\n\n/**\n * Run the test and invoke `fn(err)`.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunnable.prototype.run = function(fn){\n  var self = this\n    , ms = this.timeout()\n    , start = new Date\n    , ctx = this.ctx\n    , finished\n    , emitted;\n\n  if (ctx) ctx.runnable(this);\n\n  // timeout\n  if (this.async) {\n    if (ms) {\n      this.timer = setTimeout(function(){\n        done(new Error('timeout of ' + ms + 'ms exceeded'));\n        self.timedOut = true;\n      }, ms);\n    }\n  }\n\n  // called multiple times\n  function multiple(err) {\n    if (emitted) return;\n    emitted = true;\n    self.emit('error', err || new Error('done() called multiple times'));\n  }\n\n  // finished\n  function done(err) {\n    if (self.timedOut) return;\n    if (finished) return multiple(err);\n    self.clearTimeout();\n    self.duration = new Date - start;\n    finished = true;\n    fn(err);\n  }\n\n  // for .resetTimeout()\n  this.callback = done;\n\n  // async\n  if (this.async) {\n    try {\n      this.fn.call(ctx, function(err){\n        if (err instanceof Error || toString.call(err) === \"[object Error]\") return done(err);\n        if (null != err) return done(new Error('done() invoked with non-Error: ' + err));\n        done();\n      });\n    } catch (err) {\n      done(err);\n    }\n    return;\n  }\n\n  if (this.asyncOnly) {\n    return done(new Error('--async-only option in use without declaring `done()`'));\n  }\n\n  // sync\n  try {\n    if (!this.pending) this.fn.call(ctx);\n    this.duration = new Date - start;\n    fn();\n  } catch (err) {\n    fn(err);\n  }\n};\n\n}); // module: runnable.js\n\nrequire.register(\"runner.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:runner')\n  , Test = require('./test')\n  , utils = require('./utils')\n  , filter = utils.filter\n  , keys = utils.keys\n  , noop = function(){};\n\n/**\n * Non-enumerable globals.\n */\n\nvar globals = [\n  'setTimeout',\n  'clearTimeout',\n  'setInterval',\n  'clearInterval',\n  'XMLHttpRequest',\n  'Date'\n];\n\n/**\n * Expose `Runner`.\n */\n\nmodule.exports = Runner;\n\n/**\n * Initialize a `Runner` for the given `suite`.\n *\n * Events:\n *\n *   - `start`  execution started\n *   - `end`  execution complete\n *   - `suite`  (suite) test suite execution started\n *   - `suite end`  (suite) all tests (and sub-suites) have finished\n *   - `test`  (test) test execution started\n *   - `test end`  (test) test completed\n *   - `hook`  (hook) hook execution started\n *   - `hook end`  (hook) hook complete\n *   - `pass`  (test) test passed\n *   - `fail`  (test, err) test failed\n *\n * @api public\n */\n\nfunction Runner(suite) {\n  var self = this;\n  this._globals = [];\n  this.suite = suite;\n  this.total = suite.total();\n  this.failures = 0;\n  this.on('test end', function(test){ self.checkGlobals(test); });\n  this.on('hook end', function(hook){ self.checkGlobals(hook); });\n  this.grep(/.*/);\n  this.globals(this.globalProps().concat(['errno']));\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nfunction F(){};\nF.prototype = EventEmitter.prototype;\nRunner.prototype = new F;\nRunner.prototype.constructor = Runner;\n\n\n/**\n * Run tests with full titles matching `re`. Updates runner.total\n * with number of tests matched.\n *\n * @param {RegExp} re\n * @param {Boolean} invert\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.grep = function(re, invert){\n  debug('grep %s', re);\n  this._grep = re;\n  this._invert = invert;\n  this.total = this.grepTotal(this.suite);\n  return this;\n};\n\n/**\n * Returns the number of tests matching the grep search for the\n * given suite.\n *\n * @param {Suite} suite\n * @return {Number}\n * @api public\n */\n\nRunner.prototype.grepTotal = function(suite) {\n  var self = this;\n  var total = 0;\n\n  suite.eachTest(function(test){\n    var match = self._grep.test(test.fullTitle());\n    if (self._invert) match = !match;\n    if (match) total++;\n  });\n\n  return total;\n};\n\n/**\n * Return a list of global properties.\n *\n * @return {Array}\n * @api private\n */\n\nRunner.prototype.globalProps = function() {\n  var props = utils.keys(global);\n\n  // non-enumerables\n  for (var i = 0; i < globals.length; ++i) {\n    if (~utils.indexOf(props, globals[i])) continue;\n    props.push(globals[i]);\n  }\n\n  return props;\n};\n\n/**\n * Allow the given `arr` of globals.\n *\n * @param {Array} arr\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.globals = function(arr){\n  if (0 == arguments.length) return this._globals;\n  debug('globals %j', arr);\n  utils.forEach(arr, function(arr){\n    this._globals.push(arr);\n  }, this);\n  return this;\n};\n\n/**\n * Check for global variable leaks.\n *\n * @api private\n */\n\nRunner.prototype.checkGlobals = function(test){\n  if (this.ignoreLeaks) return;\n  var ok = this._globals;\n  var globals = this.globalProps();\n  var isNode = process.kill;\n  var leaks;\n\n  // check length - 2 ('errno' and 'location' globals)\n  if (isNode && 1 == ok.length - globals.length) return\n  else if (2 == ok.length - globals.length) return;\n\n  leaks = filterLeaks(ok, globals);\n  this._globals = this._globals.concat(leaks);\n\n  if (leaks.length > 1) {\n    this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));\n  } else if (leaks.length) {\n    this.fail(test, new Error('global leak detected: ' + leaks[0]));\n  }\n};\n\n/**\n * Fail the given `test`.\n *\n * @param {Test} test\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.fail = function(test, err){\n  ++this.failures;\n  test.state = 'failed';\n\n  if ('string' == typeof err) {\n    err = new Error('the string \"' + err + '\" was thrown, throw an Error :)');\n  }\n  \n  this.emit('fail', test, err);\n};\n\n/**\n * Fail the given `hook` with `err`.\n *\n * Hook failures (currently) hard-end due\n * to that fact that a failing hook will\n * surely cause subsequent tests to fail,\n * causing jumbled reporting.\n *\n * @param {Hook} hook\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.failHook = function(hook, err){\n  this.fail(hook, err);\n  this.emit('end');\n};\n\n/**\n * Run hook `name` callbacks and then invoke `fn()`.\n *\n * @param {String} name\n * @param {Function} function\n * @api private\n */\n\nRunner.prototype.hook = function(name, fn){\n  var suite = this.suite\n    , hooks = suite['_' + name]\n    , self = this\n    , timer;\n\n  function next(i) {\n    var hook = hooks[i];\n    if (!hook) return fn();\n    self.currentRunnable = hook;\n\n    self.emit('hook', hook);\n\n    hook.on('error', function(err){\n      self.failHook(hook, err);\n    });\n\n    hook.run(function(err){\n      hook.removeAllListeners('error');\n      var testError = hook.error();\n      if (testError) self.fail(self.test, testError);\n      if (err) return self.failHook(hook, err);\n      self.emit('hook end', hook);\n      next(++i);\n    });\n  }\n\n  process.nextTick(function(){\n    next(0);\n  });\n};\n\n/**\n * Run hook `name` for the given array of `suites`\n * in order, and callback `fn(err)`.\n *\n * @param {String} name\n * @param {Array} suites\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hooks = function(name, suites, fn){\n  var self = this\n    , orig = this.suite;\n\n  function next(suite) {\n    self.suite = suite;\n\n    if (!suite) {\n      self.suite = orig;\n      return fn();\n    }\n\n    self.hook(name, function(err){\n      if (err) {\n        self.suite = orig;\n        return fn(err);\n      }\n\n      next(suites.pop());\n    });\n  }\n\n  next(suites.pop());\n};\n\n/**\n * Run hooks from the top level down.\n *\n * @param {String} name\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hookUp = function(name, fn){\n  var suites = [this.suite].concat(this.parents()).reverse();\n  this.hooks(name, suites, fn);\n};\n\n/**\n * Run hooks from the bottom up.\n *\n * @param {String} name\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hookDown = function(name, fn){\n  var suites = [this.suite].concat(this.parents());\n  this.hooks(name, suites, fn);\n};\n\n/**\n * Return an array of parent Suites from\n * closest to furthest.\n *\n * @return {Array}\n * @api private\n */\n\nRunner.prototype.parents = function(){\n  var suite = this.suite\n    , suites = [];\n  while (suite = suite.parent) suites.push(suite);\n  return suites;\n};\n\n/**\n * Run the current test and callback `fn(err)`.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runTest = function(fn){\n  var test = this.test\n    , self = this;\n\n  if (this.asyncOnly) test.asyncOnly = true;\n\n  try {\n    test.on('error', function(err){\n      self.fail(test, err);\n    });\n    test.run(fn);\n  } catch (err) {\n    fn(err);\n  }\n};\n\n/**\n * Run tests in the given `suite` and invoke\n * the callback `fn()` when complete.\n *\n * @param {Suite} suite\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runTests = function(suite, fn){\n  var self = this\n    , tests = suite.tests.slice()\n    , test;\n\n  function next(err) {\n    // if we bail after first err\n    if (self.failures && suite._bail) return fn();\n\n    // next test\n    test = tests.shift();\n\n    // all done\n    if (!test) return fn();\n\n    // grep\n    var match = self._grep.test(test.fullTitle());\n    if (self._invert) match = !match;\n    if (!match) return next();\n\n    // pending\n    if (test.pending) {\n      self.emit('pending', test);\n      self.emit('test end', test);\n      return next();\n    }\n\n    // execute test and hook(s)\n    self.emit('test', self.test = test);\n    self.hookDown('beforeEach', function(){\n      self.currentRunnable = self.test;\n      self.runTest(function(err){\n        test = self.test;\n\n        if (err) {\n          self.fail(test, err);\n          self.emit('test end', test);\n          return self.hookUp('afterEach', next);\n        }\n\n        test.state = 'passed';\n        self.emit('pass', test);\n        self.emit('test end', test);\n        self.hookUp('afterEach', next);\n      });\n    });\n  }\n\n  this.next = next;\n  next();\n};\n\n/**\n * Run the given `suite` and invoke the\n * callback `fn()` when complete.\n *\n * @param {Suite} suite\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runSuite = function(suite, fn){\n  var total = this.grepTotal(suite)\n    , self = this\n    , i = 0;\n\n  debug('run suite %s', suite.fullTitle());\n\n  if (!total) return fn();\n\n  this.emit('suite', this.suite = suite);\n\n  function next() {\n    var curr = suite.suites[i++];\n    if (!curr) return done();\n    self.runSuite(curr, next);\n  }\n\n  function done() {\n    self.suite = suite;\n    self.hook('afterAll', function(){\n      self.emit('suite end', suite);\n      fn();\n    });\n  }\n\n  this.hook('beforeAll', function(){\n    self.runTests(suite, next);\n  });\n};\n\n/**\n * Handle uncaught exceptions.\n *\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.uncaught = function(err){\n  debug('uncaught exception %s', err.message);\n  var runnable = this.currentRunnable;\n  if (!runnable || 'failed' == runnable.state) return;\n  runnable.clearTimeout();\n  err.uncaught = true;\n  this.fail(runnable, err);\n\n  // recover from test\n  if ('test' == runnable.type) {\n    this.emit('test end', runnable);\n    this.hookUp('afterEach', this.next);\n    return;\n  }\n\n  // bail on hooks\n  this.emit('end');\n};\n\n/**\n * Run the root suite and invoke `fn(failures)`\n * on completion.\n *\n * @param {Function} fn\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.run = function(fn){\n  var self = this\n    , fn = fn || function(){};\n\n  debug('start');\n\n  // callback\n  this.on('end', function(){\n    debug('end');\n    process.removeListener('uncaughtException', function(err){\n      self.uncaught(err);\n    });\n    fn(self.failures);\n  });\n\n  // run suites\n  this.emit('start');\n  this.runSuite(this.suite, function(){\n    debug('finished running');\n    self.emit('end');\n  });\n\n  // uncaught exception\n  process.on('uncaughtException', function(err){\n    self.uncaught(err);\n  });\n\n  return this;\n};\n\n/**\n * Filter leaks with the given globals flagged as `ok`.\n *\n * @param {Array} ok\n * @param {Array} globals\n * @return {Array}\n * @api private\n */\n\nfunction filterLeaks(ok, globals) {\n  return filter(globals, function(key){\n    var matched = filter(ok, function(ok){\n      if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);\n      // Opera and IE expose global variables for HTML element IDs (issue #243)\n      if (/^mocha-/.test(key)) return true;\n      return key == ok;\n    });\n    return matched.length == 0 && (!global.navigator || 'onerror' !== key);\n  });\n}\n\n}); // module: runner.js\n\nrequire.register(\"suite.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:suite')\n  , milliseconds = require('./ms')\n  , utils = require('./utils')\n  , Hook = require('./hook');\n\n/**\n * Expose `Suite`.\n */\n\nexports = module.exports = Suite;\n\n/**\n * Create a new `Suite` with the given `title`\n * and parent `Suite`. When a suite with the\n * same title is already present, that suite\n * is returned to provide nicer reporter\n * and more flexible meta-testing.\n *\n * @param {Suite} parent\n * @param {String} title\n * @return {Suite}\n * @api public\n */\n\nexports.create = function(parent, title){\n  var suite = new Suite(title, parent.ctx);\n  suite.parent = parent;\n  if (parent.pending) suite.pending = true;\n  title = suite.fullTitle();\n  parent.addSuite(suite);\n  return suite;\n};\n\n/**\n * Initialize a new `Suite` with the given\n * `title` and `ctx`.\n *\n * @param {String} title\n * @param {Context} ctx\n * @api private\n */\n\nfunction Suite(title, ctx) {\n  this.title = title;\n  this.ctx = ctx;\n  this.suites = [];\n  this.tests = [];\n  this.pending = false;\n  this._beforeEach = [];\n  this._beforeAll = [];\n  this._afterEach = [];\n  this._afterAll = [];\n  this.root = !title;\n  this._timeout = 2000;\n  this._slow = 75;\n  this._bail = false;\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nfunction F(){};\nF.prototype = EventEmitter.prototype;\nSuite.prototype = new F;\nSuite.prototype.constructor = Suite;\n\n\n/**\n * Return a clone of this `Suite`.\n *\n * @return {Suite}\n * @api private\n */\n\nSuite.prototype.clone = function(){\n  var suite = new Suite(this.title);\n  debug('clone');\n  suite.ctx = this.ctx;\n  suite.timeout(this.timeout());\n  suite.slow(this.slow());\n  suite.bail(this.bail());\n  return suite;\n};\n\n/**\n * Set timeout `ms` or short-hand such as \"2s\".\n *\n * @param {Number|String} ms\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.timeout = function(ms){\n  if (0 == arguments.length) return this._timeout;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._timeout = parseInt(ms, 10);\n  return this;\n};\n\n/**\n * Set slow `ms` or short-hand such as \"2s\".\n *\n * @param {Number|String} ms\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.slow = function(ms){\n  if (0 === arguments.length) return this._slow;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('slow %d', ms);\n  this._slow = ms;\n  return this;\n};\n\n/**\n * Sets whether to bail after first error.\n *\n * @parma {Boolean} bail\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.bail = function(bail){\n  if (0 == arguments.length) return this._bail;\n  debug('bail %s', bail);\n  this._bail = bail;\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` before running tests.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.beforeAll = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"before all\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._beforeAll.push(hook);\n  this.emit('beforeAll', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` after running tests.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.afterAll = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"after all\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._afterAll.push(hook);\n  this.emit('afterAll', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` before each test case.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.beforeEach = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"before each\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._beforeEach.push(hook);\n  this.emit('beforeEach', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` after each test case.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.afterEach = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"after each\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._afterEach.push(hook);\n  this.emit('afterEach', hook);\n  return this;\n};\n\n/**\n * Add a test `suite`.\n *\n * @param {Suite} suite\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.addSuite = function(suite){\n  suite.parent = this;\n  suite.timeout(this.timeout());\n  suite.slow(this.slow());\n  suite.bail(this.bail());\n  this.suites.push(suite);\n  this.emit('suite', suite);\n  return this;\n};\n\n/**\n * Add a `test` to this suite.\n *\n * @param {Test} test\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.addTest = function(test){\n  test.parent = this;\n  test.timeout(this.timeout());\n  test.slow(this.slow());\n  test.ctx = this.ctx;\n  this.tests.push(test);\n  this.emit('test', test);\n  return this;\n};\n\n/**\n * Return the full title generated by recursively\n * concatenating the parent's full title.\n *\n * @return {String}\n * @api public\n */\n\nSuite.prototype.fullTitle = function(){\n  if (this.parent) {\n    var full = this.parent.fullTitle();\n    if (full) return full + ' ' + this.title;\n  }\n  return this.title;\n};\n\n/**\n * Return the total number of tests.\n *\n * @return {Number}\n * @api public\n */\n\nSuite.prototype.total = function(){\n  return utils.reduce(this.suites, function(sum, suite){\n    return sum + suite.total();\n  }, 0) + this.tests.length;\n};\n\n/**\n * Iterates through each suite recursively to find\n * all tests. Applies a function in the format\n * `fn(test)`.\n *\n * @param {Function} fn\n * @return {Suite}\n * @api private\n */\n\nSuite.prototype.eachTest = function(fn){\n  utils.forEach(this.tests, fn);\n  utils.forEach(this.suites, function(suite){\n    suite.eachTest(fn);\n  });\n  return this;\n};\n\n}); // module: suite.js\n\nrequire.register(\"test.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Runnable = require('./runnable');\n\n/**\n * Expose `Test`.\n */\n\nmodule.exports = Test;\n\n/**\n * Initialize a new `Test` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Test(title, fn) {\n  Runnable.call(this, title, fn);\n  this.pending = !fn;\n  this.type = 'test';\n}\n\n/**\n * Inherit from `Runnable.prototype`.\n */\n\nfunction F(){};\nF.prototype = Runnable.prototype;\nTest.prototype = new F;\nTest.prototype.constructor = Test;\n\n\n}); // module: test.js\n\nrequire.register(\"utils.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar fs = require('browser/fs')\n  , path = require('browser/path')\n  , join = path.join\n  , debug = require('browser/debug')('mocha:watch');\n\n/**\n * Ignored directories.\n */\n\nvar ignore = ['node_modules', '.git'];\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param  {String} html\n * @return {String}\n * @api private\n */\n\nexports.escape = function(html){\n  return String(html)\n    .replace(/&/g, '&amp;')\n    .replace(/\"/g, '&quot;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;');\n};\n\n/**\n * Array#forEach (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @param {Object} scope\n * @api private\n */\n\nexports.forEach = function(arr, fn, scope){\n  for (var i = 0, l = arr.length; i < l; i++)\n    fn.call(scope, arr[i], i);\n};\n\n/**\n * Array#indexOf (<=IE8)\n *\n * @parma {Array} arr\n * @param {Object} obj to find index of\n * @param {Number} start\n * @api private\n */\n\nexports.indexOf = function(arr, obj, start){\n  for (var i = start || 0, l = arr.length; i < l; i++) {\n    if (arr[i] === obj)\n      return i;\n  }\n  return -1;\n};\n\n/**\n * Array#reduce (<=IE8)\n * \n * @param {Array} array\n * @param {Function} fn\n * @param {Object} initial value\n * @api private\n */\n\nexports.reduce = function(arr, fn, val){\n  var rval = val;\n\n  for (var i = 0, l = arr.length; i < l; i++) {\n    rval = fn(rval, arr[i], i, arr);\n  }\n\n  return rval;\n};\n\n/**\n * Array#filter (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @api private\n */\n\nexports.filter = function(arr, fn){\n  var ret = [];\n\n  for (var i = 0, l = arr.length; i < l; i++) {\n    var val = arr[i];\n    if (fn(val, i, arr)) ret.push(val);\n  }\n\n  return ret;\n};\n\n/**\n * Object.keys (<=IE8)\n *\n * @param {Object} obj\n * @return {Array} keys\n * @api private\n */\n\nexports.keys = Object.keys || function(obj) {\n  var keys = []\n    , has = Object.prototype.hasOwnProperty // for `window` on <=IE8\n\n  for (var key in obj) {\n    if (has.call(obj, key)) {\n      keys.push(key);\n    }\n  }\n\n  return keys;\n};\n\n/**\n * Watch the given `files` for changes\n * and invoke `fn(file)` on modification.\n *\n * @param {Array} files\n * @param {Function} fn\n * @api private\n */\n\nexports.watch = function(files, fn){\n  var options = { interval: 100 };\n  files.forEach(function(file){\n    debug('file %s', file);\n    fs.watchFile(file, options, function(curr, prev){\n      if (prev.mtime < curr.mtime) fn(file);\n    });\n  });\n};\n\n/**\n * Ignored files.\n */\n\nfunction ignored(path){\n  return !~ignore.indexOf(path);\n}\n\n/**\n * Lookup files in the given `dir`.\n *\n * @return {Array}\n * @api private\n */\n\nexports.files = function(dir, ret){\n  ret = ret || [];\n\n  fs.readdirSync(dir)\n  .filter(ignored)\n  .forEach(function(path){\n    path = join(dir, path);\n    if (fs.statSync(path).isDirectory()) {\n      exports.files(path, ret);\n    } else if (path.match(/\\.(js|coffee)$/)) {\n      ret.push(path);\n    }\n  });\n\n  return ret;\n};\n\n/**\n * Compute a slug from the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.slug = function(str){\n  return str\n    .toLowerCase()\n    .replace(/ +/g, '-')\n    .replace(/[^-\\w]/g, '');\n};\n\n/**\n * Strip the function definition from `str`,\n * and re-indent for pre whitespace.\n */\n\nexports.clean = function(str) {\n  str = str\n    .replace(/^function *\\(.*\\) *{/, '')\n    .replace(/\\s+\\}$/, '');\n\n  var spaces = str.match(/^\\n?( *)/)[1].length\n    , re = new RegExp('^ {' + spaces + '}', 'gm');\n\n  str = str.replace(re, '');\n\n  return exports.trim(str);\n};\n\n/**\n * Escape regular expression characters in `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.escapeRegexp = function(str){\n  return str.replace(/[-\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\");\n};\n\n/**\n * Trim the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.trim = function(str){\n  return str.replace(/^\\s+|\\s+$/g, '');\n};\n\n/**\n * Parse the given `qs`.\n *\n * @param {String} qs\n * @return {Object}\n * @api private\n */\n\nexports.parseQuery = function(qs){\n  return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){\n    var i = pair.indexOf('=')\n      , key = pair.slice(0, i)\n      , val = pair.slice(++i);\n\n    obj[key] = decodeURIComponent(val);\n    return obj;\n  }, {});\n};\n\n/**\n * Highlight the given string of `js`.\n *\n * @param {String} js\n * @return {String}\n * @api private\n */\n\nfunction highlight(js) {\n  return js\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\\/\\/(.*)/gm, '<span class=\"comment\">//$1</span>')\n    .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n    .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n    .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n    .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n    .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n}\n\n/**\n * Highlight the contents of tag `name`.\n *\n * @param {String} name\n * @api private\n */\n\nexports.highlightTags = function(name) {\n  var code = document.getElementsByTagName(name);\n  for (var i = 0, len = code.length; i < len; ++i) {\n    code[i].innerHTML = highlight(code[i].innerHTML);\n  }\n};\n\n}); // module: utils.js\n/**\n * Node shims.\n *\n * These are meant only to allow\n * mocha.js to run untouched, not\n * to allow running node code in\n * the browser.\n */\n\nprocess = {};\nprocess.exit = function(status){};\nprocess.stdout = {};\nglobal = window;\n\n/**\n * next tick implementation.\n */\n\nprocess.nextTick = (function(){\n  // postMessage behaves badly on IE8\n  if (window.ActiveXObject || !window.postMessage) {\n    return function(fn){ fn() };\n  }\n\n  // based on setZeroTimeout by David Baron\n  // - http://dbaron.org/log/20100309-faster-timeouts\n  var timeouts = []\n    , name = 'mocha-zero-timeout'\n\n  window.addEventListener('message', function(e){\n    if (e.source == window && e.data == name) {\n      if (e.stopPropagation) e.stopPropagation();\n      if (timeouts.length) timeouts.shift()();\n    }\n  }, true);\n\n  return function(fn){\n    timeouts.push(fn);\n    window.postMessage(name, '*');\n  }\n})();\n\n/**\n * Remove uncaughtException listener.\n */\n\nprocess.removeListener = function(e){\n  if ('uncaughtException' == e) {\n    window.onerror = null;\n  }\n};\n\n/**\n * Implements uncaughtException listener.\n */\n\nprocess.on = function(e, fn){\n  if ('uncaughtException' == e) {\n    window.onerror = function(err, url, line){\n      fn(new Error(err + ' (' + url + ':' + line + ')'));\n    };\n  }\n};\n\n// boot\n;(function(){\n\n  /**\n   * Expose mocha.\n   */\n\n  var Mocha = window.Mocha = require('mocha'),\n      mocha = window.mocha = new Mocha({ reporter: 'html' });\n\n  /**\n   * Override ui to ensure that the ui functions are initialized.\n   * Normally this would happen in Mocha.prototype.loadFiles.\n   */\n\n  mocha.ui = function(ui){\n    Mocha.prototype.ui.call(this, ui);\n    this.suite.emit('pre-require', window, null, this);\n    return this;\n  };\n\n  /**\n   * Setup mocha with the given setting options.\n   */\n\n  mocha.setup = function(opts){\n    if ('string' == typeof opts) opts = { ui: opts };\n    for (var opt in opts) this[opt](opts[opt]);\n    return this;\n  };\n\n  /**\n   * Run mocha, returning the Runner.\n   */\n\n  mocha.run = function(fn){\n    var options = mocha.options;\n    mocha.globals('location');\n\n    var query = Mocha.utils.parseQuery(window.location.search || '');\n    if (query.grep) mocha.grep(query.grep);\n    if (query.invert) mocha.invert();\n\n    return Mocha.prototype.run.call(mocha, function(){\n      Mocha.utils.highlightTags('code');\n      if (fn) fn();\n    });\n  };\n})();\n})();"
  },
  {
    "path": "test/spec/infinity/pathmodel.js",
    "content": "/*global describe, it */\n'use strict';\n(function () {\n    describe('GXPath', function () {\n        this.bail(false);\n\n        it('Set and get PROPERTY_CLOSED', function () {\n            var path = new GXPath();\n            expect(path).to.be.an('Object');\n\n            expect(path.getProperty(GXPath.PROPERTY_CLOSED)).to.be.null;\n            path.setProperty(GXPath.PROPERTY_CLOSED, true);\n            expect(path.getProperty(GXPath.PROPERTY_CLOSED)).to.be.true;\n            path.setProperty(GXPath.PROPERTY_CLOSED, false);\n            expect(path.getProperty(GXPath.PROPERTY_CLOSED)).to.not.be.ok;\n        });\n\n        it('Updates handles of first two points and last two points when setting PROPERTY_CLOSED', function () {\n            expect(1).to.be.false;\n        });\n\n        it('#getAnchorPoints returns AnchorPointContainer', function () {\n            var path = new GXPath();\n            var container = path.getAnchorPoints();\n            expect(container.toString()).to.equal(\"[GXPath.AnchorPointContainer]\");\n        });\n\n        it('#setCType updates corner type and shoulders length for all anchor points in the path', function () {\n            var path = new GXPath();\n            path.appendAnchorPoint(new GXPath.AnchorPoint(new IFPoint(10, 10), null,\n                null, new IFPoint(15, 0)));\n            path.appendAnchorPoint(new GXPath.AnchorPoint(new IFPoint(50, 10), null,\n                new IFPoint(15, -10), new IFPoint(60, 20)));\n            path.appendAnchorPoint(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n            path.appendAnchorPoint(new GXPath.AnchorPoint(new IFPoint(30, 100)));\n            var aCTypes = [\n                GXPath.AnchorPoint.CType.Regular,\n                GXPath.AnchorPoint.CType.Connector,\n                GXPath.AnchorPoint.CType.Smooth,\n                GXPath.AnchorPoint.CType.Rounded,\n                GXPath.AnchorPoint.CType.InverseRounded,\n                GXPath.AnchorPoint.CType.Bevel,\n                GXPath.AnchorPoint.CType.Inset,\n                GXPath.AnchorPoint.CType.Fancy\n            ];\n            var ctype;\n            var cx = 5, cy = 10;\n            for (var i = 0; i < aCTypes.length; ++i, ++cx, ++cy) {\n                 ctype = aCTypes[i];\n\n                path.setCType(ctype, cx, cy);\n\n                for (var anchorPoint = path.getAnchorPoints().getFirstChild(); anchorPoint != null;\n                     anchorPoint = anchorPoint.getNext()) {\n\n                     expect(anchorPoint.$ctype).to.be.equal(ctype);\n                     if (ctype > GXPath.AnchorPoint.CType.Smooth) {\n                         expect(anchorPoint.$cx).to.be.equal(cx);\n                         expect(anchorPoint.$cy).to.be.equal(cy);\n                     }\n                }\n            }\n        });\n        it('#setAuto updates handles to be auto or not for all anchor points in the path', function () {\n            var aCTypes = [\n                GXPath.AnchorPoint.CType.Regular,\n                GXPath.AnchorPoint.CType.Connector,\n                GXPath.AnchorPoint.CType.Smooth,\n                GXPath.AnchorPoint.CType.Rounded,\n                GXPath.AnchorPoint.CType.InverseRounded,\n                GXPath.AnchorPoint.CType.Bevel,\n                GXPath.AnchorPoint.CType.Inset,\n                GXPath.AnchorPoint.CType.Fancy\n            ];\n\n            var path = new GXPath();\n            for (var i = 0; i < aCTypes.length; ++i) {\n                path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                    new IFPoint(5*i, 10*i + i), aCTypes[i], new IFPoint(0, 8*i), new IFPoint(3*i, 0)));\n            }\n\n            var anchorPoint;\n            for (anchorPoint = path.getAnchorPoints().getFirstChild(); anchorPoint != null;\n                 anchorPoint = anchorPoint.getNext()) {\n\n                expect(anchorPoint.$ah).to.be.false;\n            }\n            path.setAuto(true);\n            for (anchorPoint = path.getAnchorPoints().getFirstChild(); anchorPoint != null;\n                 anchorPoint = anchorPoint.getNext()) {\n\n                expect(anchorPoint.$ah).to.be.true;\n            }\n            path.setAuto(false);\n            for (anchorPoint = path.getAnchorPoints().getFirstChild(); anchorPoint != null;\n                 anchorPoint = anchorPoint.getNext()) {\n\n                expect(anchorPoint.$ah).to.be.false;\n            }\n        });\n        it('#_detailHitTest makes hit-testing', function () {\n            expect(1).to.be.false;\n        });\n        it('#insertChild insert anchor point and recalculate handles of this and two neighbour points', function () {\n            expect(1).to.be.false;\n        });\n        it('#removeChild remove anchor point and recalculate handles of two neighbour points', function () {\n            expect(1).to.be.false;\n        });\n\n        describe('AnchorPoint', function () {\n            it('should construct AnchorPoint', function() {\n                expect(GXPath).itself.respondTo('AnchorPoint');\n                var anchorPt = new GXPath.AnchorPoint();\n                expect(anchorPt).to.have.property('$x');\n                expect(anchorPt).to.have.property('$y');\n                expect(anchorPt).to.have.property('$hlx');\n                expect(anchorPt).to.have.property('$hly');\n                expect(anchorPt).to.have.property('$hrx');\n                expect(anchorPt).to.have.property('$hry');\n                expect(anchorPt).to.have.property('$cx');\n                expect(anchorPt).to.have.property('$cy');\n                expect(anchorPt).to.have.property('$ctype');\n                expect(anchorPt).to.have.property('$ah');\n                expect(anchorPt.$x).to.be.equal(0);\n                expect(anchorPt.$y).to.be.equal(0);\n                expect(anchorPt.$hlx).to.be.null;\n                expect(anchorPt.$hly).to.be.null;\n                expect(anchorPt.$hrx).to.be.null;\n                expect(anchorPt.$hry).to.be.null;\n                expect(anchorPt.$ctype).to.be.equal(GXPath.AnchorPoint.CType.Regular);\n                expect(anchorPt.$cx).to.be.equal(0);\n                expect(anchorPt.$cy).to.be.equal(0);\n                expect(anchorPt.$ah).to.not.be.ok;\n\n                var x = 20, y = 30.5, hlx = 40, hly = 50.5, hrx = 60, hry = 60.5, cx = 10, cy = 15;\n                anchorPt = new GXPath.AnchorPoint(new IFPoint(x, y), null, null, new IFPoint(hrx, hry));\n\n                expect(anchorPt.$x).to.be.equal(x);\n                expect(anchorPt.$y).to.be.equal(y);\n                expect(anchorPt.$hlx).to.be.null;\n                expect(anchorPt.$hly).to.be.null;\n                expect(anchorPt.$hrx).to.be.equal(hrx);\n                expect(anchorPt.$hry).to.be.equal(hry);\n                expect(anchorPt.$ctype).to.be.equal(GXPath.AnchorPoint.CType.Regular);\n\n                anchorPt = new GXPath.AnchorPoint(new IFPoint(x, y), GXPath.AnchorPoint.CType.Connector,\n                    new IFPoint(hlx, hly), new IFPoint(hrx, hry));\n\n                expect(anchorPt.$hlx).to.be.equal(hlx);\n                expect(anchorPt.$hly).to.be.equal(hly);\n                expect(anchorPt.$hrx).to.be.equal(hrx);\n                expect(anchorPt.$hry).to.be.equal(hry);\n                expect(anchorPt.$ctype).to.be.equal(GXPath.AnchorPoint.CType.Connector);\n\n                anchorPt = new GXPath.AnchorPoint(new IFPoint(x, y), GXPath.AnchorPoint.CType.Smooth, new IFPoint(hlx, hly));\n\n                expect(anchorPt.$ctype).to.be.equal(GXPath.AnchorPoint.CType.Smooth);\n                expect(anchorPt.$hlx).to.be.equal(hlx);\n                expect(anchorPt.$hly).to.be.equal(hly);\n                expect(anchorPt.$hrx).to.be.null;\n                expect(anchorPt.$hry).to.be.null;\n            });\n            describe('#setProperty with GXPath.AnchorPoint.PROPERTY_CX, GXPath.AnchorPoint.PROPERTY_CY', function () {\n                it('Update anchor point shoulders lengths ($cx, $cy) for all styled corners', function () {\n                    var anchorPt = new GXPath.AnchorPoint();\n\n                    var styledCTypes = [\n                        GXPath.AnchorPoint.CType.Rounded,\n                        GXPath.AnchorPoint.CType.InverseRounded,\n                        GXPath.AnchorPoint.CType.Bevel,\n                        GXPath.AnchorPoint.CType.Inset,\n                        GXPath.AnchorPoint.CType.Fancy\n                    ];\n\n                    var aCType;\n                    var cx = 10, cy = 15;\n                    for (var i = 0; i < styledCTypes.length; ++i) {\n                        aCType = styledCTypes[i];\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, aCType);\n                        expect(anchorPt.$cx).to.be.equal(0);\n                        expect(anchorPt.$cy).to.be.equal(0);\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CX, cx);\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CY, cy);\n                        expect(anchorPt.$cx).to.be.equal(cx);\n                        expect(anchorPt.$cy).to.be.equal(cy);\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CX, 0);\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CY, 0);\n                        expect(anchorPt.$cx).to.be.equal(0);\n                        expect(anchorPt.$cy).to.be.equal(0);\n                    }\n                });\n            });\n            describe('#setProperty with GXPath.AnchorPoint.PROPERTY_CTYPE', function () {\n                it('Update anchor point corner type ($ctype property)', function () {\n                    var anchorPt = new GXPath.AnchorPoint();\n\n                    var anchorCTypes = [\n                        GXPath.AnchorPoint.CType.Connector,\n                        GXPath.AnchorPoint.CType.Smooth,\n                        GXPath.AnchorPoint.CType.Regular,\n\n                        GXPath.AnchorPoint.CType.Rounded,\n                        GXPath.AnchorPoint.CType.InverseRounded,\n                        GXPath.AnchorPoint.CType.Bevel,\n                        GXPath.AnchorPoint.CType.Inset,\n                        GXPath.AnchorPoint.CType.Fancy\n                    ];\n\n                    var aCType;\n\n                    expect(anchorPt.$ctype).to.be.equal(GXPath.AnchorPoint.CType.Regular);\n                    for (var i = 0; i < anchorCTypes.length; ++i) {\n                        aCType = anchorCTypes[i];\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, aCType);\n                        expect(anchorPt.$ctype).to.be.equal(aCType);\n                    }\n                });\n                it('Recalculate handles of anchor point for Connector type: Start point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Connector);\n                    expect(aPt.$hlx).to.be.equal(x1 - 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 + 5);\n                });\n                it('Recalculate handles of anchor point for Connector type: Start point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n\n                    var aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Connector);\n                    expect(aPt.$hlx).to.be.equal(x1 - 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                    expect(aPt.$hrx).to.be.equal(x1 + 5);\n                    expect(aPt.$hry).to.be.equal(y1);\n                });\n                it('Recalculate handles of anchor point for Connector type: End point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(60, 10), new IFPoint(40, 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1 + 5, y1), new IFPoint(x1, y1 + 5)));\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getLastChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Connector);\n                    expect(aPt.$hrx).to.be.equal(x1 - 5);\n                    expect(aPt.$hry).to.be.equal(y1);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                });\n                it('Recalculate handles of anchor point for Connector type: End point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(60, 10), new IFPoint(40, 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1 + 5, y1), new IFPoint(x1, y1 + 5)));\n\n                    var aPt = path.getAnchorPoints().getLastChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Connector);\n                    expect(aPt.$hrx).to.be.equal(x1 - 5);\n                    expect(aPt.$hry).to.be.equal(y1);\n                    expect(aPt.$hlx).to.be.equal(x1 + 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                });\n                it('Recalculate handles of anchor point for Connector type: path middle point', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getFirstChild().getNext();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Connector);\n                    expect(aPt.$hlx).to.be.equal(x1 - 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 + 5);\n                });\n                it('Recalculate (not auto-)handles of anchor point for Smooth type: Start point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, y2)));\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Smooth);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 - 5);\n                });\n                it('Recalculate (not auto-)handles of anchor point for Smooth type: Start point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, y2)));\n\n                    var aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Smooth);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 - 5);\n                });\n                it('Recalculate (not auto-)handles of anchor point for Smooth type: End point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(60, 10), new IFPoint(40, 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 - 5, y1)));\n\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getLastChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Smooth);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 - 5);\n                });\n                it('Recalculate (not auto-)handles of anchor point for Smooth type: End point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(60, 10), new IFPoint(40, 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 - 5, y1)));\n\n                    var aPt = path.getAnchorPoints().getLastChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Smooth);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 - 5);\n\n                });\n                it('Recalculate (not auto-)handles of anchor point for Smooth type: path middle point', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getFirstChild().getNext();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, GXPath.AnchorPoint.CType.Smooth);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 - 5);\n\n                });\n            });\n            describe('#setProperty with GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES', function () {\n                it('Updates $ah property', function () {\n                    var anchorPt = new GXPath.AnchorPoint();\n\n                    var anchorCTypes = [\n                        GXPath.AnchorPoint.CType.Regular,\n                        GXPath.AnchorPoint.CType.Connector,\n                        GXPath.AnchorPoint.CType.Smooth,\n\n                        GXPath.AnchorPoint.CType.Rounded,\n                        GXPath.AnchorPoint.CType.InverseRounded,\n                        GXPath.AnchorPoint.CType.Bevel,\n                        GXPath.AnchorPoint.CType.Inset,\n                        GXPath.AnchorPoint.CType.Fancy\n                    ];\n\n                    var aCType;\n                    for (var i = 0; i < anchorCTypes.length; ++i) {\n                        aCType = anchorCTypes[i];\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_CTYPE, aCType);\n                        expect(anchorPt.$ah).to.be.false;\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES,true);\n                        expect(anchorPt.$ah).to.be.true;\n                        anchorPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES,false);\n                        expect(anchorPt.$ah).to.be.false;\n                    }\n                });\n                it('Recalculate handles of anchor point for Smooth type: Start point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var x2 = 50;\n                    var y2 = y1;\n                    var x4 = x1 - 10;\n                    var y4 = -10;\n\n                    var aPt;\n                    var res;\n                    var ptx, pty;\n                    var ccntr;\n                    var offs = 0.4;\n                    var dirLen, hLen;\n                    var dx, dy;\n\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Smooth,\n                        new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y2), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x4, y4)));\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n\n                    ccntr = gMath.getCircumcircleCenter(x4, y4, x1, y1, x2, y2);\n                    dirLen = Math.sqrt(gMath.ptSqrDist(x1, y1, ccntr.getX(), ccntr.getY()));\n                    dx = (y1 - ccntr.getY()) / dirLen;\n                    dy = (ccntr.getX() - x1) / dirLen;\n                    if (gMath.segmentSide(x1, y1, (x4 + x2)/2, (y4 + y2)/2, x4, y4) !=\n                        gMath.segmentSide(x1, y1, (x4 + x2)/2, (y4 + y2)/2, x1  - dx, y1  - dy)) {\n                        dx = -dx;\n                        dy = -dy;\n                    }\n\n                    hLen = Math.sqrt(gMath.ptSqrDist(x1, y1, x4, y4)) * offs;\n\n                    ptx = x1 - dx * hLen;\n                    res = gMath.isEqualEps(aPt.$hlx, ptx);\n                    expect(res).to.be.true;\n\n                    pty = y1 - dy * hLen;\n                    res = gMath.isEqualEps(aPt.$hly, pty);\n                    expect(res).to.be.true;\n\n                    hLen = Math.sqrt(gMath.ptSqrDist(x1, y1, x2, y2)) * offs;\n\n                    ptx = x1 + dx * hLen;\n                    res = gMath.isEqualEps(aPt.$hrx, ptx);\n                    expect(res).to.be.true;\n\n                    pty = y1 + dy * hLen;\n                    res = gMath.isEqualEps(aPt.$hry, pty);\n                    expect(res).to.be.true;\n                });\n                it('Recalculate handles of anchor point for Smooth type: Start point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var x2 = 50;\n\n                    var aPt;\n                    var res;\n\n                    var offs = 0.4;\n                    var hLen;\n\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Smooth,\n                        new IFPoint(x1, y1 + 5), new IFPoint(x1, y1 - 3)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, -10)));\n\n                    aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n\n                    hLen = (x2 - x1) * offs;\n\n                    res = gMath.isEqualEps(aPt.$hlx, x1 - hLen);\n                    expect(res).to.be.true;\n\n                    res = gMath.isEqualEps(aPt.$hly, y1);\n                    expect(res).to.be.true;\n\n                    res = gMath.isEqualEps(aPt.$hrx, x1 + hLen);\n                    expect(res).to.be.true;\n\n                    res = gMath.isEqualEps(aPt.$hry, y1);\n                    expect(res).to.be.true;\n                });\n                it('Recalculate handles of anchor point for Smooth type: End point - path closed', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Recalculate handles of anchor point for Smooth type: End point - path opened', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Recalculate handles of anchor point for Smooth type: path middle point', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Recalculate handles for Regular and styled corners: Start point - path closed', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Recalculate handles of Regular and styled corners: Start point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var x2 = 50;\n                    var y2 = y1;\n                    var x3 = 50;\n                    var y3 = 70;\n\n                    var aPt;\n                    var res;\n                    var ptx, pty;\n                    var ccntr;\n                    var offs = 0.4;\n                    var dirLen, hLen;\n                    var dx, dy;\n\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), null, new IFPoint(x1, y1 + 5), new IFPoint(x1, y1 - 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y2), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x3, y3)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1 - 10, -10)));\n\n                    aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n\n                    ccntr = gMath.getCircumcircleCenter(x1, y1, x2, y2, x3, y3);\n                    dirLen = Math.sqrt(gMath.ptSqrDist(x1, y1, ccntr.getX(), ccntr.getY()));\n                    dx = (y1 - ccntr.getY()) / dirLen;\n                    dy = (ccntr.getX() - x1) / dirLen;\n                    if (gMath.segmentSide(x1, y1, (x2 + x3)/2, (y2 + y3)/2, x2, y2) !=\n                        gMath.segmentSide(x1, y1, (x2 + x3)/2, (y2 + y3)/2, x1  + dx, y1  + dy)) {\n                        dx = -dx;\n                        dy = -dy;\n                    }\n\n                    hLen = Math.sqrt(gMath.ptSqrDist(x1, y1, x2, y2)) * offs;\n\n                    ptx = x1 + dx * hLen;\n                    res = gMath.isEqualEps(aPt.$hrx, ptx);\n                    expect(res).to.be.true;\n\n                    pty = y1 + dy * hLen;\n                    res = gMath.isEqualEps(aPt.$hry, pty);\n                    expect(res).to.be.true;\n\n                    expect(aPt.$hlx).to.be.null;\n                    expect(aPt.$hly).to.be.null;\n                });\n                it('Recalculate handles of Regular and styled corners: End point - path closed', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Recalculate handles of Regular and styled corners: End point - path opened', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Recalculate handles of Regular and styled corners: path middle point', function() {\n                    expect(1).to.be.false;\n\n                });\n                it('Do not affect handles of Connector anchor points: Start point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Connector,\n                        new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n                    expect(aPt.$hlx).to.be.equal(x1 - 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 + 5);\n                });\n                it('Do not affect handles of Connector anchor points: Start point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Connector,\n                        new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n\n                    var aPt = path.getAnchorPoints().getFirstChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n                    expect(aPt.$hlx).to.be.equal(x1 - 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                    expect(aPt.$hrx).to.be.equal(x1 + 5);\n                    expect(aPt.$hry).to.be.equal(y1);\n                });\n                it('Do not affect handles of Connector anchor points: End point - path closed', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(60, 10), new IFPoint(40, 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Connector,\n                        new IFPoint(x1 + 5, y1), new IFPoint(x1, y1 + 5)));\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getLastChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n                    expect(aPt.$hrx).to.be.equal(x1 - 5);\n                    expect(aPt.$hry).to.be.equal(y1);\n                    expect(aPt.$hlx).to.be.equal(x1);\n                    expect(aPt.$hly).to.be.equal(y1 + 5);\n                });\n                it('Do not affect handles of Connector anchor points: End point - path opened', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(60, 10), new IFPoint(40, 5)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Connector,\n                        new IFPoint(x1 + 5, y1), new IFPoint(x1, y1 + 5)));\n\n                    var aPt = path.getAnchorPoints().getLastChild();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n                    expect(aPt.$hrx).to.be.equal(x1 - 5);\n                    expect(aPt.$hry).to.be.equal(y1);\n                    expect(aPt.$hlx).to.be.equal(x1 + 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                });\n                it('Do not affect handles of Connector anchor points: path middle point', function() {\n                    var path = new GXPath();\n                    var x1 = 10;\n                    var y1 = 0;\n                    var y2 = -10;\n                    var x2 = 50;\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(x1, y2)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x1, y1), GXPath.AnchorPoint.CType.Connector,\n                        new IFPoint(x1, y1 + 5), new IFPoint(x1 + 5, y1)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(\n                        new IFPoint(x2, y1), null, new IFPoint(40, 5), new IFPoint(60, 10)));\n                    path.getAnchorPoints().appendChild(new GXPath.AnchorPoint(new IFPoint(50, 70)));\n\n                    path.setProperty(GXPath.PROPERTY_CLOSED, true);\n\n                    var aPt = path.getAnchorPoints().getFirstChild().getNext();\n                    aPt.setProperty(GXPath.AnchorPoint.PROPERTY_AUTO_HANDLES, true);\n                    expect(aPt.$hlx).to.be.equal(x1 - 5);\n                    expect(aPt.$hly).to.be.equal(y1);\n                    expect(aPt.$hrx).to.be.equal(x1);\n                    expect(aPt.$hry).to.be.equal(y1 + 5);\n                });\n            });\n            it('setting corner type Smooth when auto-handles are marked works the same as setting auto handles for Smooth corner type',\n                function() {\n\n                expect(1).to.be.false;\n            });\n            describe('#transform', function () {\n                it('Makes shift transformation of anchor point with handles', function () {\n                    expect(1).to.be.false;\n                });\n                it('Makes scaling of anchor point with handles and shoulders(if handles or neighbour points present)',\n                    function () {\n                    expect(1).to.be.false;\n                });\n                it('Makes rotation of anchor point with handles', function () {\n                    expect(1).to.be.false;\n                });\n                it('Makes complex transformation of anchor point with handles and shoulders', function () {\n                    expect(1).to.be.false;\n                });\n            });\n        });\n\n        describe('AnchorPointContainer', function () {\n            describe('#appendChild', function () {\n                it('should add anchorPoint to container', function () {\n                    var path = new GXPath();\n                    var container = path.getAnchorPoints();\n                    var boxWidth = 70, boxHeight = 80, brim = 20;\n                    var pathWidth = 50, pathHeight = 60, pathRadiusX = 10, pathRadiusY = 10;\n                    var x = 10, y = 10;\n\n                    var anchorPointOrig = new GXPath.AnchorPoint(\n                        new IFPoint(brim, brim), null, null, new IFPoint(brim + pathWidth / 2, 0));\n\n                    expect(container.getFirstChild(true)).to.be.null;\n                    container.appendChild(anchorPointOrig);\n\n                    var anchorPoint1 = container.getFirstChild(true);\n\n                    expect(anchorPoint1.toString()).to.equal(\"[GXPath.AnchorPoint]\");\n                    expect(anchorPoint1.$x).to.equal(anchorPointOrig.$x);\n                    expect(anchorPoint1.$y).to.equal(anchorPointOrig.$y);\n                    expect(anchorPoint1.$ctype).to.equal(anchorPointOrig.$ctype);\n\n                    anchorPointOrig = new GXPath.AnchorPoint(new IFPoint(brim + pathWidth, brim),\n                        GXPath.AnchorPoint.CType.Inset,\n                        new IFPoint(brim + pathWidth / 3 * 2, brim + pathHeight / 3),\n                        new IFPoint(pathWidth + brim, boxHeight / 2) );\n\n                    expect(container.getLastChild(true)).to.equal(anchorPoint1);\n                    container.appendChild(anchorPointOrig);\n                    var anchorPoint2 = container.getLastChild(true);\n                    expect(anchorPoint2).to.not.equal(anchorPoint1);\n                    expect(anchorPoint2.toString()).to.equal(\"[GXPath.AnchorPoint]\");\n                    expect(anchorPoint2.$x).to.equal(anchorPointOrig.$x);\n                    expect(anchorPoint2.$y).to.equal(anchorPointOrig.$y);\n                    expect(anchorPoint2.$ctype).to.equal(anchorPointOrig.$ctype);\n                    expect(anchorPoint2.$hlx).to.equal(anchorPointOrig.$hlx);\n                    expect(anchorPoint2.$hly).to.equal(anchorPointOrig.$hly);\n                    expect(anchorPoint2.$hrx).to.equal(anchorPointOrig.$hrx);\n                    expect(anchorPoint2.$hry).to.equal(anchorPointOrig.$hry);\n                });\n            });\n            describe('#readVertex', function () {\n                it('calculate styled corners from anchor points and return path vertices one by one', function() {\n                    expect(1).to.be.false;\n                });\n            });\n            describe('#appendVertices', function () {\n                it('Compose anchor points from source vertices and adds to container', function() {\n                    expect(1).to.be.false;\n                });\n                it('Updates handles of the two first and last and new points according to type', function() {\n                    expect(1).to.be.false;\n                });\n            });\n            describe('#clearVertices', function () {\n                it('Remove all vertices from container', function() {\n                    expect(1).to.be.false;\n                });\n            });\n            describe('#rewindVertices', function () {\n                it('Reset iterator to the first child', function() {\n                    expect(1).to.be.false;\n                });\n            });\n\n        });\n\n    });\n})();\n"
  },
  {
    "path": "test/spec/test.js",
    "content": "/*global describe, it */\n'use strict';\n(function () {\n    describe('Give it some context', function () {\n        describe('maybe a bit more context here', function () {\n            it('should run here few assertions', function () {\n\n            });\n        });\n    });\n})();\n"
  }
]