[
  {
    "path": ".angular-cli.json",
    "content": "{\n  \"project\": {\n    \"version\": \"1.0.0-beta.32.3\",\n    \"name\": \"StudioWeb\"\n  },\n  \"apps\": [\n    {\n      \"root\": \"src\",\n      \"outDir\": \"dist\",\n      \"assets\": [\n        \"assets\",\n        \"favicon.ico\",\n        \"manifest.json\",\n        \"service-worker.js\"\n      ],\n      \"index\": \"index.html\",\n      \"main\": \"main.ts\",\n      \"test\": \"test.ts\",\n      \"tsconfig\": \"tsconfig.json\",\n      \"prefix\": \"app\",\n      \"mobile\": false,\n      \"styles\": [\n        \"../node_modules/font-awesome/css/font-awesome.css\",\n        \"../node_modules/bootstrap/dist/css/bootstrap.min.css\",\n        \"../node_modules/ng2-toastr/ng2-toastr.css\",\n        \"../node_modules/primeng/resources/themes/bootstrap/theme.css\",\n        \"../node_modules/primeng/resources/primeng.min.css\",\n        \"./libs/bootstrap-timepicker/css/bootstrap-timepicker.css\",\n        \"./libs/minicolors/jquery.minicolors.css\",\n        \"./libs/ruler/ruler.css\",\n        \"./styles/style.css\",\n        \"./styles/jquery.timepicker.min.css\"\n      ],\n      \"scripts\": [\n        \"../node_modules/jquery/dist/jquery.min.js\",\n        \"./libs/jquery.base64.js\",\n        \"./libs/jquery-ui.js\",\n        \"./libs/jquery.knob.min.js\",\n        \"./libs/flashdetect/flashdetect.js\",\n        \"./libs/rc4v1/rc4v1.js\",\n        \"./libs/rc4v2/rc4v2.js\",\n        \"./libs/qrcode/qrcode.js\",\n        \"./libs/bootstrap-timepicker/js/bootstrap-timepicker.min.js\",\n        \"./libs/jquery.timepicker/jquery.timepicker.min.js\",\n        \"./libs/contextmenu/bootstrap-contextmenu.js\",\n        \"./libs/stop-watch/stop-watch.js\",\n        \"./store/signage_sdk.js\",\n        \"../node_modules/bootstrap/dist/js/bootstrap.js\",\n        \"../node_modules/bootbox/bootbox.js\",\n        \"../node_modules/platform/platform.js\",\n        \"./libs/fabric.require1-4-12.js\",\n        \"./libs/minicolors/jquery.minicolors.js\",\n        \"./libs/gradient/colorpicker.js\",\n        \"./libs/xml2js/xml2js.js\",\n        \"./libs/gradient/jquery.gradientpicker.js\",\n        \"./libs/enjoyhint/enjoyhint.js\",\n        \"../node_modules/xdate/src/xdate.js\",\n        \"./libs/ruler/ruler.js\"\n      ],\n      \"environmentSource\": \"environments/environment.ts\",\n      \"environments\": {\n        \"dev\": \"environments/environment.ts\",\n        \"hmr\": \"environments/environment.hmr.ts\",\n        \"prod\": \"environments/environment.prod.ts\"\n      }\n    }\n  ],\n  \"addons\": [\n    \"../node_modules/font-awesome/fonts/*.+(otf|eot|svg|ttf|woff|woff2)\",\n    \"./styles/fonts//montserrat.woff2\"\n  ],\n  \"packages\": [],\n  \"e2e\": {\n    \"protractor\": {\n      \"config\": \"./protractor.conf.js\"\n    }\n  },\n  \"test\": {\n    \"karma\": {\n      \"config\": \"./karma.conf.js\"\n    }\n  },\n  \"defaults\": {\n    \"styleExt\": \"css\",\n    \"prefixInterfaces\": false,\n    \"inline\": {\n      \"style\": false,\n      \"template\": false\n    },\n    \"spec\": {\n      \"class\": false,\n      \"component\": true,\n      \"directive\": true,\n      \"module\": false,\n      \"pipe\": true,\n      \"service\": true\n    }\n  }\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# Editor configuration, see http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\nmax_line_length = off\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".gitignore",
    "content": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n\n\n# compiled output\n/dist/*.js\n/dist/**\n/dist\n/tmp\n\n# dependencies\n/node_modules\n/bower_components\n\n# IDEs and editors\n/.idea\n/.idea/workspace.xml\n/.vscode\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n\n# misc\n/.sass-cache\n/documentation\n/connect.lock\n/coverage/*\n/libpeerconnection.log\nnpm-debug.log\ntestem.log\n/typings\n*.log.*\n\n#include\n!index.js\n!/typings\n\n\n# js/map\n*.js\nsrc/**/*.js\n*prod.js\nsrc/**/*.map\n#System Files\n.DS_Store\nThumbs.db\nworkspace.xml\n\n!signageSDK.js\n!service-worker.js\n!src/store/signage_sdk.js\n!src/libs/*\n!src/libs/**/*\n!src/locale/**/*\n#src/store/application.state.js\n#src/store/imsdb.interfaces.js\n#src/store/imsdb.interfaces_auto.js\n#src/store/store.data.js\n#*.xlf\n#*.xmb\n!temp/*.js\n!temp/*.txt\n"
  },
  {
    "path": "LICENSE",
    "content": "======================================================================\n\n                        MediaSignage Add-on license\n                      to GNU GENERAL PUBLIC LICENSE V3\n                                Jan 7, 2014\n\nMediaSignage Inc SignagePlayer open source under GPL V3 modified license.\nGPL V3 add-on License for MediaSignage Copyright (c) SignagePlayer\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"),\nto deal in the Software with some restriction as described in exhibit (A).\n\nThe SignagePlayer open source software is available without any warranty,\ndocumentation and support. The primary purpose of this software is:\n\nA) Educational: study of this product design and architecture\nB) Security: transparency into the inner workings of the mediaCLOUD and related apps\nC) All usage permitted only within the operation of the DigitalSignage.com mediaCLOUD\n   and only under MediaSignage Inc related products and services.\nD) Customization and modification which are governed under items A-C\n\nExhibit A:\n==========\nUsage, modification, compilation and any other benefit of the SignagePlayer\nsource code must come in a form of connection into the MediaSignage public mediaCLOUD\nservice or to a private mediaSERVER purchased from MediaSignage Inc.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\nINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE\n\n\n                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n\n"
  },
  {
    "path": "README.md",
    "content": "StudioLite, Digital Signage for the rest of us\n---------------------------------------\n\n<!-- [![NPM](https://nodei.co/npm/studiolite.png)](https://nodei.co/npm/studiolite/) -->\n\n<p align=\"center\">  \n  <img src=\"http://www.digitalsignage.com/files/techlogos.png\">\n</p>\n\n\n------------------------------------------------------------------------\n\nStudioLite is an open source, 100% FREE, Digital Signage platform that was designed with ease of use in mind.\nWith StudioLite anyone can have a Digital Signage solution that is entirely customizable. \nTake the source code, modify it, brand it and build a product that's right for you and your customers.\nBest of all, you will take full advantage of the world's most popular Digital Signage cloud so you don't have to worry about backend programming or even setup a server, it's all done for you using the mediaCLOUD.\n\n - Based on the poplar SignageStudio Pro ( [MediaSignage]: http://www.DigitalSignage.com )\n - Connected to a private mediaSERVER or the public free mediaCLOUD\n - 100% open source based on GNU V3 license\n - Contributors are welcome, fork, modify and send pull requests\n - Powered by Google's Angular Framework + TypeScript +  ngrx \n\nLinks:\n------------------------------------------------------------------------\n- StudioLite documentation: http://www.digitalsignage.com/lite_docs/\n- Cloud web app: http://go.digitalsignage.com\n- Home: http://lite.digitalsignage.com\n- Docs: http://www.digitalsignage.com/msdocs/\n- Support: http://script.digitalsignage.com/forum/index.php/board,9.0.html\n- Developer video tutorial: http://goo.gl/nkx7wr\n- StudioLite intro video: http://lite.digitalsignage.com/video1.html\n- StudioLite advanced  video: http://lite.digitalsignage.com/video2.html\n- Developers page: http://www.digitalsignage.com/_html/open_source_digital_signage.html\n- Angular: https://angular.io/\n\nTechnical data:\n------------------------------------------------------------------------\n- Build on top the latest version Google's Angular framework with a clean MV* design\n- Developed using the latest version of TypeScript and ngrx store\n- Powered by Bootstrap using responsive design for phones, tablets and desktops\n- Lazy loaded modules for best user load experience\n- Driven using Soap API and includes Helper SDK\n- Uses a local msdb (database) through SDK for offline work\n- Support Angular AOT mode\n- Support available through the MediaSignage support forum\n\nInstallation:\n------------------------------------------------------------------------\n\nStudioLite can be downloaded directly from GitHub\nWith git you will be able to easily update to the latest version of StudioLite as well as take advantage Angular CLI which is included in the bundle\n\ncurrently the application should run under:\n- typescript 2.4\n- node 6.x \n\nto install and host:\n\n``` npm install -g npm``` (this will ensure npm 5.4.2 >)\n\n\n```\ngit clone https://github.com/born2net/studio-lite.git\ncd studio-lite\nnpm install -g @angular/cli@latest\nnpm install\nopen browser to: http://localhost:4208/\n```\n\nCustomization:\n------------------------------------------------------------------------\nKeep in mind the SignageStudio lite as well as its related SDK Pepper are often released with new updates, so you will lose any changes you make to your code if you overwrite it with our release builds.\n\nTo overcome this you can follow these guidelines:\n\n1.\tAlways be sure to override files and not modify the original source file. This is true for both CSS and JavaScript code. Simply load your version of the CSS after ours to apply your latest changes. HTML files can be diffed (see below).\n2.\tOur code base is modulated and uses 100% object oriented design pattern. This allows you to sub class (aka inherit) from our classes and make your applied changes (use _.extend to mixin).\n3.\tYou can also use pre-processor scripts which replace code segments automatically using directives.\n4.\tAnd finally, even while following steps 1-3 you may find that your code is broken due to design changes in the original repository. That’s when GitHub comes to the rescue. When your fork the source repository, you can always merge the tree onto your forked project. Use source control diff tool to merge the changes into your code and resolve any conflicts.\n\nWith the above steps you can ensure that your source code is fully customizable while still keeping it synchronized with our ongoing development efforts.\nAnd if you built something wonderful, just send us a pull request so we check it out. \nIf we like what you did we we will merge it into our code base, so you will always receive it when you fetch our changes.\n\nIf you are not a developer you can hire professional, inexpensive help from sites like oDesk and Freelancer.\nSince Angular is an opinionated framework, any developer who is verse in Angular, will be able to quickly customize a solution for your own business logic. \n\nVideos:\n------------------------------------------------------------------------\n\n[![Development with StudioLite](http://img.youtube.com/vi/Znti-QVDjvg/0.jpg)](https://www.youtube.com/watch?v=Znti-QVDjvg&feature=youtu.be \"Advanced angular tips and tricks\")\n\n\nprevious version:\n------------------------------------------------------------------------\nIf you are looking for the previous version of StudioLite which was developed using BackboneJS, go to the branch:\n - https://github.com/born2net/studio-lite/tree/studiolite-backbone\n\nLicense:\n------------------------------------------------------------------------\nThe SignageStudio Web Lite and Pepper SDK are available under GPL\n - V3 https://github.com/born2net/studio-lite/blob/master/LICENSE\n\n\n\n"
  },
  {
    "path": "dev/notes.txt",
    "content": "////////////// NOTES ////////////////\n\n\n\nneed to find a way to remove core-js from videoangular definitions\nsed -i.bak '/core-js/d' './node_modules/videogular2/src/core/vg-media/i-playable.d.ts ; sed -i.bak '/core-js/d' './node_modules/videogular2/src/core/services/vg-api.d.ts'\n\n\nreload video:\nhttps://github.com/videogular/videogular2/issues/442\n\n\nnpm uninstall -g angular-cli @angular/cli\nnpm cache clean\nnpm install -g @angular/cli@latest\nOR\n\nnpm install -g @angular/cli@1.2.6\nnpm install -g @angular/cli@8.0.2\n\nLocal project package:\n\nrm -rf node_modules dist # use rmdir on Windows\nnpm install --save-dev @angular/cli@latest <<<<<<<<<<<<<<<<\nnpm install\n\n\nng init --ng4\n\n==================================================================================================================\n\n\n------------------------------------\n>>> switch to StudioLite global env:\n------------------------------------\nnvm use 6.16.0 ; node --version;\nrm -r -f /cygdrive/c/Program\\ Files/nodejs/node_modules/typescript;\ncp -r -f /cygdrive/c/Program\\ Files/nodejs/node_modules/typescript-2.4.2/ /cygdrive/c/Program\\ Files/nodejs/node_modules/typescript;\nnpm remove  -g @angular/cli ;  npm install -g @angular/cli@1.2.4;\n\n\n------------------------------------\n>>> switch to latest global env:\n------------------------------------\nnvm use 10.15.0 ; node --version;\nrm -r -f /cygdrive/c/Program\\ Files/nodejs/node_modules/typescript;\ncp -r -f /cygdrive/c/Program\\ Files/nodejs/node_modules/typescript-3.5.1/ /cygdrive/c/Program\\ Files/nodejs/node_modules/typescript;\nnpm remove  -g @angular/cli ; npm install -g @angular/cli@8.0.2;\n\n\n==================================================================================================================\n\n\ndebug sessions:\n\nreflection:\n    http://127.0.0.1:8080/src/create_reflection.html\n\nlocal:\n    http://localhost:4208/\n\ncampaigns:\n    http://localhost:4208/campaigns\n\nFasterqRemoteStatus (base64):\n    http://localhost:4208/index.html?mode=remoteStatus&param=eyJjYWxsX3R5cGUiOiJFTUFJTCIsInNlcnZpY2VfaWQiOjE5LCJ2ZXJpZmljYXRpb24iOjY5NSwibGluZV9pZCI6IjIxMTAiLCJsaW5lX25hbWUiOiIgbmV3IGxpbmUgMSIsImJ1c2luZXNzX2lkIjoiMzU4NjEzIiwic21zIjoiIiwiZW1haWwiOiJib3JuMm5ldEBnbWFpbC5jb20iLCJkYXRlIjoiNC83LzIwMTcifQ==\n\nFasterqTerminal (rc4):\n    http://localhost:4208/index.html?data=5b6bcb27d4547657cfe4e021e1c6761fe8b4a33c3d62983ee8f6b0ccbded7b8a6578e47862f0aca0ca7ac070a1a27121fe17f5c496483ee08cf0a061440f277a3e49dcaaf3bb198c71033ed398d60166e3b82c9153f4c3a6d346f7d11b3016\n\nauto-login local demo_lite\n\thttp://localhost:4208/index.html?param=dXNlcj1kZW1vX2xpdGVAbXMuY29tLHBhc3M9cGFzc3dvcmQ=\n\nauto-login remote demo_lite\n\thttps://secure.digitalsignage.com/studioweb/index.html?param=dXNlcj1kZW1vX2xpdGVAbXMuY29tLHBhc3M9cGFzc3dvcmQ=\n\nauto-login local lite22\n\thttp://localhost:4208/index.html?param=dXNlcj1saXRlMjJAbXMuY29tLHBhc3M9MTIzMTIz\n\nauto-login local lite90\n\thttp://localhost:4208/index.html?param=dXNlcj1saXRlOTBAbXMuY29tLHBhc3M9MTIzMTIz\n\nauto-login local lite28\n\thttp://localhost:4208/index.html?param=dXNlcj1saXRlMjhAbXMuY29tLHBhc3M9MTIzMTIz\n\n==================================================================================================================\n\nrevert webpack ng tools: npm install --save @ngtools/webpack@1.2.4\n\n\n==================================================================================================================\n\n\nclear cache: npm clear cache\n\nnpm install @angular/cli@latest -g\nnpm install -g @angular/cli\n\n\n==================================================================================================================\n\nreflection Usage:\n\nto run this script and generate interface sdk / msdb:\n\nrun live-server inside /cygdrive/c/msweb/studiolite\n\nopen browser to:\n\nhttp://127.0.0.1:8080/src/create_reflection.html\n\n\n==================================================================================================================\n\nSwitching fabric versions:\n\nadd/remove import \"fabric\"; from app-modules.ts\nadd/remove form angular-cli.json:\n\"../node_modules/fabric/dist/fabric.js\"\nor \nangular-cli.json: \"./libs/fabric.require1-4-12.js\",\nor\nto load remotely:\n<script src=\"https://secure.digitalsignage.com/studioweb/fabric1-4-2.min.js\"></script>\n<script src=\"https://secure.digitalsignage.com/studioweb/fabric.require1-4-12.min.js\"></script>\n\n==================================================================================================================\n\n\n<!--<script src=\"https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/shim.min.js\"></script>-->\n<!--<script>-->\n    <!--(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){-->\n            <!--(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),-->\n        <!--m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)-->\n    <!--})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');-->\n\n    <!--ga('create', 'UA-36671151-9', 'auto');-->\n    <!--ga('send', 'pageview');-->\n<!--</script>-->\n\n==================================================================================================================\n\nfor translation:\n\n1. release_aot > to generate all ./dist files in english\n2. x_translate > to create an english version of ./src/local/messages.xmb\n3. develop_new_script > to generate ./src/local/hebrew.xtb from messages.xmb (use server API)\n    https://secure.digitalsignage.com/getLocal/he/xxx/go%20find%20me%20and%20bring%20me%20here\n4. release_aot_hebrew > to create new StudioLite in hebrew and upload to specific local server dir"
  },
  {
    "path": "e2e/app.e2e-spec.ts",
    "content": "import { NgKitchenSinkPage } from './app.po';\n\ndescribe('ng-kitchen-sink App', function() {\n  let page: NgKitchenSinkPage;\n\n  beforeEach(() => {\n    page = new NgKitchenSinkPage();\n  });\n\n  it('should display message saying app works', () => {\n    page.navigateTo();\n    expect(page.getParagraphText()).toEqual('app works!');\n  });\n});\n"
  },
  {
    "path": "e2e/app.po.ts",
    "content": "import { browser, element, by } from 'protractor';\n\nexport class NgKitchenSinkPage {\n  navigateTo() {\n    return browser.get('/');\n  }\n\n  getParagraphText() {\n    return element(by.css('app-root h1')).getText();\n  }\n}\n"
  },
  {
    "path": "e2e/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"declaration\": false,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"../dist/out-tsc-e2e\",\n    \"sourceMap\": true,\n    \"target\": \"es5\",\n    \"typeRoots\": [\n      \"../node_modules/@types\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/adStatsSample.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Report>\n   <Fields>\n      <ExtStat>stationId,packageId,packageContentId,packageName,contentName,day,hour,counts,duration,mph,rate</ExtStat>\n      <LocalStat>stationId,localContentId,day,hour,counts,duration,mph,rate</LocalStat>\n   </Fields>\n   <Data>\n      <Domain name=\"signage.me\">\n         <Business businessId=\"367626\">\n            <LocalStat>14,136,3,8,9,1214.9,0.221447,0</LocalStat>\n            <LocalStat>14,136,3,9,14,1889.8,0.442799,0</LocalStat>\n            <LocalStat>14,136,3,10,14,1856.2,0.383568,0</LocalStat>\n            <LocalStat>14,136,3,11,14,1890.1,0.456984,0</LocalStat>\n            <LocalStat>14,136,3,12,14,1848.5,0.41431,0</LocalStat>\n            <LocalStat>14,136,3,13,13,1754.9,0.39168,0</LocalStat>\n            <LocalStat>14,136,3,14,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,3,15,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,3,16,14,1890.1,0.456983,0</LocalStat>\n            <LocalStat>14,136,3,17,14,1890,0.45696,0</LocalStat>\n            <LocalStat>14,136,3,18,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,3,19,14,1890.1,0.456984,0</LocalStat>\n            <LocalStat>14,136,3,20,14,1890,0.45696,0</LocalStat>\n            <LocalStat>14,136,3,21,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,3,22,15,2025.3,0.489672,0</LocalStat>\n            <LocalStat>14,136,3,23,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,0,14,1890.3,0.457031,0</LocalStat>\n            <LocalStat>14,136,4,1,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,4,2,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,4,3,14,1890.2,0.457007,0</LocalStat>\n            <LocalStat>14,136,4,4,14,1890.1,0.456984,0</LocalStat>\n            <LocalStat>14,136,4,5,14,1889.9,0.42432,0</LocalStat>\n            <LocalStat>14,136,4,6,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,7,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,8,14,1890.2,0.457007,0</LocalStat>\n            <LocalStat>14,136,4,9,14,1890,0.45696,0</LocalStat>\n            <LocalStat>14,136,4,10,15,2024.9,0.489575,0</LocalStat>\n            <LocalStat>14,136,4,11,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,12,14,1889.7,0.42427,0</LocalStat>\n            <LocalStat>14,136,4,13,14,1889.6,0.45686,0</LocalStat>\n            <LocalStat>14,136,4,14,14,1890,0.456959,0</LocalStat>\n            <LocalStat>14,136,4,15,14,1889.7,0.456885,0</LocalStat>\n            <LocalStat>14,136,4,16,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,17,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,18,14,1890,0.45696,0</LocalStat>\n            <LocalStat>14,136,4,19,15,2024.9,0.489575,0</LocalStat>\n            <LocalStat>14,136,4,20,14,1889.9,0.456934,0</LocalStat>\n            <LocalStat>14,136,4,21,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,4,22,14,1889.8,0.45691,0</LocalStat>\n            <LocalStat>14,136,4,23,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,5,0,14,1889.9,0.456935,0</LocalStat>\n            <LocalStat>14,136,5,1,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,5,2,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,5,3,14,1890,0.456959,0</LocalStat>\n            <LocalStat>14,136,5,4,14,1889.7,0.456885,0</LocalStat>\n            <LocalStat>14,136,5,5,14,1890.1,0.424368,0</LocalStat>\n            <LocalStat>14,136,5,6,14,1890,0.45696,0</LocalStat>\n            <LocalStat>14,136,5,7,14,1890,0.45696,0</LocalStat>\n            <LocalStat>14,136,5,8,13,1716.2,0.349707,0</LocalStat>\n            <LocalStat>14,136,5,9,14,1890.2,0.457008,0</LocalStat>\n            <LocalStat>14,136,5,10,9,1215.3,0.293832,0</LocalStat>\n            <LocalStat>14,136,7,12,2,27.4,0,0</LocalStat>\n            <LocalStat>14,136,7,13,13,1756.2,0.391992,0</LocalStat>\n            <LocalStat>14,136,7,14,14,1891.8,0.457392,0</LocalStat>\n            <LocalStat>14,136,7,15,15,2026.4,0.489936,0</LocalStat>\n            <LocalStat>14,136,7,16,14,1892,0.45744,0</LocalStat>\n            <LocalStat>14,136,7,17,14,1892.3,0.457512,0</LocalStat>\n            <LocalStat>14,136,7,18,14,1891.5,0.45732,0</LocalStat>\n            <LocalStat>14,136,7,19,14,1891.2,0.457248,0</LocalStat>\n            <LocalStat>14,136,7,20,14,1891.2,0.457248,0</LocalStat>\n            <LocalStat>14,136,7,21,14,1891.5,0.45732,0</LocalStat>\n            <LocalStat>14,136,7,22,14,1891.4,0.457296,0</LocalStat>\n            <LocalStat>14,136,7,23,14,1891.5,0.45732,0</LocalStat>\n            <LocalStat>14,136,8,0,14,1891.7,0.457368,0</LocalStat>\n            <LocalStat>14,136,8,1,14,1891.8,0.457391,0</LocalStat>\n            <LocalStat>14,136,8,2,14,1891.1,0.457224,0</LocalStat>\n            <LocalStat>14,136,8,3,15,2026.7,0.490008,0</LocalStat>\n            <LocalStat>14,136,8,4,13,1756.8,0.424752,0</LocalStat>\n            <LocalStat>14,136,8,5,14,1889.9,0.424319,0</LocalStat>\n            <LocalStat>14,136,8,6,14,1889.7,0.456884,0</LocalStat>\n            <LocalStat>14,136,8,7,14,1890.1,0.456984,0</LocalStat>\n            <LocalStat>14,136,8,8,13,1755,0.391703,0</LocalStat>\n            <LocalStat>14,136,8,9,14,1889.8,0.45691,0</LocalStat>\n            <LocalStat>14,136,8,10,15,2025,0.489599,0</LocalStat>\n            <LocalStat>14,136,8,11,4,539.9,0.130535,0</LocalStat>\n            <LocalStat>14,136,8,12,9,1047.5,0.195815,0</LocalStat>\n            <LocalStat>14,136,8,13,2,515.1,0.124539,0</LocalStat>\n            <LocalStat>14,137,3,8,8,481,0.112702,0</LocalStat>\n            <LocalStat>14,137,3,9,15,901.5,0.21123,0</LocalStat>\n            <LocalStat>14,137,3,10,12,699.9,0.165785,0</LocalStat>\n            <LocalStat>14,137,3,11,14,841.9,0.203545,0</LocalStat>\n            <LocalStat>14,137,3,12,13,781.4,0.188915,0</LocalStat>\n            <LocalStat>14,137,3,13,13,781.4,0.188916,0</LocalStat>\n            <LocalStat>14,137,3,14,14,841.5,0.203446,0</LocalStat>\n            <LocalStat>14,137,3,15,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,137,3,16,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,3,17,15,901.8,0.218025,0</LocalStat>\n            <LocalStat>14,137,3,18,14,841.3,0.203397,0</LocalStat>\n            <LocalStat>14,137,3,19,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,3,20,14,841.6,0.203471,0</LocalStat>\n            <LocalStat>14,137,3,21,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,3,22,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,3,23,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,137,4,0,14,841.3,0.203397,0</LocalStat>\n            <LocalStat>14,137,4,1,14,841.5,0.203447,0</LocalStat>\n            <LocalStat>14,137,4,2,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,137,4,3,15,901.6,0.217976,0</LocalStat>\n            <LocalStat>14,137,4,4,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,137,4,5,14,841.7,0.203495,0</LocalStat>\n            <LocalStat>14,137,4,6,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,4,7,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,4,8,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,9,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,10,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,11,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,4,12,14,813.4,0.196651,0</LocalStat>\n            <LocalStat>14,137,4,13,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,14,15,901.2,0.217878,0</LocalStat>\n            <LocalStat>14,137,4,15,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,16,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,4,17,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,18,14,841.2,0.203372,0</LocalStat>\n            <LocalStat>14,137,4,19,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,4,20,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,4,21,14,841.2,0.203372,0</LocalStat>\n            <LocalStat>14,137,4,22,14,840.9,0.2033,0</LocalStat>\n            <LocalStat>14,137,4,23,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,5,0,15,901.3,0.217902,0</LocalStat>\n            <LocalStat>14,137,5,1,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,5,2,14,841.2,0.203372,0</LocalStat>\n            <LocalStat>14,137,5,3,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,137,5,4,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,5,5,13,781.3,0.18889,0</LocalStat>\n            <LocalStat>14,137,5,6,15,901.4,0.217926,0</LocalStat>\n            <LocalStat>14,137,5,7,14,841.2,0.203372,0</LocalStat>\n            <LocalStat>14,137,5,8,11,637.2,0.154052,0</LocalStat>\n            <LocalStat>14,137,5,9,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,5,10,9,540.9,0.13077,0</LocalStat>\n            <LocalStat>14,137,7,13,13,782.8,0.18926,0</LocalStat>\n            <LocalStat>14,137,7,14,14,843.1,0.203841,0</LocalStat>\n            <LocalStat>14,137,7,15,14,842.7,0.203742,0</LocalStat>\n            <LocalStat>14,137,7,16,14,842.8,0.203765,0</LocalStat>\n            <LocalStat>14,137,7,17,14,842.7,0.203741,0</LocalStat>\n            <LocalStat>14,137,7,18,14,842.3,0.203643,0</LocalStat>\n            <LocalStat>14,137,7,19,14,842.8,0.203765,0</LocalStat>\n            <LocalStat>14,137,7,20,14,843.1,0.203839,0</LocalStat>\n            <LocalStat>14,137,7,21,15,904,0.218564,0</LocalStat>\n            <LocalStat>14,137,7,22,14,842.6,0.203717,0</LocalStat>\n            <LocalStat>14,137,7,23,14,842.7,0.203741,0</LocalStat>\n            <LocalStat>14,137,8,0,14,842.5,0.203693,0</LocalStat>\n            <LocalStat>14,137,8,1,14,842.9,0.203792,0</LocalStat>\n            <LocalStat>14,137,8,2,14,842.3,0.203642,0</LocalStat>\n            <LocalStat>14,137,8,3,14,842.8,0.203767,0</LocalStat>\n            <LocalStat>14,137,8,4,14,842.1,0.203595,0</LocalStat>\n            <LocalStat>14,137,8,5,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,8,6,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,8,7,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,137,8,8,13,781.2,0.188866,0</LocalStat>\n            <LocalStat>14,137,8,9,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,8,10,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,137,8,11,5,300.5,0.07265,0</LocalStat>\n            <LocalStat>14,137,8,12,6,360.6,0.08718,0</LocalStat>\n            <LocalStat>14,137,8,13,1,60.1,0.01453,0</LocalStat>\n            <LocalStat>14,138,3,8,7,420.7,0.098574,0</LocalStat>\n            <LocalStat>14,138,3,9,14,841.3,0.197123,0</LocalStat>\n            <LocalStat>14,138,3,10,12,721.4,0.170824,0</LocalStat>\n            <LocalStat>14,138,3,11,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,138,3,12,13,781.5,0.18894,0</LocalStat>\n            <LocalStat>14,138,3,13,13,781.3,0.18889,0</LocalStat>\n            <LocalStat>14,138,3,14,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,3,15,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,138,3,16,14,841.7,0.203495,0</LocalStat>\n            <LocalStat>14,138,3,17,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,3,18,14,841.6,0.203471,0</LocalStat>\n            <LocalStat>14,138,3,19,15,901.8,0.218025,0</LocalStat>\n            <LocalStat>14,138,3,20,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,138,3,21,14,841.5,0.203446,0</LocalStat>\n            <LocalStat>14,138,3,22,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,3,23,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,4,0,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,138,4,1,14,841.3,0.203397,0</LocalStat>\n            <LocalStat>14,138,4,2,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,3,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,138,4,4,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,4,5,13,781.4,0.188915,0</LocalStat>\n            <LocalStat>14,138,4,6,14,841.2,0.203373,0</LocalStat>\n            <LocalStat>14,138,4,7,14,841.5,0.203445,0</LocalStat>\n            <LocalStat>14,138,4,8,15,901.6,0.217975,0</LocalStat>\n            <LocalStat>14,138,4,9,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,10,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,4,11,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,12,13,781.2,0.188866,0</LocalStat>\n            <LocalStat>14,138,4,13,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,138,4,14,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,15,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,138,4,16,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,4,17,15,901.7,0.218,0</LocalStat>\n            <LocalStat>14,138,4,18,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,19,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,20,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,21,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,4,22,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,4,23,14,841.2,0.203372,0</LocalStat>\n            <LocalStat>14,138,5,0,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,138,5,1,14,841.3,0.203396,0</LocalStat>\n            <LocalStat>14,138,5,2,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,5,3,15,901.5,0.217952,0</LocalStat>\n            <LocalStat>14,138,5,4,14,841.5,0.203445,0</LocalStat>\n            <LocalStat>14,138,5,5,13,781.2,0.188866,0</LocalStat>\n            <LocalStat>14,138,5,6,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,5,7,14,841.5,0.203445,0</LocalStat>\n            <LocalStat>14,138,5,8,11,661.2,0.159855,0</LocalStat>\n            <LocalStat>14,138,5,9,14,841.6,0.20347,0</LocalStat>\n            <LocalStat>14,138,5,10,9,541,0.130795,0</LocalStat>\n            <LocalStat>14,138,7,13,13,782.7,0.189236,0</LocalStat>\n            <LocalStat>14,138,7,14,14,842.8,0.203766,0</LocalStat>\n            <LocalStat>14,138,7,15,14,843.1,0.203838,0</LocalStat>\n            <LocalStat>14,138,7,16,14,842.9,0.20379,0</LocalStat>\n            <LocalStat>14,138,7,17,14,842.5,0.203693,0</LocalStat>\n            <LocalStat>14,138,7,18,14,843.3,0.203888,0</LocalStat>\n            <LocalStat>14,138,7,19,14,842.9,0.203791,0</LocalStat>\n            <LocalStat>14,138,7,20,14,843.1,0.203841,0</LocalStat>\n            <LocalStat>14,138,7,21,14,843,0.203814,0</LocalStat>\n            <LocalStat>14,138,7,22,14,843.2,0.203865,0</LocalStat>\n            <LocalStat>14,138,7,23,14,843,0.203815,0</LocalStat>\n            <LocalStat>14,138,8,0,15,902.7,0.218248,0</LocalStat>\n            <LocalStat>14,138,8,1,14,842.4,0.203669,0</LocalStat>\n            <LocalStat>14,138,8,2,14,843.1,0.203837,0</LocalStat>\n            <LocalStat>14,138,8,3,14,842.4,0.203667,0</LocalStat>\n            <LocalStat>14,138,8,4,14,842.8,0.203766,0</LocalStat>\n            <LocalStat>14,138,8,5,13,781.1,0.188842,0</LocalStat>\n            <LocalStat>14,138,8,6,14,841.4,0.20342,0</LocalStat>\n            <LocalStat>14,138,8,7,14,841.4,0.203421,0</LocalStat>\n            <LocalStat>14,138,8,8,14,793.3,0.191791,0</LocalStat>\n            <LocalStat>14,138,8,9,14,841.3,0.203397,0</LocalStat>\n            <LocalStat>14,138,8,10,14,841.5,0.203445,0</LocalStat>\n            <LocalStat>14,138,8,11,4,240.4,0.05812,0</LocalStat>\n            <LocalStat>14,138,8,12,6,360.8,0.08723,0</LocalStat>\n            <LocalStat>14,138,8,13,1,60.1,0.01453,0</LocalStat>\n            <LocalStat>18,136,2,15,2,269.9,0.06324,0</LocalStat>\n            <LocalStat>18,136,2,16,1,134.9,0.031608,0</LocalStat>\n            <LocalStat>18,137,2,15,1,60,0.014058,0</LocalStat>\n            <LocalStat>18,137,2,16,2,120.1,0.02814,0</LocalStat>\n            <LocalStat>18,138,2,15,2,120.1,0.02814,0</LocalStat>\n            <LocalStat>18,138,2,16,2,120,0.028116,0</LocalStat>\n            <LocalStat>19,136,3,12,1,134.9,0,0</LocalStat>\n            <LocalStat>19,136,3,13,14,1398.6,0.156452,0</LocalStat>\n            <LocalStat>19,136,3,16,2,270.3,0.032736,0</LocalStat>\n            <LocalStat>19,136,4,13,7,9960.4,2.301675,0</LocalStat>\n            <LocalStat>19,137,3,12,1,66.1,0.015981,0</LocalStat>\n            <LocalStat>19,137,3,13,5,304.1,0.073522,0</LocalStat>\n            <LocalStat>19,137,3,16,1,60.5,0.014627,0</LocalStat>\n            <LocalStat>19,137,4,13,4,244.5,0.059113,0</LocalStat>\n            <LocalStat>19,138,3,12,1,93.9,0.022702,0</LocalStat>\n            <LocalStat>19,138,3,13,5,303.3,0.073329,0</LocalStat>\n            <LocalStat>19,138,3,16,1,61.2,0.014796,0</LocalStat>\n            <LocalStat>19,138,4,13,4,185.6,0.044872,0</LocalStat>\n         </Business>\n      </Domain>\n   </Data>\n</Report>"
  },
  {
    "path": "examples/apps_table.txt",
    "content": "app_id\tapp_name\thelp_name\tdescription\tuninstallable\thidden\tprice\tmin_version\n10005\tEmbeded Resource\t\"\"\tEmbeded Resource\tFalse\tTrue\t0\t4.12\n10010\tScene\t\"\"\tScene\tFalse\tTrue\t0\t4.12\n10020\tExternal Resource\t\"\"\tExternal Resource\tFalse\tFalse\t0\t4.12\n10030\tLabel\t\"\"\tLabel\tFalse\tFalse\t0\t4.12\n10040\tHtml\t\"\"\tHtml\tFalse\tFalse\t0\t4.12\n10050\tRss Text\t\"\"\tRss Text\tFalse\tFalse\t0\t4.12\n10060\tCustom Rss\t\"\"\tCustom Rss\tFalse\tFalse\t0\t4.12\n10070\tMedia Rss/Podcast\t\"\"\tMedia Rss/Podcast\tFalse\tFalse\t0\t4.12\n10080\tWeather\t\"\"\tWeather\tFalse\tFalse\t0\t4.12\n10090\tStock\t\"\"\tStock\tFalse\tFalse\t0\t4.12\n10100\tCatalog\t\"\"\tCatalog\tFalse\tFalse\t0\t4.12\n10110\tCapture/Camera\t\"\"\tCapture/Camera\tTrue\tFalse\t0\t4.12\n10120\tClock\t\"\"\tClock\tTrue\tFalse\t0\t4.12\n10122\tCountdown\t\"\"\tCountdown\tTrue\tFalse\t0\t4.12\n10130\tGrid/Chart\t\"\"\tGrid/Chart\tTrue\tFalse\t0\t4.12\n10140\tExt Application\t\"\"\tExt Application\tTrue\tFalse\t0\t4.12\n10145\tWebkit\t\"\"\tWebkit\tTrue\tFalse\t0\t4.33\n10150\tAdvertising\t\"\"\tAdvertising\tTrue\tFalse\t0\t4.12\n10160\tQR Code\t\"\"\tQR Code\tTrue\tFalse\t0\t4.12\n10180\tCollectionViewer\t\"\"\tCollectionViewer\tTrue\tFalse\t0\t4.12\n10185\tLocation based\t\"\"\tLocation based\tTrue\tFalse\t0\t4.33\n10190\tXML Player\t\"\"\tXML Player\tTrue\tFalse\t0\t4.12\n10195\tJSON Player\t\"\"\tJSON Player\tTrue\tFalse\t0\t4.33\n10210\tTwitter\t\"\"\tTwitter\tTrue\tFalse\t0\t4.12\n10220\tYouTube\t\"\"\tYouTube\tTrue\tFalse\t0\t4.12\n10300\tForm\t\"\"\tForm\tTrue\tFalse\t0\t4.12\n10400\tMessage\t\"\"\tMessage\tTrue\tFalse\t0\t4.12\n10500\tLabel Queue\t\"\"\tLabel Queue\tTrue\tFalse\t0\t4.15\n11000\tBrowser\t\"\"\tBrowser\tTrue\tFalse\t0\t4.33\n12000\tDigg\t\"\"\tDigg\tTrue\tFalse\t0\t4.33\n12010\tWorld weather\t\"\"\tWeather\tTrue\tFalse\t0\t4.33\n12020\tFacebook\t\"\"\tFacebook\tTrue\tFalse\t0\t4.33\n12030\tGoogle calendar\t\"\"\tGoogle calendar\tTrue\tFalse\t0\t4.33\n12032\tGoogle Sheets\t\"\"\tGoogle Sheets\tTrue\tFalse\t0\t4.33\n12040\tGoogle plus\t\"\"\tGoogle plus\tTrue\tFalse\t0\t4.33\n12050\tPicasa\t\"\"\tPicasa\tTrue\tFalse\t0\t4.33\n12060\tInstagram\t\"\"\tInstagram\tTrue\tFalse\t0\t4.33\n12070\tGoogle drive\t\"\"\tGoogle drive\tTrue\tFalse\t0\t4.33\n12080\t500px\t\"\"\t500px\tTrue\tFalse\t0\t4.33\n12090\tPinterest\t\"\"\tPinterest\tTrue\tFalse\t0\t4.33\n12100\tFasterQ\t\"\"\tFasterQ\tTrue\tFalse\t0\t4.33\n12200\tTumblr\t\"\"\tTumblr\tTrue\tFalse\t0\t4.33\n12210\tDropbox\t\"\"\tDropbox\tTrue\tFalse\t0\t4.33\n12220\tFlickr\t\"\"\tFlickr\tTrue\tFalse\t0\t4.33\n12230\tTwitter\t\"\"\tTwitter\tTrue\tFalse\t0\t4.33\n12240\tYelp\t\"\"\tYelp\tTrue\tFalse\t0\t4.33\n12250\tEtsy\t\"\"\tEtsy\tTrue\tFalse\t0\t4.33\n12260\tMashape\t\"\"\tMashape\tTrue\tFalse\t0\t4.33"
  },
  {
    "path": "examples/calendar_google.xml",
    "content": "scene\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"Cal Scene\" interactive=\"0\" mimeType=\"Json.calendar\" id=\"YmxvY2tpZDgy\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDgz\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"58\" y=\"103\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"summary\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDg0\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"145\" y=\"234\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"endDateTime_time\" fieldType=\"date\" dateFormat=\"MM/DD/YY\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDg1\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"245\" y=\"67\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"startDateTime_time\" fieldType=\"date\" dateFormat=\"MM/DD/YY\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDg2\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"19\" y=\"259\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"organizerEmail\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>\n\n\n\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDgz\">\n   <Data>\n      <Layout rotation=\"0\" x=\"58\" y=\"103\" width=\"100\" height=\"100\" />\n      <XmlItem fieldName=\"summary\" fieldType=\"text\">\n         <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n      </XmlItem>\n   </Data>\n</Player>\n\n\n\nPlayer\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6020\" label=\"\" interactive=\"0\">\n   <Data>\n      <Json providerType=\"calendar\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"5\" playVideoInFull=\"1\" randomOrder=\"1\">\n         <Player src=\"45\" hDataSrc=\"16\" />\n         <Data token=\"22222222222222222222\" mode=\"offset\" before=\"3\" after=\"6\" startDate=\"1449691200000\" endDate=\"1450209600000\" />\n      </Json>\n   </Data>\n</Player>\n\n\n\nplayer\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6020\" label=\"\" interactive=\"0\">\n   <Data>\n      <Json providerType=\"calendar\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"5\" playVideoInFull=\"1\" randomOrder=\"1\">\n         <Player src=\"45\" hDataSrc=\"16\" />\n         <Data token=\"uuuuuuuuuuuuuuuuu\" mode=\"fixed\" startDate=\"1450382400000\" endDate=\"1452974400000\" />\n      </Json>\n   </Data>\n</Player>\n\n\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6020\" label=\"\" interactive=\"0\">\n   <Data>\n      <Json providerType=\"calendar\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"5\" playVideoInFull=\"1\" randomOrder=\"1\">\n         <Player src=\"45\" hDataSrc=\"16\" />\n         <Data token=\"8c0f2d56-e77c-4977-8433-b3ba99a7eb4b\" mode=\"offset\" before=\"3\" after=\"6\" startDate=\"1449691200000\" endDate=\"1450209600000\" id=\"#contacts@group.v.calendar.google.com\" />\n      </Json>\n   </Data>\n</Player>\n"
  },
  {
    "path": "examples/collection.xml",
    "content": "\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"4100\" label=\"Collection\" interactive=\"0\">\n   <Data>\n      <EventCommands>\n         <EventCommand from=\"ev1\" condition=\"\" command=\"firstPage\" />\n         <EventCommand from=\"ev2\" condition=\"\" command=\"nextPage\" />\n         <EventCommand from=\"ev3\" condition=\"\" command=\"lastPage\" />\n         <EventCommand from=\"ev4\" condition=\"\" command=\"selectPage\">\n            <Params>\n               <Page name=\"page4\" />\n            </Params>\n         </EventCommand>\n         <EventCommand from=\"ev5\" condition=\"\" command=\"selectPage\">\n            <Params>\n               <Page name=\"page5\" />\n            </Params>\n         </EventCommand>\n      </EventCommands>\n      <Collection mode=\"kiosk\" duration=\"10\">\n         <Page page=\"page1\" type=\"resource\" duration=\"11\">\n            <Player player=\"3130\">\n               <Data>\n                  <Resource resource=\"11\" hResource=\"4\" />\n               </Data>\n            </Player>\n            <AdLocalContent id=\"1\" handle=\"0\" />\n         </Page>\n         <Page page=\"page3\" type=\"resource\" duration=\"312\">\n            <Player player=\"3130\">\n               <Data>\n                  <Resource resource=\"14\" hResource=\"6\" />\n               </Data>\n            </Player>\n         </Page>\n         <Page page=\"page4\" type=\"resource\" duration=\"22\">\n            <Player player=\"3130\">\n               <Data>\n                  <Resource resource=\"15\" hResource=\"7\" />\n               </Data>\n            </Player>\n         </Page>\n         <Page page=\"page5\" type=\"scene\" duration=\"42\">\n            <Player src=\"1\" hDataSrc=\"0\" />\n         </Page>\n         <Page page=\"page2\" type=\"resource\" duration=\"22\">\n            <Player player=\"3130\">\n               <Data>\n                  <Resource resource=\"13\" hResource=\"5\" />\n               </Data>\n            </Player>\n         </Page>\n      </Collection>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/collection_scene.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"collection scene\" interactive=\"0\" id=\"YmxvY2tpZDg3\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4100\" label=\"Collection\" interactive=\"0\" id=\"YmxvY2tpZDg4\">\n               <Data>\n                  <TransitionPool handle=\"0\" />\n                  <Layout rotation=\"0\" x=\"92\" y=\"81\" width=\"100\" height=\"100\" />\n                  <Collection mode=\"slideshow\" duration=\"2\">\n                     <Page page=\"page1\" type=\"resource\">\n                        <Player player=\"3130\" id=\"YmxvY2tpZDg5\">\n                           <Data>\n                              <Resource resource=\"21\" hResource=\"0\" />\n                           </Data>\n                        </Player>\n                     </Page>\n                     <Page page=\"page2\" type=\"resource\">\n                        <Player player=\"3130\" id=\"YmxvY2tpZDkw\">\n                           <Data>\n                              <Resource resource=\"22\" hResource=\"1\" />\n                           </Data>\n                        </Player>\n                     </Page>\n                     <Page page=\"page3\" type=\"resource\">\n                        <Player player=\"3130\" id=\"YmxvY2tpZDkx\">\n                           <Data>\n                              <Resource resource=\"24\" hResource=\"3\" />\n                           </Data>\n                        </Player>\n                     </Page>\n                     <Page page=\"page4\" type=\"resource\">\n                        <Player player=\"3130\" id=\"YmxvY2tpZDky\">\n                           <Data>\n                              <Resource resource=\"25\" hResource=\"4\" />\n                           </Data>\n                        </Player>\n                     </Page>\n                  </Collection>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/digg.xml",
    "content": "Scene:\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"Digg cene\" interactive=\"0\" mimeType=\"Json.digg\" id=\"YmxvY2tpZDU3\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDU4\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"96\" y=\"131\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"title\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDU5\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"232\" y=\"102\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"link\" fieldType=\"resource\" maintainAspectRatio=\"1\" />\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>\n\n\nPlayer:\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6000\" label=\"Digg\" interactive=\"0\">\n   <Data>\n      <Json providerType=\"digg\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"7\" playVideoInFull=\"1\" randomOrder=\"1\">\n         <Player src=\"33\" hDataSrc=\"10\" />\n         <Data />\n      </Json>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/googlesheets.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"Sheets\" interactive=\"0\" mimeType=\"Json.spreadsheet\" id=\"YmxvY2tpZDI2\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDI3\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"64\" y=\"94\" width=\"249\" height=\"79\" />\n                  <XmlItem fieldName=\"$cells.13.4.value\" fieldType=\"text\">\n                     <Font fontSize=\"14\" fontColor=\"204\" fontFamily=\"Arial\" fontWeight=\"bold\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/instagram_feed.xml",
    "content": "scene:\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"insat feed\" interactive=\"0\" mimeType=\"Json.instagram.feed\" id=\"YmxvY2tpZDc3\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc4\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"54\" y=\"48\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"title\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc5\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"30\" y=\"198\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"video\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDgw\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"218\" y=\"36\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"urlImage\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>\n\nplayer:\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6050\" iconName=\"player6050Icon\" label=\"\">\n   <Data>\n      <Json providerType=\"instagram.feed\">\n         <Player src=\"43\" hDataSrc=\"15\" />\n      </Json>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/jsonItem.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"json scene\" interactive=\"0\" id=\"YmxvY2tpZDY3\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY4\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"36\" y=\"38\" width=\"307\" height=\"51\" />\n                  <XmlItem fieldName=\"text\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"6710886\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY5\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"166\" y=\"202\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"someResource\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDcw\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"36\" y=\"202\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"title\" fieldType=\"date\" dateFormat=\"YY/EE\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/jsonPlayer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"4300\" label=\"json\" interactive=\"0\">\n   <Data>\n      <EventCommands>\n         <EventCommand from=\"ev1\" condition=\"\" command=\"loadUrl\">\n            <Params>\n               <Url name=\"http://www.google.com\" />\n            </Params>\n         </EventCommand>\n         <EventCommand from=\"ev2\" condition=\"\" command=\"firstPage\" />\n         <EventCommand from=\"ev3\" condition=\"\" command=\"firstPage\" />\n         <EventCommand from=\"ev4\" condition=\"\" command=\"nextPage\" />\n         <EventCommand from=\"ev5\" condition=\"\" command=\"lastPage\" />\n      </EventCommands>\n      <Appearance alpha=\"1\" blendMode=\"normal\" />\n      <Border borderThickness=\"0\" borderColor=\"65535\" cornerRadius=\"0\" />\n      <Background style=\"Gradient\" gradientType=\"linear\" angle=\"0\" offsetX=\"0\" offsetY=\"0\">\n         <GradientPoints>\n            <Point color=\"4361162\" opacity=\"1\" midpoint=\"125\" />\n         </GradientPoints>\n      </Background>\n      <Json providerType=\"\" itemsPath=\"ZZ\" slideShow=\"1\" itemInterval=\"12\" playVideoInFull=\"1\" randomOrder=\"1\" url=\"XX\">\n         <Player src=\"7\" hDataSrc=\"2\" />\n         <Data />\n      </Json>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/json_as3_maps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ms:PlayerPage xmlns:fx=\"http://ns.adobe.com/mxml/2009\"\n\t\t\t   xmlns:s=\"library://ns.adobe.com/flex/spark\"\n\t\t\t   xmlns:mx=\"library://ns.adobe.com/flex/mx\"\n\t\t\t   xmlns:ms=\"*\"\n\t\t\t   width=\"100%\" height=\"300\"\n\tlabel=\"Json\">\n\n\t<fx:Script>\n\t\t<![CDATA[\n\t\t\timport mx.collections.ArrayCollection;\n[Bindable]  private var m_fieldCollection:ArrayCollection;\n\n\t\t\tprotected override function createChildren():void\n\t\t\t{\n\t\t\t\tsuper.createChildren();\n\t\t\t\tfontCtrl.addEventListener(FontCtrl.FONT_CHANGED, onFontChanged);\n\t\t\t}\n\n\t\t\tprotected override function commitProperties():void\n\t\t\t{\n\t\t\t\tsuper.commitProperties();\n\t\t\t\tif (m_playerLoader.player==null)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar mimeType:String = \"\";\n\t\t\t\tif (m_playerLoader.parentPlayerLoader!=null)\n\t\t\t\t{\n\t\t\t\t\tmimeType = PlayerLoader(m_playerLoader.parentPlayerLoader).mimeType;\n\t\t\t\t}\n\n\t\t\t\tm_fieldCollection = new ArrayCollection();\n\t\t\t\tswitch(mimeType)\n\t\t\t\t{\n\t\t\t\t\tcase \"Json.digg\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"link\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.weather\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.current_condition[0].iconPath\",type:\"resource\",label:\"current icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.current_condition[0].temp_@\",type:\"text\",label:\"current temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.current_condition[0].humidity\",type:\"text\",label:\"current humidity\"});\n\n\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[0].iconPath\",type:\"resource\",label:\"today icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[0].mintemp@\",type:\"text\",label:\"today min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[0].maxtemp@\",type:\"text\",label:\"today max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[0].day\",type:\"text\",label:\"today label\"});\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[1].iconPath\",type:\"resource\",label:\"today+1 icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[1].mintemp@\",type:\"text\",label:\"today+1 min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[1].maxtemp@\",type:\"text\",label:\"today+1 max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[1].day\",type:\"text\",label:\"today+1 label\"});\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[2].iconPath\",type:\"resource\",label:\"today+2 icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[2].mintemp@\",type:\"text\",label:\"today+2 min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[2].maxtemp@\",type:\"text\",label:\"today+2 max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[2].day\",type:\"text\",label:\"today+2 label\"});\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[3].iconPath\",type:\"resource\",label:\"today+3 icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[3].mintemp@\",type:\"text\",label:\"today+3 min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[3].maxtemp@\",type:\"text\",label:\"today+3 max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[3].day\",type:\"text\",label:\"today+3 label\"});\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[4].iconPath\",type:\"resource\",label:\"today+4 icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[4].mintemp@\",type:\"text\",label:\"today+4 min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[4].maxtemp@\",type:\"text\",label:\"today+4 max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[4].day\",type:\"text\",label:\"today+4 label\"});\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[5].iconPath\",type:\"resource\",label:\"today+5 icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[5].mintemp@\",type:\"text\",label:\"today+5 min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[5].maxtemp@\",type:\"text\",label:\"today+5 max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[5].day\",type:\"text\",label:\"today+5 label\"});\n\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[6].iconPath\",type:\"resource\",label:\"today+6 icon\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[6].mintemp@\",type:\"text\",label:\"today+6 min temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[6].maxtemp@\",type:\"text\",label:\"today+6 max temp\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$[0].data.weather[6].day\",type:\"text\",label:\"today+6 label\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.facebook.wall\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"txt\",type:\"text\",label:\"Text\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"pic\",type:\"resource\",label:\"Picture\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.facebook.album\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"src\",type:\"resource\",label:\"Picture\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.facebook.videos\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"desc\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"src\",type:\"resource\",label:\"Video\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.picasa\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"src\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.plus\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"published\",type:\"text\",label:\"Published\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"src\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.calendar\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"summary\",type:\"text\",label:\"Summary\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"organizer\",type:\"text\",label:\"Organizer name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"organizerEmail\",type:\"text\",label:\"Organizer email\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"created\",type:\"text\",label:\"Created\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"startDateTime_time\",type:\"date\",label:\"Start time\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"endDateTime_time\",type:\"date\",label:\"End time\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"updated\",type:\"text\",label:\"Updated\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.spreadsheet\":\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.instagram.feed\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"urlImage\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"video\",type:\"resource\",label:\"Video\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"Json.instagram.media\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"urlImage\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"video\",type:\"resource\",label:\"Video\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.500px.collection\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"name\",type:\"text\",label:\"Name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"image_url\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"Json.500px.user\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"name\",type:\"text\",label:\"Name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"image_url\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.pinterest.user\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"boardThumb\",type:\"resource\",label:\"Thumb\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"boardName\",type:\"text\",label:\"Name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"src\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"likes\",type:\"text\",label:\"Likes\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.pinterest.board\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"src\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"likes\",type:\"text\",label:\"Likes\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.tumblr.posts\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"date_time\",type:\"date\",label:\"Date\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"slug\",type:\"text\",label:\"Slug\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"body\",type:\"text\",label:\"Body\"});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"Json.tumblr.videos\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"body\",type:\"text\",label:\"Body\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"date_time\",type:\"date\",label:\"Date\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"video_url\",type:\"resource\",label:\"Video\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"slug\",type:\"text\",label:\"Slug\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.tumblr.photos\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"body\",type:\"text\",label:\"Body\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"date_time\",type:\"date\",label:\"Date\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"photo_url\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"slug\",type:\"text\",label:\"Slug\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.tumblr.texts\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"date_time\",type:\"date\",label:\"Date\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"slug\",type:\"text\",label:\"Slug\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"body\",type:\"text\",label:\"Body\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.flickr\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"thumbnail\",type:\"resource\",label:\"Thumbnail\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"large\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.twitter\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"name\",type:\"text\",label:\"Name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"text\",type:\"text\",label:\"Text\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"screen_name\",type:\"text\",label:\"Screen name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"created_at\",type:\"text\",label:\"Created at\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"profile_background_image_url\",type:\"resource\",label:\"Background image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"profile_image_url\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.drive\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"id\",type:\"object\",label:\"File\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.dropbox\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"file\",type:\"object\",label:\"File\"});\n\t\t\t\t\t\tbreak;\n\n\n\t\t\t\t\tcase \"Json.yelp.info\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$rating\",type:\"text\",label:\"Rating\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$name\",type:\"text\",label:\"Name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$phone\",type:\"text\",label:\"Phone\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$snippet_text\",type:\"text\",label:\"Snippet text\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$snippet_image_url\",type:\"resource\",label:\"Snippet image\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$rating_img_url_small\",type:\"resource\",label:\"Rating image small\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$rating_img_url_large\",type:\"resource\",label:\"Rating image large\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$image_url\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.yelp.reviews\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"rating\",type:\"text\",label:\"Rating\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"excerpt\",type:\"text\",label:\"Excerpt\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"time_created\",type:\"date\",label:\"Created\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"rating_image_url\",type:\"resource\",label:\"Rating image\"})\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"rating_image_small_url\",type:\"resource\",label:\"Rating image small\"})\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"rating_image_large_url\",type:\"resource\",label:\"Rating image large\"})\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"user.name\",type:\"text\",label:\"User name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"user.image_url\",type:\"resource\",label:\"User image\"})\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.etsy.shopListings\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"title\",type:\"text\",label:\"Title\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"description\",type:\"text\",label:\"Description\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"quantity\",type:\"text\",label:\"Quantity\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"price\",type:\"text\",label:\"Price\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"currency_code\",type:\"text\",label:\"Currency\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"image_full\",type:\"resource\",label:\"Image full\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"image_large\",type:\"resource\",label:\"Image large\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"image_medium\",type:\"resource\",label:\"Image medium\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"image_small\",type:\"resource\",label:\"Image small\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.etsy.shopAbout\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$story\",type:\"text\",label:\"Story\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$story_headline\",type:\"text\",label:\"Story headline\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$story_leading_paragraph\",type:\"text\",label:\"Story paragraph\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$status\",type:\"text\",label:\"status\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.etsy.userProfile\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$first_name\",type:\"text\",label:\"First name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$last_name\",type:\"text\",label:\"Last name\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$bio\",type:\"text\",label:\"bio\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$birth_day\",type:\"text\",label:\"Birth day\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$birth_month\",type:\"text\",label:\"Birth month\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$city\",type:\"text\",label:\"City\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$location\",type:\"text\",label:\"Location\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$region\",type:\"text\",label:\"Region\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$gender\",type:\"text\",label:\"Gender\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$is_seller\",type:\"text\",label:\"Seller\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$materials\",type:\"text\",label:\"Materials\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$transaction_buy_count\",type:\"text\",label:\"transaction_buy_count\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$transaction_sold_count\",type:\"text\",label:\"transaction_sold_count\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$image_url_75x75\",type:\"resource\",label:\"Image\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.mashape.randomQuote\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"quote\",type:\"text\",label:\"quote\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"author\",type:\"text\",label:\"author\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"category\",type:\"text\",label:\"category\"});\n\t\t\t\t\t\tbreak;\n\n\n\t\t\t\t\tcase \"Json.mashape.btc\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$currency\",type:\"text\",label:\"currency\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$value\",type:\"text\",label:\"value\"});\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"Json.mashape.currency\":\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$from\",type:\"text\",label:\"From currency\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$to\",type:\"text\",label:\"To currency\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$from_amount\",type:\"text\",label:\"From amount\"});\n\t\t\t\t\t\tm_fieldCollection.addItem({name:\"$to_amount\",type:\"text\",label:\"To amount\"});\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\n\t\t\t\tfieldPath.text = BlockJsonItemPlayer(m_playerLoader.player).fieldName;\n\n\n\t\t\t\tif (mimeType==\"Json.spreadsheet\")\n\t\t\t\t{\n\t\t\t\t\tfieldComboForm.label = \"Row/Column\";\n\t\t\t\t\tfieldComboForm.visible = true;\n\t\t\t\t\tfieldComboForm.height = NaN;\n\t\t\t\t\tfieldPathForm.enabled = false;\n\t\t\t\t\tfieldTypeForm.enabled = false;\n\n\t\t\t\t\tfieldCombo.visible = false;\n\t\t\t\t\tspreadsheetFrame.visible = true;\n\n\n\t\t\t\t\tvar fieldName:String = fieldPath.text = BlockJsonItemPlayer(m_playerLoader.player).fieldName;\n\t\t\t\t\tif (fieldName.substr(0, 7)==\"$cells.\")\n\t\t\t\t\t{\n\t\t\t\t\t\tfieldName = fieldName.substring(7, fieldName.length-6);\n\t\t\t\t\t\tvar rowCol:Array = fieldName.split('.');\n\t\t\t\t\t\trow.value = Math.max(1, int(rowCol[0]));\n\t\t\t\t\t\tcol.value = Math.max(1, int(rowCol[1]));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (fieldPath.text==\"title\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trow.value = 1;\n\t\t\t\t\t\t\tcol.value = 1;\n\t\t\t\t\t\t\tonSpreadsheetCell();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (m_fieldCollection.length>0)\n\t\t\t\t{\n\n\t\t\t\t\tfor each(var item:Object in m_fieldCollection.source)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (item.name==BlockJsonItemPlayer(m_playerLoader.player).fieldName)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfieldCombo.selectedItem = item;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfieldComboForm.label = \"Field name\";\n\t\t\t\t\tfieldComboForm.visible = true;\n\t\t\t\t\tfieldComboForm.height = NaN;\n\t\t\t\t\tspreadsheetFrame.visible = false;\n\t\t\t\t\tfieldPathForm.enabled = false;\n\t\t\t\t\tfieldTypeForm.enabled = false;\n\t\t\t\t\tfieldCombo.visible = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfieldComboForm.label = \"Field name\";\n\t\t\t\t\tfieldComboForm.visible = false;\n\t\t\t\t\tfieldComboForm.height = 10;\n\t\t\t\t\tfieldPathForm.enabled = true;\n\t\t\t\t\tfieldTypeForm.enabled = true;\n\t\t\t\t\tfieldCombo.visible = true;\n\t\t\t\t}\n\n\t\t\t\tfontCtrl.fontItem = BlockJsonItemPlayer(m_playerLoader.player).fontItem;\n\t\t\t\tfor each(var fieldType:Object in ArrayList(fieldTypeCombo.dataProvider).source)\n\t\t\t\t{\n\t\t\t\t\tif (fieldType.name==BlockJsonItemPlayer(m_playerLoader.player).fieldType)\n\t\t\t\t\t{\n\t\t\t\t\t\tfieldTypeCombo.selectedItem = fieldType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tupdateButtons();\n\t\t\t\tif (BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"date\")\n\t\t\t\t{\n\t\t\t\t\tdateFormat.text = BlockJsonItemPlayer(m_playerLoader.player).dateFormat;\n\t\t\t\t}\n\t\t\t\telse if (BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"resource\" || BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"object\")\n\t\t\t\t{\n\t\t\t\t\tmaintainAspectRatio.selected = BlockJsonItemPlayer(m_playerLoader.player).maintainAspectRatio;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate function onFieldChanged(event:Event):void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).fieldType= fieldCombo.selectedItem.type;\n\t\t\t\tfieldPath.text = BlockJsonItemPlayer(m_playerLoader.player).fieldName = fieldCombo.selectedItem.name;\n\t\t\t\tif (BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"date\")\n\t\t\t\t{\n\t\t\t\t\tdateFormat.text = BlockJsonItemPlayer(m_playerLoader.player).dateFormat;\n\t\t\t\t}\n\t\t\t\telse if (BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"resource\" || BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"object\")\n\t\t\t\t{\n\t\t\t\t\tmaintainAspectRatio.selected = BlockJsonItemPlayer(m_playerLoader.player).maintainAspectRatio;\n\t\t\t\t}\n\n\t\t\t\tupdateButtons();\n\n\t\t\t\tfor each(var fieldType:Object in ArrayList(fieldTypeCombo.dataProvider).source)\n\t\t\t\t{\n\t\t\t\t\tif (fieldType.name==BlockJsonItemPlayer(m_playerLoader.player).fieldType)\n\t\t\t\t\t{\n\t\t\t\t\t\tfieldTypeCombo.selectedItem = fieldType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate function onFieldPathChanged(event:Event):void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).fieldName = fieldPath.text;\n\t\t\t}\n\n\n\t\t\tprivate function onFieldType():void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).fieldType= fieldTypeCombo.selectedItem.name;\n\t\t\t\tupdateButtons();\n\t\t\t}\n\n\t\t\tprivate function onFontChanged(event:Event):void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).fontItem = fontCtrl.fontItem;\n\t\t\t}\n\n\t\t\tprivate function onMaintainAspectRatio():void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).maintainAspectRatio = maintainAspectRatio.selected;\n\t\t\t}\n\n\t\t\tprivate function onDateFormat():void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).dateFormat = dateFormat.text;\n\t\t\t}\n\n\n\t\t\tprivate function onSpreadsheetCell():void\n\t\t\t{\n\t\t\t\tBlockJsonItemPlayer(m_playerLoader.player).fieldName = fieldPath.text = \"$cells.\" + row.value + \".\" + col.value + \".value\";\n\t\t\t}\n\n\t\t\tprivate function updateButtons():void\n\t\t\t{\n\t\t\t\tif (BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"text\")\n\t\t\t\t{\n\t\t\t\t\tfontCtrl.visible = true;\n\t\t\t\t\tmaintainAspectRatioForm.visible = false;\n\t\t\t\t\tdateFormatForm.visible = dateInfo.visible = false;\n\t\t\t\t}\n\t\t\t\telse if (BlockJsonItemPlayer(m_playerLoader.player).fieldType==\"date\")\n\t\t\t\t{\n\t\t\t\t\tfontCtrl.visible = true;\n\t\t\t\t\tmaintainAspectRatioForm.visible = false;\n\t\t\t\t\tdateFormatForm.visible = dateInfo.visible = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfontCtrl.visible = false;\n\t\t\t\t\tmaintainAspectRatioForm.visible = true;\n\t\t\t\t\tdateFormatForm.visible = dateInfo.visible = false;\n\t\t\t\t}\n\t\t\t}\n\t\t]]>\n\t</fx:Script>\n\n\t<fx:Declarations>\n\t</fx:Declarations>\n\n\t<ms:layout>\n\t\t<s:VerticalLayout/>\n\t</ms:layout>\n\n\t<s:Form width=\"100%\">\n\t\t<s:FormItem width=\"100%\" id=\"fieldComboForm\"\n\t\t\tlabel=\"Field name\">\n\t\t\t<s:layout>\n\t\t\t\t<s:BasicLayout/>\n\t\t\t</s:layout>\n\t\t\t<s:DropDownList id=\"fieldCombo\" width=\"100%\"\n\t\t\t\t\tdataProvider=\"{m_fieldCollection}\" labelField=\"label\"\n\t\t\t\t\tchange=\"onFieldChanged(event)\"/>\n\n\t\t\t<s:HGroup id=\"spreadsheetFrame\">\n\t\t\t\t<s:NumericStepper id=\"row\" minimum=\"1\" maximum=\"10000\" change=\"onSpreadsheetCell()\"/>\n\t\t\t\t<s:Label text=\":\" paddingTop=\"5\" fontWeight=\"bold\"/>\n\t\t\t\t<s:NumericStepper id=\"col\" minimum=\"1\" maximum=\"10000\" change=\"onSpreadsheetCell()\"/>\n\t\t\t</s:HGroup>\n\t\t</s:FormItem>\n\t\t<s:FormItem id=\"fieldPathForm\" width=\"100%\"\n\t\t\t\t\tlabel=\"Field path\">\n\t\t\t<s:TextInput id=\"fieldPath\" width=\"100%\"\n\t\t\t\t\t\tenter=\"onFieldPathChanged(event)\" focusOut=\"onFieldPathChanged(event)\"/>\n\t\t</s:FormItem>\n\t\t<s:FormItem id=\"fieldTypeForm\" width=\"100%\"\n\t\t\t\t\tlabel=\"Field type\">\n\t\t\t<s:DropDownList id=\"fieldTypeCombo\" labelField=\"label\" width=\"100%\"\n\t\t\t\t\t\tchange=\"onFieldType()\">\n\t\t\t\t<s:dataProvider>\n\t\t\t\t\t<s:ArrayList>\n\t\t\t\t\t\t<fx:Object name=\"text\" label=\"Text\"/>\n\t\t\t\t\t\t<fx:Object name=\"date\" label=\"Date\"/>\n\t\t\t\t\t\t<fx:Object name=\"resource\" label=\"Resource\"/>\n\t\t\t\t\t\t<fx:Object name=\"object\" label=\"Object\"/>\n\t\t\t\t\t</s:ArrayList>\n\t\t\t\t</s:dataProvider>\n\t\t\t</s:DropDownList>\n\t\t</s:FormItem>\n\t\t<s:FormItem id=\"maintainAspectRatioForm\" width=\"100%\"\n\t\t\t\t\tlabel=\"Maintain aspect ratio\">\n\t\t\t<s:CheckBox id=\"maintainAspectRatio\" change=\"onMaintainAspectRatio()\"/>\n\t\t</s:FormItem>\n\t\t<s:FormItem id=\"dateFormatForm\" width=\"100%\"\n\t\t\t\t\tlabel=\"Date format\">\n\t\t\t<s:TextInput id=\"dateFormat\"\n\t\t\t\t\t\t focusOut=\"onDateFormat()\" enter=\"onDateFormat()\"/>\n\t\t</s:FormItem>\n\t</s:Form>\n\t<ms:FontCtrl id=\"fontCtrl\" width=\"100%\"/>\n\n\t<s:VGroup id=\"dateInfo\" width=\"100%\" height=\"100%\">\n\t\t<s:Line width=\"100%\" height=\"1\"/>\n\n\t\t<s:RichText>\n\t\t\t<s:text>\n\t\t\t\tY Year              YY YYYY\n\t\t\t\tM Month in year     M MM MMM MMM\n\t\t\t\tD Day in month      D DD\n\t\t\t\tE Days in week      E EE EEE EEEE\n\t\t\t\tA AM/PM             AM or PM\n\t\t\t\tJ Hour in Day       0-23\n\t\t\t\tH Hour in Day       1-24\n\t\t\t\tK Hour in am/pm     0-11\n\t\t\t\tL Hour in am/pm     1-12\n\t\t\t\tN Minute in hour    N NN\n\t\t\t\tS Seconds in minute SS\n\t\t\t</s:text>\n\t\t</s:RichText>\n\t</s:VGroup>\n\n</ms:PlayerPage>\n"
  },
  {
    "path": "examples/json_scenes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6010\" label=\"\" interactive=\"0\">\n   <Data>\n      <Json providerType=\"weather\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"5\" playVideoInFull=\"1\" randomOrder=\"1\">\n         <Player src=\"11\" hDataSrc=\"2\" />\n         <Data unit=\"F\" style=\"2\" address=\"91301\" />\n      </Json>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/jsonsheets.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"vanilla json\" interactive=\"0\" id=\"YmxvY2tpZDM3\">\n   <Data>\n      <Appearance alpha=\"1.0\" blendMode=\"normal\" />\n      <Border borderThickness=\"0\" borderColor=\"65535\" cornerRadius=\"0\" />\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"600\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"vanilla json\" interactive=\"0\" id=\"YmxvY2tpZDM4\">\n               <Data>\n                  <Appearance alpha=\"1.0\" blendMode=\"normal\" />\n                  <Background style=\"Gradient\" gradientType=\"linear\" angle=\"0\" offsetX=\"0\" offsetY=\"0\">\n                     <GradientPoints>\n                        <Point color=\"4361162\" opacity=\"1\" midpoint=\"125\" />\n                     </GradientPoints>\n                  </Background>\n                  <Border borderThickness=\"0\" borderColor=\"65535\" cornerRadius=\"0\" />\n                  <Layout rotation=\"0\" x=\"108\" y=\"84\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$cells.6.3.value\" fieldType=\"text\" maintainAspectRatio=\"0\">\n                     <Font fontSize=\"12\" fontColor=\"0\" fontFamily=\"Astron Boy Video\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"underline\" textAlign=\"center\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/location.xml",
    "content": "\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"4105\" label=\"Location based\" interactive=\"0\">\n   <Data>\n      <LocationBased duration=\"10\">\n         <GPS>\n            <Page page=\"page2\" type=\"resource\" duration=\"5\" lat=\"34.15585218402147\" lng=\"-118.80546569824219\" radios=\"1\" priority=\"0\">\n               <Player player=\"3130\">\n                  <Data>\n                     <Resource resource=\"350\" hResource=\"4\" />\n                  </Data>\n               </Player>\n            </Page>\n            <Page page=\"page3\" type=\"resource\" duration=\"5\" lat=\"34.15585218402147\" lng=\"-118.80546569824219\" radios=\"1\" priority=\"1\">\n               <Player player=\"3130\">\n                  <Data>\n                     <Resource resource=\"352\" hResource=\"6\" />\n                  </Data>\n               </Player>\n            </Page>\n         </GPS>\n         <Fixed>\n            <Page page=\"page1\" type=\"resource\" duration=\"3\">\n               <Player player=\"3130\">\n                  <Data>\n                     <Resource resource=\"363\" hResource=\"15\" />\n                  </Data>\n               </Player>\n            </Page>\n            <Page page=\"page2\" type=\"resource\" duration=\"3\">\n               <Player player=\"3130\">\n                  <Data>\n                     <Resource resource=\"362\" hResource=\"14\" />\n                  </Data>\n               </Player>\n            </Page>\n         </Fixed>\n      </LocationBased>\n   </Data>\n</Player>\n"
  },
  {
    "path": "examples/player_weather_scene.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6010\" iconName=\"player6010Icon\" label=\"\">\n   <Data>\n      <Json providerType=\"weather\" slideShow=\"1\">\n         <Player src=\"15\" hDataSrc=\"6\" />\n      </Json>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/reseller_sample.xml",
    "content": "<!-- Galaxy app_compoenents > app_compontn / module_id -->\n\n<BusinessInfo businessId=\"300762\" name=\"XXXXXXXXXXXX\" businessDescription=\"\" accountStatus=\"4\" archiveState=\"0\" applicationId=\"3\" resellerId=\"1\" providerId=\"10\">\n\t<WhiteLabel enabled=\"1\">\n\t\t<Studio>\n\t\t\t<Application>\n\t\t\t\t<Logo tooltip=\"www.MediaSignage.com\" link=\"http://www.mediasignage.com/b.thml\" filename=\"XXXXXXXXLogo.png\"/>\n\t\t\t\t<Links home=\"http://mediasignage.com\" download=\"http://mediasignage.com/html/download.html\" contact=\"http://mediasignage.com/html/contact.html\"/>\n\t\t\t\t<CreateAccount show=\"1\"/>\n\t\t\t</Application>\n\t\t\t<MainMenu>\n\t\t\t\t<CommandGroup id=\"help\" label=\"Help\" icon=\"helpIcon\">\n\t\t\t\t\t<Command id=\"help1\" label=\"Visit site\" href=\"http://mediasignage.com\"/>\n\t\t\t\t\t<Command id=\"help2\" label=\"Video Tutorial\" href=\"http://mediasignage.com/html/signage_video.html\"/>\n\t\t\t\t\t<Command id=\"help3\" label=\"Support\" href=\"http://mediasignage.com/simplemachinesforum/index.php\"/>\n\t\t\t\t\t<Command id=\"help4\" label=\"Report a bug\" href=\"http://mediasignage.com/simplemachinesforum/index.php?board=3.0\"/>\n\t\t\t\t\t<Command id=\"about\" label=\"About...\"/>\n\t\t\t\t</CommandGroup>\n\t\t\t</MainMenu>\n\t\t\t<Banner embeddedReference=\"1\"/>\n\t\t\t<Twitter show=\"1\" link=\"http://twitter.com/mediasignage\"/>\n\t\t\t<Chat show=\"1\" link=\"http://messenger.providesupport.com/messenger/mediasignage.html\"/>\n\t\t</Studio>\n\t</WhiteLabel>\n\t<Privileges defaultPrivilegeId=\"300079\">\n\t\t<Privilege id=\"301746\" name=\"limited\">\n\t\t\t<Groups>\n\t\t\t\t<Group name=\"Global\" visible=\"0\">\n\t\t\t\t\t<Tables global_settings=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Screens\" visible=\"0\">\n\t\t\t\t\t<Tables boards=\"0\" board_templates=\"0\" board_template_viewers=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Resources\" visible=\"0\" resourceMode=\"0\">\n\t\t\t\t\t<Tables resources=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Editors\" visible=\"0\">\n\t\t\t\t\t<Tables player_data=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Catalog\" visible=\"0\">\n\t\t\t\t\t<Tables catalog_items=\"0\" catalog_item_infos=\"0\" catalog_item_resources=\"0\" catalog_item_categories=\"0\" category_values=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Campaigns\" visible=\"0\">\n\t\t\t\t\t<Tables campaigns=\"0\" campaign_events=\"0\" campaign_timelines=\"0\" campaign_timeline_sequences=\"0\" campaign_timeline_schedules=\"0\" campaign_sequences=\"0\" campaign_sequence_timelines=\"0\" campaign_sequence_schedules=\"0\" campaign_timeline_channels=\"0\" campaign_timeline_chanels=\"0\" campaign_timeline_chanel_players=\"0\" campaign_timeline_board_viewer_channels=\"0\" campaign_timeline_board_viewer_chanels=\"0\" campaign_timeline_board_templates=\"0\" campaign_channels=\"0\" campaign_channel_players=\"0\" campaign_boards=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Transitions\" visible=\"1\">\n\t\t\t\t\t<Tables transition_pools=\"7\" transition_pool_items=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdLocal\" visible=\"0\">\n\t\t\t\t\t<Tables ad_local_packages=\"0\" ad_local_contents=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdOut\" visible=\"0\" globalSearch=\"1\">\n\t\t\t\t\t<Tables ad_out_packages=\"0\" ad_out_package_stations=\"0\" ad_out_package_contents=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdIn\" visible=\"0\">\n\t\t\t\t\t<Tables ad_in_domains=\"0\" ad_in_domain_businesses=\"0\" ad_in_domain_business_packages=\"0\" ad_in_domain_business_package_stations=\"0\" ad_rates=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdRate\" visible=\"0\">\n\t\t\t\t\t<Tables ad_rates=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdAnalytic\" visible=\"0\">\n\t\t\t\t\t<Tables/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Music\" visible=\"0\">\n\t\t\t\t\t<Tables music_channels=\"0\" music_channel_songs=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Stations\" visible=\"1\" stationsNetwork=\"0\" updateOnSave=\"0\" lanServer=\"0\" zwave=\"0\">\n\t\t\t\t\t<Tables branch_stations=\"7\" station_ads=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Changelist\" visible=\"0\">\n\t\t\t\t\t<Tables/>\n\t\t\t\t</Group>\n\t\t\t</Groups>\n\t\t</Privilege>\n\t\t<Privilege id=\"300079\" name=\"privilege\">\n\t\t\t<Groups>\n\t\t\t\t<Group name=\"Global\" visible=\"1\">\n\t\t\t\t\t<Tables global_settings=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Screens\" visible=\"1\">\n\t\t\t\t\t<Tables boards=\"7\" board_templates=\"7\" board_template_viewers=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Resources\" visible=\"1\" resourceMode=\"0\">\n\t\t\t\t\t<Tables resources=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Editors\" visible=\"1\">\n\t\t\t\t\t<Tables player_data=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Catalog\" visible=\"1\">\n\t\t\t\t\t<Tables catalog_items=\"7\" catalog_item_infos=\"7\" catalog_item_resources=\"7\" catalog_item_categories=\"7\" category_values=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Campaigns\" visible=\"1\">\n\t\t\t\t\t<Tables campaigns=\"7\" campaign_events=\"7\" campaign_timelines=\"7\" campaign_timeline_sequences=\"7\" campaign_timeline_schedules=\"7\" campaign_sequences=\"7\" campaign_sequence_timelines=\"7\" campaign_sequence_schedules=\"7\" campaign_timeline_channels=\"7\" campaign_timeline_chanels=\"7\" campaign_timeline_chanel_players=\"7\" campaign_timeline_board_viewer_channels=\"7\" campaign_timeline_board_viewer_chanels=\"7\" campaign_timeline_board_templates=\"7\" campaign_channels=\"7\" campaign_channel_players=\"7\" campaign_boards=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Transitions\" visible=\"1\">\n\t\t\t\t\t<Tables transition_pools=\"7\" transition_pool_items=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdLocal\" visible=\"1\">\n\t\t\t\t\t<Tables ad_local_packages=\"7\" ad_local_contents=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdOut\" visible=\"1\" globalSearch=\"1\">\n\t\t\t\t\t<Tables ad_out_packages=\"7\" ad_out_package_stations=\"7\" ad_out_package_contents=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdIn\" visible=\"1\">\n\t\t\t\t\t<Tables ad_in_domains=\"7\" ad_in_domain_businesses=\"7\" ad_in_domain_business_packages=\"7\" ad_in_domain_business_package_stations=\"7\" ad_rates=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdRate\" visible=\"1\">\n\t\t\t\t\t<Tables ad_rates=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdAnalytic\" visible=\"1\">\n\t\t\t\t\t<Tables/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Music\" visible=\"1\">\n\t\t\t\t\t<Tables music_channels=\"7\" music_channel_songs=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Stations\" visible=\"1\" stationsNetwork=\"1\" updateOnSave=\"1\" lanServer=\"1\" zwave=\"1\">\n\t\t\t\t\t<Tables branch_stations=\"7\" station_ads=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Changelist\" visible=\"1\">\n\t\t\t\t\t<Tables/>\n\t\t\t\t</Group>\n\t\t\t</Groups>\n\t\t</Privilege>\n\t\t<Privilege id=\"301724\" name=\"UpStat\">\n\t\t\t<Groups>\n\t\t\t\t<Group name=\"Global\" visible=\"0\">\n\t\t\t\t\t<Tables global_settings=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Screens\" visible=\"0\">\n\t\t\t\t\t<Tables boards=\"0\" board_templates=\"0\" board_template_viewers=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Resources\" visible=\"0\" resourceMode=\"0\">\n\t\t\t\t\t<Tables resources=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Editors\" visible=\"0\">\n\t\t\t\t\t<Tables player_data=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Catalog\" visible=\"0\">\n\t\t\t\t\t<Tables catalog_items=\"0\" catalog_item_infos=\"0\" catalog_item_resources=\"0\" catalog_item_categories=\"0\" category_values=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Campaigns\" visible=\"0\">\n\t\t\t\t\t<Tables campaigns=\"0\" campaign_events=\"0\" campaign_timelines=\"0\" campaign_timeline_sequences=\"0\" campaign_timeline_schedules=\"0\" campaign_timeline_channels=\"0\" campaign_timeline_chanels=\"0\" campaign_timeline_chanel_players=\"0\" campaign_timeline_board_viewer_channels=\"0\" campaign_timeline_board_viewer_chanels=\"0\" campaign_timeline_board_templates=\"0\" campaign_channels=\"0\" campaign_channel_players=\"0\" campaign_boards=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Transitions\" visible=\"1\">\n\t\t\t\t\t<Tables transition_pools=\"7\" transition_pool_items=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdLocal\" visible=\"0\">\n\t\t\t\t\t<Tables ad_local_packages=\"0\" ad_local_contents=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdOut\" visible=\"0\" globalSearch=\"1\">\n\t\t\t\t\t<Tables ad_out_packages=\"0\" ad_out_package_stations=\"0\" ad_out_package_contents=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdIn\" visible=\"0\">\n\t\t\t\t\t<Tables ad_in_domains=\"0\" ad_in_domain_businesses=\"0\" ad_in_domain_business_packages=\"0\" ad_in_domain_business_package_stations=\"0\" ad_rates=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdRate\" visible=\"0\">\n\t\t\t\t\t<Tables ad_rates=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"AdAnalytic\" visible=\"0\">\n\t\t\t\t\t<Tables/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Music\" visible=\"0\">\n\t\t\t\t\t<Tables music_channels=\"0\" music_channel_songs=\"0\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Stations\" visible=\"1\" stationsNetwork=\"1\" updateOnSave=\"1\" lanServer=\"0\" zwave=\"0\">\n\t\t\t\t\t<Tables branch_stations=\"7\" station_ads=\"7\"/>\n\t\t\t\t</Group>\n\t\t\t\t<Group name=\"Changelist\" visible=\"0\">\n\t\t\t\t\t<Tables/>\n\t\t\t\t</Group>\n\t\t\t</Groups>\n\t\t</Privilege>\n\t</Privileges>\n\t<Themes defaultThemeId=\"0\">\n\t\t<Theme name=\"White\" ver=\"1420\" studioStyles=\"Themes/StudioStyles2.swf\" playerStyles=\"Themes/PlayerStyles2.swf\" studioIcons=\"Themes/StudioIcons2.swf\" playerIcons=\"Themes/AirPlayerIcons2.swf\" componentIcons=\"Themes/componentIcons2.swf\" id=\"1\"/>\n\t\t<Theme name=\"Black\" ver=\"1420\" studioStyles=\"Themes/StudioStyles.swf\" playerStyles=\"Themes/PlayerStyles.swf\" studioIcons=\"Themes/StudioIcons.swf\" playerIcons=\"Themes/AirPlayerIcons.swf\" componentIcons=\"Themes/componentIcons.swf\" id=\"0\"/>\n\t</Themes>\n\t<InstalledApps>\n\t\t<App id=\"10500\" installed=\"1\"/>\n\t\t<App id=\"10140\" installed=\"1\"/>\n\t\t<App id=\"10050\" installed=\"1\"/>\n\t\t<App id=\"10400\" installed=\"1\"/>\n\t\t<App id=\"10220\" installed=\"1\"/>\n\t\t<App id=\"10130\" installed=\"1\"/>\n\t\t<App id=\"10040\" installed=\"1\"/>\n\t\t<App id=\"10300\" installed=\"1\"/>\n\t\t<App id=\"10210\" installed=\"1\"/>\n\t\t<App id=\"10120\" installed=\"1\"/>\n\t\t<App id=\"10030\" installed=\"1\"/>\n\t\t<App id=\"10200\" installed=\"1\"/>\n\t\t<App id=\"10110\" installed=\"1\"/>\n\t\t<App id=\"10020\" installed=\"1\"/>\n\t\t<App id=\"10190\" installed=\"1\"/>\n\t\t<App id=\"10100\" installed=\"1\"/>\n\t\t<App id=\"10010\" installed=\"1\"/>\n\t\t<App id=\"10005\" installed=\"1\"/>\n\t\t<App id=\"10180\" installed=\"1\"/>\n\t\t<App id=\"10090\" installed=\"1\"/>\n\t\t<App id=\"10080\" installed=\"1\"/>\n\t\t<App id=\"10060\" installed=\"1\"/>\n\t\t<App id=\"10160\" installed=\"1\"/>\n\t\t<App id=\"10070\" installed=\"1\"/>\n\t\t<App id=\"10150\" installed=\"1\"/>\n\t\t<App id=\"10122\" installed=\"1\"/>\n\t</InstalledApps>\n</BusinessInfo>"
  },
  {
    "path": "examples/sceneSample.xml",
    "content": "<Player player=\"3510\" label=\"my scene 1\" interactive=\"0\">\n\t<Data>\n\t\t<EventCommands>\n\t\t\t<EventCommand from=\"\" condition=\"\" command=\"redirect\"/>\n\t\t</EventCommands>\n\t\t<Layout rotation=\"0\" x=\"10\" y=\"20\" width=\"555\" height=\"405\"/>\n\t\t<Appearance alpha=\"0.9\" blendMode=\"normal\"/>\n\t\t<Border borderThickness=\"3\" borderColor=\"16711680\" cornerRadius=\"8\"/>\n\t\t<Background style=\"Gradient\" gradientType=\"linear\" angle=\"90\" offsetX=\"0\" offsetY=\"0\">\n\t\t\t<GradientPoints>\n\t\t\t\t<Point color=\"16769071\" opacity=\"0.6\" midpoint=\"5\"/>\n\t\t\t\t<Point color=\"16772453\" opacity=\"0.7\" midpoint=\"46\"/>\n\t\t\t\t<Point color=\"16777215\" opacity=\"0.2\" midpoint=\"181\"/>\n\t\t\t\t<Point color=\"16515072\" opacity=\"0.8\" midpoint=\"227\"/>\n\t\t\t</GradientPoints>\n\t\t</Background>\n\t\t<Scene defaultDuration=\"10\">\n\t\t\t<Layout>\n\t\t\t\t<BasicLayout/>\n\t\t\t</Layout>\n\t\t\t<Players>\n\t\t\t\t<Player player=\"3130\" label=\"Resource\" interactive=\"0\">\n\t\t\t\t\t<Data>\n\t\t\t\t\t\t<Layout rotation=\"0\" x=\"51\" y=\"189\" width=\"153\" height=\"46\"/>\n\t\t\t\t\t\t<Resource resource=\"9\" hResource=\"0\">\n\t\t\t\t\t\t\t<AspectRatio maintain=\"0\"/>\n\t\t\t\t\t\t</Resource>\n\t\t\t\t\t</Data>\n\t\t\t\t</Player>\n\t\t\t\t<Player player=\"3320\" label=\"Clock\" interactive=\"0\">\n\t\t\t\t\t<Data>\n\t\t\t\t\t\t<Layout rotation=\"0\" x=\"38\" y=\"302\" width=\"301\" height=\"58\"/>\n\t\t\t\t\t\t<Clock clockFormat=\"time\" clockMask=\"J:NN:SS\">\n\t\t\t\t\t\t\t<Font fontSize=\"72\" fontColor=\"3355443\" fontFamily=\"Arial Rounded MT Bold\" fontWeight=\"bold\" fontStyle=\"none\" textDecoration=\"none\" textAlign=\"left\"/>\n\t\t\t\t\t\t</Clock>\n\t\t\t\t\t</Data>\n\t\t\t\t</Player>\n\t\t\t\t<Player player=\"3241\" label=\"component name\" interactive=\"0\">\n\t\t\t\t\t<Data>\n\t\t\t\t\t\t<Layout rotation=\"0\" left=\"64\" verticalCenter=\"-50\" width=\"296\" height=\"56\"/>\n\t\t\t\t\t\t<Border borderThickness=\"4\" borderColor=\"16711680\" cornerRadius=\"6\"/>\n\t\t\t\t\t\t<Background style=\"Gradient\" gradientType=\"linear\" angle=\"90\" offsetX=\"0\" offsetY=\"0\">\n\t\t\t\t\t\t\t<GradientPoints>\n\t\t\t\t\t\t\t\t<Point color=\"16733463\" opacity=\"0.9\" midpoint=\"7\"/>\n\t\t\t\t\t\t\t\t<Point color=\"16777215\" opacity=\"0.7\" midpoint=\"59\"/>\n\t\t\t\t\t\t\t\t<Point color=\"5240588\" opacity=\"0.9\" midpoint=\"117\"/>\n\t\t\t\t\t\t\t\t<Point color=\"16777215\" opacity=\"0.3\" midpoint=\"176\"/>\n\t\t\t\t\t\t\t\t<Point color=\"11942570\" opacity=\"1\" midpoint=\"244\"/>\n\t\t\t\t\t\t\t</GradientPoints>\n\t\t\t\t\t\t</Background>\n\t\t\t\t\t\t<Blur blurX=\"2\" blurY=\"1\"/>\n\t\t\t\t\t\t<Label>\n\t\t\t\t\t\t\t<Text>Sean text</Text>\n\t\t\t\t\t\t\t<Font fontSize=\"48\" fontColor=\"10027059\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"italic\" textDecoration=\"none\" textAlign=\"left\"/>\n\t\t\t\t\t\t</Label>\n\t\t\t\t\t</Data>\n\t\t\t\t</Player>\n\t\t\t\t<Player player=\"3430\" label=\"QR Code\" interactive=\"0\">\n\t\t\t\t\t<Data>\n\t\t\t\t\t\t<Layout rotation=\"0\" x=\"23.4\" y=\"14.8\" width=\"71\" height=\"61\"/>\n\t\t\t\t\t\t<Text textSource=\"static\">I am qr</Text>\n\t\t\t\t\t</Data>\n\t\t\t\t</Player>\n\t\t\t\t<Player player=\"3345\" label=\"Rss news\" interactive=\"0\">\n\t\t\t\t\t<Data>\n\t\t\t\t\t\t<Layout rotation=\"0\" x=\"153.75\" y=\"15.6\" width=\"240\" height=\"89\"/>\n\t\t\t\t\t\t<Rss url=\"http://rss.news.yahoo.com/rss/tech\" minRefreshTime=\"24\" speed=\"20\" vertical=\"1\" rtl=\"0\">\n\t\t\t\t\t\t\t<Title>\n\t\t\t\t\t\t\t\t<Font fontSize=\"16\" fontColor=\"102\" fontFamily=\"Arial\" fontWeight=\"bold\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\"/>\n\t\t\t\t\t\t\t</Title>\n\t\t\t\t\t\t\t<Description>\n\t\t\t\t\t\t\t\t<Font fontSize=\"16\" fontColor=\"10053171\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\"/>\n\t\t\t\t\t\t\t</Description>\n\t\t\t\t\t\t</Rss>\n\t\t\t\t\t</Data>\n\t\t\t\t</Player>\n\t\t\t\t<Player player=\"3150\" label=\"External video\" interactive=\"0\">\n\t\t\t\t\t<Data>\n\t\t\t\t\t\t<Layout rotation=\"0\" x=\"259.2\" y=\"215.15\" width=\"100\" height=\"56\"/>\n\t\t\t\t\t\t<LINK src=\"http://somesite.com/vifro.flv\"/>\n\t\t\t\t\t</Data>\n\t\t\t\t</Player>\n\t\t\t</Players>\n\t\t</Scene>\n\t</Data>\n</Player>"
  },
  {
    "path": "examples/sceneSampleLayout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"locks\" interactive=\"0\" id=\"YmxvY2tpZDQx\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"3130\" label=\"Resource\" interactive=\"0\" id=\"YmxvY2tpZDQy\">\n               <Data>\n                  <Layout rotation=\"0\" left=\"25\" right=\"273\" top=\"43\" bottom=\"255\" />\n                  <Resource resource=\"4\" hResource=\"1\">\n                     <AspectRatio maintain=\"0\" />\n                  </Resource>\n               </Data>\n            </Player>\n            <Player player=\"3130\" label=\"Resource\" interactive=\"0\" id=\"YmxvY2tpZDQz\">\n               <Data>\n                  <Layout rotation=\"0\" horizontalCenter=\"30\" verticalCenter=\"10\" width=\"100\" height=\"100\" />\n                  <Resource resource=\"7\" hResource=\"4\">\n                     <AspectRatio maintain=\"0\" />\n                  </Resource>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/twitterv3.xml",
    "content": "Scene\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"ywitter csns\" interactive=\"0\" mimeType=\"Json.twitter\" id=\"YmxvY2tpZDYx\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"400\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDYy\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"27\" y=\"19\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"name\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDYz\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"251\" y=\"19\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"screen_name\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY0\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"138\" y=\"72\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"profile_background_image_url\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY1\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"38\" y=\"192\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"created_at\" fieldType=\"text\">\n                     <Font fontSize=\"22\" fontColor=\"255\" fontFamily=\"Arial\" fontWeight=\"bold\" fontStyle=\"italic\" textDecoration=\"underline\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY2\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"138\" y=\"36\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"text\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY3\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"251\" y=\"72\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"profile_image_url\" fieldType=\"resource\" maintainAspectRatio=\"1\" />\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>\n\n\nPlayer\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"6230\" label=\"\" interactive=\"0\">\n   <Data>\n      <Json providerType=\"twitter\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"5\" playVideoInFull=\"0\" randomOrder=\"0\">\n         <Player src=\"37\" hDataSrc=\"11\" />\n         <Data token=\"d1b05f94-df59-46d4-b5b0-05536f48ab44\" screenName=\"\" />\n      </Json>\n   </Data>\n</Player>"
  },
  {
    "path": "examples/worldweather.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Player player=\"3510\" label=\"WeatherScene\" interactive=\"0\" mimeType=\"Json.weather\" id=\"YmxvY2tpZDY3\">\n   <Data>\n      <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"900\" height=\"400\" />\n      <Scene defaultDuration=\"10\">\n         <Layout>\n            <BasicLayout />\n         </Layout>\n         <Players>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY4\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.current_condition[0].iconPath\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDY5\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"100\" y=\"0\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.current_condition[0].temp_@\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDcw\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"0\" y=\"231\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.weather[0].day\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDcx\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"227\" y=\"131\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.weather[0].maxtemp@\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDcy\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"247\" y=\"0\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.current_condition[0].humidity\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDcz\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"0\" y=\"131\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.weather[0].iconPath\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc0\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"100\" y=\"131\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.weather[0].mintemp@\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc1\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"113\" y=\"231\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.weather[1].iconPath\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc2\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"270\" y=\"250\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$[0].data.weather[1].mintemp@\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc3\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"0\" y=\"350\" width=\"100\" height=\"48\" />\n                  <XmlItem fieldName=\"$[0].data.weather[1].maxtemp@\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc4\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"678\" y=\"31\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"link\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDc5\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"678\" y=\"168\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$image_url_75x75\" fieldType=\"resource\" maintainAspectRatio=\"0\" />\n               </Data>\n            </Player>\n            <Player player=\"4310\" label=\"JSON Item\" interactive=\"0\" id=\"YmxvY2tpZDgw\">\n               <Data>\n                  <Layout rotation=\"0\" x=\"678\" y=\"288\" width=\"100\" height=\"100\" />\n                  <XmlItem fieldName=\"$birth_month\" fieldType=\"text\">\n                     <Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />\n                  </XmlItem>\n               </Data>\n            </Player>\n         </Players>\n      </Scene>\n   </Data>\n</Player>\n\n"
  },
  {
    "path": "notes.txt",
    "content": "////////////// NOTES ////////////////\n\n\n\nneed to find a way to remove core-js from videoangular definitions\nsed -i.bak '/core-js/d' './node_modules/videogular2/src/core/vg-media/i-playable.d.ts ; sed -i.bak '/core-js/d' './node_modules/videogular2/src/core/services/vg-api.d.ts'\n\n\nreload video:\nhttps://github.com/videogular/videogular2/issues/442\n\n\nnpm uninstall -g angular-cli @angular/cli\nnpm cache clean\nnpm install -g @angular/cli@latest\nLocal project package:\n\nrm -rf node_modules dist # use rmdir on Windows\nnpm install --save-dev @angular/cli@latest <<<<<<<<<<<<<<<<\nnpm install\n\n\nng init --ng4\n\n\n==================================================================================================================\ndebug sessions:\n\nreflection:\n    http://127.0.0.1:8080/src/create_reflection.html\n\nlocal:\n    http://localhost:4208/\n\ncampaigns:\n    http://localhost:4208/campaigns\n\nFasterqRemoteStatus (base64):\n    http://localhost:4208/index.html?mode=remoteStatus&param=eyJjYWxsX3R5cGUiOiJFTUFJTCIsInNlcnZpY2VfaWQiOjE5LCJ2ZXJpZmljYXRpb24iOjY5NSwibGluZV9pZCI6IjIxMTAiLCJsaW5lX25hbWUiOiIgbmV3IGxpbmUgMSIsImJ1c2luZXNzX2lkIjoiMzU4NjEzIiwic21zIjoiIiwiZW1haWwiOiJib3JuMm5ldEBnbWFpbC5jb20iLCJkYXRlIjoiNC83LzIwMTcifQ==\n\nFasterqTerminal (rc4):\n    http://localhost:4208/index.html?data=5b6bcb27d4547657cfe4e021e1c6761fe8b4a33c3d62983ee8f6b0ccbded7b8a6578e47862f0aca0ca7ac070a1a27121fe17f5c496483ee08cf0a061440f277a3e49dcaaf3bb198c71033ed398d60166e3b82c9153f4c3a6d346f7d11b3016\n\nauto-login local demo_lite\n\thttp://localhost:4208/index.html?param=dXNlcj1kZW1vX2xpdGVAbXMuY29tLHBhc3M9cGFzc3dvcmQ=\n\nauto-login remote demo_lite\n\thttps://secure.digitalsignage.com/studioweb/index.html?param=dXNlcj1kZW1vX2xpdGVAbXMuY29tLHBhc3M9cGFzc3dvcmQ=\n\nauto-login remote demo_lite\n    https://goo.gl/rru309\n\nauto-login local lite22\n\thttp://localhost:4208/index.html?param=dXNlcj1saXRlMjJAbXMuY29tLHBhc3M9MTIzMTIz\n\nauto-login local lite90\n\thttp://localhost:4208/index.html?param=dXNlcj1saXRlOTBAbXMuY29tLHBhc3M9MTIzMTIz\n\nauto-login local lite28\n\thttp://localhost:4208/index.html?param=dXNlcj1saXRlMjhAbXMuY29tLHBhc3M9MTIzMTIz\n\n\n==================================================================================================================\n\nrevert webpack ng tools: npm install --save @ngtools/webpack@1.2.4\n\n\n==================================================================================================================\n\n\nclear cache: npm clear cache\n\nnpm install @angular/cli@latest -g\nnpm install -g @angular/cli\n\n\n==================================================================================================================\n\nreflection Usage:\n\nto run this script and generate interface sdk / msdb:\n\nrun live-server inside /cygdrive/c/msweb/studiolite\n\nopen browser to:\n\nhttp://127.0.0.1:8080/src/create_reflection.html\n\n\n==================================================================================================================\n\nSwitching fabric versions:\n\nadd/remove import \"fabric\"; from app-modules.ts\nadd/remove form angular-cli.json:\n\"../node_modules/fabric/dist/fabric.js\"\nor\nangular-cli.json: \"./libs/fabric.require1-4-12.js\",\nor\nto load remotely:\n<script src=\"https://secure.digitalsignage.com/studioweb/fabric1-4-2.min.js\"></script>\n<script src=\"https://secure.digitalsignage.com/studioweb/fabric.require1-4-12.min.js\"></script>\n\n==================================================================================================================\n\n\n<!--<script src=\"https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/shim.min.js\"></script>-->\n<!--<script>-->\n    <!--(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){-->\n            <!--(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),-->\n        <!--m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)-->\n    <!--})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');-->\n\n    <!--ga('create', 'UA-36671151-9', 'auto');-->\n    <!--ga('send', 'pageview');-->\n<!--</script>-->\n\n\n\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"studioweb\",\n  \"version\": \"0.1.778\",\n  \"license\": \"Modified GPL (see readme.md)\",\n  \"angular-cli\": {},\n  \"scripts\": {\n    \"postinstall\": \"npm run dev\",\n    \"compodoc\": \"./node_modules/.bin/compodoc -p src/tsconfig.json\",\n    \"x_disk-build\": \"ng build && npm run sw\",\n    \"x_disk-serve\": \"cd dist && live-server --port=4208 --host=localhost --entry-file=/index.html\",\n    \"x_reg_release\": \"rm -r -f ./dist && npm run x_bump && npm run x_prod && npm run x_rsync\",\n    \"x_start\": \"ng serve\",\n    \"x_lint\": \"tslint \\\"src/**/*.ts\\\"\",\n    \"x_prod_jit\": \"ng build --target=production --base-href ./ --aot fiw.alse\",\n    \"x_prod_aot\": \"ng build --target=production --base-href ./ --aot true\",\n    \"x_prod_aot_hebrew\": \"ng build --locale iw -i18n-file src/locale/iw.xtb --i18n-format xtb --target=production --base-href ./ --aot true\",\n    \"x_rsync\": \"rsync --progress  --chmod=ug=rwx --chmod=o=rx -av --stats -e ssh /cygdrive/c/msweb/studiolite/dist/ Sean@secure.digitalsignage.com:/var/www/sites/dynasite/htdocs/_msportal/_js/_node/_studioweb\",\n    \"x_rsync_docs\": \"rsync --progress  --chmod=ug=rwx --chmod=o=rx -av --stats -e ssh /cygdrive/c/msweb/studiolite/documentation/ Sean@digitalsignage.com:/var/www/sites/mediasignage.com/htdocs/lite_docs\",\n    \"x_rsync_iw\": \"rsync --progress  --chmod=ug=rwx --chmod=o=rx -av --stats -e ssh /cygdrive/c/msweb/studiolite/dist/ Sean@digitalsignage.com:/var/www/sites/dynasite/htdocs/_msportal/_js/_node/_studioweb/locale/iw\",\n    \"x_sw\": \"sw-precache --root=dist --config=sw-precache-config.js\",\n    \"x_bump\": \"gulp x_bump\",\n    \"x_cssDev\": \"gulp cssDev\",\n    \"x_cssRelease\": \"gulp cssRelease\",\n    \"x_translate\": \"node_modules/.bin/ng-xi18n -p src/tsconfig.json --i18nFormat=xmb\",\n    \"x_node_copy\": \"cp -r -f ./node_modules/ ./dist/out-tsc/\",\n    \"cp module\": \"cp ./node_modules/ng-mslib/src/myng-component.ts ./node_modules/ng-mslib/dist/\",\n    \"generate_locale\": \"npm run x_node_copy && npm run x_translate\",\n    \"hmr\": \"ng serve --port 4208 --aot false --hmr -e=hmr\",\n    \"dev\": \"npm run x_cssDev && ng serve --port 4208 --aot false\",\n    \"release_aot_hebrew\": \"npm run x_cssRelease && rm -r -f ./dist && npm run x_bump && npm run x_prod_aot_hebrew && npm run x_sw && npm run x_rsync_iw\",\n    \"release_aot\": \"npm run x_cssRelease && rm -r -f ./dist && npm run x_bump && npm run x_prod_aot && npm run x_sw && npm run x_rsync\",\n    \"release_aot_no_sync\": \"npm run x_cssRelease && rm -r -f ./dist && npm run x_bump && npm run x_prod_aot && npm run x_sw\",\n    \"release_jit\": \"npm run x_cssRelease && rm -r -f ./dist && npm run x_bump && npm run x_prod_jit && npm run x_sw && npm run x_rsync\"\n  },\n  \"dependencies\": {\n    \"@angular/animations\": \"^4.3.1\",\n    \"@angular/common\": \"^4.3.1\",\n    \"@angular/compiler\": \"^4.3.1\",\n    \"@angular/core\": \"^4.3.1\",\n    \"@angular/forms\": \"^4.3.1\",\n    \"@angular/http\": \"^4.3.1\",\n    \"@angular/platform-browser\": \"^4.3.1\",\n    \"@angular/platform-browser-dynamic\": \"^4.3.1\",\n    \"@angular/router\": \"^4.3.1\",\n    \"@ngrx/core\": \"^1.2.0\",\n    \"@ngrx/effects\": \"^2.0.0\",\n    \"@ngrx/store\": \"^2.2.1\",\n    \"@ngrx/store-devtools\": \"^3.2.3\",\n    \"@ngtools/webpack\": \"^1.2.4\",\n    \"@types/bootbox\": \"^4.4.30\",\n    \"@types/gsap\": \"1.19.0\",\n    \"@types/lodash\": \"^4.14.52\",\n    \"@types/xdate\": \"^0.8.27\",\n    \"angular-pipes\": \"^5.4.0\",\n    \"angular2-fontawesome\": \"~0.8.0\",\n    \"angular2-google-maps\": \"^0.17.0\",\n    \"angular2-highcharts\": \"^0.4.1\",\n    \"angular2-redux-util\": \"^0.8.86\",\n    \"angular2-uuid\": \"^1.1.0\",\n    \"bootbox\": \"^4.4.0\",\n    \"bootstrap\": \"^3.3.7\",\n    \"core-js\": \"^2.4.1\",\n    \"fabric\": \"git://github.com/born2net/fabric.js.git\",\n    \"font-awesome\": \"~4.7.0\",\n    \"gsap\": \"1.19.1\",\n    \"gulp-bump\": \"^2.5.1\",\n    \"hammerjs\": \"^2.0.8\",\n    \"immutable\": \"^3.8.1\",\n    \"jquery\": \"^3.1.1\",\n    \"lodash\": \"^4.17.4\",\n    \"moment\": \"^2.17.1\",\n    \"ng-mslib\": \"^1.0.109\",\n    \"ng-validators\": \"^0.2.1\",\n    \"ng2-bs3-modal\": \"^0.10.4\",\n    \"ng2-toastr\": \"^4.1.2\",\n    \"ngrx-store-freeze\": \"^0.1.6\",\n    \"ngx-bootstrap\": \"^1.7.1\",\n    \"ngx-color-picker\": \"^4.0.0\",\n    \"ngx-contextmenu\": \"^1.0.3\",\n    \"platform\": \"^1.3.3\",\n    \"primeng\": \"^4.0.0-rc.2\",\n    \"print-js\": \"^1.0.34\",\n    \"redux\": \"^3.6.0\",\n    \"redux-thunk\": \"^2.1.0\",\n    \"reselect\": \"^2.5.4\",\n    \"rxjs\": \"^5.4.2\",\n    \"stacktrace-js\": \"^1.3.1\",\n    \"string\": \"^3.3.3\",\n    \"ts-helpers\": \"^1.1.1\",\n    \"typescript\": \"2.4.0\",\n    \"videogular2\": \"^5.2.0\",\n    \"x2js\": \"^3.1.0\",\n    \"xdate\": \"^0.8.0\",\n    \"xml2js\": \"^0.4.17\",\n    \"zone.js\": \"^0.8.12\"\n  },\n  \"devDependencies\": {\n    \"@angular/cli\": \"^1.0.1\",\n    \"@angular/compiler-cli\": \"^4.3.1\",\n    \"@angular/language-service\": \"^4.3.1\",\n    \"@angularclass/hmr\": \"^1.2.2\",\n    \"@compodoc/compodoc\": \"^1.0.0-beta.9\",\n    \"@types/core-js\": \"^0.9.41\",\n    \"@types/hammerjs\": \"^2.0.33\",\n    \"@types/immutable\": \"^3.8.6\",\n    \"@types/jasmine\": \"2.5.38\",\n    \"@types/jquery\": \"^2.0.34\",\n    \"@types/node\": \"^6.0.42\",\n    \"@types/x2js\": \"0.0.27\",\n    \"autoprefixer\": \"^6.6.1\",\n    \"co\": \"^4.6.0\",\n    \"codelyzer\": \"~2.0.0\",\n    \"fs-extra\": \"^2.1.2\",\n    \"gulp\": \"^3.9.1\",\n    \"gulp-comment-swap\": \"0.0.10\",\n    \"gulp-concat\": \"^2.6.0\",\n    \"gulp-git\": \"^1.6.0\",\n    \"gulp-inject\": \"^1.3.1\",\n    \"gulp-insert\": \"^0.5.0\",\n    \"gulp-replace\": \"^0.5.4\",\n    \"gulp-rimraf\": \"^0.2.0\",\n    \"gulp-shell\": \"^0.5.2\",\n    \"gulp-sourcemaps\": \"^1.6.0\",\n    \"gulp-tslint\": \"^4.3.1\",\n    \"gulp-tslint-stylish\": \"^1.1.1\",\n    \"gulp-typedoc\": \"^1.2.1\",\n    \"gulp-typescript\": \"^3.0.1\",\n    \"gulp-uglify\": \"^1.2.0\",\n    \"gulp-util\": \"^3.0.7\",\n    \"gulp-watch\": \"^4.2.4\",\n    \"node-fetch\": \"^1.6.3\",\n    \"replace\": \"^0.3.0\",\n    \"rsync\": \"^0.5.0\",\n    \"run-sequence\": \"^1.2.2\",\n    \"sw-precache\": \"4.2.1\",\n    \"ts-node\": \"~2.0.0\",\n    \"tslint\": \"~4.4.2\",\n    \"webdriver-manager\": \"10.2.5\",\n    \"xml2js\": \"^0.4.17\"\n  }\n}\n"
  },
  {
    "path": "src/Lib.ts",
    "content": "/** Common Library **/\nimport {Injectable} from \"@angular/core\";\nimport * as Immutable from \"immutable\";\nimport {List, Map} from \"immutable\";\nimport * as _ from \"lodash\";\nimport * as moment from 'moment'\nimport {Observable} from \"rxjs\";\nimport {PartialObserver} from \"rxjs/Observer\";\nimport {AnonymousSubscription} from \"rxjs/Subscription\";\nimport {environment} from \"./environments/environment\";\nimport {FormGroup, ValidatorFn} from \"@angular/forms\";\n\nexport var simpleRegExp = '[\\\\[\\\\]\\\\-A-Za-z0-9_~=!:@\\.|\\ ]{3,50}';\n//(https?:\\/\\/(?:www\\.|(?!www))[^\\s\\.]+\\.[^\\s]{2,}|www\\.[^\\s]+\\.[^\\s]{2,})\nexport var urlRegExp = `(https?:\\/\\/(?:www\\.|(?!www))\\.*)`\n\n\n/** this control value must be equal to given control's value */\nexport function equalValueValidator(targetKey: string, toMatchKey: string): ValidatorFn {\n    return (group: FormGroup): { [key: string]: any } => {\n        const target = group.controls[targetKey];\n        const toMatch = group.controls[toMatchKey];\n        if (target.touched && toMatch.touched) {\n            const isMatch = target.value === toMatch.value;\n            // set equal value error on dirty controls\n            if (!isMatch && target.valid && toMatch.valid) {\n                toMatch.setErrors({equalValue: targetKey});\n                const message = targetKey + ' != ' + toMatchKey;\n                return {'equalValue': message};\n            }\n            if (isMatch && toMatch.hasError('equalValue')) {\n                toMatch.setErrors(null);\n            }\n        }\n\n        return null;\n    };\n}\n\nconst rxjsDebugger = true;\nconst rc4Key = '226a3a42f34ddd778ed2c3ba56644315';\nObservable.prototype.sub = Observable.prototype.subscribe;\n\nwindow['con'] = (msg, stringify) => {\n    if (Lib.DevMode()) {\n        if (stringify)\n            msg = JSON.stringify(msg);\n        console.info(`${_.uniqueId()}:${new Date().toLocaleTimeString()} ${msg}`);\n    }\n\n}\n\ndeclare module 'rxjs/Observable' {\n    interface Observable<T> {\n        debug: (...any) => Observable<T>\n    }\n\n    // interface Observable<T> {\n    //     get(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;\n    // }\n}\n\ndeclare module \"rxjs/Observable\" {\n    interface Observable<T> {\n        sub: (observerOrNext: PartialObserver<T> | ((value: T) => void),\n              error: (error: any) => void,\n              complete?: () => void) => AnonymousSubscription;\n    }\n}\n\nObservable.prototype.debug = function (message: string) {\n    return this.do(\n        nextValue => {\n            if (rxjsDebugger) {\n                console.debug('ObsDebug-I: ' + message, (nextValue.type || nextValue))\n            }\n        },\n        error => {\n            if (rxjsDebugger) {\n                console.error('ObsDebug-E: ' + message, error)\n            }\n        },\n        () => {\n            if (rxjsDebugger) {\n                console.debug('ObsDebug-C: ' + message);\n                /** for DevTools colors: **/\n                //console.log(\"%cObsDebug-C %s\", \"color: red\", message);\n            }\n        }\n    );\n};\n\n@Injectable()\nexport class Lib {\n\n    static Con(msg: any, stringify?: boolean) {\n        con(msg, stringify)\n    }\n\n    /**\n     *\n     * @param dateString format of date + time: /Date(1469923200000+0000)/\"\n     * @returns {any}\n     * @constructor\n     */\n    static ProcessDateField(dateString: string, addDay: boolean = false): any {\n        if (_.isUndefined(dateString))\n            return '';\n        var epoc = dateString.match(/Date\\((.*)\\)/)\n        if (epoc[1]) {\n            var date = epoc[1].split('+')[0]\n            var time = epoc[1].split('+')[1]\n            var result;\n            //todo: adding +1 on save to server hack, need to ask Alon\n            if (addDay) {\n                result = moment(Number(date)).add(1, 'day');\n            } else {\n                result = moment(Number(date));\n            }\n            return moment(result).format('YYYY-MM-DD');\n            /** moment examples\n             var a = moment().unix().format()\n             console.log(moment.now());\n             console.log(moment().format('dddd'));\n             console.log(moment().startOf('day').fromNow());\n             **/\n        }\n    }\n\n    static ToValidNumber(i_value): number {\n        if (_.isNaN(i_value))\n            return 0;\n        if (_.isNumber(i_value))\n            return i_value;\n        return 0;\n    }\n\n    static Try(i_fn: () => void) {\n        try {\n            i_fn();\n        } catch (e) {\n            if (Lib.DevMode())\n                console.error('Lib.Try exception in function: ' + i_fn + ' ' + e);\n        }\n    }\n\n    /** deep compare two objects **/\n    static IsEqual(obj1, obj2) {\n        function _equals(obj1, obj2) {\n            var clone = $.extend(true, {}, obj1);\n            var cloneStr = JSON.stringify(clone);\n            return cloneStr === JSON.stringify($.extend(true, clone, obj2));\n        }\n\n        return _equals(obj1, obj2) && _equals(obj2, obj1);\n    }\n\n    static GetThemeColor() {\n        var light = true;\n        if (light)\n            return '#428ac9 ';\n        return '#eb7c66';\n    }\n\n    static EncryptUserPass(i_user, i_pass) {\n        var rc4 = new RC4(rc4Key);\n        var crumb = i_user + ':SignageStudioLite:' + i_pass + ':' + ' USER'\n        return rc4.doEncrypt(crumb);\n    }\n\n    static AlertOnLeave() {\n        if (!Lib.DevMode()) {\n            window.onbeforeunload = function (e) {\n                var message = \"Did you save your changes?\",\n                    e = e || window.event;\n                // For IE and Firefox\n                if (e) {\n                    e.returnValue = message;\n                }\n                // For Safari\n                return message;\n            };\n        }\n\n    }\n\n    /**\n     Format a seconds value into an object broken into hours / minutes / seconds\n     @method formatSecondsToObject\n     @param {Number} i_totalSeconds\n     @return {Object}\n     **/\n    static FormatSecondsToObject(i_totalSeconds) {\n        var seconds: any = 0;\n        var minutes: any = 0;\n        var hours: any = 0;\n        var totalInSeconds = i_totalSeconds;\n        if (i_totalSeconds >= 3600) {\n            hours = Math.floor(i_totalSeconds / 3600);\n            i_totalSeconds = i_totalSeconds - (hours * 3600);\n        }\n        if (i_totalSeconds >= 60) {\n            minutes = Math.floor(i_totalSeconds / 60);\n            seconds = i_totalSeconds - (minutes * 60);\n        }\n        if (hours == 0 && minutes == 0)\n            seconds = i_totalSeconds;\n        var playbackLength = {\n            hours: parseInt(hours),\n            minutes: parseInt(minutes),\n            seconds: parseInt(seconds),\n            totalInSeconds: parseInt(totalInSeconds)\n        };\n        return playbackLength;\n    }\n\n    /**\n     *\n     * @param dateString format of date + time: /Date(1469923200000+0000)/\"\n     * @returns {any}\n     * @constructor\n     */\n    static ProcessDateFieldToUnix(dateString: string, addDay: boolean = false): any {\n        if (_.isUndefined(dateString))\n            return '';\n        //todo: adding +1 on save to server hack, need to ask Alon\n        if (addDay) {\n            return moment(dateString, 'YYYY-MM-DD').add(0, 'day').valueOf();\n        } else {\n            return moment(dateString, 'YYYY-MM-DD').valueOf();\n        }\n    }\n\n    /**\n     Pad zeros\n     @method padZeros\n     @param {Number} n value\n     @param {Number} width pre-pad width\n     @param {Number} z negative as in '-'\n     @return {Number} zero padded string\n     **/\n    static PadZeros(n, width, z) {\n        z = z || '0';\n        n = n + '';\n        return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;\n    }\n\n    /**\n     Convert number or string to float with double precision\n     @method parseToFloatDouble\n     @param {Object} i_value\n     @return {Number}\n     **/\n    static ParseToFloatDouble(i_value: any): number {\n        return parseFloat(parseFloat(i_value).toFixed(2));\n    }\n\n    /**\n     Capitilize first letter\n     @method capitaliseFirst\n     @param {String} string\n     @return {String} string\n     **/\n    static CapitaliseFirst(string) {\n        return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();\n    }\n\n    /**\n     base64Encode\n     @method base64Encode\n     @param {String}\n     @return {String}\n     **/\n    static Base64Encode(str) {\n        var c1, c2, c3;\n        var Base64 = {\n            _keyStr: \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\", encode: function (e) {\n                var t = \"\";\n                var n, r, i, s, o, u, a;\n                var f = 0;\n                e = Base64._utf8_encode(e);\n                while (f < e.length) {\n                    n = e.charCodeAt(f++);\n                    r = e.charCodeAt(f++);\n                    i = e.charCodeAt(f++);\n                    s = n >> 2;\n                    o = (n & 3) << 4 | r >> 4;\n                    u = (r & 15) << 2 | i >> 6;\n                    a = i & 63;\n                    if (isNaN(r)) {\n                        u = a = 64\n                    } else if (isNaN(i)) {\n                        a = 64\n                    }\n                    t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)\n                }\n                return t\n            }, decode: function (e) {\n                var t = \"\";\n                var n, r, i;\n                var s, o, u, a;\n                var f = 0;\n                e = e.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n                while (f < e.length) {\n                    s = this._keyStr.indexOf(e.charAt(f++));\n                    o = this._keyStr.indexOf(e.charAt(f++));\n                    u = this._keyStr.indexOf(e.charAt(f++));\n                    a = this._keyStr.indexOf(e.charAt(f++));\n                    n = s << 2 | o >> 4;\n                    r = (o & 15) << 4 | u >> 2;\n                    i = (u & 3) << 6 | a;\n                    t = t + String.fromCharCode(n);\n                    if (u != 64) {\n                        t = t + String.fromCharCode(r)\n                    }\n                    if (a != 64) {\n                        t = t + String.fromCharCode(i)\n                    }\n                }\n                t = Base64._utf8_decode(t);\n                return t\n            }, _utf8_encode: function (e) {\n                e = e.replace(/\\r\\n/g, \"\\n\");\n                var t = \"\";\n                for (var n = 0; n < e.length; n++) {\n                    var r = e.charCodeAt(n);\n                    if (r < 128) {\n                        t += String.fromCharCode(r)\n                    } else if (r > 127 && r < 2048) {\n                        t += String.fromCharCode(r >> 6 | 192);\n                        t += String.fromCharCode(r & 63 | 128)\n                    } else {\n                        t += String.fromCharCode(r >> 12 | 224);\n                        t += String.fromCharCode(r >> 6 & 63 | 128);\n                        t += String.fromCharCode(r & 63 | 128)\n                    }\n                }\n                return t\n            }, _utf8_decode: function (e) {\n                var t = \"\";\n                var n = 0;\n                var r = c1 = c2 = 0;\n                while (n < e.length) {\n                    r = e.charCodeAt(n);\n                    if (r < 128) {\n                        t += String.fromCharCode(r);\n                        n++\n                    } else if (r > 191 && r < 224) {\n                        c2 = e.charCodeAt(n + 1);\n                        t += String.fromCharCode((r & 31) << 6 | c2 & 63);\n                        n += 2\n                    } else {\n                        c2 = e.charCodeAt(n + 1);\n                        c3 = e.charCodeAt(n + 2);\n                        t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);\n                        n += 3\n                    }\n                }\n                return t\n            }\n        }\n        return Base64.encode(str);\n    }\n\n    /**\n     base64Decode\n     @method base64Decode\n     @param {String}\n     @return {String}\n     **/\n    static Base64Decode(str) {\n        var c1, c2, c3;\n        var Base64 = {\n            _keyStr: \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\", encode: function (e) {\n                var t = \"\";\n                var n, r, i, s, o, u, a;\n                var f = 0;\n                e = Base64._utf8_encode(e);\n                while (f < e.length) {\n                    n = e.charCodeAt(f++);\n                    r = e.charCodeAt(f++);\n                    i = e.charCodeAt(f++);\n                    s = n >> 2;\n                    o = (n & 3) << 4 | r >> 4;\n                    u = (r & 15) << 2 | i >> 6;\n                    a = i & 63;\n                    if (isNaN(r)) {\n                        u = a = 64\n                    } else if (isNaN(i)) {\n                        a = 64\n                    }\n                    t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)\n                }\n                return t\n            }, decode: function (e) {\n                var t = \"\";\n                var n, r, i;\n                var s, o, u, a;\n                var f = 0;\n                e = e.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n                while (f < e.length) {\n                    s = this._keyStr.indexOf(e.charAt(f++));\n                    o = this._keyStr.indexOf(e.charAt(f++));\n                    u = this._keyStr.indexOf(e.charAt(f++));\n                    a = this._keyStr.indexOf(e.charAt(f++));\n                    n = s << 2 | o >> 4;\n                    r = (o & 15) << 4 | u >> 2;\n                    i = (u & 3) << 6 | a;\n                    t = t + String.fromCharCode(n);\n                    if (u != 64) {\n                        t = t + String.fromCharCode(r)\n                    }\n                    if (a != 64) {\n                        t = t + String.fromCharCode(i)\n                    }\n                }\n                t = Base64._utf8_decode(t);\n                return t\n            }, _utf8_encode: function (e) {\n                e = e.replace(/\\r\\n/g, \"\\n\");\n                var t = \"\";\n                for (var n = 0; n < e.length; n++) {\n                    var r = e.charCodeAt(n);\n                    if (r < 128) {\n                        t += String.fromCharCode(r)\n                    } else if (r > 127 && r < 2048) {\n                        t += String.fromCharCode(r >> 6 | 192);\n                        t += String.fromCharCode(r & 63 | 128)\n                    } else {\n                        t += String.fromCharCode(r >> 12 | 224);\n                        t += String.fromCharCode(r >> 6 & 63 | 128);\n                        t += String.fromCharCode(r & 63 | 128)\n                    }\n                }\n                return t\n            }, _utf8_decode: function (e) {\n                var t = \"\";\n                var n = 0;\n                var r = c1 = c2 = 0;\n                while (n < e.length) {\n                    r = e.charCodeAt(n);\n                    if (r < 128) {\n                        t += String.fromCharCode(r);\n                        n++\n                    } else if (r > 191 && r < 224) {\n                        c2 = e.charCodeAt(n + 1);\n                        t += String.fromCharCode((r & 31) << 6 | c2 & 63);\n                        n += 2\n                    } else {\n                        c2 = e.charCodeAt(n + 1);\n                        c3 = e.charCodeAt(n + 2);\n                        t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);\n                        n += 3\n                    }\n                }\n                return t\n            }\n        }\n        return Base64.decode(str);\n    }\n\n    /**\n     Simplify a string to basic character set\n     @method cleanChar\n     @param {String} value\n     @return {String} cleaned string\n     **/\n    static CleanChar(value) {\n        if (value == null)\n            value = '';\n        if ($.isNumeric(value))\n            return value;\n        value = value.replace(/,/g, ' ');\n        value = value.replace(/\\\\}/g, ' ');\n        value = value.replace(/{/g, ' ');\n        value = value.replace(/\"/g, ' ');\n        value = value.replace(/'/g, ' ');\n        value = value.replace(/&/g, 'and');\n        value = value.replace(/>/g, ' ');\n        value = value.replace(/</g, ' ');\n        value = value.replace(/\\[/g, ' ');\n        value = value.replace(/]/g, ' ');\n        return value;\n    }\n\n\n    /**\n     Remove characters that a problemtaic to app / js\n     **/\n    static CleanProbCharacters(i_string: string, i_restriction: number) {\n        switch (i_restriction) {\n            case 1: {\n                i_string = i_string.replace(/{/ig, \"(\");\n                i_string = i_string.replace(/}/ig, \")\");\n            }\n            case 2: {\n                i_string = i_string.replace(/</ig, \"(\");\n                i_string = i_string.replace(/>/ig, \")\");\n            }\n            case 3: {\n                i_string = i_string.replace(/&/ig, \"and\");\n            }\n            case 4: {\n                i_string = i_string.replace(/\"/ig, \"`\");\n                i_string = i_string.replace(/'/ig, \"`\");\n            }\n        }\n        return i_string;\n    }\n\n    static IsNumber(value) {\n        if (_.isNaN(Number(value))) return false;\n        return true;\n    }\n\n    static CleanCharForXml(value: any): any {\n        var clean = function (value: string) {\n            if (_.isUndefined(value))\n                return '';\n            if (_.isNull(value))\n                return '';\n            if (_.isNumber(value))\n                return value;\n            if (_.isBoolean(value))\n                return value;\n            value = value.replace(/\\}/g, ' ');\n            value = value.replace(/%/g, ' ');\n            value = value.replace(/{/g, ' ');\n            value = value.replace(/\"/g, '`');\n            value = value.replace(/'/g, '`');\n            value = value.replace(/&/g, 'and');\n            value = value.replace(/>/g, ' ');\n            value = value.replace(/</g, ' ');\n            value = value.replace(/\\[/g, ' ');\n            value = value.replace(/]/g, ' ');\n            value = value.replace(/#/g, ' ');\n            value = value.replace(/\\$/g, ' ');\n            value = value.replace(/\\^/g, ' ');\n            value = value.replace(/;/g, ' ');\n            return value\n        }\n        if (_.isUndefined(value))\n            return '';\n        if (_.isNull(value))\n            return '';\n        if (_.isNumber(value))\n            return value;\n        if (_.isBoolean(value))\n            return value;\n        if (_.isString(value))\n            return clean(value);\n        _.forEach(value, (v, k) => {\n            // currently we don't support / clean arrays\n            if (_.isArray(value[k]))\n                return value[k] = v;\n            value[k] = clean(v);\n        });\n        return value;\n    }\n\n    static UnionList(a: List<any>, b: List<any>) {\n        return a.toSet().union(b.toSet()).toList();\n    }\n\n    static ProcessHourStartEnd(value: string, key: string): any {\n        if (_.isUndefined(!value))\n            return '';\n        if (key == 'hourStart')\n            return `${value}:00`;\n        return `${value}:59`;\n    }\n\n    /**\n     * CheckFoundIndex will check if a return value is -1 and error out if in dev mode (list.findIndex or indexOf for example)\n     * @param i_value\n     * @param i_message\n     * @returns {number}\n     * @constructor\n     */\n    static CheckFoundIndex(i_value: number, i_message: string = 'CheckFoundIndex did not find index'): number {\n        if (i_value === -1) {\n            console.log(i_message);\n            if (Lib.DevMode()) {\n                alert(i_message);\n                throw Error(i_message);\n            }\n        }\n        return i_value;\n    }\n\n    // static GetCompSelector(i_constructor) {\n    //     return 'need to fix 2';\n    // if (!Lib.DevMode())\n    //     return;\n    // var annotations = Reflect.getMetadata('annotations', i_constructor);\n    // var componentMetadata = annotations.find(annotation => {\n    //     return (annotation instanceof Component);\n    // });\n    // return componentMetadata.selector;\n    // }\n\n    static BootboxHide(i_time = 1500) {\n        setTimeout(() => {\n            bootbox.hideAll();\n        }, i_time)\n    }\n\n    static DateToAbsolute(year, month) {\n        return year * 12 + month;\n    }\n\n    static DateFromAbsolute(value: number) {\n        var year = Math.floor(value / 12);\n        var month = value % 12 + 1;\n        return {\n            year,\n            month\n        }\n    }\n\n    static MapOfIndex(map: Map<string, any>, index: number, position: \"first\" | \"last\"): string {\n        var mapJs = map.toJS();\n        var mapJsPairs = _.toPairs(mapJs);\n        var offset = position == 'first' ? 0 : 1;\n        if (mapJsPairs[index] == undefined)\n            return \"0\"\n        return mapJsPairs[index][offset];\n    }\n\n    /**\n     *  PrivilegesXmlTemplate will generate a template for priveleges in 2 possible modes\n     *\n     *  mode 1: just a raw template (we will ignore the values set) and this is the mode when\n     *  no selPrivName and appStore params are given\n     *\n     *  mode 2: is when we actually serialize data to save to server and in this mode we do pass\n     *  in the selPrivName and appStore which we use to retrieve current values from user appStore\n     *  and generate the final XML to save to server\n     *\n     * @param selPrivName\n     * @param appStore\n     * @param callBack\n     * @constructor\n     */\n    static Base64() {\n\n        var _PADCHAR = \"=\", _ALPHA = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\", _VERSION = \"1.0\";\n\n\n        function _getbyte64(s, i) {\n            // This is oddly fast, except on Chrome/V8.\n            // Minimal or no improvement in performance by using a\n            // object with properties mapping chars to value (eg. 'A': 0)\n\n            var idx = _ALPHA.indexOf(s.charAt(i));\n\n            if (idx === -1) {\n                throw \"Cannot decode base64\";\n            }\n\n            return idx;\n        }\n\n\n        function _decode(s) {\n            var pads = 0, i, b10, imax = s.length, x = [];\n\n            s = String(s);\n\n            if (imax === 0) {\n                return s;\n            }\n\n            if (imax % 4 !== 0) {\n                throw \"Cannot decode base64\";\n            }\n\n            if (s.charAt(imax - 1) === _PADCHAR) {\n                pads = 1;\n\n                if (s.charAt(imax - 2) === _PADCHAR) {\n                    pads = 2;\n                }\n\n                // either way, we want to ignore this last block\n                imax -= 4;\n            }\n\n            for (i = 0; i < imax; i += 4) {\n                b10 = ( _getbyte64(s, i) << 18 ) | ( _getbyte64(s, i + 1) << 12 ) | ( _getbyte64(s, i + 2) << 6 ) | _getbyte64(s, i + 3);\n                x.push(String.fromCharCode(b10 >> 16, ( b10 >> 8 ) & 0xff, b10 & 0xff));\n            }\n\n            switch (pads) {\n                case 1:\n                    b10 = ( _getbyte64(s, i) << 18 ) | ( _getbyte64(s, i + 1) << 12 ) | ( _getbyte64(s, i + 2) << 6 );\n                    x.push(String.fromCharCode(b10 >> 16, ( b10 >> 8 ) & 0xff));\n                    break;\n\n                case 2:\n                    b10 = ( _getbyte64(s, i) << 18) | ( _getbyte64(s, i + 1) << 12 );\n                    x.push(String.fromCharCode(b10 >> 16));\n                    break;\n            }\n\n            return x.join(\"\");\n        }\n\n\n        function _getbyte(s, i) {\n            var x = s.charCodeAt(i);\n\n            if (x > 255) {\n                throw \"INVALID_CHARACTER_ERR: DOM Exception 5\";\n            }\n\n            return x;\n        }\n\n\n        function _encode(s) {\n            if (arguments.length !== 1) {\n                throw \"SyntaxError: exactly one argument required\";\n            }\n\n            s = String(s);\n\n            var i, b10, x = [], imax = s.length - s.length % 3;\n\n            if (s.length === 0) {\n                return s;\n            }\n\n            for (i = 0; i < imax; i += 3) {\n                b10 = ( _getbyte(s, i) << 16 ) | ( _getbyte(s, i + 1) << 8 ) | _getbyte(s, i + 2);\n                x.push(_ALPHA.charAt(b10 >> 18));\n                x.push(_ALPHA.charAt(( b10 >> 12 ) & 0x3F));\n                x.push(_ALPHA.charAt(( b10 >> 6 ) & 0x3f));\n                x.push(_ALPHA.charAt(b10 & 0x3f));\n            }\n\n            switch (s.length - imax) {\n                case 1:\n                    b10 = _getbyte(s, i) << 16;\n                    x.push(_ALPHA.charAt(b10 >> 18) + _ALPHA.charAt(( b10 >> 12 ) & 0x3F) + _PADCHAR + _PADCHAR);\n                    break;\n\n                case 2:\n                    b10 = ( _getbyte(s, i) << 16 ) | ( _getbyte(s, i + 1) << 8 );\n                    x.push(_ALPHA.charAt(b10 >> 18) + _ALPHA.charAt(( b10 >> 12 ) & 0x3F) + _ALPHA.charAt(( b10 >> 6 ) & 0x3f) + _PADCHAR);\n                    break;\n            }\n\n            return x.join(\"\");\n        }\n\n\n        return {\n            decode: _decode,\n            encode: _encode,\n            VERSION: _VERSION\n        };\n    }\n\n    // static LoadComponentAsync(name: string, path: string) {\n    //\n    //     return System.import(path).then(c => c[name]);\n    //\n    //     //return System.import('/dist/public/out.js')\n    //     //    .catch(function (e) {\n    //     //        alert('prob loading out.js ' + e);\n    //     //    }).then(function (e) {\n    //     //        alert(e);\n    //     //        alert(e[name]);\n    //     //        alert(JSON.stringify(e));\n    //     //        return System.import('App1').then(c => c[name]);\n    //     //    });\n    // }\n\n\n    static ConstructImmutableFromTable(path): Array<any> {\n        var arr = [];\n        path.forEach((member) => {\n            var obj = {};\n            obj[member._attr.name] = {\n                table: {}\n            }\n            for (var k in member._attr) {\n                var value = member._attr[k]\n                obj[member._attr.name][k] = value;\n                for (var t in member.Tables[\"0\"]._attr) {\n                    var value = member.Tables[\"0\"]._attr[t]\n                    obj[member._attr.name]['table'][t] = value;\n                }\n            }\n            arr.push(Immutable.fromJS(obj));\n        });\n        return arr;\n    }\n\n    static ComputeMask(accessMask): number {\n        var bits = [1, 2, 4, 8, 16, 32, 64, 128];\n        var computedAccessMask = 0;\n        accessMask.forEach(value => {\n            var bit = bits.shift();\n            if (value) computedAccessMask = computedAccessMask + bit;\n\n        })\n        return computedAccessMask;\n    }\n\n    static ValidateEmail(email) {\n        var re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n        return re.test(email);\n    }\n\n    static GetAccessMask(accessMask): List<any> {\n        var checks = List();\n        var bits = [1, 2, 4, 8, 16, 32, 64, 128];\n        for (var i = 0; i < bits.length; i++) {\n            let checked = (bits[i] & accessMask) > 0 ? true : false;\n            checks = checks.push(checked)\n        }\n        return checks;\n    }\n\n    static GetADaysMask(accessMask): List<any> {\n        var checks = List();\n        var bits = [1, 2, 4, 8, 16, 32, 64];\n        for (var i = 0; i < bits.length; i++) {\n            let checked = (bits[i] & accessMask) > 0 ? true : false;\n            checks = checks.push(checked)\n        }\n        return checks;\n    }\n\n    static log(msg) {\n        console.log(new Date().toTimeString().replace(/.*(\\d{2}:\\d{2}:\\d{2}).*/, \"$1\") + ': ' + msg);\n    }\n\n    static guid(): string {\n        function s4() {\n            return Math.floor((1 + Math.random()) * 0x10000)\n                .toString(16)\n                .substring(1);\n        }\n\n        return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();\n    }\n\n    /**\n     Smart convert color (many) to decinal\n     @method colorToDecimal\n     @param {String} color\n     @return {Number} decimal\n     **/\n    static ColorToDecimal(color) {\n        if (color.match('rgb')) {\n            color = this.RgbToHex(color);\n            return this.HexToDecimal(color)\n        }\n        return this.HexToDecimal(color);\n    }\n\n    static ColorToHex(color) {\n        if (color.match('#')) {\n            return color;\n        }\n        if (color.match('rgb')) {\n            return '#' + this.RgbToHex(color);\n        }\n        return '#' + color;\n    }\n\n    /**\n     Hex to decimal converter\n     @method hexToDecimal\n     @param {String} h\n     @return {Number} decimal\n     **/\n    static HexToDecimal(h) {\n        function hexfix(str) {\n            var v, w;\n            v = parseInt(str, 16);\t// in rrggbb\n            if (str.length == 3) {\n                // nybble colors - fix to hex colors\n                //  0x00000rgb              -> 0x000r0g0b\n                //  0x000r0g0b | 0x00r0g0b0 -> 0x00rrggbb\n                w = ((v & 0xF00) << 8) | ((v & 0x0F0) << 4) | (v & 0x00F);\n                v = w | (w << 4);\n            }\n            return v.toString(16).toUpperCase();\n        }\n\n\n        var h = h.replace(/#/gi, '');\n        h = hexfix(h);\n        return parseInt(h, 16);\n    }\n\n    /**\n     RGB color to hex converter\n     @method rgbToHex\n     @param {Number} rgb\n     @return {String} hex\n     **/\n    static RgbToHex(rgb) {\n        function componentFromStr(numStr, percent) {\n            var num = Math.max(0, parseInt(numStr, 10));\n            return percent ?\n                Math.floor(255 * Math.min(100, num) / 100) : Math.min(255, num);\n        }\n\n        var rgbRegex = /^rgb\\(\\s*(-?\\d+)(%?)\\s*,\\s*(-?\\d+)(%?)\\s*,\\s*(-?\\d+)(%?)\\s*\\)$/;\n        var result, r, g, b, hex = \"\";\n        if ((result = rgbRegex.exec(rgb))) {\n            r = componentFromStr(result[1], result[2]);\n            g = componentFromStr(result[3], result[4]);\n            b = componentFromStr(result[5], result[6]);\n            hex = (0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1);\n        }\n        return hex;\n    }\n\n    /**\n     Decimal to hex converter\n     @method decimalToHex\n     @param {Number} d\n     @return {String} hex\n     **/\n    static DecimalToHex(d) {\n        var hex = Number(d).toString(16);\n        hex = \"000000\".substr(0, 6 - hex.length) + hex;\n        return hex;\n    }\n\n    static ReduxLoggerMiddleware = store => next => action => {\n        // console.log(\"dispatching\", action.type);\n        let result = next(action);\n        //console.log(\"next state\", store.getState());\n        return result\n    };\n\n    /**\n     this.ngmslibService.inDevMode() uses url localhost (window.location.href.indexOf('localhost') > -1)\n     while Lib.DevMode uses environment var\n     */\n    static DevMode(): boolean {\n        if (environment.production) {\n            return false;\n        }\n        return true;\n    }\n\n    static GetSamples(): Object {\n        return {\n            1019: 'Sushi Restaurant,pro',\n            1029: 'food menu board,pro',\n            1007: 'Home and Garden,pro',\n            1009: 'Hotel Lobby,pro',\n            1016: 'Coffee Shop,pro',\n            1011: 'Hobby Shop,pro',\n            1013: 'Sports Bar,pro',\n            1014: 'Museum,pro',\n            1017: 'Bank,pro',\n            1018: 'Gas Station,pro',\n            1020: 'Casino,pro',\n            1000: 'Travel,pro',\n            1021: 'Bicycle Shop,pro',\n            1022: 'Tanning Salon,pro',\n            1023: 'Pharmacy,pro',\n            1024: 'Laser Away,pro',\n            1025: 'Dentistry,pro',\n            1026: 'Clothing store,pro',\n            1027: 'Golf club,pro',\n            1028: 'RC Heli,pro',\n            1030: 'seven eleven,pro',\n            1031: 'Subway,pro',\n            1032: 'Super market,pro',\n            1033: 'Investment Group,pro',\n            1035: 'Synagogue,pro',\n            1036: 'Dry Cleaning,pro',\n            1037: 'Ice Cream Shop,pro',\n            1038: 'Real Estate office,pro',\n            1039: 'Night Club,pro',\n            1040: 'Hockey,pro',\n            1041: 'Train Station,pro',\n            1042: 'Realtor,pro',\n            1043: 'Toy Store,pro',\n            1044: 'Indian Restaurant,pro',\n            1045: 'Library,pro',\n            1046: 'Movie Theater,pro',\n            1047: 'Airport,pro',\n            1048: 'LAX,pro',\n            100310: 'Motel,pro',\n            100301: 'Parks and Recreations,pro',\n            100322: 'Corner Bakery,pro',\n            100331: 'Retirement home,pro',\n            100368: 'Navy recruiting office,pro',\n            100397: 'Martial arts school,pro',\n            100414: 'Supercuts,pro',\n            100432: 'The UPS Store,pro',\n            100438: 'Cruise One,pro',\n            100483: 'Car service,pro',\n            100503: 'fedex kinkos,pro',\n            100510: 'veterinarian,pro',\n            100556: 'YMCA,pro',\n            100574: 'Tax services,pro',\n            100589: 'Wedding planner,pro',\n            100590: 'Cleaning services,pro',\n            100620: 'Pet Training,pro',\n            100661: 'Gymboree Kids,pro',\n            100677: 'Trader Joes,pro',\n            100695: 'Men Haircuts,pro',\n            100722: 'Jiffy Lube,pro',\n            100738: 'Toyota  car dealer,pro',\n            100747: 'Winery,pro',\n            100771: 'Savings and Loans,pro',\n            100805: 'Nail Salon,pro',\n            100822: 'Weight Watchers,pro',\n            100899: 'Dollar Tree,pro',\n            100938: 'Western Bagles,pro',\n            100959: 'Kaiser Permanente,pro',\n            300143: 'Funeral home,pro',\n            205734: 'Church,pro',\n            220354: 'College,pro',\n            206782: 'Dr Waiting Room,pro',\n            300769: 'NFL Stadium,pro',\n            301814: 'University Campus,pro',\n            303038: 'Day care,pro',\n            304430: 'GameStop,pro',\n            307713: 'Del Taco,pro',\n            305333: 'General Hospital,pro',\n            305206: 'Starbucks,pro',\n            308283: 'training and fitness,pro',\n            311519: 'High school hall,pro',\n            309365: 'Winery,pro',\n            310879: 'Law Firm,pro',\n            1001: 'Health Club,pro',\n            1002: 'Gym,pro',\n            1003: 'Flower Shop,pro',\n            1004: 'Car Dealership,pro',\n            1012: 'Pet Shop,pro',\n            1005: 'Hair Salon,pro',\n            1209: 'Motorcycle shop,lite',\n            1210: 'Sushi and Grill,lite',\n            1211: 'the Coffee Shop,lite',\n            1212: 'Pizzeria,lite',\n            1213: 'Music Store,lite',\n            1214: 'Diner,lite',\n            1215: 'the Hair Salon,lite',\n            1216: 'Dentist,lite',\n            1203: 'Jewelry,lite',\n            1217: 'Crossfit,lite',\n            1218: 'Copy and Print shop,lite',\n            1219: 'Antique Store,lite',\n            1220: 'Clock Repair Store,lite',\n            1221: 'Eastern Cuisine,lite',\n            1222: 'the Toy Store,lite',\n            1223: 'Pet Store Grooming,lite',\n            1224: 'the Veterinarian,lite',\n            1225: 'Tattoo Parlor,lite',\n            1226: 'Camera Store,lite',\n            1228: 'Bike shop,lite',\n            1229: 'Gun Shop,lite',\n            1230: 'Chiropractic Clinic,lite',\n            1231: 'French Restaurant,lite',\n            1233: 'Winery,lite',\n            1232: 'Mexican Taqueria,lite',\n            1234: 'Bistro Restaurant,lite',\n            1235: 'Vitamin Shop,lite',\n            1227: 'Tailor Shop,lite',\n            1236: 'Computer Repair,lite',\n            1237: 'Car Detail,lite',\n            1238: 'Asian Restaurants,lite',\n            1239: 'Marijuana Dispensary,lite',\n            1240: 'the Church,lite',\n            1241: 'Synagogue,lite',\n            1242: 'Frozen Yogurt Store,lite',\n            1244: 'Baby Day Care,lite',\n            1052: 'Car wash,lite',\n            1053: 'Smoke shop,lite',\n            1054: 'Yoga place,lite',\n            1055: 'Laundromat,lite',\n            1056: 'Baby clothes,lite',\n            1057: 'Travel agency,lite',\n            1058: 'Real Estate agent,lite'\n        }\n    }\n\n    static Xml2Json() {\n        //https://github.com/metatribal/xmlToJSON\n        var xmlToJSON = (function () {\n\n            this.version = \"1.3\";\n\n            var options = { // set up the default options\n                mergeCDATA: true, // extract cdata and merge with text\n                grokAttr: true, // convert truthy attributes to boolean, etc\n                grokText: true, // convert truthy text/attr to boolean, etc\n                normalize: true, // collapse multiple spaces to single space\n                xmlns: true, // include namespaces as attribute in output\n                namespaceKey: '_ns', // tag name for namespace objects\n                textKey: '_text', // tag name for text nodes\n                valueKey: '_value', // tag name for attribute values\n                attrKey: '_attr', // tag for attr groups\n                cdataKey: '_cdata', // tag for cdata nodes (ignored if mergeCDATA is true)\n                attrsAsObject: true, // if false, key is used as prefix to name, set prefix to '' to merge children and attrs.\n                stripAttrPrefix: true, // remove namespace prefixes from attributes\n                stripElemPrefix: true, // for elements of same name in diff namespaces, you can enable namespaces and access the nskey property\n                childrenAsArray: true // force children into arrays\n            };\n\n            var prefixMatch: any = new RegExp('(?!xmlns)^.*:/');\n            var trimMatch: any = new RegExp('^\\s+|\\s+$g');\n\n            this.grokType = function (sValue) {\n                if (/^\\s*$/.test(sValue)) {\n                    return null;\n                }\n                if (/^(?:true|false)$/i.test(sValue)) {\n                    return sValue.toLowerCase() === \"true\";\n                }\n                if (isFinite(sValue)) {\n                    return parseFloat(sValue);\n                }\n                return sValue;\n            };\n\n            this.parseString = function (xmlString, opt) {\n                return this.parseXML(this.stringToXML(xmlString), opt);\n            }\n\n            this.parseXML = function (oXMLParent, opt) {\n\n                // initialize options\n                for (var key in opt) {\n                    options[key] = opt[key];\n                }\n\n                var vResult = {}, nLength = 0, sCollectedTxt = \"\";\n\n                // parse namespace information\n                if (options.xmlns && oXMLParent.namespaceURI) {\n                    vResult[options.namespaceKey] = oXMLParent.namespaceURI;\n                }\n\n                // parse attributes\n                // using attributes property instead of hasAttributes method to support older browsers\n                if (oXMLParent.attributes && oXMLParent.attributes.length > 0) {\n                    var vAttribs = {};\n\n                    for (nLength; nLength < oXMLParent.attributes.length; nLength++) {\n                        var oAttrib = oXMLParent.attributes.item(nLength);\n                        vContent = {};\n                        var attribName = '';\n\n                        if (options.stripAttrPrefix) {\n                            attribName = oAttrib.name.replace(prefixMatch, '');\n\n                        } else {\n                            attribName = oAttrib.name;\n                        }\n\n                        if (options.grokAttr) {\n                            vContent[options.valueKey] = this.grokType(oAttrib.value.replace(trimMatch, ''));\n                        } else {\n                            vContent[options.valueKey] = oAttrib.value.replace(trimMatch, '');\n                        }\n\n                        if (options.xmlns && oAttrib.namespaceURI) {\n                            vContent[options.namespaceKey] = oAttrib.namespaceURI;\n                        }\n\n                        if (options.attrsAsObject) { // attributes with same local name must enable prefixes\n                            vAttribs[attribName] = vContent;\n                        } else {\n                            vResult[options.attrKey + attribName] = vContent;\n                        }\n                    }\n\n                    if (options.attrsAsObject) {\n                        vResult[options.attrKey] = vAttribs;\n                    } else {\n                    }\n                }\n\n                // iterate over the children\n                if (oXMLParent.hasChildNodes()) {\n                    for (var oNode, sProp, vContent, nItem = 0; nItem < oXMLParent.childNodes.length; nItem++) {\n                        oNode = oXMLParent.childNodes.item(nItem);\n\n                        if (oNode.nodeType === 4) {\n                            if (options.mergeCDATA) {\n                                sCollectedTxt += oNode.nodeValue;\n                            } else {\n                                if (vResult.hasOwnProperty(options.cdataKey)) {\n                                    if (vResult[options.cdataKey].constructor !== Array) {\n                                        vResult[options.cdataKey] = [vResult[options.cdataKey]];\n                                    }\n                                    vResult[options.cdataKey].push(oNode.nodeValue);\n\n                                } else {\n                                    if (options.childrenAsArray) {\n                                        vResult[options.cdataKey] = [];\n                                        vResult[options.cdataKey].push(oNode.nodeValue);\n                                    } else {\n                                        vResult[options.cdataKey] = oNode.nodeValue;\n                                    }\n                                }\n                            }\n                        } /* nodeType is \"CDATASection\" (4) */ else if (oNode.nodeType === 3) {\n                            sCollectedTxt += oNode.nodeValue;\n                        } /* nodeType is \"Text\" (3) */ else if (oNode.nodeType === 1) { /* nodeType is \"Element\" (1) */\n\n                            if (nLength === 0) {\n                                vResult = {};\n                            }\n\n                            // using nodeName to support browser (IE) implementation with no 'localName' property\n                            if (options.stripElemPrefix) {\n                                sProp = oNode.nodeName.replace(prefixMatch, '');\n                            } else {\n                                sProp = oNode.nodeName;\n                            }\n\n                            vContent = xmlToJSON.parseXML(oNode);\n\n                            if (vResult.hasOwnProperty(sProp)) {\n                                if (vResult[sProp].constructor !== Array) {\n                                    vResult[sProp] = [vResult[sProp]];\n                                }\n                                vResult[sProp].push(vContent);\n\n                            } else {\n                                if (options.childrenAsArray) {\n                                    vResult[sProp] = [];\n                                    vResult[sProp].push(vContent);\n                                } else {\n                                    vResult[sProp] = vContent;\n                                }\n                                nLength++;\n                            }\n                        }\n                    }\n                } else if (!sCollectedTxt) { // no children and no text, return null\n                    if (options.childrenAsArray) {\n                        vResult[options.textKey] = [];\n                        vResult[options.textKey].push(null);\n                    } else {\n                        vResult[options.textKey] = null;\n                    }\n                }\n\n                if (sCollectedTxt) {\n                    if (options.grokText) {\n                        var value = this.grokType(sCollectedTxt.replace(trimMatch, ''));\n                        if (value !== null && value !== undefined) {\n                            vResult[options.textKey] = value;\n                        }\n                    } else if (options.normalize) {\n                        vResult[options.textKey] = sCollectedTxt.replace(trimMatch, '').replace(/\\s+/g, \" \");\n                    } else {\n                        vResult[options.textKey] = sCollectedTxt.replace(trimMatch, '');\n                    }\n                }\n\n                return vResult;\n            }\n\n\n            // Convert xmlDocument to a string\n            // Returns null on failure\n            this.xmlToString = function (xmlDoc) {\n                try {\n                    var xmlString = xmlDoc.xml ? xmlDoc.xml : (new XMLSerializer()).serializeToString(xmlDoc);\n                    return xmlString;\n                } catch (err) {\n                    console.log('error ' + err);\n                    return null;\n                }\n            }\n\n            // Convert a string to XML Node Structure\n            // Returns null on failure\n            this.stringToXML = function (xmlString) {\n                try {\n                    var xmlDoc = null;\n\n                    if (window['DOMParser']) {\n\n                        var parser = new DOMParser();\n                        xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n                        return xmlDoc;\n                    } else {\n                        xmlDoc = new ActiveXObject(\"Microsoft.XMLDOM\");\n                        xmlDoc.async = false;\n                        xmlDoc.loadXML(xmlString);\n\n                        return xmlDoc;\n                    }\n                } catch (e) {\n                    console.log('error stringToXML ' + e);\n                    return null;\n                }\n            }\n\n            return this;\n        }).call({});\n        return xmlToJSON;\n    }\n\n\n}\n\n\n/* tslint:disable */\n// polyfill for Object.assign (not part of TS yet)\n// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\nif (!Object.assign) {\n    Object.defineProperty(Object, \"assign\", {\n        enumerable: false,\n        configurable: true,\n        writable: true,\n        value: function (target) {\n            \"use strict\";\n            if (target === undefined || target === null) {\n                throw new TypeError(\"Cannot convert first argument to object\");\n            }\n\n            var to = Object(target);\n            for (var i = 1; i < arguments.length; i++) {\n                var nextSource = arguments[i];\n                if (nextSource === undefined || nextSource === null) {\n                    continue;\n                }\n                nextSource = Object(nextSource);\n\n                var keysArray = Object.keys(nextSource);\n                for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {\n                    var nextKey = keysArray[nextIndex];\n                    var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);\n                    if (desc !== undefined && desc.enumerable) {\n                        to[nextKey] = nextSource[nextKey];\n                    }\n                }\n            }\n            return to;\n        }\n    });\n}\n\n// window['StringJS'] = ss.default;\n// MyS.prototype = StringJS('')\n// MyS.prototype.constructor = MyS;\n// function MyS(val) {\n//     this.setValue(val);\n// }\n//\n// var formatMoney = function(n, c, d, t){\n//     var c = isNaN(c = Math.abs(c)) ? 2 : c,\n//         d = d == undefined ? \".\" : d,\n//         t = t == undefined ? \",\" : t,\n//         s = n < 0 ? \"-\" : \"\",\n//         i:any = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),\n//         j = (j = i.length) > 3 ? j % 3 : 0;\n//     return s + (j ? i.substr(0, j) + t : \"\") + i.substr(j).replace(/(\\d{3})(?=\\d)/g, \"$1\" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : \"\");\n// };\n//\n// MyS.prototype.isBlank = function () {\n//     var value = this.s;\n//     if (_.isNaN(value))\n//         return true;\n//     if (_.isUndefined(value))\n//         return true;\n//     if (_.isNull(value))\n//         return true;\n//     if (_.isEmpty(String(value)))\n//         return true;\n//     return false;\n// }\n//\n// MyS.prototype.isNotBlank = function () {\n//     var value = this.s;\n//     if (_.isNaN(value))\n//         return false;\n//     if (_.isUndefined(value))\n//         return false;\n//     if (_.isNull(value))\n//         return false;\n//     if (_.isEmpty(String(value)))\n//         return false;\n//     return true;\n// }\n//\n// /**\n//  *  booleanToNumber\n//  *  convert boolean to a number 0 or 1\n//  *  if forceCast is true, it will always return a number, else it will alow strings to pass through it\n//  * @param forceCast\n//  * @returns {any}\n//  */\n// MyS.prototype.booleanToNumber = function (forceCasting: boolean = false) {\n//     var value = this.s;\n//     if (value == '')\n//         return 0;\n//     if (_.isUndefined(value) || _.isNull(value) || value == 'NaN' || value == 'null' || value == 'NULL')\n//         return 0;\n//     if (value === \"0\" || value === 'false' || value === \"False\" || value === false)\n//         return 0;\n//     if (value === 1 || value === \"true\" || value === \"True\" || value === true)\n//         return 1;\n//     if (forceCasting) {\n//         return parseInt(value);\n//     } else {\n//         return value;\n//     }\n// }\n//\n// MyS.prototype.toCurrency = function (format?: 'us'|'eu') {\n//\n//     var value = StringJS(this.s).toFloat(2);\n//     if (_.isNaN(value))\n//         value = 0;\n//     switch (format) {\n//         case 'eu': {\n//             return '€' + formatMoney(value, 2, '.', ',');\n//         }\n//         case 'us': {}\n//         default: {\n//             return '$' + formatMoney(value, 2, '.', ',');\n//         }\n//     }\n// }\n//\n// MyS.prototype.toPercent = function () {\n//     return StringJS(this.s).toFloat(2) + '%';\n// }\n//\n// MyS.prototype.fileTailName = function (i_level) {\n//     var fileName = this.s;\n//     var arr = fileName.split('/');\n//     var size = arr.length;\n//     var c = arr.slice(0 - i_level, size)\n//     return new this.constructor(c.join('/'));\n// }\n//\n// MyS.prototype.cleanChar = function () {\n//     var value = this.s;\n//     if (_.isUndefined(value))\n//         return '';\n//     if (_.isNull(value))\n//         return '';\n//     if (_.isNumber(value))\n//         return value;\n//     if (_.isBoolean(value))\n//         return value;\n//     value = value.replace(/\\}/g, ' ');\n//     value = value.replace(/%/g, ' ');\n//     value = value.replace(/{/g, ' ');\n//     value = value.replace(/\"/g, '`');\n//     value = value.replace(/'/g, '`');\n//     value = value.replace(/&/g, 'and');\n//     value = value.replace(/>/g, ' ');\n//     value = value.replace(/</g, ' ');\n//     value = value.replace(/\\[/g, ' ');\n//     value = value.replace(/]/g, ' ');\n//     value = value.replace(/#/g, ' ');\n//     value = value.replace(/\\$/g, ' ');\n//     value = value.replace(/\\^/g, ' ');\n//     value = value.replace(/;/g, ' ');\n//     return value;\n// }\n//\n// window['StringJS'] = function (str) {\n//     if (_.isNull(str) || _.isUndefined(str))\n//         str = '';\n//     return new MyS(str);\n// }"
  },
  {
    "path": "src/app/app-component.css",
    "content": ".md-radio-button {\n    padding-left: 20px;\n}"
  },
  {
    "path": "src/app/app-component.html",
    "content": "<div id=\"domRoot\" [ngClass]=\"{hidden: m_hidden}\">\n    <div id=\"headerPad\"></div>\n    <nav id=\"fileMenu\" class=\"navbar navbar-inverse navbar-fixed-top\" role=\"navigation\">\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\" data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <span class=\"pull-left\" id=\"angularText\" style=\"color: ghostwhite; padding-top: 5px; padding-left: 10px\">\n\n                <Logo          class=\"pull-left\" *ngIf=\"isBrandingDisabled\" style=\"padding-left: 5px; padding-top: 5px\"></Logo>\n                <reseller-logo class=\"pull-left\" *ngIf=\"!isBrandingDisabled\" style=\"padding-left: 5px; padding-top: 5px\"></reseller-logo>\n\n                <span class=\"pull-left\" style=\"padding-top: 4px; padding-left: 4px\">\n                    <span style=\"font-size: 1.4em\">{{productName}}</span>\n                    <!--<label [ngClass]=\"{offline: offlineDevMode}\" style=\"padding-left: 20px; font-size: 10px; color: gray; font-family: Arial\">version {{version}} | angular build {{ngVersion}} | {{offlineDevMode==true ? 'offline' : 'online'}}</label>-->\n                </span>\n                <div class=\"clearfix\"></div>\n\n            </span>\n\n        </div>\n        <div id=\"appNavigatorComp\" class=\"noCollapsing collapse navbar-collapse\" id=\"bs-example-navbar-collapse-1\">>\n            <ng-menu [routePrefix]=\"'App1'\" [fileMenuMode]=\"false\">\n                <ng-menu-item [fontawesome]=\"'fa-dashboard'\" i18n-title name=\"Dashboard\" title=\"Dashboard\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-navicon'\" i18n-title name=\"Campaigns\" title=\"Campaigns\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-certificate'\" i18n-title name=\"Resources\" title=\"Resources\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-edit'\" i18n-title name=\"Scenes\" title=\"Scenes\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-laptop'\" i18n-title name=\"Stations\" title=\"Stations\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-group'\" i18n-title name=\"Fasterq\" title=\"Fasterq\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-heart'\" i18n-title name=\"Help\" title=\"Help\"></ng-menu-item>\n                <ng-menu-item *ngIf=\"isBrandingDisabled\" [fontawesome]=\"'fa-laptop'\" i18n-title name=\"Install\" title=\"Install\"></ng-menu-item>\n                <!--<ng-menu-item [fontawesome]=\"'fa-cog'\" name=\"Settings\" title=\"'Settings'\"></ng-menu-item>-->\n                <ng-menu-item [fontawesome]=\"'fa-cloud-upload'\" i18n-title name=\"Studiopro\" title=\"Studiopro\"></ng-menu-item>\n                <ng-menu-item [fontawesome]=\"'fa-power-off'\" i18n-title name=\"Logout\" title=\"Logout\"></ng-menu-item>\n            </ng-menu>\n\n            <ul style=\"height: 20px\" class=\"nav navbar-nav navbar-right noCollapsing\">\n                <li>\n                    <a i18n-title title=\"upgrade\" style=\"padding-bottom: 0px; margin-bottom: 0px\" (click)=\"_onMenuIcon('upgrade',$event)\" *ngIf=\"isBrandingDisabled\" class=\"showUpgradeModal reshid\" href=\"#\"><i style=\"color: red\" class=\"faHeader fa fa-cloud-upload\"></i></a>\n                </li>\n                <li>\n                    <a i18n-title title=\"Cont-S\" style=\"padding-bottom: 0px; margin-bottom: 0px\" (click)=\"_onMenuIcon('save',$event)\" href=\"#\"><i style=\"color: greenyellow\" class=\"faHeader fa fa-save\"></i></a>\n                </li>\n                <li>\n                    <a i18n-title title=\"language\" style=\"padding-bottom: 0px; margin-bottom: 0px\" (click)=\"_onMenuIcon('locale',$event)\" href=\"#\"><i class=\"faHeader fa fa-question-circle\"></i></a>\n                </li>\n                <li>\n                    <a i18n-title title=\"live chat\" (click)=\"_onMenuIcon('chat',$event)\" *ngIf=\"isBrandingDisabled\" class=\"reshid\" id=\"liveChat\" href=\"#\"><i class=\"faHeader fa fa-comments-o\"></i></a>\n                </li>\n                <li style=\"padding-right: 20px\">\n                    <a i18n-title title=\"web site\" style=\"padding-bottom: 0px; margin-bottom: 0px\" (click)=\"_onMenuIcon('web',$event)\" *ngIf=\"isBrandingDisabled\"  href=\"#\"><i class=\"faHeader fa fa-globe\"></i></a>\n                </li>\n                <!--<li style=\"padding-right: 20px\">-->\n                <!--<a (click)=\"_onMenuIcon('dash',$event)\" id=\"dashboard\" href=\"#\"><i class=\"faHeader fa fa-dashboard\"></i></a>-->\n                <!--</li>-->\n            </ul>\n\n        </div>\n    </nav>\n    <div id=\"appEntry\">\n        <router-outlet></router-outlet>\n\n        <div id=\"waitScreenEntryApp\" style=\"display: none\">\n            <span style=\"position: absolute; left: 45%; top: 20%\"> <img src=\"./assets/preload5.gif\"> </span>\n        </div>\n        <div id=\"appLogout\" style=\"display: none\"> <span style=\"position: absolute; left: 40%; top: 20%\">\n      <h3 data-localize=\"haveNiceDay\">Have a nice day :)</h3>\n      </span>\n        </div>\n        <div id=\"appSelector\" class=\"noScroll container\" style=\"display: none\">\n            <div align=\"center\" style=\"padding-top: 100px\">\n                <button type=\"button\" name=\"mailWasp\" class=\"btn btn-default\">\n                    <i style=\"margin: 20px; padding: 20px; font-size: 5em\" class=\"fa fa-envelope\"></i>\n                    <span data-localize=\"none\"></span>\n                </button>\n                <button type=\"button\" name=\"everNodes\" class=\"btn btn-default\">\n                    <i style=\"margin: 20px; padding: 20px ; font-size: 5em\" class=\"fa fa-sitemap\"></i>\n                    <span data-localize=\"none\"></span>\n                </button>\n            </div>\n        </div>\n        <div id=\"appMailWaspContent\" class=\"noScroll container\" style=\"display: none\"></div>\n        <div id=\"appEverNodesContent\" class=\"noScroll container\" style=\"display: none\"></div>\n    </div>\n</div>\n<div *ngIf=\"m_showMode == m_ShowModeEnum.SAVE\">\n    <loading [style]=\"{'margin-top': '150px'}\"></loading>\n    <h5 style=\"text-align: center; margin-top: 20px\" i18n>loading...</h5>\n</div>\n<div [@logoutState]=\"m_logoutState\" *ngIf=\"m_showMode == m_ShowModeEnum.LOGOUT\">\n    <h1 style=\"text-align: center; margin-top: 200px\"><span i18n>have a nice day </span></h1>\n    <h1 style=\"text-align: center\"><i class=\"fa fa-smile-o\"></i></h1>\n</div>\n\n<live-preview *ngIf=\"m_showMode == m_ShowModeEnum.PREVIEW\"></live-preview>\n\n<modal #modalProUpgrade>\n    <modal-header [show-close]=\"true\">\n        <h4 i18n class=\"modal-title\">Upgrade to Enterprise</h4>\n    </modal-header>\n    <modal-body>\n        <pro-upgrade></pro-upgrade>\n    </modal-body>\n    <modal-footer [show-default-buttons]=\"false\"></modal-footer>\n</modal>\n\n<modal #modalLocale>\n    <modal-header [show-close]=\"true\">\n        <h4 i18n class=\"modal-title\">Pick your language</h4>\n    </modal-header>\n    <modal-body>\n        <locale-selector #localSelector (onLocaleChanged)=\"_onLocaleChanged($event)\" [orientation]=\"'modal'\"></locale-selector>\n    </modal-body>\n    <modal-footer [show-default-buttons]=\"false\"></modal-footer>\n</modal>\n\n\n"
  },
  {
    "path": "src/app/app-component.ts",
    "content": "import {AfterViewInit, Component, VERSION, ViewChild, ViewContainerRef} from \"@angular/core\";\nimport \"rxjs/add/operator/catch\";\nimport {ActivatedRoute, NavigationEnd, Router} from \"@angular/router\";\nimport {CommBroker} from \"../services/CommBroker\";\nimport {EventManager, Title} from \"@angular/platform-browser\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {Observable} from \"rxjs\";\nimport * as packageJson from \"../../package.json\";\nimport {AuthService} from \"../services/AuthService\";\nimport {LocalStorage} from \"../services/LocalStorage\";\nimport {YellowPepperService} from \"../services/yellowpepper.service\";\nimport {RedPepperService} from \"../services/redpepper.service\";\nimport {IUiState} from \"../store/store.data\";\nimport {ACTION_LIVELOG_UPDATE, ACTION_UISTATE_UPDATE} from \"../store/actions/appdb.actions\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {Map, List} from 'immutable';\nimport {Consts} from \"../interfaces/Consts\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport * as moment from 'moment'\nimport {LiveLogModel} from \"../models/live-log-model\";\nimport {LocaleSelector} from \"./locale-selector/local-selector\";\n\nenum MainAppShowModeEnum {\n    MAIN,\n    SAVE,\n    PREVIEW,\n    LOGOUT\n}\n\nexport enum MainAppShowStateEnum {\n    INIT,\n    NORMAL,\n    SAVE,\n    SAVING,\n    SAVE_AND_PREVIEW,\n    SAVED,\n    GOODBYE\n}\n\n@Component({\n    selector: 'app-root',\n    templateUrl: './app-component.html',\n    animations: [\n        trigger('logoutState', [\n            state('active', style({\n                transform: 'scale(2)',\n                alpha: 0\n            })),\n            transition('* => active', animate('1000ms ease-out'))\n        ])\n    ]\n})\n\nexport class AppComponent implements AfterViewInit {\n    version: string;\n    ngVersion: string;\n    offlineDevMode: any = window['offlineDevMode'];\n    m_ShowModeEnum = MainAppShowModeEnum;\n    m_showMode: any = MainAppShowModeEnum.MAIN;\n    m_hidden = false;\n    m_localSelected;\n    // isBrandingDisabled: Observable<boolean>;\n    syncOnSave = false;\n    m_logoutState = '';\n    productName = 'Studio-Lite';\n    isBrandingDisabled: boolean = false;\n    demoModeMsg = `Sorry cannot save while in demo mode, <a href=\"https://secure.digitalsignage.com/msgetstarted/#selectStudioLite\">please open a new FREE account</a> to be able to use all features...`;\n\n    constructor(private router: Router,\n                private localStorage: LocalStorage,\n                private commBroker: CommBroker,\n                private rp: RedPepperService,\n                private authService: AuthService,\n                private yp: YellowPepperService,\n                private activatedRoute: ActivatedRoute,\n                private vRef: ViewContainerRef,\n                private titleService: Title,\n                private eventManager: EventManager,\n                private toastr: ToastsManager) {\n\n        // this.version = packageJson.version;\n        // this.ngVersion = VERSION.full\n\n        // this.localStorage.removeItem('remember_me')\n        // this.localStorage.removeItem('business_id')\n        // this.localStorage.removeItem('no_show_limited')\n\n        this.checkPlatform();\n        this.listenAppStateChange();\n        this.toastr.setRootViewContainerRef(vRef);\n        this.listenRouterUpdateTitle();\n        this.listenUpgradeEnterpris();\n        this.listenSaves();\n        this.appResized();\n        Observable.fromEvent(window, 'resize').debounceTime(250)\n            .subscribe(() => {\n                this.appResized();\n            }, (e) => {\n                console.error(e)\n            });\n    }\n\n    @ViewChild('modalProUpgrade')\n    modal: ModalComponent;\n\n    @ViewChild('modalLocale')\n    modalLocale: ModalComponent;\n\n    @ViewChild('localSelector')\n    localSelector: LocaleSelector;\n\n    ngOnInit() {\n\n        this.yp.isBrandingDisabled()\n            .subscribe((v) => {\n                this.isBrandingDisabled = v;\n                if (!this.isBrandingDisabled)\n                    this.productName = this.rp.getUserData().resellerName;\n            }, (e) => console.error(e));\n\n        let s = this.router.events\n            .subscribe((val) => {\n                if (val instanceof NavigationEnd) {\n                    if (val.url.indexOf('data') > -1 || val.url.indexOf('remoteStatus') > -1) {\n                        this.router.navigate(['/FasterqTerminal', val.url.split('?')[1]]);\n                    } else {\n                        this.authService.start();\n                    }\n                    s.unsubscribe();\n                }\n            }, (e) => console.error(e));\n    }\n\n    _onMenuIcon(icon, event) {\n        event.stopImmediatePropagation();\n        event.preventDefault();\n        switch (icon) {\n            case 'web': {\n                window.open('http://www.digitalsignage.com', '_blank');\n                break;\n            }\n            case 'chat': {\n                window.open('http://www.digitalsignage.com/_html/live_chat.html', '_blank');\n                break;\n            }\n            case 'upgrade': {\n                this.modal.open();\n                break;\n            }\n            case 'save': {\n                this.saveAndRestartPrompt(() => {\n                })\n                break;\n            }\n            case 'locale': {\n                this.modalLocale.open();\n                break;\n            }\n        }\n    }\n\n    /**\n     Save and serialize configuration to remote mediaSERVER> Save and restart will check if\n     the Stations module has been loaded and if no connected stations are present, it will NOT\n     prompt for option to restart station on save, otherwise it will.\n     @method saveAndRestartPrompt\n     @param {Function} call back after save\n     **/\n    saveAndRestartPrompt(i_callBack) {\n        bootbox.dialog({\n            message: 'Restart connected stations and apply your saved work?',\n            title: 'Save work to remote server',\n            buttons: {\n                success: {\n                    label: 'OK',\n                    className: \"btn-success\",\n                    callback: () => {\n                        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE}\n                        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'app saved'})}));\n                    }\n                },\n                danger: {\n                    label: 'Save & restart stations',\n                    className: \"btn-success\",\n                    callback: () => {\n                        // reboot will reboot the PC or exits presentation android\n                        // pepper.sendCommand('rebootStation', -1, function () {});\n                        // reboot player exits player\n                        // pepper.sendCommand('rebootPlayer', -1, function () {\n                        // sync and restart does a fast / soft restart of player\n                        this.syncOnSave = true;\n                        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE}\n                        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'app saved and restarting all stations'})}));\n                    }\n                },\n                main: {\n                    label: 'Cancel',\n                    callback: () => {\n                        return;\n                    }\n                }\n            }\n        });\n    }\n\n    ngAfterViewInit() {\n        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.NORMAL}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onLocaleChanged(i_localSelected) {\n        this.m_localSelected = i_localSelected;\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: {mainAppState: MainAppShowStateEnum.SAVE}}));\n        this.modalLocale.close();\n    }\n\n    private listenAppStateChange() {\n        this.yp.listenMainAppState()\n            .subscribe((i_value: MainAppShowStateEnum) => {\n                switch (i_value) {\n\n                    case MainAppShowStateEnum.SAVE_AND_PREVIEW: {\n                        if (this.rp.getUserData().businessID == 459848) {\n                            this.viewMode(MainAppShowModeEnum.MAIN);\n                            const uiState: IUiState = {mainAppState: MainAppShowStateEnum.NORMAL};\n                            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n                            return bootbox.alert(this.demoModeMsg);\n                        }\n                        this.save(() => {\n                            this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'loading preview'})}));\n                            this.viewMode(MainAppShowModeEnum.PREVIEW);\n                        });\n                        break;\n                    }\n\n                    case MainAppShowStateEnum.NORMAL: {\n                        this.viewMode(MainAppShowModeEnum.MAIN);\n                        break;\n                    }\n\n                    case MainAppShowStateEnum.SAVED: {\n                        con('Saved to server');\n                        if (this.syncOnSave)\n                            this.rp.sendCommand('syncAndStart', -1, () => {\n                            });\n                        this.syncOnSave = false;\n                        const uiState: IUiState = {appSaved: moment().format('h:mm:ss')};\n                        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n                        if (this.m_localSelected)\n                            this.localSelector.redirect(this.m_localSelected)\n                        break;\n                    }\n\n                    case MainAppShowStateEnum.GOODBYE: {\n                        con('Goodbye');\n                        this.m_logoutState = 'active'\n                        this.viewMode(MainAppShowModeEnum.LOGOUT);\n                        break;\n                    }\n\n                    case MainAppShowStateEnum.SAVE: {\n                        if (this.rp.getUserData().businessID == 459848) {\n                            this.viewMode(MainAppShowModeEnum.MAIN);\n                            const uiState: IUiState = {mainAppState: MainAppShowStateEnum.NORMAL};\n                            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n                            return bootbox.alert(this.demoModeMsg);\n                        }\n                        this.save(() => {\n                            this.viewMode(MainAppShowModeEnum.MAIN);\n                            const uiState: IUiState = {mainAppState: MainAppShowStateEnum.NORMAL};\n                            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n                        });\n                        break;\n                    }\n                }\n            }, (e) => console.error(e))\n    }\n\n    private save(i_cb: () => void) {\n        this.viewMode(MainAppShowModeEnum.SAVE);\n        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVING}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.rp.save((result) => {\n            if (result.status == true) {\n                this.rp.reduxCommit(null, true)\n                let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVED}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                i_cb();\n            } else {\n                alert('error ' + JSON.stringify(result));\n            }\n        })\n    }\n\n    private viewMode(i_mode: MainAppShowModeEnum) {\n        this.m_showMode = i_mode;\n        switch (i_mode) {\n            case MainAppShowModeEnum.MAIN: {\n                this.m_hidden = false;\n                break;\n            }\n            case MainAppShowModeEnum.PREVIEW: {\n                this.m_hidden = true;\n                break;\n            }\n            case MainAppShowModeEnum.SAVE: {\n                this.m_hidden = true;\n                break;\n            }\n            case MainAppShowModeEnum.LOGOUT: {\n                this.m_hidden = true;\n                break;\n            }\n        }\n    }\n\n    private checkPlatform() {\n        switch (platform.name.toLowerCase()) {\n            case 'microsoft edge': {\n                // alert(`${platform.name} browser not supported at this time, please use Google Chrome`);\n                break;\n            }\n            case 'chrome': {\n                break;\n            }\n            default: {\n                // alert('for best performance please use Google Chrome');\n                break;\n            }\n        }\n    }\n\n    private listenUpgradeEnterpris() {\n        this.commBroker.onEvent(Consts.Events().UPGRADE_ENTERPRISE)\n            .subscribe((v) => {\n                this.modal.open();\n            }, (e) => console.error(e));\n    }\n\n    private listenSaves() {\n        this.eventManager.addGlobalEventListener('window', 'keydown.control.s', (event) => {\n            event.preventDefault();\n            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: {mainAppState: MainAppShowStateEnum.SAVE}}));\n        })\n    }\n\n    public appResized(): void {\n        var appHeight = document.body.clientHeight;\n        var appWidth = document.body.clientWidth;\n        var uiState: IUiState = {appSized: Map({width: appWidth, height: appHeight})}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n\n        this.commBroker.setValue(Consts.Values().APP_SIZE, {\n            height: appHeight,\n            width: appWidth\n        });\n        this.commBroker.fire({\n            fromInstance: self,\n            event: Consts.Events().WIN_SIZED,\n            context: '',\n            message: {\n                height: appHeight,\n                width: appWidth\n            }\n        })\n    }\n\n    private listenRouterUpdateTitle() {\n        this.router.events\n            .filter(event => event instanceof NavigationEnd)\n            .map(() => this.activatedRoute)\n            .map(route => {\n                while (route.firstChild) {\n                    route = route.firstChild\n                }\n                return route;\n            }).filter(route => route.outlet === 'primary')\n            .mergeMap(route => route.data)\n            .subscribe((event) => {\n                this.titleService.setTitle(event['title'])\n            }, (e) => console.error(e));\n    }\n}"
  },
  {
    "path": "src/app/app-module.ts",
    "content": "import {BrowserModule} from \"@angular/platform-browser\";\nimport {Compiler, NgModule, ErrorHandler} from \"@angular/core\";\nimport {FormsModule, ReactiveFormsModule} from \"@angular/forms\";\nimport {HttpModule, JsonpModule} from \"@angular/http\";\nimport {Ng2Bs3ModalModule} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {AppComponent} from \"./app-component\";\nimport {LocalStorage} from \"../services/LocalStorage\";\nimport {RedPepperService} from \"../services/redpepper.service\";\nimport {YellowPepperService} from \"../services/yellowpepper.service\";\nimport {MsLibModule} from \"ng-mslib/dist/mslib.module\";\nimport {ToastModule, ToastOptions} from \"ng2-toastr\";\nimport {AccordionModule, AlertModule, ModalModule} from \"ngx-bootstrap\";\nimport {DropdownModule, DropdownModule as DropdownModulePrime, InputTextModule, SelectButtonModule, TreeModule} from \"primeng/primeng\";\nimport {routing} from \"../app-routes\";\nimport {LoginPanel} from \"../comps/entry/LoginPanel\";\nimport {Logout} from \"../comps/logout/Logout\";\nimport {AgmCoreModule} from \"angular2-google-maps/core\";\nimport {ImgLoader} from \"../comps/imgloader/ImgLoader\";\nimport {ChartModule} from \"angular2-highcharts\";\nimport {CommBroker} from \"../services/CommBroker\";\nimport {AUTH_PROVIDERS} from \"../services/AuthService\";\nimport {StoreService} from \"../services/StoreService\";\nimport {NgMenu} from \"../comps/ng-menu/ng-menu\";\nimport {NgMenuItem} from \"../comps/ng-menu/ng-menu-item\";\nimport {AutoLogin} from \"../comps/entry/AutoLogin\";\nimport {StoreModule} from \"@ngrx/store\";\nimport {INITIAL_APPLICATION_STATE} from \"../store/application.state\";\nimport {EffectsModule} from \"@ngrx/effects\";\nimport {StoreDevtoolsModule} from \"@ngrx/store-devtools\";\nimport {ACTION_LIVELOG_UPDATE, AppdbAction} from \"../store/actions/appdb.actions\";\nimport {AppDbEffects} from \"../store/effects/appdb.effects\";\nimport {MsdbEffects} from \"../store/effects/msdb.effects\";\nimport {environment} from \"../environments/environment\";\nimport {productionReducer} from \"../store/store.data\";\nimport {NgmslibService} from \"ng-mslib\";\nimport {SharedModule} from \"../modules/shared.module\";\nimport {Dashboard} from \"./dashboard/dashboard-navigation\";\nimport {Appwrap} from \"./appwrap\";\nimport \"hammerjs\";\nimport \"print-js\";\nimport \"gsap\";\nimport \"gsap/CSSPlugin\";\nimport \"gsap/Draggable\";\nimport \"gsap/TweenLite\";\nimport \"gsap/ScrollToPlugin\";\nimport {Lib} from \"../Lib\";\nimport {FontLoaderService} from \"../services/font-loader-service\";\nimport {SimpleGridModule} from \"../comps/simple-grid-module/SimpleGridModule\";\nimport {GlobalErrorHandler} from \"../services/global-error-handler\";\nimport {BrowserAnimationsModule} from \"@angular/platform-browser/animations\";\nimport {FasterqTerminal} from \"./fasterq/fasterq-terminal\";\nimport {WizardService} from \"../services/wizard-service\";\nimport {ResellerLogo} from \"../comps/logo/reseller-logo\";\nimport {DashPanel} from \"./dashboard/dash-panel\";\nimport {ServerAvg} from \"./dashboard/server-avg\";\nimport {StorageUsed} from \"./dashboard/storage-used\";\nimport {LiveLogModel} from \"../models/live-log-model\";\n\n// import \"fabric\"; // need to remove if we import via cli\n// import {ScreenTemplate} from \"../comps/screen-template/screen-template\";\n\ndeclare global {\n    interface JQueryStatic {\n        base64: any;\n        knob: any;\n        gradientPicker: any;\n        timepicker: any;\n        contextmenu: any;\n        index: any;\n    }\n}\n\nexport class CustomToastOption extends ToastOptions {\n    animate: 'flyRight';\n    positionClass: 'toast-bottom-right';\n    toastLife: 10000;\n    showCloseButton: true;\n    maxShown: 5;\n    newestOnTop: true;\n    enableHTML: true;\n    dismiss: 'auto';\n    messageClass: \"\";\n    titleClass: \"\"\n}\n\nexport const providing = [CommBroker, WizardService, AUTH_PROVIDERS, RedPepperService, YellowPepperService, LocalStorage, StoreService, FontLoaderService, AppdbAction, {\n    provide: \"OFFLINE_ENV\",\n    useValue: window['offlineDevMode']\n    },\n    {\n        provide: \"HYBRID_PRIVATE\",\n        useValue: false\n    },\n    {\n        provide: ErrorHandler,\n        useClass: GlobalErrorHandler\n    },\n    {\n        provide: ToastOptions,\n        useClass: CustomToastOption\n    }\n];\n\nconst decelerations = [AppComponent, AutoLogin, LoginPanel, Appwrap, Dashboard, Logout, NgMenu, NgMenuItem, ImgLoader, FasterqTerminal, DashPanel, ServerAvg, StorageUsed];\n\nexport function appReducer(state: any = INITIAL_APPLICATION_STATE, action: any) {\n    if (environment.production) {\n        return productionReducer(state, action);\n    } else {\n        return productionReducer(state, action);\n        // return developmentReducer(state, action);\n    }\n}\n\n\n@NgModule({\n    declarations: [decelerations],\n    imports: [\n        BrowserModule,\n        FormsModule,\n        BrowserAnimationsModule,\n        ReactiveFormsModule,\n        Ng2Bs3ModalModule,\n        HttpModule,\n        ChartModule,\n        StoreModule.provideStore(appReducer),\n        EffectsModule.run(AppDbEffects),\n        EffectsModule.run(MsdbEffects),\n        environment.imports,  \n        // StoreDevtoolsModule.instrumentStore({maxAge: 2}),\n        // StoreDevtoolsModule.instrumentOnlyWithExtension(),\n        AgmCoreModule.forRoot({\n            apiKey: 'AIzaSyDKa8Z3QLtACfSfxF-S8A44gm5bkvNTmuM',\n            libraries: ['places']\n        }),\n        SimpleGridModule.forRoot(),\n        SharedModule.forRoot(),\n        ToastModule.forRoot(),\n        AlertModule.forRoot(),\n        MsLibModule.forRoot({a: 1}),\n        ModalModule.forRoot(),\n        DropdownModule,\n        AccordionModule.forRoot(),\n        JsonpModule,\n        TreeModule,\n        InputTextModule,\n        SelectButtonModule,\n        InputTextModule,\n        DropdownModulePrime,\n        routing,\n    ],\n    providers: [providing],\n    bootstrap: [AppComponent]\n})\n\nexport class AppModule {\n    constructor(private commBroker: CommBroker, private compiler: Compiler, private ngmslibService: NgmslibService, private yp: YellowPepperService, private fontLoaderService: FontLoaderService) {\n        Lib.Con(`running in dev mode: ${Lib.DevMode()}`);\n        Lib.Con(`App in ${(compiler instanceof Compiler) ? 'AOT' : 'JIT'} mode`);\n        window['business_id'] = -1;\n        window['jQueryAny'] = jQuery;\n        window['jXML'] = jQuery;\n        this.ngmslibService.globalizeStringJS();\n        Lib.Con(StringJS('app-loaded-and-ready').humanize().s);\n        Lib.AlertOnLeave();\n        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'app started'})}));\n    }\n}\n\n"
  },
  {
    "path": "src/app/appwrap.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {Router} from \"@angular/router\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Observable} from \"rxjs/Observable\";\nimport {YellowPepperService} from \"../services/yellowpepper.service\";\n\n@Component({\n    template: `\n        <div id=\"appWrapComp\" class=\"row\" style=\"margin-left: 0; margin-right: 0;\">\n            <ng-menu class=\"col-md-1\" [routePrefix]=\"'App1'\" [fileMenuMode]=\"true\">\n                <ng-menu-item  i18n-title [fontawesome]=\"'fa-dashboard'\" name=\"Dashboard\" title=\"Dashboard\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-navicon'\" name=\"Campaigns\" title=\"Campaigns\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-certificate'\" name=\"Resources\" title=\"Resources\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-crosshairs'\" name=\"Scenes\" title=\"Scenes\" class=\"wizardHookScene\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-laptop'\" name=\"Stations\" title=\"Stations\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-group'\" name=\"Fasterq\" title=\"Fasterq\"></ng-menu-item>\n                <!--<ng-menu-item i18n-title [fontawesome]=\"'fa-cog'\" name=\"Settings\" title=\"'Settings'\"></ng-menu-item>-->\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-cloud-upload'\" name=\"Studiopro\" title=\"Studiopro\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-heart'\" name=\"Help\" title=\"Help\"></ng-menu-item>\n                <ng-menu-item i18n-title *ngIf=\"isBrandingDisabled | async\" [fontawesome]=\"'fa-rocket'\" name=\"Install\" title=\"Install\"></ng-menu-item>\n                <ng-menu-item i18n-title [fontawesome]=\"'fa-power-off'\" name=\"Logout\" title=\"Logout\"></ng-menu-item>\n            </ng-menu>\n            <div class=\"col-md-11\" id=\"mainPanelWrapWasp\" >\n                <router-outlet></router-outlet>\n            </div>\n        </div>\n    `\n})\nexport class Appwrap extends Compbaser {\n\n    isBrandingDisabled: Observable<boolean>\n\n    constructor(private router: Router, private yp:YellowPepperService) {\n        super();\n        jQuery(\".navbar-header .navbar-toggle\").trigger(\"click\");\n        jQuery('.navbar-nav').css({\n            display: 'block'\n        });\n        this.isBrandingDisabled = this.yp.isBrandingDisabled()\n    }\n\n    // public listenMenuChanges() {\n    // var unsub = self.commBroker.onEvent(Consts.Events().MENU_SELECTION).subscribe((e: IMessage) => {\n    //     if (!this.routerActive)\n    //         return;\n    //     let screen = (e.message);\n    //     self.router.navigate([`/App1/${screen}`]);\n    // });\n    // }\n}"
  },
  {
    "path": "src/app/blocks/block-fabric-image.ts",
    "content": "import {BlockFabric} from \"./block-fabric\";\nimport * as _ from \"lodash\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\n\nconst blockType = BlockLabels.BLOCKCODE_IMAGE;\n\nexport class BlockFabricImage extends BlockFabric {\n\n    m_canvas;\n    m_gridMagneticMode = 0;\n    m_nativeID;\n    m_fileFormat;\n\n    constructor(options, i_blockService, i_pepper) {\n        super(options, i_blockService, i_pepper, blockType)\n        this.m_blockService = i_blockService;\n        this.m_pepper = i_pepper;\n        this.m_blockType = blockType;\n        _.extend(options, {blockType: this.m_blockType})\n        this._initResourcesData();\n    }\n\n    /**\n     Set the instance resource data from msdb which includes resource_id (handle of a resource)\n     as well as the description of the resource and icon.\n     @method _initResourcesData\n     **/\n    _initResourcesData() {\n        var domPlayerData = this._getBlockPlayerData();\n        var xSnippet = $(domPlayerData).find('Resource');\n        this.m_resourceID = $(xSnippet).attr('hResource');\n        this.m_nativeID = this.m_pepper.getResourceNativeID(this.m_resourceID);\n        if (_.isNull(this.m_nativeID)) {\n            this._selfDestruct();\n            return;\n        }\n        this.m_blockName = this.m_pepper.getResourceRecord(this.m_resourceID).resource_name;\n        this.m_blockDescription = this.m_pepper.getResourceName(this.m_resourceID);\n        this.m_fileFormat = this.m_pepper.getResourceType(this.m_resourceID);\n        this.m_blockFontAwesome = this.m_blockService.getFontAwesome(this.m_fileFormat);\n    }\n\n    /**\n     Convert the block into a fabric js compatible object\n     @Override\n     @method fabricateBlock\n     **/\n    fabricateBlock(i_canvasScale, i_callback) {\n\n        var domPlayerData = this._getBlockPlayerData();\n        var layout = $(domPlayerData).find('Layout');\n        var businessID = this.m_pepper.getUserData().businessID;\n        var elemID = _.uniqueId('imgElemrand')\n        var imgPath;\n\n        if (this.m_fileFormat == 'swf') {\n            imgPath = './_assets/flash.png';\n        } else {\n            /*\n             if (platform.name == 'Chrome') {\n             // CDN\n             imgPath = window.g_protocol + 's3.signage.me/business' + this.m_pepper.getUserData().businessID + '/resources/';\n             imgPath = 'https://s3.signage.me/business' + this.m_pepper.getUserData().businessID + '/resources/';\n             imgPath += +this.m_nativeID + '.' + this.m_fileFormat;\n             } else {\n             // Legacy\n             imgPath = window.g_protocol + this.m_pepper.getUserData().domain + '/Resources/business' + this.m_pepper.getUserData().businessID + '/resources/' + this.m_nativeID + '.' + this.m_fileFormat;\n             }\n             */\n            imgPath = window.g_protocol + this.m_pepper.getUserData().domain + '/Resources/business' + this.m_pepper.getUserData().businessID + '/resources/' + this.m_nativeID + '.' + this.m_fileFormat;\n            // log('loading img from ' + imgPath);\n        }\n\n        var initImage = (i_image, i_passed) => {\n            if (!i_passed) {\n                i_callback();\n                return;\n            }\n            $(i_image).width(1000).height(800).appendTo('body');\n            var options = this._fabricateOptions(parseInt(layout.attr('y')), parseInt(layout.attr('x')), parseInt(layout.attr('width')), parseInt(layout.attr('height')), parseInt(layout.attr('rotation')));\n            var img = new fabric.Image(i_image, options);\n            _.extend(this, img);\n            this._fabricAlpha(domPlayerData);\n            this._fabricLock();\n            this['canvasScale'] = i_canvasScale;\n            i_callback();\n        };\n\n        // manage errors of resources which don't load\n        $(`<img src=\"${imgPath}\" style=\"display: none\" >`).on('load', function() {\n            initImage(this, true);\n        }).on('error', function() {\n            initImage(this, false);\n        })\n    }\n\n    /**\n     Get the resource id of the embedded resource\n     **/\n    getResourceID() {\n        return this.m_resourceID;\n    }\n\n    /**\n     Delete this block\n     @method deleteBlock\n     @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb\n     **/\n    deleteBlock(i_memoryOnly) {\n        // $(Elements.IMAGE_ASPECT_RATIO).off('change', this.m_inputChangeHandler);\n        this._deleteBlock(i_memoryOnly);\n    }\n\n}\n"
  },
  {
    "path": "src/app/blocks/block-fabric-josn-item.ts",
    "content": "import {BlockFabric} from \"./block-fabric\";\nimport * as _ from \"lodash\";\nimport {Lib} from \"../../Lib\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\nimport {BlockFabricLabel} from \"./block-fabric-label\";\n\n\nconst blockType = BlockLabels.BLOCKCODE_JSON_ITEM;\n\nexport class BlockFabricJsonItem extends BlockFabricLabel {\n\n    protected m_options;\n    protected m_selected;\n    protected m_labelFontSelector:any;\n    protected m_config:{};\n    protected m_sceneMime:string;\n\n    constructor(options, i_blockService, i_pepper) {\n        super(options, i_blockService, i_pepper)\n        this.m_blockService = i_blockService;\n        this.m_pepper = i_pepper;\n        this.m_blockType = blockType;\n        _.extend(options, {blockType: this.m_blockType})\n        this.m_sceneMime = this.m_pepper.getSceneMime(this.m_sceneID);\n        this.m_config = {\n            'Json.instagram.feed': {\n                title: 'Instagram',\n                tabTitle: 'Posts',\n                fields: {\n                    1: {\n                        name: \"title\",\n                        type: \"text\",\n                        label: \"title\"\n                    },\n                    2: {\n                        name: \"urlImage\",\n                        type: \"resource\",\n                        label: \"image\"\n                    },\n                    3: {\n                        name: \"video\",\n                        type: \"resource\",\n                        label: \"video\"\n                    }\n                }\n            },\n            'Json.twitter': {\n                title: 'Twitter',\n                tabTitle: 'Tweets',\n                fields: {\n                    1: {\n                        name: \"name\",\n                        type: \"text\",\n                        label: \"name\"\n                    },\n                    2: {\n                        name: \"text\",\n                        type: \"text\",\n                        label: \"text\"\n                    },\n                    3: {\n                        name: \"screen_name\",\n                        type: \"text\",\n                        label: \"screen name\"\n                    },\n                    4: {\n                        name: \"created_at\",\n                        type: \"text\",\n                        label: \"created at\"\n                    },\n                    5: {\n                        name: \"profile_background_image_url\",\n                        type: \"resource\",\n                        label: \"Background image\"\n                    },\n                    6: {\n                        name: \"profile_image_url\",\n                        type: \"resource\",\n                        label: \"Image\"\n                    }\n                }\n            },\n            'Json.digg': {\n                title: 'Digg',\n                tabTitle: 'Posts',\n                fields: {\n                    1: {\n                        name: \"title\",\n                        type: \"text\",\n                        label: \"title\"\n                    },\n                    2: {\n                        name: \"link\",\n                        type: \"resource\",\n                        label: \"image\"\n                    }\n                }\n            },\n            'Json.spreadsheet': {\n                title: 'Spreadsheet',\n                tabTitle: 'Cells',\n                fields: {\n                    1: {\n                        name: \"$cells.1.1.value\",\n                        type: \"dual_numeric\",\n                        label: \"Sheet cell\"\n                    }\n                }\n            },\n\n            'Json.calendar': {\n                title: 'Calendar',\n                tabTitle: 'Date',\n                fields: {\n                    1: {\n                        name: \"summary\",\n                        type: \"text\",\n                        label: \"summary\"\n                    },\n                    2: {\n                        name: \"description\",\n                        type: \"text\",\n                        label: \"description\"\n                    },\n                    3: {\n                        name: \"organizer\",\n                        type: \"text\",\n                        label: \"organizer\"\n                    },\n                    4: {\n                        name: \"organizerEmail\",\n                        type: \"text\",\n                        label: \"organizer email\"\n                    },\n                    5: {\n                        name: \"created\",\n                        type: \"text\",\n                        label: \"created\"\n                    },\n                    6: {\n                        name: \"startDateTime_time\",\n                        type: \"date\",\n                        label: \"start date time\"\n                    },\n                    7: {\n                        name: \"endDateTime_time\",\n                        type: \"date\",\n                        label: \"end date time\"\n                    },\n                    8: {\n                        name: \"updated\",\n                        type: \"text\",\n                        label: \"updated\"\n                    }\n                }\n            },\n            'Json.weather': {\n                title: 'World weather',\n                tabTitle: 'Conditions',\n                fields: {\n                    1: {\n                        name: \"$[0].data.current_condition[0].iconPath\",\n                        type: \"resource\",\n                        label: \"current icon\"\n                    },\n                    2: {\n                        name: \"$[0].data.current_condition[0].temp_@\",\n                        type: \"text\",\n                        label: \"current temp\"\n                    },\n                    3: {\n                        name: \"$[0].data.current_condition[0].humidity\",\n                        type: \"text\",\n                        label: \"current humidity\"\n                    },\n                    4: {\n                        name: \"$[0].data.weather[0].iconPath\",\n                        type: \"resource\",\n                        label: \"today icon\"\n                    },\n                    5: {\n                        name: \"$[0].data.weather[0].mintemp@\",\n                        type: \"text\",\n                        label: \"today min temp\"\n                    },\n                    6: {\n                        name: \"$[0].data.weather[0].maxtemp@\",\n                        type: \"text\",\n                        label: \"today max temp\"\n                    },\n                    7: {\n                        name: \"$[0].data.weather[0].day\",\n                        type: \"text\",\n                        label: \"today label\"\n                    },\n                    8: {\n                        name: \"$[0].data.weather[1].iconPath\",\n                        type: \"resource\",\n                        label: \"today+1 icon\"\n                    },\n                    9: {\n                        name: \"$[0].data.weather[1].mintemp@\",\n                        type: \"text\",\n                        label: \"today+1 min temp\"\n                    },\n                    10: {\n                        name: \"$[0].data.weather[1].maxtemp@\",\n                        type: \"text\",\n                        label: \"today+1 max temp\"\n                    },\n                    11: {\n                        name: \"$[0].data.weather[1].day\",\n                        type: \"text\",\n                        label: \"today+1 label\"\n                    },\n                    12: {\n                        name: \"$[0].data.weather[2].iconPath\",\n                        type: \"resource\",\n                        label: \"today+2 icon\"\n                    },\n                    13: {\n                        name: \"$[0].data.weather[2].mintemp@\",\n                        type: \"text\",\n                        label: \"today+2 min temp\"\n                    },\n                    14: {\n                        name: \"$[0].data.weather[2].maxtemp@\",\n                        type: \"text\",\n                        label: \"today+2 max temp\"\n                    },\n                    15: {\n                        name: \"$[0].data.weather[2].day\",\n                        type: \"text\",\n                        label: \"today+2 label\"\n                    },\n                    16: {\n                        name: \"$[0].data.weather[3].iconPath\",\n                        type: \"resource\",\n                        label: \"today+3 icon\"\n                    },\n                    17: {\n                        name: \"$[0].data.weather[3].mintemp@\",\n                        type: \"text\",\n                        label: \"today+3 min temp\"\n                    },\n                    18: {\n                        name: \"$[0].data.weather[3].maxtemp@\",\n                        type: \"text\",\n                        label: \"today+3 max temp\"\n                    },\n                    19: {\n                        name: \"$[0].data.weather[3].day\",\n                        type: \"text\",\n                        label: \"today+3 label\"\n                    },\n                    20: {\n                        name: \"$[0].data.weather[4].iconPath\",\n                        type: \"resource\",\n                        label: \"today+4 icon\"\n                    },\n                    21: {\n                        name: \"$[0].data.weather[4].mintemp@\",\n                        type: \"text\",\n                        label: \"today+4 min temp\"\n                    },\n                    22: {\n                        name: \"$[0].data.weather[4].maxtemp@\",\n                        type: \"text\",\n                        label: \"today+4 max temp\"\n                    },\n                    23: {\n                        name: \"$[0].data.weather[4].day\",\n                        type: \"text\",\n                        label: \"today+4 label\"\n                    },\n                    24: {\n                        name: \"$[0].data.weather[5].iconPath\",\n                        type: \"resource\",\n                        label: \"today+5 icon\"\n                    },\n                    25: {\n                        name: \"$[0].data.weather[5].mintemp@\",\n                        type: \"text\",\n                        label: \"today+5 min temp\"\n                    },\n                    26: {\n                        name: \"$[0].data.weather[5].maxtemp@\",\n                        type: \"text\",\n                        label: \"today+5 max temp\"\n                    },\n                    27: {\n                        name: \"$[0].data.weather[5].day\",\n                        type: \"text\",\n                        label: \"today+5 label\"\n                    },\n                    28: {\n                        name: \"$[0].data.weather[6].iconPath\",\n                        type: \"resource\",\n                        label: \"today+6 icon\"\n                    },\n                    29: {\n                        name: \"$[0].data.weather[6].mintemp@\",\n                        type: \"text\",\n                        label: \"today+6 min temp\"\n                    },\n                    30: {\n                        name: \"$[0].data.weather[6].maxtemp@\",\n                        type: \"text\",\n                        label: \"today+6 max temp\"\n                    },\n                    31: {\n                        name: \"$[0].data.weather[6].day\",\n                        type: \"text\",\n                        label: \"today+6 label\"\n                    }\n                }\n            }\n        };\n    }\n\n    /**\n     translate a json item path such as $[0].data.weather... to it's label\n     @method _translateToLabel\n     @param {Number} i_playerData\n     @return {Number} Unique clientId.\n     **/\n    private _translateToLabel(i_jsonPath:string):string {\n        var self = this;\n\n        // no mime configured in scnene so return same label\n        if (_.isUndefined(self.m_sceneMime))\n            return i_jsonPath;\n\n        switch (self.m_sceneMime) {\n            case 'Json.spreadsheet':\n            {\n                // lookup up label in m_config for spreadsheet\n                return self.m_config['Json.spreadsheet'].fields['1'].label;\n            }\n            default:\n            {\n                // look up label in m_config db for everything else\n                var fields:any = self.m_config[self.m_sceneMime].fields;\n                for (var item in fields) {\n                    if (fields[item].name == i_jsonPath)\n                        return fields[item].label;\n                }\n            }\n        }\n        return i_jsonPath;\n    }\n\n    /**\n     Some json item field names need to be muated into something else.\n     For example, the default fieldName of text needs to be changed into '$cells.1.1.value' when\n     used in a scene of mimeType\n     @method _mutateCustomFieldName\n     **/\n    private _mutateCustomFieldName():void {\n        var self = this;\n        switch (self.m_sceneMime) {\n            case 'Json.spreadsheet':\n            {\n                var domPlayerData = self._getBlockPlayerData();\n                var xSnippet = $(domPlayerData).find('XmlItem');\n                var fieldName = $(xSnippet).attr('fieldName');\n                if (fieldName == 'text') {\n                    var value = self.m_config['Json.spreadsheet'].fields['1'].name;\n                    $(xSnippet).attr('fieldName', value);\n                    // self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);\n                }\n                break;\n            }\n            default:\n            {\n            }\n        }\n    }\n\n    /**\n     Convert the block into a fabric js compatible object\n     @Override\n     @method fabricateBlock\n     @param {number} i_canvasScale\n     @param {function} i_callback\n     **/\n    fabricateBlock(i_canvasScale, i_callback) {\n        var self= this;\n        self._mutateCustomFieldName();\n        var domPlayerData = self._getBlockPlayerData();\n        var layout = $(domPlayerData).find('Layout');\n        var xSnippet = $(domPlayerData).find('XmlItem');\n        var fieldName = $(xSnippet).attr('fieldName');\n        var text = self._translateToLabel(fieldName);\n        var font = $(xSnippet).find('Font');\n        var link = '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';\n        var url = ('https:' === document.location.protocol ? 'https' : 'http') + link;\n\n        //$.getScript(src, function (data) {\n        //    console.log(data);\n        //});\n\n        var t = new fabric.IText(text, {\n            fontSize: Number($(font).attr('fontSize')),\n            //fontFamily: 'Graduate',\n            //fontFamily: 'Jolly Lodger',\n            //fontFamily: 'Arial',\n            fontFamily: $(font).attr('fontFamily'),\n            fill: '#' + Lib.DecimalToHex($(font).attr('fontColor')),\n            textDecoration: $(font).attr('textDecoration'),\n            fontWeight: $(font).attr('fontWeight'),\n            fontStyle: $(font).attr('fontStyle'),\n            textAlign: $(font).attr('textAlign'),\n            top: 5,\n            left: 5\n        });\n\n        // calculate block so it can always contain the text it holds and doesn't bleed\n        //self.m_minSize.w = t.width < 50 ? 50 : t.width * 1.2;\n        //self.m_minSize.h = t.height < 50 ? 50 : t.height * 1.2;\n        //var w = parseInt(layout.attr('width')) < self.m_minSize.w ? self.m_minSize.w : parseInt(layout.attr('width'));\n        //var h = parseInt(layout.attr('height')) < self.m_minSize.h ? self.m_minSize.h : parseInt(layout.attr('height'));\n\n        var w = parseInt(layout.attr('width'));\n        var textWidth = t.width * 1.2;\n        if (textWidth > w) {\n            t.setText('...');\n        }\n        var h = parseInt(layout.attr('height'));\n        var textHeight = t.height * 1.2;\n        if (textHeight > h) {\n            t.setText('...');\n        }\n        var rec = self._fabricRect(w, h, domPlayerData);\n        var o = self._fabricateOptions(parseInt(layout.attr('y')), parseInt(layout.attr('x')), w, h, parseInt(layout.attr('rotation')));\n\n        rec.originX = 'center';\n        rec.originY = 'center';\n        t.top = 0 - (rec.height / 2);\n        t.left = 0 - (rec.width / 2);\n        _.extend(self, o);\n        self.add(rec);\n        self.add(t);\n        self._fabricAlpha(domPlayerData);\n        self._fabricLock();\n        self['canvasScale'] = i_canvasScale;\n\n        //$.ajax({\n        //    url: url,\n        //    async: false,\n        //    dataType: 'script',\n        //    complete: function (e) {\n        //        setTimeout(i_callback, 1);\n        //    }\n        //});\n        setTimeout(i_callback, 1);\n\n        var direction = $(font).attr('textAlign');\n        switch (direction) {\n            case 'left':\n            {\n                break;\n            }\n            case 'center':\n            {\n                t.set({\n                    textAlign: direction,\n                    originX: direction,\n                    left: 0\n                });\n                break;\n            }\n            case 'right':\n            {\n                t.set({\n                    textAlign: direction,\n                    originX: direction,\n                    left: rec.width / 2\n                });\n                break;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/app/blocks/block-fabric-label.ts",
    "content": "import {BlockFabric} from \"./block-fabric\";\nimport * as _ from \"lodash\";\nimport {Lib} from \"../../Lib\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\n\n\nconst blockType = BlockLabels.LABEL;\n\nexport class BlockFabricLabel extends BlockFabric {\n\n    constructor(options, i_blockService, i_pepper) {\n        super(options, i_blockService, i_pepper, blockType)\n        this.m_blockService = i_blockService;\n        this.m_pepper = i_pepper;\n        this.m_blockType = blockType;\n        _.extend(options, {blockType: this.m_blockType})\n    }\n\n    /**\n     Convert the block into a fabric js compatible object\n     @Override\n     @method fabricateBlock\n     @param {number} i_canvasScale\n     @param {function} i_callback\n     **/\n    fabricateBlock(i_canvasScale, i_callback) {\n\n        var domPlayerData = this._getBlockPlayerData();\n        var layout = $(domPlayerData).find('Layout');\n        var label = $(domPlayerData).find('Label');\n        var text = $(label).find('Text').text();\n        var font = $(label).find('Font');\n\n        var url = ('https:' === document.location.protocol ? 'https' : 'http') + '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';\n\n        //$.getScript(src, function (data) {\n        //    console.log(data);\n        //});\n\n        var t = new fabric.IText(text, {\n            fontSize: Number($(font).attr('fontSize')),\n            //fontFamily: 'Graduate',\n            //fontFamily: 'Jolly Lodger',\n            //fontFamily: 'Arial',\n            fontFamily: $(font).attr('fontFamily'),\n            fill: '#' + Lib.DecimalToHex($(font).attr('fontColor')),\n            textDecoration: $(font).attr('textDecoration'),\n            fontWeight: $(font).attr('fontWeight'),\n            fontStyle: $(font).attr('fontStyle'),\n            textAlign: $(font).attr('textAlign'),\n            top: 5,\n            left: 5\n        });\n\n        // calculate block so it can always contain the text it holds and doesn't bleed\n        this.m_minSize.w = t.width < 50 ? 50 : t.width * 1.2;\n        this.m_minSize.h = t.height < 50 ? 50 : t.height * 1.2;\n        var w = parseInt(layout.attr('width')) < this.m_minSize.w ? this.m_minSize.w : parseInt(layout.attr('width'));\n        var h = parseInt(layout.attr('height')) < this.m_minSize.h ? this.m_minSize.h : parseInt(layout.attr('height'));\n\n        var rec = this._fabricRect(w, h, domPlayerData);\n        var o = this._fabricateOptions(parseInt(layout.attr('y')), parseInt(layout.attr('x')), w, h, parseInt(layout.attr('rotation')));\n        //var group = new fabric.Group([ rec, t ], o);\n        //_.extend(this, group);\n\n        rec.originX = 'center';\n        rec.originY = 'center';\n        t.top = 0 - (rec.height / 2);\n        t.left = 0 - (rec.width / 2);\n        _.extend(this, o);\n        this.add(rec);\n        this.add(t);\n        this._fabricAlpha(domPlayerData);\n        this._fabricLock();\n        this['canvasScale'] = i_canvasScale;\n\n        //$.ajax({\n        //    url: url,\n        //    async: false,\n        //    dataType: \"script\",\n        //    complete: function(e){\n        //        setTimeout(i_callback,1)\n        //    }\n        //});\n        setTimeout(i_callback,1);\n\n        var direction = $(font).attr('textAlign');\n        switch (direction) {\n            case 'left': {\n                break;\n            }\n            case 'center': {\n                t.set({\n                    textAlign: direction,\n                    originX: direction,\n                    left: 0\n                });\n                break;\n            }\n            case 'right': {\n                t.set({\n                    textAlign: direction,\n                    originX: direction,\n                    left: rec.width / 2\n                });\n                break;\n            }\n        }\n\n        // todo: add shadow\n        //http://jsfiddle.net/Kienz/fgWNL/\n        //http://jsfiddle.net/fabricjs/7gvJG/\n        //http://jsfiddle.net/5KKQ2/\n        //t.set('shadow', {\n        //    color: 'black',\n        //    blur: 1,\n        //    offsetX:3,\n        //    offsetY: 1\n        //});({ color: 'rgba(12,12,12,1)' });\n        //rec.set('shadow', {\n        //    color: 'black',\n        //    blur: 1,\n        //    offsetX:3,\n        //    offsetY: 1\n        //});\n    }\n\n    /**\n     Delete this block\n     @method deleteBlock\n     @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb\n     **/\n    deleteBlock(i_memoryOnly) {\n        // $(Elements.IMAGE_ASPECT_RATIO).off('change', this.m_inputChangeHandler);\n        this._deleteBlock(i_memoryOnly);\n    }\n\n}\n"
  },
  {
    "path": "src/app/blocks/block-fabric-scene.ts",
    "content": "import {BlockFabric} from \"./block-fabric\";\nimport * as _ from 'lodash';\nimport {Lib} from \"../../Lib\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\n\nconst blockType = BlockLabels.BLOCKCODE_SCENE;\n\nexport class BlockFabricScene extends BlockFabric {\n\n    m_canvas;\n    m_gridMagneticMode = 0;\n\n    constructor(options, i_blockService, i_pepper) {\n        super(options, i_blockService, i_pepper, blockType)\n        this.m_blockService = i_blockService;\n        this.m_pepper = i_pepper;\n        this.m_blockType = blockType;\n        _.extend(options, {blockType: this.m_blockType})\n    }\n\n    /**\n     get player data for a scene\n     @Override\n     **/\n    getBlockData() {\n        var data = BlockFabric.prototype.getBlockData.call(this);\n        var domPlayerData = this._getBlockPlayerData();\n        data.blockName = $(domPlayerData).find('Player').eq(0).attr('label');\n        return data;\n    }\n\n    /**\n     Update the msdb for the block with new values inside its player_data\n     @Override\n     **/\n    _setBlockPlayerData(i_xmlDoc, i_noNotify) {\n        // var player_data = (new XMLSerializer()).serializeToString(i_xmlDoc);\n        // switch (this.m_placement) {\n        //     case BB.CONSTS.PLACEMENT_CHANNEL: {\n        //         var recBlock = pepper.getCampaignTimelineChannelPlayerRecord(this.m_block_id);\n        //         var domPlayerData = $.parseXML(recBlock['player_data']);\n        //         var scene_id = $(domPlayerData).find('Player').attr('hDataSrc');\n        //         var player_data = (new XMLSerializer()).serializeToString(i_xmlDoc);\n        //         pepper.setScenePlayerData(scene_id, player_data);\n        //         break;\n        //     }\n        //\n        //     case BB.CONSTS.PLACEMENT_IS_SCENE: {\n        //         pepper.setScenePlayerData(this.m_block_id, player_data);\n        //         //if (!i_noNotify)\n        //         //    this._announceBlockChanged();\n        //         break;\n        //     }\n        // }\n    }\n\n    /**\n     Get the XML player data of a block, depending where its placed\n     @Override\n     **/\n    _getBlockPlayerData(): any {\n        var blockID = this.m_pepper.getSceneIdFromPseudoId(this.m_block_id);\n        var recPlayerData = this.m_pepper.getScenePlayerRecord(blockID);\n        var xPlayerdata = recPlayerData['player_data_value'];\n        return $.parseXML(xPlayerdata);\n        // var recBlock = undefined;\n        //\n        // switch (this.m_placement) {\n        //\n        //     case BB.CONSTS.PLACEMENT_CHANNEL: {\n        //         recBlock = pepper.getCampaignTimelineChannelPlayerRecord(this.m_block_id);\n        //         var domPlayerData = $.parseXML(recBlock['player_data']);\n        //         var sceneHandle = $(domPlayerData).find('Player').attr('hDataSrc');\n        //         return pepper.getScenePlayerdataDom(sceneHandle);\n        //         break;\n        //     }\n        //\n        //     case BB.CONSTS.PLACEMENT_IS_SCENE: {\n        //         var blockID = pepper.getSceneIdFromPseudoId(this.m_block_id);\n        //         var recPlayerData = BB.Pepper.getScenePlayerRecord(blockID);\n        //         var xPlayerdata = recPlayerData['player_data_value'];\n        //         return $.parseXML(xPlayerdata);\n        //         break;\n        //     }\n        // }\n    }\n\n    /**\n     Find the border section in player_data for selected block\n     **/\n    // _findBorder(i_domPlayerData) {\n    //     var xSnippet = $(i_domPlayerData).find('Layout').eq(0).siblings().filter('Border');\n    //     return xSnippet;\n    // }\n\n    /**\n     Find the background section in player_data for selected block\n     **/\n    // _findBackground(i_domPlayerData) {\n    //     var xSnippet = $(i_domPlayerData).find('Layout').eq(0).siblings().filter('Background');\n    //     return xSnippet;\n    // }\n\n    /**\n     Find the gradient blocks in player_data for selected scene block\n     **/\n    _findGradientPoints(i_domPlayerData) {\n        var xBackground = $(i_domPlayerData).find('Layout').eq(0).siblings().filter('Background');\n        var xSnippet = $(xBackground).find('GradientPoints').eq(0);\n        return xSnippet;\n    }\n\n    /**\n     Add the checkers background to a scene\n     **/\n    _fabricApplySceneBgImage(i_image) {\n        this.m_canvas.setBackgroundColor('', this.m_canvas.renderAll.bind(this.m_canvas));\n        $('#sceneCanvasContainer').find('.canvas-container').removeClass('checkers').removeClass('grid25').removeClass('grid50').addClass(i_image);\n        this.m_canvas.renderAll();\n    }\n\n    /**\n     Set a scene's background color or image\n     @method fabricSceneBg\n     **/\n    fabricSceneBg() {\n        var domPlayerData = this._getBlockPlayerData();\n        var colorPoints = this._findGradientPoints(domPlayerData)\n        var color = $(colorPoints).find('Point').attr('color');\n\n        switch (this.m_gridMagneticMode) {\n            case 0: {\n                if (_.isUndefined(color)) {\n                    this._fabricApplySceneBgImage('checkers');\n                    return;\n                }\n                color = '#' + Lib.DecimalToHex(color);\n                if (this.m_canvas.backgroundColor == color)\n                    return;\n                this.m_canvas.setBackgroundColor(color, function () {\n                });\n                this.m_canvas.renderAll();\n                break;\n            }\n            case 1: {\n                this._fabricApplySceneBgImage('grid25');\n                break;\n            }\n            case 2: {\n                this._fabricApplySceneBgImage('grid50');\n                break;\n            }\n        }\n    }\n\n    /**\n     Set reference to managed canvas\n     **/\n    setCanvas(i_canvas, i_magneticGridMode) {\n        this.m_canvas = i_canvas;\n        this.m_gridMagneticMode = i_magneticGridMode;\n        this.fabricSceneBg();\n    }\n\n    /**\n     Get the scene id that's associated with this block given that it resides in a timeline > channel\n     **/\n    // getChannelBlockSceneID() {\n    // var recBlock = pepper.getCampaignTimelineChannelPlayerRecord(this.m_block_id);\n    // var domPlayerData = $.parseXML(recBlock['player_data']);\n    // var scene_id = $(domPlayerData).find('Player').attr('hDataSrc');\n    // return scene_id;\n    // }\n\n    /**\n     Delete this block\n     @method deleteBlock\n     @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb\n     **/\n    deleteBlock(i_memoryOnly) {\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.SCENE_BG_COLOR_CHANGED, this);\n        // $(Elements.SCENE_NAME_INPUT).off(\"input\", this.m_inputNameChangeHandler);\n        // $(Elements.SCENE_WIDTH_INPUT).off(\"input\", this.m_inputWidthChangeHandler);\n        // $(Elements.SCENE_WIDTH_INPUT).off(\"blur\", this.m_inputWidthChangeHandler);\n        // $(Elements.SCENE_HEIGHT_INPUT).off(\"blur\", this.m_inputWidthChangeHandler);\n        // $(Elements.SCENE_HEIGHT_INPUT).off(\"input\", this.m_inputHeightChangeHandler);\n        // this._deleteBlock(i_memoryOnly);\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-fabric-svg.ts",
    "content": "import {BlockFabric} from \"./block-fabric\";\nimport * as _ from \"lodash\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\n\n\nconst blockType = BlockLabels.BLOCKCODE_SVG;\n\nexport class BlockFabricSvg extends BlockFabric {\n\n    m_nativeID;\n    m_fileFormat;\n\n    constructor(options, i_blockService, i_pepper) {\n        super(options, i_blockService, i_pepper, blockType)\n        this.m_blockService = i_blockService;\n        this.m_pepper = i_pepper;\n        this.m_blockType = blockType;\n        _.extend(options, {blockType: this.m_blockType})\n        this._initResourcesData();\n    }\n\n    /**\n     Set the instance resource data from msdb which includes resource_id (handle of a resource)\n     as well as the description of the resource and icon.\n     @method _initResourcesData\n     **/\n    _initResourcesData() {\n        var domPlayerData = this._getBlockPlayerData();\n        var xSnippet = $(domPlayerData).find('Resource');\n        this.m_resourceID = $(xSnippet).attr('hResource');\n        this.m_nativeID = this.m_pepper.getResourceNativeID(this.m_resourceID);\n        if (_.isNull(this.m_nativeID)) {\n            this._selfDestruct();\n            return;\n        }\n        this.m_blockName = this.m_pepper.getResourceRecord(this.m_resourceID).resource_name;\n        this.m_blockDescription = this.m_pepper.getResourceName(this.m_resourceID);\n        this.m_fileFormat = this.m_pepper.getResourceType(this.m_resourceID);\n        this.m_blockFontAwesome = this.m_blockService.getFontAwesome(this.m_fileFormat);\n    }\n\n\n    // /var/www/sites/dynasite/htdocs/_msportal/_js/_node/public/assets/14.svg\n    /**\n     Convert the block into a fabric js compatible object, called externally on creation of block\n     @Override\n     @method fabricateBlock\n     **/\n    fabricateBlock(i_canvasScale, i_callback) {\n        var self = this;\n\n        var domPlayerData = self._getBlockPlayerData();\n        var layout = $(domPlayerData).find('Layout');\n\n        var w = parseInt(layout.attr('width'));\n        var h = parseInt(layout.attr('height'));\n        var rec = self._fabricRect(w, h, domPlayerData);\n\n        var svgPath = window.g_protocol + self.m_pepper.getUserData().domain + '/Resources/business' + self.m_pepper.getUserData().businessID + '/resources/' + self.m_nativeID + '.' + self.m_fileFormat;\n        var urlPath = jQuery.base64.encode(svgPath);\n        var srvPath = 'https://secure.digitalsignage.com/proxyRequest/' + urlPath;\n\n        //svgPath = 'https://secure.digitalsignage.com/_public/assets/15.svg';\n        //svgPath = 'https://ida.signage.me/Test/14.svg';\n        //svgPath = 'https://ida.signage.me/code/14.svg';\n        //svgPath = \"https://s3-us-west-2.amazonaws.com/oregon-signage-resources/business372844/resources/14.svg\";\n        //svgPath = 'https://ida2.signage.me/14.svg';\n\n        $.get(srvPath, function (svg) {\n            var hh, ww, svgHeight, svgWidth, re;\n\n            // set new height in SVG per current selection box height\n            hh = layout.attr('height');\n\n            // catch load errors\n            svgHeight = svg.match(/(height=\")([^\\\"]*)/)\n            if (_.isNull(svgHeight)) {\n                i_callback();\n                return;\n            }\n            svgHeight = svgHeight[2];\n            re = new RegExp('height=\"' + svgHeight + '\"', \"ig\");\n            svg = svg.replace(re, 'height=\"' + hh + '\"');\n\n            // set new width in SVG per current selection box width\n            ww = layout.attr('width');\n            svgWidth = svg.match(/(width=\")([^\\\"]*)/)[2];\n            re = new RegExp('width=\"' + svgWidth + '\"', \"ig\");\n            svg = svg.replace(re, 'width=\"' + ww + '\"');\n\n            fabric.loadSVGFromString(svg, function (objects:any, options) {\n                objects[0].heightAttr = hh;\n                objects[0].widthAttr = ww;\n                objects[0].height = hh;\n                objects[0].width = ww;\n\n                var groupSvg = fabric.util.groupSVGElements(objects, options);\n\n                rec.originX = 'center';\n                rec.originY = 'center';\n                groupSvg.originX = 'center';\n                groupSvg.originY = 'center';\n                var o = {\n                    left: parseInt(layout.attr('x')),\n                    top: parseInt(layout.attr('y')),\n                    width: parseInt(layout.attr('width')),\n                    height: parseInt(layout.attr('height')),\n                    angle: parseInt(layout.attr('rotation')),\n                    hasRotatingPoint: false,\n                    stroke: 'transparent',\n                    cornerColor: 'black',\n                    cornerSize: 5,\n                    lockRotation: true,\n                    transparentCorners: false\n                };\n                _.extend(self, o);\n                self.add(rec);\n                self.add(groupSvg);\n                self._fabricAlpha(domPlayerData);\n                self._fabricLock();\n                self['canvasScale'] = i_canvasScale;\n                i_callback();\n            });\n\n        }, 'text');\n    }\n\n    /**\n     Get the resource id of the embedded resource\n     @method getResourceID\n     @return {Number} resource_id;\n     **/\n    getResourceID() {\n        return this.m_resourceID;\n    }\n\n    /**\n     Delete this block\n     @method deleteBlock\n     @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb\n     **/\n    deleteBlock(i_memoryOnly) {\n        // $(Elements.IMAGE_ASPECT_RATIO).off('change', this.m_inputChangeHandler);\n        this._deleteBlock(i_memoryOnly);\n    }\n\n}\n"
  },
  {
    "path": "src/app/blocks/block-fabric.ts",
    "content": "import * as _ from 'lodash';\nimport {Lib} from \"../../Lib\";\nimport {BlockService} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\n\nexport class BlockFabric extends fabric.Group {\n\n    m_block_id;\n    m_sceneID;\n    m_blockType;\n    m_zIndex = -1;\n    m_minSize = {w: 50, h: 50};\n    m_blockName;\n    m_blockAcronym;\n    m_blockDescription;\n    m_blockIcon;\n    m_blockFontAwesome;\n    m_blockSvg;\n    m_resourceID;\n    m_blockProperty;\n    m_blockService: BlockService;\n    m_pepper: RedPepperService;\n\n    constructor(options, i_blockService, i_pepper, i_blockType) {\n        super()\n        this.m_blockType = i_blockType\n        this.m_blockService = i_blockService;\n        this.m_pepper = i_pepper;\n        this.m_block_id = options.i_block_id;\n        this.m_sceneID = options.i_scene_player_data_id;\n        this.m_zIndex = -1;\n        this.m_minSize = {w: 50, h: 50};\n        this.m_blockName = i_blockService.getBlockBoilerplate(this.m_blockType).name;\n        this.m_blockAcronym = i_blockService.getBlockBoilerplate(this.m_blockType).acronym;\n        this.m_blockDescription = i_blockService.getBlockBoilerplate(this.m_blockType).description;\n        this.m_blockIcon = i_blockService.getBlockBoilerplate(this.m_blockType).icon;\n        this.m_blockFontAwesome = i_blockService.getBlockBoilerplate(this.m_blockType).fontAwesome;\n        this.m_blockSvg = i_blockService.getBlockBoilerplate(this.m_blockType).svg;\n        this.m_resourceID = undefined;\n    }\n\n    // _setBlockPlayerData(i_xmlDoc, i_noNotify, i_xmlIsString) {\n    //     var player_data;\n    //     if (i_xmlIsString == true) {\n    //         player_data = i_xmlDoc;\n    //     } else {\n    //         player_data = (new XMLSerializer()).serializeToString(i_xmlDoc);\n    //     }\n    //     this.m_pepper.setScenePlayerdataBlock(this.m_sceneID, this.m_block_id, player_data);\n    //     this.m_pepper.reduxCommit();\n    //     // switch (this.m_placement) {\n    //     //     case PLACEMENT_SCENE: {\n    //     //         this.m_pepper.setScenePlayerdataBlock(this.m_sceneID, this.m_block_id, player_data);\n    //     //         break;\n    //     //     }\n    //     //     case PLACEMENT_IS_SCENE: {\n    //     //         this.m_pepper.setScenePlayerData(this.m_block_id, player_data);\n    //     //         break;\n    //     //     }\n    //     // }\n    // }\n\n    /**\n     Get the XML player data of a block, depending where its placed\n     If you like to view XML raw data, be sure to debug domPlayerData.children[0].outerHTML\n     **/\n    _getBlockPlayerData(): any {\n        return this.m_pepper.getScenePlayerdataBlock(this.m_sceneID, this.m_block_id);\n        // to view data debug domPlayerData.children[0].outerHTML\n    }\n\n    /**\n     Find the border section in player_data for selected block\n     **/\n    _findBorder(i_domPlayerData) {\n        return $(i_domPlayerData).find('Border');\n    }\n\n    /**\n     Fabricate alpha to canvas\n     **/\n    _fabricAlpha(i_domPlayerData) {\n        var appearance = $(i_domPlayerData).find('Appearance');\n        var opacity: any = $(appearance).attr('alpha');\n        this.setOpacity(opacity);\n    }\n\n    /**\n     Fabricate color points to canvas\n     **/\n    _fabricColorPoints(i_domPlayerData) {\n        var gradientPoints = $(i_domPlayerData).find('GradientPoints');\n        var points = $(gradientPoints).find('Point');\n        var colorStops = {}\n        _.each(points, function (point) {\n            var color = '#' + Lib.DecimalToHex(($(point).attr('color')));\n            var offset: any = $(point).attr('midpoint');\n            offset = offset / 250;\n            colorStops[offset] = color;\n        });\n        return colorStops;\n    }\n\n    /**\n     Config the fabric block border\n     **/\n    _fabricateBorder(i_options) {\n        var domPlayerData = this._getBlockPlayerData()\n        var border = this._findBorder(domPlayerData);\n        var color = border.length == 0 ? 'transparent' : '#' + Lib.DecimalToHex($(border).attr('borderColor'));\n        return _.extend({\n            // borderColor: '#5d5d5d',\n            stroke: color,\n            strokeWidth: 1\n        }, i_options);\n    }\n\n    /**\n     Build the options injected into a newly created fabric object\n     **/\n    _fabricateOptions(i_top, i_left, i_width, i_height, i_angle) {\n        var options = {\n            top: i_top,\n            left: i_left,\n            width: i_width,\n            height: i_height,\n            angle: i_angle,\n            fill: '#ececec',\n            hasRotatingPoint: false,\n            transparentCorners: false,\n            cornerColor: 'black',\n            cornerSize: 5,\n            lockRotation: true,\n            lineWidth: 1\n        };\n        return this._fabricateBorder(options);\n    }\n\n    /**\n     Fabricate color points to canvas\n     **/\n    _fabricRect(i_width, i_height, i_domPlayerData) {\n        var options = this._fabricateOptions(0, 0, i_width, i_height, 0);\n        var r = new fabric.Rect(options);\n        r.setGradient('fill', {\n            x1: 0 - (i_width / 2),\n            y1: 0,\n            x2: (i_width / 2),\n            y2: 0,\n            colorStops: this._fabricColorPoints(i_domPlayerData)\n        });\n        return r;\n    }\n\n\n\n    \n    /**\n     Convert the block into a fabric js compatible object, called externally on creation of block\n     @Override\n     @method fabricateBlock\n     **/\n    fabricateBlock(i_canvasScale, i_callback) {\n        var domPlayerData = this._getBlockPlayerData();\n        var layout = $(domPlayerData).find('Layout');\n\n        var w = parseInt(layout.attr('width'));\n        var h = parseInt(layout.attr('height'));\n        var rec = this._fabricRect(w, h, domPlayerData);\n\n        fabric.loadSVGFromString(this.m_blockSvg, (objects, options) => {\n            var groupSvg = fabric.util.groupSVGElements(objects, options);\n            rec.originX = 'center';\n            rec.originY = 'center';\n            groupSvg.originX = 'center';\n            groupSvg.originY = 'center';\n\n            var o = {\n                left: parseInt(layout.attr('x')),\n                top: parseInt(layout.attr('y')),\n                width: parseInt(layout.attr('width')),\n                height: parseInt(layout.attr('height')),\n                angle: parseInt(layout.attr('rotation')),\n                hasRotatingPoint: false,\n                stroke: 'transparent',\n                cornerColor: 'black',\n                cornerSize: 5,\n                lockRotation: true,\n                transparentCorners: false\n            };\n            _.extend(this, o);\n            this.add(rec);\n            this.add(groupSvg);\n            this._fabricAlpha(domPlayerData);\n            this._fabricLock();\n            this['canvasScale'] = i_canvasScale;\n            i_callback();\n        });\n    }\n\n    /**\n     On changes in msdb model updated UI common lock properties\n     **/\n    _fabricLock() {\n        var domPlayerData = this._getBlockPlayerData();\n        var locked: any = $(domPlayerData).attr('locked');\n        if (_.isUndefined(locked) || locked == '0') {\n            locked = false;\n        } else {\n            locked = true;\n        }\n        this.lockMovementX = locked;\n        this.lockMovementY = locked;\n        //self.lockScalingX = locked; self.lockScalingY = locked; self.lockUniScaling = locked; self.lockRotation = locked;\n        /////var dimensionProps = BB.comBroker.getService(BB.SERVICES['DIMENSION_PROPS_LAYOUT']);\n        /////if (_.isUndefined(dimensionProps))\n        //////     return;\n        //////dimensionProps.setLock(locked);\n    }\n\n    /**\n     Get block data as a json formatted object literal and return to caller\n     **/\n    getBlockData() {\n        var data = {\n            blockID: this.m_block_id,\n            blockType: this.m_blockType,\n            blockName: this.m_blockName,\n            blockDescription: this.m_blockDescription,\n            blockIcon: this.m_blockIcon,\n            blockFontAwesome: this.m_blockFontAwesome,\n            blockAcronym: this.m_blockAcronym,\n            blockMinWidth: this.m_minSize.w,\n            blockMinHeight: this.m_minSize.h,\n            blockData: this._getBlockPlayerData()\n        };\n        return data;\n    }\n\n    /**\n     Set a block's z-index in case we know it (i.e.: it is going to be a re-render of a previous block that\n     was removed from the canvas)\n     **/\n    setZindex(i_zIndex) {\n        this.m_zIndex = i_zIndex;\n    }\n\n    /**\n     Get a block's z-index\n     @method getZindex\n     @param {Number} i_index\n     **/\n    getZindex(i_zIndex) {\n        return this.m_zIndex;\n    }\n\n    /**\n     Delete block is a public method used as fall back method, if not overridden by inherited instance.\n     It is also a semi abstract method, all implementations should go into _deleteBlock();\n     @method deleteBlock\n     @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb\n     @return none\n     **/\n    deleteBlock(i_memoryOnly) {\n        /* semi-abstract, overridden, do not modify */\n        this._deleteBlock(i_memoryOnly);\n    }\n\n    /**\n     bug fix: backward comparability with player_data that includes deleted resources\n     this was already fixed but we live _selfDestruct for backwards compatability\n     @method _selfDestruct\n     **/\n    _selfDestruct() {\n        setTimeout(() => {\n            //todo: ???\n            // var sceneEditView = BB.comBroker.getService(BB.SERVICES['SCENE_EDIT_VIEW']);\n            // if (!_.isUndefined(sceneEditView)) {\n            //     var selectedSceneID = sceneEditView.getSelectedSceneID();\n            //     pepper.removeScenePlayer(selectedSceneID, self.m_block_id);\n            //     BB.comBroker.fire(BB.EVENTS.LOAD_SCENE, this, null, selectedSceneID);\n            // }\n        }, 2000);\n    }\n\n    /**\n     Delete block is a private method that is always called regardless if instance has\n     been inherited or not. Used for releasing memory for garbage collector.\n     @method _deleteBlock\n     @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb\n     @return none\n     **/\n    _deleteBlock(i_memoryOnly) {\n        // if (!i_memoryOnly)\n        //     pepper.removeBlockFromTimelineChannel(this.m_block_id);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.BLOCK_SELECTED, this);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.BLOCK_LENGTH_CHANGING, this);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.GRADIENT_COLOR_CHANGED, this);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.GRADIENT_COLOR_CLOSED, this);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.BLOCK_BORDER_CHANGE, this);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.ALPHA_CHANGED, this);\n        // BB.comBroker.stopListenWithNamespace(BB.EVENTS.LOCK_CHANGED, this);\n        // $(Elements.SHOW_BACKGROUND).off(this.m_proxyToggleBgKey, this.m_proxyToggleBg);\n        // $(Elements.SHOW_BORDER).off(this.m_proxyToggleBorderKey, this.m_proxyToggleBorder);\n\n        // if (this.off != undefined)\n        //     this.off('modified');\n        //\n        // if (this.m_sceneSelectedHandler)\n        //     this.m_canvas.off('object:selected', this.m_sceneSelectedHandler);\n        //\n        // $.each(this, function (k) {\n        //     this[k] = undefined;\n        // });\n    }\n}"
  },
  {
    "path": "src/app/blocks/block-prop-calendar.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport * as moment from 'moment'\n\n@Component({\n    selector: 'block-prop-calendar',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div *ngIf=\"!jsonMode\">\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <span i18n>token</span><br/>\n                            <input class=\"default-prop-width\" (blur)=\"_getGoogleCalendars()\" type=\"text\" [formControl]=\"m_contGroup.controls['token']\"/>\n                        </li>\n                        <li class=\"list-group-item\">                                                              \n                            <button i18n class=\"btn btn-default default-prop-width\" (click)=\"_onCreateToken()\">create token</button>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <span i18n>Load with calendar</span>\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                                <select #sceneSelection (change)=\"_onCalSelected($event)\" style=\"height: 30px; width: 234px\" formControlName=\"calSelection\">\n                                    <option [value]=\"cal.id\" *ngFor=\"let cal of m_calList\">{{cal.label}}</option>\n                                </select>\n\n                            </div>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <span i18n>offset range mode</span>\n                            <div class=\"material-switch pull-right\">\n                                <input (click)=\"_onModeChange(w1.checked)\"\n                                       [formControl]=\"m_contGroup.controls['mode']\"\n                                       id=\"w1\" #w1\n                                       name=\"w1\" type=\"checkbox\"/>\n                                <label for=\"w1\" class=\"label-primary\"></label>\n                            </div>\n                        </li>\n\n                        <li *ngIf=\"m_mode\" class=\"list-group-item\">\n                            <label i18n>days before today</label><br/>\n                            <input type=\"number\" min=\"1\" [formControl]=\"m_contGroup.controls['before']\"/>\n                        </li>\n\n                        <li *ngIf=\"m_mode\" class=\"list-group-item\">\n                            <label i18n>days after today</label><br/>\n                            <input type=\"number\" min=\"1\" [formControl]=\"m_contGroup.controls['after']\"/>\n                        </li>\n\n                        <li *ngIf=\"!m_mode\" class=\"list-group-item\">\n                            <label i18n>start date</label><br/>\n                            <input (blur)=\"_saveDates('daily_start',$event)\" #datepickerSchedulerDailyStart type=\"date\" [formControl]=\"m_contGroup.controls['startDate']\"\n                                   class=\"form-control\"\n                                   placeholder=\"start date\">\n                        </li>\n\n                        <li *ngIf=\"!m_mode\" class=\"list-group-item\">\n                            <label i18n>end date</label><br/>\n                            <input (blur)=\"_saveDates('daily_start',$event)\" #datepickerSchedulerDailyStart type=\"date\" [formControl]=\"m_contGroup.controls['endDate']\"\n                                   class=\"form-control\"\n                                   placeholder=\"start date\">\n                        </li>\n\n                    </ul>\n                </div>\n                <div *ngIf=\"jsonMode\">\n                    <block-prop-json-player [setBlockData]=\"m_blockData\"></block-prop-json-player>\n                </div>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropCalendar extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_calList = [];\n    m_calSeleced: any = {};\n    m_mode = false;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'token': [''],\n            'mode': [''],\n            'startDate': ['1/1/2020'],\n            'endDate': ['1/1/2020'],\n            'before': [],\n            'after': [],\n            'calSelection': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() jsonMode: boolean;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    _saveDates(range) {\n\n    }\n\n    _onCalSelected(event) {\n        var calId = event.target.value;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('id', calId);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var $data = jXML(domPlayerData).find('Json').find('Data');\n        var mode = $data.attr('mode');\n        this.m_mode = (mode == 'fixed') ? false : true;\n        var before = $data.attr('before');\n        var after = $data.attr('after');\n        this.m_formInputs['mode'].setValue(this.m_mode);\n        this.m_formInputs['after'].setValue(after);\n        this.m_formInputs['before'].setValue(before);\n        this.m_formInputs['token'].setValue($data.attr('token'));\n        this._getGoogleCalendars();\n        this._populateStartEndDates();\n    }\n\n    /**\n     Populate the start and end dates for Google calendar date range selection\n     If first time date component is used, set startDate and endDate where\n     startDate is relative to today and endDate for a week from now\n     @method _populateStartEndDates\n     **/\n    _populateStartEndDates(): void {\n        var startDate = this._getRangeDate('startDate');\n        var endDate = this._getRangeDate('endDate');\n        this.m_formInputs['startDate'].setValue(startDate);\n        this.m_formInputs['endDate'].setValue(endDate);\n    }\n\n    _setRangeDate(i_field: 'startDate' | 'endDate', i_value): void {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json').find('Data');\n        var value = moment(i_value).unix() + '000';\n        jXML(xSnippet).attr(i_field, value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _getRangeDate(i_field): string {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        var value: any = jXML(item).attr(i_field);\n        if (_.isEmpty(value)) {\n            var date = new Date();\n            var lastWeek: number = date.setDate(new Date().getDate() - 7);\n            var newDate = moment(lastWeek).format('YYYY-MM-DD');\n            return newDate;\n        }\n        value = value.slice(0, -3);\n        value = moment.unix(parseInt(value)).format('YYYY-MM-DD');\n        return value;\n    }\n\n    _onModeChange(i_value) {\n        var mode = i_value == true ? 'offset' : 'fixed';\n        this.m_mode = i_value;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json').find('Data');\n        jXML(xSnippet).attr('mode', mode);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _getGoogleCalendars() {\n        var self = this;\n        try {\n            jQuery.ajax({\n                url: `https://secure.digitalsignage.com/GoogleCalendarList/${self.m_contGroup.value.token}/100`,\n                dataType: \"json\",\n                type: \"post\",\n                complete: function (response, status) {\n                    self.m_calSeleced = {};\n                    self.m_calList = [];\n                    if (_.isUndefined(response.responseText) || response.responseText.length == 0)\n                        return;\n                    if (response.responseText.indexOf('Cannot')>-1)\n                        return;\n                    var jData = JSON.parse(response.responseText);\n                    _.forEach(jData, function (k: any) {\n                        self.m_calList.push({\n                            id: k.id,\n                            label: k.summary\n                        })\n                    });\n                    var id = self._getFileId();\n                    if (id && id.length > 10)\n                        self.m_calSeleced = self.m_calList.find(item => item.id == id);\n                    self.m_formInputs['calSelection'].setValue(self.m_calSeleced.id);\n                    self.cd.markForCheck()\n                },\n                error: function (jqXHR, exception) {\n                    console.log('ajax req:' + jqXHR, exception);\n                }\n            });\n        } catch (e) {\n            console.error('error on ajax' + e);\n        }\n    }\n\n    private _getFileId(): string {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        return jXML(item).attr('id');\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onCreateToken() {\n        var win = window.open('http://google.signage.me', '_blank');\n        if (win) {\n            win.focus();\n        } else {\n            bootbox.alert('Browser popups are blocked, please enable and try again');\n        }\n    }\n\n    private saveToStore() {\n        // Lib.Con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('before', this.m_contGroup.value.before);\n        jXML(item).attr('after', this.m_contGroup.value.after);\n        jXML(item).attr('token', this.m_contGroup.value.token);\n        this._setRangeDate('startDate',this.m_contGroup.value.startDate)\n        this._setRangeDate('endDate',this.m_contGroup.value.endDate)\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-clock.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from \"@angular/core\";\nimport {FormBuilder} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser} from \"ng-mslib\";\nimport {IFontSelector} from \"../../comps/font-selector/font-selector\";\nimport {Lib} from \"../../Lib\";\n\n@Component({\n    selector: 'block-prop-clock',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div style=\"padding: 5px\">\n            <form novalidate autocomplete=\"off\">\n                <div class=\"row\">\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <div id=\"blockClockCommonProperties\">\n                                <span i18n>Choose format</span>\n                                <div class=\"radio\" *ngFor=\"let item of m_clockFormats\">\n                                    <label>\n                                        <input type=\"radio\" name=\"options\" (click)=\"m_model.options = item; _onFormatChanged(item)\" [checked]=\"item === m_model.options\" [value]=\"item\">\n                                        {{item.format}}\n                                    </label>\n                                </div>\n                            </div>\n                        </li>\n                    </ul>\n                </div>\n            </form>\n        </div>\n        <font-selector (onChange)=\"_onFontChanged($event)\" [setConfig]=\"m_fontConfig\"></font-selector>\n    `\n})\nexport class BlockPropClock extends Compbaser implements AfterViewInit {\n\n    m_blockData: IBlockData;\n    m_fontConfig: IFontSelector;\n    m_clockFormats = [{\n        type: 'longDateAndTime',\n        format: 'Friday, Mar 21 2018 at 8:59AM'\n    }, {\n        type: 'longDate',\n        format: 'Friday, Mar 21 2018'\n    }, {\n        type: 'shortDayTime',\n        format: 'Friday 9:10 AM'\n    }, {\n        type: 'date',\n        format: '3/21/18'\n    }, {\n        type: 'time',\n        format: '9:00:39 AM'\n    }];\n\n    m_model = {\n        options: this.m_clockFormats[0]\n    };\n\n    constructor(private fb: FormBuilder, private rp: RedPepperService, private bs: BlockService) {\n        super();\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    _onFontChanged(config: IFontSelector) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Clock');\n        var xSnippetFont = jXML(xSnippet).find('Font');\n        config.bold == true ? xSnippetFont.attr('fontWeight', 'bold') : xSnippetFont.attr('fontWeight', 'normal');\n        config.italic == true ? xSnippetFont.attr('fontStyle', 'italic') : xSnippetFont.attr('fontStyle', 'normal');\n        config.underline == true ? xSnippetFont.attr('textDecoration', 'underline') : xSnippetFont.attr('textDecoration', 'none');\n        xSnippetFont.attr('fontColor', Lib.ColorToDecimal(config.color));\n        xSnippetFont.attr('fontSize', config.size);\n        xSnippetFont.attr('fontFamily', config.font);\n        xSnippetFont.attr('textAlign', config.alignment);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _onFormatChanged(e) {\n        var mask = this.bs.getBlockBoilerplate(this.m_blockData.blockCode).getDateTimeMask(e.type);\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Clock');\n        xSnippet.attr('clockMask', mask);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        var self = this;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Clock');\n        var mask = jXML(xSnippet).attr('clockMask');\n        var xSnippetFont = jXML(xSnippet).find('Font');\n\n        this.m_clockFormats.forEach(i_clockFormat => {\n            var currMask = self.bs.getBlockBoilerplate(self.m_blockData.blockCode).getDateTimeMask(i_clockFormat.type);\n            if (mask == currMask) {\n                this.m_model = {options: i_clockFormat};\n            }\n        });\n\n        this.m_fontConfig = {\n            size: Number(xSnippetFont.attr('fontSize')),\n            alignment: <any>xSnippetFont.attr('textAlign'),\n            bold: xSnippetFont.attr('fontWeight') == 'bold' ? true : false,\n            italic: xSnippetFont.attr('fontStyle') == 'italic' ? true : false,\n            font: xSnippetFont.attr('fontFamily'),\n            underline: xSnippetFont.attr('textDecoration') == 'underline' ? true : false,\n            color: Lib.ColorToHex(Lib.DecimalToHex(xSnippetFont.attr('fontColor'))),\n        }\n    }\n\n    destroy() {\n        // console.log('destroy html component');\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-collection.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, ViewChild} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {List} from \"immutable\";\nimport {ISimpleGridEdit} from \"../../comps/simple-grid-module/SimpleGrid\";\nimport {StoreModel} from \"../../store/model/StoreModel\";\nimport {SimpleGridRecord} from \"../../comps/simple-grid-module/SimpleGridRecord\";\nimport {SimpleGridTable} from \"../../comps/simple-grid-module/SimpleGridTable\";\nimport {ISimpleGridDraggedData} from \"../../comps/simple-grid-module/SimpleGridDraggable\";\nimport {JsonEventResourceModel} from \"./json-event-grid\";\nimport {Lib} from \"../../Lib\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {IAddContents} from \"../../interfaces/IAddContent\";\nimport {BlockLabels, PLACEMENT_LISTS, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\n@Component({\n    selector: 'block-prop-collection',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    styles: [`\n        /* walk up the ancestor tree and if darkTheme is found, apply style */\n        /*:host-context(.darkTheme) * {*/\n        /*background-color: #1e1e1e;*/\n        /*}*/\n    `],\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <li class=\"list-group-item\">\n                    <span i18n>Kiosk mode</span><br/>\n                    <div class=\"material-switch pull-right\" style=\"position: relative; top: -24px\">\n                        <input #imageRatio (change)=\"_toggleKioskMode(imageRatio.checked)\" [formControl]=\"m_contGroup.controls['mode']\" id=\"imageRatio\" name=\"imageRatio\" type=\"checkbox\"/>\n                        <label for=\"imageRatio\" class=\"label-primary\"></label>\n                    </div>\n                </li>\n                \n                <li class=\"list-group-item\">\n                    <button (click)=\"_onAddNewCollectionItem()\" type=\"button\" title=\"add event\" class=\"btn btn-default btn-sm\">\n                        <span class=\"fa fa-plus\"></span>\n                    </button>\n                    <button (click)=\"_onRemoveCollectionItem()\" type=\"button\" title=\"remove event\" class=\"btn btn-default btn-sm\">\n                        <span class=\"fa fa-minus\"></span>\n                    </button>                    \n                </li>\n                <li class=\"list-group-item\">\n                    <label i18n>Play collection in sequence</label>\n                    <div style=\"overflow-x: auto\">\n                        <div style=\"width: 250px\">\n                            <simpleGridTable #simpleGrid>\n                                <thead>\n                                <tr>\n                                    <th>name</th>\n                                    <th>seconds</th>\n                                    <th>order</th>\n                                </tr>\n                                </thead>\n                                <tbody simpleGridDraggable (dragCompleted)=\"_onDragComplete($event)\">\n                                <tr class=\"simpleGridRecord\" simpleGridRecord *ngFor=\"let item of m_collectionList; let index=index\" [item]=\"item\" [index]=\"index\">\n                                    <td style=\"width: 45%\" [editable]=\"true\" (labelEdited)=\"_onPageNameEdited($event,index)\" field=\"name\" simpleGridData [item]=\"item\"></td>\n                                    <td style=\"width: 45%\" [editable]=\"true\" (labelEdited)=\"_onDurationEdited($event,index)\" field=\"duration\" simpleGridData [item]=\"item\"></td>\n                                    <td style=\"width: 10%\" simpleGridDataImage [item]=\"item\" [color]=\"'blue'\" [field]=\"'fa-arrows-v'\"></td>\n                                </tr>\n                                </tbody>\n                            </simpleGridTable>\n                        </div>\n                    </div>\n                </li>\n                <li *ngIf=\"m_contGroup.controls['mode'].value == 1\" class=\"list-group-item\">\n                    <json-event-grid [collectionList]=\"m_collectionList\" [resources]=\"this.m_jsonEventResources\" [showOption]=\"'page'\" [setBlockData]=\"m_blockData\"></json-event-grid>\n                </li>\n            </div>\n        <modal #modal>\n            <modal-header [show-close]=\"true\">\n                <h4 i18n class=\"modal-title\">add content to collection</h4>\n            </modal-header>\n            <modal-body>\n                <add-content [placement]=\"m_PLACEMENT_LISTS\" #addContent (onClosed)=\"_onClosed()\" (onAddContentSelected)=\"_onAddedContent($event)\"></add-content>\n            </modal-body>\n            <modal-footer [show-default-buttons]=\"true\"></modal-footer>\n        </modal>\n    `\n})\nexport class BlockPropCollection extends Compbaser implements AfterViewInit {\n\n    formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    m_PLACEMENT_LISTS = PLACEMENT_LISTS;\n    m_collectionList: List<StoreModel>;\n    m_jsonEventResources: Array<JsonEventResourceModel>;\n\n    constructor(private fb: FormBuilder, private yp:YellowPepperService, private cd: ChangeDetectorRef, private bs: BlockService, @Inject('BLOCK_PLACEMENT') private blockPlacement: string, private rp: RedPepperService) {\n        super();\n        this.m_contGroup = fb.group({\n            'mode': [0]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @ViewChild('simpleGrid')\n    simpleGrid: SimpleGridTable;\n\n    @ViewChild(ModalComponent)\n    modal: ModalComponent;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        this.m_blockData = i_blockData;\n        this._render();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onAddNewBlock() {\n        this.modal.open()\n    }\n\n    _onClosed(){\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    // _onAddedNewBlock(i_addContents:IAddContents) {\n    //     console.log('added ' + i_addContents.name);\n    //     this.modal.close()\n    // }\n\n    _onDragComplete(dragData: ISimpleGridDraggedData) {\n        // dragData.items.forEach((item: StoreModel, i) => con(i + ' ' + item.getKey('name')) );\n        var currentIndex = dragData.currentIndex;\n        var newIndex = dragData.newIndex;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var target = jXML(domPlayerData).find('Collection').children().get(newIndex);\n        var source = jXML(domPlayerData).find('Collection').children().get(currentIndex);\n        newIndex > currentIndex ? jXML(target).after(source) : jXML(target).before(source);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _onRemoveCollectionItem() {\n        var record: SimpleGridRecord = this.simpleGrid.getSelected();\n        if (_.isUndefined(record)) return;\n        var rowIndex = this.simpleGrid.getSelected().index;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        jXML(domPlayerData).find('Collection').children().eq(rowIndex).remove();\n        // self._populateTableCollection(domPlayerData);\n        this._populateTableEvents();\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onAddNewCollectionItem() {\n        this._onAddNewBlock()\n    }\n\n    _onDurationEdited(event: ISimpleGridEdit, index) {\n        var value = event.value;\n        if (!Lib.IsNumber(value)) return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Collection').children().get(index);\n        jXML(item).attr('duration', value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onPageNameEdited(event: ISimpleGridEdit, index) {\n        var value = event.value;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Collection').children().get(index);\n        jXML(item).attr('page', value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n\n    _populateTableCollection() {\n        this.m_collectionList = List([]);\n        var domPlayerData = this.m_blockData.playerDataDom as any\n        var rowIndex = 0;\n\n        jXML(domPlayerData).find('Collection').children().each((k, page) => {\n            var resource_hResource, scene_hDataSrc;\n            var type = jXML(page).attr('type');\n            if (type == 'resource') {\n                resource_hResource = jXML(page).find('Resource').attr('hResource');\n            } else {\n                scene_hDataSrc = jXML(page).find('Player').attr('hDataSrc');\n            }\n            //con('populating ' + resource_hResource);\n\n            var storeModel = new StoreModel({\n                rowIndex: rowIndex,\n                checkbox: true,\n                name: jXML(page).attr('page'),\n                duration: jXML(page).attr('duration'),\n                type: type,\n                resource_hResource: resource_hResource,\n                scene_hDataSrc: scene_hDataSrc\n            });\n            this.m_collectionList = this.m_collectionList.push(storeModel);\n            rowIndex++;\n        });\n        this.m_collectionList = this._sortCollection(this.m_collectionList);\n    }\n\n    /**\n     Load event list to block props UI\n     @method _populateTableEvents\n     **/\n    _populateTableEvents() {\n        var data: Array<JsonEventResourceModel> = [], rowIndex = 0;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        // self.m_collectionEventTable.bootstrapTable('removeAll');\n        jXML(domPlayerData).find('EventCommands').children().each(function (k, eventCommand) {\n            var pageName = '';\n            if (jXML(eventCommand).attr('command') == 'selectPage')\n                pageName = jXML(eventCommand).find('Page').attr('name');\n            var storeModel = new JsonEventResourceModel({\n                    rowIndex: rowIndex,\n                    checkbox: true,\n                    event: jXML(eventCommand).attr('from'),\n                    pageName: pageName,\n                    action: jXML(eventCommand).attr('command')\n                }\n            )\n            data.push(storeModel)\n            rowIndex++;\n        });\n        this.m_jsonEventResources = data;\n    }\n\n    _sortCollection(i_collection: List<StoreModel>): List<StoreModel> {\n        var sorted = i_collection.sort((a, b) => {\n            if (a.getKey('rowIndex') > b.getKey('rowIndex'))\n                return 1;\n            if (a.getKey('rowIndex') < b.getKey('rowIndex'))\n                return -1;\n            return 0;\n        })\n        return sorted as List<StoreModel>;\n    }\n\n    _render() {\n        this.m_contGroup.reset();\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xSnippetCollection = jXML(domPlayerData).find('Collection');\n        var mode = jXML(xSnippetCollection).attr('mode') == 'kiosk' ? 1 : 0;\n        this.formInputs['mode'].setValue(mode);\n        this._populateTableCollection();\n        this._populateTableEvents();\n        this.cd.markForCheck();\n    }\n\n    _toggleKioskMode(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        jXML(domPlayerData).find('Collection').attr('mode', i_value ? 'kiosk' : 'slideshow');\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    /**\n     Add a new collection item which can include a Scene or a resource (not a component)\n     @method _onAddedContent\n     @param {Event} e\n     **/\n    _onAddedContent(i_addContents: IAddContents) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippetCollection = jXML(domPlayerData).find('Collection');\n        var buff = '';\n        if (Number(i_addContents.blockCode) == BlockLabels.BLOCKCODE_SCENE) {\n            // add scene to collection, if block resides in scene don't allow cyclic reference to collection scene inside current scene\n            if (this.blockPlacement == PLACEMENT_SCENE && this.m_blockData.scene.handle == i_addContents.sceneData.scene_id) {\n                return bootbox.alert('You cannot display a scene in a collection that refers to itself, that is just weird');\n            }        \n            var sceneName = i_addContents.sceneData.domPlayerDataJson.Player._label;\n            var nativeId = i_addContents.sceneData.scene_native_id;\n            buff = `<Page page=\"${sceneName}\" type=\"scene\" duration=\"5\"> \n                        <Player src=\"${nativeId}\" hDataSrc=\"${i_addContents.sceneData.scene_id}\"/>\n                    </page>`;\n        } else {\n            // Add resources to collection\n            var resourceName = this.rp.getResourceRecord(i_addContents.resourceId).resource_name;\n            buff = `<Page page=\"${resourceName}\" type=\"resource\" duration=\"5\">\n                            <Player player=\"${i_addContents.blockCode}\">\n                                <Data>\n                                    <Resource hResource=\"${i_addContents.resourceId}\"/>\n                                </Data>\n                            </Player>\n                        </page>`\n        }\n        jXML(xSnippetCollection).append(jXML(buff));\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        // var domPlayerData = this.m_blockData.playerDataDom;\n        // var xSnippet = jXML(domPlayerData).find('HTML');\n        // xSnippet.attr('src', this.m_contGroup.value.url);\n        // this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n\n"
  },
  {
    "path": "src/app/blocks/block-prop-common.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Subject} from \"rxjs\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Lib} from \"../../Lib\";\nimport * as _ from \"lodash\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\n\n@Component({\n    selector: 'block-prop-common',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form class=\"inner5\" novalidate autocomplete=\"off\" [formGroup]=\"contGroup\">\n            <div class=\"row\">\n                <div class=\"panel-heading\">\n                    <small class=\"release\">common properties\n                        <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                    </small>\n\n                </div>\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        alpha\n                        <input id=\"slider1\" (change)=\"_onAlphaChange($event)\" [formControl]=\"contGroup.controls['alpha']\" type=\"range\" min=\"0\" max=\"1\" step=\"0.1\"/>\n                    </li>\n                    <li [ngClass]=\"{hidden: m_isPropsForScene}\" class=\"list-group-item\">\n                        background\n                        <button style=\"position: relative; top: 15px\" (click)=\"_onRemoveBackgroundClicked()\" class=\"btn btn-default btn-sm pull-right\" type=\"button\">\n                            <i class=\"fa fa-times\"></i>\n                        </button>\n                        <div id=\"bgColorGradientSelector\"></div>\n                    </li>\n                    <li *ngIf=\"m_isPropsForScene\" class=\"list-group-item\">\n                        <div style=\"padding-top: 20px; padding-bottom: 20px\">\n                            <span i18n>scene background color</span>\n                            <br/>\n                            <div class=\"material-switch pull-right\">\n                                <input #colorSelection (change)=\"_toggleSceneBackground(colorSelection.checked)\"\n                                       [formControl]=\"contGroup.controls['sceneBackground']\"\n                                       id=\"colorSelection\"\n                                       name=\"colorSelection\" type=\"checkbox\"/>\n                                <label for=\"colorSelection\" class=\"label-primary\"></label>\n                            </div>\n                            <input #sceneBackgroundColor [disabled]=\"!colorSelection.checked\" (colorPickerChange)=\"m_sceneBackgroundColorChanged.next($event)\"\n                                   [cpOKButton]=\"true\" [cpOKButtonClass]=\"'btn btn-primary btn-xs'\"\n                                   [cpFallbackColor]=\"'#123'\"\n                                   [cpPresetColors]=\"[]\"\n                                   [(colorPicker)]=\"m_sceneBackgroundColor\" [cpPosition]=\"'bottom'\"\n                                   [cpAlphaChannel]=\"'disabled'\" style=\"width: 185px\"\n                                   [style.background]=\"m_sceneBackgroundColor\" [value]=\"m_sceneBackgroundColor\"/>\n                        </div>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <div style=\"padding-top: 20px; padding-bottom: 20px\">\n                            <span i18n>border color</span>\n                            <br/>\n                            <div class=\"material-switch pull-right\">\n                                <input #borderSelection (change)=\"_toggleBorder(borderSelection.checked)\"\n                                       [formControl]=\"contGroup.controls['border']\"\n                                       id=\"borderSelection\"\n                                       name=\"borderSelection\" type=\"checkbox\"/>\n                                <label for=\"borderSelection\" class=\"label-primary\"></label>\n                            </div>\n                            <input #borderColor [disabled]=\"!borderSelection.checked\" (colorPickerChange)=\"m_borderColorChanged.next($event)\"\n                                   [cpOKButton]=\"true\" [cpOKButtonClass]=\"'btn btn-primary btn-xs'\"\n                                   [cpFallbackColor]=\"'#123'\"\n                                   [cpPresetColors]=\"[]\"\n                                   [(colorPicker)]=\"m_color\" [cpPosition]=\"'bottom'\"\n                                   [cpAlphaChannel]=\"'disabled'\" style=\"width: 185px\"\n                                   [style.background]=\"m_color\" [value]=\"m_color\"/>\n                        </div>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropCommon extends Compbaser implements AfterViewInit {\n\n    private formInputs = {};\n    contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_isPropsForScene: boolean = false;\n    m_borderColorChanged = new Subject();\n    m_sceneBackgroundColorChanged = new Subject();\n    m_color;\n    m_sceneBackgroundColor;\n\n    constructor(@Inject('BLOCK_PLACEMENT') private blockPlacement: string, private cd: ChangeDetectorRef, private fb: FormBuilder, private rp: RedPepperService, private bs: BlockService, private el: ElementRef) {\n        super();\n        this.contGroup = fb.group({\n            'alpha': [0],\n            'borderColor': [],\n            'border': [0],\n            'sceneBackgroundColor': [],\n            'sceneBackground': [0]\n        });\n        _.forEach(this.contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.contGroup.controls[key] as FormControl;\n        })\n        this._listenBorderChanged();\n    }\n\n    /**\n     * set block data for the component.\n     * on first selection we just set the blockData, in subsequent calls we only\n     * re-render if we are dealing with a new block id, note that on componet creation\n     * the rendering is done via ngAfterViewInit\n     * @param i_blockData\n     */\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    ngAfterViewInit() {\n        this._listenBorderChanged();\n        this._bgGradientWidgetInit();\n        this._render();\n    }\n\n    /**\n     * Render the component with latest data from BlockData\n     */\n    _render() {\n        this.m_isPropsForScene = parseInt(this.m_blockData.blockCode) == BlockLabels.BLOCKCODE_SCENE ? true : false;\n        this._alphaPopulate();\n        this._gradientPopulate();\n        this._sceneBackgroundPopulate();\n        this._borderPropsPopulate();\n    }\n\n    _listenBorderChanged() {\n        this.cancelOnDestroy(\n            //\n            this.m_borderColorChanged\n                .debounceTime(500)\n                .filter(v => v != '#123')\n                .subscribe((i_color: any) => {\n                    var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n                    var border = this._findBorder(domPlayerData);\n                    jXML(border).attr('borderColor', Lib.HexToDecimal(i_color));\n                    this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.m_sceneBackgroundColorChanged\n                .debounceTime(500)\n                .filter(v => v != '#123')\n                .subscribe((i_color: any) => {\n                    var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n                    var xPoints = this._findGradientPoints(domPlayerData);\n                    jXML(xPoints).find('Point').attr('color', Lib.HexToDecimal(i_color));\n                    this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n                    this.bs.notifySceneBgChanged();\n                }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Toggle block background on UI checkbox selection\n     @method _toggleBorder\n     @param {event} e\n     **/\n    _toggleSceneBackground(i_checked: boolean) {\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n        var checked = i_checked == true ? 1 : 0;\n        if (checked) {\n            var xBgSnippet = this.bs.getCommonBackgroundXML();\n            var data = jXML(domPlayerData).find('Data').eq(0);\n            jXML(data).find('Background').remove();\n            jXML(data).append(jXML(xBgSnippet));\n            this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n            this._sceneBackgroundPopulate();\n        } else {\n            var xSnippet = this._findGradientPointsScene(domPlayerData);\n            jXML(xSnippet).empty();\n            this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        }\n        this.bs.notifySceneBgChanged()\n    }\n\n    /**\n     Toggle block background on UI checkbox selection\n     @method _toggleBorder\n     @param {event} e\n     **/\n    _toggleBorder(i_checked: boolean) {\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n        var checked = i_checked == true ? 1 : 0;\n        if (checked) {\n            var xBgSnippet = this.bs.getCommonBorderXML();\n            var data = jXML(domPlayerData).find('Data').eq(0);\n            var bgData: any = this._findBorder(data);\n            if (bgData.length > 0 && !_.isUndefined(bgData.replace)) { // ie bug workaround\n                bgData.replace(jXML(xBgSnippet));\n            } else {\n                jXML(data).append(jXML(xBgSnippet));\n            }\n            this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        } else {\n            var xSnippet = this._findBorder(domPlayerData);\n            jXML(xSnippet).remove();\n            this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        }\n    }\n\n    /**\n     On changes in msdb model updated UI common alpha properties\n     @method _alphaPopulate\n     **/\n    _alphaPopulate() {\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData);\n        var data = jXML(domPlayerData).find('Data').eq(0);\n        var xSnippet = jXML(data).find('Appearance').eq(0);\n        var a1: any = jXML(xSnippet).attr('alpha');\n        if (_.isUndefined(a1)) a1 = 1;\n        this.formInputs['alpha'].setValue(a1)\n    }\n\n    _onAlphaChange(event) {\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData);\n        var data = jXML(domPlayerData).find('Data').eq(0);\n        var xSnippet = jXML(data).find('Appearance').eq(0);\n        jXML(xSnippet).attr('alpha', event.target.value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        this.bs.notifySceneBlockChanged(this.m_blockData)\n    }\n\n    _sceneBackgroundPropsPopulate() {\n        var self = this;\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n        var xSnippet = self._findBorder(domPlayerData);\n        if (xSnippet.length > 0) {\n            var color = jXML(xSnippet).attr('borderColor');\n            this._updateBorderColor(true, color)\n        } else {\n            this._updateBorderColor(false, '16777215')\n        }\n    }\n\n    /**\n     On changes in msdb model updated UI common border properties\n     @method _borderPropsPopulate\n     **/\n    _borderPropsPopulate() {\n        var self = this;\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n        var xSnippet = self._findBorder(domPlayerData);\n        if (xSnippet.length > 0) {\n            var color = jXML(xSnippet).attr('borderColor');\n            this._updateBorderColor(true, color)\n        } else {\n            this._updateBorderColor(false, '16777215')\n        }\n    }\n\n    @timeout(50)\n    _sceneBackgroundPopulate() {\n        if (!this.m_isPropsForScene) return;\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n        var xPoints = this._findGradientPointsScene(domPlayerData);\n        var color = jXML(xPoints).find('Point').attr('color');\n        if (_.isUndefined(color))\n            return this.formInputs['sceneBackground'].setValue(false)\n        this.formInputs['sceneBackground'].setValue(true);\n        color = '#' + Lib.DecimalToHex(color);\n        this.m_sceneBackgroundColor = color;\n        this.cd.markForCheck();\n    }\n\n    @timeout(50)\n    _updateBorderColor(i_value, i_color) {\n        this.formInputs['border'].setValue(i_value);\n        this.m_color = '#' + Lib.DecimalToHex(i_color);\n        // this.formInputs['border_input'].setValue(this.m_color);\n        this.cd.markForCheck();\n    }\n\n    @timeout(50)\n    _updateSceneBackgroundColor(i_value, i_color) {\n        this.formInputs['sceneBackground'].setValue(i_value);\n        this.m_color = '#' + Lib.DecimalToHex(i_color);\n        this.cd.markForCheck();\n    }\n\n    /**\n     Find the border section in player_data for selected block\n     @method _findBorder\n     @param  {object} i_domPlayerData\n     @return {Xml} xSnippet\n     **/\n    _findBorder(i_domPlayerData) {\n        return jXML(i_domPlayerData).find('Border');\n    }\n\n    /**\n     Load jXML gradient component once\n     @method _bgGradientWidgetInit\n     **/\n    _bgGradientWidgetInit() {\n        var self = this;\n        var lazyUpdateBgColor = _.debounce(function (points, styles) {\n            if (points.length == 0)\n                return;\n            self._gradientChanged({points: points, styles: styles})\n            // console.log('gradient 1...' + Math.random());\n        }, 50);\n\n        var gradientColorPickerClosed = function () {\n            // console.log('gradient 2');\n        };\n\n        jQuery('#bgColorGradientSelector', self.el.nativeElement).gradientPicker({\n            change: lazyUpdateBgColor,\n            closed: gradientColorPickerClosed,\n            fillDirection: \"90deg\"\n        });\n\n        // always close gradient color picker on mouseout\n        // jXML('.colorpicker').on('mouseleave', function (e) {\n        //     jXML(document).trigger('mousedown');\n        //     console.log('gradient 3');\n        // });\n    }\n\n    /**\n     On changes in msdb model updated UI common gradient background properties\n     @method _gradientPopulate\n     **/\n    _gradientPopulate() {\n        var self = this;\n        var gradient = jXML('#bgColorGradientSelector', self.el.nativeElement).data(\"gradientPicker-sel\");\n        // gradient.changeFillDirection(\"top\"); /* change direction future support */\n        this._bgGradientWidgetClear();\n        var domPlayerData = self.m_blockData.playerDataDom;\n        var xSnippet = self._findGradientPoints(domPlayerData);\n        if (xSnippet.length > 0) {\n            var points = jXML(xSnippet).find('Point');\n            $.each(points, function (i, point) {\n                var pointColor = Lib.DecimalToHex(jXML(point).attr('color'));\n                var pointMidpoint = (parseInt(jXML(point).attr('midpoint')) / 250);\n                gradient.addPoint(pointMidpoint, pointColor, true);\n            });\n        }\n    }\n\n    _bgGradientWidgetClear() {\n        var gradient = jQuery('#bgColorGradientSelector', this.el.nativeElement).data(\"gradientPicker-sel\");\n        gradient.removeAllPoints();\n        gradient.clear();\n    }\n\n    _gradientChanged(e) {\n        var self = this;\n        var points: any = e.points;\n        var styles = e.styles;\n        if (points.length == 0)\n            return;\n        var domPlayerData = self.m_blockData.playerDataDom;\n        jXML(domPlayerData).find('Background').remove();\n        var pointsXML = \"\";\n        for (var i = 0; i < points.length; ++i) {\n            var pointMidpoint: any = (points[i].position * 250);\n            var color = Lib.ColorToDecimal(points[i].color);\n            var xPoint = '<Point color=\"' + color + '\" opacity=\"1\" midpoint=\"' + pointMidpoint + '\" />';\n            // log(xPoint);\n            // jXML(gradientPoints).append(xPoint);\n            pointsXML += xPoint;\n        }\n        var xPointsSnippet = jXML.parseXML(this.bs.getCommonBackgroundXML());\n        jXML(xPointsSnippet).find('GradientPoints').empty().append(pointsXML);\n        var newGradientPoints = (new XMLSerializer()).serializeToString(xPointsSnippet);\n        jXML(domPlayerData).find('Data').append(newGradientPoints)\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _findGradientPoints(i_domPlayerData) {\n        var xSnippet = jXML(i_domPlayerData).find('GradientPoints');\n        return xSnippet;\n    }\n\n    _findGradientPointsScene(i_domPlayerData) {\n        var xBackground = jXML(i_domPlayerData).find('Layout').eq(0).siblings().filter('Background');\n        var xSnippet = jXML(xBackground).find('GradientPoints').eq(0);\n        return xSnippet;\n    }\n\n\n    _onRemoveBackgroundClicked() {\n        this._bgGradientWidgetClear();\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var gradientPoints = this._findGradientPoints(domPlayerData);\n        jXML(gradientPoints).empty();\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _findBackground(i_domPlayerData) {\n        var xSnippet = jXML(i_domPlayerData).find('Background');\n        return xSnippet;\n    }\n\n    destroy() {\n        var gradient = jXML('#bgColorGradientSelector', this.el.nativeElement).data(\"gradientPicker-sel\");\n        gradient.destroyed();\n    }\n}\n\n"
  },
  {
    "path": "src/app/blocks/block-prop-container.ts",
    "content": "import {AfterViewInit, ChangeDetectorRef, Component, Inject, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {BlockService, IBlockData, ISceneData} from \"./block-service\";\nimport {CampaignTimelineChanelPlayersModel} from \"../../store/imsdb.interfaces_auto\";\nimport {ColorPickerService} from \"ngx-color-picker\";\nimport {Tab} from \"../../comps/tabs/tab\";\nimport {BlockLabels, PLACEMENT_CHANNEL, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\n\n\n@Component({\n    selector: 'block-prop-container',\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <tabs>\n            <tab [tabtitle]=\"'style'\">\n                <block-prop-common [setBlockData]=\"m_blockData\"></block-prop-common>\n            </tab>\n            <tab [tabtitle]=\"m_tabTitle\">\n                <div [ngSwitch]=\"m_blockTypeSelected\">\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_IMAGE\">\n                        <block-prop-image [external]=\"false\" [setBlockData]=\"m_blockData\"></block-prop-image>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_SVG\">\n                        <block-prop-image [external]=\"false\" [setBlockData]=\"m_blockData\"></block-prop-image>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.IMAGE\">\n                        <block-prop-image [external]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-image>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_VIDEO\">\n                        <block-prop-video [external]=\"false\" [setBlockData]=\"m_blockData\"></block-prop-video>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.EXTERNAL_VIDEO\">\n                        <block-prop-video [external]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-video>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.MRSS\">\n                        <block-prop-mrss [setBlockData]=\"m_blockData\"></block-prop-mrss>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_COLLECTION\">\n                        <block-prop-collection [setBlockData]=\"m_blockData\"></block-prop-collection>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.RSS\">\n                        <block-prop-rss [setBlockData]=\"m_blockData\"></block-prop-rss>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.LABEL\">\n                        <block-prop-label [setBlockData]=\"m_blockData\"></block-prop-label>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.QR\">\n                        <block-prop-qr [setBlockData]=\"m_blockData\"></block-prop-qr>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.CLOCK\">\n                        <block-prop-clock [setBlockData]=\"m_blockData\"></block-prop-clock>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.HTML\">\n                        <block-prop-html [setBlockData]=\"m_blockData\"></block-prop-html>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.FASTERQ\">\n                        <block-prop-fasterq [setBlockData]=\"m_blockData\"></block-prop-fasterq>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_SCENE\">\n                        <block-prop-scene [setBlockData]=\"m_blockData\"></block-prop-scene>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.LOCATION\">\n                        <block-prop-location [setBlockData]=\"m_blockData\"></block-prop-location>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.YOUTUBE\">\n                        <block-prop-youtube [setBlockData]=\"m_blockData\"></block-prop-youtube>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_JSON\">\n                        <block-prop-json-player [standAlone]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-json-player>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_JSON_ITEM\">\n                        <block-prop-json-item [setBlockData]=\"m_blockData\"></block-prop-json-item>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_WORLD_WEATHER\">\n                        <block-prop-weather [setBlockData]=\"m_blockData\"></block-prop-weather>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_INSTAGRAM\">\n                        <block-prop-instagram [setBlockData]=\"m_blockData\"></block-prop-instagram>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_DIGG\">\n                        <block-prop-digg [setBlockData]=\"m_blockData\"></block-prop-digg>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_CALENDAR\">\n                        <block-prop-calendar [setBlockData]=\"m_blockData\"></block-prop-calendar>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_TWITTERV3\">\n                        <block-prop-twitter [setBlockData]=\"m_blockData\"></block-prop-twitter>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_GOOGLE_SHEETS\">\n                        <block-prop-sheets [setBlockData]=\"m_blockData\"></block-prop-sheets>\n                    </div>\n                    <div *ngSwitchDefault>\n                        <h3>no block prop found, new?</h3>\n                        {{m_blockTypeSelected}}\n                    </div>\n                </div>\n            </tab>\n            <!-- below are JSON based blocked which bind to scenes -->\n            <tab #settings [tabtitle]=\"'settings'\">\n                <div [ngSwitch]=\"m_blockTypeSelected\">\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_WORLD_WEATHER\">\n                        <block-prop-weather [jsonMode]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-weather>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_INSTAGRAM\">\n                        <block-prop-instagram [jsonMode]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-instagram>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_DIGG\">\n                        <block-prop-digg [jsonMode]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-digg>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_CALENDAR\">\n                        <block-prop-calendar [jsonMode]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-calendar>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_TWITTERV3\">\n                        <block-prop-twitter [jsonMode]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-twitter>\n                    </div>\n                    <div *ngSwitchCase=\"m_blockLabels.BLOCKCODE_GOOGLE_SHEETS\">\n                        <block-prop-sheets [jsonMode]=\"true\" [setBlockData]=\"m_blockData\"></block-prop-sheets>\n                    </div>\n                </div>\n            </tab>\n        </tabs>\n    `,\n})\nexport class BlockPropContainer extends Compbaser implements AfterViewInit {\n\n    m_blockTypeSelected: string = 'none';\n    m_blockLabels = BlockLabels;\n    m_blockData: IBlockData;\n    m_tabTitle: string = 'none';\n    m_showSettingsTab = true;\n\n    constructor(@Inject('BLOCK_PLACEMENT') private blockPlacement: string, private yp: YellowPepperService, private bs: BlockService, private cpService: ColorPickerService, private cd: ChangeDetectorRef) {\n        super();\n        // console.log(blockPlacement);\n        if (this.blockPlacement == PLACEMENT_CHANNEL)\n            this._listenOnChannels();\n        if (this.blockPlacement == PLACEMENT_SCENE)\n            this._listenOnScenes();\n    }\n\n    @ViewChild('settings')\n    settings: Tab;\n\n    ngAfterViewInit() {\n        this.toggleSettingsTab();\n    }\n\n    private _listenOnChannels() {\n        this.cancelOnDestroy(\n            //\n            this.yp.listenBlockChannelSelectedOrChanged()\n                .mergeMap((i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModel) => {\n                    return this.bs.getBlockData(i_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId())\n                })\n                .subscribe((blockData: IBlockData) => {\n                    this.m_blockTypeSelected = blockData.blockCode;\n                    this.m_tabTitle = blockData.blockAcronym;\n                    this.m_blockData = blockData;\n                    // for json based scenes show the settings, unless its the actual Json Player which we don't\n                    if (blockData.playerMimeScene && this.m_blockTypeSelected != '4300') {\n                        this.m_showSettingsTab = true;\n                        this.toggleSettingsTab();\n                    } else {\n                        this.m_showSettingsTab = false;\n                        this.toggleSettingsTab();\n                    }\n                }, (e) => console.error(e))\n        )\n    }\n\n    private _listenOnScenes() {\n        this.cancelOnDestroy(\n            //\n            this.yp.listenSceneOrBlockSelectedChanged()\n                .mergeMap((i_sceneData: ISceneData) => {\n                    return this.bs.getBlockDataInScene(i_sceneData)\n                })\n                .subscribe((blockData: IBlockData) => {\n                    this.m_blockTypeSelected = blockData.blockCode;\n                    this.m_tabTitle = blockData.blockAcronym;\n                    this.m_blockData = blockData;\n                    this.m_showSettingsTab = false;\n                    this.toggleSettingsTab();\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n    }\n\n    // private getTabTitle(i_blockData: IBlockData): string {\n    //     // this.bs.getCommonBorderXML()if (i_blockData.blockAcronym.indexOf('JSON')) > -1 ? blockData.playerMimeScene : blockData.blockAcronym\n    // }\n\n    private toggleSettingsTab() {\n        if (!this.settings) return;\n        this.settings.show = this.m_showSettingsTab;\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/blocks/block-prop-fasterq.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {Subject} from \"rxjs\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Lib} from \"../../Lib\";\n\n@Component({\n    selector: 'block-prop-fasterq',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    styles: [`\n        .offSet {\n            position: relative;\n            top: 5px;\n        }\n\n        button {\n            margin: 5px;\n            height: 30px;\n        }\n\n        .colorPicker {\n            width: 20px;\n            float: left;\n            display: inline-block;\n            margin: 0 10px 0 0;\n            padding: 15px 45px;\n            border-radius: 0;\n            border: 1px solid gray;\n            padding: 10px 20px 10px 20px;\n            background: #21ff2e;\n            text-decoration: none;\n        }\n    `],\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <span i18n>customer lines</span><br/>\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <label i18n>background color</label>\n                        <button (click)=\"_moveColorPicker()\" #borderColor (colorPickerChange)=\"m_borderColorChanged.next($event)\"\n                                [cpOKButton]=\"true\" [cpOKButtonClass]=\"'btn btn-primary btn-xs'\"\n                                [(colorPicker)]=\"m_color\" [cpPosition]=\"'left'\" style=\"width: 59px\"\n                                [cpAlphaChannel]=\"'disabled'\" class=\"colorPicker offSet pull-right\"\n                                [style.background]=\"m_color\"></button>\n                        <br/>\n                        <br/>\n                    </li>\n                    <li class=\"list-group-item\"><input class=\"default-prop-width\" type=\"text\" formControlName=\"lineID1\"/></li>\n                    <li class=\"list-group-item\"><input class=\"default-prop-width\" type=\"text\" formControlName=\"lineID2\"/></li>\n                    <li class=\"list-group-item\"><input class=\"default-prop-width\" type=\"text\" formControlName=\"lineID3\"/></li>\n                    <li class=\"list-group-item\"><input class=\"default-prop-width\" type=\"text\" formControlName=\"lineID4\"/></li>\n                    <li class=\"list-group-item\"><input class=\"default-prop-width\" type=\"text\" formControlName=\"lineID5\"/></li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropFasterQ extends Compbaser implements AfterViewInit {\n\n    formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_borderColorChanged = new Subject();\n    m_moveColorPickerOnce = false;\n    m_color = '#ffffff';\n\n    constructor(private fb: FormBuilder, private el: ElementRef, private bs: BlockService, private cd: ChangeDetectorRef) {\n        super();\n        this.m_contGroup = fb.group({\n            'lineID1': [''],\n            'lineID2': [''],\n            'lineID3': [''],\n            'lineID4': [''],\n            'lineID5': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n        this._listenColorChanged();\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    _listenColorChanged() {\n        this.cancelOnDestroy(\n            //\n            this.m_borderColorChanged\n                .debounceTime(500)\n                .distinct()\n                .skip(1)\n                .subscribe((i_color) => {\n                    this.m_color = String(i_color);\n                    this.saveToStore();\n                }, (e) => console.error(e))\n        )\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xWebKit = jXML(domPlayerData).find('Webkit');\n        var xWebKitData = jXML(xWebKit).find('Data');\n        this.formInputs['lineID1'].setValue(jXML(xWebKitData).attr('lineID1'));\n        this.formInputs['lineID2'].setValue(jXML(xWebKitData).attr('lineID2'));\n        this.formInputs['lineID3'].setValue(jXML(xWebKitData).attr('lineID3'));\n        this.formInputs['lineID4'].setValue(jXML(xWebKitData).attr('lineID4'));\n        this.formInputs['lineID5'].setValue(jXML(xWebKitData).attr('lineID5'));\n        this.setNewColor(jXML(xWebKitData).attr('bgColor'));\n        // this.m_color = Lib.ColorToHex(Lib.DecimalToHex(jXML(xWebKitData).attr('bgColor')));\n    }\n\n    @timeout()\n    _moveColorPicker() {\n        console.log(this.m_color);\n        if (this.m_moveColorPickerOnce) return;\n        this.m_moveColorPickerOnce = true;\n        jXML(\".color-picker\", this.el.nativeElement).css(\"left\", \"+=100\");\n    }\n\n    @timeout(50)\n    private setNewColor(i_color) {\n        if (_.isNaN(Lib.ColorToDecimal(i_color)))\n            i_color = '#ffffff';\n        this.m_color = i_color\n        this.cd.markForCheck();\n    }\n\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xWebKit = jXML(domPlayerData).find('Webkit');\n        var xWebKitData = jXML(xWebKit).find('Data');\n        jXML(xWebKitData).attr('lineID1', this.formInputs['lineID1'].value);\n        jXML(xWebKitData).attr('lineID2', this.formInputs['lineID2'].value);\n        jXML(xWebKitData).attr('lineID3', this.formInputs['lineID3'].value);\n        jXML(xWebKitData).attr('lineID4', this.formInputs['lineID4'].value);\n        jXML(xWebKitData).attr('lineID5', this.formInputs['lineID5'].value);\n        jXML(xWebKitData).attr('bgColor', this.m_color);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-html.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-html',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <span i18n>url</span><br/>\n                        <input class=\"default-prop-width\" type=\"text\" [formControl]=\"m_contGroup.controls['url']\"/>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropHtml extends Compbaser implements AfterViewInit {\n\n    private formInputs = {};\n    m_contGroup: FormGroup;\n    private m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private rp: RedPepperService, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'url': ['', [Validators.pattern(urlRegExp)]]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        this.m_contGroup.reset();\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xSnippet = jXML(domPlayerData).find('HTML');\n        this.formInputs['url'].setValue(xSnippet.attr('src'));\n    }\n\n\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('HTML');\n        xSnippet.attr('src', this.m_contGroup.value.url);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-image.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {urlRegExp} from \"../../Lib\";\n\n@Component({\n    selector: 'block-prop-image',\n    host: {'(input-blur)': 'saveToStore($event)'},\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li *ngIf=\"external\" class=\"list-group-item\">\n                        <span i18n>url</span><br/>\n                        <input class=\"default-prop-width\" type=\"text\" [formControl]=\"m_contGroup.controls['url']\"/>\n                    </li>\n                    <li *ngIf=\"!external\" class=\"list-group-item\">\n                        <span i18n>maintain aspect ratio</span>\n                        <div class=\"material-switch pull-right\">\n                            <input #imageRatio (change)=\"_toggleAspectRatio(imageRatio.checked)\"\n                                   [formControl]=\"m_contGroup.controls['maintain']\"\n                                   id=\"imageRatio\"\n                                   name=\"imageRatio\" type=\"checkbox\"/>\n                            <label for=\"imageRatio\" class=\"label-primary\"></label>\n                        </div>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropImage extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'url': ['', [Validators.pattern(urlRegExp)]],\n            'maintain': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    @Input() external: boolean = false;\n\n    /**\n     Toggle maintain aspect ratio\n     **/\n    _toggleAspectRatio(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('AspectRatio');\n        jXML(xSnippet).attr('maintain', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        if (this.external) {\n            var xSnippet = jXML(domPlayerData).find('LINK');\n            this.m_formInputs['url'].setValue(xSnippet.attr('src'));\n        } else {\n            var xSnippet = jXML(domPlayerData).find('AspectRatio');\n            var maintain = StringJS(jXML(xSnippet).attr('maintain')).booleanToNumber();\n            this.m_formInputs['maintain'].setValue(maintain);\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    private saveToStore() {\n        con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('LINK');\n        xSnippet.attr('src', this.m_contGroup.value.url);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/blocks/block-prop-instagram.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-instagram',\n    host: {'(input-blur)': 'saveToStore($event)'},\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div *ngIf=\"!jsonMode\">\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <span i18n>token</span>\n                            <input type=\"text\" [formControl]=\"m_contGroup.controls['token']\"/>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <button class=\"btn btn-default\" (click)=\"_onCreateToken()\"><span i18n>create instagram access token</span></button>\n                        </li>\n                    </ul>\n                </div>\n                <div *ngIf=\"jsonMode\">\n                    <block-prop-json-player [setBlockData]=\"m_blockData\"></block-prop-json-player>\n                </div>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropInstagram extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'token': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() jsonMode: boolean;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var jXMLdata = jXML(domPlayerData).find('Json').find('Data');\n        this.m_formInputs['token'].setValue(jXMLdata.attr('token'));\n        // this.cd.markForCheck();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onCreateToken() {\n        var win = window.open('http://instagram.signage.me', '_blank');\n        if (win) {\n            win.focus();\n        } else {\n            bootbox.alert('Browser popups are blocked, please enable and try again');\n        }\n    }\n\n    private saveToStore() {\n        con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('token', this.m_contGroup.value.token);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-json-item.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {IFontSelector} from \"../../comps/font-selector/font-selector\";\nimport {Lib} from \"../../Lib\";\n\n@Component({\n    selector: 'block-prop-json-item',\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div id=\"blockJsonItemCommonProperties\">\n                    <div *ngIf=\"jsonItemFieldContainer\">\n                        <span data-localize=\"JsonItem\">Json path notation</span>\n                        <br/>\n                        <input (change)=\"_onJsonItemTextFieldChanged($event)\" type=\"text\" name=\"name\" formControlName=\"jsonItemField\" value=\"jsonItemField\" placeholder=\"json item\">\n                    </div>\n                    <div>\n                        <div *ngIf=\"jsonItemTextFieldsContainer\">\n                            <label style=\"padding-right: 78px; width: 200px\" for=\"jsonItemTextFields\" data-localize=\"field\">\n                                field </label>\n                            <select formControlName=\"jsonItemTextFields\" (change)=\"_onJsonItemTextFieldsChanged($event)\" class=\"propControlWidth form-control\">\n                                <option [value]=\"field.value\" *ngFor=\"let field of m_fields\">{{field.label}}</option>\n                            </select>\n                        </div>\n                    </div>\n                    <br/>\n                    <div *ngIf=\"jsonItemDualNumericSettings\">\n                        <label style=\"display: inline-block; padding-right: 8px\"> row </label>\n                        <label style=\"display: inline-block\"> column </label>\n                        <div class=\"spinnerDimHeight\">\n                            <div style=\"float: left\">\n                                <span data-numeric=\"column\">\n                                     <input (change)=\"_onDualNumericChanged()\" formControlName=\"jsonItemDualNumeric1\" type=\"number\" style=\"width: 60px\">\n                                </span>\n                            </div>\n                        </div>\n                        <div class=\"spinnerDimHeight\">\n                            <div style=\"float: left\">\n                                <span data-numeric=\"row\">\n                                 <input (change)=\"_onDualNumericChanged()\" formControlName=\"jsonItemDualNumeric2\" type=\"number\" style=\"width: 60px\">\n                              </span>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"clearfix\"></div>\n                    <div *ngIf=\"jsonItemFontSettings\">\n                        <font-selector (onChange)=\"_onFontChanged($event)\" [setConfig]=\"m_fontConfig\"></font-selector>\n                    </div>\n                    <div *ngIf=\"jsonItemDateSettings\">\n                        <div class=\"clearfix\"></div>\n                        <label class=\"pull-left\" data-localize=\"dateFormat\">date format</label>\n                        <select formControlName=\"jsonItemDateFormat\" (change)=\"_onJsonItemDateFieldsChanged($event)\" class=\"propControlWidth form-control\">\n                            <option [value]=\"dateField.value\" *ngFor=\"let dateField of m_dateFields\">{{dateField.value}}</option>\n                        </select>\n                    </div>\n                    <div *ngIf=\"jsonItemIconSettings\">\n                        <span i18n>maintain aspect ratio</span>\n                        <div class=\"material-switch pull-right\">\n                            <input #imageRatio (change)=\"_toggleAspectRatio(imageRatio.checked)\"\n                                   formControlName=\"jsonItemMaintainAspectRatio\"\n                                   class=\"default-prop-width\"\n                                   id=\"imageRatio\"\n                                   name=\"imageRatio\" type=\"checkbox\"/>\n                            <label for=\"imageRatio\" class=\"label-primary\"></label>\n                        </div>\n                        <div class=\"clearfix\" style=\"padding-bottom: 13px\"></div>\n                    </div>\n                </div>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropJsonItem extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_sheetList = [];\n    m_sheetSeleced: any = {};\n    m_fields = [];\n    m_dateFields = [];\n    m_fontConfig: IFontSelector;\n\n    jsonItemFieldContainer;\n    jsonItemTextFieldsContainer;\n    jsonItemDualNumericSettings;\n    jsonItemIconSettings;\n    jsonItemDateSettings;\n    jsonItemFontSettings;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'jsonItemField': [''],\n            'jsonItemTextFields': [''],\n            'jsonItemDualNumeric1': [''],\n            'jsonItemDualNumeric2': [''],\n            'jsonItemDateFormat': [''],\n            'jsonItemMaintainAspectRatio': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var jXMLdata = jXML(domPlayerData).find('Json').find('Data');\n        var mode = jXMLdata.attr('mode');\n\n        // JSON item (no mime)\n        if (_.isUndefined(this.m_blockData.playerMimeScene)) {\n            var domPlayerData = this.m_blockData.playerDataDom;\n            var xSnippet = jXML(domPlayerData).find('XmlItem');\n            var xSnippetFont = jXML(xSnippet).find('Font');\n            var fieldName = jXML(xSnippet).attr('fieldName');\n\n            this.jsonItemFieldContainer = true;\n            this.jsonItemTextFieldsContainer = false;\n            this.jsonItemDualNumericSettings = false;\n            this.jsonItemIconSettings = false;\n            this.jsonItemDateSettings = false;\n            this.jsonItemFontSettings = true;\n            this.m_formInputs['jsonItemField'].setValue(fieldName);\n            this._populateFonts(xSnippetFont)\n        } else {\n            // Json mime\n            this._populateMimeType();\n        }\n    }\n\n    _toggleAspectRatio(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        jXML(xSnippet).attr('maintainAspectRatio', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onJsonItemTextFieldChanged(i_event) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        jXML(xSnippet).attr('fieldName', i_event.target.value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onJsonItemTextFieldsChanged(event) {\n        var name = event.target.value;\n        var mime = this.m_blockData.playerMimeScene;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        _.forEach(this.m_config[mime].fields, (k:any) => {\n            if (k.name == name) {\n                jXML(xSnippet).attr('fieldType', k.type);\n                jXML(xSnippet).attr('fieldName', k.name);\n                this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n                this._populateMimeType();\n\n            }\n        })\n    }\n\n    _onJsonItemDateFieldsChanged(event) {\n        var value = event.target.value;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        jXML(xSnippet).attr('dateFormat', value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        this._populateMimeType();\n    }\n\n    _onDualNumericChanged(){\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        var row = this.m_contGroup.value.jsonItemDualNumeric1;\n        var column = this.m_contGroup.value.jsonItemDualNumeric2;\n        var fieldName = `$cells.${row}.${column}.value`;\n        jXML(xSnippet).attr('fieldName', fieldName);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n    \n    _onFontChanged(config: IFontSelector) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        var xSnippetFont = jXML(xSnippet).find('Font');\n        config.bold == true ? xSnippetFont.attr('fontWeight', 'bold') : xSnippetFont.attr('fontWeight', 'normal');\n        config.italic == true ? xSnippetFont.attr('fontStyle', 'italic') : xSnippetFont.attr('fontStyle', 'normal');\n        config.underline == true ? xSnippetFont.attr('textDecoration', 'underline') : xSnippetFont.attr('textDecoration', 'none');\n        xSnippetFont.attr('fontColor', Lib.ColorToDecimal(config.color));\n        xSnippetFont.attr('fontSize', config.size);\n        xSnippetFont.attr('fontFamily', config.font);\n        xSnippetFont.attr('textAlign', config.alignment);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    /**\n     The component is a subclass of JSON item (i.e.: it has a mimetype) so we need to populate it according\n     to its mimetype config options\n     **/\n    private _populateMimeType() {\n        var self = this;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        var xSnippetFont = jXML(xSnippet).find('Font');\n        var fieldType = jXML(xSnippet).attr('fieldType');\n        var fieldName = jXML(xSnippet).attr('fieldName');\n        var maintainAspectRatio = jXML(xSnippet).attr('maintainAspectRatio');\n        var dateFormat = jXML(xSnippet).attr('dateFormat');\n\n        this.jsonItemFieldContainer = false;\n        this.jsonItemTextFieldsContainer = true;\n\n        this.m_fields = [{type: '', value: '', label: 'no field selected'}];\n        var fields: any = self.m_config[this.m_blockData.playerMimeScene].fields;\n        _.each(fields, (k: any) => this.m_fields.push({type: k.type, value: k.name, label: k.label}));\n        this.m_formInputs['jsonItemTextFields'].setValue(fieldName)\n\n        // populate according to filed type (text/resource)\n        switch (fieldType) {\n            case 'resource': {\n                this.jsonItemFontSettings = false;\n                this.jsonItemDateSettings = false;\n                this.jsonItemIconSettings = true;\n                self._populateAspectRatio(maintainAspectRatio);\n                break;\n            }\n            case 'date': {\n                self._populateDateFormat(dateFormat);\n                this._populateFonts(xSnippetFont);\n                this.jsonItemDateSettings = true;\n                break;\n            }\n            case 'dual_numeric': {\n            }\n            case 'text': {\n                this.jsonItemIconSettings = false;\n                this.jsonItemDateSettings = false;\n                this.jsonItemFontSettings = true;\n                this._populateFonts(xSnippetFont);\n                break;\n            }\n        }\n\n        // populate according to mimetype exception or default behavior\n        switch (this.m_blockData.playerMimeScene) {\n            case 'Json.spreadsheet': {\n                this.jsonItemDualNumericSettings = true;\n                self._populateDualNumeric();\n                break;\n            }\n            default: {\n                this.jsonItemDualNumericSettings = false;\n            }\n        }\n        this.cd.markForCheck();\n        this.cd.detectChanges();\n    }\n\n    private _populateFonts(xSnippetFont) {\n        this.m_fontConfig = {\n            bold: xSnippetFont.attr('fontWeight') === 'bold' ? true : false,\n            italic: xSnippetFont.attr('fontStyle') === 'italic' ? true : false,\n            underline: xSnippetFont.attr('textDecoration') === 'underline' ? true : false,\n            alignment: <any>xSnippetFont.attr('textAlign'),\n            font: xSnippetFont.attr('fontFamily'),\n            color: Lib.ColorToHex(Lib.DecimalToHex(xSnippetFont.attr('fontColor'))),\n            size: Number(xSnippetFont.attr('fontSize'))\n        };\n        // this.cd.markForCheck();\n    }\n\n    /**\n     Populate date format for common types of date styles on dropdown selection\n     @method _populateDateFormat\n     @param {string} i_selectedFormat\n     **/\n    private _populateDateFormat(i_selectedFormat) {\n        var formats = [\n            'D/M/Y',\n            'DD/MM/YY',\n            'DD/MM/YYYY',\n            'DD/MMM/YY',\n            'MM/DD/YY',\n            'MM/DD/YYYY',\n            'MMM/DD/YYYY ',\n            'D/M/Y J:NN:SS',\n            'DD/MM/YY J:NN:SS',\n            'DD/MM/YYYY J:NN:SS',\n            'DD/MMM/YY J:NN:SS',\n            'MM/DD/YY J:NN:SS',\n            'MM/DD/YYYY J:NN:SS',\n            'MMM/DD/YYYY J:NN:SS',\n            'J:NN:SS',\n            'J:NN:SS A',\n            'J:NN:SS A',\n            'J:NN'\n        ];\n        this.m_dateFields = [{value: 'select format'}];\n        for (var i = 0; i < formats.length; i++) {\n            this.m_dateFields.push({value: formats[i]});\n        }\n        this.m_formInputs['jsonItemDateFormat'].setValue(i_selectedFormat)\n    }\n\n    /**\n     Populate aspect ratio switch button\n     **/\n    private _populateAspectRatio(i_aspectRatio) {\n        var value = StringJS(i_aspectRatio).booleanToNumber();\n        this.m_formInputs['jsonItemMaintainAspectRatio'].setValue(value)\n    }\n\n    /**\n     Populate the dual numeric steppers that are used in components like the google sheets\n     @method _populateDualNumeric\n     **/\n    private _populateDualNumeric() {\n        var row: string = '1';\n        var column: string = '1';\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('XmlItem');\n        var fieldName = jXML(xSnippet).attr('fieldName');\n        var re = /cells.([0-9]+).([0-9]+).value/i;\n        var match = fieldName.match(re);\n        if (!_.isNull(match)) {\n            row = String(match[1]);\n            column = String(match[2]);\n        }\n        this.m_formInputs['jsonItemDualNumeric1'].setValue(row)\n        this.m_formInputs['jsonItemDualNumeric2'].setValue(column)\n        // var spinners = jXML('.spinner', Elements.JSON_ITEM_DUAL_NUMERIC_SETTINGS);\n        // jXML(spinners[0]).spinner('value', row);\n        // jXML(spinners[2]).spinner('value', column);\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    m_config = {\n        'Json.instagram.feed': {\n            title: 'Instagram',\n            tabTitle: 'Posts',\n            fields: {\n                1: {\n                    name: \"title\",\n                    type: \"text\",\n                    label: \"title\"\n                },\n                2: {\n                    name: \"urlImage\",\n                    type: \"resource\",\n                    label: \"image\"\n                },\n                3: {\n                    name: \"video\",\n                    type: \"resource\",\n                    label: \"video\"\n                }\n            }\n        },\n        'Json.twitter': {\n            title: 'Twitter',\n            tabTitle: 'Tweets',\n            fields: {\n                1: {\n                    name: \"name\",\n                    type: \"text\",\n                    label: \"name\"\n                },\n                2: {\n                    name: \"text\",\n                    type: \"text\",\n                    label: \"text\"\n                },\n                3: {\n                    name: \"screen_name\",\n                    type: \"text\",\n                    label: \"screen name\"\n                },\n                4: {\n                    name: \"created_at\",\n                    type: \"text\",\n                    label: \"created at\"\n                },\n                5: {\n                    name: \"profile_background_image_url\",\n                    type: \"resource\",\n                    label: \"Background image\"\n                },\n                6: {\n                    name: \"profile_image_url\",\n                    type: \"resource\",\n                    label: \"Image\"\n                }\n            }\n        },\n        'Json.digg': {\n            title: 'Digg',\n            tabTitle: 'Posts',\n            fields: {\n                1: {\n                    name: \"title\",\n                    type: \"text\",\n                    label: \"title\"\n                },\n                2: {\n                    name: \"link\",\n                    type: \"resource\",\n                    label: \"image\"\n                }\n            }\n        },\n        'Json.spreadsheet': {\n            title: 'Spreadsheet',\n            tabTitle: 'Cells',\n            fields: {\n                1: {\n                    name: \"$cells.1.1.value\",\n                    type: \"dual_numeric\",\n                    label: \"Sheet cell\"\n                }\n            }\n        },\n\n        'Json.calendar': {\n            title: 'Calendar',\n            tabTitle: 'Date',\n            fields: {\n                1: {\n                    name: \"summary\",\n                    type: \"text\",\n                    label: \"summary\"\n                },\n                2: {\n                    name: \"description\",\n                    type: \"text\",\n                    label: \"description\"\n                },\n                3: {\n                    name: \"organizer\",\n                    type: \"text\",\n                    label: \"organizer\"\n                },\n                4: {\n                    name: \"organizerEmail\",\n                    type: \"text\",\n                    label: \"organizer email\"\n                },\n                5: {\n                    name: \"created\",\n                    type: \"text\",\n                    label: \"created\"\n                },\n                6: {\n                    name: \"startDateTime_time\",\n                    type: \"date\",\n                    label: \"start date time\"\n                },\n                7: {\n                    name: \"endDateTime_time\",\n                    type: \"date\",\n                    label: \"end date time\"\n                },\n                8: {\n                    name: \"updated\",\n                    type: \"text\",\n                    label: \"updated\"\n                }\n            }\n        },\n        'Json.weather': {\n            title: 'World weather',\n            tabTitle: 'Conditions',\n            fields: {\n                1: {\n                    name: \"$[0].data.current_condition[0].iconPath\",\n                    type: \"resource\",\n                    label: \"current icon\"\n                },\n                2: {\n                    name: \"$[0].data.current_condition[0].temp_@\",\n                    type: \"text\",\n                    label: \"current temp\"\n                },\n                3: {\n                    name: \"$[0].data.current_condition[0].humidity\",\n                    type: \"text\",\n                    label: \"current humidity\"\n                },\n                4: {\n                    name: \"$[0].data.weather[0].iconPath\",\n                    type: \"resource\",\n                    label: \"today icon\"\n                },\n                5: {\n                    name: \"$[0].data.weather[0].mintemp@\",\n                    type: \"text\",\n                    label: \"today min temp\"\n                },\n                6: {\n                    name: \"$[0].data.weather[0].maxtemp@\",\n                    type: \"text\",\n                    label: \"today max temp\"\n                },\n                7: {\n                    name: \"$[0].data.weather[0].day\",\n                    type: \"text\",\n                    label: \"today label\"\n                },\n                8: {\n                    name: \"$[0].data.weather[1].iconPath\",\n                    type: \"resource\",\n                    label: \"today+1 icon\"\n                },\n                9: {\n                    name: \"$[0].data.weather[1].mintemp@\",\n                    type: \"text\",\n                    label: \"today+1 min temp\"\n                },\n                10: {\n                    name: \"$[0].data.weather[1].maxtemp@\",\n                    type: \"text\",\n                    label: \"today+1 max temp\"\n                },\n                11: {\n                    name: \"$[0].data.weather[1].day\",\n                    type: \"text\",\n                    label: \"today+1 label\"\n                },\n                12: {\n                    name: \"$[0].data.weather[2].iconPath\",\n                    type: \"resource\",\n                    label: \"today+2 icon\"\n                },\n                13: {\n                    name: \"$[0].data.weather[2].mintemp@\",\n                    type: \"text\",\n                    label: \"today+2 min temp\"\n                },\n                14: {\n                    name: \"$[0].data.weather[2].maxtemp@\",\n                    type: \"text\",\n                    label: \"today+2 max temp\"\n                },\n                15: {\n                    name: \"$[0].data.weather[2].day\",\n                    type: \"text\",\n                    label: \"today+2 label\"\n                },\n                16: {\n                    name: \"$[0].data.weather[3].iconPath\",\n                    type: \"resource\",\n                    label: \"today+3 icon\"\n                },\n                17: {\n                    name: \"$[0].data.weather[3].mintemp@\",\n                    type: \"text\",\n                    label: \"today+3 min temp\"\n                },\n                18: {\n                    name: \"$[0].data.weather[3].maxtemp@\",\n                    type: \"text\",\n                    label: \"today+3 max temp\"\n                },\n                19: {\n                    name: \"$[0].data.weather[3].day\",\n                    type: \"text\",\n                    label: \"today+3 label\"\n                },\n                20: {\n                    name: \"$[0].data.weather[4].iconPath\",\n                    type: \"resource\",\n                    label: \"today+4 icon\"\n                },\n                21: {\n                    name: \"$[0].data.weather[4].mintemp@\",\n                    type: \"text\",\n                    label: \"today+4 min temp\"\n                },\n                22: {\n                    name: \"$[0].data.weather[4].maxtemp@\",\n                    type: \"text\",\n                    label: \"today+4 max temp\"\n                },\n                23: {\n                    name: \"$[0].data.weather[4].day\",\n                    type: \"text\",\n                    label: \"today+4 label\"\n                },\n                24: {\n                    name: \"$[0].data.weather[5].iconPath\",\n                    type: \"resource\",\n                    label: \"today+5 icon\"\n                },\n                25: {\n                    name: \"$[0].data.weather[5].mintemp@\",\n                    type: \"text\",\n                    label: \"today+5 min temp\"\n                },\n                26: {\n                    name: \"$[0].data.weather[5].maxtemp@\",\n                    type: \"text\",\n                    label: \"today+5 max temp\"\n                },\n                27: {\n                    name: \"$[0].data.weather[5].day\",\n                    type: \"text\",\n                    label: \"today+5 label\"\n                },\n                28: {\n                    name: \"$[0].data.weather[6].iconPath\",\n                    type: \"resource\",\n                    label: \"today+6 icon\"\n                },\n                29: {\n                    name: \"$[0].data.weather[6].mintemp@\",\n                    type: \"text\",\n                    label: \"today+6 min temp\"\n                },\n                30: {\n                    name: \"$[0].data.weather[6].maxtemp@\",\n                    type: \"text\",\n                    label: \"today+6 max temp\"\n                },\n                31: {\n                    name: \"$[0].data.weather[6].day\",\n                    type: \"text\",\n                    label: \"today+6 label\"\n                }\n            }\n        }\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-json-player.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, ViewChild} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser} from \"ng-mslib\";\nimport {urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Once} from \"../../decorators/once-decorator\";\nimport {SimpleGridTable} from \"../../comps/simple-grid-module/SimpleGridTable\";\n\n@Component({\n    selector: 'block-prop-json-player',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {'(input-blur)': 'saveToStore($event)'},\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form class=\"inner15\" novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li *ngIf=\"standAlone\" class=\"list-group-item\">\n                        <div class=\"input-group\">\n                            <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                            <input type=\"text\" class=\"form-control\" minlength=\"3\" placeholder=\"json url\" [formControl]=\"m_contGroup.controls['itemsUrl']\">\n                        </div>\n                    </li>\n                    <li *ngIf=\"standAlone\" class=\"list-group-item\">\n                        <div class=\"input-group\">\n                            <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                            <input type=\"text\" class=\"form-control\" minlength=\"3\" placeholder=\"object path\" [formControl]=\"m_contGroup.controls['itemsPath']\">\n                        </div>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>load with scene</span>\n                        <div class=\"input-group\">\n                            <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                            <p-dropdown [style]=\"{'width':'220px'}\" (onChange)=\"_onSceneSelectionChanged($event)\" [(ngModel)]=\"m_sceneSeleced\" [options]=\"m_sceneSelection\" [filter]=\"true\" formControlName=\"sceneSelection\"></p-dropdown>\n                        </div>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <label i18n>interval</label><br/>\n                        <input style=\"width: 268px\" type=\"number\" min=\"1\" [formControl]=\"m_contGroup.controls['itemInterval']\"/>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>play video to completion</span>\n                        <div class=\"material-switch pull-right\">\n                            <input (change)=\"_onPlayVideoInFull(playVideoInFull.checked)\"\n                                   [formControl]=\"m_contGroup.controls['playVideoInFull']\"\n                                   id=\"playVideoInFull\" #playVideoInFull\n                                   name=\"playVideoInFull\" type=\"checkbox\"/>\n                            <label for=\"playVideoInFull\" class=\"label-primary\"></label>\n                        </div>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>random playback</span>\n                        <div class=\"material-switch pull-right\">\n                            <input (change)=\"_onRandomPlay(randomOrder.checked)\"\n                                   [formControl]=\"m_contGroup.controls['randomOrder']\"\n                                   id=\"randomOrder\" #randomOrder\n                                   name=\"randomOrder\" type=\"checkbox\"/>\n                            <label for=\"randomOrder\" class=\"label-primary\"></label>\n                        </div>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>slideshow</span>\n                        <div class=\"material-switch pull-right\">\n                            <input (change)=\"_onSlideShow(slideShow.checked)\"\n                                   [formControl]=\"m_contGroup.controls['slideShow']\"\n                                   id=\"slideShow\" #slideShow\n                                   name=\"slideShow\" type=\"checkbox\"/>\n                            <label for=\"slideShow\" class=\"label-primary\"></label>\n                        </div>\n                    </li>\n\n                    <li *ngIf=\"!m_slideShowMode\" class=\"list-group-item\">\n                        <json-event-grid [showOption]=\"'url'\" [setBlockData]=\"m_blockData\"></json-event-grid>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropJsonPlayer extends Compbaser implements AfterViewInit {\n\n    formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_sceneSelection = [];\n    m_sceneSeleced: any = {};\n    m_slideShowMode = 0;\n\n    constructor(private fb: FormBuilder, private yp: YellowPepperService, private rp: RedPepperService, private bs: BlockService, private cd: ChangeDetectorRef) {\n        super();\n        this.m_contGroup = fb.group({\n            'sceneSelection': [],\n            'randomOrder': [],\n            'slideShow': [],\n            'playVideoInFull': [],\n            'itemInterval': [],\n            'itemsPath': [],\n            'itemsUrl': ['', [Validators.pattern(urlRegExp)]],\n            'url': ['', [Validators.pattern(urlRegExp)]]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @ViewChild('simpleGrid')\n    simpleGrid: SimpleGridTable;\n\n    @Input() standAlone: boolean = false;\n\n\n    @Input()\n    set setBlockData(i_blockData) {\n        /**\n         Disabled as in this component we wish to always update UI on block changes\n         since we are addinf and removing elements to event grid and need to be updated\n         if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n              this.m_blockData = i_blockData;\n             this._render();\n          } else {\n              this.m_blockData = i_blockData;\n         }\n         **/\n        this.m_blockData = i_blockData;\n        this._render();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onPlayVideoInFull(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json');\n        jXML(xSnippet).attr('playVideoInFull', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onRandomPlay(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json');\n        jXML(xSnippet).attr('randomOrder', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onSlideShow(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        this.m_slideShowMode = i_value;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json');\n        jXML(xSnippet).attr('slideShow', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onSceneSelectionChanged(i_scene_id) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json');\n        var xSnippetPlayer = jXML(xSnippet).find('Player');\n        jXML(xSnippetPlayer).attr('hDataSrc', i_scene_id.value.id);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    /**\n     Populate the LI with all available scenes from msdb\n     if the mimetype is empty (used for this class) we show all scenes in dropdown, but if mimetype exists\n     (used by subclasses of this class) we filter dropdown list by matching mimetypes\n     @method _populateSceneDropdown\n     **/\n    @Once()\n    private _initSceneDropdown() {\n        var self = this;\n        return this.yp.getSceneNames()\n            .subscribe((scenes) => {\n                this.m_sceneSelection = [];\n                var domPlayerData = this.m_blockData.playerDataDom;\n                var xSnippet = jXML(domPlayerData).find('Json');\n                var xSnippetPlayer = jXML(xSnippet).find('Player');\n                var selectedSceneID = jXML(xSnippetPlayer).attr('hDataSrc');\n                for (var scene in scenes) {\n                    var mimeType = scenes[scene].mimeType;\n                    var label = scenes[scene].label;\n                    var sceneId = scenes[scene].id;\n                    if (sceneId == selectedSceneID) {\n                        this.m_sceneSeleced = scenes[scene];\n                    }\n                    // if this component is used as a standalone Json Player, include in drop down all possible scenes\n                    if (self.m_blockData.playerMimeScene == mimeType || this.standAlone) {\n                        this.m_sceneSelection.push({\n                            sceneId, label, mimeType, value: scenes[scene]\n                        })\n                    }\n                }\n            }, (e) => console.error(e))\n    }\n\n    _render() {\n        this._initSceneDropdown();\n        // this._initEventTable();\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xSnippet = jXML(domPlayerData).find('Json');\n        var playVideoInFull = StringJS(jXML(xSnippet).attr('playVideoInFull')).booleanToNumber();\n        this.formInputs['playVideoInFull'].setValue(playVideoInFull);\n        var randomOrder = StringJS(jXML(xSnippet).attr('randomOrder')).booleanToNumber();\n        this.formInputs['randomOrder'].setValue(randomOrder);\n        this.m_slideShowMode = StringJS(jXML(xSnippet).attr('slideShow')).booleanToNumber(true) as number;\n        this.formInputs['slideShow'].setValue(this.m_slideShowMode);\n        this.formInputs['itemsPath'].setValue(jXML(xSnippet).attr('itemsPath'));\n        this.formInputs['itemInterval'].setValue(jXML(xSnippet).attr('itemInterval'));\n        this.formInputs['itemsUrl'].setValue(jXML(xSnippet).attr('url'));\n    }\n\n    private saveToStore() {\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Json');\n        xSnippet.attr('itemsPath', this.m_contGroup.value.itemsPath);\n        xSnippet.attr('url', this.m_contGroup.value.itemsUrl);\n        xSnippet.attr('itemInterval', this.m_contGroup.value.itemInterval);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/blocks/block-prop-label.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {Lib, urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\nimport {IFontSelector} from \"../../comps/font-selector/font-selector\";\n\n@Component({\n    selector: 'block-prop-label',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <textarea class=\"default-prop-width\" spellcheck=\"true\" rows=\"10\" cols=\"50\" type=\"textarea\" [formControl]=\"m_contGroup.controls['text']\">\n                        </textarea>\n                    </li>\n                </ul>\n            </div>\n        </form>\n        <font-selector (onChange)=\"_onFontChanged($event)\" [setConfig]=\"m_fontConfig\"></font-selector>\n    `\n})\nexport class BlockPropLabel extends Compbaser implements AfterViewInit {\n\n    private formInputs = {};\n    m_fontConfig: IFontSelector;\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private rp: RedPepperService, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'text': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xSnippetLabel = jXML(domPlayerData).find('Label');\n        var xSnippetText = jXML(xSnippetLabel).find('Text');\n        var xSnippetFont = jXML(xSnippetLabel).find('Font');\n        this.m_fontConfig = {\n            bold: xSnippetFont.attr('fontWeight') == 'bold' ? true : false,\n            italic: xSnippetFont.attr('fontStyle') == 'italic' ? true : false,\n            underline: xSnippetFont.attr('textDecoration') == 'underline' ? true : false,\n            alignment: xSnippetFont.attr('textAlign') as any,\n            font: xSnippetFont.attr('fontFamily'),\n            color: Lib.ColorToHex(Lib.DecimalToHex(xSnippetFont.attr('fontColor'))),\n            size: parseInt(xSnippetFont.attr('fontSize'))\n        };\n        this.formInputs['text'].setValue(xSnippetText.text());\n    }\n\n    _onFontChanged(config: IFontSelector) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Label');\n        var xSnippetFont = jXML(xSnippet).find('Font');\n        config.bold == true ? xSnippetFont.attr('fontWeight', 'bold') : xSnippetFont.attr('fontWeight', 'normal');\n        config.italic == true ? xSnippetFont.attr('fontStyle', 'italic') : xSnippetFont.attr('fontStyle', 'normal');\n        config.underline == true ? xSnippetFont.attr('textDecoration', 'underline') : xSnippetFont.attr('textDecoration', 'none');\n        xSnippetFont.attr('fontColor', Lib.ColorToDecimal(config.color));\n        xSnippetFont.attr('fontSize', config.size);\n        xSnippetFont.attr('fontFamily', config.font);\n        xSnippetFont.attr('textAlign', config.alignment);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var text = this.formInputs['text'].value;\n        text = Lib.CleanProbCharacters(text, 1);\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Label');\n        var xSnippetText = jXML(xSnippet).find('Text');\n        if (text != xSnippetText.text()){\n            jXML(xSnippetText).text(text);\n        }\n\n\n        var xSnippet = jXML(domPlayerData).find('HTML');\n        xSnippet.attr('src', this.formInputs['text'].value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-location.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, ViewChild} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {List} from \"immutable\";\nimport {ISimpleGridEdit} from \"../../comps/simple-grid-module/SimpleGrid\";\nimport {StoreModel} from \"../../store/model/StoreModel\";\nimport {SimpleGridRecord} from \"../../comps/simple-grid-module/SimpleGridRecord\";\nimport {SimpleGridTable} from \"../../comps/simple-grid-module/SimpleGridTable\";\nimport {ISimpleGridDraggedData} from \"../../comps/simple-grid-module/SimpleGridDraggable\";\nimport {Lib} from \"../../Lib\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {IAddContents} from \"../../interfaces/IAddContent\";\nimport {BlockLabels, PLACEMENT_LISTS, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {LocationMarkModel} from \"../../models/LocationMarkModel\";\n\n@Component({\n    selector: 'block-prop-location',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <li class=\"list-group-item\">\n                    <button (click)=\"_onAddNewBlock('Fixed')\" type=\"button\" title=\"add event\" class=\"btn btn-default btn-sm\">\n                        <span class=\"fa fa-plus\"></span>\n                    </button>\n                    <button (click)=\"_onRemoveCollectionItem()\" type=\"button\" title=\"remove event\" class=\"btn btn-default btn-sm\">\n                        <span class=\"fa fa-minus\"></span>\n                    </button>\n                </li>\n                <li class=\"list-group-item\">\n                    <label i18n>Default sequential playlist</label>\n                    <div style=\"overflow-x: auto\">\n                        <div style=\"width: 250px\">\n                            <simpleGridTable #simpleGrid>\n                                <thead>\n                                <tr>\n                                    <th>name</th>\n                                    <th>seconds</th>\n                                    <th>order</th>\n                                </tr>\n                                </thead>\n                                <tbody simpleGridDraggable (dragCompleted)=\"_onDragComplete($event)\">\n                                <tr class=\"simpleGridRecord\" simpleGridRecord *ngFor=\"let item of m_collectionList; let index=index\" [item]=\"item\" [index]=\"index\">\n                                    <td style=\"width: 45%\" [editable]=\"true\" (labelEdited)=\"_onPageNameEdited($event,index)\" field=\"name\" simpleGridData [item]=\"item\"></td>\n                                    <td style=\"width: 45%\" [editable]=\"true\" (labelEdited)=\"_onDurationEdited($event,index)\" field=\"duration\" simpleGridData [item]=\"item\"></td>\n                                    <td style=\"width: 10%\" simpleGridDataImage [item]=\"item\" [color]=\"'blue'\" [field]=\"'fa-arrows-v'\"></td>\n                                </tr>\n                                </tbody>\n                            </simpleGridTable>\n                        </div>\n                    </div>\n                </li>\n            </div>\n            <hr/>\n            <h4 *ngIf=\"!m_pendingBlocAddition\" id=\"locationControls\" class=\"panel-title\">\n                <button (click)=\"_onAddNewBlock('GPS')\" type=\"button\" name=\"addLocation\" title=\"add a new item\" class=\"addResourceToLocation btn btn-default btn-sm\">\n                    <span class=\"glyphicon glyphicon-plus\"></span>\n                </button>\n                <button (click)=\"_removeLocation()\" type=\"button\" name=\"removeLocation\" title=\"remove item\" class=\"btn btn-default btn-sm\">\n                    <span class=\"glyphicon glyphicon-minus\"></span>\n                </button>\n                <button (click)=\"_jumpToLocation('prev')\" type=\"button\" name=\"previous\" title=\"remove item\" class=\"btn btn-default btn-sm\">\n                    <span class=\"glyphicon glyphicon-chevron-left\"></span>\n                </button>\n                <button (click)=\"_jumpToLocation('next')\" type=\"button\" name=\"next\" title=\"remove item\" class=\"btn btn-default btn-sm\">\n                    <span class=\"glyphicon glyphicon-chevron-right\"></span>\n                </button>\n                <button (click)=\"_openMap()\" type=\"button\" name=\"openLocation\" title=\"openLocation item\" class=\"btn btn-default btn-sm\">\n                    <span class=\"glyphicon glyphicon glyphicon-map-marker\"></span>\n                </button>\n            </h4>\n            <br/>\n            <label>\n                <span i18n>Total location based: ></span><span>{{m_totalLocations}}</span>\n            </label>\n\n            <div class=\"row\" *ngIf=\"!m_pendingBlocAddition\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <span i18n class=\"inliner\">name</span>\n                        <input type=\"text\" class=\"numStepper inliner\" formControlName=\"label\">\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n class=\"inliner\">latitude</span>\n                        <input type=\"number\" step=\"0.1\" class=\"numStepper inliner\" formControlName=\"lat\">\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n class=\"inliner\">longitude</span>\n                        <input type=\"number\" step=\"0.1\" class=\"numStepper inliner\" formControlName=\"lng\">\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n class=\"inliner\">duration</span>\n                        <input type=\"number\" min=\"5\" max=\"86400\" class=\"numStepper inliner\" formControlName=\"duration\">\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>radius range </span><span>{{m_radius}} </span> <span i18n> kilometers</span><br/>\n                        <input #radiusControl (change)=\"m_radius = radiusControl.value\" class=\"default-prop-width\" type=\"range\" max=\"0.10\" step=\"0.1\" max=\"4\" formControlName=\"radius\"/>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>conflict priority</span><br/>\n                        <input class=\"default-prop-width\" type=\"range\" step=\"1\" max=\"1\" max=\"5\" formControlName=\"priority\"/>\n                    </li>\n                </ul>\n            </div>\n        </form>\n        <modal #modalAddContent>\n            <modal-header [show-close]=\"true\">\n                <h4 i18n class=\"modal-title\">add content to collection</h4>\n            </modal-header>\n            <modal-body>\n                <add-content [placement]=\"m_PLACEMENT_LISTS\" #addContent (onClosed)=\"_onClosed()\" (onAddContentSelected)=\"_onAddedContent($event)\"></add-content>\n            </modal-body>\n            <modal-footer [show-default-buttons]=\"true\"></modal-footer>\n        </modal>\n        <!--<modal [cssClass]=\"modal-xl\" (onClose)=\"_onModelMapClosed()\" #modalMap [size]=\"'lg'\">-->\n        <!--<modal-header [show-close]=\"false\">-->\n        <!--<h4 i18n class=\"modal-title\">add content to collection</h4>-->\n        <!--</modal-header>-->\n        <!--<modal-body>-->\n        <!--<location-map *ngIf=\"m_showMap\"></location-map>-->\n        <!--</modal-body>-->\n        <!--<modal-footer [show-default-buttons]=\"true\"></modal-footer>-->\n        <!--</modal>-->\n    `\n})\nexport class BlockPropLocation extends Compbaser implements AfterViewInit {\n\n    m_formInputs = {};\n    m_currentIndex = 0;\n    m_radius = 0;\n    m_totalLocations = 0;\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_pendingBlocAddition: { type: string, content: IAddContents, xmlSnippet: string };\n\n    m_showMap = false;\n    m_PLACEMENT_LISTS = PLACEMENT_LISTS;\n    m_collectionList: List<StoreModel>;\n\n    constructor(private fb: FormBuilder, private yp: YellowPepperService, private cd: ChangeDetectorRef, private bs: BlockService, @Inject('BLOCK_PLACEMENT') private blockPlacement: string, private rp: RedPepperService) {\n        super();\n        this.m_contGroup = fb.group({\n            'mode': [0],\n            'label': [0],\n            'lng': [0],\n            'lat': [0],\n            'duration': [0],\n            'priority': [0],\n            'radius': [0]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenLocationMarkerSelected()\n                .filter((i_LocationMarkModel: LocationMarkModel) => !_.isEmpty(this.m_pendingBlocAddition))\n                .subscribe((i_LocationMarkModel: LocationMarkModel) => {\n                    var domPlayerData = this.m_blockData.playerDataDom;\n                    var reLat = new RegExp(\":LAT:\", \"ig\");\n                    var reLng = new RegExp(\":LNG:\", \"ig\");\n                    this.m_pendingBlocAddition.xmlSnippet = this.m_pendingBlocAddition.xmlSnippet.replace(reLat, i_LocationMarkModel.lat);\n                    this.m_pendingBlocAddition.xmlSnippet = this.m_pendingBlocAddition.xmlSnippet.replace(reLng, i_LocationMarkModel.lng);\n                    var xSnippetLocation = jXML(domPlayerData).find('GPS');\n                    jXML(xSnippetLocation).append(jXML(this.m_pendingBlocAddition.xmlSnippet));\n                    this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n                    this.m_pendingBlocAddition = null;\n                    this._jumpToLocation('last')\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenLocationMapLoad()\n                .pairwise()\n                .filter(v => v[0] == true && v[1] == false && this.m_pendingBlocAddition && this.m_pendingBlocAddition.xmlSnippet != '')\n                .do(() => {\n                    console.log(1);\n                })\n                .combineLatest(this.yp.ngrxStore.select(store => store.appDb.uiState.locationMap.locationMarkerSelected))\n                .subscribe((v) => {\n                    console.log(v);\n                }, (e) => console.error(e))\n        )\n    }\n\n    @ViewChild('simpleGrid')\n    simpleGrid: SimpleGridTable;\n\n    @ViewChild('modalAddContent')\n    modalAddContent: ModalComponent;\n\n    // @ViewChild('modalMap')\n    // modalMap: ModalComponent;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        this.m_blockData = i_blockData;\n        this._render();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n        this._jumpToLocation('first');\n    }\n\n    _onModelMapClosed() {\n        this.m_showMap = false;\n    }\n\n    _onDragComplete(dragData: ISimpleGridDraggedData) {\n        // dragData.items.forEach((item: StoreModel, i) => con(i + ' ' + item.getKey('name')) );\n        var currentIndex = dragData.currentIndex;\n        var newIndex = dragData.newIndex;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var target = jXML(domPlayerData).find('Fixed').children().get(newIndex);\n        var source = jXML(domPlayerData).find('Fixed').children().get(currentIndex);\n        newIndex > currentIndex ? jXML(target).after(source) : jXML(target).before(source);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _onRemoveCollectionItem() {\n        var record: SimpleGridRecord = this.simpleGrid.getSelected();\n        if (_.isUndefined(record)) return;\n        var rowIndex = this.simpleGrid.getSelected().index;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        jXML(domPlayerData).find('Fixed').children().eq(rowIndex).remove();\n        // self._populateTableCollection(domPlayerData);\n        // this._populateTableEvents();\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n\n    _onClosed() {\n        this.modalAddContent.close()\n    }\n\n    _onAddNewBlock(type: string) {\n        this.m_pendingBlocAddition = {type: type, content: null, xmlSnippet: ''}\n        this.modalAddContent.open()\n    }\n\n    /**\n     Add a new collection item which can include a Scene or a resource (not a component)\n     @method _onAddedContent\n     @param {Event} e\n     **/\n    _onAddedContent(i_addContents: IAddContents) {\n\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var buff = '';\n        var locationBuff;\n        var xSnippetLocation;\n\n        switch (this.m_pendingBlocAddition.type) {\n            case 'Fixed': {\n                xSnippetLocation = jXML(domPlayerData).find('Fixed');\n                locationBuff = '>';\n                break;\n            }\n            case 'GPS': {\n                locationBuff = 'lat=\":LAT:\" lng=\":LNG:\" radios=\"4\" duration=\"5\" priority=\"1\">';\n                xSnippetLocation = jXML(domPlayerData).find('GPS');\n                break;\n            }\n        }\n\n        if (Number(i_addContents.blockCode) == BlockLabels.BLOCKCODE_SCENE) {\n            // add scene to collection, if block resides in scene don't allow cyclic reference to collection scene inside current scene\n            if (this.blockPlacement == PLACEMENT_SCENE && this.m_blockData.scene.handle == i_addContents.sceneData.scene_id) {\n                return bootbox.alert('You cannot display a scene in a collection that refers to itself, that is just weird');\n            }\n\n            var sceneName = i_addContents.sceneData.domPlayerDataJson.Player._label;\n            var nativeId = i_addContents.sceneData.scene_native_id;\n\n            buff = `<Page page=\"${sceneName}\" type=\"scene\" duration=\"5\" ${locationBuff}\n                        <Player src=\"${nativeId}\" hDataSrc=\"${i_addContents.sceneData.scene_id}\"/>\n                    </page>\n                    `;\n        } else {\n\n            var resourceName = this.rp.getResourceRecord(i_addContents.resourceId).resource_name;\n            buff = `<Page page=\"${resourceName}\" type=\"resource\" duration=\"5\" ${locationBuff}\n                        <Player player=\"${i_addContents.blockCode}\">\n                            <Data>\n                                <Resource hResource=\"${i_addContents.resourceId}\"/>\n                            </Data>\n                        </Player>\n                    </page>`\n        }\n\n        // if default item, just add it. if location item, remember it and only add it once user select\n        // a location for it in google the map as we need to wait for the coordinates.\n\n        switch (this.m_pendingBlocAddition.type) {\n\n            case 'Fixed': {\n                jXML(xSnippetLocation).append(jXML(buff));\n                this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n                this.m_pendingBlocAddition = null;\n                break;\n            }\n            case 'GPS': {\n                this.m_pendingBlocAddition.content = i_addContents;\n                this.m_pendingBlocAddition.xmlSnippet = buff;\n                this._openMap();\n                break;\n            }\n        }\n\n    }\n\n    _removeLocation() {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        jXML(domPlayerData).find('GPS').children().eq(this.m_currentIndex).remove();\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        this._jumpToLocation('first');\n    }\n\n    /**\n     Populate the total map locations set\n     @method _populateTotalMapLocations\n     @param {Object} domPlayerData\n     **/\n    _populateTotalMapLocations() {\n        var domPlayerData = this.m_blockData.playerDataDom\n        this.m_totalLocations = jXML(domPlayerData).find('GPS').children().length;\n        if (this.m_totalLocations == 0) {\n            this.m_currentIndex = 0;\n        } else {\n            // jXML(Elements.LOCATION_SELECTED).show();\n        }\n        // jXML(Elements.TOTAL_MAP_LOCATIONS).text(total);\n    }\n\n    _openMap() {\n        var uiState: IUiState = {locationMap: {loadLocationMap: true}}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    /**\n     Select specific location and populate both the UI as well scroll map to coordinates\n     **/\n    _jumpToLocation(i_item?) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var total = jXML(domPlayerData).find('GPS').children().length;\n        var item;\n\n        if (total == 0) {\n            this._populateTotalMapLocations();\n            var uiState: IUiState = {locationMap: {locationMarkerSelected: null}}\n            this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n            return;\n        }\n        if (this.m_currentIndex > total - 1)\n            i_item = 'first';\n\n        switch (i_item) {\n            case 'first': {\n                this.m_currentIndex = 0;\n                item = jXML(domPlayerData).find('GPS').children().first();\n                break;\n            }\n            case 'last': {\n                this.m_currentIndex = total - 1;\n                item = jXML(domPlayerData).find('GPS').children().last();\n                break;\n            }\n            case 'next': {\n                if (this.m_currentIndex == (total - 1)) {\n                    item = jXML(domPlayerData).find('GPS').children().last();\n                } else {\n                    this.m_currentIndex++;\n                    item = jXML(domPlayerData).find('GPS').children().get(this.m_currentIndex);\n                }\n                break;\n            }\n            case 'prev': {\n                if (this.m_currentIndex == 0) {\n                    item = jXML(domPlayerData).find('GPS').children().first();\n                } else {\n                    this.m_currentIndex--;\n                    item = jXML(domPlayerData).find('GPS').children().get(this.m_currentIndex);\n                }\n                break;\n            }\n            default: {\n                item = jXML(domPlayerData).find('GPS').children().get(this.m_currentIndex);\n            }\n        }\n\n        this.m_radius = parseFloat(jXML(item).attr('radios'));\n        var lat = parseFloat(jXML(item).attr('lat'));\n        var lng = parseFloat(jXML(item).attr('lng'));\n        var duration = parseFloat(jXML(item).attr('duration'));\n\n        var marker: LocationMarkModel = new LocationMarkModel({\n            id: Math.random(),\n            lat: lat,\n            lng: lng,\n            radius: this.m_radius,\n            new: false,\n            label: '',\n            draggable: true\n        })\n\n        this.m_formInputs['label'].setValue(jXML(item).attr('page'));\n        this.m_formInputs['priority'].setValue(jXML(item).attr('priority'));\n        this.m_formInputs['lat'].setValue(lat);\n        this.m_formInputs['lng'].setValue(lng);\n        this.m_formInputs['duration'].setValue(duration);\n        this.m_formInputs['radius'].setValue(this.m_radius);\n\n        var uiState: IUiState = {locationMap: {locationMarkerSelected: marker}}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n\n        // this.m_addBlockLocationView.panToPoint(jXML(item).attr('lat'), jXML(item).attr('lng'));\n    }\n\n    _onDurationEdited(event: ISimpleGridEdit, index) {\n        var value = event.value;\n        if (!Lib.IsNumber(value)) return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Fixed').children().get(index);\n        jXML(item).attr('duration', value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onPageNameEdited(event: ISimpleGridEdit, index) {\n        var value = event.value;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Fixed').children().get(index);\n        jXML(item).attr('page', value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n\n    _populateTableCollection() {\n        this.m_collectionList = List([]);\n        var domPlayerData = this.m_blockData.playerDataDom as any\n        var rowIndex = 0;\n\n        jXML(domPlayerData).find('Fixed').children().each((k, page) => {\n            var resource_hResource, scene_hDataSrc;\n            var type = jXML(page).attr('type');\n            if (type == 'resource') {\n                resource_hResource = jXML(page).find('Resource').attr('hResource');\n            } else {\n                scene_hDataSrc = jXML(page).find('Player').attr('hDataSrc');\n            }\n            //con('populating ' + resource_hResource);\n\n            var storeModel = new StoreModel({\n                rowIndex: rowIndex,\n                checkbox: true,\n                name: jXML(page).attr('page'),\n                duration: jXML(page).attr('duration'),\n                type: type,\n                resource_hResource: resource_hResource,\n                scene_hDataSrc: scene_hDataSrc\n            });\n            this.m_collectionList = this.m_collectionList.push(storeModel);\n            rowIndex++;\n        });\n        this.m_collectionList = this._sortCollection(this.m_collectionList);\n    }\n\n    // /**\n    //  Load event list to block props UI\n    //  @method _populateTableEvents\n    //  **/\n    // _populateTableEvents() {\n    //     var data: Array<JsonEventResourceModel> = [], rowIndex = 0;\n    //     var domPlayerData = this.m_blockData.playerDataDom;\n    //     // self.m_collectionEventTable.bootstrapTable('removeAll');\n    //     jXML(domPlayerData).find('EventCommands').children().each(function (k, eventCommand) {\n    //         var pageName = '';\n    //         if (jXML(eventCommand).attr('command') == 'selectPage')\n    //             pageName = jXML(eventCommand).find('Page').attr('name');\n    //         var storeModel = new JsonEventResourceModel({\n    //                 rowIndex: rowIndex,\n    //                 checkbox: true,\n    //                 event: jXML(eventCommand).attr('from'),\n    //                 pageName: pageName,\n    //                 action: jXML(eventCommand).attr('command')\n    //             }\n    //         )\n    //         data.push(storeModel)\n    //         rowIndex++;\n    //     });\n    //     this.m_jsonEventResources = data;\n    // }\n\n    _sortCollection(i_collection: List<StoreModel>): List<StoreModel> {\n        var sorted = i_collection.sort((a, b) => {\n            if (a.getKey('rowIndex') > b.getKey('rowIndex'))\n                return 1;\n            if (a.getKey('rowIndex') < b.getKey('rowIndex'))\n                return -1;\n            return 0;\n        })\n        return sorted as List<StoreModel>;\n    }\n\n    _render() {\n        this.m_contGroup.reset();\n        this._populateTableCollection();\n        this._populateTotalMapLocations();\n        this._jumpToLocation();\n        this.cd.markForCheck();\n    }\n\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var total = jXML(domPlayerData).find('GPS').children().length;\n        if (total == 0)\n            return;\n        var item = jXML(domPlayerData).find('GPS').children().get(this.m_currentIndex);\n        jXML(item).attr('radios', this.m_contGroup.value.radius);\n        jXML(item).attr('page', this.m_contGroup.value.label);\n        jXML(item).attr('lat', this.m_contGroup.value.lat);\n        jXML(item).attr('lng', this.m_contGroup.value.lng);\n        jXML(item).attr('duration', this.m_contGroup.value.duration);\n        jXML(item).attr('priority', this.m_contGroup.value.priority);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n\n        // var xSnippet = jXML(domPlayerData).find('HTML');\n        // xSnippet.attr('src', this.m_contGroup.value.url);\n        // this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n\n"
  },
  {
    "path": "src/app/blocks/block-prop-mrss.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-mrss',\n    host: {'(input-blur)': 'saveToStore($event)'},\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <span i18n>maintain aspect ratio</span>\n                        <div class=\"material-switch pull-right\">\n                            <input #imageRatio (change)=\"_toggleAspectRatio(imageRatio.checked)\"\n                                   [formControl]=\"m_contGroup.controls['maintain']\"\n                                   class=\"default-prop-width\"\n                                   id=\"imageRatio\"\n                                   name=\"imageRatio\" type=\"checkbox\"/>\n                            <label for=\"imageRatio\" class=\"label-primary\"></label>\n                        </div>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <select #sceneSelection class=\"default-prop-width\" (change)=\"_onRssSelected($event)\" formControlName=\"rssSelection\">\n                            <option [value]=\"rss.url\" *ngFor=\"let rss of m_mrssLinksData\">{{rss.label}}</option>\n                        </select>\n                    </li>\n                    <li *ngIf=\"m_showCustomUrl\" class=\"list-group-item\">\n                        <input class=\"default-prop-width\" type=\"text\" formControlName=\"url\"/>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropMrss extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_showCustomUrl = false;\n    m_mrssLinksData = [];\n    m_mrssLinks = '<TextRss>' +\n        '<Rss label=\"CNN Showbiz\" url=\"http://rss.cnn.com/services/podcasting/ShowbizTonight/rss.xml\"/>' +\n        '<Rss label=\"CNN News \" url=\"http://rss.cnn.com/services/podcasting/cnnnewsroom/rss.xml\"/>' +\n        '<Rss label=\"CNN missed it \" url=\"http://rss.cnn.com/services/podcasting/incaseyoumissed/rss.xml\"/>' +\n        '<Rss label=\"CNN Latino \" url=\"http://rss.cnn.com/services/podcasting/inamerica/rss.xmll\"/>' +\n        '<Rss label=\"CNN Amanpour\" url=\"http://rss.cnn.com/services/podcasting/amanpour_video/rss\"/>' +\n        '<Rss label=\"CNN Student\" url=\"http://rss.cnn.com/services/podcasting/studentnews/rss.xml\"/>' +\n        '<Rss label=\"CNN King\" url=\"http://rss.cnn.com/services/podcasting/lkl/rss.xml\"/>' +\n        '<Rss label=\"CNN Meade\" url=\"http://rss.cnn.com/services/podcasting/robinmeade/rss.xml\"/>' +\n        '<Rss label=\"CNN Absurd\" url=\"http://rss.cnn.com/services/podcasting/absurd/rss.xml\"/>' +\n        '<Rss label=\"CNN Health\" url=\"http://rss.cnn.com/services/podcasting/gupta/rss.xml\"/>' +\n        '<Rss label=\"CNN Fareed\" url=\"http://rss.cnn.com/services/podcasting/fareedzakaria/rss.xml\"/>' +\n        '<Rss label=\"CNN Screening\" url=\"http://rss.cnn.com/services/podcasting/thescreeningroom/rss.xml\"/>' +\n        '<Rss label=\"CNN Politics\" url=\"http://rss.cnn.com/services/podcasting/bestpolitics/rss.xml\"/>' +\n        '<Rss label=\"ABC World News\" url=\"http://feeds.abcnews.com/abcnews/worldnewsvideopodcast\"/>' +\n        '<Rss label=\"ABC 20/20\" url=\"http://feeds.abcnews.com/abcnews/2020intouchvideopodcast\"/>' +\n        '<Rss label=\"ABC Medical Minute\" url=\"http://feeds.abcnews.com/abcnews/medicalminutevideoppodcast\"/>' +\n        '<Rss label=\"ABC Popcorn\" url=\"http://feeds.abcnews.com/abcnews/popcornvideopodcast\"/>' +\n        '<Rss label=\"ABC Buzz\" url=\"http://feeds.abcnews.com/abcnews/whatsthebuzzvideopodcast\"/>' +\n        '<Rss label=\"ABC Nightline\" url=\"http://feeds.abcnews.com/abcnews/nightlinevideopodcast\"/>' +\n        '<Rss label=\"ABC Health\" url=\"http://feeds.abcnews.com/abcnews/gmahealthvideopodcast\"/>' +\n        '<Rss label=\"ABC Money Minute\" url=\"http://feeds.abcnews.com/abcnews/moneyminutevideopodcast\"/>' +\n        '<Rss label=\"ABC Extreme\" url=\"http://feeds.abcnews.com/abcnews/extremevideopodcast\"/>' +\n        '<Rss label=\"ABC Top Line\" url=\"http://feeds.abcnews.com/abcnews/toplinevideopodcast\"/>' +\n        '<Rss label=\"ABC Curve\" url=\"http://feeds.abcnews.com/abcnews/aheadofthecurvevideopodcast\"/>' +\n        '<Rss label=\"ABC Interview\" url=\"http://feeds.abcnews.com/abcnews/blausteinreviewsvideopodcast\"/>' +\n        '<Rss label=\"NBC Press\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-MTP-NETCAST-M4V.xml\"/>' +\n        '<Rss label=\"NBC Nightly\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-NN-NETCAST-M4V.xml\"/>' +\n        '<Rss label=\"NBC Today\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-TDY-PODCAST-M4V.xml\"/>' +\n        '<Rss label=\"NBC Countdown\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-COUNTDOWN-NETCAST-M4V.xml\"/>' +\n        '<Rss label=\"NBC meadow\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-MADDOW-NETCAST-M4V.xml\"/>' +\n        '<Rss label=\"NBC Zeitgeist\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-MADDOW-NETCAST-M4V.xml\"/>' +\n        '<Rss label=\"NBC Business\" url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-YB-NETCAST-M4V.xml\"/>' +\n        '<Rss label=\"Discovery\" url=\"http://www.discovery.com/radio/xml/discovery_video.xml\"/>' +\n        '<Rss label=\"NOVA \" url=\"http://www.pbs.org/wgbh/nova/rss/nova-vodcast-pb.xml\"/>' +\n        '<Rss label=\"Link Tv\" url=\"http://www.linktv.org/rss/hq/globalpulse.xml\"/>' +\n        '<Rss label=\"Geek Brief\" url=\"http://geekbrief.podshow.com/feed.xml\"/>' +\n        '<Rss label=\"Dig Nation\" url=\"http://feeds.feedburner.com/diggnationvideo\"/>' +\n        '<Rss label=\"Tiki Bar\" url=\"http://feeds.feedburner.com/TikiBarTV\"/>' +\n        '<Rss label=\"Fox lips and ears\" url=\"http://video.foxnews.com/v/feed/playlist/86876.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox Hollyowood\" url=\"http://video.foxnews.com/v/feed/playlist/86878.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox showbiz\" url=\"http://video.foxnews.com/v/feed/playlist/86871.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox Us new\" url=\"http://video.foxnews.com/v/feed/playlist/86856.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox lates news\" url=\"http://video.foxnews.com/v/feed/playlist/87249.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox Business\" url=\"http://video.foxnews.com/v/feed/playlist/86927.xml?template=rss\"/>' +\n        '<Rss label=\"Fox world news\" url=\"http://video.foxnews.com/v/feed/playlist/86857.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox politics\" url=\"http://video.foxnews.com/v/feed/playlist/86858.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"Fox Health\" url=\"http://video.foxnews.com/v/feed/playlist/86859.xml?template=rss.xml?template=rss\"/>' +\n        '<Rss label=\"CBS Face The Nation\" url=\"http://feeds.cbsnews.com/podcast_nation_video_1\"/>' +\n        '<Rss label=\"CBS Evening News\" url=\"http://feeds.cbsnews.com/podcast_eveningnews_video_1\"/>' +\n        '<Rss label=\"TED TALKS\" url=\"http://feeds.feedburner.com/tedtalks_video\"/>' +\n        '<Rss label=\"CNET.COM Always On\" url=\"http://feeds.feedburner.com/AlwaysOnsd\"/>' +\n        '<Rss label=\"CNET.COM ApleByte\" url=\"http://feeds2.feedburner.com/cnet/applebyte\"/>' +\n        '<Rss label=\"CNET.COM  Cars\" url=\"http://feeds.feedburner.com/CnetOnCarssd\"/>' +\n        '<Rss label=\"CNET.COM  Crave \" url=\"http://feeds.feedburner.com/cnet/cravehq\"/>' +\n        '<Rss label=\"CNET.COM  UPDATE\" url=\"http://feeds.feedburner.com/CNETUpdateSD\"/>' +\n        '<Rss label=\"CNET.COM  News\" url=\"http://feeds.feedburner.com/cnet/news\"/>' +\n        '<Rss label=\"CNET.COM  CarTech\" url=\"http://feeds2.feedburner.com/cnet/cartechvideo\"/>' +\n        '<Rss label=\"CNET.COM  CrackingOpen\" url=\"http://feeds.feedburner.com/CrackingOpenSD\"/>' +\n        '<Rss label=\"CNET.COM  Conversations\" url=\"http://feeds.feedburner.com/cnet/conversations\"/>' +\n        '<Rss label=\"CNET.COM  Top5\" url=\"http://feeds2.feedburner.com/cnet/top5\"/>' +\n        '<Rss label=\"CNET.COM FirstLook\" url=\"http://feeds.feedburner.com/cnet/firstlook\"/>' +\n        '<Rss label=\"CNET.COM  InsideScoop\" url=\"http://feeds.feedburner.com/InsideScoopsd\"/>' +\n        '<Rss label=\"CNET.COM 404\" url=\"http://feeds.feedburner.com/cnet/the404video\"/>' +\n        '<Rss label=\"CNET.COM HowTo\" url=\"http://feeds2.feedburner.com/cnet/howto\"/>' +\n        '<Rss label=\"CNET.COM  PrizeFight\" url=\"http://feeds2.feedburner.com/cnet/prizefight\"/>' +\n        '<Rss label=\"CNET.COM  RumorHasIt\" url=\"http://feeds.feedburner.com/RumorHasItsd\"/>' +\n        '<Rss label=\"CNET.COM  TapThatApp\" url=\"http://feeds.feedburner.com/cnet/tapthatapp\"/>' +\n        '<Rss label=\"LINKTV  EartFocus\" url=\"http://www.linktv.org/rss/general/earth.xml\"/>' +\n        '<Rss label=\"LINKTV  Explore\" url=\"http://www.linktv.org/rss/general/explorespecial1.xml\"/>' +\n        '<Rss label=\"LINKTV  GlobalPulse\" url=\"http://www.linktv.org/rss/general/globalpulse.xml\"/>' +\n        '<Rss label=\"LINKTV  LatinPulse\" url=\"http://www.linktv.org/rss/general/latin_pulse.xml\"/>' +\n        '<Rss label=\"LINKTV  MosaicIR\" url=\"http://www.linktv.org/rss/general/MIR.xml\"/>' +\n        '<Rss label=\"LINKTV MosaicNews\" url=\"http://www.linktv.org/rss/general/mosaic.xml\"/>' +\n        '<Rss label=\"LINKTV  Best\" url=\"http://www.linktv.org/rss/general/best.xml\"/>' +\n        '<Rss label=\"NOVA Video\" url=\"http://feeds.pbs.org/pbs/wgbh/nova-video\"/>' +\n        '<Rss label=\"Washington Post Video\" url=\"http://www.washingtonpost.com/wp-srv/mmedia/vipod.xml\"/>' +\n        '<Rss label=\"CBC  TheNational\" url=\"http://www.cbc.ca/podcasting/includes/thenational-video-podcast.xml\"/>' +\n        '<Rss label=\"CBC  AtIssue\" url=\"http://www.cbc.ca/mediafeeds/rss/cbc/atissue-video-podcast.xml\"/>' +\n        '<Rss label=\"CBC  Rex Murphy\" url=\"http://www.cbc.ca/mediafeeds/rss/cbc/rexmurphy-video-podcast.xml\"/>' +\n        '<Rss label=\"IMORE Show\" url=\"http://feeds.feedburner.com/iphonelivevideo\"/>' +\n        '<Rss label=\"IMORE  MobileNations\" url=\"http://feeds.feedburner.com/mobilenationsvideo\"/>' +\n        '<Rss label=\"IMORE  AndroidCentral\" url=\"http://feeds.feedburner.com/androidcentralvideo\"/>' +\n        '<Rss label=\"IMORE  ZenAndTech\" url=\"http://feeds.feedburner.com/zenandtechvideo\"/>' +\n        '<Rss label=\"REUTERS  Financial\" url=\"http://feeds.reuters.com/reuters/video/companyus/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  BrakingNews\" url=\"http://feeds.reuters.com/reuters/video/breakingviews/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  Chrystia Freeland\" url=\"http://feeds.reuters.com/reuters/video/chrystiafreeland/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  Entertainment\" url=\"http://feeds.reuters.com/reuters/video/entertainment/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  Felix Salmon\" url=\"http://feeds.reuters.com/reuters/video/felixsalmon/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  Newsmaker\" url=\"http://feeds.reuters.com/reuters/video/newsmakerus/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  Odly Enough\" url=\"http://feeds.reuters.com/reuters/video/andfinally/rss/m4v/\"/>' +\n        '<Rss label=\"REUTERS  PersonalFinance\" url=\"http://feeds.reuters.com/reuters/video/personalfinance/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  Technology\" url=\"http://feeds.reuters.com/reuters/video/technology/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  QuickCut\" url=\"http://feeds.reuters.com/reuters/video/quickcut/rss/mp4/\"/>' +\n        '<Rss label=\"REUTERS  TopNews\" url=\"http://feeds.reuters.com/reuters/USVideoTopNews\"/>' +\n        '<Rss label=\"REUTERS  Politics\" url=\"http://feeds.reuters.com/reuters/USVideoPolitics\"/>' +\n        '<Rss label=\"REUTERS  Rough Cuts\" url=\"http://feeds.reuters.com/reuters/USVideoRoughCuts\"/>' +\n        '<Rss label=\"REUTERS  World News\" url=\"http://feeds.reuters.com/reuters/USVideoWorldNews\"/>' +\n        '<Rss label=\"REUTERS  Small Business\" url=\"http://feeds.reuters.com/reuters/USVideoSmallBusiness\"/>' +\n        '<Rss label=\"REUTERS  GigaOM\" url=\"http://feeds.reuters.com/reuters/USVideoGigaom\"/>' +\n        '<Rss label=\"REUTERS  Envinroment\" url=\"http://feeds.reuters.com/reuters/USVideoEnvironment\"/>' +\n        '<Rss label=\"REUTERS  Latest Video\" url=\"http://feeds.reuters.com/reuters/USVideoLatest\"/>' +\n        '<Rss label=\"AL JAZEERA  World\" url=\"http://feeds.aljazeera.net/podcasts/aljazeeraworld\"/>' +\n        '<Rss label=\"AL JAZEERA  Correspondent\" url=\"http://feeds.aljazeera.net/podcasts/aljazeeracorrespondent\"/>' +\n        '<Rss label=\"AL JAZEERA  Indian Hospital\" url=\"http://feeds.aljazeera.net/podcasts/indianhospital\"/>' +\n        '<Rss label=\"AL JAZEERA  The Cure\" url=\"http://feeds.aljazeera.net/podcasts/thecure\"/>' +\n        '<Rss label=\"AL JAZEERA LivingTheLanguage\" url=\"http://feeds.aljazeera.net/podcasts/livingthelanguage\"/>' +\n        '<Rss label=\"AL JAZEERA  Slavery\" url=\"http://feeds.aljazeera.net/podcasts/slavery\"/>' +\n        '<Rss label=\"AL JAZEERA Africa Investigates\" url=\"http://feeds.aljazeera.net/podcasts/africainvestigates\"/>' +\n        '<Rss label=\"AL JAZEERA  Artscape\" url=\"http://feeds.aljazeera.net/podcasts/artscape\"/>' +\n        '<Rss label=\"AL JAZEERA  Earthrise\" url=\"http://feeds.aljazeera.net/podcasts/earthrise\"/>' +\n        '<Rss label=\"AL JAZEERA  Faultlines\" url=\"http://feeds.aljazeera.net/podcasts/faultlines\"/>' +\n        '<Rss label=\"AL JAZEERA  Documentaries\" url=\"http://feeds.aljazeera.net/podcasts/featureddocumentaries\"/>' +\n        '<Rss label=\"AL JAZEERA  PeopleAndPower\" url=\"http://feeds.aljazeera.net/podcasts/peopleandpower\"/>' +\n        '<Rss label=\"AL JAZEERA  TheStream\" url=\"http://feeds.aljazeera.net/podcasts/thestream\"/>' +\n        '<Rss label=\"AL JAZEERA  SurprisingEurope\" url=\"http://feeds.aljazeera.net/podcasts/surprisingeurope\"/>' +\n        '<Rss label=\"AL JAZEERA  Activate\" url=\"http://feeds.aljazeera.net/podcasts/activate\"/>' +\n        '<Rss label=\"NASA  Vodcast\" url=\"http://www.nasa.gov/rss/dyn/NASAcast_vodcast.rss\"/>' +\n        '<Rss label=\"DEMOCRACY NOW\" url=\"http://www.democracynow.org/podcast-video.xml\"/>' +\n        '<Rss label=\"KQED  Check Please\" url=\"http://www.kqed.org/rss/checkplease.xml\"/>' +\n        '<Rss label=\"KQED  Quest Video\" url=\"http://www.kqed.org/rss/questvideo.xml\"/>' +\n        '<Rss label=\"KQED  Science On Spot\" url=\"http://www.kqed.org/rss/quest_sots_HD.xml\"/>' +\n        '<Rss label=\"KQED This Week\" url=\"http://feeds.feedburner.com/kqedthisweek\"/>' +\n        '<Rss label=\"KQED  TrueCaShorts\" url=\"http://feeds.feedburner.com/KqedTrulyCaShorts\"/>' +\n        '<Rss label=\"CFR Podcasts\" url=\"http://feeds.cfr.org/publication/video\"/>' +\n        '<Rss label=\"DOCTOR FLOYD\" url=\"http://www.doctorfloyd.com/video/rss.xml\"/>' +\n        '<Rss label=\"ESRI  Events\" url=\"http://feeds.feedburner.com/EsriVideo-Eventssmall\"/>' +\n        '<Rss label=\"ESRI  People\" url=\"http://feeds.feedburner.com/EsriVideo-Peoplesmall\"/>' +\n        '<Rss label=\"ESRI  Products\" url=\"http://feeds.feedburner.com/EsriVideo-Productssmall\"/>' +\n        '<Rss label=\"KCM\" url=\"http://www.kcm.org/feed/en/itunes/webcast/video\"/>' +\n        '<Rss label=\"EURONEWS  NoComment\" url=\"http://feeds.feedburner.com/euronews/en/Euronews-NoComment/\"/>' +\n        '<Rss label=\"DIVEFILM  Diving Films\" url=\"http://divefilm.com/podcasts/podcast.xml\"/>' +\n        '<Rss label=\"CARNEGIE COUNCIL\" url=\"http://www.carnegiecouncil.org/resources/video/rss/feed.xml\"/>' +\n        '<Rss label=\"AMAZINGFACTS Presents\" url=\"http://feeds.feedburner.com/AmazingFactsPresents\"/>' +\n        '<Rss label=\"CSH\" url=\"http://feeds.feedburner.com/CSHVideo\"/>' +\n        '<Rss label=\"CALIFORNIA ACADEMY\" url=\"http://www.calacademy.org/rss/feed/?id=2\"/>' +\n        '<Rss label=\"TIMES OF INDIA 1\" url=\"http://timesofindia.feedsportal.com/c/33039/f/534004/index.rss\"/>' +\n        '<Rss label=\"AMEINFO.COM Latest\" url=\"http://www.ameinfo.com/rss/ame_video_mp4.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Industry\" url=\"http://www.ameinfo.com/rss/italk_mp4.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Aviation\" url=\"http://www.ameinfo.com/rssfeeds/11168.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Business\" url=\"http://www.ameinfo.com/rssfeeds/3191.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Conferences\" url=\"http://www.ameinfo.com/rssfeeds/3187.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Face to Face\" url=\"http://www.ameinfo.com/rssfeeds/9992.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Gitex\" url=\"http://www.ameinfo.com/rssfeeds/10587.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM IT, Internet, and Telcos\" url=\"http://www.ameinfo.com/rssfeeds/3184.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Luxury\" url=\"http://www.ameinfo.com/rssfeeds/9617.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Media, PR, Advertisement\" url=\"http://www.ameinfo.com/rssfeeds/3974.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Mobile, Electronics\" url=\"http://www.ameinfo.com/rssfeeds/3185.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Test Drive\" url=\"http://www.ameinfo.com/rssfeeds/3289.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Property Report\" url=\"http://www.ameinfo.com/rssfeeds/3188.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Retail\" url=\"http://www.ameinfo.com/rssfeeds/3190.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM Technology\" url=\"http://www.ameinfo.com/rssfeeds/10660.xml\"/>' +\n        '<Rss label=\"AMEINFO.COM  Travel\" url=\"http://www.ameinfo.com/rssfeeds/3183.xml\"/>' +\n        '<Rss label=\"CATEGORY 5\" url=\"http://rss.cat5.tv/sd\"/>' +\n        '<Rss label=\"1 UP Show\" url=\"http://feeds.feedburner.com/1UP/1upShow\"/>' +\n        '<Rss label=\"1 UP Broken Pixels\" url=\"http://www.1up.com/flat/Podcasts/brokenpixels.xml\"/>' +\n        '<Rss label=\"I UP Espn\" url=\"http://www.1up.com/flat/Podcasts/espn.xml\"/>' +\n        '<Rss label=\"1UP Retro\" url=\"http://www.1up.com/flat/Podcasts/retrobonusstage.xml\"/>' +\n        '<Rss label=\"64MM - Skateboarding\" url=\"http://feeds.feedburner.com/64mmVlog\"/>' +\n        '<Rss label=\"FEM - Blogs\" url=\"http://feeds.feedburner.com/FEMvideoblogs\"/>' +\n        '<Rss label=\"Bringing Disneyland Home\" url=\"http://www.oakfan.com/BDHVodcast.xml\"/>' +\n        '<Rss label=\"Ricky Gervais\" url=\"http://podcast.rickygervais.com/podcast.xml\"/>' +\n        '<Rss label=\"Terra Videos\" url=\"http://feeds.feedburner.com/Terravideos\"/>' +\n        '<Rss label=\"PLAYHOUSE TV\" url=\"http://playhousetv.podomatic.com/rss2.xml\"/>' +\n        '<Rss label=\"DLTV\" url=\"http://feeds2.feedburner.com/ziffdavis/dltvipodpspvideo\"/>' +\n        '<Rss label=\"ADOBE CREATIVE SUITE \" url=\"http://creativesuitepodcast.com/rss\"/>' +\n        '<Rss label=\"COMMAND N\" url=\"http://feeds.feedburner.com/commandN_pod\"/>' +\n        '<Rss label=\"GEEK BRIEF TV\" url=\"http://geekbrief.podshow.com/feed.xml\"/>' +\n        '<Rss label=\"One Minute Tip (Photoshop)\" url=\"http://www.newmediamanuals.com/podcast/ivideos/video.xml\"/>' +\n        '<Rss label=\"PHOTOSHOP TV\" url=\"http://feeds.feedburner.com/photoshoptv\"/>' +\n        '<Rss label=\"LDS.ORH   Mormon Church \" url=\"http://feeds.lds.org/cesfiresidesvideo\"/>' +\n        '<Rss label=\"LDS.ORH   Conferences\" url=\"http://feeds.lds.org/lds-general-conference-sd-eng\"/>' +\n        '<Rss label=\"UCL London\" url=\"http://itunes.ucl.ac.uk/rss-feeds/introducing/provost/rss\"/>' +\n        '<Rss label=\"UCL News\" url=\"http://itunes.ucl.ac.uk/rss-feeds/news/news4/rss\"/>' +\n        '<Rss label=\"UCL Fine arts\" url=\"http://itunes.ucl.ac.uk/rss-feeds/news/news5/rss\"/>' +\n        '<Rss label=\"UCL Torture Team\" url=\"http://itunes.ucl.ac.uk/rss-feeds/news/news6/rss\"/>' +\n        '<Rss label=\"UCL Donor Reception\" url=\"http://itunes.ucl.ac.uk/rss-feeds/news/news7/rss\"/>' +\n        '<Rss label=\"UCL Research\" url=\"http://itunes.ucl.ac.uk/rss-feeds/research/price/rss\"/>' +\n        '<Rss label=\"UCL Research China\" url=\"http://itunes.ucl.ac.uk/rss-feeds/research/boxing/rss\"/>' +\n        '<Rss label=\"UCL Health\" url=\"http://itunes.ucl.ac.uk/rss-feeds/global-health/governance/rss\"/>' +\n        '<Rss label=\"VH1 BestWeek\" url=\"http://feeds.feedburner.com/vh1_bestweekever\"/>' +\n        '<Rss label=\"VH1 BestOf\" url=\"http://feeds.feedburner.com/vh1_bestof\"/>' +\n        '<Rss label=\"VH1 Celebreality\" url=\"http://feeds.feedburner.com/vh1_celebreality\"/>' +\n        '<Rss label=\"VH1 FlavorOfLove\" url=\"http://feeds.feedburner.com/vh1_flavoroflove\"/>' +\n        '<Rss label=\"TWIT TV\" url=\"http://feeds.twit.tv/twit_video_large\"/>' +\n        '<Rss label=\"NBC MONTANA\" url=\"http://www.nbcmontana.com/-/14594424/15193836/-/format/rss_2.0/view/asFeed/-/7ht7wl/-/index.xml\"/>' +\n        '<Rss label=\"ItunesPoadcast Tutorial\" url=\"http://www.feedforall.com/rss-video-tutorials.xml\"/>' +\n        '<Rss label=\"BEST OF YOUTUBE\" url=\"http://mevio.com/feeds/bestofyoutube.xml\"/>' +\n        '<Rss label=\"Custom\" url=\"\"/>' +\n        '</TextRss>'\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'url': ['', [Validators.pattern(urlRegExp)]],\n            'rssSelection': [],\n            'maintain': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n        var links = jXML(jXML.parseXML(this.m_mrssLinks)).find('Rss');\n        _.forEach(links, (k, v) => {\n            this.m_mrssLinksData.push({\n                url: jXML(k).attr('url'),\n                label: jXML(k).attr('label')\n            })\n        });\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    @Input() external: boolean = false;\n\n    /**\n     Toggle maintain aspect ratio\n     **/\n    _toggleAspectRatio(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Rss');\n        jXML(xSnippet).attr('maintainAspectRatio', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _isUrlCustom(i_url): boolean {\n        var feed = this.m_mrssLinksData.find(o => o.url == i_url);\n        if (feed && feed.label == 'Custom') return true;\n        if (feed) return false;\n        return true;\n    }\n\n    _onRssSelected(event) {\n        this.m_showCustomUrl = this._isUrlCustom(event.target.value);\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var xSnippet = jXML(domPlayerData).find('Rss');\n        var url = xSnippet.attr('url');\n        var maintain = StringJS(jXML(xSnippet).attr('maintainAspectRatio')).booleanToNumber();\n        this.m_formInputs['maintain'].setValue(maintain);\n\n        if (this._isUrlCustom(url)) {\n            this.m_showCustomUrl = true;\n            this.m_formInputs['rssSelection'].setValue('');\n            this.m_formInputs['url'].setValue(url);\n        } else {\n            this.m_showCustomUrl = false;\n            this.m_formInputs['rssSelection'].setValue(url);\n        }\n        this.cd.markForCheck();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    private saveToStore() {\n        // con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Rss');\n        if (this.m_contGroup.value.rssSelection == ''){\n            jXML(xSnippet).attr('url', this.m_contGroup.value.url);\n        } else {\n            jXML(xSnippet).attr('url', this.m_contGroup.value.rssSelection);\n        }\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/blocks/block-prop-position.ts",
    "content": "import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport * as _ from \"lodash\";\nimport {BlockService, IBlockData, ISceneData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {BlockLabels} from \"../../interfaces/Consts\";\n\n@Component({\n    selector: 'block-prop-position',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n\n        \n\n        li {\n            padding-top: 3px;\n            padding-bottom: 3px;\n        }\n\n        form {\n            padding: 20px;\n        }\n\n        .inliner {\n            display: inline-block;\n            width: 60px;\n        }\n\n        input.ng-invalid {\n            border-right: 10px solid red;\n        }\n\n        .material-switch {\n            position: relative;\n            padding-top: 10px;\n        }\n\n        .input-group {\n            padding-top: 10px;\n        }\n\n        i {\n            width: 20px;\n        }\n    `],\n    template: `\n        <div>\n            <form novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n                <div class=\"row\">\n                    <div class=\"inner userGeneral\">\n                        <div class=\"row\">\n                            <div class=\"inner userGeneral\">\n                                <ul class=\"list-group\">\n                                    <li *ngIf=\"!m_blockIsScene\" class=\"list-group-item\">\n                                        <span i18n class=\"inliner\">top</span>\n                                        <input type=\"number\" class=\"numStepper inliner\" formControlName=\"pixel_y\">\n                                    </li>\n                                    <li *ngIf=\"!m_blockIsScene\" class=\"list-group-item\">\n                                        <span i18n class=\"inliner\">left</span>\n                                        <input type=\"number\" class=\"numStepper inliner\" formControlName=\"pixel_x\">\n                                    </li>\n                                    <li class=\"list-group-item\">\n                                        <span i18n class=\"inliner\">width</span>\n                                        <input type=\"number\" type=\"number\" min=\"50\" max=\"4096\" class=\"numStepper inliner\" formControlName=\"pixel_width\">\n                                    </li>\n                                    <li class=\"list-group-item\">\n                                        <span i18n class=\"inliner\">height</span>\n                                        <input type=\"number\" min=\"50\" max=\"4096\" class=\"numStepper inliner\" formControlName=\"pixel_height\">\n                                    </li>\n                                    <li *ngIf=\"!m_blockIsScene\" class=\"list-group-item\">\n                                        <span i18n class=\"inliner\">rotation</span>\n                                        <input type=\"number\" min=\"0\" max=\"360\" class=\"numStepper inliner\" formControlName=\"rotation\">\n                                    </li>\n                                    <li class=\"list-group-item\">\n                                        <button i18n type=\"button\" style=\"width: 125px\" class=\"btn btn-secondary btn-sm\" (click)=\"saveToStoreLayout()\">apply changes</button>\n                                    </li>\n                                    <hr/>\n                                    <li *ngIf=\"!m_blockIsScene\" class=\"list-group-item\">\n                                        <br/>\n                                        <span i18n>locked</span>\n                                        <div class=\"material-switch pull-right\">\n                                            <input (change)=\"saveToStoreLock(locked.checked)\"\n                                                   formControlName=\"locked\"\n                                                   id=\"locked\" #locked\n                                                   name=\"locked\" type=\"checkbox\"/>\n                                            <label for=\"locked\" class=\"label-primary\"></label>\n                                        </div>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n\n               \n            </form>\n        </div>\n    `\n})\nexport class BlockPropPosition extends Compbaser {\n\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_canvasScale = -1;\n    m_blockIsScene = false;\n\n    constructor(private fb: FormBuilder, private rp: RedPepperService, private yp: YellowPepperService, private bs: BlockService, private cd: ChangeDetectorRef) {\n        super();\n\n        this.m_contGroup = fb.group({\n            'pixel_y': [0],\n            'pixel_x': [0],\n            'pixel_width': [0],\n            'pixel_height': [0],\n            'rotation': [0],\n            'locked': [],\n            'x1_check':  [{value: '', disabled: true}],\n            'x2_check':  [{value: '', disabled: true}],\n            'x3_check': [{value: '', disabled: true}],\n            'y1_check': [{value: '', disabled: true}],\n            'y2_check': [{value: '', disabled: true}],\n            'y3_check': [{value: '', disabled: true}],\n            'x1_text': [{value: '', disabled: true}],\n            'x2_text': [{value: '', disabled: true}],\n            'x3_text': [{value: '', disabled: true}],\n            'y1_text': [{value: '', disabled: true}],\n            'y2_text': [{value: '', disabled: true}],\n            'y3_text': [{value: '', disabled: true}]\n        });\n\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n\n        // this.m_formInputs['x1_check'].disable();\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenSceneOrBlockSelectedChanged()\n                .combineLatest(this.yp.listenFabricSceneScaled(), (i_sceneData: ISceneData, i_scale: number) => {\n                    this.m_canvasScale = i_scale;\n                    return i_sceneData\n                })\n                .mergeMap((i_sceneData: ISceneData) => {\n                    return this.bs.getBlockDataInScene(i_sceneData)\n                })\n                .subscribe((blockData: IBlockData) => {\n                    this.m_blockIsScene = parseInt(blockData.blockCode) == BlockLabels.BLOCKCODE_SCENE ? true : false;\n                    this.m_blockData = blockData;\n                    this.m_formInputs['locked'].setValue(StringJS(blockData.playerDataJson.Player._locked).booleanToNumber());\n                    this.m_formInputs['rotation'].setValue(blockData.playerDataJson.Player.Data.Layout._rotation);\n                    this.m_formInputs['pixel_height'].setValue(blockData.playerDataJson.Player.Data.Layout._height);\n                    this.m_formInputs['pixel_width'].setValue(blockData.playerDataJson.Player.Data.Layout._width);\n                    this.m_formInputs['pixel_x'].setValue(blockData.playerDataJson.Player.Data.Layout._x);\n                    this.m_formInputs['pixel_y'].setValue(blockData.playerDataJson.Player.Data.Layout._y);\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n    }\n\n    ngAfterViewInit() {\n        // this.cancelOnDestroy(\n        //     this.m_contGroup.valueChanges\n        //         .map(v => {\n        //             for (var z in v)\n        //                 v[z] = parseInt(v[z])\n        //             return v;\n        //         })\n        //         .filter(v => !_.some(v, (o) => _.isNaN(o)))\n        //         .startWith({})\n        //         .pairwise()\n        //         .filter(v => !_.isEqual(v[0], v[1]))\n        //         .debounceTime(1000)\n        //         .subscribe((v) => {\n        //             this.saveToStoreLayout();\n        //         }, (e) => console.error(e)) //cancelOnDestroy please\n        // )\n    }\n\n    saveToStoreLayout() {\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var x = this.m_contGroup.value.pixel_x;\n        var y = this.m_contGroup.value.pixel_y;\n        var w = this.m_contGroup.value.pixel_width;\n        var h = this.m_contGroup.value.pixel_height;\n        var r = this.m_contGroup.value.rotation;\n        var blockMinWidth = 50;\n        var blockMinHeight = 50;\n        if (h < blockMinHeight)\n            h = blockMinHeight;\n        if (w < blockMinWidth)\n            w = blockMinWidth;\n\n        if (this.m_blockIsScene) {\n            $(domPlayerData).find('Layout').eq(0).attr('width', w);\n            $(domPlayerData).find('Layout').eq(0).attr('height', h);\n            this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n            this.bs.notifyReloadScene(this.m_blockData.scene.handle);\n\n        } else {\n\n            var layout = $(domPlayerData).find('Layout');\n            layout.attr('rotation', parseInt(r));\n            layout.attr('x', parseInt(x));\n            layout.attr('y', parseInt(y));\n            layout.attr('width', parseInt(w));\n            layout.attr('height', parseInt(h));\n            this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n            this.bs.notifySceneBlockChanged(this.m_blockData);\n        }\n    }\n\n    @timeout(250)\n    private saveToStoreLock(v) {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var r = v == true ? 1 : 0;\n        jXML(domPlayerData).find('Player').attr('locked', r);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n        this.bs.notifySceneBlockChanged(this.m_blockData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-qr.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-qr',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <span i18n>QR code</span><br/>\n                        <input class=\"default-prop-width\" type=\"text\" [formControl]=\"m_contGroup.controls['text']\"/>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropQR extends Compbaser implements AfterViewInit {\n\n    private formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private bs: BlockService) {\n        super();\n        this.m_contGroup = fb.group({\n            'text': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xSnippet = jXML(domPlayerData).find('Text');\n        this.formInputs['text'].setValue(xSnippet.text());\n    }\n\n    private saveToStore() {\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Text');\n        jXML(xSnippet).text(this.m_contGroup.value.text);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-rss.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {Lib, urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\nimport {IFontSelector} from \"../../comps/font-selector/font-selector\";\n\n@Component({\n    selector: 'block-prop-rss',\n    host: {'(input-blur)': 'saveToStore($event)'},\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <select #sceneSelection class=\"default-prop-width\" (change)=\"_onRssSelected($event)\" formControlName=\"rssSelection\">\n                            <option [value]=\"rss.url\" *ngFor=\"let rss of m_mrssLinksData\">{{rss.label}}</option>\n                        </select>\n                    </li>\n                    <li *ngIf=\"m_showCustomUrl\" class=\"list-group-item\">\n                        <input class=\"default-prop-width\" type=\"text\" formControlName=\"url\"/>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <label i18n>RSS refresh (minutes)</label><br/>\n                        <input class=\"default-prop-width\" type=\"number\" min=\"1\" [formControl]=\"m_contGroup.controls['minRefreshTime']\"/>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <label i18n>RSS scroll direction</label>\n                        <br/>\n                        <input type=\"radio\" value=\"0\" name=\"vertical\" formControlName=\"vertical\">\n                        <span i18n>Horizontal</span>\n                        <br/>\n                        <input type=\"radio\" value=\"1\" name=\"vertical\" formControlName=\"vertical\">\n                        <span i18n>Vertical</span>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <label i18n>RSS scroll speed</label>\n                        <br/>\n                        <input type=\"radio\" value=\"20\" name=\"speed\" formControlName=\"speed\">\n                        <span i18n>slow</span>\n                        <br/>\n                        <input type=\"radio\" value=\"50\" name=\"speed\" formControlName=\"speed\">\n                        <span i18n>medium</span>\n                        <br/>\n                        <input type=\"radio\" value=\"100\" name=\"speed\" formControlName=\"speed\">\n                        <span i18n>fast</span>\n                    </li>\n                    \n                </ul>\n            </div>\n            <font-selector (onChange)=\"_onFontChanged($event)\" [setConfig]=\"m_fontConfig\"></font-selector>\n        </form>\n    `\n})\nexport class BlockPropRss extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_fontConfig: IFontSelector;\n    m_blockData: IBlockData;\n    m_showCustomUrl = false;\n    m_mrssLinksData = [];\n    m_mrssLinks = '<TextRss>' +\n        '<Rss label=\"Top Stories\" url=\"http://rss.news.yahoo.com/rss/topstories\"/>' +\n        '<Rss label=\"U.S. National\" url=\"http://rss.news.yahoo.com/rss/us\"/>' +\n        '<Rss label=\"Elections\" url=\"http://rss.news.yahoo.com/rss/elections\"/>' +\n        '<Rss label=\"Terrorism\" url=\"http://rss.news.yahoo.com/rss/terrorism\"/>' +\n        '<Rss label=\"World\" url=\"http://rss.news.yahoo.com/rss/world\"/>' +\n        '<Rss label=\"Mideast Conflict\" url=\"http://rss.news.yahoo.com/rss/mideast\"/>' +\n        '<Rss label=\"Iraq\" url=\"http://rss.news.yahoo.com/rss/iraq\"/>' +\n        '<Rss label=\"Politics\" url=\"http://rss.news.yahoo.com/rss/politics\"/>' +\n        '<Rss label=\"Business\" url=\"http://rss.news.yahoo.com/rss/business\"/>' +\n        '<Rss label=\"Technology\" url=\"http://rss.news.yahoo.com/rss/tech\"/>' +\n        '<Rss label=\"Sports\" url=\"http://rss.news.yahoo.com/rss/sports\"/>' +\n        '<Rss label=\"Entertainment\" url=\"http://rss.news.yahoo.com/rss/entertainment\"/>' +\n        '<Rss label=\"Health\" url=\"http://rss.news.yahoo.com/rss/health\"/>' +\n        '<Rss label=\"Odd News\" url=\"http://rss.news.yahoo.com/rss/oddlyenough\"/>' +\n        '<Rss label=\"Science\" url=\"http://rss.news.yahoo.com/rss/science\"/>' +\n        '<Rss label=\"Opinion/Editorial\" url=\"http://rss.news.yahoo.com/rss/oped\"/>' +\n        '<Rss label=\"Obituaries\" url=\"http://rss.news.yahoo.com/rss/obits\"/>' +\n        '<Rss label=\"Most Emailed\" url=\"http://rss.news.yahoo.com/rss/mostemailed\"/>' +\n        '<Rss label=\"Most Viewed\" url=\"http://rss.news.yahoo.com/rss/mostviewed\"/>' +\n        '<Rss label=\"Most Recommended\" url=\"http://rss.news.yahoo.com/rss/highestrated\"/>' +\n        '<Rss label=\"Custom\" url=\"\"/>' +\n        '</TextRss>'\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'url': ['', [Validators.pattern(urlRegExp)]],\n            'minRefreshTime': [1],\n            'vertical': [0],\n            'speed': [50],\n            'rssSelection': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n        var links = jXML(jXML.parseXML(this.m_mrssLinks)).find('Rss');\n        _.forEach(links, (k, v) => {\n            this.m_mrssLinksData.push({\n                url: jXML(k).attr('url'),\n                label: jXML(k).attr('label')\n            })\n        });\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    @Input() external: boolean = false;\n\n    _isUrlCustom(i_url): boolean {\n        var feed = this.m_mrssLinksData.find(o => o.url == i_url);\n        if (feed && feed.label == 'Custom') return true;\n        if (feed) return false;\n        return true;\n    }\n\n    _onRssSelected(event) {\n        this.m_showCustomUrl = this._isUrlCustom(event.target.value);\n    }\n\n    _onFontChanged(config: IFontSelector) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Rss');\n        var xSnippetFont = jXML(xSnippet).find('Font').eq(0);\n        config.bold == true ? xSnippetFont.attr('fontWeight', 'bold') : xSnippetFont.attr('fontWeight', 'normal');\n        config.italic == true ? xSnippetFont.attr('fontStyle', 'italic') : xSnippetFont.attr('fontStyle', 'normal');\n        config.underline == true ? xSnippetFont.attr('textDecoration', 'underline') : xSnippetFont.attr('textDecoration', 'none');\n        xSnippetFont.attr('fontColor', Lib.ColorToDecimal(config.color));\n        xSnippetFont.attr('fontSize', config.size);\n        xSnippetFont.attr('fontFamily', config.font);\n        xSnippetFont.attr('textAlign', config.alignment);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var xSnippet = jXML(domPlayerData).find('Rss');\n        var xSnippetFont = jXML(xSnippet).find('Font').eq(0);\n        var url = xSnippet.attr('url');\n        var vertical = jXML(xSnippet).attr('vertical');\n        var minRefreshTime = jXML(xSnippet).attr('minRefreshTime')\n        var speed = jXML(xSnippet).attr('speed')\n\n        if (this._isUrlCustom(url)) {\n            this.m_showCustomUrl = true;\n            this.m_formInputs['rssSelection'].setValue('');\n            this.m_formInputs['url'].setValue(url);\n        } else {\n            this.m_showCustomUrl = false;\n            this.m_formInputs['rssSelection'].setValue(url);\n        }\n        this.m_formInputs['minRefreshTime'].setValue(minRefreshTime);\n        this.m_formInputs['speed'].setValue(speed);\n        this.m_formInputs['vertical'].setValue(vertical);\n\n        this.m_fontConfig = {\n            size: Number(xSnippetFont.attr('fontSize')),\n            alignment: <any>xSnippetFont.attr('textAlign'),\n            bold: xSnippetFont.attr('fontWeight') == 'bold' ? true : false,\n            italic: xSnippetFont.attr('fontStyle') == 'italic' ? true : false,\n            font: xSnippetFont.attr('fontFamily'),\n            underline: xSnippetFont.attr('textDecoration') == 'underline' ? true : false,\n            color: Lib.ColorToHex(Lib.DecimalToHex(xSnippetFont.attr('fontColor'))),\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    private saveToStore() {\n        // con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('Rss');\n        if (this.m_contGroup.value.rssSelection == ''){\n            jXML(xSnippet).attr('url', this.m_contGroup.value.url);\n        } else {\n            jXML(xSnippet).attr('url', this.m_contGroup.value.rssSelection);\n        }\n        jXML(xSnippet).attr('minRefreshTime', this.m_contGroup.value.minRefreshTime);\n        jXML(xSnippet).attr('speed', this.m_contGroup.value.speed);\n        jXML(xSnippet).attr('vertical', this.m_contGroup.value.vertical);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/blocks/block-prop-scene.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {Lib, urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-scene',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <span i18n>scene name</span><br/>\n                        <input class=\"default-prop-width\" type=\"text\" [formControl]=\"m_contGroup.controls['name']\"/>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropScene extends Compbaser implements AfterViewInit {\n\n    private formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(@Inject('BLOCK_PLACEMENT') private blockPlacement, private fb: FormBuilder, private cd: ChangeDetectorRef, private rp: RedPepperService, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'name': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        this.m_blockData = i_blockData;\n        this._render();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData);\n        var name = jXML(domPlayerData).find('Player').eq(0).attr('label');\n        this.formInputs['name'].setValue(name);\n    }\n\n    private saveToStore() {\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData);\n        var name = Lib.CleanProbCharacters(this.m_contGroup.value.name, 1);\n        jXML(domPlayerData).find('Player').eq(0).attr('label', name);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-sheets.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport * as moment from 'moment'\n\n@Component({\n    selector: 'block-prop-sheets',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div *ngIf=\"!jsonMode\">\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <span i18n>token</span><br/>\n                            <input class=\"default-prop-width\" (blur)=\"_getGoogleSheets()\" type=\"text\" [formControl]=\"m_contGroup.controls['token']\"/>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <button i18n class=\"btn btn-default default-prop-width\" (click)=\"_onCreateToken()\">create token</button>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <span i18n>Load with sheet</span>\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                                <select #sceneSelection (change)=\"_onSheetSelected($event)\" style=\"height: 30px; width: 234px\" formControlName=\"sheetSelection\">\n                                    <option [value]=\"cal.id\" *ngFor=\"let cal of m_sheetList\">{{cal.label}}</option>\n                                </select>\n\n                            </div>\n                        </li>\n                    </ul>\n                </div>\n                <div *ngIf=\"jsonMode\">\n                    <block-prop-json-player [setBlockData]=\"m_blockData\"></block-prop-json-player>\n                </div>\n            </div>\n        </form>\n    `\n})\n\nexport class BlockPropSheets extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_sheetList = [];\n    m_sheetSeleced: any = {};\n    m_mode = false;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'token': [''],\n            'sheetSelection': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() jsonMode: boolean;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    _onSheetSelected(event) {\n        var calId = event.target.value;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('id', calId);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var jXMLdata = jXML(domPlayerData).find('Json').find('Data');\n        var mode = jXMLdata.attr('mode');\n        this.m_formInputs['token'].setValue(jXMLdata.attr('token'));\n        this._getGoogleSheets();\n    }\n\n    _getGoogleSheets() {\n        var self = this;\n        try {\n            jXML.ajax({\n                url: `https://secure.digitalsignage.com/GoogleSheetsList/${self.m_contGroup.value.token}`,\n                dataType: \"json\",\n                type: \"post\",\n                complete: function (response, status) {\n                    self.m_sheetSeleced = {};\n                    self.m_sheetList = [];\n                    if (_.isUndefined(response.responseText) || response.responseText.length == 0)\n                        return;\n                    if (response.responseText.indexOf('Cannot')>-1)\n                        return;\n                    var jData = JSON.parse(response.responseText);\n                    _.forEach(jData, function (k: any) {\n                        self.m_sheetList.push({\n                            id: k.id,\n                            label: k.title,\n                            mimeType: k.mimeType\n                        })\n                    });\n                    var id = self._getFileId();\n                    if (id && id.length > 10)\n                        self.m_sheetSeleced = self.m_sheetList.find(item => item.id == id);\n                    self.m_formInputs['sheetSelection'].setValue(self.m_sheetSeleced.id);\n                    self.cd.markForCheck()\n                },\n                error: function (jqXHR, exception) {\n                    console.log('ajax req:' + jqXHR, exception);\n                }\n            });\n        } catch (e) {\n            console.error('error on ajax' + e);\n        }\n    }\n\n    private _getFileId(): string {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        return jXML(item).attr('id');\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onCreateToken() {\n        var win = window.open('http://google.signage.me', '_blank');\n        if (win) {\n            win.focus();\n        } else {\n            bootbox.alert('Browser popups are blocked, please enable and try again');\n        }\n    }\n\n    private saveToStore() {\n        // Lib.Con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('token', this.m_contGroup.value.token);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-twitter.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-twitter',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div *ngIf=\"!jsonMode\">\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <span i18n>screen name</span><br/>\n                            <input type=\"text\" placeholder=\"filter\"  [formControl]=\"m_contGroup.controls['screenName']\"/>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <span i18n>token</span><br/>\n                            <input type=\"text\" [formControl]=\"m_contGroup.controls['token']\"/>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <button i18n class=\"btn btn-default\" (click)=\"_onCreateToken()\">create access token</button>\n                        </li>\n                    </ul>\n                </div>\n                <div *ngIf=\"jsonMode\">\n                    <block-prop-json-player [setBlockData]=\"m_blockData\"></block-prop-json-player>\n                </div>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropTwitter extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'screenName': [''],\n            'token': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() jsonMode: boolean;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var jXMLdata = jXML(domPlayerData).find('Json').find('Data');\n        this.m_formInputs['token'].setValue(jXMLdata.attr('token'));\n        this.m_formInputs['screenName'].setValue(jXMLdata.attr('screenName'));\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onCreateToken() {\n        var win = window.open('http://twitter.signage.me', '_blank');\n        if (win) {\n            win.focus();\n        } else {\n            bootbox.alert('Browser popups are blocked, please enable and try again');\n        }\n    }\n\n    private saveToStore() {\n        con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('screenName', this.m_contGroup.value.screenName);\n        jXML(item).attr('token', this.m_contGroup.value.token);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-video.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {urlRegExp} from \"../../Lib\";\n\n@Component({\n    selector: 'block-prop-video',\n    host: {'(input-blur)': 'saveToStore($event)'},\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li *ngIf=\"external\" class=\"list-group-item\">\n                        <span i18n>url</span><br/>\n                        <input class=\"default-prop-width\" type=\"text\" [formControl]=\"m_contGroup.controls['url']\"/>\n                    </li>\n                    <li *ngIf=\"!external\" class=\"list-group-item\">\n                        <span i18n>maintain aspect ratio</span>\n                        <div class=\"material-switch pull-right\">\n                            <input #imageRatio (change)=\"_toggleAspectRatio(imageRatio.checked)\"\n                                   [formControl]=\"m_contGroup.controls['maintain']\"\n                                   id=\"imageRatio\"\n                                   name=\"imageRatio\" type=\"checkbox\"/>\n                            <label for=\"imageRatio\" class=\"label-primary\"></label>\n                        </div>\n                    </li>\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropVideo extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'url': ['', [Validators.pattern(urlRegExp)]],\n            'maintain': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() external: boolean = false;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    /**\n     Toggle maintain aspect ratio\n     **/\n    _toggleAspectRatio(i_value) {\n        i_value = StringJS(i_value).booleanToNumber()\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('AspectRatio');\n        jXML(xSnippet).attr('maintain', i_value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        if (this.external) {\n            var xSnippet = jXML(domPlayerData).find('LINK');\n            this.m_formInputs['url'].setValue(xSnippet.attr('src'));\n        } else {\n            var xSnippet = jXML(domPlayerData).find('AspectRatio');\n            var maintain = StringJS(jXML(xSnippet).attr('maintain')).booleanToNumber();\n            this.m_formInputs['maintain'].setValue(maintain);\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    private saveToStore() {\n        con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('LINK');\n        xSnippet.attr('src', this.m_contGroup.value.url);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop-weather.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {simpleRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-weather',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div *ngIf=\"!jsonMode\">\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <label i18n>Unit</label>\n                            <br/>\n                            <input type=\"radio\" value=\"F\" name=\"unit\" formControlName=\"unit\">\n                            <span i18n>Fahrenheit</span>\n                            <br/>\n                            <input type=\"radio\" value=\"C\" name=\"unit\" formControlName=\"unit\">\n                            <span i18n>Celsius</span>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <label i18n>Styles</label>\n                            <br/>\n                            <input type=\"radio\" value=\"1\" name=\"style\" formControlName=\"style\">\n                            <span i18n>Black</span>\n                            <br/>\n                            <input type=\"radio\" value=\"2\" name=\"style\" formControlName=\"style\">\n                            <span i18n>White</span>\n                            <br/>\n                            <input type=\"radio\" value=\"3\" name=\"style\" formControlName=\"style\">\n                            <span i18n>Color</span>\n                        </li>\n                        <li class=\"list-group-item\">\n                            address / zip code\n                            <input type=\"text\" [formControl]=\"m_contGroup.controls['address']\"/>\n                        </li>\n                    </ul>\n                </div>\n                <div *ngIf=\"jsonMode\">\n                    <block-prop-json-player [setBlockData]=\"m_blockData\"></block-prop-json-player>\n                </div>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropWeather extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef, private bs: BlockService, private ngmslibService: NgmslibService) {\n        super();\n        this.m_contGroup = fb.group({\n            'style': \"\",\n            'unit': \"\",\n            'address': ['', [Validators.pattern(simpleRegExp)]]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() jsonMode: boolean;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        var jXMLdata = jXML(domPlayerData).find('Json').find('Data');\n        this.m_formInputs['unit'].setValue(jXMLdata.attr('unit'));\n        this.m_formInputs['style'].setValue(jXMLdata.attr('style'));\n        this.m_formInputs['address'].setValue(jXMLdata.attr('address'));\n        //this.cd.markForCheck();\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom;\n        var item = jXML(domPlayerData).find('Json').find('Data');\n        jXML(item).attr('unit', this.m_contGroup.value.unit);\n        jXML(item).attr('style', this.m_contGroup.value.style);\n        jXML(item).attr('address', this.m_contGroup.value.address);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n\n\n"
  },
  {
    "path": "src/app/blocks/block-prop-youtube.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {urlRegExp} from \"../../Lib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-youtube',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <span i18n>volume</span>\n                        <input formControlName=\"volume\" type=\"range\" min=\"0\" max=\"100\" step=\"1\"/>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <span i18n>video quality</span>\n                        <select #sceneSelection class=\"default-prop-width\" formControlName=\"quality\">\n                            <option [value]=\"'default'\">default</option>\n                            <option [value]=\"'small'\">small</option>\n                            <option [value]=\"'medium'\">medium</option>\n                            <option [value]=\"'large'\">large</option>\n                            <option [value]=\"'hd720'\">HD</option>\n                        </select>\n                    </li>\n                    <li *ngIf=\"m_contGroup.controls['listType'].value == 'most_viewed'\" class=\"list-group-item\">\n                        <span i18n>region</span>\n                        <select #sceneSelection class=\"default-prop-width\" formControlName=\"region\">\n                            <option [value]=\"region\" *ngFor=\"let region of m_regions\">{{region}}</option>\n                        </select>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <input type=\"radio\" value=\"most_viewed\" name=\"listType\" formControlName=\"listType\">\n                        <span i18n>most viewed</span>\n                        <br/>\n                        <input type=\"radio\" value=\"manually\" name=\"listType\" formControlName=\"listType\">\n                        <span i18n>custom list</span>\n                    </li>\n                    <li *ngIf=\"m_contGroup.controls['listType'].value != 'most_viewed'\" class=\"list-group-item\">\n                        <span i18n>video ids</span><br/>\n                        <textarea placeholder=\"enter comma separated video IDs, for example: SIFUUhN3TVo, pZH1itk6Udg, azZo59ayLS4\" class=\"default-prop-width\" spellcheck=\"false\" rows=\"10\" cols=\"50\" type=\"textarea\"\n                                  [formControl]=\"m_contGroup.controls['customList']\">\n                        </textarea>\n                    </li>\n\n                </ul>\n            </div>\n        </form>\n    `\n})\nexport class BlockPropYouTube extends Compbaser implements AfterViewInit {\n\n    formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n    m_regions = ['US', 'AR', 'AU', 'AT', 'BE', 'BR', 'CA', 'CL', 'CO', 'CZ', 'EG', 'FR', 'DE', 'GB', 'HK', 'HU', 'IN', 'IE', 'IL', 'IT', 'JP', 'JO', 'MY', 'MX', 'MA', 'NL', 'NZ', 'PE', 'PH', 'PL', 'RU', 'SA', 'SG', 'ZA', 'KR', 'ES', 'SE', 'CH', 'TW', 'AE'];\n\n    constructor(private fb: FormBuilder, private bs: BlockService, private cd: ChangeDetectorRef) {\n        super();\n        this.m_contGroup = fb.group({\n            'volume': [100],\n            'listType': [0],\n            'quality': [5],\n            'region': ['US'],\n            'customList': [''],\n            'text': []\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _render() {\n        var domPlayerData = this.m_blockData.playerDataDom\n        var xSnippetYouTube = jXML(domPlayerData).find('YouTube');\n        var xSnippetYouTubeManualList = jXML(domPlayerData).find('VideoIdList');\n        var videoIDs = jXML(xSnippetYouTubeManualList).text();\n        var listType = jXML(xSnippetYouTube).attr('listType'); //manually most_viewed\n        var region = jXML(xSnippetYouTube).attr('listRegion');\n        var volume = parseFloat(xSnippetYouTube.attr('volume'));\n        var quality = jXML(xSnippetYouTube).attr('quality');\n        this.formInputs['volume'].setValue(volume);\n        this.formInputs['listType'].setValue(listType);\n        this.formInputs['quality'].setValue(quality);\n        this.formInputs['region'].setValue(region);\n        this.formInputs['customList'].setValue(videoIDs);\n        this.cd.markForCheck();\n    }\n\n    private saveToStore() {\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var xSnippet = jXML(domPlayerData).find('YouTube');\n        jXML(xSnippet).attr('volume', this.m_contGroup.value.volume);\n        jXML(xSnippet).attr('quality', this.m_contGroup.value.quality);\n        jXML(xSnippet).attr('listRegion', this.m_contGroup.value.region);\n        jXML(xSnippet).attr('listType', this.m_contGroup.value.listType);\n        jXML(xSnippet).find('VideoIdList').remove();\n        if (this.m_contGroup.value.listType == 'manually') {\n            jXML(xSnippet).append(jXML(`<VideoIdList>${this.m_contGroup.value.customList}</VideoIdList>`));\n        } else {\n            jXML(xSnippet).find('VideoIdList').remove();\n        }\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-prop.digg.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'block-prop-digg',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div class=\"row\">\n                <div *ngIf=\"!jsonMode\" style=\"padding: 10px\">\n                    <h5>Digg, it's what's new on the web...</h5>\n                    <span class=\"fa fa-digg fa-4x pull-right\"></span>    \n                </div>\n            </div>\n        </form>\n        <div *ngIf=\"jsonMode\">\n            <block-prop-json-player [setBlockData]=\"m_blockData\"></block-prop-json-player>\n        </div>\n    `\n})\nexport class BlockPropDigg extends Compbaser implements AfterViewInit {\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blockData: IBlockData;\n\n    constructor(private fb: FormBuilder) {\n        super();\n        this.m_contGroup = fb.group({\n            'token': ['']\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.m_formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n    }\n\n    @Input() jsonMode: boolean;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        if (this.m_blockData && this.m_blockData.blockID != i_blockData.blockID) {\n            this.m_blockData = i_blockData;\n            this._render();\n        } else {\n            this.m_blockData = i_blockData;\n        }\n    }\n\n    private _render() {\n        var domPlayerData: XMLDocument = this.m_blockData.playerDataDom\n        jXML(domPlayerData).find('Json').find('Data');\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/blocks/block-service.ts",
    "content": "/**\n * Block service is responsible only for procedures related to channel and scene blocks\n */\n\nimport {Inject, Injectable} from \"@angular/core\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport * as X2JS from \"x2js\";\nimport * as _ from \"lodash\";\nimport {Observable} from \"rxjs\";\nimport {CampaignTimelineChanelPlayersModelExt, PlayerDataModelExt} from \"../../store/model/msdb-models-extended\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ResourcesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {BLOCK_SERVICE, BlockLabels, PLACEMENT_CHANNEL, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {CommBroker} from \"../../services/CommBroker\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\n\n//// import X2JS from \"x2js\";\n\ninterface IDomPlayerDataJson {\n    Player: {\n        Data: {\n            Appearance: {\n                _alpha: string;\n                _blendMode: string;\n            }\n            Background: {\n                GradientPoints: {\n                    Point: {\n                        _color: string;\n                        _opacity: string;\n                        _midpoint: string;\n                    }\n                }\n                _style: string;\n                _gradientType: string;\n                _angle: string;\n                _offsetX: string;\n                _offsetY: string;\n            };\n            Border: {\n                _borderThickness: string;\n                _borderColor: string;\n                _cornerRadius: string;\n            };\n            Layout: {\n                _rotation: string;\n                _x: string;\n                _y: string;\n                _width: string;\n                _height: string;\n            };\n            Resource: {\n                AspectRatio: {\n                    _maintain: string;\n                };\n                Image: string;\n                _resource: string;\n                _hResource: string;\n            }\n        };\n        _player: string;\n        _label: string;\n        _interactive: string;\n        _locked: string;\n        _id: string;\n    }\n}\n\nexport interface ISceneData {\n    scene_id: number;\n    scene_id_pseudo_id: string;\n    scene_native_id: number;\n    playerDataModel: PlayerDataModelExt;\n    domPlayerData: XMLDocument;\n    domPlayerDataJson: IDomPlayerDataJson;\n    domPlayerDataXml: string;\n    block_pseudo_id: any;\n    mimeType?;\n}\n\nexport interface IBlockData {\n    blockID: number;\n    blockType: string;\n    blockCode: string;\n    blockName: string;\n    blockDescription: string;\n    blockIcon: string;\n    blockFontAwesome: string;\n    blockAcronym: string;\n    blockMinWidth: number;\n    blockMinHeight: number;\n    playerDataJson: any;\n    playerDataDom: XMLDocument,\n    playerMimeScene: string;\n    playerDataJsonHandle: number;\n    campaignTimelineChanelPlayersModelExt: CampaignTimelineChanelPlayersModelExt,\n    duration: number;\n    offset: number;\n    scene?: {\n        name: string,\n        handle: any,\n        playerDataJson: IDomPlayerDataJson;\n        playerDataDom: XMLDocument\n    },\n    resource?: {\n        name: string,\n        handle: string,\n        type: string,\n    }\n}\n\n@Injectable()\nexport class BlockService {\n    parser;\n\n    private m_zIndex = -1;\n    private m_minSize = {w: 50, h: 50};\n    private m_components = {};\n    private m_fontAwesome = {};\n    private m_blockCodes = {};\n    private m_commBroker;\n\n    constructor(private commBroker: CommBroker, @Inject('BLOCK_PLACEMENT') private blockPlacement: string, private yp: YellowPepperService, private rp: RedPepperService) {\n        this.parser = new X2JS({\n            escapeMode: true,\n            attributePrefix: \"_\",\n            arrayAccessForm: \"none\",\n            emptyNodeForm: \"text\",\n            enableToStringFunc: true,\n            arrayAccessFormPaths: [],\n            skipEmptyTextNodesForObj: true\n        });\n\n\n        var self = this;\n        this.m_blockCodes = _.invert(BlockLabels);\n        this.m_fontAwesome = {\n            'scene': {image: 'fa-pencil-square-o'},\n            'qr': {image: 'fa-qrcode'},\n            'youtube': {image: 'fa-youtube'},\n            'collection': {image: 'fa-stack-exchange'},\n            'location': {image: 'fa-map-marker'},\n            'fasterq': {image: 'fa-male'},\n            'twitter': {image: 'fa-twitter'},\n            'twitteritem': {image: 'fa-twitter'},\n            'instagram': {image: 'fa-instagram'},\n            'json': {image: 'fa-cubes'},\n            'jsonitem': {image: 'fa-cubes'},\n            'worldweather': {image: 'fa-sun-o'},\n            'googlesheets': {image: 'fa-table'},\n            'googlecalendar': {image: 'fa-calendar'},\n            'digg': {image: 'fa-digg'},\n            'rss': {image: 'fa-rss'},\n            'mrss': {image: 'fa-rss-square'},\n            'flv': {image: 'fa-file-video-o'},\n            'mp4': {image: 'fa-video-camera'},\n            'png': {image: 'fa-picture-o'},\n            'swf': {image: 'fa-bolt'},\n            'jpg': {image: 'fa-file-image-o'},\n            'svg': {image: 'fa-file-image-o'},\n            'html5': {image: 'fa-html5'},\n            'clock': {image: 'fa-clock-o'},\n            'label': {image: 'fa-file-text-o'},\n            'extvideo': {image: 'fa-share-square-o'},\n            'extimage': {image: 'fa-share-square '}\n        };\n\n        this.m_components = {\n            3100: {\n                name: 'Video',\n                //color: '#D50D36',\n                color: '#E5E5E5',\n                acronym: 'video',\n                description: 'Movie file',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect fill=\"none\" id=\"canvas_background\" height=\"52\" width=\"52\" y=\"-1\" x=\"-1\"/></g><g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path id=\"svg_3\" d=\"m36.6875,10l-24.375,0c-4.02187,0 -7.3125,3.17812 -7.3125,7.0625l0,14.125c0,3.88438 3.29063,7.0625 7.3125,7.0625l24.375,0c4.02188,0 7.3125,-3.17812 7.3125,-7.0625l0,-14.125c0,-3.88438 -3.29062,-7.0625 -7.3125,-7.0625zm4.875,21.1875c0,1.24984 -0.50944,2.43002 -1.43409,3.32328c-0.92488,0.89304 -2.14676,1.38506 -3.44091,1.38506l-24.375,0c-1.29408,0 -2.51603,-0.49202 -3.44084,-1.38506c-0.9248,-0.89326 -1.43416,-2.07343 -1.43416,-3.32328l0,-14.125c0,-1.24984 0.50936,-2.43001 1.43416,-3.3232c0.9248,-0.89319 2.14675,-1.38514 3.44084,-1.38514l24.375,0c1.29409,0 2.51603,0.49195 3.44091,1.38514c0.9248,0.89319 1.43409,2.07336 1.43409,3.3232l0,14.125zm-21.9375,2.35417l12.1875,-9.41667l-12.1875,-9.41667l0,18.83334z\"/></g></g></g></svg>'),\n                fontAwesome: self.getFontAwesome('mp4'),\n                getDefaultPlayerData: function (i_placement, i_resourceID) {\n                    return '<Player player=\"3100\" label=\"Video\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Resource hResource=\"' + i_resourceID + '\">' +\n                        '<AspectRatio maintain=\"1\" />' +\n                        '<Video autoRewind=\"1\" volume=\"1\" backgroundAlpha=\"1\" />' +\n                        '</Resource>' +\n                        '</Data>' +\n                        '</Player>';\n                },\n                ext: [\n                    0, 'flv',\n                    1, 'mp4'\n                ]\n            },\n            3130: {\n                name: 'Image',\n                //color: '#24870D',\n                color: '#E5E5E5',\n                acronym: 'Image',\n                description: 'Bitmap file',\n                fontAwesome: self.getFontAwesome('jpg'),\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect x=\"-1\" y=\"-1\" width=\"52\" height=\"52\" id=\"canvas_background\" fill=\"none\"/></g> <g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path id=\"svg_1\" d=\"m9,7.5625l0,28.4375l36,0l0,-28.4375l-36,0zm33.75,26.25l-31.5,0l0,-24.0625l31.5,0l0,24.0625zm-9,-18.59375c0,1.812195 1.511017,3.28125 3.375,3.28125s3.375,-1.469055 3.375,-3.28125s-1.511017,-3.28125 -3.375,-3.28125s-3.375,1.469055 -3.375,3.28125zm6.75,16.40625l-27,0l6.75,-17.5l9,10.9375l4.5,-3.28125l6.75,9.84375z\"/></g></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement, i_resourceID) {\n                    return '<Player player=\"3130\" label=\"\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Resource hResource=\"' + i_resourceID + '\">' +\n                        '<AspectRatio maintain=\"0\" />' +\n                        '<Image />' +\n                        '</Resource>' +\n                        '</Data>' +\n                        '</Player>';\n                },\n                ext: [\n                    0, 'png',\n                    1, 'jpg',\n                    2, 'swf'\n                ]\n            },\n            3140: {\n                name: 'SVG',\n                //color: '#24870D',\n                color: '#E5E5E5',\n                acronym: 'SVG',\n                description: 'SVG file',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect x=\"-1\" y=\"-1\" width=\"52\" height=\"52\" id=\"canvas_background\" fill=\"none\"/></g> <g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path id=\"svg_1\" d=\"m9,7.5625l0,28.4375l36,0l0,-28.4375l-36,0zm33.75,26.25l-31.5,0l0,-24.0625l31.5,0l0,24.0625zm-9,-18.59375c0,1.812195 1.511017,3.28125 3.375,3.28125s3.375,-1.469055 3.375,-3.28125s-1.511017,-3.28125 -3.375,-3.28125s-3.375,1.469055 -3.375,3.28125zm6.75,16.40625l-27,0l6.75,-17.5l9,10.9375l4.5,-3.28125l6.75,9.84375z\"/></g></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement, i_resourceID) {\n                    return '<Player player=\"3140\" label=\"\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Resource hResource=\"' + i_resourceID + '\">' +\n                        '<AspectRatio maintain=\"0\" />' +\n                        '<Image />' +\n                        '</Resource>' +\n                        '</Data>' +\n                        '</Player>';\n                },\n                ext: [\n                    0, 'svg'\n                ]\n            },\n            3160: {\n                name: 'External image',\n                //color: '#B6B5A1',\n                color: '#E5E5E5',\n                acronym: 'ext image',\n                description: 'Download images and Flash swf from external web links',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect fill=\"none\" id=\"canvas_background\" height=\"52\" width=\"52\" y=\"-1\" x=\"-1\"/> </g> <g><title>Layer 1</title><g id=\"svg_1\"> <g id=\"svg_2\"><path d=\"m38,14l0,20l-24,0l0,-20l24,0m2,-2l-28,0l0,24l28,0l0,-24l0,0zm-24,18l20,0l-4,-12l-6,8l-4,-4l-6,8zm2,-12c-1.1055,0 -2,0.89456 -2,2s0.89456,2 2,2s2,-0.89456 2,-2s-0.8945,-2 -2,-2zm-10,-10l0,24l2,0l0,-22l26,0l0,-2l-28,0z\" id=\"svg_1\"/> </g></g> </g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3160\" label=\"External image Code\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<LINK src=\"\"/>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('extimage')\n            },\n            3150: {\n                name: 'External video',\n                //color: '#5BB5E8',\n                color: '#E5E5E5',\n                acronym: 'ext video',\n                description: 'Download video from external web links',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title>  <rect x=\"-1\" y=\"-1\" width=\"52\" height=\"52\" id=\"canvas_background\" fill=\"none\"/> </g> <g>  <title>Layer 1</title>  <g id=\"svg_1\">   <g id=\"svg_2\">    <path id=\"svg_3\" d=\"m36.875,11l-23.75,0c-3.91875,0 -7.125,2.89688 -7.125,6.4375l0,12.875c0,3.54063 3.20625,6.4375 7.125,6.4375l23.75,0c3.91875,0 7.125,-2.89687 7.125,-6.4375l0,-12.875c0,-3.54062 -3.20625,-6.4375 -7.125,-6.4375zm-16.625,21.45834l0,-17.16667l11.875,8.58333l-11.875,8.58334z\"/>   </g>  </g> </g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3150\" label=\"External video\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<LINK src=\"\"/>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('extvideo')\n            },\n            3430: {\n                name: 'QR',\n                app_id: '10160',\n                color: '#E5E5E5',\n                acronym: 'qr',\n                description: 'QR code for mobile device integration',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect fill=\"none\" id=\"canvas_background\" height=\"52\" width=\"52\" y=\"-1\" x=\"-1\"/></g><g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path d=\"M17.16,25.713h1.427v1.426h1.426v1.426h-7.129v-1.426h1.426v-2.852h2.853v1.426H17.16z M35.695,38.543h1.424v-1.426h-1.424V38.543z M18.586,25.713h1.426v-1.426h-1.426V25.713z M38.543,38.543h1.426v-1.426h-1.426V38.543z M21.439,39.969h2.85v-1.426h-2.85V39.969z M34.268,39.969v-1.426h-1.426v1.426H34.268z M28.566,39.969h1.426v-2.852h-1.426V39.969z M17.16,21.436v1.426h4.277v-1.426H17.16z M15.736,22.861v-1.426h-2.853v2.852h1.426v-1.426H15.736z M20.012,20.01h-9.979v-9.979h9.979V20.01z M18.586,11.457h-7.129v7.127h7.129V11.457z M12.883,37.117h4.276V32.84h-4.276V37.117z M27.139,35.691v1.426h1.428v-1.426H27.139z M17.16,12.883h-4.276v4.275h4.276V12.883z M39.969,10.031v9.979H29.99v-9.979H39.969z M38.543,11.457h-7.127v7.127h7.127V11.457z M10.031,29.988h9.98v9.979h-9.98V29.988z M11.458,38.543h7.129v-7.129h-7.129V38.543z M11.458,21.436h-1.427v7.129h1.427V21.436z M29.99,28.564v1.424h1.426v-1.424H29.99z M25.713,34.266V32.84h-1.426v1.426h-2.85v2.853h2.85v1.426h1.426v-2.853h1.426v-1.426H25.713L25.713,34.266z M21.439,15.734h2.85v-1.428h-2.85V15.734z M32.842,27.139h2.854v1.426h1.424v-4.276h-1.424v-2.853h-1.428v4.277h-4.275v1.426h1.426v1.426h1.426v-1.426H32.842z M34.268,31.414h-1.426v-1.426h-1.426v2.852h-4.277v1.426h2.854v2.853h1.426v1.426h1.426v-2.853h5.701v-1.426H34.27v-2.852H34.268z M34.268,31.414h1.428v-2.85h-1.428V31.414z M22.863,31.414v-1.426h1.424v-1.424h1.426v-1.427h1.426v-2.852h4.277v-2.853H29.99v1.426h-1.426v-5.703h-1.426v-2.852h1.426v-4.273h-1.426v2.852h-1.426v-2.852h-4.276v2.852h1.426v-1.426h1.424v2.85h1.426v4.277h1.426v1.426h-1.426v2.852h-1.426V20.01h-1.424v-1.426h-1.426v2.852h1.426v1.426h-1.426v4.277h1.426v-2.852h1.424v2.852h-1.424v1.426h-1.426v4.275h2.85v-1.426H22.863z M38.543,32.84v-1.426h-2.85v1.426H38.543z M37.117,12.883h-4.275v4.275h4.275V12.883z M25.713,31.414h2.854v-1.426h-1.428v-1.424h-1.426V31.414z M28.566,28.564v-1.426h-1.428v1.426H28.566z M37.117,22.861h2.852v-1.426h-2.852V22.861z M38.543,34.266h1.426V32.84h-1.426V34.266z M38.543,25.713h1.426v-1.426h-1.426V25.713z M25.713,18.584h-1.426v1.426h1.426V18.584z\"/></g></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3430\" label=\"QR Code\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Text textSource=\"static\"></Text>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('qr')\n            },\n            4600: {\n                name: 'YouTube',\n                app_id: '10220',\n                color: '#E5E5E5',\n                acronym: 'YouTube',\n                description: 'YouTube - broadcast yourself',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g transform=\"translate(0,0)\"><g><path d=\"M22.767,28.354h1.398v6.377l-1.123-0.002l0.003-0.824c-0.301,0.646-1.507,1.168-2.136,0.714\tc-0.337-0.241-0.326-0.666-0.36-1.029c-0.018-0.206-0.003-0.659-0.004-1.269l-0.004-3.967h1.39l0.007,4.03\tc0,0.55-0.03,0.87,0.004,0.976c0.198,0.607,0.71,0.279,0.823-0.032c0.038-0.103,0.002-0.392,0.002-0.97V28.354z M28.635,29.604\tl0.004,3.334c0,1.615-0.922,2.535-2.391,1.188l-0.104,0.533l-1.149,0.017l0.007-8.55l1.396-0.002l-0.006,2.478\tC27.684,27.576,28.634,28.336,28.635,29.604z M27.6,29.438c0-0.275-0.275-0.502-0.611-0.502s-0.611,0.227-0.611,0.502v3.74\tc0,0.276,0.275,0.502,0.611,0.502s0.611-0.226,0.611-0.502V29.438z M24.753,21.281c0.341,0,0.619-0.306,0.619-0.681v-3.529\tc0-0.375-0.278-0.682-0.619-0.682c-0.34,0-0.619,0.307-0.619,0.682v3.529C24.134,20.976,24.413,21.281,24.753,21.281z\t M20.815,27.237v-1.11l-4.471-0.007v1.093l1.396,0.003v7.52h1.399l-0.002-7.498H20.815z M41,9v32H9V9H41L41,9z M27.475,20.019\tc0,0.567,0.01,0.948,0.027,1.141c0.02,0.191,0.062,0.375,0.135,0.554c0.071,0.175,0.184,0.315,0.336,0.425\tc0.15,0.105,0.342,0.158,0.572,0.158c0.201,0,0.38-0.056,0.536-0.168c0.155-0.111,0.286-0.277,0.394-0.501l-0.027,0.549h1.559\tv-6.628h-1.227v5.158c0,0.279-0.23,0.508-0.512,0.508c-0.279,0-0.512-0.229-0.512-0.508v-5.158h-1.279v4.471H27.475z M23.072,16.478\tc-0.105,0.357-0.159,0.854-0.159,1.49v1.754c0,0.582,0.029,1.019,0.087,1.309c0.059,0.289,0.156,0.539,0.293,0.742\tc0.136,0.205,0.327,0.358,0.574,0.459c0.247,0.104,0.546,0.151,0.901,0.151c0.318,0,0.6-0.059,0.846-0.178\tc0.241-0.117,0.444-0.304,0.6-0.551c0.158-0.25,0.261-0.519,0.308-0.806s0.071-0.74,0.071-1.354v-1.675\tc0-0.486-0.024-0.848-0.079-1.086c-0.051-0.235-0.146-0.467-0.289-0.69c-0.139-0.224-0.338-0.403-0.598-0.543\tc-0.258-0.14-0.567-0.21-0.927-0.21c-0.429,0-0.781,0.109-1.057,0.326C23.369,15.832,23.178,16.119,23.072,16.478z M17.97,12.935\tl1.849,4.366l0.001,5.081h1.471l0.001-5.083l1.738-4.354h-1.608l-0.924,3.234l-0.937-3.244H17.97z M35.055,26.845\tc0-1.707-1.48-3.104-3.291-3.104H18.236c-1.81,0-3.29,1.396-3.29,3.104v7.116c0,1.707,1.479,3.104,3.29,3.104h13.528\tc1.811,0,3.291-1.397,3.291-3.104V26.845z M33.014,32.496c0.479,2.841-3.531,3.308-3.531,0.005v-1.986\tc0-0.596,0.058-1.064,0.178-1.408c0.119-0.344,0.32-0.6,0.587-0.789c0.847-0.612,2.522-0.424,2.694,0.771\tc0.055,0.377,0.072,1.037,0.072,1.697v0.902h-2.4v0.832v0.644v0.063c0,0.313,0.258,0.568,0.572,0.568h0.205\tc0.314,0,0.573-0.256,0.573-0.568v-0.584c0-0.054,0.002-0.101,0.003-0.143L33.014,32.496z M30.63,30.586h1.325l0.016-0.771\tc0-0.342-0.281-0.621-0.627-0.621h-0.082c-0.345,0-0.625,0.279-0.625,0.621L30.63,30.586z\"/></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4600\" label=\"YouTube\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<YouTube quality=\"default\" listType=\"most_viewed\" listRegion=\"US\" volume=\"100\"/>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('youtube')\n            },\n            4100: {\n                name: 'Collection',\n                app_id: '10180',\n                color: '#E5E5E5',\n                acronym: 'Collection',\n                description: 'Collection - just list your content',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g transform=\"translate(24,24)\"><path stroke=\"null\" d=\"m4.8096,15.92069l19.3238,11.9374c0.13634,0.08587 0.28196,0.12678 0.42783,0.12678s0.29082,-0.04304 0.42784,-0.12678l19.3234,-11.9374c0.40796,-0.25262 0.66934,-0.83582 0.66008,-1.47638c-0.00913,-0.64096 -0.28691,-1.20843 -0.70132,-1.43528l-19.32394,-10.60758c-0.24972,-0.13746 -0.52454,-0.13746 -0.77359,0l-19.32327,10.60739c-0.41439,0.22685 -0.69205,0.79549 -0.70172,1.43528c-0.00913,0.63958 0.25255,1.22491 0.66089,1.47657zm19.75097,-10.37145l16.41912,9.01295l-16.41912,10.14365l-16.41941,-10.14345l16.41941,-9.01315z\" id=\"svg_3\"/>    <path stroke=\"null\" d=\"m4.8096,22.71394l19.75097,12.20183l19.75055,-12.20183c0.55316,-0.34142 0.80893,-1.26466 0.57237,-2.06169c-0.23588,-0.79549 -0.87339,-1.16908 -1.42803,-0.82611l-18.89488,11.67371l-18.89559,-11.67371c-0.55289,-0.34201 -1.19188,0.02966 -1.42842,0.82611c-0.23657,0.79799 0.02029,1.72026 0.57303,2.06169z\" id=\"svg_4\"/>    <path stroke=\"null\" d=\"m4.8096,28.99497l19.75097,12.20222l19.75055,-12.20222c0.55316,-0.3414 0.80893,-1.26369 0.57237,-2.0611c-0.23588,-0.79547 -0.87339,-1.16967 -1.42803,-0.82611l-18.89488,11.67371l-18.89559,-11.67351c-0.55289,-0.34163 -1.19188,0.02946 -1.42842,0.8261c-0.23657,0.79742 0.02029,1.71952 0.57303,2.06092z\" id=\"svg_5\"/>    <path stroke=\"null\" d=\"m4.8096,35.27677l19.75097,12.20224l19.75055,-12.20224c0.55316,-0.3416 0.80893,-1.26388 0.57237,-2.0613c-0.23588,-0.79547 -0.87339,-1.16733 -1.42803,-0.82611l-18.89488,11.67375l-18.89559,-11.67375c-0.55289,-0.3414 -1.19188,0.02969 -1.42842,0.82611c-0.23657,0.79742 0.02029,1.7197 0.57303,2.0613z\" id=\"svg_6\"/>          </g>     </g>    </svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4100\" label=\"Collection\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Collection mode=\"slideshow\" duration=\"10\">' +\n                        '</Collection>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('collection')\n            },\n            4105: {\n                name: 'Location',\n                app_id: '10185',\n                color: '#E5E5E5',\n                acronym: 'Location',\n                description: 'Location - content by GPS coordinates',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g transform=\"translate(24,24)\"><path stroke=\"null\" id=\"svg_1\" fill=\"#010002\" d=\"m25,2.8932c-10.44884,0 -18.91998,6.9469 -18.91998,15.51556c0,0.65596 0.06417,1.29528 0.16198,1.92903c1.61666,12.11973 17.52947,26.08818 17.52947,26.08818c0.28355,0.26021 0.55687,0.42072 0.8201,0.53689l0.01355,0.00556l0.52989,0.13837l0.5299,-0.13837l0.01354,-0.00556c0.26323,-0.11626 0.53668,-0.28506 0.82011,-0.53689c0,0 15.68332,-13.9934 17.26279,-26.11577c0.09449,-0.62547 0.15864,-1.25932 0.15864,-1.90417c-0.00344,-8.56593 -8.47114,-15.51283 -18.91998,-15.51283zm0,25.49585c-6.70936,0 -12.16998,-4.47807 -12.16998,-9.9802s5.46061,-9.9802 12.16998,-9.9802s12.16666,4.47807 12.16666,9.9802s-5.45729,9.9802 -12.16666,9.9802z\"/>         </g>     </g>    </svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4105\" label=\"Location\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<LocationBased duration=\"10\">' +\n                        '<GPS></GPS>' +\n                        '<Fixed></Fixed>' +\n                        '</LocationBased>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('location')\n            },\n            6100: {\n                name: 'FasterQ',\n                app_id: '12100',\n                color: '#E5E5E5',\n                acronym: 'FasterQ',\n                description: 'FasterQ - smart lines',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\">     <g transform=\"translate(0,0)\"> <g><path stroke=\"null\" d=\"m21.25243,26.86432c-4.75631,0 -8.60994,-4.53651 -8.60994,-10.12846c0,-5.59135 3.85363,-9.73586 8.60994,-9.73586c4.75705,0 8.61387,4.14451 8.61387,9.73586c0,5.59195 -3.85696,10.12846 -8.61387,10.12846zm-13.39309,13.69223c0,0 -1.82628,0.11837 -2.63069,-0.97008c-0.43465,-0.588 -0.13188,-1.77959 0.16536,-2.44448l0.72795,-1.62905c0,0 2.01319,-4.4214 4.3049,-6.98353c1.40775,-1.57113 3.08209,-1.21335 4.16503,-0.70238c0.667,0.31437 1.42118,1.2304 1.97231,1.71587c0.75947,0.66889 2.10024,1.42906 4.29222,1.47186l1.34484,0c2.19063,-0.0428 3.5314,-0.80298 4.29025,-1.47186c0.55051,-0.48534 1.28389,-1.42978 1.94485,-1.75456c0.99391,-0.4886 2.5067,-0.78919 3.87764,0.74119c2.29245,2.56226 4.10802,7.06382 4.10802,7.06382l0.74605,1.59749c0.3087,0.66031 0.62489,1.84597 0.2023,2.44183c-0.75406,1.06536 -2.44711,0.92401 -2.44711,0.92401s-27.06395,-0.00012 -27.06395,-0.00012l0.00002,0z\" fill=\"#010002\" id=\"svg_2\"/>          </g>     </g>    </svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6100\" label=\"FasterQ\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Webkit>' +\n                        '<Data bgColor=\"white\" lineID1=\"\" lineID2=\"\" lineID3=\"\" lineID4=\"\" lineID5=\"\"/>' +\n                        '</Webkit>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('fasterq')\n            },\n            4500: {\n                name: 'Twitter',\n                app_id: '10210',\n                color: '#E5E5E5',\n                acronym: 'Twitter',\n                description: 'Twitter',\n                svg: '',\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4500\" label=\"Twitter\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Twitter screenName=\"CNN\" slideShow=\"1\" itemInterval=\"4\">' +\n                        '<Player src=\"\" hDataSrc=\"\"/>' +\n                        '</Twitter>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('twitter')\n            },\n            4505: {\n                name: 'Twitter Item',\n                app_id: '10210',\n                color: '#E5E5E5',\n                acronym: 'Twitter',\n                description: 'Twitter',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g transform=\"translate(5,5)\"><g>  <path stroke=\"null\" id=\"svg_1\" d=\"m34.24468,3l-29.48936,0c-0.96929,0 -1.75532,0.78603 -1.75532,1.75532l0,29.48936c0,0.96929 0.78603,1.75532 1.75532,1.75532l29.48936,0c0.96929,0 1.75532,-0.78603 1.75532,-1.75532l0,-29.48936c0,-0.96929 -0.78603,-1.75532 -1.75532,-1.75532zm-1.09742,8.18049c-0.74496,1.11533 -1.66825,2.079 -2.74462,2.86608c0.00878,0.21626 0.01299,0.43286 0.01299,0.65122c0,7.83399 -5.96107,15.93689 -15.9369,15.93689c-3.04969,0 -6.01864,-0.87029 -8.58632,-2.51678c-0.05336,-0.03405 -0.07618,-0.1004 -0.05442,-0.16008c0.02142,-0.05933 0.08215,-0.09619 0.14359,-0.08917c0.43146,0.05126 0.87134,0.07688 1.30912,0.07688c2.37249,0 4.6186,-0.73337 6.5182,-2.12499c-2.27735,-0.19203 -4.23453,-1.73355 -4.93877,-3.93191c-0.01439,-0.04564 -0.00386,-0.09514 0.02809,-0.1313c0.0316,-0.03616 0.08039,-0.05161 0.12708,-0.04353c0.63086,0.12041 1.27225,0.12744 1.89118,0.02773c-2.34862,-0.73056 -3.99967,-2.92998 -3.99967,-5.43482l0.0007,-0.07302c0.00105,-0.04774 0.02703,-0.09128 0.06776,-0.11445c0.04143,-0.02387 0.09268,-0.02422 0.13376,-0.00105c0.6119,0.33983 1.29086,0.55854 1.98527,0.64174c-1.34949,-1.07566 -2.14219,-2.70635 -2.14219,-4.45079c0,-1.0065 0.26681,-1.99615 0.77023,-2.86047c0.02247,-0.03827 0.06249,-0.06389 0.10707,-0.0667c0.04459,-0.00456 0.08777,0.01474 0.1155,0.04985c2.76287,3.38812 6.82608,5.47484 11.1712,5.7427c-0.07302,-0.36511 -0.10953,-0.74074 -0.10953,-1.12024c0,-3.13711 2.55259,-5.68899 5.68934,-5.68899c1.54292,0 3.03284,0.63402 4.10078,1.74128c1.2045,-0.24539 2.35107,-0.68808 3.41023,-1.31649c0.0488,-0.02879 0.10989,-0.02422 0.15412,0.01053c0.04388,0.03546 0.06179,0.09408 0.04424,0.1478c-0.35844,1.12305 -1.05916,2.10252 -1.99966,2.80991c0.88573,-0.15412 1.74619,-0.41496 2.56312,-0.77726c0.05547,-0.02528 0.12041,-0.00948 0.15903,0.03651c0.03932,0.04634 0.04353,0.11234 0.00948,0.16289z\"/></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4505\" label=\"Twitter\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<XmlItem fieldName=\"text\" fieldType=\"text\">' +\n                        '<Font fontSize=\"12\" fontColor=\"0\" fontFamily=\"Astron Boy Video\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"underline\" textAlign=\"center\"/>' +\n                        '</XmlItem>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('twitteritem')\n            },\n            4300: {\n                name: 'JS Object player',\n                app_id: '10195',\n                color: '#E5E5E5',\n                acronym: 'JSON',\n                description: 'JSON',\n                svg: '',\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4300\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"2\" playVideoInFull=\"1\" randomOrder=\"1\" url=\"\">' +\n                        '<Player/>' +\n                        '<Data/>' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('json')\n            },\n            4310: {\n                name: 'JS Object item',\n                app_id: '10195',\n                color: '#E5E5E5',\n                acronym: 'JSON item',\n                description: 'JSON item',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\">     <g transform=\"translate(-15,-15)\">             <g>               <path stroke=\"null\" id=\"svg_2\" d=\"m41.94732,72.56479l-0.04744,-23.53474l-18.99409,-11.80735l-18.95979,11.76463l0.0462,23.71895l18.91359,11.71272l19.04152,-11.85422zm-17.11468,5.91254l0.03388,-16.4782l13.20205,-8.2264l0.03388,16.44207l-13.26982,8.26253zm-1.92951,-36.5139l13.26653,8.2483l-13.22156,8.23691l-13.26695,-8.2794l13.22198,-8.20581zm-15.10528,11.77734l13.22711,8.25553l-0.03368,16.50076l-13.1616,-8.1517l-0.03183,-16.60458z\"/>   <path stroke=\"null\" id=\"svg_3\" d=\"m62.43145,37.22401l-18.95918,11.76332l0.04744,23.71895l18.91399,11.71272l19.03927,-11.85422l-0.04744,-23.53475l-18.99408,-11.80603zm-0.00267,4.73941l13.26695,8.2483l-13.22198,8.23691l-13.26715,-8.27962l13.22218,-8.20559zm-15.10507,11.77734l13.22567,8.25553l-0.03368,16.50076l-13.15831,-8.1517l-0.03368,-16.60458zm17.03582,24.73657l0.03265,-16.4782l13.20206,-8.2264l0.03368,16.44207l-13.26839,8.26253z\"/>   <path stroke=\"null\" id=\"svg_4\" d=\"m61.70614,11.80406l-18.9947,-11.80406l-18.95918,11.76135l0.04559,23.72005l18.91359,11.7136l19.03988,-11.85421l-0.04518,-23.53672zm-18.99717,-7.06531l13.26777,8.24633l-13.22156,8.23976l-13.26777,-8.28181l13.22156,-8.20427zm-15.10549,11.77646l13.22711,8.25706l-0.03306,16.50076l-13.16222,-8.15039l-0.03183,-16.60743zm17.03418,24.73789l0.03327,-16.47864l13.20267,-8.22771l0.03368,16.44337l-13.26962,8.26297z\"/>          </g>     </g>   </svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"4310\" label=\"Json item\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<XmlItem fieldName=\"text\" fieldType=\"text\" dateFormat=\"mm/dd/yy\" maintainAspectRatio=\"0\">' +\n                        '<Font fontSize=\"12\" fontColor=\"0\" fontFamily=\"Astron Boy Video\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"underline\" textAlign=\"center\"/>' +\n                        '</XmlItem>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('jsonitem')\n            },\n            6010: {\n                name: 'Weather',\n                app_id: '12010',\n                color: '#E5E5E5',\n                acronym: 'weather',\n                description: 'World Weather',\n                mimeType: 'Json.weather',\n                jsonItemLongDescription: 'Include a seven day extended weather forecast in your presentation, including highs, lows, humidity, wind conditions and more. Pick from white, black or color icons',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\">     <g transform=\"translate(-10,-10)\">             <g>                 <path stroke=\"null\" id=\"svg_3\" d=\"m31.47559,9.46342c1.03125,0 1.86591,-0.83591 1.86591,-1.86583l0,-3.73167c0,-1.02991 -0.83466,-1.86592 -1.86591,-1.86592c-1.03117,0 -1.86584,0.83592 -1.86584,1.86592l0,3.73167c0,1.03 0.83467,1.86583 1.86584,1.86583zm7.25075,20.73217c2.03992,-1.92683 3.32242,-4.64467 3.32242,-7.67117c0,-5.83767 -4.73434,-10.57317 -10.57317,-10.57317c-3.509,0 -6.61134,1.71658 -8.53442,4.34867c-1.23516,-0.38808 -2.54,-0.617 -3.90458,-0.617c-6.94225,0 -12.60325,5.41967 -13.02116,12.25742c-2.97917,1.55741 -5.01542,4.67091 -5.01542,8.26708c0,5.15341 4.17575,9.32925 9.32925,9.32925l24.87809,0c4.46558,0 8.08525,-3.61983 8.08525,-8.08533c0.00008,-3.20066 -1.86951,-5.94592 -4.56625,-7.25574zm-7.25075,-14.51259c3.77275,0 6.8415,3.06875 6.8415,6.8415c0,1.24508 -0.35075,2.4045 -0.93658,3.4095c-1.46783,-3.02892 -4.52033,-5.14475 -8.08533,-5.26042c-0.82108,-1.04117 -1.80492,-1.94425 -2.89958,-2.69558c1.25134,-1.40067 3.0575,-2.295 5.08,-2.295zm3.73175,26.12193l-24.87809,0c-3.08608,0 -5.59758,-2.51151 -5.59758,-5.59759c0,-2.0885 1.15442,-3.98917 3.01275,-4.9595l1.86708,-0.9765l0.12817,-2.10342c0.301,-4.90842 4.38475,-8.75333 9.29692,-8.75333c2.86967,0 5.53909,1.30108 7.32658,3.56875l1.07475,1.36458l1.7365,0.056c3.03384,0.09825 5.411,2.55116 5.411,5.58383l0,2.48658l2.29625,0.95784c1.627,0.67908 2.67934,2.25642 2.67934,4.01908c-0.00008,2.40075 -1.95292,4.35367 -4.35367,4.35367zm6.2195,-27.36584c0.515,0 0.98142,-0.209 1.3185,-0.54608l2.48783,-2.48783c0.33842,-0.33833 0.54733,-0.80483 0.54733,-1.31975c0,-1.02992 -0.83475,-1.86583 -1.86591,-1.86583c-0.51501,0 -0.98142,0.209 -1.3185,0.54733l-2.48775,2.48775c-0.33842,0.33708 -0.54733,0.80358 -0.54733,1.31858c-0.00008,1.02992 0.83466,1.86583 1.86583,1.86583zm-21.22225,-0.54608c0.33842,0.33708 0.80484,0.54608 1.31975,0.54608c1.03,0 1.86592,-0.83591 1.86592,-1.86583c0,-0.515 -0.209,-0.98141 -0.54733,-1.31975l-2.48783,-2.48783c-0.33708,-0.33708 -0.80359,-0.54608 -1.3185,-0.54608c-1.02991,0 -1.86583,0.83591 -1.86583,1.86583c0,0.515 0.209,0.98141 0.54733,1.31858l2.4865,2.489zm29.9295,6.76558l-3.73167,0c-1.02991,0 -1.86583,0.83592 -1.86583,1.86583s0.83583,1.86592 1.86583,1.86592l3.73167,0c1.02991,0 1.86591,-0.83591 1.86591,-1.86592s-0.83591,-1.86583 -1.86591,-1.86583z\"/>          </g>     </g>   </svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6010\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"weather\" itemsPath=\"\" slideShow=\"0\" itemInterval=\"3600\" playVideoInFull=\"0\" randomOrder=\"0\">' +\n                        '<Player/>' +\n                        '<Data unit=\"F\" style=\"2\" address=\"91301\" />' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('worldweather')\n            },\n            6022: {\n                name: 'Sheets',\n                app_id: '12032',\n                color: '#E5E5E5',\n                acronym: 'Sheets',\n                description: 'Google Sheets',\n                mimeType: 'Json.spreadsheet',\n                jsonItemLongDescription: 'Easily link Scene labels to Google spreadsheet cells simply by specifying the column and row you want to link to, on the Google cloud spreadsheet. Very flexible, easy to add and even easier to edit',\n                svg: '',\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6022\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"spreadsheet\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"2\" playVideoInFull=\"1\" randomOrder=\"1\">' +\n                        '<Player/>' +\n                        '<Data token=\"\" id=\"\" />' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('googlesheets')\n            },\n            6020: {\n                name: 'Calendar',\n                app_id: '12030',\n                color: '#E5E5E5',\n                acronym: 'Calendar',\n                description: 'Google Calendar',\n                mimeType: 'Json.calendar',\n                jsonItemLongDescription: 'With the Google Calendar component you can simply select only the Calendar you want and set a specific date range relative to today, allowing your content to always stay relevant',\n                svg: '',\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6020\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"calendar\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"2\" playVideoInFull=\"1\" randomOrder=\"1\">' +\n                        '<Player/>' +\n                        '<Data id=\"\" token=\"\" mode=\"offset\" startDate=\"\" endDate=\"\" before=\"3\" after=\"6\"/>' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('googlecalendar')\n            },\n            6230: {\n                name: 'Twitter V3',\n                app_id: '12230',\n                color: '#E5E5E5',\n                acronym: 'Twitter V3',\n                description: 'Twitter V3',\n                mimeType: 'Json.twitter',\n                jsonItemLongDescription: 'Get live tweets from your favorite twitter account, filter by a twitter user name and mix images and other fields in your Twitter scene',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g transform=\"translate(5,5)\"><g>  <path stroke=\"null\" id=\"svg_1\" d=\"m34.24468,3l-29.48936,0c-0.96929,0 -1.75532,0.78603 -1.75532,1.75532l0,29.48936c0,0.96929 0.78603,1.75532 1.75532,1.75532l29.48936,0c0.96929,0 1.75532,-0.78603 1.75532,-1.75532l0,-29.48936c0,-0.96929 -0.78603,-1.75532 -1.75532,-1.75532zm-1.09742,8.18049c-0.74496,1.11533 -1.66825,2.079 -2.74462,2.86608c0.00878,0.21626 0.01299,0.43286 0.01299,0.65122c0,7.83399 -5.96107,15.93689 -15.9369,15.93689c-3.04969,0 -6.01864,-0.87029 -8.58632,-2.51678c-0.05336,-0.03405 -0.07618,-0.1004 -0.05442,-0.16008c0.02142,-0.05933 0.08215,-0.09619 0.14359,-0.08917c0.43146,0.05126 0.87134,0.07688 1.30912,0.07688c2.37249,0 4.6186,-0.73337 6.5182,-2.12499c-2.27735,-0.19203 -4.23453,-1.73355 -4.93877,-3.93191c-0.01439,-0.04564 -0.00386,-0.09514 0.02809,-0.1313c0.0316,-0.03616 0.08039,-0.05161 0.12708,-0.04353c0.63086,0.12041 1.27225,0.12744 1.89118,0.02773c-2.34862,-0.73056 -3.99967,-2.92998 -3.99967,-5.43482l0.0007,-0.07302c0.00105,-0.04774 0.02703,-0.09128 0.06776,-0.11445c0.04143,-0.02387 0.09268,-0.02422 0.13376,-0.00105c0.6119,0.33983 1.29086,0.55854 1.98527,0.64174c-1.34949,-1.07566 -2.14219,-2.70635 -2.14219,-4.45079c0,-1.0065 0.26681,-1.99615 0.77023,-2.86047c0.02247,-0.03827 0.06249,-0.06389 0.10707,-0.0667c0.04459,-0.00456 0.08777,0.01474 0.1155,0.04985c2.76287,3.38812 6.82608,5.47484 11.1712,5.7427c-0.07302,-0.36511 -0.10953,-0.74074 -0.10953,-1.12024c0,-3.13711 2.55259,-5.68899 5.68934,-5.68899c1.54292,0 3.03284,0.63402 4.10078,1.74128c1.2045,-0.24539 2.35107,-0.68808 3.41023,-1.31649c0.0488,-0.02879 0.10989,-0.02422 0.15412,0.01053c0.04388,0.03546 0.06179,0.09408 0.04424,0.1478c-0.35844,1.12305 -1.05916,2.10252 -1.99966,2.80991c0.88573,-0.15412 1.74619,-0.41496 2.56312,-0.77726c0.05547,-0.02528 0.12041,-0.00948 0.15903,0.03651c0.03932,0.04634 0.04353,0.11234 0.00948,0.16289z\"/></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6230\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"twitter\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"2\" playVideoInFull=\"1\" randomOrder=\"1\">' +\n                        '<Player/>' +\n                        '<Data token=\"\" screenName=\"\" />' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('twitter')\n            },\n            6050: {\n                name: 'Instagram',\n                app_id: '12060',\n                color: '#E5E5E5',\n                acronym: 'Instagram',\n                description: 'Instagram',\n                mimeType: 'Json.instagram.feed',\n                jsonItemLongDescription: 'Get a live feed from your favorite Instagram account. Load data in real time and watch your posts come to life inside your digital signage presentation',\n                svg: new String(''),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6050\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"instagram.feed\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"2\" playVideoInFull=\"1\" randomOrder=\"1\">' +\n                        '<Player/>' +\n                        '<Data token=\"\" screenName=\"\" />' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('instagram')\n            },\n            6000: {\n                name: 'Digg',\n                app_id: '12000',\n                color: '#E5E5E5',\n                acronym: 'Digg',\n                description: 'Digg',\n                mimeType: 'Json.digg',\n                jsonItemLongDescription: 'In one click add live content from Digg.com and keep your screen always fresh with live a feed that includes images and news',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\">  <g transform=\"translate(-10,-10)\">    <g>   <path stroke=\"null\" id=\"svg_2\" d=\"m11.00993,15.37582l-6.00993,0l0,15.47803l10.01428,0l0,-22.14885l-4.00435,0l0,6.67082zm-0.12917,10.69365l-2.00331,0l0,-6.3598l2.00331,0c0,0 0,6.3598 0,6.3598zm11.84989,4.97622l5.85356,0l0,1.95619l-5.85356,0l0,4.66812l9.86245,0l0,-22.2128l-9.86245,0l0,15.58849zm3.74374,-10.67912l1.99651,0l0,6.3598l-1.99651,0l0,-6.3598zm8.03817,-4.90937l0,15.58267l5.85356,0l0,1.95619l-5.85356,0l0,4.66812l9.86245,0l0,-22.20698l-9.86245,0l0,0zm5.74025,11.26917l-1.99651,0l0,-6.3598l1.99651,0l0,6.3598zm-23.42784,-17.95743l4.00888,0l0,4.34257l-4.00888,0l0,-4.34257zm0,6.66791l4.00888,0l0,15.53617l-4.00888,0l0,-15.53617z\"/>          </g>     </g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"6000\" label=\"json\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<EventCommands></EventCommands>' +\n                        '<Json providerType=\"digg\" itemsPath=\"\" slideShow=\"1\" itemInterval=\"2\" playVideoInFull=\"1\" randomOrder=\"1\">' +\n                        '<Player/>' +\n                        '<Data token=\"\" id=\"\" />' +\n                        '</Json>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('digg')\n            },\n            3340: {\n                name: 'Multimedia RSS',\n                //color: '#AAE4E0',\n                color: '#E5E5E5',\n                acronym: 'mrss',\n                description: 'multimedia video stream',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect x=\"-1\" y=\"-1\" width=\"52\" height=\"52\" id=\"canvas_background\" fill=\"none\"/> </g> <g><title>Layer 1</title><g id=\"svg_1\"> <g id=\"svg_2\"><path id=\"svg_3\" d=\"m40.58189,8.36218c-1.32502,-1.2887 -2.92123,-1.93318 -4.78776,-1.93318l-22.58868,0c-1.86653,0 -3.46274,0.64449 -4.78834,1.93318c-1.32531,1.28898 -1.98811,2.84108 -1.98811,4.65604l0,21.96427c0,1.81496 0.6628,3.36707 1.98811,4.65604c1.3256,1.28898 2.92181,1.93347 4.78834,1.93347l22.58838,0c1.86653,0 3.46274,-0.64449 4.78777,-1.93347c1.3256,-1.28897 1.9884,-2.84108 1.9884,-4.65604l0,-21.96427c0,-1.81496 -0.6628,-3.36735 -1.98811,-4.65604zm-22.98808,26.49451c-0.58858,0.57175 -1.29816,0.85791 -2.12963,0.85791c-0.83117,0 -1.54105,-0.28616 -2.12934,-0.85791c-0.58829,-0.57204 -0.88258,-1.26229 -0.88258,-2.07079c0,-0.80821 0.29429,-1.49847 0.88258,-2.07051c0.58829,-0.57204 1.29817,-0.85791 2.12934,-0.85791c0.83146,0 1.54134,0.28588 2.12963,0.85791c0.588,0.57203 0.88229,1.2623 0.88229,2.07051c0,0.80849 -0.294,1.49875 -0.88229,2.07079zm8.9289,0.62877c-0.15682,0.15248 -0.33732,0.22831 -0.54121,0.22831l-3.01163,0c-0.20389,0 -0.37631,-0.06431 -0.51753,-0.19433c-0.14123,-0.12946 -0.21978,-0.29346 -0.23537,-0.492c-0.17242,-2.34852 -1.12142,-4.36202 -2.84701,-6.04022c-1.72559,-1.67764 -3.79602,-2.60042 -6.21185,-2.76835c-0.20389,-0.01488 -0.37255,-0.09099 -0.50569,-0.22831c-0.13342,-0.13704 -0.20014,-0.30497 -0.20014,-0.50323l0,-2.9287c0,-0.19826 0.07855,-0.37377 0.23537,-0.52626c0.15682,-0.15249 0.34512,-0.22101 0.5649,-0.20584c3.6392,0.19826 6.74498,1.54846 9.31763,4.04975c2.57265,2.50185 3.96092,5.52154 4.16482,9.06047c0.01588,0.21342 -0.05545,0.39624 -0.21227,0.54873zm9.03547,0c-0.15682,0.15248 -0.33703,0.22859 -0.54093,0.22859l-3.01192,0c-0.20389,0 -0.3766,-0.06852 -0.51753,-0.20556c-0.14123,-0.13704 -0.21949,-0.30497 -0.23537,-0.50352c-0.10975,-3.11151 -0.98453,-5.99444 -2.62348,-8.6485c-1.63895,-2.65405 -3.82345,-4.77792 -6.55292,-6.37159c-2.72947,-1.59395 -5.69403,-2.44428 -8.89425,-2.55099c-0.20389,-0.01517 -0.37631,-0.09155 -0.51753,-0.22859c-0.14093,-0.13732 -0.21169,-0.30525 -0.21169,-0.50352l0,-2.9287c0,-0.19826 0.07855,-0.3735 0.23537,-0.52626c0.14122,-0.15249 0.32144,-0.22101 0.54121,-0.20556c2.41554,0.0761 4.74907,0.50295 6.99999,1.28111c2.25093,0.7776 4.29016,1.84163 6.11799,3.19155c1.82754,1.34963 3.4353,2.91326 4.82329,4.6903s2.48254,3.75994 3.28253,5.94867c0.79969,2.18901 1.23925,4.45778 1.31751,6.80658c0.03119,0.21371 -0.03899,0.38894 -0.21227,0.52598z\"/> </g></g> </g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3340\" label=\"MRSS / Podcast\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Rss url=\"http://podcast.msnbc.com/audio/podcast/MSNBC-YB-NETCAST-M4V.xml\" maintainAspectRatio=\"1\" />' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('mrss')\n            },\n            3235: {\n                name: 'HTML Website content',\n                //color: '#FD6060',\n                color: '#E5E5E5',\n                acronym: 'web',\n                description: 'HTML5 web integration',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect x=\"-1\" y=\"-1\" width=\"52\" height=\"52\" id=\"canvas_background\" fill=\"none\"/> </g> <g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"> <polygon id=\"svg_3\" points=\"12.674722671508789,22.193620681762695 13.99514389038086,27.34623908996582 15.938240051269531,27.34623908996582 18.395078659057617,19.33791732788086 16.39751625061035,19.33791732788086 14.940195083618164,24.58469581604004 13.662463188171387,19.33791732788086 11.712006568908691,19.33791732788086 10.39452838897705,24.58469581604004 8.963705062866211,19.33791732788086 7,19.33791732788086 9.417093276977539,27.34623908996582 11.38374137878418,27.34623908996582 \"/> <polygon id=\"svg_4\" points=\"25.116422653198242,19.33791732788086 23.167438507080078,19.33791732788086 21.84848976135254,24.58469581604004 20.41177749633789,19.33791732788086 18.448070526123047,19.33791732788086 20.86958122253418,27.34623908996582 22.83770179748535,27.34623908996582 24.130155563354492,22.193620681762695 25.453519821166992,27.34623908996582 27.393672943115234,27.34623908996582 29.850509643554688,19.33791732788086 27.857364654541016,19.33791732788086 26.392683029174805,24.58469581604004 \"/> <polygon id=\"svg_5\" points=\"39.30543518066406,19.33791732788086 37.84370040893555,24.58469581604004 36.568912506103516,19.33791732788086 34.61551284790039,19.33791732788086 33.29656219482422,24.58469581604004 31.867204666137695,19.33791732788086 29.900558471679688,19.33791732788086 32.32353973388672,27.34623908996582 34.288719177246094,27.34623908996582 35.581172943115234,22.193620681762695 36.90011978149414,27.34623908996582 38.846160888671875,27.34623908996582 41.30299758911133,19.33791732788086 \"/> <path id=\"svg_6\" d=\"m24.15076,8c-5.90731,0 -10.9888,3.66148 -13.3264,8.92832l26.65427,0c-2.34055,-5.26684 -7.42057,-8.92832 -13.32787,-8.92832z\"/> <path id=\"svg_7\" d=\"m24.15076,38.85087c5.90878,0 10.98438,-3.65993 13.3264,-8.92832l-26.64985,0c2.3376,5.26839 7.41615,8.92832 13.32346,8.92832z\"/></g></g> </g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3235\" label=\"HTML5\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<HTML src=\"http://google.com\" config=\"\" />' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('html5')\n            },\n            3320: {\n                name: 'Clock Date/Time',\n                //color: '#8AC697',\n                color: '#E5E5E5',\n                acronym: 'clock',\n                description: 'Set live local date and time',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect fill=\"none\" id=\"canvas_background\" height=\"52\" width=\"52\" y=\"-1\" x=\"-1\"/></g><g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path d=\"m24.9995,23.47004l6.76257,6.56696l-1.29171,1.20142l-8.17656,-6.59284l-0.15029,-1.0365l0.584,-9.90738l1.69856,0l0.57343,9.76834zm15.15601,0.05438c0,8.00763 -7.16399,14.5 -16,14.5s-16,-6.49237 -16,-14.5s7.16401,-14.5 16,-14.5s16,6.49238 16,14.5zm-2.66685,0c0,-6.67363 -5.96944,-12.08342 -13.33315,-12.08342s-13.33343,5.40979 -13.33343,12.08342c0,6.67336 5.96971,12.08316 13.33343,12.08316s13.33315,-5.40981 13.33315,-12.08316z\" id=\"svg_1\"/></g></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3320\" label=\"Clock Date\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Clock clockFormat=\"custom\" clockMask=\"EEEE, MMM. D, YYYY at L:NN A\">' +\n                        '<Font fontSize=\"11\" fontColor=\"13158\" fontFamily=\"Arial\" fontWeight=\"bold\" fontStyle=\"italic\" textDecoration=\"none\" textAlign=\"center\" />' +\n                        '</Clock>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('clock'),\n                getDateTimeMask: function (i_mask) {\n                    switch (i_mask) {\n                        case 'longDateAndTime': {\n                            return 'EEEE, MMM. D, YYYY at L:NN A';\n                        }\n                        case 'longDate': {\n                            return 'EEEE, MMM. D, YYYY';\n                        }\n                        case 'shortDayTime': {\n                            return 'EEEE L:NN A';\n                        }\n                        case 'date': {\n                            return 'MM/DD/YY';\n                        }\n                        case 'time': {\n                            return 'J:NN:SS A';\n                        }\n                    }\n                }\n            },\n            3241: {\n                name: 'Label text',\n                //color: '#B3F26A',\n                color: '#E5E5E5',\n                acronym: 'text',\n                description: 'Label editor with custom text properties',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect fill=\"none\" id=\"canvas_background\" height=\"52\" width=\"52\" y=\"-1\" x=\"-1\"/></g><g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path d=\"m24.9995,23.47004l6.76257,6.56696l-1.29171,1.20142l-8.17656,-6.59284l-0.15029,-1.0365l0.584,-9.90738l1.69856,0l0.57343,9.76834zm15.15601,0.05438c0,8.00763 -7.16399,14.5 -16,14.5s-16,-6.49237 -16,-14.5s7.16401,-14.5 16,-14.5s16,6.49238 16,14.5zm-2.66685,0c0,-6.67363 -5.96944,-12.08342 -13.33315,-12.08342s-13.33343,5.40979 -13.33343,12.08342c0,6.67336 5.96971,12.08316 13.33343,12.08316s13.33315,-5.40981 13.33315,-12.08316z\" id=\"svg_1\"/></g></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3241\" label=\"Label\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Label>' +\n                        '<Text>some text here!</Text>' +\n                        '<Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />' +\n                        '</Label>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('label')\n            },\n\n            3510: {\n                name: 'Scene',\n                //color: '#BCDEB1',\n                color: '#E5E5E5',\n                acronym: 'scene',\n                description: 'A Scene editor',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect fill=\"none\" id=\"canvas_background\" height=\"52\" width=\"52\" y=\"-1\" x=\"-1\"/></g><g><title>Layer 1</title><g id=\"svg_1\"><g id=\"svg_2\"><path d=\"m24.9995,23.47004l6.76257,6.56696l-1.29171,1.20142l-8.17656,-6.59284l-0.15029,-1.0365l0.584,-9.90738l1.69856,0l0.57343,9.76834zm15.15601,0.05438c0,8.00763 -7.16399,14.5 -16,14.5s-16,-6.49237 -16,-14.5s7.16401,-14.5 16,-14.5s16,6.49238 16,14.5zm-2.66685,0c0,-6.67363 -5.96944,-12.08342 -13.33315,-12.08342s-13.33343,5.40979 -13.33343,12.08342c0,6.67336 5.96971,12.08316 13.33343,12.08316s13.33315,-5.40981 13.33315,-12.08316z\" id=\"svg_1\"/></g></g></g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3510\" label=\"My scene\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonSceneDefaultXML() +\n                        self.getCommonSceneLayout(i_placement, 600, 400) +\n                        '<Scene defaultDuration=\"10\">' +\n                        '<Layout>' +\n                        '<BasicLayout/>' +\n                        '</Layout>' +\n                        '<Players>' +\n                        '</Players>' +\n                        '</Scene>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('scene')\n            },\n            3345: {\n                name: 'Really Simple Syndication',\n                //color: '#FDA401',\n                color: '#E5E5E5',\n                acronym: 'rss',\n                description: 'RSS for daily fresh scrolling news feed',\n                svg: new String('<svg width=\"50\" height=\"50\" xmlns=\"http://www.w3.org/2000/svg\"><g><title>background</title><rect x=\"-1\" y=\"-1\" width=\"52\" height=\"52\" id=\"canvas_background\" fill=\"none\"/> </g> <g><title>Layer 1</title><g id=\"svg_1\"> <g id=\"svg_2\"><circle id=\"svg_3\" r=\"3.21217\" cy=\"33.5\" cx=\"14.5\"/><path id=\"svg_4\" d=\"m11,9l0,5.25c12.565,0 22.75,10.185 22.75,22.75l5.25,0c0,-15.46475 -12.53525,-28 -28,-28z\"/><path id=\"svg_5\" d=\"m23.25,37l5.25,0c0,-9.6635 -7.83475,-17.5 -17.5,-17.5l0,5.25c6.7655,0 12.25,5.4845 12.25,12.25z\"/> </g></g> </g></svg>'),\n                getDefaultPlayerData: function (i_placement) {\n                    return '<Player player=\"3345\" label=\"RSS news\" interactive=\"0\">' +\n                        '<Data>' +\n                        self.getCommonDefaultXML() +\n                        self.getCommonSceneLayout(i_placement) +\n                        '<Rss url=\"http://rss.news.yahoo.com/rss/politics\" minRefreshTime=\"30\" speed=\"10\" vertical=\"0\" rtl=\"0\">' +\n                        '<Title>' +\n                        '<Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />' +\n                        '</Title>' +\n                        '<Description>' +\n                        '<Font fontSize=\"16\" fontColor=\"65280\" fontFamily=\"Arial\" fontWeight=\"normal\" fontStyle=\"normal\" textDecoration=\"none\" textAlign=\"left\" />' +\n                        '</Description>' +\n                        '</Rss>' +\n                        '</Data>' +\n                        '</Player>'\n                },\n                fontAwesome: self.getFontAwesome('rss')\n            }\n        };\n\n        this.commBroker.setService(BLOCK_SERVICE, this)\n    }\n\n    getBlockNameByCode(i_blockCode: number): string {\n        return this.m_blockCodes[i_blockCode];\n    }\n\n    /**\n     Get the common layout which only applies when block is inside a scene\n     @method getCommonSceneLayout\n     @param {string} i_placement\n     @return {String} common xml\n     **/\n    getCommonSceneLayout(i_placement, w ?, h ?) {\n        w = w == undefined ? 100 : w;\n        h = h == undefined ? 100 : h;\n        if (i_placement == PLACEMENT_CHANNEL)\n            return '';\n        return '<Layout rotation=\"0\" x=\"0\" y=\"0\" width=\"' + w + '\" height=\"' + h + '\" />';\n    }\n\n    /**\n     Get the common properties XML with all default values\n     @method getCommonDefaultXML\n     @return {String} common xml\n     **/\n    getCommonDefaultXML() {\n        var self = this;\n        var common = '<Appearance alpha=\"1.0\" blendMode=\"normal\" />' + self.getCommonBackgroundXML() + self.getCommonBorderXML();\n        return common;\n    }\n\n    /**\n     Get the common properties Scene XML with all default values\n     @method getCommonSceneDefaultXML\n     @return {String} common xml\n     **/\n    getCommonSceneDefaultXML() {\n        var self = this;\n        var common = '<Appearance alpha=\"1.0\" blendMode=\"normal\" />' + self.getCommonBorderXML();\n        return common;\n    }\n\n    /**\n     Get the common border XML with all default values\n     @method getCommonBorderXML\n     @return {String} common xml\n     **/\n    getCommonBorderXML() {\n        return '<Border borderThickness=\"0\" borderColor=\"65535\" cornerRadius=\"0\"/>';\n    }\n\n    /**\n     Get the common properties XML with all default values\n     @method getCommonBackgroundXML\n     @return {String} common xml\n     **/\n    getCommonBackgroundXML() {\n        var common = `\n            <Background style=\"Gradient\" gradientType=\"linear\" angle=\"0\" offsetX=\"0\" offsetY=\"0\"> \n                <GradientPoints> \n                    <Point color=\"4361162\" opacity=\"1\" midpoint=\"125\" /> \n                </GradientPoints> \n            </Background>\n            `\n        return common;\n    }\n\n    /**\n     Get a component data structure and properties for a particular component id.\n     @method getBlockBoilerplate\n     @param {Number} i_blockID\n     @return {Object} return the data structure of a specific component\n     **/\n    getBlockBoilerplate(i_blockID) {\n        var self = this;\n        return self.m_components[i_blockID];\n    }\n\n    /**\n     Translate a mimeType to a font-awesome icon of generic icons if does not exist\n     @method getIconFromMimeType\n     @param {Number} i_playerData\n     @return {String} foundMimeIcon\n     **/\n    getIconFromMimeType(i_mimeType) {\n        var self = this;\n        var foundMimeIcon = 'fa-star';\n        var blocks = self.getBlocks();\n        _.forEach(blocks, function (block: any) {\n            if (block.mimeType && block.mimeType == i_mimeType)\n                foundMimeIcon = block.fontAwesome;\n        });\n        return foundMimeIcon\n    }\n\n    /**\n     Get the entire set data structure for all components.\n     @method getBlocks\n     @return {Object} return all data structure\n     **/\n    getBlocks() {\n        var self = this;\n        return self.m_components;\n    }\n\n    /**\n     Retrieve a component code from a file extension type (i.e.: flv > 3100).\n     @method getBlockCodeFromFileExt\n     @param {String} i_fileExtension\n     @return {Number} return component code\n     **/\n    getBlockCodeFromFileExt(i_fileExtension) {\n        var self = this;\n        for (var code in self.m_components) {\n            if (self.m_components[code]['ext'] != undefined) {\n                for (var i = 0; i < self.m_components[code]['ext'].length; i++) {\n                    if (self.m_components[code]['ext'][i] == i_fileExtension) {\n                        return code;\n                    }\n                }\n            }\n        }\n        return -1;\n    }\n\n    /**\n     Get the font awesome path\n     @method getFontAwesome\n     @param {String} i_fontName\n     @return {String} url path\n     **/\n    getFontAwesome(i_fontName) {\n        var self = this;\n        if (_.isUndefined((self.m_fontAwesome[i_fontName])))\n            return undefined;\n        return self.m_fontAwesome[i_fontName]['image'];\n    }\n\n    \n    /**\n     Get the  entire font awesome set\n     @method getFontsAwesome\n     @return {Object} data set\n     **/\n    getFontsAwesome() {\n        var self = this;\n        return self.m_fontAwesome;\n    }\n\n    /**\n     Convert player data to json format\n     @method playerDataTojson\n     @param {String} i_playerData\n     @return {Json} jPlayerData\n     **/\n    playerDataTojson(i_playerData) {\n        // var x2js = BB.comBroker.getService('compX2JS');\n        // var jPlayerData = x2js.xml_str2json(i_playerData);\n        // return jPlayerData;\n    }\n\n    /**\n     Convert player data to xml format\n     @method playerDataToxml\n     @param {String} i_playerData\n     @return {XML} xml data\n     **/\n    playerDataToxml(i_playerData) {\n        // var x2js = BB.comBroker.getService('compX2JS');\n        // var xPlayerData = x2js.json2xml_str(i_playerData);\n        // return xPlayerData;\n    }\n\n    public getServiceType(): string {\n        return this.blockPlacement;\n    }\n\n    public getBlockDataInScene(i_sceneData: ISceneData): Observable<IBlockData> {\n        let domPlayerData = i_sceneData.domPlayerData\n        let playerMimeScene = i_sceneData.mimeType;\n        let playerDataJson = this.parser.xml2js(i_sceneData.domPlayerDataXml);\n        let code = playerDataJson['Player']['_player'];\n        let blockType: any = this.getBlockNameByCode(code)\n        var sceneData = {\n            name: '',\n            handle: i_sceneData.scene_id,\n            playerDataJson: null,\n            playerDataDom: null\n        }\n        var data: IBlockData = {\n            blockID: i_sceneData.block_pseudo_id,\n            blockType: blockType,\n            blockCode: code,\n            blockName: this.getBlockBoilerplate(code).name,\n            blockDescription: this.getBlockBoilerplate(code).description,\n            blockIcon: this.getBlockBoilerplate(code).icon,\n            blockFontAwesome: this.getBlockBoilerplate(code).fontAwesome,\n            blockAcronym: this.getBlockBoilerplate(code).acronym,\n            blockMinWidth: this.m_minSize.w,\n            blockMinHeight: this.m_minSize.h,\n            playerDataDom: domPlayerData,\n            playerDataJson: playerDataJson,\n            playerMimeScene: playerMimeScene,\n            playerDataJsonHandle: null,\n            duration: -1,\n            offset: -1,\n            campaignTimelineChanelPlayersModelExt: null,\n            scene: sceneData\n        };\n        return Observable.of(data);\n    }\n\n    public getBlockData(blockId): Observable<IBlockData> {\n\n        return this.yp.getChannelBlockRecord(blockId)\n            .mergeMap((i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModelExt) => {\n                // var t0 = performance.now();\n                var xml = i_campaignTimelineChanelPlayersModel.getPlayerData();\n                var code: any;\n                var playerMimeScene;\n                var playerDataJsonHandle;\n                var playerDataDom = $.parseXML(xml);\n                let playerDataJson = this.parser.xml2js(xml);\n                if (playerDataJson['Player']['_player']) {\n\n                    /************************************\n                     * Block\n                     ************************************/\n\n                    code = playerDataJson['Player']['_player'];\n                    var blockType = this.getBlockNameByCode(code)\n                    playerMimeScene = playerDataJson.Player.Data.Json ? `Json.${playerDataJson.Player.Data.Json._providerType}` : null;\n                    playerDataJsonHandle = (playerDataJson.Player.Data.Json && playerDataJson.Player.Data.Json.Player) ? playerDataJson.Player.Data.Json.Player : null;\n\n                    if (_.isUndefined(blockType)) {\n                        var e = `Panic using a component / block which is not supported yet ${code} ${blockType}`;\n                        throw new Error(e)\n                    }\n                    // console.log(`Serialization of block ${code} took ${(performance.now() - t0)} milliseconds`)\n\n                } else {\n\n                    /************************************\n                     * Block is a scene\n                     ************************************/\n\n                    code = BlockLabels['BLOCKCODE_SCENE'];\n                    var blockType = this.getBlockNameByCode(code)\n                    var sceneData = {\n                        name: '',\n                        handle: jXML(playerDataDom).find('Player').attr('hDataSrc'),\n                        playerDataJson: null,\n                        playerDataDom: null\n                    }\n                }\n\n                var data: IBlockData = {\n                    blockID: blockId,\n                    blockType: blockType,\n                    blockCode: code,\n                    blockName: this.getBlockBoilerplate(code).name,\n                    blockDescription: this.getBlockBoilerplate(code).description,\n                    blockIcon: this.getBlockBoilerplate(code).icon,\n                    blockFontAwesome: this.getBlockBoilerplate(code).fontAwesome,\n                    blockAcronym: this.getBlockBoilerplate(code).acronym,\n                    blockMinWidth: this.m_minSize.w,\n                    blockMinHeight: this.m_minSize.h,\n                    playerDataDom: playerDataDom,\n                    playerDataJson: playerDataJson,\n                    playerMimeScene: playerMimeScene,\n                    playerDataJsonHandle: playerDataJsonHandle,\n                    duration: i_campaignTimelineChanelPlayersModel.getPlayerDurationInt(),\n                    offset: i_campaignTimelineChanelPlayersModel.getPlayerOffsetTimeInt(),\n                    campaignTimelineChanelPlayersModelExt: i_campaignTimelineChanelPlayersModel,\n                    scene: sceneData\n                };\n                return Observable.of(data)\n\n            }).mergeMap((blockData: any) => {\n\n                /** additional data for: scenes **/\n                if (blockData.scene) {\n                    return this.yp.getScenePlayerdataDom(blockData.scene.handle)\n                        .map((xml: string) => {\n                            var domPlayerData = $.parseXML(xml)\n                            blockData.scene.name = jXML(domPlayerData).find('Player').eq(0).attr('label');\n                            blockData.scene.playerDataDom = domPlayerData;\n                            blockData.scene.playerDataJson = this.parser.xml2js(xml);\n                            return blockData;\n                        })\n                } else {\n                    return Observable.of(blockData);\n                }\n\n                /** additional data for: resources (images, videos, svg ) fill additional data (make exception for collection | location) **/\n            }).mergeMap((blockData: IBlockData) => {\n\n                if (Number(blockData.blockCode) == BlockLabels.BLOCKCODE_COLLECTION || Number(blockData.blockCode) == BlockLabels.LOCATION)\n                    return Observable.of(blockData);\n\n                var domPlayerData = blockData.playerDataDom;\n                var xSnippet = jXML(domPlayerData).find('Resource');\n                if (xSnippet.length > 0) {\n                    blockData.resource = {\n                        handle: jXML(xSnippet).attr('hResource'),\n                        name: '',\n                        type: ''\n                    };\n                    return this.yp.getResourceRecord(blockData.resource.handle)\n                        .map((i_resourcesModel: ResourcesModel) => {\n                            // todo: temp hack till resolved\n                            if (_.isUndefined(i_resourcesModel)) {\n                                blockData.resource.name = '???';\n                                blockData.resource.type = '';\n                            } else {\n                                blockData.resource.name = i_resourcesModel.getResourceName()\n                                blockData.resource.type = i_resourcesModel.getResourceType()\n                            }\n                            return blockData;\n                        })\n                }\n                return Observable.of(blockData);\n            })\n    }\n\n    /**\n     Help method to get the proper playerDataDom depending of we are dealing with a regular block or a scene block\n     **/\n    getBlockPlayerData(i_blockData: IBlockData): XMLDocument {\n\n\n        switch (this.blockPlacement) {\n\n            case PLACEMENT_CHANNEL: {\n                switch (Number(i_blockData.blockCode)) {\n                    case BlockLabels.BLOCKCODE_SCENE: {\n                        return i_blockData.scene.playerDataDom;\n                    }\n                    default: {\n                        return i_blockData.playerDataDom;\n                    }\n                }\n            }\n\n            case PLACEMENT_SCENE: {\n\n                switch (Number(i_blockData.blockCode)) {\n                    case BlockLabels.BLOCKCODE_SCENE: {\n                        return i_blockData.playerDataDom;\n                    }\n                    default: {\n                        return i_blockData.playerDataDom;\n                    }\n                }\n\n            }\n        }\n    }\n\n    notifySceneBgChanged() {\n        this.commBroker.fire({event: 'SCENE_CHANGE', fromInstance: this, message: []});\n    }\n\n    notifySceneBlockChanged(i_block: string | IBlockData) {\n        if (i_block['blockID']) i_block = i_block['blockID'];\n        this.commBroker.fire({event: 'SCENE_BLOCK_CHANGE', fromInstance: this, message: [i_block]});\n    }\n\n    notifyReloadScene(i_sceneId) {\n        var uiState: IUiState = {scene: {sceneSelected: -1, blockSelected: -1}}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        var uiState: IUiState = {scene: {sceneSelected: i_sceneId, blockSelected: -1}}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        // if (i_block['blockID']) i_block = i_block['blockID'];\n        // this.commBroker.fire({event: 'LOAD_SCENE', fromInstance: this, message: [i_block]});\n    }\n\n    /**\n     Update the msdb for the block with new values inside its player_data\n     **/\n    setBlockPlayerData(blockData: IBlockData, i_xmlDoc: XMLDocument | string) {\n        var player_data: string, player_data_json;\n\n        if (i_xmlDoc instanceof XMLDocument) {\n            player_data = (new XMLSerializer()).serializeToString(i_xmlDoc as XMLDocument);\n        } else {\n            player_data = i_xmlDoc as string;\n        }\n        player_data_json = this.parser.xml2js(player_data);\n        player_data = this.rp.ieFixEscaped(player_data);\n        var playerCode = Number(player_data_json.Player._player);\n        switch (this.blockPlacement) {\n\n            case PLACEMENT_CHANNEL: {\n                switch (playerCode) {\n                    /***** scene *****/\n                    case BlockLabels.BLOCKCODE_SCENE: {\n                        this.yp.getChannelBlockRecord(blockData.blockID)\n                            .subscribe((i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModelExt) => {\n                                var domPlayerData = $.parseXML(i_campaignTimelineChanelPlayersModel.getPlayerData());\n                                var scene_id = jXML(domPlayerData).find('Player').attr('hDataSrc');\n                                this.rp.setScenePlayerData(scene_id, player_data);\n                            })\n                        break;\n                    }\n                    /***** all block *****/\n                    default: {\n                        this.rp.setCampaignTimelineChannelPlayerRecord(blockData.blockID, 'player_data', player_data);\n                    }\n                }\n                break;\n            }\n\n            case PLACEMENT_SCENE: {\n                switch (playerCode) {\n                    /***** scene *****/\n                    case BlockLabels.BLOCKCODE_SCENE: {\n                        this.rp.setScenePlayerData(blockData.blockID, player_data);\n                        break;\n                    }\n                    /***** all blocks *****/\n                    default: {\n                        this.rp.setScenePlayerdataBlock(blockData.scene.handle, blockData.blockID, player_data);\n                    }\n                }\n                break;\n            }\n        }\n        this.rp.reduxCommit();\n    }\n\n\n}\n\n\n// export const MapMimeProviders = {\n//     'weather': 'Json.weather',\n//     'instagram.feed': 'Json.instagram.feed',\n// }\n//instagram.media\n"
  },
  {
    "path": "src/app/blocks/json-event-grid.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, Input, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {ISimpleGridEdit} from \"../../comps/simple-grid-module/SimpleGrid\";\nimport {StoreModel} from \"../../store/model/StoreModel\";\nimport {BlockService, IBlockData} from \"./block-service\";\nimport {SimpleGridRecord} from \"../../comps/simple-grid-module/SimpleGridRecord\";\nimport {SimpleGridTable} from \"../../comps/simple-grid-module/SimpleGridTable\";\nimport {List} from \"immutable\";\nimport * as _ from \"lodash\";\n\n\nexport class JsonEventResourceModel extends StoreModel {\n    constructor(data: {\n                    rowIndex: number;\n                    checkbox: boolean;\n                    event: string;\n                    pageName: string;\n                    action: string;\n                }) {\n        super(data);\n    }\n}\n\n@Component({\n    selector: 'json-event-grid',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <label i18n>On event take the following action</label>\n        <h4 class=\"panel-title\" style=\"padding-bottom: 15px\">\n            <button (click)=\"_onAddNewEvent()\" type=\"button\" title=\"add event\" class=\"btn btn-default btn-sm\">\n                <span class=\"fa fa-plus\"></span>\n            </button>\n            <button (click)=\"_onRemoveEvent()\" type=\"button\" title=\"remove event\" class=\"btn btn-default btn-sm\">\n                <span class=\"fa fa-minus\"></span>\n            </button>\n        </h4>\n        <div style=\"overflow-x: scroll\">\n            <div style=\"width: 600px\">\n                <simpleGridTable #simpleGrid>\n                    <thead>\n                    <tr>\n                        <th>event</th>\n                        <th>action</th>\n                        <th>go to</th>\n                    </tr>\n                    </thead>\n                    <tbody>\n                    <tr class=\"simpleGridRecord\" simpleGridRecord *ngFor=\"let item of m_events; let index=index\" [item]=\"item\" [index]=\"index\">\n                        <td simpleGridData style=\"width: 30%\" [editable]=\"true\" (labelEdited)=\"_onLabelEdited($event,index)\" field=\"event\" [item]=\"item\"></td>\n                        <td simpleGridDataDropdown style=\"width: 35%\" [testSelection]=\"_selectedAction()\" (changed)=\"_setAction($event,index)\" field=\"name\" [item]=\"item\" [dropdown]=\"m_actions\"></td>\n                        <td simpleGridData *ngIf=\"m_mode == 'url'\" style=\"width: 35%\" [editable]=\"true\" (labelEdited)=\"_onUrlEdited($event,index)\" field=\"url\" [item]=\"item\"></td>\n                        <td simpleGridDataDropdown *ngIf=\"m_mode == 'page'\" style=\"width: 35%\" [testSelection]=\"_selectedResource()\" (changed)=\"_onPageEdited($event,index)\" field=\"name\" [item]=\"item\" [dropdown]=\"m_collectionList\"></td>\n                    </tr>\n                    </tbody>\n                </simpleGridTable>\n            </div>\n        </div>\n    `\n})\nexport class JsonEventGrid extends Compbaser implements AfterViewInit {\n\n    m_blockData: IBlockData;\n    m_events: List<StoreModel>;\n    m_actions: List<StoreModel>;\n    m_collectionList: List<StoreModel>;\n    m_mode: 'url' | 'page';\n    m_jsonEventResources: Array<JsonEventResourceModel>;\n\n    constructor(private yp: YellowPepperService, private bs: BlockService) {\n        super();\n        this.m_actions = List([\n            new StoreModel({name: 'firstPage'}),\n            new StoreModel({name: 'nextPage'}),\n            new StoreModel({name: 'prevPage'}),\n            new StoreModel({name: 'lastPage'}),\n            new StoreModel({name: 'loadUrl'}),\n            new StoreModel({name: 'selectPage'})\n        ]);\n    }\n\n    @ViewChild('simpleGrid')\n    simpleGrid: SimpleGridTable;\n\n    @Input()\n    set setBlockData(i_blockData) {\n        this.m_blockData = i_blockData;\n        this._render();\n    }\n\n    @Input()\n    set resources(i_jsonEventResources: Array<JsonEventResourceModel>) {\n        this.m_jsonEventResources = i_jsonEventResources;\n    }\n\n    @Input()\n    set collectionList(i_collectionList) {\n        this.m_collectionList = i_collectionList;\n    }\n\n    @Input()\n    set showOption(i_value: 'url' | 'page') {\n        this.m_mode = i_value;\n        if (i_value == 'url') {\n            this.m_actions = this.m_actions.filter((v: StoreModel) => {\n                return v.getKey('name') != 'selectPage';\n            }) as List<any>;\n            return;\n        }\n        if (i_value == 'page') {\n            this.m_actions = this.m_actions.filter((v: StoreModel) => {\n                return v.getKey('name') != 'loadUrl';\n            }) as List<any>;\n            return;\n        }\n    }\n\n    _render() {\n        this._initEventTable();\n    }\n\n    /**\n     Load event list to block props UI\n     @method _initEventTable\n     **/\n    _initEventTable() {\n        var rowIndex = 0;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var events = [];\n        jXML(domPlayerData).find('EventCommands').children().each((k, eventCommand) => {\n            var url = '';\n            if (jXML(eventCommand).attr('command') == 'loadUrl')\n                url = jXML(eventCommand).find('Url').attr('name');\n            if (jXML(eventCommand).attr('command') == 'selectPage')\n                url = jXML(eventCommand).find('Page').attr('name');\n            if (_.isUndefined(url) || _.isEmpty(url))\n                url = '---';\n            var storeModel = new StoreModel({\n                id: rowIndex,\n                event: jXML(eventCommand).attr('from'),\n                url: url,\n                action: jXML(eventCommand).attr('command')\n            });\n            events.push(storeModel)\n            rowIndex++;\n        });\n        this.m_events = List(events)\n    }\n\n    _setAction(event: ISimpleGridEdit, index: number) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var target = jXML(domPlayerData).find('EventCommands').children().get(index);\n        jXML(target).attr('command', event.value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _onRemoveEvent() {\n        var record: SimpleGridRecord = this.simpleGrid.getSelected();\n        if (_.isUndefined(record)) return;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        jXML(domPlayerData).find('EventCommands').children().eq(record.index).remove();\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData)\n    }\n\n    _onAddNewEvent() {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var buff = '<EventCommand from=\"event\" condition=\"\" command=\"firstPage\" />';\n        jXML(domPlayerData).find('EventCommands').append(jXML(buff));\n        // domPlayerData = this.rp.xmlToStringIEfix(domPlayerData)\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _selectedAction() {\n        return (a: StoreModel, b: StoreModel) => {\n            return a.getKey('name') == b.getKey('action') ? 'selected' : '';\n        }\n    }\n\n    _selectedResource() {\n        return (a: StoreModel, b: StoreModel) => {\n            return a.getKey('name') == b.getKey('url') ? 'selected' : '';\n        }\n    }\n\n    _onUrlEdited(event: ISimpleGridEdit, index) {\n        var url = event.value;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var target = jXML(domPlayerData).find('EventCommands').children().get(parseInt(index));\n        jXML(target).find('Params').remove();\n        jXML(target).append('<Params> <Url name=\"' + url + '\" /></Params>');\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _onPageEdited(event: ISimpleGridEdit, index) {\n        var page = event.value;\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var target = jXML(domPlayerData).find('EventCommands').children().get(parseInt(index));\n        jXML(target).find('Params').remove();\n        jXML(target).append('<Params><Page name=\"' + page + '\"/></Params>');\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    _onLabelEdited(event: ISimpleGridEdit, index) {\n        var domPlayerData = this.m_blockData.playerDataDom;\n        var target = jXML(domPlayerData).find('EventCommands').children().get(index);\n        jXML(target).attr('from', event.value);\n        this.bs.setBlockPlayerData(this.m_blockData, domPlayerData);\n    }\n\n    ngAfterViewInit() {\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/add-content.ts",
    "content": "import {AfterViewInit, Component, EventEmitter, Inject, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {BlockService, ISceneData} from \"../blocks/block-service\";\nimport {UserModel} from \"../../models/UserModel\";\nimport {ResourcesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {IAddContents} from \"../../interfaces/IAddContent\";\nimport {BlockTypeEnum} from \"../../interfaces/BlockTypeEnum\";\nimport {BlockLabels, Consts, PLACEMENT_CHANNEL, PLACEMENT_LISTS, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {CommBroker} from \"../../services/CommBroker\";\nimport {ADD_NEW_BLOCK_SCENE} from \"../scenes/scene-editor\";\nimport {Lib} from \"../../Lib\";\nimport {List} from \"immutable\";\nimport * as _ from \"lodash\";\nimport {BehaviorSubject} from \"rxjs/BehaviorSubject\";\nimport {Subject} from \"rxjs/Subject\";\nimport {Observer} from \"rxjs/Observer\";\nimport {Observable} from \"rxjs/Observable\";\n\n@Component({\n    selector: 'add-content',\n    styles: [`\n        .nowAllowed {\n            opacity: 0.4;\n        }\n\n        .btn-primary {\n            position: relative;\n            top: -45px\n        }\n\n        li:hover {\n            background-color: #dadada;\n            cursor: pointer;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <!--<button *ngIf=\"m_placement == m_PLACEMENT_CHANNEL\" (click)=\"_close()\" id=\"prev\" type=\"button\" class=\"openPropsButton btn btn-default btn-sm\">-->\n        <!--<span class=\"glyphicon glyphicon-chevron-left\"></span>-->\n        <!--</button>-->\n        <input [(ngModel)]=\"m_filter\" style=\"width: 300px; margin-right: 30px\" class=\"form-control pull-right\" placeholder=\"search for\" required=\"\">        \n        <div style=\"padding-top: 20px; padding-right: 30px\" class=\"panel-group clearFloat\" id=\"accordion\" role=\"tablist\" aria-multiselectable=\"true\">\n            <div *ngIf=\"m_placement == m_PLACEMENT_SCENE || m_placement == m_PLACEMENT_CHANNEL\" class=\"panel panel-default\">\n                <div class=\"panel-heading\" role=\"tab\" id=\"headingOne\">\n                    <h4 class=\"panel-title\">\n                        <a role=\"button\" data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseOne\" aria-expanded=\"false\" aria-controls=\"collapseOne\">\n                            Components\n                        </a>\n                    </h4>\n                </div>\n                <div id=\"collapseOne\" class=\"panel-collapse collapse in\" role=\"tabpanel\" aria-labelledby=\"headingOne\">\n                    <div class=\"panel-body\">\n                        <ul class=\"list-group\" id=\"addComponentBlockList\" style=\"padding:20px\">\n                            <li (click)=\"_onComponentSelected(component)\" \n                                *ngFor=\"let component of m_componentList\"\n                                [class.hidden]=\"component | FilterModelPipe:m_filter:component:'name'\"\n                                class=\"list-group-item\">\n                                <i [ngClass]=\"{nowAllowed: !component.allow}\" style=\"display: inline\" class=\"fa fa-2x {{component.fa}}\"></i>\n                                <h3 [ngClass]=\"{nowAllowed: !component.allow}\" style=\" display: inline\"> {{component.name}} </h3>\n                                <h6 [ngClass]=\"{nowAllowed: !component.allow}\"> {{component.description}}</h6>\n                                <button (click)=\"_onUpgEnterprise($event)\" class=\"btn btn-primary pull-right\" *ngIf=\"!component.allow\">\n                                    upgrade to enterprise\n                                </button>\n                            </li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading\" role=\"tab\" id=\"headingTwo\">\n                    <h4 class=\"panel-title\">\n                        <a class=\"collapsed\" role=\"button\" data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseTwo\" aria-expanded=\"false\" aria-controls=\"collapseTwo\">\n                            Resources\n                        </a>\n                    </h4>\n                </div>\n                <div id=\"collapseTwo\" class=\"panel-collapse collapse in\" role=\"tabpanel\" aria-labelledby=\"headingTwo\">\n                    <div class=\"panel-body\">\n                        <ul class=\"list-group\" id=\"addComponentBlockList\" style=\"padding:20px\">\n                            <li (click)=\"_onResourceSelected(resource)\"\n                                *ngFor=\"let resource of m_resourceList\" class=\"list-group-item\"\n                                [class.hidden]=\"resource | FilterModelPipe:m_filter:resource:'name'\">\n                                <i style=\"display: inline\" class=\"fa fa-2x {{resource.fa}}\"></i>\n                                <h3 style=\" display: inline\"> {{resource.name}} </h3>\n                                <h6> {{resource.description}}</h6>\n                            </li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n            <div *ngIf=\"m_placement == m_PLACEMENT_LISTS || m_placement == m_PLACEMENT_CHANNEL\" class=\"panel panel-default\">\n                <div class=\"panel-heading\" role=\"tab\" id=\"headingThree\">\n                    <h4 class=\"panel-title\">\n                        <a class=\"collapsed\" role=\"button\" data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseThree\" aria-expanded=\"false\" aria-controls=\"collapseThree\">\n                            Scenes\n                        </a>\n                    </h4>\n                </div>\n                <div id=\"collapseThree\" class=\"panel-collapse collapse in\" role=\"tabpanel\" aria-labelledby=\"headingThree\">\n                    <div class=\"panel-body\">\n                        <ul class=\"list-group\" id=\"addComponentBlockList\" style=\"padding:20px\">\n                            <li (click)=\"_onSceneSelected(scene)\" *ngFor=\"let scene of m_sceneList\"\n                                [class.hidden]=\"scene | FilterModelPipe:m_filter:scene:'name'\"\n                                class=\"list-group-item\">\n                                <i style=\"display: inline\" class=\"fa fa-2x {{scene.fa}}\"></i>\n                                <h3 style=\" display: inline\"> {{scene.name}} </h3>\n                            </li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <!--<ul class=\"list-group\" id=\"addComponentBlockList\" style=\"padding:20px\">-->\n        <!--<li (click)=\"_onComponentSelected(component)\" *ngFor=\"let component of m_componentList\" class=\"list-group-item \">-->\n        <!--<i [ngClass]=\"{nowAllowed: !component.allow}\" style=\"display: inline\" class=\"fa fa-2x {{component.fa}}\"></i>-->\n        <!--<h3 [ngClass]=\"{nowAllowed: !component.allow}\" style=\" display: inline\"> {{component.name}} </h3>-->\n        <!--<h6 [ngClass]=\"{nowAllowed: !component.allow}\"> {{component.description}}</h6>-->\n        <!--<button (click)=\"_onUpgEnterprise($event)\" class=\"btn btn-primary pull-right\" *ngIf=\"!component.allow\">-->\n        <!--upgrade to enterprise-->\n        <!--</button>-->\n        <!--</li>-->\n        <!--</ul>-->\n\n    `\n})\nexport class AddContent extends Compbaser implements AfterViewInit {\n    m_placement;\n    m_sceneMime;\n    m_filter;\n    m_userModel: UserModel;\n    m_resourceModels: List<ResourcesModel>;\n    m_sceneDatas: Array<ISceneData>;\n    m_componentList: Array<IAddContents> = [];\n    m_resourceList: Array<IAddContents> = [];\n    m_sceneList: Array<IAddContents> = [];\n    m_PLACEMENT_SCENE = PLACEMENT_SCENE;\n    m_PLACEMENT_LISTS = PLACEMENT_LISTS;\n    m_PLACEMENT_CHANNEL = PLACEMENT_CHANNEL;\n\n    constructor(@Inject('HYBRID_PRIVATE') private hybrid_private: boolean,\n                private commBroker: CommBroker,\n                private yp: YellowPepperService,\n                private bs: BlockService) {\n        super();\n\n        this.cancelOnDestroy(\n            //\n            this.yp.getUserModel()\n                .subscribe((i_userModel: UserModel) => {\n                    this.m_userModel = i_userModel;\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenResources()\n                .subscribe((i_resources: List<ResourcesModel>) => {\n                    this.m_resourceModels = i_resources;\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.getScenes()\n                .subscribe((i_playerDatas: Array<ISceneData>) => {\n                    this.m_sceneDatas = i_playerDatas;\n                }, (e) => console.error(e))\n        )\n    }\n\n    @Input()\n    set placement(i_value) {\n        this.m_placement = i_value;\n        switch (i_value) {\n            case PLACEMENT_LISTS: {\n                break;\n            }\n            case PLACEMENT_CHANNEL: {\n                var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                break;\n            }\n            case PLACEMENT_SCENE: {\n                var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                break;\n            }\n        }\n        this._render();\n    }\n\n    // @Output()\n    // onAddContentSelected: EventEmitter<IAddContents> = new EventEmitter<IAddContents>();\n\n    // @Output()\n    // onClosed: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onClosed: Observable<any> = new Subject().debounceTime(200).delay(333);\n\n    @Output()\n    onAddContentSelected: Observable<any> = new Subject().debounceTime(200);\n\n    _addBlock(i_addContents: IAddContents) {\n        switch (this.m_placement) {\n            case PLACEMENT_CHANNEL: {\n                (this.onAddContentSelected as Subject<any>).next(i_addContents)\n                // this.onAddContentSelected.emit(i_addContents)\n                break;\n            }\n\n            case PLACEMENT_LISTS: {\n                (this.onAddContentSelected as Subject<any>).next(i_addContents)\n                // this.onAddContentSelected.emit(i_addContents)\n                break;\n            }\n\n            case PLACEMENT_SCENE: {\n                this.commBroker.fire({event: ADD_NEW_BLOCK_SCENE, fromInstance: this, message: i_addContents});\n                break;\n            }\n        }\n    }\n\n    ngAfterViewInit() {\n        this._render();\n    }\n\n    _onUpgEnterprise(event: MouseEvent) {\n        event.stopImmediatePropagation();\n        event.preventDefault();\n        this.commBroker.fire({event: Consts.Events().UPGRADE_ENTERPRISE, fromInstance: this, message: ''});\n    }\n\n    _onComponentSelected(i_component) {\n        if (!i_component.allow)\n            return bootbox.alert('Please upgrade to the Enterprise edition')\n        this._addBlock(i_component);\n        this._close();\n    }\n\n    _onResourceSelected(i_resource) {\n        this._addBlock(i_resource);\n        this._close();\n    }\n\n    _onSceneSelected(i_scene) {\n        this._addBlock(i_scene);\n        this._close();\n    }\n\n    _close() {\n        (this.onClosed as Subject<any>).next();\n    }\n\n    /**\n     Build lists of components, resources and scenes (respectively showing what's needed per placement mode)\n     Once an LI is selected proper event fired to announce block is added.\n     @method _render\n     @return none\n     **/\n    _render() {\n        this.m_componentList = [];\n        this.m_sceneList = []\n\n\n        /////////////////////////////////////////////////////////\n        // component selection list\n        /////////////////////////////////////////////////////////\n        var components = this.bs.getBlocks();\n        var specialJsonItemName = '';\n        var specialJsonItemColor = '';\n        //var sceneHasMimeType = '';\n\n        for (var i_componentID in components) {\n            var componentID: any = i_componentID;\n\n            if (componentID == BlockLabels.BLOCKCODE_IMAGE ||\n                componentID == BlockLabels.BLOCKCODE_SVG ||\n                componentID == BlockLabels.BLOCKCODE_TWITTER ||\n                componentID == BlockLabels.BLOCKCODE_TWITTER_ITEM ||\n                componentID == BlockLabels.BLOCKCODE_VIDEO ||\n                componentID == BlockLabels.BLOCKCODE_SCENE ||\n                (this.m_placement == PLACEMENT_CHANNEL && componentID == BlockLabels.BLOCKCODE_JSON_ITEM) ||\n                (this.m_placement == PLACEMENT_CHANNEL && componentID == BlockLabels.BLOCKCODE_TWITTER_ITEM) ||\n                (this.m_placement == PLACEMENT_SCENE && componentID == BlockLabels.BLOCKCODE_JSON) ||\n                (this.m_placement == PLACEMENT_SCENE && componentID == BlockLabels.BLOCKCODE_WORLD_WEATHER) ||\n                (this.m_placement == PLACEMENT_SCENE && componentID == BlockLabels.BLOCKCODE_GOOGLE_SHEETS) ||\n                (this.m_placement == PLACEMENT_SCENE && componentID == BlockLabels.BLOCKCODE_TWITTER)) {\n                continue;\n            }\n\n            // if PLACEMENT_SCENE and mimetype is set to specific, don't show any JSON based players\n            if (this.m_sceneMime && this.m_placement == PLACEMENT_SCENE) {\n                var jsonBasedPlayerXML = this.bs.getBlockBoilerplate(componentID).getDefaultPlayerData(PLACEMENT_SCENE);\n                jsonBasedPlayerXML = $.parseXML(jsonBasedPlayerXML);\n                if ($(jsonBasedPlayerXML).find('Json').length > 0)\n                    continue;\n            }\n\n            // if PLACEMENT_SCENE and mimetype is set on scene, give special attention to JSON_ITEM component since it will often be the one user needs\n            if (this.m_sceneMime && this.m_placement == PLACEMENT_SCENE && componentID == BlockLabels.BLOCKCODE_JSON_ITEM) {\n                specialJsonItemName = Lib.CapitaliseFirst(this.m_sceneMime.split('.')[1]);\n                // specialJsonItemColor = BB.CONSTS['THEME'] === 'light' ? '#A9CFFA' : '#262627';\n            } else {\n                specialJsonItemName = '';\n                specialJsonItemColor = '';\n            }\n\n            // check if and how to render components depending on user account type\n            var status = this._checkAllowedComponent(componentID)\n            switch (status) {\n                case 0: {\n                    continue;\n                }\n                case 1:\n                case 2: {\n                    this.m_componentList.push({\n                        blockId: componentID,\n                        type: BlockTypeEnum.COMPONENT,\n                        allow: status == 1 ? true : false,\n                        blockCode: componentID,\n                        name: components[componentID].name,\n                        fa: components[componentID].fontAwesome,\n                        specialJsonItemName: specialJsonItemName,\n                        specialJsonItemColor: specialJsonItemColor,\n                        description: components[componentID].description\n\n                    })\n                    break;\n                }\n            }\n        }\n\n\n        /////////////////////////////////////////////////////////\n        // show resource selection list\n        /////////////////////////////////////////////////////////\n\n        // var recResources = pepper.listenResources();\n        this.m_resourceModels.forEach((i_resourcesModel: ResourcesModel) => {\n            var size = (i_resourcesModel.getResourceBytesTotal() / 1000).toFixed(2);\n            var resourceDescription = 'size: ' + size;\n            this.m_resourceList.push({\n                resourceId: i_resourcesModel.getResourceId(),\n                type: BlockTypeEnum.RESOURCE,\n                name: i_resourcesModel.getResourceName(),\n                blockCode: this.bs.getBlockCodeFromFileExt(i_resourcesModel.getResourceType()) as number,\n                size: size,\n                allow: true,\n                fa: this.bs.getFontAwesome(i_resourcesModel.getResourceType()),\n                description: resourceDescription\n            })\n        })\n\n        /////////////////////////////////////////////////////////\n        // show scene selection list in Scene or block list modes\n        /////////////////////////////////////////////////////////\n\n        if (this.m_placement == PLACEMENT_CHANNEL || this.m_placement == PLACEMENT_LISTS) {\n            this.m_sceneDatas.forEach((i_sceneData: ISceneData) => {\n                var label = $(i_sceneData.domPlayerData).find('Player').eq(0).attr('label');\n                var mimeType = $(i_sceneData.domPlayerData).find('Player').eq(0).attr('mimeType');\n\n                // don't allow adding mimetype scenes to channels directly as needs to be added via Player block\n                if (this.m_placement == PLACEMENT_CHANNEL) {\n                    if (!_.isUndefined(mimeType))\n                        return;\n                }\n                this.m_sceneList.push({\n                    sceneData: i_sceneData,\n                    type: BlockTypeEnum.SCENE,\n                    blockCode: 3510,\n                    name: label,\n                    fa: this.bs.getFontAwesome('scene'),\n                    allow: true,\n                    description: 'scene'\n                })\n            })\n        }\n\n        //reset mimetype\n        this.m_sceneMime = undefined;\n    }\n\n\n    /**\n     Check if component is allowed under enterprise / prime membership\n     Note that if running under Hybrid or Private server default is to always allow\n     all components\n     @method _checkAllowedComponent\n     @param {Number} i_componentID\n     @return {Number} 0 = hide, 1 = show, 2 = upgradable\n     **/\n    _checkAllowedComponent(i_componentID) {\n        // include all\n        if (this.hybrid_private)\n            return 1;\n\n        // FasterQ, open to all\n        if (i_componentID == 6100) {\n            return 1;\n        }\n\n        var appID = this.bs.getBlockBoilerplate(i_componentID).app_id;\n        if (_.isUndefined(appID))\n            return 1;\n\n        // component is prime, account is free type, upgradable\n        if (this.m_userModel.getKey('resellerId') == 1)\n            return 2;\n\n        // account is under a reseller and component not available, hide it\n        if (this.m_userModel.getKey('resellerId') != 1 && _.isUndefined(this.m_userModel.getKey('components')[appID]))\n            return 0;\n\n        // account is under a reseller and component is available, show it\n        return 1;\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/campaigns/campaign-channels.ts",
    "content": "import {AfterViewInit, ChangeDetectorRef, Component, Input, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {CampaignTimelineBoardViewerChanelsModel, CampaignTimelineChanelPlayersModel, CampaignTimelineChanelsModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {BlockService, IBlockData} from \"../blocks/block-service\";\nimport {Observable, Subject} from \"rxjs\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Once} from \"../../decorators/once-decorator\";\nimport {List} from \"immutable\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {DraggableList} from \"../../comps/draggable-list/draggable-list\";\nimport {IAddContents} from \"../../interfaces/IAddContent\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Lib} from \"../../Lib\";\n\n\n@Component({\n    selector: 'campaign-channels',\n    styles: [`\n        * {\n            font-size: 1.1em !important;\n        }\n\n        .dragch {\n            float: right;\n            padding-right: 10px;\n            position: relative;\n            top: 5px;\n        }\n\n        .lengthTimer {\n            float: right;\n            padding-right: 10px;\n        }\n\n        .listItems {\n            cursor: pointer;\n        }\n\n        .listItems a i {\n            display: inline;\n            font-size: 40px;\n            padding-right: 20px;\n        }\n\n        .listItems a span {\n            display: inline;\n            font-size: 1.5em;\n            position: relative;\n            top: -12px;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <!-- todo: need to investigate as performance sometime lag when using the matchBodyHeight directive here -->\n        <div matchBodyHeight=\"540\" id=\"campaignViewList\" style=\"padding-right: 5px; overflow-y: auto\">\n            <draggable-list (onItemSelected)=\"_onItemSelected($event)\" [customTemplate]=\"customTemplate\" (onDragComplete)=\"_onDragComplete($event)\" [items]=\"m_blockList\"></draggable-list>\n            <ng-template #customTemplate let-item>\n                <a href=\"#\" [attr.data-block_id]=\"item.blockID\">\n                    <i class=\"fa {{item.blockFontAwesome}}\"></i>\n                    <span>{{item.scene?.name || item.resource?.name || item.blockName}}</span>\n                    <i class=\"dragch fa fa-arrows-v\"></i>\n                    <span class=\"lengthTimer hidden-xs\"> \n                    {{item.duration | FormatSecondsPipe}}\n                </span>\n                </a>\n            </ng-template>\n        </div>\n    `\n})\n\nexport class CampaignChannels extends Compbaser implements AfterViewInit {\n\n    private selected_campaign_timeline_id: number = -1;\n    private selected_campaign_timeline_chanel_id: number = -1;\n    private durationChanged$ = new Subject();\n    m_blockList: List<IBlockData> = List([]);\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private bs: BlockService, private cd:ChangeDetectorRef) {\n        super();\n    }\n\n    @ViewChild(DraggableList)\n    draggableList: DraggableList;\n\n    ngAfterViewInit() {\n        this.listenChannelSelected();\n        this.preventRedirect(true);\n\n    }\n\n    @timeout()\n    private listenChannelSelected() {\n        this.cd.markForCheck();\n        this.cancelOnDestroy(\n            this.yp.listenCampaignTimelineBoardViewerSelected(true)\n                .skip(1)\n                .distinctUntilChanged()\n                .subscribe(() => {\n                    this.draggableList.deselect();\n                })\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenCampaignTimelineBoardViewerSelected(true)\n                .combineLatest(\n                    this.durationChanged$,\n                    this.yp.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players)\n                )\n                .filter((v) => {\n                    var campaignTimelineBoardViewerChanelsModel: CampaignTimelineBoardViewerChanelsModel = v[0];\n                    var totalDuration = v[1];\n                    var campaignTimelineChanelPlayersModel = v[2];\n                    if (campaignTimelineBoardViewerChanelsModel == null) this.m_blockList = List([]);\n                    return campaignTimelineBoardViewerChanelsModel != null;\n\n                })\n                .withLatestFrom(this.yp.listenTimelineSelected(), (i_channelModel: CampaignTimelineBoardViewerChanelsModel, i_timelinesModel: CampaignTimelinesModel) => {\n                    this.selected_campaign_timeline_chanel_id = i_channelModel[0].getCampaignTimelineChanelId();\n                    this.selected_campaign_timeline_id = i_timelinesModel.getCampaignTimelineId();\n                    return i_channelModel[0].getCampaignTimelineBoardViewerChanelId()\n\n                })\n                .mergeMap(i_boardViewerChanelId => {\n                    return this.yp.getChannelFromCampaignTimelineBoardViewer(i_boardViewerChanelId)\n\n                })\n                .mergeMap((i_campaignTimelineChanelsModel: CampaignTimelineChanelsModel) => {\n                    return this.yp.getChannelBlocks(i_campaignTimelineChanelsModel.getCampaignTimelineChanelId())\n\n                })\n                .mergeMap(blockIds => {\n                    if (blockIds.length == 0)\n                        return Observable.of([])\n\n                    return Observable.from(blockIds)\n                        .map((blockId) => this.bs.getBlockData(blockId))\n                        .combineAll()\n\n                })\n                .subscribe((i_blockList: Array<IBlockData>) => {\n                    this.m_blockList = List(this._sortBlock(i_blockList));\n                    // this.draggableList.createSortable()\n                }, e => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenTimelineDurationChanged()\n                .subscribe((totalDuration) => {\n                    this.durationChanged$.next(totalDuration);\n                })\n        )\n    }\n\n    _onItemSelected(event) {\n        var blockData: IBlockData = event.item;\n        var uiState: IUiState = {\n            campaign: {\n                blockChannelSelected: blockData.blockID\n            },\n            uiSideProps: SideProps.channelBlock\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onDragComplete(i_blocks) {\n        this._reOrderChannelBlocks(i_blocks);\n    }\n\n    private _sortBlock(i_blockList: Array<IBlockData>): Array<IBlockData> {\n\n        var sorted = i_blockList.sort((a, b) => {\n            if (a.offset < b.offset)\n                return -1;\n            if (a.offset > b.offset)\n                return 1;\n            if (a.offset === b.offset)\n                return 0;\n        })\n        return sorted;\n    }\n\n    /**\n     Update the blocks offset times according to current order of LI elements and reorder accordingly in msdb.\n     @method _reOrderChannelBlocks\n     @return none\n     **/\n    _reOrderChannelBlocks(i_blocks) {\n        var self = this\n        var blocks = i_blocks;\n        var playerOffsetTime: any = 0;\n        jQuery(blocks).each(function (i) {\n            var block_id = jQuery('[data-block_id]', this).data('block_id');\n            self._getBlockRecord(block_id, (i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModel) => {\n                var playerDuration = i_campaignTimelineChanelPlayersModel.getPlayerDuration();\n                self.rp.setBlockRecord(block_id, 'player_offset_time', Lib.ToValidNumber(playerOffsetTime));\n                // console.log('player ' + block_id + ' offset ' + playerOffsetTime + ' playerDuration ' + playerDuration);\n                playerOffsetTime = parseFloat(playerOffsetTime) + parseFloat(playerDuration);\n            })\n        });       \n        self.rp.updateTotalTimelineDuration(this.selected_campaign_timeline_id);\n        self.rp.reduxCommit();\n    }\n\n    @Once()\n    private _getBlockRecord(i_blockId, i_cb: (i_blockId: CampaignTimelineChanelPlayersModel) => void) {\n        return this.yp.getChannelBlockRecord(i_blockId)\n            .subscribe((block: CampaignTimelineChanelPlayersModel) => {\n                i_cb(block);\n            }, (e) => console.error(e));\n    }\n\n\n    ngOnInit() {\n    }\n\n    destroy() {\n        this.selected_campaign_timeline_chanel_id = -1;\n        this.selected_campaign_timeline_id = -1;\n    }\n}\n\n\n// var campaign_timeline_chanel_player_id = jData['campaign_timeline_chanel_player_id'];\n// var campaign_timeline_chanel_player_data = jData['campaign_timeline_chanel_player_data'];\n// var timeline = BB.comBroker.getService(BB.SERVICES.CAMPAIGN_VIEW).getTimelineInstance(self.selected_campaign_timeline_id);\n// var channel = timeline.getChannelInstance(self.selected_campaign_timeline_chanel_id);\n// channel.createChannelBlock(campaign_timeline_chanel_player_id, campaign_timeline_chanel_player_data);\n//\n// var campaign_timeline_board_viewer_id = self.selected_campaign_timeline_board_viewer_id;\n// var campaign_timeline_id = self.selected_campaign_timeline_id;\n// var campaign_timeline_chanel_id = self.selected_campaign_timeline_chanel_id;\n//\n// // self._resetChannel();\n// $(Elements.SORTABLE).empty();\n// self._loadChannelBlocks(campaign_timeline_id, campaign_timeline_chanel_id);\n// self._listenBlockSelected();\n// // self._deselectBlocksFromChannel();\n// self._selectLastBlockOnChannel();\n// self._reOrderChannelBlocks();\n// var blocksSorted = {};\n// _.forEach(i_blockList, (i_block: IBlockData) => {\n//     var player_data = i_block.campaignTimelineChanelPlayersModelExt.getPlayerData();\n//     var domPlayerData = $.parseXML(player_data);\n//     var sceneHandle = jQuery(domPlayerData).find('Player').attr('player');\n//     // workaround to remove scenes listed inside table campaign_timeline_chanel_players\n//     if (sceneHandle == '3510')\n//         return;\n//     var a = i_block.campaignTimelineChanelPlayersModelExt.getKey('player_offset_time');\n//     var offsetTime = i_block.campaignTimelineChanelPlayersModelExt.getPlayerOffsetTimeInt();\n//     console.log(i_block.blockName + ' duration: ' + i_block.length + ' offset: ' + offsetTime);\n//     blocksSorted[offsetTime] = i_block;\n// });\n// return _.values(blocksSorted) as Array<IBlockData>;"
  },
  {
    "path": "src/app/campaigns/campaign-duration.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Observable} from \"rxjs\";\n\n@Component({\n    selector: 'campaign-duration',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <span style=\"font-size: 1em\" data-localize=\"campaignLength\">campaign length:</span>\n        <span id=\"timelinesTotalLength\" style=\"font-size: 1em\">{{m_duration$ | async | FormatSecondsPipe}} </span>\n    `\n})\nexport class CampaignDuration extends Compbaser implements AfterViewInit {\n\n    m_duration$:Observable<number>;\n\n    constructor(private yp: YellowPepperService, private cd:ChangeDetectorRef) {\n        super();\n    }\n\n    ngAfterViewInit() {\n        this.m_duration$ = this.yp.listenTimelineDurationChanged()\n        this.cd.markForCheck()\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaign-editor-props.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {Observable} from \"rxjs\";\n\n\n@Component({\n    selector: 'campaign-editor-props',\n    host: {\n        '(input-blur)': 'onFormChange($event)'\n    },\n    template: `\n        <div>\n            <div class=\"row\">\n                <div class=\"inner userGeneral\">\n                    <div class=\"panel panel-default tallPanel\">\n                        <div class=\"panel-heading\">\n                            <small class=\"release\">editor properties\n                                <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                            </small>\n                            <small class=\"debug\">{{me}}</small>\n                        </div>\n                        <ul class=\"list-group\">\n                            <li class=\"list-group-item\">\n                                <h4>{{(m_campaignModel$ | async)?.getCampaignName() }}</h4>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == '1'\">\n                                    <h4><i class=\"fa fa-calendar\"></i>playback mode: scheduler</h4>\n                                </div>\n                                <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == '0'\">\n                                    <h4><i class=\"fa fa fa-repeat\"></i>playback mode: sequencer</h4>\n                                </div>\n                            </li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n        </div>\n    `,\n    styles: [`\n        i {\n            width: 20px;\n        }\n    `]\n\n})\nexport class CampaignEditorProps extends Compbaser {\n    m_campaignModel$: Observable<CampaignsModelExt>;\n\n    constructor(private yp: YellowPepperService) {\n        super();\n        this.m_campaignModel$ = this.yp.listenCampaignValueChanged()\n    }\n\n    destroy() {\n    }\n}\n\n\n\n"
  },
  {
    "path": "src/app/campaigns/campaign-editor.ts",
    "content": "import {ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Output, ViewChild} from \"@angular/core\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {Compbaser} from \"ng-mslib\";\nimport {CampaignsModelExt, CampaignTimelineChanelPlayersModelExt} from \"../../store/model/msdb-models-extended\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {CampaignTimelineChanelsModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {List} from \"immutable\";\nimport {ACTION_UISTATE_UPDATE, AppdbAction, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState, StoryBoardListViewModeEnum} from \"../../store/store.data\";\nimport {PreviewModeEnum} from \"../live-preview/live-preview\";\nimport * as _ from \"lodash\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {Lib} from \"../../Lib\";\nimport {CampaignStoryTimeline, ITimelineState} from \"./campaign-story-timeline\";\n\n// https://github.com/AlexWD/ds-timeline-widget\n\n@Component({\n    selector: 'campaign-editor',\n    templateUrl: './campaign-editors.html',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        .btn.active.focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn:active:focus, .btn:focus {\n            outline: 0;\n        }\n\n        label {\n            border-radius: 0px;\n        }\n    `],\n    animations: [\n        trigger('visibilityChanged', [\n            state('on', style({transform: 'rotate(0deg)'})),\n            state('off', style({transform: 'rotate(180deg)'})),\n            transition('* => *', animate('300ms'))\n        ]),\n\n        trigger('fadeInOut', [\n            transition(':enter', [\n                style({opacity: 0}),\n                animate('400ms', style({opacity: 1}))\n            ]),\n            transition(':leave', [\n                style({opacity: 1}),\n                animate('200ms', style({opacity: 0}))\n            ])\n        ])\n\n    ]\n})\n\nexport class CampaignEditor extends Compbaser {\n\n    campaignModel: CampaignsModelExt;\n    campaignTimelinesModel: CampaignTimelinesModel;\n    channelModel: CampaignTimelineChanelsModel;\n    m_campaignTimelinesModels: List<CampaignTimelinesModel>;\n    m_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModelExt;\n    m_isVisible1 = 'off';\n    zoom = 1;\n    loginState: string = '';\n    m_inDevMode = Lib.DevMode();\n    m_storyBoardListViewModeEnum = StoryBoardListViewModeEnum;\n    m_storyBoardListViewModeSelection = StoryBoardListViewModeEnum.ListMode;\n    m_switchMode = false;\n    m_duration:number = 0;\n\n    constructor(private yp: YellowPepperService, private actions: AppdbAction, private rp: RedPepperService, private cd: ChangeDetectorRef) {\n        super();\n\n        this.cancelOnDestroy(\n            this.yp.listenStoryBoardListViewModeSelected()\n                .subscribe((v) => {\n                    this._onTimelineViewMode(v);\n                }, (e) => console.error(e))\n        );\n\n        this.cancelOnDestroy(\n            this.yp.listenCampaignSelected()\n                .switchMap((i_campaignsModelExt: CampaignsModelExt) => {\n                    this.campaignModel = i_campaignsModelExt;\n                    return this.yp.listenCampaignTimelines(i_campaignsModelExt.getCampaignId())\n                })\n                .subscribe((i_campaignTimelinesModel: List<CampaignTimelinesModel>) => {\n                    this.m_campaignTimelinesModels = i_campaignTimelinesModel;\n                }, (e) => console.error(e))\n        );\n\n        this.cancelOnDestroy(\n            this.yp.listenTimelineSelected(true)\n                .subscribe((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                    this.campaignTimelinesModel = i_campaignTimelinesModel;\n                    if (this.campaignTimelinesModel){\n                        this.m_duration = this.campaignTimelinesModel.getTimelineDuration();\n                        console.log('duration ' + this.m_duration);\n                        //todo: error when enabled but need for Duration component\n                        // this.cd.detectChanges();\n                    }\n\n                }, (e) => console.error(e))\n        );\n        this.cancelOnDestroy(\n            this.yp.listenChannelSelected(true)\n                .subscribe((channel: CampaignTimelineChanelsModel) => {\n                    this.channelModel = channel;\n                }, (e) => {\n                    console.error(e)\n                })\n        );\n        this.cancelOnDestroy(\n            this.yp.listenBlockChannelSelected(true)\n                .subscribe((i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModelExt) => {\n                    this.m_campaignTimelineChanelPlayersModel = i_campaignTimelineChanelPlayersModel;\n                }, (e) => console.error(e))\n        )\n    }\n\n    @ViewChild(CampaignStoryTimeline)\n    campaignStoryTimeline:CampaignStoryTimeline;\n\n    @Output()\n    onToScreenLayoutEditor: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onToAddContent: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onToAddTimeline: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onGoBack: EventEmitter<any> = new EventEmitter<any>();\n\n    _onAddContent() {\n        if (!this.channelModel)\n            return bootbox.alert('Select channel to add content to. First be sure to select a timeline and next, click the [Next Channel] button');\n        this.onToAddContent.emit();\n    }\n\n    _timelineDurationChange(i_duration) {\n        this.m_duration = i_duration;\n        console.log('CampaignEditor db total new duration ' + i_duration + ' ' + this.campaignTimelinesModel.getCampaignTimelineId());\n        this.rp.setTimelineTotalDuration(this.campaignTimelinesModel.getCampaignTimelineId(), i_duration);\n        this.rp.reduxCommit();\n        this.cd.markForCheck();\n    }\n\n    _campaignStoryTimelineCmd(i_cmd){\n        this.campaignStoryTimeline[i_cmd]();\n    }\n\n    _onStateChanged(state:ITimelineState){\n        // this.m_duration = state.duration;\n    }\n\n    _onRemoveTimeline() {\n        if (!this.campaignTimelinesModel)\n            return bootbox.alert('you must first select a timeline to remove');\n        if (this.rp.getCampaignTimelines(this.campaignTimelinesModel.getCampaignId()).length == 1)\n            return bootbox.alert('you must keep at least one Timeline')\n\n        bootbox.confirm('are you sure you want to remove the selected timeline?', (i_result) => {\n            if (i_result == true) {\n                var boardTemplateID = this.rp.getGlobalTemplateIdOfTimeline(this.campaignTimelinesModel.getCampaignTimelineId());\n                this.rp.removeTimelineFromCampaign(this.campaignTimelinesModel.getCampaignTimelineId());\n                this.rp.removeSchedulerFromTime(this.campaignTimelinesModel.getCampaignTimelineId());\n                var campaignTimelineBoardTemplateID = this.rp.removeBoardTemplateFromTimeline(this.campaignTimelinesModel.getCampaignTimelineId());\n                this.rp.removeBoardTemplate(boardTemplateID);\n                this.rp.removeTimelineBoardViewerChannels(campaignTimelineBoardTemplateID);\n                this.rp.removeBoardTemplateViewers(boardTemplateID);\n                this.rp.getChannelsOfTimeline(this.campaignTimelinesModel.getCampaignTimelineId()).forEach(i_campaign_timeline_chanel_id => {\n                    this.rp.removeChannelFromTimeline(i_campaign_timeline_chanel_id);\n                    this.rp.getChannelBlocks(i_campaign_timeline_chanel_id).forEach((i_block_id) => {\n                        this.rp.removeBlockFromTimelineChannel(i_block_id);\n                    })\n                });\n                var uiState: IUiState = {\n                    uiSideProps: SideProps.miniDashboard,\n                    campaign: {\n                        timelineSelected: -1,\n                        campaignTimelineChannelSelected: -1,\n                        campaignTimelineBoardViewerSelected: -1\n                    }\n                }\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                this.rp.reduxCommit();\n            }\n        });\n    }\n\n    _changeZoom(value) {\n        // console.log(value);\n    }\n\n    _onTimelineViewMode(i_mode: StoryBoardListViewModeEnum) {\n        var uiState: IUiState = {\n            campaign: {\n                storyBoardListViewModeSelected: i_mode\n            }\n        }\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.m_storyBoardListViewModeSelection = i_mode;\n    }\n\n    _onAddTimeline() {\n        this.onToAddTimeline.emit();\n    }\n\n    _onEditScreenLayout() {\n        if (!this.campaignTimelinesModel)\n            return bootbox.alert('no timeline selected')\n        var uiState: IUiState = {uiSideProps: SideProps.screenLayoutEditor}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.onToScreenLayoutEditor.emit();\n    }\n\n    /**\n     Delete the selected block from the channel\n     @method _deleteChannelBlock\n     @return none\n     **/\n    _onRemoveContent() {\n        if (!this.m_campaignTimelineChanelPlayersModel)\n            return bootbox.alert('No item selected');\n        this.rp.removeBlockFromTimelineChannel(this.m_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId());\n        this.rp.reduxCommit();\n        let uiState: IUiState = {\n            uiSideProps: SideProps.miniDashboard,\n            campaign: {\n                blockChannelSelected: -1\n            }\n        }\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onCampaignPreview() {\n        return bootbox.alert('HTML preview coming soon! for now preview using Desktop Signage Player');\n        // let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE_AND_PREVIEW, previewMode: PreviewModeEnum.CAMPAIGN}\n        // this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onTimelinePreview() {\n        return bootbox.alert('HTML preview coming soon! for now preview using Desktop Signage Player');\n        // if (_.isUndefined(this.campaignTimelinesModel))\n        //     return bootbox.alert('No timeline selected');\n        // let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE_AND_PREVIEW, previewMode: PreviewModeEnum.TIMELINE}\n        // this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onGoBack() {\n        this.actions.resetCampaignSelection();\n        this.onGoBack.emit()\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/campaigns/campaign-editors.html",
    "content": "<small class=\"debug\">{{me}}</small>\n<h4 i18n>campaign editor</h4>\n<!-- todo: need to investigate as performance sometime laggy when using the matchBodyHeight directive here -->\n<!--<div matchBodyHeight=\"150\" id=\"campaignView\" style=\"margin-right: 30px; padding-right: 5px; overflow-y: auto\">-->\n<div id=\"campaignView\" style=\"padding-right: 24px\">\n    <div class=\"panel-group\" id=\"timelinesCollapsible\">\n\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <h4 class=\"panel-title\">\n                    <a (click)=\"m_isVisible1 = m_isVisible1 == 'on' ? 'off' : 'on'\" id=\"toggleTimelinesCollapsible\" data-toggle=\"collapse\" data-parent=\"#timelinesCollapsible\" href=\"#screenSelectorContainerCollapse\">\n                        <span style=\"position: relative; top: 3px\" [@visibilityChanged]=\"m_isVisible1\" class=\"glyphicon glyphicon-chevron-down\"></span>\n                    </a>\n                    <button (click)=\"_onGoBack()\" type=\"button\" style=\"margin-left: 8px\" title=\"add new timeline\" data-localize-tooltip=\"backToCampaignsTooltip\" class=\"btn btn-default btn-sm\">\n                        <span class=\"glyphicon glyphicon-chevron-left\"></span>\n                    </button>\n\n                    <button (click)=\"_onAddTimeline()\" id=\"addNewTimelineButton\" type=\"button\" title=\"add new timeline\" data-localize-tooltip=\"addNewTimelineButtonToolTip\" class=\"btn btn-default btn-sm\">\n                        <span class=\"glyphicon glyphicon-plus\"></span>\n                    </button>\n                    <button (click)=\"_onRemoveTimeline()\" id=\"removeTimelineButton\" type=\"button\" title=\"remove the selected timeline\" data-localize-tooltip=\"removeTimelineButtonToolTip\" class=\"btn btn-default btn-sm\">\n                        <span class=\"glyphicon glyphicon-minus\"></span>\n                    </button>\n                    <button (click)=\"_onEditScreenLayout()\" id=\"editScreenLayout\" type=\"button\" title=\"edit screen layout\" data-localize-tooltip=\"editScreenLayout\" class=\"btn btn-default btn-sm\">\n                        <i class=\"fa fa-object-group\"></i>\n                    </button>\n                    <button id=\"campaignPreview\" (click)=\"_onCampaignPreview()\" type=\"button\" title=\"campaign preview\" data-localize-tooltip=\"campaignPreviewTooltip\" class=\"btn btn-default btn-sm\">\n                        <i class=\"fa fa-play-circle\"></i>\n                    </button>\n\n                    <div class=\"sequenceClass\" style=\"float: right; margin-right: 35px; position: relative; top: 6px\">\n                        <campaign-duration></campaign-duration>\n                    </div>\n                </h4>\n            </div>\n            <div id=\"screenSelectorContainerCollapse\" class=\"panel-collapse collapse in\">\n                <div class=\"panel-body\">\n                    <aside>\n                        <aside>\n                            <div id=\"screenSelectorContainer\" vertical-align=\"middle\">\n                                <div id=\"screenLayoutsUL\" style=\"overflow-x: scroll\">\n                                    <sequencer #sequencer (onEditLayout)=\"_onEditScreenLayout()\" [setCampaignTimelinesModels]=\"m_campaignTimelinesModels\"></sequencer>\n                                </div>\n                            </div>\n                        </aside>\n                    </aside>\n                </div>\n            </div>\n        </div>\n    </div>\n    <div class=\"panel-group\" id=\"storylineCollapsible\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <h4 class=\"panel-title\">\n                    <span data-localize=\"timeline\">Timeline</span>\n                    <button (click)=\"sequencer.onSelectNextChannel()\" style=\"margin-left: 30px\" id=\"selectNextChannel\" type=\"button\" class=\"btn btn-default btn-sm\">\n                        <i i18n class=\"fa fa-crosshairs\"></i><span data-localize=\"nextChannel\"> next channel</span>\n                    </button>\n                    <button id=\"addBlockButton\" (click)=\"_onAddContent()\" type=\"button\" title=\"add content\" class=\"btn btn-default btn-sm\">\n                        <i class=\"fa fa-plus\"></i>\n                    </button>\n                    <button (click)=\"_onRemoveContent()\" id=\"removeBlockButton\" type=\"button\" title=\"remove content\" data-localize-tooltip=\"removeContent\" class=\"btn btn-default btn-sm\">\n                        <i class=\"fa fa-minus\"></i>\n                    </button>\n                    <button (click)=\"_onTimelinePreview()\" id=\"timelinePreview\" type=\"button\" title=\"campaign preview\" data-localize-tooltip=\"campaignPreviewTooltip\" class=\"btn btn-default btn-sm\">\n                        <i class=\"fa fa-play-circle\"></i>\n                    </button>\n\n                    <div style=\"height: 30px\" class=\"btn-group\" data-toggle=\"buttons\">\n\n                        <label title=\"view as list\" (click)=\"_onTimelineViewMode(m_storyBoardListViewModeEnum.ListMode)\" style=\"height: 30px\"\n                               [ngClass]=\"{active: m_storyBoardListViewModeSelection==m_storyBoardListViewModeEnum.ListMode}\"\n                               class=\"btn btn-default\" data-active-class=\"success\">\n                            <i class=\"fa fa-list-ul\"></i>\n                            <input type=\"radio\" name=\"options\" id=\"option1\" autocomplete=\"off\"> list\n                        </label>\n\n                        <label title=\"view as timeline\" (click)=\"_onTimelineViewMode(m_storyBoardListViewModeEnum.StoryMode)\" style=\"height: 30px\"\n                               [ngClass]=\"{active: m_storyBoardListViewModeSelection==m_storyBoardListViewModeEnum.StoryMode}\"\n                               class=\"btn btn-default\" data-active-class=\"danger\">\n                            <i class=\"fa fa-sliders\"></i>\n                            <input type=\"radio\" name=\"options\" id=\"option2\" autocomplete=\"off\"> timeline\n                        </label>\n                    </div>\n\n                    <span style=\"float: right\" *ngIf=\"m_storyBoardListViewModeSelection==m_storyBoardListViewModeEnum.StoryMode\">\n                        <button (click)=\"_campaignStoryTimelineCmd('closedGaps')\" type=\"button\" title=\"remove gaps\" class=\"btn btn-default btn-sm\">\n                            <i class=\"fa fa-scissors\"></i>\n                        </button>\n                        <button (click)=\"_campaignStoryTimelineCmd('resizeToLargest')\"  type=\"button\" title=\"resize to largest\" class=\"btn btn-default btn-sm\">\n                            <i class=\"fa fa-arrows-h\"></i>\n                        </button>\n                        <button (click)=\"_campaignStoryTimelineCmd('alignLeft')\" type=\"button\" title=\"align left\" class=\"btn btn-default btn-sm\">\n                            <i class=\"fa fa fa-outdent\"></i>\n                        </button>\n                        <button (click)=\"_campaignStoryTimelineCmd('alignLeft')\" type=\"button\" title=\"align right\" class=\"btn btn-default btn-sm\">\n                            <i class=\"fa fa fa-indent\"></i>\n                        </button>\n                        <!--<label title=\"switch place mode\" style=\"height: 30px\" (click)=\"m_switchMode = !m_switchMode\"-->\n                        <!--[ngClass]=\"{active: m_switchMode}\"-->\n                        <!--class=\"btn btn-default\" data-active-class=\"danger\">-->\n                        <!--<i style=\"position: relative; top: -3px\" class=\"fa fa-exchange\"></i>-->\n                        <!--</label>-->\n                        <select style=\"float: right\" title=\"zoom (ratio / pixels)\" style=\"width: 70px; height: 30px; position: relative; top: 2px; border: solid 1px #d1d1d1\" (change)=\"_changeZoom($event)\" [(ngModel)]=\"zoom\">\n                              <option value=\"1\">1.0 : 10</option>\n                              <option value=\"2\">2.0 : 10</option>\n                              <option value=\"5\">5.0 : 10</option>\n                              <option value=\"10\">10 : 10</option>\n                              <option value=\"20\">20 : 10</option>\n                              <option value=\"40\">40 : 10</option>\n                        </select>\n                        <app-duration-input style=\"float: right; position: relative; top: -3px\"\n                                            *ngIf=\"m_storyBoardListViewModeSelection == m_storyBoardListViewModeEnum.StoryMode\"\n                                            [setDuration]=\"m_duration\"\n                                            (durationChange)=\"_timelineDurationChange($event)\">\n                        </app-duration-input>\n                        <!--<input value=\"{{m_duration}}\"/>-->\n                    </span>\n\n                </h4>\n            </div>\n            <div [@fadeInOut] *ngIf=\"m_storyBoardListViewModeSelection==m_storyBoardListViewModeEnum.StoryMode\">\n                <!--<campaign-story-timeline (stateChanged)=\"_onStateChanged($event)\" [duration]=\"m_duration\" [switchMode]=\"m_switchMode\" [zoom]=\"zoom\"></campaign-story-timeline>-->\n                <campaign-story-timeline #campaignStoryTimeline [switchMode]=\"m_switchMode\" [zoom]=\"zoom\"></campaign-story-timeline>\n            </div>\n            <div [@fadeInOut] *ngIf=\"m_storyBoardListViewModeSelection==m_storyBoardListViewModeEnum.ListMode\">\n                <campaign-channels></campaign-channels>\n            </div>\n            <div id=\"storylineContainerCollapse\" class=\"panel-collapse collapse\">\n                <div class=\"panel-body\">\n                    <aside>\n                        <aside>\n                        </aside>\n                    </aside>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n\n\n"
  },
  {
    "path": "src/app/campaigns/campaign-layout.ts",
    "content": "import {Component, EventEmitter, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport * as screenTemplates from \"../../libs/screen-templates.json\";\nimport * as _ from \"lodash\";\nimport {OrientationEnum} from \"./campaign-orientation\";\nimport {Observable, Observer} from \"rxjs\";\nimport {Once} from \"../../decorators/once-decorator\";\nimport {IUiStateCampaign} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {IScreenTemplateData} from \"../../interfaces/IScreenTemplate\";\nimport {ACTION_LIVELOG_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\n\n@Component({\n    selector: 'campaign-layout',\n    styles: [`\n        :host /deep/ .svgSD {\n            cursor: pointer;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <h4 i18n>screen layout</h4>\n        <div id=\"screenLayoutList\" style=\"min-width: 500px; min-height: 500px\">\n            <div (click)=\"_nextClick.next(screenLayout)\" style=\"float: left; padding: 20px\" *ngFor=\"let screenLayout of m_screenLayouts\">\n                <screen-template [mouseHoverEffect]=\"m_mouseHoverEffect\" [setTemplate]=\"screenLayout\"></screen-template>\n            </div>\n        </div>\n    `\n})\nexport class CampaignLayout extends Compbaser {\n\n    private m_resolution: string;\n    private m_screenTemplateData: IScreenTemplateData;\n    private m_orientation: OrientationEnum;\n    _nextClick: Observer<any>;\n    m_addToExistingCampaignMode = false;\n    m_screenLayouts: Array<IScreenTemplateData>;\n    m_campaignName: string;\n    m_onNewCampaignMode: boolean;\n    m_mouseHoverEffect:boolean = false;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n    }\n\n    ngAfterViewInit() {\n        this.getNewCampaignParams();\n        this.cancelOnDestroy(\n            Observable.create(observer => {\n                this._nextClick = observer\n            }).map((i_screenTemplateData: IScreenTemplateData) => {\n                this.m_screenTemplateData = i_screenTemplateData;\n                return i_screenTemplateData;\n            })\n                .debounceTime(200)\n                .do(() => {\n                    this.onSelection.emit(this.m_screenTemplateData)\n                }).subscribe(() => {\n            }, (e) => console.error(e))\n        )\n    }\n\n    @Input()\n    set mouseHoverEffect(i_value) {\n        this.m_mouseHoverEffect = i_value;\n    }\n\n    @Input()\n    set onNewCampaignMode(i_value: boolean) {\n        this.m_onNewCampaignMode = i_value;\n    }\n\n    @Once()\n    private getNewCampaignParams() {\n        return this.yp.getNewCampaignParmas()\n            .subscribe((value: IUiStateCampaign) => {\n                if (this.m_onNewCampaignMode) {\n                    this.m_addToExistingCampaignMode = false;\n                    this.m_resolution = value.campaignCreateResolution;\n                    this.m_orientation = value.campaignCreateOrientation;\n                    this.m_campaignName = value.campaignCreateName;\n                    this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'campaign created ' + this.m_campaignName})}));\n                } else {\n                    this.m_addToExistingCampaignMode = true;\n                    var recBoard = this.rp.getGlobalBoardFromCampaignId(value.campaignSelected)\n                    var h = parseInt(recBoard.board_pixel_height);\n                    var w = parseInt(recBoard.board_pixel_width);\n                    this.m_resolution = `${w}x${h}`;\n                    this.m_orientation = w > h ? OrientationEnum.HORIZONTAL : OrientationEnum.VERTICAL;\n                    this.m_campaignName = '';\n                }\n                this._render();\n            }, (e) => console.error(e))\n    }\n\n\n    @Output()\n    onSelection: EventEmitter<IScreenTemplateData> = new EventEmitter<IScreenTemplateData>();\n\n\n    private _render() {\n        if (_.isUndefined(this.m_orientation) || _.isUndefined(this.m_resolution))\n            return;\n        this.m_screenLayouts = [];\n        for (var screenType in screenTemplates[this.m_orientation][this.m_resolution]) {\n            var screenTemplateData: IScreenTemplateData = {\n                orientation: this.m_orientation,\n                resolution: this.m_resolution,\n                screenType: screenType,\n                screenProps: screenTemplates[this.m_orientation][this.m_resolution][screenType],\n                scale: 14,\n                name: this.m_campaignName\n            };\n            this.m_screenLayouts.push(screenTemplateData);\n        }\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaign-list.ts",
    "content": "import {Component, ChangeDetectionStrategy, Input, Output, EventEmitter} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {List} from \"immutable\";\nimport {IUiState} from \"../../store/store.data\";\nimport {SideProps} from \"../../store/actions/appdb.actions\";\n\n@Component({\n    selector: 'campaign-list',\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <ul (click)=\"$event.preventDefault()\" class=\"appList list-group\">\n\n            <a *ngFor=\"let campaign of m_campaigns; let i = index\" (click)=\"_onCampaignSelected($event, campaign, i)\"\n               [ngClass]=\"{'selectedItem': selectedIdx == i}\" href=\"#\" class=\"list-group-item\">\n\n                <h4>{{campaign?.getCampaignName()}}</h4>\n                <p class=\"list-group-item-text\">play list mode: {{campaign?.getCampaignPlaylistModeName()}} </p>\n                <div class=\"openProps\">\n                    <button type=\"button\" class=\"props btn btn-default btn-sm\"><i style=\"font-size: 1.5em\" class=\"props fa fa-gear\"></i></button>\n                </div>\n            </a>\n        </ul>\n    `,\n})\nexport class CampaignList extends Compbaser {\n    selectedIdx = -1;\n    m_campaigns: List<CampaignsModelExt>;\n    m_selectedCampaign: CampaignsModelExt;\n\n    constructor() {\n        super();\n    }\n\n    @Input()\n    set campaigns(i_campaigns: List<CampaignsModelExt>) {\n        this.m_campaigns = i_campaigns;\n    }\n\n    @Output()\n    slideToCampaignEditor: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    slideToCampaignName: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onCampaignSelected: EventEmitter<any> = new EventEmitter<any>();\n\n    _onCampaignSelected(event: MouseEvent, campaign: CampaignsModelExt, index) {\n        // event.stopPropagation();\n        // event.preventDefault();\n        this.selectedIdx = index;\n        let uiState: IUiState;\n        if (jQuery(event.target).hasClass('props')) {\n            uiState = {\n                uiSideProps: SideProps.campaignProps,\n                campaign: {\n                    campaignSelected: campaign.getCampaignId()\n                }\n            }\n            this.onCampaignSelected.emit(uiState)\n        } else {\n            uiState = {\n                uiSideProps: SideProps.campaignEditor,\n                campaign: {\n                    campaignSelected: campaign.getCampaignId()\n                }\n            }\n            this.slideToCampaignEditor.emit();\n            this.onCampaignSelected.emit(uiState)\n        }\n        this.m_selectedCampaign = campaign;\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaign-manager.html",
    "content": "<small class=\"debug\" style=\"padding-left: 30px\">{{me}}</small>\n\n<div style=\"padding-bottom: 10px\">\n    <span i18n style=\"font-size: 1.8em;\" i18n>campaign selection</span>\n</div>\n<div>\n    <div class=\"btn-group\">\n        <button id=\"newCampaign\" (click)=\"_createCampaign()\" type=\"button\" class=\"btn btn-default\">\n            <i style=\"font-size: 1em\" class=\"fa fa-rocket\"></i>\n            <span i18n>new campaign</span>\n        </button>\n        <!--<button disabled=\"true\" type=\"button\" class=\"btn btn-danger\">-->\n        <button (click)=\"_onWizard()\" type=\"button\" class=\"btn btn-danger\">\n            <i class=\"fa fa-magic\"></i>\n            <span i18n>Get Wizard help</span>\n        </button>\n        <!--<button (click)=\"save()\" type=\"button\" class=\"btn btn-primary\">-->\n            <!--<i class=\"fa fa-plane\"></i>-->\n            <!--<span i18n>save</span>-->\n        <!--</button>-->\n    </div>\n</div>             \n<!--<button (click)=\"onRoute1()\">camp</button>-->\n<!--<button (click)=\"onRoute2()\">fq</button>-->\n<!--<button (click)=\"onRoute3()\">res</button>-->\n<!--<button (click)=\"onRoute4()\">sett</button>-->\n<!--<button (click)=\"onRoute5()\">stations</button>-->\n<!--<button (click)=\"onRoute6()\">pro</button>-->\n\n<!--<h4>user name: {{(userModel$ | async)?.getUser() }}</h4>-->\n<!--<h4>account type: {{(userModel$ | async)?.getAccountType()}}</h4>-->\n\n<!-- move scroller to proper offset -->\n<div class=\"responsive-pad-right\">\n    <div matchBodyHeight=\"350\" style=\"overflow: scroll\">\n        <campaign-list (onCampaignSelected)=\"_onCampaignSelected($event)\"\n                       (slideToCampaignName)=\"slideToCampaignName.emit($event)\"\n                       (slideToCampaignEditor)=\"slideToCampaignEditor.emit($event)\"\n                       [campaigns]=\"campaigns$ | async\">\n        </campaign-list>\n        <hr/>\n        <!--<h2>sample code for testing only</h2>-->\n        <!--<h4>ng-bootstrap dropdown</h4>-->\n        <!--<div class=\"btn-group\" dropdown>-->\n            <!--<button id=\"single-button\" type=\"button\" class=\"btn btn-primary\" dropdownToggle>-->\n                <!--Button dropdown <span class=\"caret\"></span>-->\n            <!--</button>-->\n            <!--<ul dropdownMenu role=\"menu\" aria-labelledby=\"single-button\">-->\n                <!--<li role=\"menuitem\"><a class=\"dropdown-item\" href=\"#\">Action</a></li>-->\n                <!--<li role=\"menuitem\"><a class=\"dropdown-item\" href=\"#\">Another action</a></li>-->\n                <!--<li role=\"menuitem\"><a class=\"dropdown-item\" href=\"#\">Something else here</a></li>-->\n                <!--<li class=\"divider dropdown-divider\"></li>-->\n                <!--<li role=\"menuitem\"><a class=\"dropdown-item\" href=\"#\">Separated link</a></li>-->\n            <!--</ul>-->\n        <!--</div>-->\n        <!--<p-orderList [responsive]=\"true\" [value]=\"campaigns$ | async | ListToArrayPipe\">-->\n            <!--<ng-template let-car pTemplate=\"item\">-->\n                <!--<div class=\"ui-helper-clearfix\">-->\n                    <!--<div style=\"font-size:14px;float:left;margin:15px 5px 0 0\">{{car.getCampaignName()}}</div>-->\n                <!--</div>-->\n            <!--</ng-template>-->\n        <!--</p-orderList>-->\n    </div>\n</div>\n"
  },
  {
    "path": "src/app/campaigns/campaign-manager.ts",
    "content": "import {ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Output} from \"@angular/core\";\nimport {Observable} from \"rxjs\";\nimport {List} from \"immutable\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Router} from \"@angular/router\";\nimport {UserModel} from \"../../models/UserModel\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {WizardService} from \"../../services/wizard-service\";\n\n@Component({\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'campaign-manager',\n    styles: [`\n        button {\n            width: 160px;\n        }\n\n        /*.selectedItem {*/\n        /*background-color: green !important*/\n        /*}*/\n        /*a.list-group-item:focus,  button.list-group-item:focus  {*/\n        /*background-color: pink !important;*/\n        /*}*/\n\n    `],\n    templateUrl: './campaign-manager.html'\n})\nexport class CampaignManager extends Compbaser {\n\n    // public userModel$: Observable<UserModel>;\n\n    public campaigns$: Observable<List<CampaignsModelExt>>;\n    public timelineSelected$: Observable<number>;\n\n    constructor(private el: ElementRef, private yp: YellowPepperService, private redPepperService: RedPepperService, private router: Router, private wizardService: WizardService) {\n        super();\n        this.preventRedirect(true);\n        this.timelineSelected$ = this.yp.ngrxStore.select(store => store.appDb.uiState.campaign.timelineSelected).map(v => v);\n\n        // this.userModel$ = this.yp.ngrxStore.select(store => store.appDb.userModel);\n\n        this.campaigns$ = this.yp.ngrxStore.select(store => store.msDatabase.sdk.table_campaigns)\n            .map((list: List<CampaignsModelExt>) => list);\n        // this.yp.ngrxStore.select(store => store.msDatabase.sdk.table_resources).subscribe((resourceModels: List<ResourcesModel>) => {\n        //     // console.log(resourceModels.first().getResourceName());\n        //     // console.log(resourceModels.first().getResourceBytesTotal());\n        // })\n    }\n\n    // @once(6000)\n    // private testListen() {\n    //     return this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps).map((v) => {\n    //         console.log(v);\n    //     }).subscribe((e) => {\n    //         console.log(e);\n    //     });\n    // }\n\n    @Output()\n    slideToCampaignEditor: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    slideToCampaignName: EventEmitter<any> = new EventEmitter<any>();\n\n    // m_selectedCampaign: CampaignsModelExt;\n\n    // _onCampaignSelected(event: MouseEvent, campaign: CampaignsModelExt) {\n    //     let uiState: IUiState;\n    //     if (jQuery(event.target).hasClass('props')) {\n    //         uiState = {\n    //             uiSideProps: SideProps.campaignProps,\n    //             campaign: {\n    //                 campaignSelected: campaign.getCampaignId()\n    //             }\n    //         }\n    //         this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    //     } else {\n    //         uiState = {\n    //             uiSideProps: SideProps.campaignEditor,\n    //             campaign: {\n    //                 campaignSelected: campaign.getCampaignId()\n    //             }\n    //         }\n    //         this.slideToCampaignEditor.emit();\n    //         this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    //     }\n    //     this.m_selectedCampaign = campaign;\n    // }\n\n    onRoute1() {\n        this.router.navigate(['/App1/Campaigns'])\n    }\n\n    onRoute2() {\n        this.router.navigate(['/App1/Fasterq'])\n    }\n\n    onRoute3() {\n        this.router.navigate(['/App1/Resources'])\n    }\n\n    onRoute4() {\n        this.router.navigate(['/App1/Settings'])\n    }\n\n    onRoute5() {\n        this.router.navigate(['/App1/Stations'])\n    }\n\n    onRoute6() {\n        this.router.navigate(['/App1/StudioPro'])\n    }\n\n    // save() {\n    //     let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE}\n    //     this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    // }\n\n    _onCampaignSelected(i_uiState: IUiState) {\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: i_uiState}))\n    }\n\n    _createCampaign() {\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.slideToCampaignName.emit();\n    }\n\n    _onWizard() {\n        this.wizardService.start();\n    }\n\n    destroy() {\n        // var uiState: IUiState = {uiSideProps: SideProps.none}\n        // this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n}\n\n\n// let uiState: IUiState = {\n//     campaign: {\n//         campaignSelected: 123\n//     }\n// };\n// uiState.campaign.campaignSelected = _.random(1,1999);\n// this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n\n// var b: IUiState = {\n//     uiSideProps: _.random(1,1222)\n// }\n// this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: b}))\n\n"
  },
  {
    "path": "src/app/campaigns/campaign-name.ts",
    "content": "import {Component, ChangeDetectionStrategy, Output, EventEmitter} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\n\n@Component({\n    selector: 'campaign-name',\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <h3 i18n>Select your campaign name</h3>\n        <input (keydown)=\"_onKeyDown($event)\" id=\"newCampaignName\" style=\"width: 50%\" [(ngModel)]=\"m_campaignName\"\n               type=\"text\" class=\"form-control\"\n               value=\"My campaign\" i18n-placeholder placeholder=\"Enter new campaign name\">\n    `,\n})\nexport class CampaignName extends Compbaser {\n\n    constructor(private yp: YellowPepperService) {\n        super();\n    }\n\n    @Output()\n    onNext:EventEmitter<any> = new EventEmitter<any>();\n\n\n    m_campaignName: string = '';\n\n    public get getCampaignNameChanged(): string {\n        return this.m_campaignName;\n    }\n\n    _onKeyDown(event:KeyboardEvent){\n        if (event.keyCode==13){\n            this.onNext.emit();\n        }\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n        var uiState:IUiState = {\n            campaign: {\n                campaignCreateName: this.m_campaignName\n            }\n        }\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n\n}"
  },
  {
    "path": "src/app/campaigns/campaign-orientation.ts",
    "content": "import {Component, EventEmitter, forwardRef, Inject, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Observable, Observer} from \"rxjs\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\nexport enum OrientationEnum {\n    HORIZONTAL,\n    VERTICAL\n}\n\n// export type OrientationConst = \"HORIZONTAL\" | \"VERTICAL\";\n\n\n@Component({\n    selector: 'campaign-orientation',\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        .defaultOpacity {\n            opacity: 0.6;\n            cursor: pointer;\n        }\n\n        .selectedOrientation {\n            opacity: 1 !important;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <h4 i18n>screen orientation</h4>\n        <div id=\"orientationView\">\n            <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"50\">\n                <tr>\n                    <td align=\"center\">\n                        <img id=\"firstImage\" (click)=\"_nextClick.next(OrientationEnum.HORIZONTAL)\" [ngClass]=\"{'selectedOrientation': m_orientation==OrientationEnum.HORIZONTAL}\" class=\"defaultOpacity img-responsive\" src=\"assets/orientationH.png\"/>\n                    </td>\n                    <td align=\"center\">\n                        <img (click)=\"_nextClick.next(OrientationEnum.VERTICAL)\" [ngClass]=\"{'selectedOrientation': m_orientation==OrientationEnum.VERTICAL}\" class=\"defaultOpacity img-responsive\" src=\"assets/orientationV.png\"/>\n                    </td>\n                </tr>\n            </table>\n        </div>\n    `\n})\n\nexport class CampaignOrientation extends Compbaser {\n\n    m_orientation: OrientationEnum;\n    OrientationEnum = OrientationEnum;\n    _nextClick: Observer<any>;\n\n    constructor(@Inject(forwardRef(() => YellowPepperService)) private yp: YellowPepperService) {\n        super();\n        this.cancelOnDestroy(\n            Observable.create(observer => {\n                this._nextClick = observer\n            }).map((i_orientation) => {\n                this.m_orientation = i_orientation;\n                return i_orientation;\n            }).debounceTime(100)\n                .subscribe(() => {\n                    var uiState: IUiState = {\n                        campaign: {\n                            campaignCreateOrientation: this.m_orientation\n                        }\n                    }\n                    this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                    this.onSelection.emit(this.m_orientation)\n                }, (e) => {\n                    console.error(e)\n                })\n        )\n    }\n\n    @Output()\n    onSelection: EventEmitter<OrientationEnum> = new EventEmitter<OrientationEnum>();\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaign-props-manager.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Observable} from \"rxjs\";\nimport {SideProps} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\n@Component({\n    selector: 'campaign-props-manager',\n    styles: [`\n        ul {\n            padding: 0\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <ul id=\"campaignPropsManager\" matchBodyHeight=\"50\" style=\"overflow-y: auto; overflow-x: hidden\" [ngSwitch]=\"m_uiUserFocusItem$ | async\">\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.campaignProps\">\n                <campaign-props></campaign-props>\n            </div>\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.miniDashboard\">\n                <dashboard-props></dashboard-props>\n            </div>\n            <!--<div *ngSwitchCase=\"m_uiUserFocusItemEnum.campaignBoard\">-->\n            <!--<h1>NOT USED</h1>-->\n            <!--</div>-->\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.campaignEditor\">\n                <campaign-editor-props></campaign-editor-props>\n            </div>\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.timeline\">\n                <timeline-props></timeline-props>\n            </div>\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.channel\">\n                <channel-props></channel-props>\n            </div>\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.screenLayoutEditor\">\n                <screen-layout-editor-props></screen-layout-editor-props>\n            </div>\n            <!--<div *ngSwitchCase=\"m_uiUserFocusItemEnum.sceneBlock\">-->\n            <!--<block-prop></block-prop>-->\n            <!--</div>-->\n            <div *ngSwitchCase=\"m_uiUserFocusItemEnum.channelBlock\">\n                <channel-block-props></channel-block-props>\n            </div>\n        </ul>\n    `,\n})\nexport class CampaignPropsManager extends Compbaser {\n\n    constructor(private yp: YellowPepperService) {\n        super();\n        this.m_uiUserFocusItem$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n    }\n\n    m_uiUserFocusItemEnum = SideProps;\n    m_uiUserFocusItem$: Observable<SideProps>;\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaign-props.ts",
    "content": "import {Component, Input} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Observable} from \"rxjs\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_LIVELOG_UPDATE, ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport * as _ from \"lodash\";\nimport {simpleRegExp} from \"../../Lib\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\n\nenum CampaignPlaylistModeEnum  {\n    SEQUENCER,\n    SCHEDULER\n}\n\n@Component({\n    selector: 'campaign-props',\n    host: {\n        '(input-blur)': 'listenUpdatedFormBlur($event)'\n    },\n    template: `\n        <div>\n            <form novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n                <div class=\"row\">\n                    <div class=\"inner userGeneral\">\n                        <div class=\"panel panel-default tallPanel\">\n                            <div class=\"panel-heading\">\n                                <small class=\"release\">campaign properties\n                                    <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                                </small>\n                                <small class=\"debug\">{{me}}</small>\n                            </div>\n                            <ul class=\"list-group\">\n                                <li class=\"list-group-item\">\n                                    <span i18n>campaign id: </span>\n                                    {{m_campaignModel?.getCampaignId()}}\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <span i18n>kiosk mode</span>\n                                    <div class=\"material-switch pull-right\">\n                                        <input (change)=\"listenUpdatedFormBlur(customerNetwork2.checked)\"\n                                               [formControl]=\"m_contGroup.controls['kiosk_mode']\"\n                                               id=\"customerNetwork2\" #customerNetwork2\n                                               name=\"customerNetwork2\" type=\"checkbox\"/>\n                                        <label for=\"customerNetwork2\" class=\"label-primary\"></label>\n                                    </div>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <div class=\"input-group\">\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                                        <input (keyup.enter)=\"$event.preventDefault(); $event.stopImmediatePropagation()\" [formControl]=\"m_contGroup.controls['campaign_name']\" required\n                                               type=\"text\" class=\"form-control\" maxlength=\"50\"\n                                               placeholder=\"campaign name\">\n                                    </div>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <span i18n id=\"campaignModeLabel\">Campaign playback mode:</span>\n                                    <div class=\"row paddingCeilingFloor20\">\n                                        <div class=\"center-block\" style=\"width: 240px\">\n                                            <button type=\"button\" (click)=\"_onChangePlaylistMode(CampaignPlaylistModeEnum.SEQUENCER)\"\n                                                    [ngClass]=\"{faded: ((m_campaignModel$ | async)?.getCampaignPlaylistMode() == CampaignPlaylistModeEnum.SCHEDULER)}\"\n                                                    class=\"campaignPlayMode btn btn-default\">\n                                                <span class=\"fa fa-repeat\"></span>\n                                            </button>\n                                            <button type=\"button\" (click)=\"_onChangePlaylistMode(CampaignPlaylistModeEnum.SCHEDULER)\"\n                                                    [ngClass]=\"{faded: ((m_campaignModel$ | async)?.getCampaignPlaylistMode() == CampaignPlaylistModeEnum.SEQUENCER)}\"\n                                                    class=\"campaignPlayMode btn btn-default\">\n                                                <span class=\"fa fa-calendar\"></span>\n                                            </button>\n                                        </div>\n                                    </div>\n                                    <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == 0\">\n                                        <p i18n>Sequencer (simple mode):</p>\n                                        <p i18n>Play timelines for this campaign in a continuous loop. It is easy to setup and simple to use</p>\n                                    </div>\n                                    <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == 1\">\n                                        <p i18n>Scheduler (advanced mode): </p>\n                                        <p i18n>Play timelines for this campaign only on specific times. For example, play Timeline A in the morning and Timeline B at night.</p>\n                                    </div>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <div class=\"center-block row paddingCeilingFloor20\" style=\"width: 144px\">\n                                        <button type=\"button\" (click)=\"removeCampaign()\" class=\"btn btn-danger\">\n                                            <i class=\"fa fa-remove\"></i>\n                                            delete campaign\n                                        </button>\n                                    </div>\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n            </form>\n        </div>\n    `,\n    styles: [`\n        .faded {\n            opacity: 0.4;\n        }\n\n        .campaignPlayMode {\n            font-size: 4em;\n            width: 118px;\n        }\n\n        input.ng-invalid {\n            border-right: 10px solid red;\n        }\n\n        .material-switch {\n            position: relative;\n            padding-top: 10px;\n        }\n\n        .input-group {\n            padding-top: 10px;\n        }\n\n        i {\n            width: 20px;\n        }\n    `]\n})\nexport class CampaignProps extends Compbaser {\n\n    /**\n     * In this example we demonstrate two ways we can bind to the store values:\n     *\n     * 1. m_campaignModel$ via Observable subscription using async into the template: [ngClass]=\"{faded: ((m_campaignModel$ | async)?.getCampaignPlaylistMode() == 1)}\" ...\n     * 2. campaignModel direct grabbing the campaignModel from the store and doing a loop over keys: _.forEach(this.formInputs, (value, key: string) => { ...\n     *\n     * We also demoing here two ways of upding store:\n     * 1. reacting to input changes both via blur\n     * 2. reacting to the Observable of statusChanges\n     **/\n\n    m_campaignModel: CampaignsModelExt;\n    m_campaignModel$: Observable<CampaignsModelExt>;\n    private formInputs = {};\n    m_contGroup: FormGroup;\n    CampaignPlaylistModeEnum = CampaignPlaylistModeEnum;\n\n    constructor(private fb: FormBuilder, private ngmslibService: NgmslibService, private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.m_contGroup = fb.group({\n            'campaign_name': ['', [Validators.required, Validators.pattern(simpleRegExp)]],\n            'campaign_playlist_mode': [0],\n            'kiosk_mode': [0]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n\n        this.listenUpdatedFormReactive();\n\n        // example 1: subscribe to store slice via subscription and and set to local member campaignModel\n        this.cancelOnDestroy(\n            this.yp.listenCampaignSelected()\n                .subscribe((campaign: CampaignsModelExt) => {\n                    this.m_campaignModel = campaign;\n                    this.renderFormInputs();\n                    this.renderFormInputsReactive();\n                }, (e) => {\n                    console.error(e)\n                })\n        );\n\n        // example 2: hook to store slice observable and pipe to async in template\n        this.m_campaignModel$ = this.yp.listenCampaignValueChanged()\n\n    }\n\n    _onChangePlaylistMode(mode: number) {\n        switch (mode) {\n            case CampaignPlaylistModeEnum.SEQUENCER: {\n                this.rp.setCampaignRecord(this.m_campaignModel.getCampaignId(), 'campaign_playlist_mode', String(mode));\n                break;\n            }\n            case CampaignPlaylistModeEnum.SCHEDULER: {\n                this.rp.setCampaignRecord(this.m_campaignModel.getCampaignId(), 'campaign_playlist_mode', String(mode));\n                this.rp.checkAndCreateCampaignTimelineScheduler(this.m_campaignModel.getCampaignId());\n                break;\n            }\n        }\n\n        this.rp.reduxCommit();\n\n    }\n\n    // example 1 on input update via manually for looping\n    private renderFormInputs() {\n        if (!this.m_campaignModel)\n            return;\n        _.forEach(this.formInputs, (value, key: string) => {\n            let data = this.m_campaignModel.getKey(key);\n            data = StringJS(data).booleanToNumber();\n            this.formInputs[key].setValue(data)\n        });\n    };\n\n    // example 2 on input update via observable and patch value\n    private renderFormInputsReactive() {\n        this.cancelOnDestroy(\n            this.yp.listenCampaignSelected()\n                .subscribe((i_campaignModel: CampaignsModelExt) => {\n                    this.m_campaignModel = i_campaignModel;\n                    // var bb = this.m_campaignModel.toPureJs();\n                    // this.m_contGroup.patchValue(bb);\n                }, (e) => console.error(e))\n        );\n    };\n\n    // example on changes 1 blur\n    listenUpdatedFormBlur(event) {\n        this.saveToStore();\n    }\n\n    // example 2 on changes observable\n    private listenUpdatedFormReactive() {\n        this.cancelOnDestroy(\n            this.m_contGroup.statusChanges\n                .filter(valid => valid === 'VALID')\n                .withLatestFrom(this.m_contGroup.valueChanges, (valid, value) => value)\n                .debounceTime(100)\n                .subscribe(value => {\n                    // console.log('res ' + JSON.stringify(value) + ' ' + Math.random())\n                    this.saveToStore();\n                }, (e) => console.error(e))\n        )\n    }\n\n    @timeout()\n    private saveToStore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        if (this.m_contGroup.status != 'VALID')\n            return;\n        this.rp.setCampaignRecord(this.m_campaignModel.getCampaignId(), 'campaign_name', this.m_contGroup.value.campaign_name);\n        this.rp.setCampaignRecord(this.m_campaignModel.getCampaignId(), 'campaign_playlist_mode', this.m_contGroup.value.campaign_playlist_mode);\n        this.rp.setCampaignRecord(this.m_campaignModel.getCampaignId(), 'kiosk_timeline_id', 0); //todo: you need to fix this as zero is arbitrary number right now\n        this.rp.setCampaignRecord(this.m_campaignModel.getCampaignId(), 'kiosk_mode', this.m_contGroup.value.kiosk_mode);\n        this.rp.reduxCommit()\n    }\n\n    removeCampaign() {\n        var campaignId = this.m_campaignModel.getCampaignId();\n        var allCampaignIDs = this.rp.getStationCampaignIDs();\n        if (_.indexOf(allCampaignIDs, campaignId) > -1)\n            return bootbox.alert('Cannot remove this campaign as one or more stations are associated with it, be sure to remove them first.');\n        bootbox.confirm({\n            message: \"Are you sure you want to delete the campaign, there is NO WAY BACK?\",\n            buttons: {\n                confirm: {\n                    label: 'Yes',\n                    className: 'btn-success'\n                },\n                cancel: {\n                    label: 'No',\n                    className: 'btn-danger'\n                }\n            },\n            callback: (result) => {\n                if (result == true) {\n                    var campaignId = this.m_campaignModel.getCampaignId();\n                    this.rp.removeCampaignKeepBoards(campaignId);\n                    this.rp.reduxCommit();\n                    var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n                    this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                    this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'campaign deleted ' + campaignId})}));\n                }\n            }\n        });\n    }\n\n    destroy() {\n    }\n}\n\n"
  },
  {
    "path": "src/app/campaigns/campaign-resolution.ts",
    "content": "import {Component, ChangeDetectionStrategy, Input, Output, EventEmitter, ViewChild, ChangeDetectorRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport * as screenTemplates from \"../../libs/screen-templates.json\";\nimport {OrientationEnum} from \"./campaign-orientation\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Observable, Observer} from \"rxjs\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Once} from \"../../decorators/once-decorator\";\nimport {IUiState, IUiStateCampaign} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\n\n@Component({\n    selector: 'campaign-resolution',\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <h4 i18n>screen resolution</h4>\n        <div id=\"resolutionList\" (click)=\"$event.preventDefault()\">\n            <a (click)=\"_nextClick.next(screen)\" href=\"#\" class=\"list-group-item\" *ngFor=\"let screen of m_screens\">\n                <label class=\"screenResolutionLabel\">{{screen}}</label>\n            </a>\n        </div>\n    `,\n})\nexport class CampaignResolution extends Compbaser {\n\n    m_screens: Array<any> = [];\n    private m_resolution: string;\n    _nextClick: Observer<any>;\n\n    constructor(private yp: YellowPepperService) {\n        super();\n        this.getNewCampaignParams();\n\n        this.cancelOnDestroy(\n            Observable.create(observer => {\n                this._nextClick = observer\n            }).map((i_resolution) => {\n                this.m_resolution = i_resolution;\n                return i_resolution;\n            }).debounceTime(100)\n                .subscribe(() => {\n                    var uiState: IUiState = {\n                        campaign: {\n                            campaignCreateResolution: this.m_resolution\n                        }\n                    }\n                    this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                    this.onSelection.emit(this.m_resolution);\n                }, (e) => {\n                    console.error(e)\n                })\n        )\n    }\n\n    @Once()\n    private getNewCampaignParams() {\n        return this.yp.getNewCampaignParmas()\n            .subscribe((value: IUiStateCampaign) => {\n                this.m_screens = [];\n                var orientation:OrientationEnum = value.campaignCreateOrientation;\n                for (var screenResolution in screenTemplates[orientation]) {\n                    this.m_screens.push(screenResolution)\n                }\n            }, (e) => {\n                console.error(e)\n            })\n    }\n\n    @Output()\n    onSelection: EventEmitter<string> = new EventEmitter<string>();\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaign-sched-props.css",
    "content": ".carousel-control.left, .carousel-control.right {\n    background-image: none;\n\n}\n\n#schedulePriority img:first-child {\n    position: relative;\n    top: 5px;\n    left: 1px;\n}\n\n#schedulePriority img:last-child {\n    position: relative;\n    top: -4px;\n    left: -2px;\n}\n\n#schedulePriority img:hover {\n    cursor: pointer;\n}\n\n.offsetDurations {\n    float: right;\n    position: relative;\n    top: -10px;\n}\n\n.carousel-control.left span, .carousel-control.right span {\n    background-image: none;\n    color: gray;\n    font-size: 0.8em;\n}\n\n.carousel-control {\n    height: 30px;\n}\n\n.carousel-control.left {\n    position: absolute;\n    left: -15px;\n    top: 0px;\n\n}\n\n.carousel-control.right {\n    position: absolute;\n    top: 0px;\n}\n\ninput.ng-invalid {\n    border-right: 10px solid red;\n}\n\n.material-switch {\n    position: relative;\n    padding-top: 10px;\n}\n\n.input-group {\n    padding-top: 10px;\n}\n\ni {\n    width: 20px;\n}"
  },
  {
    "path": "src/app/campaigns/campaign-sched-props.html",
    "content": "<div>\n    <form novalidate autocomplete=\"off\" [formGroup]=\"contGroup\">\n        <div class=\"row\">\n            <div class=\"inner userGeneral\">\n                <div class=\"panel panel-default tallPanel\">\n                    <div class=\"panel-heading\">\n                        <small class=\"release\">scheduler properties\n                            <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                        </small>\n                        <small class=\"debug\">{{me}}</small>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <span i18n class=\"schedulerClass\">Conflict priority:</span>\n        <div id=\"schedulePriority\" style=\"width: 155px\" class=\"center-block schedulerClass\">\n            <img (click)=\"_setPriority(2)\" class=\"schedulePriorities\" name=\"2\" src=\"assets/trip1.png\"/>\n            <img (click)=\"_setPriority(1)\" class=\"schedulePriorities\" name=\"1\" src=\"assets/trip2.png\"/>\n            <img (click)=\"_setPriority(0)\" class=\"schedulePriorities\" name=\"0\" src=\"assets/trip3.png\"/>\n        </div>\n        <hr/>\n\n        <span i18n style=\"display: inline\">Duration: </span>\n        <app-duration-input class=\"offsetDurations\" [setDuration]=\"m_duration\" (durationChange)=\"_onDurationChanged($event)\">\n            <!--(durationChange)=\"_timelineDurationChange($event)\">-->\n        </app-duration-input>\n\n        <!--<span class=\"input-group-addon\"><i class=\"fa fa-key\"></i></span>-->\n        <!--<input style=\"height: 30px\" type=\"text\" [formControl]=\"contGroup.controls['duration']\"-->\n        <!--id=\"timepickerDurationInput\" class=\"schedulerClass\" name=\"start_time\" placeholder=\"hh:mm:ss\" data-default-time=\"false\">-->\n        <br/>\n        <div class=\"clearfix\"></div>\n        <span i18n class=\"schedulerClass\">Start time:</span>\n            <app-duration-input class=\"offsetDurations\" [setDuration]=\"m_startTime\" (durationChange)=\"_onStartTimeChanged($event)\">\n            <!--[setDuration]=\"m_duration\"-->\n            <!--(durationChange)=\"_timelineDurationChange($event)\">-->\n        </app-duration-input>\n\n        <!--<input style=\"height: 30px\" type=\"text\" id=\"timepickerTimeInput\" [formControl]=\"contGroup.controls['start_time']\"-->\n        <!--class=\"schedulerClass\" name=\"start_time\" placeholder=\"hh:mm:ss\" data-default-time=\"false\">-->\n        <br/>\n        <br/>\n        <br/>\n        <div id=\"schedulerContainer\" class=\"schedulerClass\">\n            <div class=\"bs-example\">\n                <div style=\"height: 200px\" id=\"schedulerRepeatMode\" class=\"carousel slide\" data-interval=\"false\" data-ride=\"carousel\">\n                    <div class=\"carousel-inner\">\n                        <div class=\"active item\">\n                            <div align=\"center\">\n                                <h4 i18n>play once</h4>\n                            </div>\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-clock-o\"></i></span>\n                                <input (blur)=\"_saveDates('once',$event)\" #datepickerSchedulerOnce type=\"date\" [formControl]=\"contGroup.controls['once']\"\n                                       class=\"form-control\"\n                                       placeholder=\"access key\">\n                            </div>\n                        </div>\n                        <div class=\"item\">\n                            <div align=\"center\">\n                                <h4 i18n>play daily</h4>\n                            </div>\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-clock-o\"></i></span>\n                                <input (blur)=\"_saveDates('daily_start',$event)\" #datepickerSchedulerDailyStart type=\"date\" [formControl]=\"contGroup.controls['daily_start']\"\n                                       class=\"form-control\"\n                                       placeholder=\"start date\">\n                            </div>\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-clock-o\"></i></span>\n                                <input (blur)=\"_saveDates('daily_end',$event)\" #datepickerSchedulerDailyEnd type=\"date\" [formControl]=\"contGroup.controls['daily_end']\"\n                                       class=\"form-control\"\n                                       placeholder=\"end date\">\n                            </div>\n                        </div>\n                        <div class=\"item\">\n                            <div align=\"center\">\n                                <h4 i18n>play weekly</h4>\n                            </div>\n\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-key\"></i></span>\n                                <input (blur)=\"_saveDates('weekly_start',$event)\" #datepickerSchedulerWeekStart type=\"date\" [formControl]=\"contGroup.controls['weekly_start']\" min=\"0\"\n                                       class=\"form-control\"\n                                       placeholder=\"start date\">\n                            </div>\n                            <div class=\"input-group\">\n                                <span class=\"input-group-addon\"><i class=\"fa fa-key\"></i></span>\n                                <input (blur)=\"_saveDates('weekly_end',$event)\" #datepickerSchedulerWeekEnd type=\"date\" [formControl]=\"contGroup.controls['weekly_end']\" min=\"0\"\n                                       class=\"form-control\"\n                                       placeholder=\"end date\">\n                            </div>\n                            <div>\n                                <br/>\n                                <span i18n>Select the days:</span>\n\n                                <div style=\"padding-left: 10px\">\n                                    <table id=\"scheduledDays\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" align=\"left\">\n                                        <tr *ngFor=\"let day of m_days; let i = index\">\n                                            <td>\n                                                <input (click)=\"_onDaysChanged($event.target.checked, day,i)\" class=\"scheduleDay\" [checked]=\"day.checked\" type=\"checkbox\">\n                                                <span> {{day.day}} </span>\n                                            </td>\n                                        </tr>\n                                    </table>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                    <div>\n                        <a (click)=\"_saveRepeat()\" class=\"carousel-control left\" href=\"#schedulerRepeatMode\" data-slide=\"prev\">\n                            <span class=\"glyphicon glyphicon-chevron-left\"></span>\n                        </a>\n                        <a (click)=\"_saveRepeat()\" class=\"carousel-control right\" href=\"#schedulerRepeatMode\" data-slide=\"next\">\n                            <span class=\"glyphicon glyphicon-chevron-right\"></span>\n                        </a>\n                    </div>\n\n                </div>\n            </div>\n\n        </div>\n\n    </form>\n</div>"
  },
  {
    "path": "src/app/campaigns/campaign-sched-props.ts",
    "content": "import {AfterViewInit, ChangeDetectorRef, Component, ElementRef, ViewChild} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport * as _ from \"lodash\";\nimport {CampaignTimelineSchedulesModel} from \"../../store/imsdb.interfaces_auto\";\n\n\n@Component({\n    selector: 'campaign-sched-props',\n    //changeDetection: ChangeDetectionStrategy.OnPush,\n    // host: {'(input-blur)': '_saveToStore($event)'},\n    templateUrl: './campaign-sched-props.html',\n    styleUrls: ['./campaign-sched-props.css']\n})\nexport class CampaignSchedProps extends Compbaser implements AfterViewInit {\n\n    private m_campaignTimelineSchedulesModel: CampaignTimelineSchedulesModel;\n    m_days: Array<any> = [];\n    m_startTime = 0;\n    m_duration = 0;\n    private formInputs = {};\n    contGroup: FormGroup;\n    private m_ONCE = '0';\n    private m_DAILY = '1';\n    private m_WEEKLY = '2';\n    private m_PRIORITY_LOW = 2;\n    private m_PRIORITY_MEDIUM = 1;\n    private m_PRIORITY_HIGH = 0;\n    private m_WEEKDAYS = [1, 2, 4, 8, 16, 32, 64];\n    private m_WEEKDAYS_NAME = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\n    constructor(private fb: FormBuilder, private el: ElementRef, private yp: YellowPepperService, private rp: RedPepperService, private cd: ChangeDetectorRef, private ngmslibService: NgmslibService) {\n        super();\n        this.contGroup = this.fb.group({\n            'once': [],\n            'weekly_start': ['1/1/2020'],\n            'weekly_end': ['1/1/2020'],\n            'daily_start': ['1/1/2020'],\n            'daily_end': ['1/1/2020']\n        });\n        _.forEach(this.contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.contGroup.controls[key] as FormControl;\n        })\n    }\n\n    ngAfterViewInit() {\n        this.cancelOnDestroy(\n            this.yp.listenSchedulerValueChanged()\n                .subscribe(i_campaignTimelineSchedulesModel => {\n                    this.m_campaignTimelineSchedulesModel = i_campaignTimelineSchedulesModel;\n                    this._renderConflictPriority();\n                    this._renderCarouselPosition();\n                    this._initTimePicker();\n                    this._initDays();\n                    this._renderFormInputs();\n                }, (e) => {\n                    console.error(e)\n                })\n        )\n    }\n\n    _setPriority(i_value: number) {\n        this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'priorty', i_value);\n        this.rp.reduxCommit();\n    }\n\n    _onDurationChanged(i_value) {\n        this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'duration', i_value);\n        this.rp.reduxCommit();\n    }\n\n    _onStartTimeChanged(i_value) {\n        this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'start_time', i_value);\n        this.rp.reduxCommit();\n    }\n\n    private _renderCarouselPosition() {\n        jQuery('#schedulerRepeatMode', this.el.nativeElement).carousel(Number(this.m_campaignTimelineSchedulesModel.getRepeatType()));\n    }\n\n    private _renderConflictPriority() {\n        if (this.m_campaignTimelineSchedulesModel.getPriorty() == this.m_PRIORITY_LOW) {\n            jQuery('#schedulePriority', this.el.nativeElement).find('img').eq(1).fadeTo('fast', 0.5).end().eq(2).fadeTo('fast', 0.5);\n        } else if (this.m_campaignTimelineSchedulesModel.getPriorty() == this.m_PRIORITY_MEDIUM) {\n            jQuery('#schedulePriority', this.el.nativeElement).find('img').eq(1).fadeTo('fast', 1).end().eq(2).fadeTo('fast', 0.5);\n        } else {\n            jQuery('#schedulePriority', this.el.nativeElement).find('img').eq(1).fadeTo('fast', 1).end().eq(2).fadeTo('fast', 1);\n        }\n    }\n\n    private _renderFormInputs() {\n\n        this.m_startTime = this.m_campaignTimelineSchedulesModel.getStartTime();\n        this.m_duration = this.m_campaignTimelineSchedulesModel.getDuration();\n\n        _.forEach(this.formInputs, (value, key: string) => {\n            switch (key) {\n                case 'once': {\n                    break;\n                }\n                case 'daily_start': {\n                }\n                case 'daily_end': {\n                }\n                case 'weekly_start': {\n                }\n                case 'weekly_end': {\n\n                    var startDate = this.m_campaignTimelineSchedulesModel.getStartDate().split(' ')[0];\n                    var endDate = this.m_campaignTimelineSchedulesModel.getEndDate().split(' ')[0];\n                    var xStart = new XDate(startDate).toString('yyyy-MM-dd');\n                    var xEnd = new XDate(endDate).toString('yyyy-MM-dd');\n                    this.formInputs['weekly_start'].setValue(xStart)\n                    this.formInputs['weekly_end'].setValue(xEnd)\n                    this.formInputs['daily_start'].setValue(xStart)\n                    this.formInputs['daily_end'].setValue(xEnd)\n                    this.formInputs['once'].setValue(xStart)\n                    return;\n                }\n\n                default: {\n                }\n            }\n            let data = this.m_campaignTimelineSchedulesModel.getKey(key);\n            data = StringJS(data).booleanToNumber();\n            this.formInputs[key].setValue(data)\n        });\n    };\n\n    private _initDays() {\n        this.m_days = [];\n        var weekDays = this.m_campaignTimelineSchedulesModel.getWeekDays();\n        this.m_WEEKDAYS.forEach((v, i) => {\n            var n = weekDays & v;\n            this.m_days.push({\n                day: this.m_WEEKDAYS_NAME[i],\n                checked: n == v ? true : false\n            })\n        });\n        this.cd.detectChanges()\n    }\n\n    private _initTimePicker() {\n        jQuery('#timepickerDurationInput', this.el.nativeElement).timepicker({\n            showSeconds: true,\n            showMeridian: false,\n            defaultTime: false,\n            minuteStep: 1,\n            secondStep: 1\n        });\n        jQuery('#timepickerTimeInput', this.el.nativeElement).timepicker({\n            showSeconds: true,\n            showMeridian: false,\n            defaultTime: false,\n            minuteStep: 1,\n            secondStep: 1\n        });\n    }\n\n    _onDaysChanged(checked, day: {}, i: number) {\n        var weekBitsTotal = 0;\n        this.m_days[i] = {\n            day: this.m_WEEKDAYS_NAME[i],\n            checked: checked\n        }\n        this.m_days.forEach((day, i) => {\n            if (day.checked)\n                weekBitsTotal = weekBitsTotal + this.m_WEEKDAYS[i]\n        });\n        this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'week_days', weekBitsTotal);\n        this.rp.reduxCommit()\n    }\n\n    _saveDates(key, event: MouseEvent) {\n        switch (key) {\n            case 'daily_start':\n            case 'weekly_start':\n            case 'once': {\n                var value = event.target['value'];\n                var date = new XDate(value).toString('MM/dd/yyyy') + ' 12:00:00 AM'\n                this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'start_date', date);\n                return;\n            }\n            case 'weekly_end':\n            case 'daily_end': {\n                var value = event.target['value'];\n                var date = new XDate(value).toString('MM/dd/yyyy') + ' 12:00:00 AM'\n                this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'end_date', date);\n                return;\n            }\n        }\n        this.rp.reduxCommit()\n    }\n\n    @timeout(1000)\n    _saveRepeat() {\n        this._saveToStore();\n    }\n\n    @timeout()\n    private _saveToStore(key?: string, event?: MouseEvent) {\n        var carouselIndex = jQueryAny('#schedulerRepeatMode .active', this.el.nativeElement).index('#schedulerRepeatMode .item', this.el.nativeElement);\n        this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'repeat_type', carouselIndex);\n        this.rp.reduxCommit()\n    }\n\n    destroy() {\n        jQuery('#timepickerDurationInput', this.el.nativeElement).off(\"hide.timepicker\");\n        jQuery('#timepickerTimeInput', this.el.nativeElement).off(\"hide.timepicker\");\n    }\n}\n\n\n\n// _listenTimepickerChanges() {\n//     jQuery('#timepickerDurationInput', this.el.nativeElement).on(\"hide.timepicker\", (e:any) => {\n//         var totalSeconds = this.rp.formatObjectToSeconds({\n//             hours: e.time.hours,\n//             minutes: e.time.minutes,\n//             seconds: e.time.seconds\n//         });\n//         this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'duration', totalSeconds);\n//         this.rp.reduxCommit();\n//     });\n//     jQuery('#timepickerTimeInput', this.el.nativeElement).on(\"hide.timepicker\", (e:any) => {\n//         var totalSeconds = this.rp.formatObjectToSeconds({\n//             hours: e.time.hours,\n//             minutes: e.time.minutes,\n//             seconds: e.time.seconds\n//         });\n//         this.rp.setCampaignsSchedule(this.m_campaignTimelineSchedulesModel.getCampaignTimelineId(), 'start_time', totalSeconds);\n//         this.rp.reduxCommit();\n//     });\n// }\n\n// var startTime = this.rp.formatSecondsToObject(this.m_campaignTimelineSchedulesModel.getStartTime());\n// var startTimeFormatted = `${startTime.hours}:${startTime.minutes}:${startTime.seconds}`;\n// this.formInputs['start_time'].setValue(startTimeFormatted);\n// jQuery('#timepickerTimeInput', this.el.nativeElement).timepicker('setTime', startTimeFormatted);\n// var duration = this.rp.formatSecondsToObject(this.m_campaignTimelineSchedulesModel.getDuration());\n// var durationFormatted = `${duration.hours}:${duration.minutes}:${duration.seconds}`;\n// this.formInputs['duration'].setValue(durationFormatted);\n// jQuery('#timepickerDurationInput', this.el.nativeElement).timepicker('setTime', durationFormatted);\n                    "
  },
  {
    "path": "src/app/campaigns/campaign-story-timeline.ts",
    "content": "/**\n Github repo: https://github.com/AlexWD/ds-timeline-widget\n **/\n\nimport {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {CampaignTimelineBoardViewerChanelsModel, CampaignTimelineChanelsModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Observable} from \"rxjs/Observable\";\nimport {BlockService, IBlockData} from \"../blocks/block-service\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {TimelineComponent} from \"./timeline/timeline.component\";\nimport {EventManager} from \"@angular/platform-browser\";\nimport {Lib} from \"../../Lib\";\nimport * as _ from \"lodash\";\nimport {List, Map} from \"immutable\";\n\ninterface IChannelCollection {\n    blocks: Array<number>;\n    channelId: number;\n}\n\ninterface IOutputs {\n    id: number;\n    name: string;\n    color: string;\n    selected: boolean;\n}\n\ninterface IChannels {\n    id: number;\n    viewerId: number;\n    name: string;\n    type: 'common' | 'normal';\n    color: string;\n    selected: boolean;\n}\n\ninterface IItem {\n    id: number;\n    type: 'output' | 'channel';\n    resource: Object;\n    title: string;\n    start: number;\n    duration: number;\n    channel: number;\n    selected: boolean;\n}\n\nexport interface ITimelineState {\n    zoom: number;\n    switch: boolean;\n    duration: number;\n    channels: Array<IChannels>;\n    outputs: Array<IOutputs>;\n    items: Array<IItem>;\n}\n\n@Component({\n    selector: 'campaign-story-timeline',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '(document:keyup)': 'handleKeyboardEvents($event,\"up\")',\n        '(document:keydown)': 'handleKeyboardEvents($event,\"down\")',\n        '(window:mouseup)': 'handleMouseEvents($event,\"up\")',\n        '(window:mousedown)': 'handleMouseEvents($event,\"down\")'\n    },\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div matchBodyHeight=\"350\" style=\"overflow: scroll\">\n            <app-timeline *ngIf=\"state && state.get('channels').length > 0\"\n                          [resources]=\"resources\"\n                          [state]=\"state\"\n                          (channelClicked)=\"onChannelClicked($event)\"\n                          (closedGaps)=\"itemsChanged($event)\"\n                          (alignedRight)=\"itemsChanged($event)\"\n                          (alignedLeft)=\"itemsChanged($event)\"\n                          (itemsClicked)=\"itemsClicked($event)\"\n                          (itemsResized)=\"itemsChanged($event)\"\n                          (itemAdded)=\"itemAdded($event)\"\n                          (channelAdded)=\"channelAdded($event)\"\n                          (resizedToLargest)=\"itemsChanged($event)\"\n                          (itemsMoved)=\"itemsMoved($event)\">\n            </app-timeline>\n        </div>\n    `\n})\nexport class CampaignStoryTimeline extends Compbaser implements AfterViewInit {\n\n    m_campaignTimelinesModels: List<CampaignTimelinesModel>;\n    campaignTimelinesModel: CampaignTimelinesModel;\n    m_contPressed: 'down' | 'up' = 'up';\n    m_selectedItems: Array<any> = [];\n    m_zoom = 1;\n\n    // @Output()\n    // stateChanged:EventEmitter<ITimelineState> = new EventEmitter<ITimelineState>();\n\n    resources = {\n        items: [\n            {\n                id: 1,\n                name: 'logo',\n                type: 'png',\n                time: '0',\n                size: '110KB',\n                src: 'assets/img/doc-13-128.png'\n            },\n            {\n                id: 2,\n                name: 'samplesvg',\n                type: 'svg',\n                time: '0',\n                size: '110KB',\n                src: 'assets/img/svgexample.svg'\n            }\n        ],\n        outputs: [\n            {\n                id: 1,\n                name: 'logo',\n                type: 'png',\n                time: '0',\n                size: '110KB',\n                src: 'assets/img/doc-13-128.png'\n            },\n            {\n                id: 2,\n                name: 'samplesvg',\n                type: 'svg',\n                time: '0',\n                size: '110KB',\n                src: 'assets/img/svgexample.svg'\n            }\n        ]\n    };\n    state: Map<any, any>;\n    // = Map({\n    //     zoom: 1,\n    //     duration: -1,\n    //     channels: [],\n    //     outputs: [],\n    //     items: []\n    // });\n\n    stateTemp: ITimelineState = {\n        zoom: 1,\n        switch: false,\n        duration: -1,\n        channels: [],\n        outputs: [],\n        items: []\n    }\n\n\n    // id = 0\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private cd: ChangeDetectorRef, private bs: BlockService, private eventManager: EventManager) {\n        super();\n\n        this.cancelOnDestroy(\n            this.yp.listenTimelineSelected()\n                .map((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                    this.campaignTimelinesModel = i_campaignTimelinesModel;\n                    console.log('selected timeline ' + i_campaignTimelinesModel.getCampaignTimelineId());\n                    return i_campaignTimelinesModel;\n                })\n                .mergeMap((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                    return this.yp.listenChannelsOfTimeline(i_campaignTimelinesModel.getCampaignTimelineId())\n                })\n                .do((i_channels: List<CampaignTimelineChanelsModel>) => {\n                    return this.updateStateChannels(i_channels);\n                })\n                .combineLatest(\n                    this.yp.listenCampaignTimelineBoardViewerSelected(true),\n                    this.yp.listenSelectedTimelineChanged(),\n                    this.yp.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players))\n                .map((i_data): List<CampaignTimelineChanelsModel> => {\n                    var i_campaignTimelinesModel = i_data[2];\n                    this.updateStateDuration(i_campaignTimelinesModel.getTimelineDuration());\n                    var i_campaignTimelineBoardViewerChanelsModel: CampaignTimelineBoardViewerChanelsModel = i_data[\"1\"]\n                    if (i_campaignTimelineBoardViewerChanelsModel)\n                        this.updateStateChannelSelection(i_campaignTimelineBoardViewerChanelsModel.getCampaignTimelineChanelId());\n                    return i_data[0];\n                })\n                .mergeMap((i_campaignTimelineChanelModels: List<CampaignTimelineChanelsModel>) => {\n                    var channelIds = [];\n                    i_campaignTimelineChanelModels.forEach((i_campaignTimelineChanelModel: CampaignTimelineChanelsModel) => {\n                        channelIds.push(i_campaignTimelineChanelModel.getCampaignTimelineChanelId());\n                    })\n                    return Observable.from(channelIds)\n                        .map((channelId) => {\n                            return this.yp.getChannelBlocks(channelId)\n                                .map((blocks) => {\n                                    if (blocks.length > 0) {\n                                        return {channelId, blocks};\n                                    } else {\n                                        return {channelId, blocks: [-1]};\n                                    }\n                                })\n                        })\n                        .combineAll()\n                })\n                .mergeMap((i_channelArray: Array<IChannelCollection>) => {\n                    return Observable.from(i_channelArray)\n                        .map((i_channelCollection: IChannelCollection) => {\n                            return Observable.from(i_channelCollection.blocks)\n                                .map((i_block) => {\n                                    if (i_block == -1) return Observable.of(-1);\n                                    return this.bs.getBlockData(i_block).map((block) => {\n                                        return {block, channelId: i_channelCollection.channelId}\n                                    })\n                                })\n                                .combineAll()\n                        })\n                        .combineAll()\n                })\n                .withLatestFrom(\n                    this.yp.ngrxStore.select(store => store.appDb.uiState.campaign.blockChannelSelected),\n                    (i_channels, i_blockIdSelected) => ({i_channels, i_blockIdSelected})\n                )\n                .subscribe(({i_channels, i_blockIdSelected}) => {\n                    this.updateStateBlocks(i_channels, i_blockIdSelected);\n                    this.applyState();\n                    this.cd.markForCheck();\n                }, e => console.error(e))\n        );\n    }\n\n    @ViewChild(TimelineComponent)\n    timelineComponent: TimelineComponent;\n\n    // @Input()\n    // set duration(i_duration:number) {\n    //     this.stateTemp.duration = i_duration;\n    //     this.applyState();\n    // }\n\n    @Input()\n    set zoom(i_zoom: number) {\n        this.stateTemp.zoom = i_zoom;\n        if (!this.timelineComponent) return;\n        this.applyState();\n        this.cd.detectChanges();\n        this.timelineComponent.changeZoom(null);\n    }\n\n    @Input()\n    set switchMode(i_mode: boolean) {\n        this.stateTemp.switch = i_mode;\n        this.applyState();\n    }\n\n    private updateStateChannelSelection(i_channelSelectedId: number) {\n        this.stateTemp.channels.forEach((ch, index) => {\n            if (ch.id == i_channelSelectedId) {\n                ch.selected = true;\n            } else {\n                ch.selected = false;\n            }\n            this.stateTemp.channels[index] = ch;\n        })\n    }\n\n    private updateStateDuration(i_duration: number) {\n        console.log('CampaignStoryTimeline: upd duration ' + i_duration);\n        this.stateTemp.duration = i_duration;\n    }\n\n    private updateStateChannels(i_channels: List<CampaignTimelineChanelsModel>) {\n        var channels = []\n        i_channels.forEach((i_channel: CampaignTimelineChanelsModel) => {\n            var channel: IChannels = {\n                id: i_channel.getCampaignTimelineChanelId(),\n                viewerId: this.rp.getAssignedViewerIdFromChannelId(i_channel.getCampaignTimelineChanelId()),\n                name: i_channel.getChanelName(),\n                color: '#' + Lib.DecimalToHex(i_channel.getChanelColor()),\n                type: 'normal',\n                selected: false\n            }\n            channels.push(channel);\n        });\n        this.stateTemp.channels = channels;\n    }\n\n    private updateStateBlocks(i_channels, i_blockIdSelected) {\n        var items = []\n        _.forEach(i_channels, (i_channel) => {\n            var channelId = i_channel[\"0\"].channelId;\n            var blockList = this._sortBlock(i_channel);\n            blockList.forEach((i_block) => {\n                if (i_block == -1) return;\n                var name;\n                if (i_block.block.scene) {\n                    name = i_block.block.scene.name;\n                } else if (i_block.block.resource) {\n                    name = i_block.block.resource.name;\n                } else {\n                    name = i_block.block.blockName;\n                }\n                var block: IBlockData = i_block.block\n                var item: IItem = {\n                    id: block.blockID,\n                    type: 'channel',\n                    channel: channelId,\n                    duration: block.duration,\n                    selected: i_blockIdSelected == block.blockID,\n                    title: name,\n                    start: block.offset,\n                    // uncomment for svg or png support\n                    // resource: {\n                    //     type: 'svg',\n                    //     src: \"assets/sample3.svg\"\n                    // }\n                    resource: {\n                        type: 'fa',\n                        src: i_block.block.blockFontAwesome\n                    }\n                }\n                items.push(item);\n            });\n            this.stateTemp.items = items;\n\n        })\n\n    }\n\n    private applyState() {\n        // if (this.stateTemp.duration == -1)\n        //     return;\n        if (!this.state)\n            return this.state = Map(this.stateTemp);\n        const currentState = this.state.toJS();\n        var equal = _.isEqual(currentState, this.stateTemp);\n        if (equal) return;\n        this.state = Map(this.stateTemp);\n        // this.stateChanged.emit(currentState);\n    }\n\n    private _sortBlock(i_blockList) {\n        var sorted = i_blockList.sort((a, b) => {\n            if (a.block.offset < b.block.offset)\n                return -1;\n            if (a.block.offset > b.block.offset)\n                return 1;\n            if (a.block.offset === b.block.offset)\n                return 0;\n        })\n        return sorted;\n    }\n\n    public closedGaps(){\n        this.timelineComponent.closeGaps();\n    }\n\n    public resizeToLargest(){\n        this.timelineComponent.resizeToLargest();\n    }\n\n    public alignLeft(){\n        this.timelineComponent.alignLeft();\n    }\n\n    public alignRight(){\n        this.timelineComponent.alignRight();\n    }\n\n    remove(id) {\n        // let index = this.items.findIndex(item => item.id === id)\n        // this.items.splice(index, 1)\n    }\n\n    reset() {\n        // this.items = []\n    }\n\n    add() {\n        // this.items.unshift({id: this.id++, name: 'item'})\n    }\n\n    itemsMoved(event) {\n        event.forEach((item) => {\n            // console.log(\"Item moved\", item);\n            this.rp.setBlockTimelineChannelBlockNewPosition(item.channel, item.id, \"player_offset_time\", item.start);\n\n        })\n        this.rp.reduxCommit();\n    }\n\n    channelAdded(event) {\n        // console.log(\"Channel added\", event);\n    }\n\n    onChannelClicked(event) {\n        var uiState: IUiState = {\n            campaign: {\n                campaignTimelineChannelSelected: event.id,\n                campaignTimelineBoardViewerSelected: event.id\n            }\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    handleMouseEvents(event: KeyboardEvent, direction) {\n        // con(event + ' ' + direction);\n    }\n\n    handleKeyboardEvents(event: KeyboardEvent, direction) {\n        var key = event.which || event.keyCode;\n        if (key != 17) return;\n        this.m_contPressed = direction;\n        return true;\n    }\n\n    itemsClicked(event) {\n        // con('Total items clicks ' + event.length);\n        if (this.m_contPressed == 'down' || event.length == 0) return;\n        const item = event[event.length - 1];\n        var uiState: IUiState = {\n            campaign: {\n                campaignTimelineBoardViewerSelected: item.channel,\n                campaignTimelineChannelSelected: item.channel,\n                blockChannelSelected: item.id\n            },\n            uiSideProps: SideProps.channelBlock\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    itemsChanged(event) {\n        event.forEach((item) => {\n            this.rp.setBlockTimelineChannelBlockNewPosition(item.channel, item.id, \"player_offset_time\", Math.round(item.start));\n            this.rp.setBlockTimelineChannelBlockNewPosition(item.channel, item.id, \"player_duration\", Math.round(item.duration));\n        })\n        this.rp.reduxCommit();\n    }\n\n    itemAdded(event) {\n        // console.log(\"Item Added\", event);\n    }\n\n    ngAfterViewInit() {\n\n\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/campaigns-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {Compbaser} from \"ng-mslib\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {AppdbAction, AuthenticateFlags} from \"../../store/actions/appdb.actions\";\nimport {PLACEMENT_CHANNEL} from \"../../interfaces/Consts\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {UserModel} from \"../../models/UserModel\";\n\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    // new animation, can't add due to aot limitation and angular language service bug\n    // host: {\n    //     '[@routerTransition]': '',\n    //     '[style.display]': \"'block'\"\n    // },\n    // animations: [routerTransition()],\n    providers: [BlockService, {\n        provide: \"BLOCK_PLACEMENT\",\n        useValue: PLACEMENT_CHANNEL\n    }],\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n\n    template: `\n        <small class=\"debug\">campaigns-navigation</small>\n        <div *ngIf=\"(userModel$ | async).getAccountType() == m_AuthenticateFlags.USER_ACCOUNT_PRO; else fullAccess\">\n            <limited-access></limited-access>            \n        </div>\n        <ng-template #fullAccess>\n            <panel-split-container>\n                <panel-split-main>\n                    <campaigns>\n                    </campaigns>\n                </panel-split-main>\n                <panel-split-side>\n                    <campaign-props-manager></campaign-props-manager>\n                </panel-split-side>\n            </panel-split-container>    \n        </ng-template>\n        \n    `\n})\nexport class CampaignsNavigation extends Compbaser {\n    userModel$;\n    m_AuthenticateFlags = AuthenticateFlags;\n    constructor(private actions: AppdbAction, private yp: YellowPepperService) {\n        super();\n        this.userModel$ = this.yp.listenUserModel();\n    }\n\n    destroy() {\n        this.actions.resetCampaignSelection();\n    }\n}\n\n"
  },
  {
    "path": "src/app/campaigns/campaigns.ts",
    "content": "import {ChangeDetectionStrategy, Component, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {ISliderItemData, Slideritem} from \"../../comps/sliderpanel/Slideritem\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState, IUiStateCampaign} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Once} from \"../../decorators/once-decorator\";\nimport {PLACEMENT_CHANNEL} from \"../../interfaces/Consts\";\nimport {IAddContents} from \"../../interfaces/IAddContent\";\nimport {CampaignTimelineBoardViewerChanelsModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {IScreenTemplateData} from \"../../interfaces/IScreenTemplate\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'campaigns',\n    template: `\n        <small class=\"debug\" style=\"padding-right: 25px\">{{me}}</small>\n        <Sliderpanel>\n            <Slideritem [templateRef]=\"a\" #sliderItemCampaignManager class=\"page center campaignList selected\" [showToButton]=\"false\" [toDirection]=\"'right'\" [to]=\"'campaignEditor'\">\n                <ng-template #a>\n                    <campaign-manager (slideToCampaignName)=\"sliderItemCampaignManager.slideTo('campaignName','right')\" (slideToCampaignEditor)=\"sliderItemCampaignManager.onNext()\"></campaign-manager>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"b\" #campaignNameSlider class=\"page left campaignName\" [toDirection]=\"'right'\" [fromDirection]=\"'left'\" [from]=\"'campaignList'\" [to]=\"'campaignOrientation'\">\n                <ng-template #b>\n                    <campaign-name (onNext)=\"campaignNameSlider.onNext()\" #campaignName></campaign-name>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"c\" #sliderItemCampaignOrientation class=\"page left campaignOrientation\" [showToButton]=\"false\" [toDirection]=\"'right'\" [fromDirection]=\"'left'\" [from]=\"'campaignName'\" [to]=\"'campaignResolution'\">\n                <ng-template #c>\n                    <campaign-orientation #campaignOrientation (onSelection)=\"sliderItemCampaignOrientation.onNext()\"></campaign-orientation>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"d\" #sliderItemCampaignResolution class=\"page left campaignResolution\" [showToButton]=\"false\" [toDirection]=\"'right'\" [fromDirection]=\"'left'\" [from]=\"'campaignOrientation'\" [to]=\"'campaignLayout'\">\n                <ng-template #d>\n                    <campaign-resolution #campaignResolution (onSelection)=\"sliderItemCampaignResolution.onNext()\"></campaign-resolution>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"e\" #sliderItemCampaignLayout (onChange)=\"_onSlideChange($event)\" class=\"page left campaignLayout\" [showToButton]=\"false\" [toDirection]=\"'right'\" [fromDirection]=\"'left'\" [from]=\"'campaignResolution'\"  [to]=\"'campaignEditor'\">\n                <ng-template #e>\n                    <campaign-layout [onNewCampaignMode]=\"true\" (onSelection)=\"sliderItemCampaignLayout.onNext(); _createCampaign($event)\"></campaign-layout>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"i\" #sliderItemCampaignLayoutAddTimeline (onChange)=\"_onSlideChange($event)\" class=\"page left campaignAddLayout\" [showToButton]=\"false\" [toDirection]=\"'right'\" [fromDirection]=\"'right'\" [from]=\"'campaignEditor'\">\n                <ng-template #i>\n                    <campaign-layout [mouseHoverEffect]=\"true\" [onNewCampaignMode]=\"false\" (onSelection)=\"_addTimelineToCampaign($event); sliderItemCampaignLayoutAddTimeline.onPrev();\"></campaign-layout>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"f\" #sliderItemCampaignEditor (onChange)=\"_onSlideChange($event)\" [showFromButton]=\"false\" class=\"page left campaignEditor\" [fromDirection]=\"'left'\" [from]=\"'campaignList'\">\n                <ng-template #f>\n                    <campaign-editor #campaignEditor\n                                     (onToAddTimeline)=\"sliderItemCampaignLayoutAddTimeline.slideTo('campaignAddLayout','left')\"\n                                     (onToAddContent)=\"sliderAddContent.slideTo('addContent','right')\"\n                                     (onToScreenLayoutEditor)=\"_onOpenScreenLayoutEditor() ; sliderScreenLayoutEditor.slideTo('screenLayoutEditor','right')\"\n                                     (onGoBack)=\"sliderItemCampaignEditor.slideTo('campaignList','left')\">\n                    </campaign-editor>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"g\" #sliderScreenLayoutEditor (onChange)=\"_onSlideChange($event)\" [showFromButton]=\"false\" class=\"page left screenLayoutEditor\" [fromDirection]=\"'left'\" [from]=\"'campaignList'\">\n                <ng-template #g>\n                    <screen-layout-editor #screenLayoutEditor (onGoBack)=\"sliderItemCampaignEditor.slideTo('campaignEditor','left')\"></screen-layout-editor>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"h\" #sliderAddContent [showFromButton]=\"true\" class=\"page left addContent\" [fromDirection]=\"'left'\" [from]=\"'campaignEditor'\">\n                <ng-template #h>\n                    <add-content #addContent [placement]=\"m_PLACEMENT_CHANNEL\" (onClosed)=\"_onAddedContentClosed()\" (onAddContentSelected)=\"_onAddedContent($event) ; sliderItemCampaignEditor.slideTo('campaignEditor','left')\"></add-content>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"j\" #sliderLocation [showFromButton]=\"false\" class=\"page left locationMap\" [fromDirection]=\"'right'\" [from]=\"'campaignEditor'\">\n                <ng-template #j>\n                    <location-map (onClose)=\"_onLocationMapClosed()\"></location-map>\n                </ng-template>\n            </Slideritem>\n            \n        </Sliderpanel>\n    `\n})\n\nexport class Campaigns extends Compbaser {\n\n    m_PLACEMENT_CHANNEL = PLACEMENT_CHANNEL;\n    private m_selected_campaign_timeline_chanel_id = -1;\n    private m_selected_campaign_timeline_id = -1;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private bs: BlockService) {\n        super();\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenTimelineSelected(true)\n                .subscribe((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                    if (!i_campaignTimelinesModel)\n                        return this.m_selected_campaign_timeline_id = -1;\n                    this.m_selected_campaign_timeline_id = i_campaignTimelinesModel.getCampaignTimelineId();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenCampaignTimelineBoardViewerSelected()\n                .subscribe((i_campaignTimelineBoardViewerChanelsModel: CampaignTimelineBoardViewerChanelsModel) => {\n                    this.m_selected_campaign_timeline_chanel_id = i_campaignTimelineBoardViewerChanelsModel.getCampaignTimelineChanelId();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenLocationMapLoad()\n                .subscribe((v) => {\n                    if (v && this.sliderItemCampaignEditor){\n                        this.sliderItemCampaignEditor.slideTo('locationMap','right');\n                    }\n            }, (e) => console.error(e))\n\n        )\n\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    @ViewChild('sliderItemCampaignEditor')\n    sliderItemCampaignEditor:Slideritem;\n\n    _onOpenScreenLayoutEditor() {\n    }\n\n    _onAddedContent(i_addContents: IAddContents) {\n        this.cancelOnDestroy(\n            //\n            this.yp.getTotalDurationChannel(this.m_selected_campaign_timeline_chanel_id)\n                .subscribe((i_totalChannelLength) => {\n                    var boilerPlate = this.bs.getBlockBoilerplate(i_addContents.blockCode);\n                    this.rp.createNewChannelPlayer(this.m_selected_campaign_timeline_chanel_id, i_addContents, boilerPlate, i_totalChannelLength);\n                    this.rp.updateTotalTimelineDuration(this.m_selected_campaign_timeline_id);\n                    this.rp.reduxCommit();\n                }, (e) => console.error(e))\n        )\n    }\n\n    _onLocationMapClosed(){\n        this.sliderItemCampaignEditor.slideTo('campaignEditor','left')\n        \n    }\n    \n    _onAddedContentClosed(){\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onSlideChange(event: ISliderItemData) {\n        if (event.direction == 'left' && event.to == 'campaignList') {\n            var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n            return this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        }\n        // if (event.direction == 'right' && event.to == 'campaignEditor')\n        //     return this._createCampaign();\n    }\n\n    @Once()\n    private _addTimelineToCampaign(i_screenTemplateData: IScreenTemplateData) {\n        return this.yp.getNewCampaignParmas()\n            .subscribe((value: IUiStateCampaign) => {\n                var campaign_board_id = this.rp.getFirstBoardIDofCampaign(value.campaignSelected);\n                var board_id = this.rp.getBoardFromCampaignBoard(campaign_board_id);\n                var newTemplateData = this.rp.createNewTemplate(board_id, i_screenTemplateData.screenProps);\n                var board_template_id = newTemplateData['board_template_id']\n                var viewers = newTemplateData['viewers'];\n                var campaign_timeline_id = this.rp.createNewTimeline(value.campaignSelected);\n                this.rp.setCampaignTimelineSequencerIndex(value.campaignSelected, campaign_timeline_id, 0);\n                this.rp.setTimelineTotalDuration(campaign_timeline_id, '0');\n                this.rp.createCampaignTimelineScheduler(value.campaignSelected, campaign_timeline_id);\n                var campaign_timeline_board_template_id = this.rp.assignTemplateToTimeline(campaign_timeline_id, board_template_id, campaign_board_id);\n                var channels = this.rp.createTimelineChannels(campaign_timeline_id, viewers);\n                this.rp.assignViewersToTimelineChannels(campaign_timeline_board_template_id, viewers, channels);\n                this.rp.reduxCommit();\n            }, (e) => {\n                console.error(e)\n            })\n    }\n\n    @Once()\n    private _createCampaign(i_screenTemplateData: IScreenTemplateData) {\n        return this.yp.getNewCampaignParmas()\n            .subscribe((value: IUiStateCampaign) => {\n                var campaignId = this.rp.createCampaignEntire(i_screenTemplateData.screenProps, i_screenTemplateData.name, value.campaignCreateResolution);\n                var uiState: IUiState = {campaign: {campaignSelected: campaignId}}\n                this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n            }, (e) => {\n                console.error(e)\n            })\n    }\n}\n\n"
  },
  {
    "path": "src/app/campaigns/channel-block-props.ts",
    "content": "import {AfterViewInit, Component, ElementRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {CampaignTimelineChanelPlayersModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {Lib} from \"../../Lib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {List} from \"immutable\";\nimport {CampaignTimelineChanelPlayersModelExt} from \"../../store/model/msdb-models-extended\";\nimport {StoryBoardListViewModeEnum} from \"../../store/store.data\";\n\n@Component({\n    selector: 'channel-block-props',\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div class=\"center-block\" style=\"width: 240px\">\n            <h5 id=\"resourceLengthDuration\" i18n>hours / minutes /seconds</h5>\n            <input id=\"blockLengthHours\" data-displayPrevious=\"false\" data-min=\"0\" data-max=\"23\" data-skin=\"tron\" data-width=\"60\" data-height=\"60\" data-thickness=\".2\" type=\"text\" class=\"knob\" data-fgColor=\"gray\">\n            <input id=\"blockLengthMinutes\" data-displayPrevious=\"false\" data-min=\"0\" data-max=\"59\" data-skin=\"tron\" data-width=\"60\" data-height=\"60\" data-thickness=\".2\" type=\"text\" class=\"knob\" data-fgColor=\"gray\">\n            <input id=\"blockLengthSeconds\" data-displayPrevious=\"false\" data-min=\"0\" data-max=\"59\" data-skin=\"tron\" data-width=\"60\" data-height=\"60\" data-thickness=\".2\" type=\"text\" class=\"knob\" data-fgColor=\"gray\">\n        </div>\n        <block-prop-container></block-prop-container>\n    `,\n})\nexport class ChannelBlockProps extends Compbaser implements AfterViewInit {\n\n    m_blockLengthHours = 0;\n    m_blockLengthMinutes = 0;\n    m_blockLengthSeconds = 0;\n\n    private m_selectedCampaignTimelinesModel: CampaignTimelinesModel;\n    private m_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModel\n\n    constructor(private rp: RedPepperService, private yp: YellowPepperService, private el: ElementRef) {\n        super();\n    }\n\n    ngAfterViewInit() {\n\n        this.cancelOnDestroy(\n            this.yp.listenTimelineSelected()\n                .subscribe((i_selectedCampaignTimelinesModel) => {\n                    this.m_selectedCampaignTimelinesModel = i_selectedCampaignTimelinesModel;\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenBlockChannelSelected()\n                .subscribe((i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModel) => {\n                    this.m_campaignTimelineChanelPlayersModel = i_campaignTimelineChanelPlayersModel;\n                    var totalSeconds = this.m_campaignTimelineChanelPlayersModel.getPlayerDuration()\n                    var totalSecondsObj = Lib.FormatSecondsToObject(totalSeconds);\n                    this.m_blockLengthHours = totalSecondsObj.hours;\n                    this.m_blockLengthMinutes = totalSecondsObj.minutes;\n                    this.m_blockLengthSeconds = totalSecondsObj.seconds;\n                    jQuery('#blockLengthHours', this.el.nativeElement).val(this.m_blockLengthHours).trigger('change');\n                    jQuery('#blockLengthMinutes', this.el.nativeElement).val(this.m_blockLengthMinutes).trigger('change');\n                    jQuery('#blockLengthSeconds', this.el.nativeElement).val(this.m_blockLengthSeconds).trigger('change');\n                }, (e) => console.error(e))\n        )\n        this._propLengthKnobsInit()\n    }\n\n    /**\n     Update the blocks offset times according to current order of LI elements and reorder accordingly in msdb.\n     @method _reOrderChannelBlocks\n     @return none\n     **/\n    _reOrderChannelBlocks() {\n        var self = this\n        this.cancelOnDestroy(\n            this.yp.getChannelBlockModels(this.m_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelId())\n                .withLatestFrom(this.yp.ngrxStore.select(store => store.appDb.uiState.campaign.storyBoardListViewModeSelected))\n                .filter(v => v[1] == StoryBoardListViewModeEnum.ListMode)\n                .subscribe((v: any) => {\n                    var i_campaignTimelineChanelPlayersModels: List<CampaignTimelineChanelPlayersModelExt> = v[0];\n                    var sorted = i_campaignTimelineChanelPlayersModels.sort((a, b) => {\n                        if (a.getPlayerOffsetTimeInt() < b.getPlayerOffsetTimeInt())\n                            return -1;\n                        if (a.getPlayerOffsetTimeInt() > b.getPlayerOffsetTimeInt())\n                            return 1;\n                        if (a.getPlayerOffsetTimeInt() === b.getPlayerOffsetTimeInt())\n                            return 0;\n                    })\n                    var playerOffsetTime: any = 0;\n                    sorted.forEach((i_campaignTimelineChanelPlayersModel) => {\n                        console.log(i_campaignTimelineChanelPlayersModel.getPlayerDuration() + ' ' + i_campaignTimelineChanelPlayersModel.getPlayerOffsetTime());\n                        var playerDuration = i_campaignTimelineChanelPlayersModel.getPlayerDuration();\n                        self.rp.setBlockRecord(i_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId(), 'player_offset_time', Lib.ToValidNumber(playerOffsetTime));\n                        console.log('player ' + i_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId() + ' offset ' + playerOffsetTime + ' playerDuration ' + playerDuration);\n                        playerOffsetTime = parseFloat(playerOffsetTime) + parseFloat(playerDuration);\n                    })\n                    self.rp.updateTotalTimelineDuration(this.m_selectedCampaignTimelinesModel.getCampaignTimelineId());\n                    self.rp.reduxCommit();\n\n                }, (e) => console.error(e))\n        )\n    }\n\n\n    /**\n     Create the block length knobs so a user can set the length of the block with respect to timeline_channel\n     @method _propLengthKnobsInit\n     @return none\n     **/\n    _propLengthKnobsInit() {\n        var self = this;\n        jQuery('.knob', this.el.nativeElement).knob({\n            /*change: function (value) {\n             console.log(\"change : \" + value);\n             var caller = this['i'][0].id;\n             },*/\n            release: function (value) {\n                // console.log(this.$.attr('value'));\n                // console.log(\"release : \" + value + ' ' + this['i'][0].id);\n                var caller = this['i'][0].id;\n\n                switch (caller) {\n                    case 'blockLengthHours': {\n                        self.m_blockLengthHours = parseInt(value)\n                        break;\n                    }\n                    case 'blockLengthMinutes': {\n                        self.m_blockLengthMinutes = parseInt(value)\n                        break;\n                    }\n                    case 'blockLengthSeconds': {\n                        self.m_blockLengthSeconds = parseInt(value)\n                        break;\n                    }\n                }\n\n                // log('upd: ' + self.m_block_id + ' ' + hours + ' ' + minutes + ' ' + seconds);\n                if (self.m_blockLengthHours == 0 && self.m_blockLengthMinutes == 0 && self.m_blockLengthSeconds < 5)\n                    return;\n                self.rp.setBlockTimelineChannelBlockLength(self.m_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId(), self.m_blockLengthHours, self.m_blockLengthMinutes, self.m_blockLengthSeconds);\n                self.rp.reduxCommit();\n                self._reOrderChannelBlocks();\n\n            },\n            /*cancel: function () {\n             console.log(\"cancel : \", this);\n             },*/\n            draw: function () {\n                if (this.$.data('skin') == 'tron') {\n\n                    var a = this.angle(this.cv)  // Angle\n                        , sa = this.startAngle          // Previous start angle\n                        , sat = this.startAngle         // Start angle\n                        , ea                            // Previous end angle\n                        , eat = sat + a                 // End angle\n                        , r = 1;\n\n                    this.g.lineWidth = this.lineWidth;\n\n                    this.o.cursor\n                    && (sat = eat - 0.3)\n                    && (eat = eat + 0.3);\n\n                    if (this.o.displayPrevious) {\n                        ea = this.startAngle + this.angle(this.v);\n                        this.o.cursor\n                        && (sa = ea - 0.3)\n                        && (ea = ea + 0.3);\n                        this.g.beginPath();\n                        this.g.strokeStyle = this.pColor;\n                        this.g.arc(this.xy, this.xy, this.radius - this.lineWidth, sa, ea, false);\n                        this.g.stroke();\n                    }\n\n                    this.g.beginPath();\n                    this.g.strokeStyle = r ? this.o.fgColor : this.fgColor;\n                    this.g.arc(this.xy, this.xy, this.radius - this.lineWidth, sat, eat, false);\n                    this.g.stroke();\n\n                    this.g.lineWidth = 2;\n                    this.g.beginPath();\n                    this.g.strokeStyle = this.o.fgColor;\n                    this.g.arc(this.xy, this.xy, this.radius - this.lineWidth + 1 + this.lineWidth * 2 / 3, 0, 2 * Math.PI, false);\n                    this.g.stroke();\n\n                    return false;\n                }\n            }\n        });\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/channel-props.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport * as _ from \"lodash\";\nimport {CampaignTimelineChanelsModel} from \"../../store/imsdb.interfaces_auto\";\nimport {Lib} from \"../../Lib\";\nimport {Subject} from \"rxjs/Subject\";\n\n@Component({\n    selector: 'channel-props',\n    host: {\n        '(input-blur)': 'onFormChange($event)'\n    },\n    template: `\n        <div style=\"padding-right: 5px\">\n            <form novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n                <div class=\"row\">\n                    <div class=\"inner userGeneral\">\n                        <div class=\"panel panel-default tallPanel\">\n                            <div class=\"panel-heading\">\n                                <small class=\"release\">channel properties\n                                    <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                                </small>\n                                <small class=\"debug\">{{me}}</small>\n                            </div>\n                            <ul class=\"list-group\">\n                                <li class=\"list-group-item\">\n                                    Name:\n                                    <!--Channel name: {{(m_channel$ | async)?.getChanelName()}}-->\n                                    <input class=\"pull-right\" [formControl]=\"m_contGroup.controls['chanel_name']\"/>\n                                    <hr/>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    Channel Color:\n                                    <!--<input class=\"pull-right\" [formControl]=\"m_contGroup.controls['chanel_color']\"/>-->\n                                    <!--<input #borderColor [disabled]=\"!borderSelection.checked\" (colorPickerChange)=\"m_channelColorChanged.next($event)\"-->\n                                    <input class=\"pull-right\" #borderColor (colorPickerChange)=\"m_channelColorChanged.next($event)\"\n                                           [cpOKButton]=\"true\" [cpOKButtonClass]=\"'btn btn-primary btn-xs'\"\n                                           [cpFallbackColor]=\"'#123'\"\n                                           [cpPresetColors]=\"[]\"\n                                           [(colorPicker)]=\"m_color\" [cpPosition]=\"'bottom'\"\n                                           [cpAlphaChannel]=\"'disabled'\" style=\"width: 185px\"\n                                           [style.background]=\"m_color\" [value]=\"m_color\"/>\n\n                                    <hr/>\n                                </li>\n\n                                <li class=\"list-group-item\">\n                                    <span i18n>repeat to fit</span>\n                                    <div class=\"material-switch pull-right\">\n                                        <input (change)=\"onFormChange(w1.checked)\"\n                                               [formControl]=\"m_contGroup.controls['repeat_to_fit']\"\n                                               id=\"w1\" #w1\n                                               name=\"w1\" type=\"checkbox\"/>\n                                        <label for=\"w1\" class=\"label-primary\"></label>\n                                    </div>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <span i18n> random order</span>\n                                    <div class=\"material-switch pull-right\">\n                                        <input (change)=\"onFormChange(w2.checked)\"\n                                               [formControl]=\"m_contGroup.controls['random_order']\"\n                                               id=\"w2\" #w2\n                                               name=\"w2\" type=\"checkbox\"/>\n                                        <label for=\"w2\" class=\"label-primary\"></label>\n                                    </div>\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n            </form>\n        </div>\n    `,\n    styles: [`\n        input.ng-invalid {\n            border-right: 10px solid red;\n        }\n\n        .material-switch {\n            position: relative;\n            padding-top: 10px;\n        }\n\n        .input-group {\n            padding-top: 10px;\n        }\n\n        i {\n            width: 20px;\n        }\n    `]\n})\nexport class ChannelProps extends Compbaser {\n\n    private channelModel: CampaignTimelineChanelsModel;\n    private formInputs = {};\n    // m_channel$: Observable<CampaignTimelineChanelsModel>;\n    m_contGroup: FormGroup;\n    m_color;\n    m_channelColorChanged = new Subject();\n\n    constructor(private fb: FormBuilder, private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.m_contGroup = fb.group({\n            'repeat_to_fit': [0],\n            'chanel_name': [''],\n            'chanel_color': ['#000'],\n            'random_order': [0]\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n        this.cancelOnDestroy(\n            this.yp.listenChannelSelected()\n                .subscribe((channel: CampaignTimelineChanelsModel) => {\n                    this.channelModel = channel;\n                    this.renderFormInputs();\n                }, (e) => {\n                    console.error(e)\n                })\n        );\n        this.cancelOnDestroy(\n            //\n            this.m_channelColorChanged\n                .debounceTime(1000)\n                .filter(v => v != '#123')\n                .subscribe((i_color: any) => {\n                    this.updateSore()\n                }, (e) => console.error(e))\n        )\n\n    }\n\n    onFormChange(event) {\n        this.updateSore();\n    }\n\n    @timeout()\n    private updateSore() {\n        // console.log(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        this.rp.setCampaignTimelineChannelRecord(this.channelModel.getCampaignTimelineChanelId(), 'random_order', this.m_contGroup.value.random_order);\n        this.rp.setCampaignTimelineChannelRecord(this.channelModel.getCampaignTimelineChanelId(), 'repeat_to_fit', this.m_contGroup.value.repeat_to_fit);\n        this.rp.setCampaignTimelineChannelRecord(this.channelModel.getCampaignTimelineChanelId(), 'chanel_name', this.m_contGroup.value.chanel_name);\n        this.rp.setCampaignTimelineChannelRecord(this.channelModel.getCampaignTimelineChanelId(), 'chanel_color', Lib.ColorToDecimal(this.m_color));\n        this.rp.reduxCommit()\n    }\n\n    private renderFormInputs() {\n        if (!this.channelModel)\n            return;\n        _.forEach(this.formInputs, (value, key: string) => {\n            let data = this.channelModel.getKey(key);\n            data = StringJS(data).booleanToNumber();\n            if (key == 'chanel_color')\n                this.m_color = '#' + Lib.DecimalToHex(data);\n            this.formInputs[key].setValue(data)\n        });\n    };\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/campaigns/dashboard-props.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy} from \"@angular/core\";\nimport {FormControl, FormGroup, FormBuilder} from \"@angular/forms\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport * as _ from \"lodash\";\nimport {Observable} from \"rxjs\";\nimport {UserModel} from \"../../models/UserModel\";\n\n@Component({\n    selector: 'dashboard-props',\n    host: {\n        '(input-blur)': 'onFormChange($event)'\n    },\n    template: `\n        <dash-panel-mini></dash-panel-mini>\n        <!--<div>-->\n            <!--<h3>Mini Dashboard!!!</h3>-->\n            <!--<div>-->\n                <!--<chart style=\"position: relative; left: -150px\" [options]=\"options\"></chart>-->\n                <!--<h4>user name: {{(userModel$ | async)?.getUser() }}</h4>-->\n                <!--<h4>account type: {{(userModel$ | async)?.getAccountType()}}</h4>-->\n            <!--</div>-->\n        <!--</div>-->\n    `\n\n})\nexport class DashboardProps extends Compbaser {\n\n    // options: Object;\n    // public userModel$: Observable<UserModel>;\n\n    constructor(private yp: YellowPepperService) {\n        super();\n        // this.userModel$ = this.yp.ngrxStore.select(store => store.appDb.userModel);\n        // this.options = {\n        //     chart: {\n        //         plotBackgroundColor: null,\n        //         plotBorderWidth: null,\n        //         plotShadow: false,\n        //         type: 'pie',\n        //         height: '250'\n        //     },\n        //     title : { text : 'simple chart' },\n        //     series: [{\n        //         data: [29.9, 71.5, 106.4, 129.2],\n        //     }]\n        // };\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/campaigns/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {CampaignsNavigation} from \"./campaigns-navigation\";\nimport {DropdownModule, DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {Campaigns} from \"./campaigns\";\nimport {OrderListModule} from \"primeng/components/orderlist/orderlist\";\nimport {CampaignManager} from \"./campaign-manager\";\nimport {CampaignName} from \"./campaign-name\";\nimport {CampaignOrientation} from \"./campaign-orientation\";\nimport {CampaignLayout} from \"./campaign-layout\";\nimport {CampaignEditor} from \"./campaign-editor\";\nimport {CampaignResolution} from \"./campaign-resolution\";\nimport {CampaignList} from \"./campaign-list\";\nimport {Sequencer} from \"./sequencer\";\nimport {ScreenLayoutEditor} from \"./screen-layout-editor\";\nimport {ScreenLayoutEditorProps} from \"./screen-layout-editor-props\";\nimport {CampaignProps} from \"./campaign-props\";\nimport {TimelineProps} from \"./timeline-props\";\nimport {ChannelProps} from \"./channel-props\";\nimport {DashboardProps} from \"./dashboard-props\";\nimport {CampaignEditorProps} from \"./campaign-editor-props\";\nimport {CampaignSchedProps} from \"./campaign-sched-props\";\nimport {CampaignPropsManager} from \"./campaign-props-manager\";\nimport {CampaignChannels} from \"./campaign-channels\";\nimport {ChannelBlockProps} from \"./channel-block-props\";\nimport {CampaignDuration} from \"./campaign-duration\";\nimport {Ng2Bs3ModalModule} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {TimelineComponent} from \"./timeline/timeline.component\";\nimport {TimelineRulerComponent} from \"./timeline-ruler/timeline-ruler.component\";\nimport {CampaignStoryTimeline} from \"./campaign-story-timeline\";\nimport {HourCounter} from \"../../comps/hour-counter/hour-counter\";\nimport {DurationInputComponent} from \"../../comps/duration-input/duration-input.component\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: CampaignsNavigation},\n    {path: ':folder/:id', component: CampaignsNavigation},\n    {path: '**', component: CampaignsNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, DropdownModule, OrderListModule, Ng2Bs3ModalModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [CampaignsNavigation, Campaigns, CampaignManager, CampaignName, CampaignOrientation, CampaignLayout, TimelineComponent, TimelineRulerComponent, HourCounter,\n        CampaignEditor, CampaignResolution, CampaignList, Sequencer, ScreenLayoutEditor, ScreenLayoutEditorProps, CampaignChannels, CampaignDuration, CampaignStoryTimeline, DurationInputComponent,\n        CampaignPropsManager, CampaignProps, TimelineProps, ChannelProps, DashboardProps, CampaignEditorProps, CampaignSchedProps, ChannelBlockProps]\n})\nexport class CampaignsLazyModule {\n}"
  },
  {
    "path": "src/app/campaigns/screen-layout-editor-props.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup} from \"@angular/forms\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport * as _ from \"lodash\";\nimport {BoardTemplateViewersModel} from \"../../store/imsdb.interfaces_auto\";\n\n@Component({\n    selector: 'screen-layout-editor-props',\n    //changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '(input-blur)': '_saveToStore($event)'\n    },\n    styles: [`\n        /*:host > > > .ui-spinner-input {*/\n        /*width: 60px;*/\n        /*}*/\n\n        input {\n            width: 70px;\n        }\n\n        .spinLabel {\n            display: inline-block;\n            width: 70px;\n        }\n    `],\n    template: `\n        <div>\n            <form novalidate autocomplete=\"off\" [formGroup]=\"contGroup\">\n                <div class=\"row\">\n                    <div class=\"inner userGeneral\">\n                        <div class=\"panel panel-default tallPanel\">\n                            <div class=\"panel-heading\">\n                                <small class=\"release\">layout properties\n                                    <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                                </small>\n                                <small class=\"debug\">{{me}}</small>\n                            </div>\n                            <ul class=\"list-group\">\n                                <li class=\"list-group-item\">\n                                    <div class=\"spinLabel\">top:</div>\n                                    <input (change)=\"_saveToStore()\" type=\"number\" class=\"numStepper\" [formControl]=\"contGroup.controls['pixel_y']\">\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <div class=\"spinLabel\">left:</div>\n                                    <input (change)=\"_saveToStore()\" type=\"number\" class=\"numStepper\" [formControl]=\"contGroup.controls['pixel_x']\">\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <div class=\"spinLabel\">width:</div>\n                                    <input (change)=\"_saveToStore()\" type=\"number\" type=\"number\" class=\"numStepper\" [formControl]=\"contGroup.controls['pixel_width']\">\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <div class=\"spinLabel\">height:</div>\n                                    <input (change)=\"_saveToStore()\" type=\"number\" class=\"numStepper\" [formControl]=\"contGroup.controls['pixel_height']\">\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n            </form>\n        </div>\n    `\n\n})\nexport class ScreenLayoutEditorProps extends Compbaser {\n\n    private boardTemplateModel: BoardTemplateViewersModel;\n    private formInputs = {};\n    contGroup: FormGroup;\n\n    constructor(private fb: FormBuilder, private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n\n        this.contGroup = fb.group({\n            'pixel_height': [0],\n            'pixel_width': [0],\n            'pixel_x': [0],\n            'pixel_y': [0]\n        });\n        _.forEach(this.contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.contGroup.controls[key] as FormControl;\n        })\n        this.cancelOnDestroy(\n            this.yp.listenGlobalBoardSelectedChanged(true)\n                .subscribe((boardTemplateModel: BoardTemplateViewersModel) => {\n                    if (!boardTemplateModel) {\n                        _.forEach(this.formInputs, (value, key: string) => {\n                            this.formInputs[key].disable();\n                            this.formInputs[key].setValue(0);\n                        });\n                        return;\n                    }\n                    _.forEach(this.formInputs, (value, key: string) => {\n                        this.formInputs[key].enable();\n                    });\n                    this.boardTemplateModel = boardTemplateModel;\n                    this.renderFormInputs();\n                }, (e) => console.error(e))\n        )\n    }\n\n    _saveToStore() {\n        // console.log(this.contGroup.status + ' ' + JSON.stringify(this.contGroup.value));\n        if (this.contGroup.status != 'VALID' || !this.boardTemplateModel)\n            return;\n        var props = {\n            x: this.contGroup.value.pixel_x,\n            y: this.contGroup.value.pixel_y,\n            w: this.contGroup.value.pixel_width,\n            h: this.contGroup.value.pixel_height\n        }\n        this.rp.setBoardTemplateViewer(-1, this.boardTemplateModel.getBoardTemplateViewerId(), props);\n        this.rp.reduxCommit()\n    }\n\n    private renderFormInputs() {\n        _.forEach(this.formInputs, (value, key: string) => {\n            let data = this.boardTemplateModel.getKey(key);\n            data = StringJS(data).booleanToNumber();\n            this.formInputs[key].setValue(data)\n        });\n    };\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/campaigns/screen-layout-editor.ts",
    "content": "import {AfterViewInit, Component, ComponentFactoryResolver, ComponentRef, ElementRef, EventEmitter, Output, ViewChild, ViewContainerRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {BoardTemplateViewersModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {Observable} from \"rxjs\";\nimport {OrientationEnum} from \"./campaign-orientation\";\nimport {ScreenTemplate} from \"../../comps/screen-template/screen-template\";\nimport * as _ from \"lodash\";\nimport {Lib} from \"../../Lib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport Any = jasmine.Any;\nimport {IScreenTemplateData} from \"../../interfaces/IScreenTemplate\";\n\ninterface selectTimelineBoardIdResult {\n    campaignTimelinesModel: CampaignTimelinesModel,\n    campaign_timeline_board_template_ids: number[]\n}\n\n@Component({\n    selector: 'screen-layout-editor',\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div [hidden]=\"true\">\n            <ng-container #container></ng-container>\n        </div>\n        <div id=\"screenLayoutEditorView\">\n            <button (click)=\"_goBack()\" id=\"prev\" type=\"button\" class=\"openPropsButton btn btn-default btn-sm\">\n                <span class=\"glyphicon glyphicon-chevron-left\"></span>\n            </button>\n            <h3 data-localize=\"empty\" data-localize=\"editScreenLayoutTitle\">Edit screen layout</h3>\n\n            <div class=\"btn-group\">\n                <button (click)=\"_onAddDivision()\" id=\"layoutEditorAddNew\" type=\"button\" data-localize-tooltip=\"addButtonToolTip\" title=\"add\" class=\"btn btn-default btn-sm\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-plus\"> </i>\n                </button>\n                <button (click)=\"_onRemoveDivision()\" id=\"layoutEditorRemove\" type=\"button\" data-localize-tooltip=\"removeButtonToolTip\" title=\"remove division\" class=\"btn btn-default btn-sm\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-minus\"> </i>\n                </button>\n                <button (click)=\"_onPushTop()\" id=\"layoutEditorPushTop\" type=\"button\" data-localize-tooltip=\"pushDivToTopButtonToolTip\" title=\"push division to top\" class=\"btn btn-default btn-sm\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-angle-double-up\"> </i>\n                </button>\n                <button (click)=\"_onPushBottom()\" id=\"layoutEditorPushBottom\" type=\"button\" data-localize-tooltip=\"pushDivToBottomButtonToolTip\" title=\"push division to bottom\" class=\"btn btn-default btn-sm\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-angle-double-down\"> </i>\n                </button>\n                <button (click)=\"_selectNextDivision()\" id=\"layoutEditorNext\" type=\"button\" data-localize-tooltip=\"getNextDivButtonToolTip\" title=\"get next division\" class=\"btn btn-default btn-sm\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-external-link\"> </i>\n                </button>\n            </div>\n        </div>\n        <div style=\"width: 100%; background-color: white; padding-top: 60px; padding-bottom: 60px\">\n            <div class=\"center-block\" style=\"width: 500px\" id=\"screenLayoutEditorCanvasWrap\">\n            </div>\n        </div>\n    `,\n})\nexport class ScreenLayoutEditor extends Compbaser implements AfterViewInit {\n\n    RATIO = 4;\n    m_canvas;\n    m_canvasID;\n    m_onOverlap;\n    m_selectedViewerID;\n    m_bgSelectedHandler;\n    m_orientation: OrientationEnum;\n    m_objectMovingHandler;\n    m_resolution: string;\n    m_screenTemplateData: IScreenTemplateData;\n    m_global_board_template_id: number = -1;\n    m_campaign_timeline_id: number = -1;\n    m_campaign_timeline_board_template_id: number = -1;\n\n    private boardTemplateModel: BoardTemplateViewersModel;\n    private componentRef: ComponentRef<ScreenTemplate>;\n\n    constructor(private yp: YellowPepperService, private componentFactoryResolver: ComponentFactoryResolver, private rp: RedPepperService, private el: ElementRef) {\n        super();\n    }\n\n    @ViewChild('container', {read: ViewContainerRef})\n    container: ViewContainerRef;\n\n    /**\n     Constructor\n     @method initialize\n     **/\n    ngAfterViewInit() {\n        this.cancelOnDestroy(\n            this.yp.listenTimelineSelected()\n                .concatMap((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                    return this.yp.getTemplatesOfTimeline(i_campaignTimelinesModel.getCampaignTimelineId())\n                        .flatMap((i_campaign_timeline_board_template_ids) => {\n                            return Observable.of({\n                                campaign_timeline_board_template_ids: i_campaign_timeline_board_template_ids,\n                                campaignTimelinesModel: i_campaignTimelinesModel\n                            })\n                        })\n                }).subscribe((result: selectTimelineBoardIdResult) => {\n                this.m_campaign_timeline_id = result.campaignTimelinesModel.getCampaignTimelineId();\n                this.m_campaign_timeline_board_template_id = result.campaign_timeline_board_template_ids[0];\n                this.selectView(result.campaignTimelinesModel.getCampaignTimelineId(), this.m_campaign_timeline_board_template_id);\n            }, (e) => {\n                console.error(e)\n            })\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenGlobalBoardSelectedChanged()\n                .subscribe((boardTemplateModel: BoardTemplateViewersModel) => {\n                    this.boardTemplateModel = boardTemplateModel;\n                    var props = {\n                        h: boardTemplateModel.getPixelHeight(),\n                        w: boardTemplateModel.getPixelWidth(),\n                        x: boardTemplateModel.getPixelX(),\n                        y: boardTemplateModel.getPixelY()\n                    }\n                    this._moveViewer(props)\n                }, (e) => {\n                    console.error(e)\n                })\n        )\n    }\n\n    /**\n     Move the object / viewer to new set of coords\n     @method _moveViewer\n     @param {Object} i_props\n     **/\n    _moveViewer(i_props) {\n        var self = this;\n        var viewer = self.m_canvas.getActiveObject();\n        if (viewer) {\n            viewer.setWidth(i_props.w / self.RATIO);\n            viewer.setHeight(i_props.h / self.RATIO);\n            viewer.set('left', i_props.x / self.RATIO);\n            viewer.set('top', i_props.y / self.RATIO);\n            self._enforceViewerMinimums(viewer);\n            self._enforceViewerVisible();\n            viewer.setCoords();\n            self.m_canvas.renderAll();\n        }\n    }\n\n    /**\n     Listen to the removal of an existing screen division\n     @method _listenRemoveDivision\n     **/\n    _onRemoveDivision() {\n        var self = this;\n        if (_.isUndefined(self.m_canvas))\n            return;\n        var totalViews = self.m_canvas.getObjects().length;\n        if (totalViews < 2) {\n            bootbox.alert('you must keep at least one viewable screen division');\n            return;\n        }\n        var campaign_timeline_chanel_id = this.rp.removeTimelineBoardViewerChannel(self.m_selectedViewerID);\n        this.rp.removeBoardTemplateViewer(self.m_campaign_timeline_board_template_id, self.m_selectedViewerID);\n        this.rp.removeChannelFromTimeline(campaign_timeline_chanel_id);\n        this.rp.removeBlocksFromTimelineChannel(campaign_timeline_chanel_id);\n        self.m_canvas.remove(self.m_canvas.getActiveObject());\n        self.m_canvas.renderAll();\n        this.rp.reduxCommit();\n        /*var viewer = self.m_canvas.item(0);\n         var props = {\n         y: viewer.get('top'),\n         x: viewer.get('left'),\n         w: viewer.get('width') * self.RATIO,\n         h: viewer.get('height') * self.RATIO\n         };\n         self._saveToStore(viewer, props);\n         BB.comBroker.fire(BB.EVENTS.VIEWER_REMOVED, this, this, {\n         campaign_timeline_chanel_id: campaign_timeline_chanel_id\n         });\n         pepper.announceTemplateViewerEdited(self.m_campaign_timeline_board_template_id);\n         */\n    }\n\n    /**\n     Listen to the addition of a new viewer\n     @method (totalViews - i)\n     **/\n    _onAddDivision() {\n        var self = this;\n        this.m_selectedViewerID  = -1;\n        self.m_canvas.deactivateAll().renderAll();\n        var props = {\n            x: 0,\n            y: 0,\n            w: 100,\n            h: 100\n        }\n        var board_viewer_id = this.rp.createViewer(self.m_global_board_template_id, props);\n        var campaign_timeline_chanel_id = this.rp.createTimelineChannel(self.m_campaign_timeline_id);\n        this.rp.assignViewerToTimelineChannel(self.m_campaign_timeline_board_template_id, board_viewer_id, campaign_timeline_chanel_id);\n        var viewer = new fabric.Rect({\n            left: 0,\n            top: 0,\n            fill: '#ececec',\n            id: board_viewer_id,\n            hasRotatingPoint: false,\n            borderColor: '#5d5d5d',\n            stroke: 'black',\n            strokeWidth: 1,\n            borderScaleFactor: 0,\n            lineWidth: 1,\n            width: 100,\n            height: 100,\n            cornerColor: 'black',\n            cornerSize: 5,\n            lockRotation: true,\n            transparentCorners: false\n        });\n        self.m_canvas.add(viewer);\n\n        var props = {\n            x: 0,\n            y: 0,\n            w: viewer.get('width') * self.RATIO,\n            h: viewer.get('height') * self.RATIO\n        }\n        self._saveToStore(viewer, props);\n        self.rp.reduxCommit();\n    }\n\n    /**\n     Load the editor into DOM using the StackView using animation slider\n     @method  selectView\n     **/\n    selectView(i_campaign_timeline_id, i_campaign_timeline_board_template_id) {\n        this.cancelOnDestroy(\n            this.yp.getGlobalTemplateIdOfTimeline(i_campaign_timeline_board_template_id)\n                .concatMap((i_board_template_id) => {\n                    this.m_global_board_template_id = i_board_template_id[0];\n                    return this.yp.getTemplateViewersScreenProps(i_campaign_timeline_id, i_campaign_timeline_board_template_id)\n                })\n                .subscribe((screenTemplateData: IScreenTemplateData) => {\n                    this.m_orientation = screenTemplateData.orientation;\n                    this.m_resolution = screenTemplateData.resolution;\n                    this.m_screenTemplateData = screenTemplateData;\n                    var w = parseInt(this.m_resolution.split('x')[0]) / this.RATIO;\n                    var h = parseInt(this.m_resolution.split('x')[1]) / this.RATIO;\n                    this._canvasFactory(w, h);\n                    this._listenObjectChanged();\n                    this._listenObjectsOverlap();\n                    this._listenBackgroundSelected();\n                }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Listen to re-order of screen division, putting selected on top\n     @method _listenPushToTopDivision\n     **/\n    _onPushTop() {\n        var self = this;\n        var viewer = self.m_canvas.getActiveObject();\n        if (!viewer)\n            return;\n        self.m_canvas.bringToFront(viewer);\n        self._updateZorder();\n    }\n\n    /**\n     Change the z-order of viewers in pepper\n     @method _updateZorder\n     **/\n    _updateZorder() {\n        var self = this;\n        var viewers = self.m_canvas.getObjects();\n        for (var i in viewers) {\n            // log(viewers[i].get('id') + ' ' + i);\n            this.rp.updateTemplateViewerOrder(viewers[i].get('id'), i);\n        }\n        var active = self.m_canvas.getActiveObject();\n        self.m_canvas.setActiveObject(active);\n        this.rp.reduxCommit();\n    }\n\n    /**\n     Listen to re-order of screen division, putting selected at bottom\n     @method _listenPushToBottomDivision\n     **/\n    _onPushBottom() {\n        var self = this;\n        var viewer = self.m_canvas.getActiveObject();\n        if (!viewer)\n            return;\n        self.m_canvas.sendToBack(viewer);\n        self._updateZorder();\n    }\n\n    /**\n     Listen to changes on selecting the background canvas\n     @method _listenBackgroundSelected\n     **/\n    _listenBackgroundSelected() {\n        var self = this;\n        self.m_bgSelectedHandler = function (e) {\n            var uiState: IUiState = {campaign: {campaignTimelineBoardViewerSelected: -1}}\n            self.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        };\n        self.m_canvas.on('selection:cleared', self.m_bgSelectedHandler);\n    }\n\n    /**\n     Listen to changes in viewer overlaps\n     @method _listenObjectsOverlap\n     **/\n    _listenObjectsOverlap() {\n        var self = this;\n        self.m_onOverlap = function (options) {\n            options.target.setCoords();\n            self.m_canvas.forEachObject(function (obj) {\n                if (obj === options.target) return;\n                obj.setOpacity(options.target.intersectsWithObject(obj) ? 0.5 : 1);\n            });\n        }\n\n        self.m_canvas.on({\n            'object:moving': self.m_onOverlap,\n            'object:scaling': self.m_onOverlap,\n            'object:rotating': self.m_onOverlap\n        });\n    }\n\n    /**\n     Create the canvas to render the screen division\n     @method _canvasFactory\n     @param {Number} i_width\n     @param {Number} i_height\n     **/\n    _canvasFactory(i_width, i_height) {\n        var self = this;\n        var offsetH = i_height / 2;\n        var offsetW = (i_width / 2) + 30;\n        this.m_canvasID = _.uniqueId('screenLayoutEditorCanvas');\n        jQuery('#screenLayoutEditorCanvasWrap', this.el.nativeElement).append(`\n            <div>\n            <span align=\"center\">${this.m_resolution.split('x')[0]}px x ${this.m_resolution.split('x')[1]}px</span> \n            <canvas id=\"${this.m_canvasID}\" width=\"${i_width}px\" height=\"${i_height}px\" style=\"border: 1px solid rgb(170, 170, 170);\"></canvas>\n            <span style=\"position: relative; top: \"-${offsetH}px\" left: \"-${offsetW}px\">\n            </span>\n            </div>`);\n        this.m_canvas = new fabric.Canvas(this.m_canvasID);\n        this.m_canvas.selection = false;\n        let factory = this.componentFactoryResolver.resolveComponentFactory(ScreenTemplate);\n        this.componentRef = this.container.createComponent(factory);\n        this.m_screenTemplateData.scale = 4;\n        this.componentRef.instance.setTemplate = this.m_screenTemplateData;\n        var rects = this.componentRef.instance.getDivisions();\n\n        for (var i = 0; i < rects.length; i++) {\n            var rectProperties: any = rects[i];\n            var rect: any = new fabric.Rect({\n                left: rectProperties.x.baseVal.value,\n                top: rectProperties.y.baseVal.value,\n                fill: '#ececec',\n                id: jQuery(rectProperties).data('campaign_timeline_board_viewer_id'),\n                hasRotatingPoint: false,\n                borderColor: '#5d5d5d',\n                stroke: 'black',\n                strokeWidth: 1,\n                borderScaleFactor: 0,\n                width: rectProperties.width.baseVal.value,\n                height: rectProperties.height.baseVal.value,\n                cornerColor: 'black',\n                cornerSize: 5,\n                lockRotation: true,\n                transparentCorners: false\n            });\n            this.m_canvas.add(rect);\n\n            //rect.on('selected', function () {\n            //  log('object selected a rectangle');\n            //});\n        }\n\n        //this.m_canvas.on('object:moving', function (e) {\n        //    log('savings: ' + this.m_global_board_template_id);\n        //});\n\n        setTimeout(function () {\n            if (!self.m_canvas)\n                return;\n            self.m_canvas.setHeight(i_height);\n            self.m_canvas.setWidth(i_width);\n            self.m_canvas.renderAll();\n        }, 500);\n\n    }\n\n    /**\n     Make sure that at least one screen division is visible within the canvas\n     @method _enforceViewerVisible\n     **/\n    _enforceViewerVisible() {\n        var self = this;\n        var pass = 0;\n        var viewer;\n        self.m_canvas.forEachObject(function (o) {\n            viewer = o;\n            if (pass)\n                return;\n            if (o.get('left') < (0 - o.get('width')) + 20) {\n            } else if (o.get('left') > self.m_canvas.getWidth() - 20) {\n            } else if (o.get('top') < (0 - o.get('height') + 20)) {\n            } else if (o.get('top') > self.m_canvas.getHeight() - 20) {\n            } else {\n                pass = 1;\n            }\n        });\n        if (!pass && viewer) {\n            viewer.set({left: 0, top: 0}).setCoords();\n            viewer.setCoords();\n            self.m_canvas.renderAll();\n            bootbox.alert({\n                message: \"you must keep at least one viewable screen division\",\n                title: \"screen division position reset\"\n            });\n            var props = {\n                x: viewer.get('top'),\n                y: viewer.get('left'),\n                w: viewer.get('width') * self.RATIO,\n                h: viewer.get('height') * self.RATIO\n            }\n            self._saveToStore(viewer, props);\n        }\n    }\n\n    /**\n     Enforce minimum x y w h props\n     @method this._enforceViewerMinimums(i_viewer);\n     @param {Object} i_rect\n     **/\n    _enforceViewerMinimums(i_viewer) {\n        var MIN_SIZE = 50;\n        if ((i_viewer.width * this.RATIO) < MIN_SIZE || (i_viewer.height * this.RATIO) < MIN_SIZE) {\n            i_viewer.width = MIN_SIZE / this.RATIO;\n            i_viewer.height = MIN_SIZE / this.RATIO;\n            var props = {\n                x: i_viewer.get('top'),\n                y: i_viewer.get('left'),\n                w: MIN_SIZE,\n                h: MIN_SIZE\n            }\n            this._saveToStore(i_viewer, props);\n        }\n    }\n\n    /**\n     Listen to changes in a viewer changes in cords and update pepper\n     @method i_props\n     **/\n    _listenObjectChanged() {\n        var self = this;\n        self.m_objectMovingHandler = function (e) {\n\n            var o = e.target;\n            if (o.width != o.currentWidth || o.height != o.currentHeight) {\n                o.width = o.currentWidth;\n                o.height = o.currentHeight;\n                o.scaleX = 1;\n                o.scaleY = 1;\n            }\n\n            self._enforceViewerMinimums(o);\n            self._enforceViewerVisible();\n\n            var x = Lib.ParseToFloatDouble(o.left) * self.RATIO;\n            var y = Lib.ParseToFloatDouble(o.top) * self.RATIO;\n            var w = Lib.ParseToFloatDouble(o.currentWidth) * self.RATIO;\n            var h = Lib.ParseToFloatDouble(o.currentHeight) * self.RATIO;\n            // var a = o.get('angle');\n            var props = {\n                w: w,\n                h: h,\n                x: x,\n                y: y\n            };\n            // self.m_property.viewPanel(Elements.VIEWER_EDIT_PROPERTIES);\n            //todo: props\n            //self.m_dimensionProps.setValues(props);\n            self.m_selectedViewerID = o.id;\n            self._saveToStore(o, props);\n\n        };\n\n        // old code was wrapped in debouncer\n        // self.m_objectMovingHandler = _.debounce(function (e) {\n        // ...\n        // }, 2000);\n\n        self.m_canvas.on({\n            // 'object:moving': self.m_objectMovingHandler,\n            // 'object:scaling': self.m_objectMovingHandler,\n            'object:selected': self.m_objectMovingHandler,\n            'object:modified': self.m_objectMovingHandler\n        });\n    }\n\n    /**\n     Update Pepper with latest object dimensions\n     @method _saveToStore\n     @param {Object} i_props\n     **/\n    _saveToStore(i_viewer, i_props) {\n        var uiState: IUiState = {campaign: {campaignTimelineBoardViewerSelected: i_viewer.get('id')}}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        // console.log('Pepper ' + i_viewer.get('id') + ' ' + JSON.stringify(i_props));\n        this.rp.setBoardTemplateViewer(this.m_campaign_timeline_board_template_id, i_viewer.get('id'), i_props);\n        i_viewer.setCoords();\n        this.m_canvas.renderAll();\n        this.rp.reduxCommit();\n    }\n\n    /**\n     Listen to selection of next viewer\n     @method _listenSelectNextDivision\n     **/\n    _selectNextDivision() {\n        var self = this;\n        var viewer = self.m_canvas.getActiveObject();\n        var viewIndex = self.m_canvas.getObjects().indexOf(viewer);\n        var totalViews = self.m_canvas.getObjects().length;\n        if (viewIndex == totalViews - 1) {\n            self.m_canvas.setActiveObject(self.m_canvas.item(0));\n        } else {\n            self.m_canvas.setActiveObject(self.m_canvas.item(viewIndex + 1));\n        }\n    }\n\n    @Output()\n    onGoBack: EventEmitter<any> = new EventEmitter<any>();\n\n    _goBack() {\n        var uiState: IUiState = {\n            uiSideProps: SideProps.miniDashboard,\n            campaign: {\n                campaignTimelineBoardViewerSelected: -1\n            }\n        }\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.onGoBack.emit();\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n        console.log('dest screen-layout-editor');\n        var self = this;\n        if (!_.isUndefined(self.m_canvas)) {\n            self.m_canvas.off('selection:cleared', self.m_bgSelectedHandler);\n            self.m_canvas.off({\n                'object:moving': self.m_objectMovingHandler,\n                'object:scaling': self.m_objectMovingHandler,\n                'object:selected': self.m_objectMovingHandler,\n                'object:modified': self.m_objectMovingHandler\n            });\n            self.m_canvas.off({\n                'object:moving': self.m_onOverlap,\n                'object:scaling': self.m_onOverlap,\n                'object:rotating': self.m_onOverlap\n            });\n            self.m_canvas.clear().renderAll();\n        }\n        // $('#screenLayoutEditorCanvasWrap').empty()\n        self.m_canvasID = undefined;\n        self.m_canvas = undefined;\n        self.m_campaign_timeline_id = undefined;\n        self.m_campaign_timeline_board_template_id = undefined;\n        self.m_orientation = undefined;\n        self.m_resolution = undefined;\n        self.m_global_board_template_id = undefined;\n        self.m_selectedViewerID = undefined;\n    }\n}\n\n// this._listenPushToTopDivision();\n// this._listenPushToBottomDivision();\n// this._listenSelectNextDivision();\n// this.listenTo(this.options.stackView, BB.EVENTS.SELECTED_STACK_VIEW, function (e) {\n//     if (e == this) {\n//         if (this.m_dimensionProps == undefined) {\n//             require(['DimensionProps'], function (DimensionProps) {\n//                 this.m_dimensionProps = new DimensionProps({\n//                     appendTo: Elements.VIEWER_DIMENSIONS,\n//                     showAngle: false\n//                 });\n//                 $(this.m_dimensionProps).on('changed', function (e) {\n//                     var props = e.target.getValues();\n//                     this._saveToStore(this.m_canvas.getActiveObject(), props);\n//                     this._moveViewer(props);\n//                 });\n//                 this._render();\n//             });\n//         } else {\n//             this._render();\n//         }\n//     }\n// });"
  },
  {
    "path": "src/app/campaigns/sequencer.ts",
    "content": "import {ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, QueryList, ViewChildren} from \"@angular/core\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {CampaignTimelineBoardViewerChanelsModel, CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {ScreenTemplate} from \"../../comps/screen-template/screen-template\";\nimport {Observable, Subscriber, Subscription} from \"rxjs\";\nimport {IUiState, IUiStateCampaign} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {List} from \"immutable\";\nimport * as _ from \"lodash\";\nimport {ContextMenuService} from \"ngx-contextmenu\";\nimport {Once} from \"../../decorators/once-decorator\";\nimport {IScreenTemplateData} from \"../../interfaces/IScreenTemplate\";\nimport {Compbaser} from \"ng-mslib\";\n// import TweenLite = gsap.TweenLite;\n\n@Component({\n    selector: 'sequencer',\n    styles: [`\n        #dragcontainer {\n            padding-left: 0;\n            margin-left: 0;\n            vertical-align: middle;\n            width: 2500px;\n            overflow-y: hidden;\n        }\n\n        .dottedHR {\n            height: 6px;\n            width: 2500px;\n            opacity: 0.6;\n            position: relative;\n            border-top: 12px dotted #c1c1c1;\n            padding-bottom: 7px;\n            top: 20px;\n        }\n\n        .draggableTimeline {\n            float: left;\n            margin: 10px;\n            overflow-y: hidden;\n        }\n\n    `],\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <div (click)=\"$event.preventDefault()\">\n            <small class=\"debug\">{{me}}</small>\n            <h4 style=\"color: #a9a9a9\">total timelines: {{m_campaignTimelinesModels?.size}}</h4>\n            <hr class=\"dottedHR\">\n            <div id=\"dragcontainer\">\n                <screen-template #st class=\"draggableTimeline\"\n                                 *ngFor=\"let screenTemplate of m_screenTemplates$ | async; trackBy: trackByFn\"\n                                 (contextmenu)=\"onContextMenu($event, screenTemplate)\"\n                                 (click)=\"_onScreenTemplateSelected(screenTemplate, st)\"\n                                 (onDivisionDoubleClicked)=\"_onDivisionDoubleClicked($event)\"\n                                 [setTemplate]=\"screenTemplate\">\n                </screen-template>\n            </div>\n            <context-menu>\n                <ng-template contextMenuItem let-item (execute)=\"_onContextClicked('load props ',$event.item)\">\n                    timeline properties for {{item?.name}}\n                </ng-template>\n                <ng-template contextMenuItem divider=\"true\"></ng-template>\n                <ng-template contextMenuItem (execute)=\"_onContextClicked('edit',$event.item)\"><span i18n>edit layout</span></ng-template>\n                <ng-template contextMenuItem (execute)=\"_onContextClicked('nextch',$event.item)\"><span i18n>next channel</span></ng-template>\n            </context-menu>\n        </div>\n    `\n})\nexport class Sequencer extends Compbaser {\n\n    m_campaignTimelinesModels: List<CampaignTimelinesModel>;\n    m_screenTemplates$: Observable<any>;\n    private m_draggables;\n    private m_thumbsContainer;\n    private target;\n    private x: number;\n    private m_selectedScreenTemplate: ScreenTemplate;\n    private m_selectedTimelineId: number;\n    private m_campaignTimelineBoardViewerSelected: number = -1;\n    private m_campaignTimelineChannelSelected: number = -1;\n    private m_selectedCampaignId: number = -1;\n\n    constructor(private el: ElementRef, private yp: YellowPepperService, private pepper: RedPepperService, private contextMenuService: ContextMenuService) {\n        super();\n        this.m_thumbsContainer = el.nativeElement;\n    }\n\n    @ViewChildren(ScreenTemplate)\n    screenTemplatesQueryList: QueryList<any>;\n\n\n    trackByFn(index, item) {\n        return item.campaignTimelineId;\n    }\n\n    ngAfterViewInit() {\n        // auto select the timeline / division on component creation if need to\n\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.uiState.campaign.campaignTimelineChannelSelected)\n                .filter(channelId => channelId != -1 && !_.isUndefined(this.m_selectedScreenTemplate))\n                .subscribe((i_channelId) => {\n                    this._onDivisionDoubleClicked(i_channelId);\n                })\n        )\n\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.uiState.campaign)\n                .take(1)\n                .subscribe((i_campaign: IUiStateCampaign) => {\n                    if (i_campaign.timelineSelected != -1 && i_campaign.campaignTimelineBoardViewerSelected != -1) {\n                        this.tmpScreenTemplates.forEach((i_screenTemplate) => {\n                            if (i_screenTemplate.campaignTimelineId == i_campaign.timelineSelected) {\n                                this.m_selectedScreenTemplate = i_screenTemplate;\n                                this.m_selectedTimelineId = i_campaign.timelineSelected;\n                                this.m_campaignTimelineBoardViewerSelected = i_campaign.campaignTimelineBoardViewerSelected;\n                                this.m_campaignTimelineChannelSelected = i_campaign.campaignTimelineChannelSelected;\n                                this.m_selectedCampaignId = i_campaign.campaignSelected;\n                                i_screenTemplate.selectFrame();\n                                i_screenTemplate.selectDivison(i_campaign.campaignTimelineBoardViewerSelected)\n                            }\n                        })\n                    }\n                }, (e) => console.error(e))\n        )\n    }\n\n    _onContextClicked(cmd: string, screenTemplateData: IScreenTemplateData) {\n        switch (cmd) {\n            case 'edit': {\n                this.onEditLayout.emit();\n                break;\n            }\n            case 'nextch': {\n                this.onSelectNextChannel()\n                break;\n            }\n        }\n    }\n\n    public onContextMenu($event: MouseEvent, item: any): void {\n        this.contextMenuService.show.next({\n            event: $event,\n            item: item,\n        });\n        $event.preventDefault();\n        $event.stopPropagation();\n    }\n\n    @ViewChildren(ScreenTemplate) tmpScreenTemplates: QueryList<ScreenTemplate>;\n\n    @Input()\n    set setCampaignTimelinesModels(i_campaignTimelinesModels: List<CampaignTimelinesModel>) {\n        if (!i_campaignTimelinesModels)\n            return;\n        this.m_campaignTimelinesModels = i_campaignTimelinesModels;\n        this.m_selectedCampaignId = this.m_campaignTimelinesModels.first().getCampaignId();\n\n        this._sortTimelines((sortedTimelines: Array<CampaignTimelinesModel>) => {\n            this.m_screenTemplates$ = Observable.from(sortedTimelines)\n                .map(i_campaignTimelinesModelsOrdered => {\n                    return this._getScreenTemplate(i_campaignTimelinesModelsOrdered)\n                }).combineAll();\n\n            setTimeout(() => {\n                this._createSortable('#dragcontainer');\n            }, 300)\n\n        });\n    }\n\n    @Output()\n    onEditLayout: EventEmitter<any> = new EventEmitter<any>();\n\n    @Once()\n    private _sortTimelines(i_cb: (sortedTimelines: Array<CampaignTimelinesModel>) => void) {\n        return Observable.from(this.m_campaignTimelinesModels.toArray())\n            .switchMap((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                return this.yp.getCampaignTimelineSequencerIndex(i_campaignTimelinesModel.getCampaignTimelineId())\n                    .filter(v => v != -1)\n                    .map((index) => {\n                        return Observable.of({\n                            index: index,\n                            campaign: i_campaignTimelinesModel\n                        })\n                    })\n            })\n            .combineAll()\n            .subscribe((i_orderedTimelines: any) => {\n                var orderedTimelines = _.sortBy(i_orderedTimelines, [function (o) {\n                    return o.index;\n                }]);\n                i_cb(\n                    _.toArray(_.map(orderedTimelines, function (o) {\n                        return o['campaign'];\n                    }))\n                );\n            }, (e) => {\n                console.error(e)\n            })\n    }\n\n    _getScreenTemplate(i_campaignTimelinesModel: CampaignTimelinesModel): Observable<IScreenTemplateData> {\n        return this.yp.getTemplatesOfTimeline(i_campaignTimelinesModel.getCampaignTimelineId())\n            .map((campaignTimelineBoardTemplateIds: Array<number>) => {\n                // for now return zero as we don't support multiple divisions per single timeline, yet\n                return campaignTimelineBoardTemplateIds[0];\n            }).switchMap((campaignTimelineBoardTemplateId) => {\n                return this.yp.getTemplateViewersScreenProps(\n                    i_campaignTimelinesModel.getCampaignTimelineId(), campaignTimelineBoardTemplateId, i_campaignTimelinesModel.getTimelineName()\n                );\n            })\n    }\n\n    _onScreenTemplateSelected(event, screenTemplate: ScreenTemplate) {\n        this.tmpScreenTemplates.forEach((i_screenTemplate) => {\n            if (i_screenTemplate == screenTemplate) {\n                if (this.m_selectedTimelineId != i_screenTemplate.m_screenTemplateData.campaignTimelineId) {\n                    i_screenTemplate.selectFrame();\n                    this.m_selectedScreenTemplate = i_screenTemplate;\n                    this.m_selectedTimelineId = i_screenTemplate.m_screenTemplateData.campaignTimelineId;\n                    this.m_campaignTimelineChannelSelected = -1;\n                    this.m_campaignTimelineBoardViewerSelected = -1;\n                    this._setAndNotifyIds();\n                } else {\n                    i_screenTemplate.deselectDivisons();\n                }\n                var uiState: IUiState = {\n                    campaign: {\n                        campaignTimelineChannelSelected: -1,\n                        campaignTimelineBoardViewerSelected: -1\n                    }\n                }\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                this._notifyPropertySelect(SideProps.timeline);\n            } else {\n                i_screenTemplate.deSelectFrame();\n                i_screenTemplate.deselectDivisons();\n            }\n        })\n\n    }\n\n\n    private _setAndNotifyIds() {\n        var uiState: IUiState = {\n            campaign: {\n                campaignTimelineChannelSelected: this.m_campaignTimelineChannelSelected,\n                campaignTimelineBoardViewerSelected: this.m_campaignTimelineBoardViewerSelected,\n                timelineSelected: this.m_selectedTimelineId\n            }\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n\n    /**\n     Create a sortable channel list\n     @method _createSortable\n     @param {Element} i_selector\n     **/\n    private _createSortable(i_selector) {\n        var self = this;\n        if (jQuery(i_selector).children().length == 0) return;\n        var sortable = document.querySelector(i_selector);\n        self.m_draggables = Draggable.create(sortable.children, {\n                type: \"x\",\n                bounds: sortable,\n                edgeResistance: 1,\n                dragResistance: 0,\n                onPress: self._sortablePress,\n                onDragStart: self._sortableDragStart,\n                onDrag: self._sortableDrag,\n                liveSnap: self._sortableSnap,\n                zIndexBoost: true,\n                onDragEnd () {\n                    var t = this.target,\n                        max = t.kids.length - 1,\n                        newIndex = Math.round(this.x / t.currentWidth);\n                    //newIndex += (newIndex < 0 ? -1 : 0) + t.currentIndex;\n                    var preIndex = newIndex;\n                    //alert(this.x);\n                    newIndex += t.originalIndex;\n                    if (newIndex === max) {\n                        t.parentNode.appendChild(t);\n                    } else {\n                        if (preIndex >= 0) t.parentNode.insertBefore(t, t.kids[newIndex + 1]);\n                        else t.parentNode.insertBefore(t, t.kids[newIndex]);\n                    }\n                    TweenLite.set(t.kids, {xPercent: 0, overwrite: \"all\"});\n                    TweenLite.set(t, {x: 0, color: \"\"});\n\n                    var orderedTimelines = self.reSequenceTimelines();\n                    // jQuery(self.m_thumbsContainer).empty();\n                    // BB.comBroker.getService(BB.SERVICES.CAMPAIGN_VIEW).populateTimelines(orderedTimelines);\n                    // var campaign_timeline_id = BB.comBroker.getService(BB.SERVICES.CAMPAIGN_VIEW).getSelectedTimeline();\n                    // self.selectTimeline(campaign_timeline_id);\n                }\n            }\n        );\n    }\n\n    /**\n     Reorder the timeline in the local msdb to match the UI order of the timeline thumbnails in the Sequencer\n     @method reSequenceTimelines\n     @return {Array} order of timelines ids\n     **/\n    reSequenceTimelines() {\n        var self = this;\n        var order = [];\n        var timelines = jQuery('#dragcontainer', self.el.nativeElement).children().each(function (sequenceIndex) {\n            var element = jQuery(this).find('[data-campaign_timeline_id]').eq(0);\n            var campaign_timeline_id = jQuery(element).data('campaign_timeline_id');\n            order.push(campaign_timeline_id);\n            self.pepper.setCampaignTimelineSequencerIndex(self.m_selectedCampaignId, campaign_timeline_id, sequenceIndex);\n        });\n        this.pepper.reduxCommit();\n        return order;\n    }\n\n    /**\n     Sortable channel list on press\n     @method _sortablePress\n     **/\n    private _sortablePress() {\n        var t = this.target,\n            i = 0,\n            child = t;\n        while (child = child.previousSibling)\n            if (child.nodeType === 1) i++;\n        t.originalIndex = i;\n        t.currentWidth = jQuery(t).outerWidth();\n        t.kids = [].slice.call(t.parentNode.children); // convert to array\n    }\n\n    /**\n     Sortable drag channel list on press\n     @method _sortableDragStart\n     **/\n    private _sortableDragStart() {\n        TweenLite.set(this.target, {color: \"#88CE02\"});\n    }\n\n    /**\n     Sortable drag channel list\n     @method _sortableDrag\n     **/\n    private _sortableDrag() {\n        var t = this.target,\n            elements = t.kids.slice(), // clone\n            // indexChange = Math.round(this.x / t.currentWidth), // round flawed on large values\n            indexChange = Math.ceil(this.x / t.currentWidth),\n            srcIndex = t.originalIndex,\n            dstIndex = srcIndex + indexChange;\n        // console.log('k ' + t.kids.length + ' s:' + srcIndex + ' d:' + indexChange + ' t:' + (dstIndex - srcIndex));\n        if (srcIndex < dstIndex) { // moved right\n            TweenLite.to(elements.splice(srcIndex + 1, dstIndex - srcIndex), 0.15, {xPercent: -140});  // 140 = width of screen layout widget\n            TweenLite.to(elements, 0.15, {xPercent: 0});\n        } else if (srcIndex === dstIndex) {\n            elements.splice(srcIndex, 1);\n            TweenLite.to(elements, 0.15, {xPercent: 0});\n        } else { // moved left\n            // ignore if destination > source index\n            if ((indexChange < 0 ? indexChange * -1 : indexChange) > srcIndex)\n                return;\n            TweenLite.to(elements.splice(dstIndex, srcIndex - dstIndex), 0.15, {xPercent: 140}); // 140 = width of screen layout widget\n            TweenLite.to(elements, 0.15, {xPercent: -10});\n        }\n    }\n\n    /**\n     snap channels to set rounder values\n     @method _sortableSnap\n     **/\n    private _sortableSnap(y) {\n        return y;\n        /* enable code below to use live drag snapping */\n        // var h = this.target.currentHeight;\n        // return Math.round(y / h) * h;\n    }\n\n    @Once()\n    _onDivisionDoubleClicked(i_campaign_timeline_board_viewer_id) {\n        this.m_campaignTimelineBoardViewerSelected = i_campaign_timeline_board_viewer_id;\n        this.m_selectedScreenTemplate.selectDivison(i_campaign_timeline_board_viewer_id)\n        return this.yp.getChannelFromViewer(this.m_selectedTimelineId, i_campaign_timeline_board_viewer_id)\n            .subscribe((result: any) => {\n                this.m_campaignTimelineChannelSelected = result.channel;\n                this._setAndNotifyIds()\n                this._notifyPropertySelect(SideProps.channel);\n\n            }, (e) => {\n                console.error(e)\n            })\n    }\n\n    private _notifyPropertySelect(i_type) {\n        var uiState: IUiState = {uiSideProps: i_type}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    /**\n     Select next channel\n     @method selectNextChannel\n     **/\n    @Once()\n    public onSelectNextChannel(): Subscription {\n        if (!this.m_selectedScreenTemplate && this.screenTemplatesQueryList)\n            this._onScreenTemplateSelected(null, this.screenTemplatesQueryList.first)\n        var timeline_channel_id;\n        return this.yp.getChannelsOfTimeline(this.m_selectedTimelineId)\n            .subscribe((channelsIDs) => {\n                if (this.m_campaignTimelineChannelSelected == -1) {\n                    timeline_channel_id = channelsIDs[0];\n                } else {\n                    for (var ch in channelsIDs) {\n                        if (channelsIDs[ch] == this.m_campaignTimelineChannelSelected) {\n                            if (_.isUndefined(channelsIDs[parseInt(ch) + 1])) {\n                                timeline_channel_id = channelsIDs[0];\n                            } else {\n                                timeline_channel_id = channelsIDs[parseInt(ch) + 1];\n                            }\n                        }\n                    }\n                }\n                this.m_campaignTimelineChannelSelected = timeline_channel_id;\n                this.getAssignedViewerIdFromChannelId(timeline_channel_id);\n            }, (e) => {\n                console.error(e)\n            });\n    }\n\n    @Once()\n    private getAssignedViewerIdFromChannelId(timeline_channel_id) {\n        return this.yp.getAssignedViewerIdFromChannelId(timeline_channel_id)\n            .subscribe((i_campaign_timeline_board_viewer_id) => {\n                // note: workaround for when viewer is unassigned, need to investigate\n                if (_.isUndefined(i_campaign_timeline_board_viewer_id))\n                    return;\n                this.m_campaignTimelineBoardViewerSelected = i_campaign_timeline_board_viewer_id;\n                this.m_selectedScreenTemplate.selectDivison(i_campaign_timeline_board_viewer_id)\n                this._setAndNotifyIds();\n                this._notifyPropertySelect(SideProps.channel);\n\n                // self._removeBlockSelection();\n                // self._addChannelSelection(timeline_channel_id);\n                // BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']).selectViewer(screenData.campaign_timeline_id, screenData.campaign_timeline_board_viewer_id);\n                // BB.comBroker.fire(BB.EVENTS.ON_VIEWER_SELECTED, this, screenData);\n                // BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_CHANNEL_SELECTED, this, null, self.m_selectedChannel);\n            }, (e) => console.error(e));\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}\n\n\n"
  },
  {
    "path": "src/app/campaigns/timeline/timeline.component.css",
    "content": "#container {\n  height: 801px;\n  overflow: visible;\n  padding: 0;\n  position: relative;\n}\n\n:host /deep/ .box {\n  background-color: #a9a9a9;\n  text-align: center;\n  font-family: Asap, Avenir, Arial, sans-serif;\n  width: 196px;\n  height: 50px;\n  line-height: 50px;\n  color: black;\n  position: absolute;\n  top: 0;\n  border: 1px solid black;\n  z-index: 1000;\n  list-style: none;\n  display: flex;\n  align-items: center;\n}\n\n:host /deep/ .fa-item {\n  float: left;\n  padding: 0 16px 0 10px;\n  opacity: 0.8;\n}\n\n.box-image {\n  user-drag: none;\n  user-select: none;\n  -moz-user-select: none;\n  -webkit-user-drag: none;\n  -webkit-user-select: none;\n  -ms-user-select: none;\n}\n\n.item-title {\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n:host /deep/ .ui-selected { background: #c7c7c7; }\n\n.ruler {\n  height: 50px;\n}\n\n.ruler-container {\n  padding-left: 0px;\n}\n\n.channel-titles {\n  padding-right: 0px;\n  /*width: 97px;*/\n}\n\n.channel-title {\n  height: 50px;\n  border: 1px solid black;\n  background-color: #2d2d2d;\n  color: #e0e0e0;\n  font-weight: bold;\n  line-height: 50px;\n  padding-left: 10px;\n  cursor: pointer;\n  text-overflow: clip;\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.common-channel {\n  text-decoration: underline;\n}\n\n.channel-color {\n  width: 10px;\n  height: 10px;\n  display: inline-block;\n}\n\n.channel-selected {\n  background: #656565;\n}\n\n.timeline {\n  padding-left: 0px;\n  /*max-width: 1200px;*/\n  overflow-x: auto;\n}\n\n:host /deep/ .timeline-row {\n  position: absolute;\n  border: 1px solid #454545;\n  width: 100%;\n}\n\n:host /deep/ .output-row {\n  background-color: #adadad;\n  border: 1px solid #454545;\n  width: 100%;\n}\n\n.timeline-container {\n\n}\n"
  },
  {
    "path": "src/app/campaigns/timeline/timeline.component.html",
    "content": "<div style=\"width: 100%\">\n  <div class=\"row\" style=\"padding-top:50px;padding-bottom:50px;\" *ngIf=\"dev\">\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"addChannel()\">Add Channel</button>\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"addCommonChannel()\">Add Common Channel</button>\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"addOutput()\">Add Output</button>\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"closeGaps()\">Close Gaps</button>\n    <input type=\"checkbox\" [(ngModel)]=\"state.magnetic\"> Magnetic\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"resizeToLargest()\">Resize to largest</button>\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"alignLeft()\">Align Left</button>\n    <button type=\"button\" class=\"btn btn-default\" (click)=\"alignRight()\">Align Right</button>\n    <input type=\"checkbox\" [(ngModel)]=\"state.switch\"> Switch\n    <input type=\"checkbox\" (change)=\"toggleFrozen($event)\"> Frozen\n    <select (change)=\"changeZoom($event)\" [(ngModel)]=\"state.zoom\">\n      <option value=\"1\">1.0 : 10</option>\n      <option value=\"2\">2.0 : 10</option>\n      <option value=\"5\">5.0 : 10</option>\n      <option value=\"10\">10 : 10</option>\n      <option value=\"20\">20 : 10</option>\n      <option value=\"40\">40 : 10</option>\n    </select>\n\n  </div>\n  <div class=\"row\" style=\"padding-bottom:50px;\">\n    <!--<app-duration-input-->\n      <!--[setDuration]=\"state.duration\"-->\n      <!--(durationChange)=\"timelineDurationChange($event)\"-->\n    <!--&gt;</app-duration-input>-->\n  </div>\n  <div class=\"row timeline-ruler\">\n    <div class=\"col-xs-11 col-xs-offset-1\" style=\"padding: 0;\">\n      <app-timeline-ruler\n        width=\"{{ state.gridWidth }}\"\n        height=\"50\"\n        position=\"{{ scrollPosition }}\"\n        scale=\"{{ state.zoom / 10}}\"\n      >\n      </app-timeline-ruler>\n    </div>\n  </div>\n  <div class=\"row timeline-container\">\n    <div class=\"col-xs-1 channel-titles\">\n      <div class=\"channel-title\" *ngFor=\"let output of state.outputs; let i = index\" (click)=\"selectOutput(i)\" [class.channel-selected]=\"output.selected\">\n        <span class=\"channel-color\" [style.backgroundColor]=\"output.color\"></span> {{ output.name }}\n      </div>\n      <div class=\"channel-title\" *ngFor=\"let channel of state.channels; let i = index\" [class.common-channel]=\"channel.type == 'common'\" [class.channel-selected]=\"channel.selected\" (click)=\"selectChannel(i)\">\n        <span class=\"channel-color\" [style.backgroundColor]=\"channel.color\"></span> {{ channel.name }}\n      </div>\n    </div>\n    <div class=\"col-xs-11 timeline\" (scroll)=\"onScroll($event)\">\n\n      <div id=\"container\">\n        <ng-container *ngFor=\"let item of state.items;let i = index\">\n          <li *ngIf=\"item.type == 'output'\"\n              class=\"resizable selectable box\" [attr.data-bid]=\"i\" [style.width.px]=\"item.width\">\n\n            <img\n              *ngIf=\"item.resource.type == 'png' || item.resource.type == 'svg'\"\n              class=\"box-image\" src=\"{{ item.resource.src }}\"\n              style=\"height: 100%;width: 100%;max-width: 50px;float:left\"\n            />\n\n            <i *ngIf=\"item.resource.type == 'fa'\" class=\"box-image fa {{ item.resource.src }} fa-item\"></i>\n\n            <div class=\"item-title\">{{ item.title }}</div>\n          </li>\n        </ng-container>\n        <ng-container *ngFor=\"let item of state.items;let i = index\">\n          <li *ngIf=\"item.type == 'channel'\"\n              class=\"resizable selectable box\" [attr.data-bid]=\"i\" [style.width.px]=\"item.width\">\n\n              <img\n                *ngIf=\"item.resource.type == 'png' || item.resource.type == 'svg'\"\n                class=\"box-image\" src=\"{{ item.resource.src }}\"\n                style=\"height: 100%;width: 100%;max-width: 50px;float:left\"\n              />\n\n              <i *ngIf=\"item.resource.type == 'fa'\" class=\"box-image fa {{ item.resource.src }} fa-item\"></i>\n\n            <div class=\"item-title\">{{ item.title }}</div>\n          </li>\n        </ng-container>\n      </div>\n    </div>\n  </div>\n  <div class=\"row\"  style=\"padding-top:50px;padding-bottom:50px;\" *ngIf=\"dev\">\n    <div class=\"col-xs-4\">\n      <h4>Resources</h4>\n      <table class=\"table\">\n        <tr>\n          <th>Name</th>\n          <th>Type</th>\n          <th>Total time</th>\n          <th>size</th>\n        </tr>\n        <tr *ngFor=\"let resource of resources.items; let i = index\" draggable=\"true\" (dragstart)=\"drag($event, 'channel', i)\">\n          <td>{{ resource.name }}</td>\n          <td>{{ resource.type }}</td>\n          <td>{{ resource.time }}</td>\n          <td>{{ resource.size }}</td>\n        </tr>\n      </table>\n\n      <h4>Outputs</h4>\n      <table class=\"table\">\n        <tr>\n          <th>Name</th>\n          <th>Type</th>\n          <th>Total time</th>\n          <th>size</th>\n        </tr>\n        <tr *ngFor=\"let resource of resources.outputs; let i = index\" draggable=\"true\" (dragstart)=\"drag($event, 'output', i)\">\n          <td>{{ resource.name }}</td>\n          <td>{{ resource.type }}</td>\n          <td>{{ resource.time }}</td>\n          <td>{{ resource.size }}</td>\n        </tr>\n      </table>\n    </div>\n    <div class=\"col-xs-4 col-xs-offset-4\">\n      <ng-container *ngFor=\"let channel of state.channels; let i = index\">\n        <div *ngIf=\"channel.selected\">\n          <form (keydown.enter)=\"$event.preventDefault()\">\n            <div class=\"form-group\">\n              <label for=\"exampleInputEmail1\">Name</label>\n              <input type=\"text\" class=\"form-control\" name=\"channel-name\" [(ngModel)]=\"channel.name\" placeholder=\"Email\">\n            </div>\n            <div class=\"form-group\">\n              <label for=\"exampleInputEmail1\">Color</label>\n              <input type=\"text\" class=\"form-control\" name=\"channel-color\" [(ngModel)]=\"channel.color\" placeholder=\"Color\">\n            </div>\n            <button type=\"submit\" class=\"btn btn-default\" (click)=\"deleteChannel(i)\">Delete</button>\n          </form>\n        </div>\n      </ng-container>\n      <ng-container *ngFor=\"let output of state.outputs; let i = index\">\n        <div *ngIf=\"output.selected\">\n          <form (keydown.enter)=\"$event.preventDefault()\">\n            <div class=\"form-group\">\n              <label for=\"exampleInputEmail1\">Name</label>\n              <input type=\"text\" class=\"form-control\" name=\"output-name\" [(ngModel)]=\"output.name\" placeholder=\"Email\">\n            </div>\n            <div class=\"form-group\">\n              <label for=\"exampleInputEmail1\">Color</label>\n              <input type=\"text\" class=\"form-control\" name=\"output-color\" [(ngModel)]=\"output.color\" placeholder=\"Color\">\n            </div>\n            <button type=\"submit\" class=\"btn btn-default\" (click)=\"deleteOutput(i)\">Delete</button>\n          </form>\n        </div>\n      </ng-container>\n      <ng-container *ngFor=\"let item of state.items; let i = index\">\n        <div *ngIf=\"item.selected\">\n          <form (keydown.enter)=\"$event.preventDefault()\">\n            <div class=\"form-group\">\n              <label for=\"exampleInputEmail1\">Name</label>\n              <input type=\"text\" class=\"form-control\" name=\"item-title\" [(ngModel)]=\"item.title\" placeholder=\"Email\">\n            </div>\n            <button type=\"submit\" class=\"btn btn-default\" (click)=\"deleteItem(i)\">Delete</button>\n          </form>\n        </div>\n      </ng-container>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "src/app/campaigns/timeline/timeline.component.spec.ts",
    "content": "/* tslint:disable:no-unused-variable */\nimport { async, ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { DebugElement } from '@angular/core';\n\nimport { TimelineComponent } from './timeline.component';\n\ndescribe('TimelineComponent', () => {\n  let component: TimelineComponent;\n  let fixture: ComponentFixture<TimelineComponent>;\n\n  beforeEach(async(() => {\n    TestBed.configureTestingModule({\n      declarations: [ TimelineComponent ]\n    })\n    .compileComponents();\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TimelineComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should create', () => {\n    expect(component).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/app/campaigns/timeline/timeline.component.ts",
    "content": "import { Component, OnInit, Input, AfterViewChecked, OnChanges, EventEmitter, Output } from '@angular/core';\n\ndeclare let $: any;\ndeclare let Draggable: any;\ndeclare let TweenLite: any;\n\n@Component({\n  selector: 'app-timeline',\n  templateUrl: './timeline.component.html',\n  styleUrls: ['./timeline.component.css']\n})\nexport class TimelineComponent implements OnInit, AfterViewChecked, OnChanges {\n  $container;\n\n  ruler = undefined;\n  dev = false;\n  draggingItem;\n  scrollPosition = 0;\n\n  defaultState = {\n    duration: 3600,\n    gridWidth: 36000,\n    gridHeight: 50,\n    items: [],\n    channels: [],\n    outputs: [],\n    selectedChannel: undefined,\n    selectedItem: undefined,\n    selectedOutput: undefined,\n    frozen: false,\n    magnetic: false,\n    switch: false,\n    zoom: 1\n  };\n\n  @Input() resources;\n  @Input() state;\n\n  @Output() itemsMoved = new EventEmitter<Object>();\n  @Output() itemAdded = new EventEmitter<Object>();\n  @Output() itemsClicked = new EventEmitter<Object>();\n  @Output() itemsResized = new EventEmitter<Object>();\n\n  @Output() channelAdded = new EventEmitter<Object>();\n  @Output() channelClicked = new EventEmitter<Object>();\n\n  @Output() outputAdded = new EventEmitter<Object>();\n  @Output() outputClicked = new EventEmitter<Object>();\n\n  @Output() closedGaps = new EventEmitter<Object>();\n  @Output() resizedToLargest = new EventEmitter<Object>();\n  @Output() alignedLeft = new EventEmitter<Object>();\n  @Output() alignedRight = new EventEmitter<Object>();\n\n\n  constructor() { }\n\n  ngOnInit() {\n    // reset item selection when the container is clicked\n    this.$container.click((e) => {\n      if (!$(e.target).hasClass('box') && !$(e.target).hasClass('box-image') && !$(e.target).hasClass('item-title')) {\n        this.resetSelection();\n      }\n    });\n  }\n\n  ngOnChanges() {\n    // ngOnChanges gets called first, so initialize here\n    this.$container = $('#container');\n\n    this.state = Object.assign({}, this.defaultState, this.state.toJS());\n\n    this.initializeStateChanges();\n  }\n\n  initializeStateChanges() {\n    // draw channels\n    this.drawChannels();\n\n    // initialize item positions\n    this.state.items.map((item) => {\n      item.left = item.start * (10 / this.state.zoom);\n      item.width = item.duration * (10 / this.state.zoom);\n      item.top = this.getChannelById(item.channel).top;\n      item.overlapsLeft = [];\n      item.overlapsRight = [];\n    });\n  }\n\n  ngAfterViewChecked() {\n    var self = this;\n    this.state.items.map((item, i) => {\n      if (item.$el === undefined) {\n\n\n        var startX, startY;\n        var companions;\n        var lastOverlap = 0;\n\n        item.$el = $(\"li[data-bid='\" + i + \"']\");\n\n        if (item.selected) {\n          item.$el.addClass('ui-selected');\n        }\n\n        var container = this.$container;\n\n        item.draggable = Draggable.create(item.$el, {\n          bounds: self.$container,\n          edgeResistance: 1.0,\n          type: \"x,y\",\n          throwProps: false,\n          lockAxis: false,\n          x: 0,\n          y: 0,\n          liveSnap: {\n            y: function(endValue) { return Math.round(endValue / self.state.gridHeight) * self.state.gridHeight; },\n            x: function(endValue) {\n              // magnetic snapping\n              if (self.state.magnetic) {\n                self.state.items.filter(filterItem => filterItem != item && filterItem.channel == item.channel).map((otherItem) => {\n                  if (endValue >= otherItem.left + otherItem.width - 5 &&\n                    endValue <= otherItem.left + otherItem.width + 5) {\n                    endValue = otherItem.left + otherItem.width;\n                  }\n\n                  if (endValue + item.width >= otherItem.left - 5 &&\n                    endValue + item.width <= otherItem.left + 5) {\n                    endValue = otherItem.left - item.width;\n                  }\n                });\n              }\n\n              // only allow objects to stop at positions that represent whole numbers of seconds\n              var timeValue = Math.round(endValue * self.state.zoom / 10);\n              return timeValue * (10 / self.state.zoom);\n            }\n          },\n          onRelease: function () {\n            // emit click event for selected items on release\n            var selectedItems = self.state.items.filter(i => i.selected);\n            self.itemsClicked.emit(selectedItems);\n            // console.log(\"Item clicked: \", selectedItems);\n          },\n          onPress: function(e) {\n            // mutli-select functionality\n            if (!e.ctrlKey && $(\".box.ui-selected\").length == 1) {\n              self.resetSelection();\n            }\n            self.selectItem(item);\n            e.stopPropagation();\n\n            //when the user presses, we'll create an array (\"companions\") and populate it with all the OTHER elements that have the \".ui-selected\" class applied (excluding the one that's being dragged). We also record their x and y position so that we can apply the delta to it in the onDrag.\n            var boxes = $(\".box.ui-selected\"),\n              i = boxes.length;\n\n            companions = [];\n            startX = this.x;\n            startY = this.y;\n\n            while (--i > -1) {\n              var boxId = $(boxes[i]).data('bid');\n              if (boxes[i] !== this.target) {\n                companions.push({\n                  e: e,\n                  selfId: self.state.items.indexOf(item),\n                  item: self.state.items[boxId],\n                  itemId: boxId,\n                  element: boxes[i],\n                  x: boxes[i]._gsTransform.x,\n                  y: boxes[i]._gsTransform.y,\n                  lastX: boxes[i]._gsTransform.x,\n                  lastY: boxes[i]._gsTransform.y\n                });\n              } else {\n                self.state.items[boxId].selected = true;\n              }\n            }\n            TweenLite.killTweensOf(\".box\");\n          },\n          onDrag: function() {\n\n            // mutliselect movement\n            var i = companions.length,\n              deltaX = this.x - startX,\n              deltaY = this.y - startY,\n              companion;\n\n            while (--i > -1) {\n              companion = companions[i];\n\n              self.moveItem(companion.item, companion.x + deltaX, companion.y + deltaY);\n\n              if (!companion.item.draggable.hitTest('#container', \"100%\")) { // if the item is moved outside of the bounds, move it back\n                self.moveItem(companion.item, companion.lastX, companion.lastY);\n              } else {\n                companion.lastX = companion.x + deltaX;\n                companion.lastY = companion.y + deltaY;\n              }\n\n              // start the companion dragging with the original event\n              self.state.items[companion.selfId].draggable.startDrag(companion.e);\n            }\n\n            // switch\n            if (self.state.switch) {\n              // self.state.items.filter(item => item.selected).map((selectedItem) => {\n              //   self.state.items.filter(item => !item.selected).map((otherItem) => {\n              //     if (selectedItem.channel == otherItem.channel) {\n              //       var selectedItemId = self.state.items.indexOf(selectedItem);\n              //\n              //       var min = 0,\n              //         max = (selectedItem.channel.type == \"common\" ? 13000 : self.state.gridWidth) - otherItem.width;\n              //\n              //       if (selectedItem.left >= otherItem.left + otherItem.width / 2 - 10 &&\n              //         selectedItem.left <= otherItem.left + otherItem.width / 2 + 10) {\n              //         self.moveItem(otherItem, Math.min(max, Math.max(min, selectedItem.left + selectedItem.width)), otherItem.top, 100);\n              //       }\n              //\n              //       if (selectedItem.left + selectedItem.width >= otherItem.left + otherItem.width / 2 - 10 &&\n              //         selectedItem.left + selectedItem.width <= otherItem.left + otherItem.width / 2 + 10) {\n              //         self.moveItem(otherItem, Math.min(max, Math.max(min, selectedItem.left - otherItem.width)), otherItem.top, 100);\n              //       }\n              //     }\n              //   });\n              // });\n\n              self.state.items.filter(item => item.selected).map((selectedItem) => {\n                self.state.items.filter(item => !item.selected).map((otherItem) => {\n                  if (selectedItem.channel == otherItem.channel) {\n                    if (selectedItem.overlapsLeft == undefined) {\n                      selectedItem.overlapsLeft = [];\n                    }\n\n                    if (selectedItem.overlapsRight == undefined) {\n                      selectedItem.overlapsRight = [];\n                    }\n\n                    if (selectedItem.draggable.hitTest(otherItem.$el)) {\n                      if (selectedItem.left <= otherItem.left &&\n                        selectedItem.overlapsLeft.indexOf(otherItem) === -1 &&\n                        selectedItem.overlapsRight.indexOf(otherItem) === -1\n                      ) {\n                        selectedItem.overlapsLeft.push(otherItem);\n                      }\n                      if (selectedItem.left > otherItem.left &&\n                        selectedItem.overlapsRight.indexOf(otherItem) === -1 &&\n                        selectedItem.overlapsLeft.indexOf(otherItem) === -1) {\n                        selectedItem.overlapsRight.push(otherItem);\n                      }\n                    }\n                  }\n                });\n                selectedItem.overlapsLeft.map((otherItem, idx) => {\n                  if (!selectedItem.draggable.hitTest(otherItem.$el, \"5%\")) {\n                    selectedItem.overlapsLeft.splice(idx, 1);\n                  }\n                });\n                selectedItem.overlapsRight.map((otherItem, idx) => {\n                  if (!selectedItem.draggable.hitTest(otherItem.$el, \"5%\")) {\n                    selectedItem.overlapsRight.splice(idx, 1);\n                  }\n                });\n              });\n\n              self.state.items.filter(item => item.selected).map((selectedItem) => {\n                selectedItem.overlapsLeft.map(otherItem => {\n                        var min = 0,\n                          max = (self.getChannelById(selectedItem.channel).type == \"common\" ? 13000 : self.state.gridWidth) - otherItem.width;\n\n                  if (selectedItem.left + selectedItem.width >= otherItem.left + otherItem.width - 10 &&\n                    selectedItem.left + selectedItem.width <= otherItem.left + otherItem.width + 10) {\n                    self.moveItem(otherItem, Math.min(max, Math.max(min, otherItem.left - selectedItem.width)), otherItem.top, 100);\n                    selectedItem.overlapsLeft = [];\n                  }\n                });\n\n                selectedItem.overlapsRight.map(otherItem => {\n                  var min = 0,\n                    max = (self.getChannelById(selectedItem.channel).type == \"common\" ? 13000 : self.state.gridWidth) - otherItem.width;\n                  if (selectedItem.left >= otherItem.left - 10 &&\n                    selectedItem.left <= otherItem.left + 10) {\n\n                    var newPos = otherItem.left + selectedItem.width;\n\n                    self.moveItem(otherItem, Math.min(max, Math.max(min, newPos)), otherItem.top, 100);\n                    selectedItem.overlapsRight = [];\n                  }\n                });\n              });\n            }\n          }\n        })[0];\n\n        //connect object to drag event listener to update position\n        item.draggable.addEventListener(\"drag\", function() {\n          item.left = this._gsTransform.x;\n          item.start = item.left * self.state.zoom / 10;\n          item.top = this._gsTransform.y;\n\n          self.updateItemChannel(item);\n        });\n\n        item.draggable.addEventListener(\"dragend\", function() {\n          var selectedItems = self.state.items.filter(i => i.selected);\n          self.itemsMoved.emit(selectedItems);\n          // console.log(\"Item Moved: \", selectedItems);\n        });\n\n        // set item initial position\n        this.moveItem(item, item.left, item.top);\n\n        // resize functionality\n        var startWidth; // define a start width to calculate deltas for multi-resize\n        $('.resizable').resizable({\n          handles: 'e, w',\n          start: function (event, ui) {\n            var id = ui.originalElement.data('bid');\n            var resizingItem = self.state.items[id];\n\n            startWidth = resizingItem.width;\n            // console.log('start: ' + startWidth);\n          },\n          resize: function (event, ui) {\n            // var newWidth = Math.round(ui.size.width / 10) * 10;\n            // $(this).width(newWidth);\n            var id = ui.originalElement.data('bid');\n            var resizingItem = self.state.items[id];\n\n            resizingItem.width = ui.size.width;\n            resizingItem.duration = ui.size.width * self.state.zoom / 10;\n            var widthDelta = resizingItem.width - startWidth;\n\n            // resizingItem.width = newWidth;\n            // resizingItem.duration = newWidth * (self.state.zoom / 10);\n            // var widthDelta = newWidth - startWidth;\n\n            // move any companions\n            self.state.items.filter((item) => item.selected).map((selectedItem) => {\n              if (selectedItem != resizingItem) {\n                selectedItem.width += widthDelta;\n                selectedItem.duration = selectedItem.width * self.state.zoom / 10;\n              }\n            });\n            // console.log('newWidth: ' + resizingItem.width);\n\n            startWidth = resizingItem.width;\n          },\n          stop: function (event, ui) {\n            // resizable modifies the left which messes with things, so we undo it and calculate the offsets\n            var left = parseInt($(this).css('left'));\n            var id = ui.originalElement.data('bid');\n            var resizingItem = self.state.items[id];\n\n            $(this).css({ left: 0 });\n\n            self.moveItem(resizingItem, resizingItem.left + left, resizingItem.top);\n\n            var selectedItems = self.state.items.filter(i => i.selected);\n\n            self.itemsResized.emit(selectedItems);\n            // console.log(\"Item resized: \" + selectedItems);\n          }\n        });\n\n        // makes GSAP Draggable avoid clicks on the resize handles\n        $('.ui-resizable-handle').attr('data-clickable', true);\n\n        this.applyItemBounds();\n      }\n    });\n  }\n\n  timelineDurationChange(dur) {\n    this.state.duration = dur;\n    // console.log('new timeline duration: ', dur);\n    this.updateContainerSize();\n  }\n\n  resetSelection() {\n    $('.resizable').removeClass('ui-selected');\n    this.state.items.map((item) => {\n      item.selected = false;\n    })\n  }\n\n  drawChannels() {\n    this.$container.find(\".timeline-row\").remove();\n\n    this.state.outputs.concat(this.state.channels).map((channel, i) => {\n      var type = this.state.channels.indexOf(channel) !== -1 ? \"channel\" : \"output\";\n      var resources;\n\n      if (type == \"channel\") {\n        resources = this.resources.items;\n      } else {\n        resources = this.resources.outputs;\n      }\n      // create element for channel and append it to the container\n\n      channel.top = i * this.state.gridHeight;\n      channel.$el = $(\"<div/>\").css({\n        height: this.state.gridHeight - 1,\n        top: channel.top,\n        left: 0\n      }).addClass('timeline-row').appendTo(this.$container);\n\n      //add ondrop event listener for accepting item drops\n      channel.$el[0].ondrop = (e) => {\n        e.preventDefault();\n\n        var data = resources[e.dataTransfer.getData(\"text\")];\n        var offset = this.$container.offset();\n        var left = e.x - offset.left;\n        var top = i * this.state.gridHeight;\n\n        this.addItem({\n          resource: {\n            src: data.src,\n            type: data.type\n          },\n          title: data.name,\n          type: type,\n          left: left,\n          width: 60 * (10 / this.state.zoom),\n          channel: channel.id,\n          top: top,\n          draggable: undefined,\n          $el: undefined,\n          selected: false\n        });\n      };\n\n      channel.$el[0].ondragover = (e) => {\n        if (type == this.draggingItem) {\n          e.preventDefault();\n        }\n      };\n    });\n\n    //set the container's size to match the grid, and ensure that the box widths/heights reflect the variables above\n    this.updateContainerSize();\n\n    this.applyItemBounds();\n  }\n\n  applyItemBounds() {\n    this.state.items.map((item) => {\n      if (item.draggable !== undefined) {\n        if (item.type == 'output') {\n          var bounds = {\n            left: 0,\n            top: 0,\n            width: this.state.gridWidth,\n            height: this.state.outputs.length * this.state.gridHeight\n          };\n          item.draggable.applyBounds(bounds);\n        } else if (item.type == 'channel') {\n          if (this.getChannelById(item.channel).type == \"common\") {\n            item.draggable.applyBounds({\n              top: 0,\n              left: 0,\n              width: 13000,\n              height: this.$container.height()\n            });\n          } else {\n            var bounds = {\n              left: 0,\n              top: this.state.outputs.length * this.state.gridHeight,\n              width: this.state.gridWidth,\n              height: this.state.channels.length * this.state.gridHeight\n            };\n            item.draggable.applyBounds(bounds);\n          }\n        }\n      }\n    });\n  }\n\n  onScroll(e) {\n    this.scrollPosition = e.target.scrollLeft;\n  }\n\n  drag(e, type, resourceIndex) {\n    e.dataTransfer.setData(\"text\", resourceIndex);\n    this.draggingItem = type;\n  }\n\n  resizeToLargest() {\n    var largest = this.state.items.reduce((accum, item) => {\n      return Math.max(accum, item.width);\n    }, 0);\n\n    var resizedItems = this.state.items.filter(item => item.selected)\n      .map((item) => {\n        item.width = largest;\n        item.duration = largest * this.state.zoom / 10;\n        item.$el.css({ width: largest });\n        return item;\n      });\n\n    this.resizedToLargest.emit(resizedItems);\n    // console.log(\"Resized to largest\", resizedItems);\n  }\n\n  closeGaps() {\n    var channel;\n    this.state.channels.concat(this.state.outputs).map((c) => {\n      if (c.selected) {\n        channel = c.id;\n      }\n    });\n    for (var i = 0; i < this.state.items.length; ++i) {\n      var item = this.state.items[i];\n      if (item.selected) {\n        channel = item.channel;\n      }\n    }\n    if (channel !== undefined) {\n      // get the items in this channel and sort them left to right\n      var groupedItems = this.state.items.filter((item) => {\n        return item.channel == channel;\n      }).sort((a, b) => {\n        return a.left - b.left;\n      });\n\n      // place the channels\n      var nextStartPos = 0;\n      groupedItems.map((item, i) => {\n        this.moveItem(item, nextStartPos, item.top);\n        nextStartPos += item.width;\n      });\n      this.closedGaps.emit(groupedItems);\n      // console.log(\"Closed gaps\", groupedItems);\n    }\n  }\n\n  alignLeft() {\n    var leftAlign = this.state.items.filter((item) => item.selected)\n      .reduce((accum, item) => Math.min(accum, item.left), Infinity);\n\n    var alignedItems = this.state.items.filter(item => item.selected)\n      .map((item, i) => {\n        this.moveItem(item, leftAlign, item.top);\n        return item;\n      });\n\n    this.alignedLeft.emit(alignedItems);\n    // console.log(\"Aligned Left\", alignedItems);\n  }\n\n  alignRight() {\n    var rightAlign = this.state.items.filter((item) => item.selected)\n      .reduce((accum, item) => Math.max(accum, item.left + item.width), 0);\n\n    var alignedItems = this.state.items.filter(item => item.selected)\n      .map((item, i) => {\n        this.moveItem(item, rightAlign - item.width, item.top);\n        return item;\n      });\n\n    this.alignedRight.emit(alignedItems);\n    // console.log(\"Aligned Right\", alignedItems);\n  }\n\n  changeZoom(e) {\n    if (!this.state) return;\n    var zoomFactor = 10 / this.state.zoom;\n\n    this.state.items.map((item) => {\n      item.width = item.duration * zoomFactor;\n      this.moveItem(item, item.start * zoomFactor, item.top);\n    });\n\n    this.updateContainerSize();\n    this.applyItemBounds();\n  }\n\n  toggleFrozen(e) {\n    this.state.frozen = !this.state.frozen;\n\n    if (this.state.frozen) {\n      this.state.items.map((item) => {\n        item.draggable.disable();\n      });\n    } else {\n      this.state.items.map((item) => {\n        item.draggable.enable();\n      });\n    }\n  }\n\n  updateItemChannel(item) {\n    var newChannel = this.state.channels.filter((c) => c.top == item.top)[0];\n    if (newChannel) {\n      item.channel = newChannel.id;\n      this.applyItemBounds();\n    }\n  }\n\n  moveItem(item, x, y, dur = 0) {\n    if (item) {\n      x = (x === undefined) ? item.left : x;\n      y = (y === undefined) ? item.top : y;\n\n      TweenLite.to(item.$el[0], dur / 1000, { x: x, y: y });\n      item.draggable.update(); // update the draggable position\n      item.left = x;\n      item.start = item.left * this.state.zoom / 10;\n      item.top = y;\n\n      this.updateItemChannel(item);\n    }\n  }\n\n  addChannel(channel) {\n    var newChannel = Object.assign(\n      {},\n      {\n        id: -1,\n        $el: undefined,\n        name: \"CH\" + this.state.channels.length,\n        type: \"normal\",\n        color: '#00FFFF'\n      },\n      channel\n    );\n    this.state.channels.push(newChannel);\n    this.drawChannels();\n\n    this.channelAdded.emit(newChannel);\n    // console.log(\"Channel Added: \" + newChannel);\n  }\n\n  addCommonChannel(channel) {\n    var newChannel = Object.assign(\n      {},\n      {\n        id: -1,\n        $el: undefined,\n        name: \"CH\" + this.state.channels.length,\n        type: \"common\",\n        color: '#0000FF'\n      },\n      channel\n    );\n    this.state.channels.push(newChannel);\n    this.drawChannels();\n\n    this.channelAdded.emit(newChannel);\n    // console.log(\"Channel added: \" + newChannel);\n  }\n\n  addOutput(output) {\n    var newOutput = Object.assign(\n      {},\n      {\n        id: -1,\n        name: \"Output\",\n        color: \"#000\"\n      },\n      output\n    );\n\n    this.state.outputs.push(newOutput);\n\n    // move all existing items on channels down one row\n    this.state.items.filter((item) => item.type == 'channel').map((item) => {\n      this.moveItem(item, item.left, item.top + this.state.gridHeight);\n    });\n    this.drawChannels();\n\n    this.outputAdded.emit(newOutput);\n    // console.log(\"Output added: \" + newOutput);\n  }\n\n  addItem(item) {\n    var newItem = Object.assign(\n      {},\n      {\n        id: -1,\n        duration: item.width,\n        start: item.left,\n        overlapsLeft: [],\n        overlapsRight: []\n      },\n      item\n    );\n    this.state.items.push(newItem);\n\n    this.itemAdded.emit(newItem);\n    // console.log(\"Item added: \" + newItem);\n  }\n\n  getChannelById(id) {\n    for (var i = 0; i < this.state.channels.length; ++i) {\n      if (this.state.channels[i].id == id)\n        return this.state.channels[i];\n    }\n    return false;\n  }\n\n  updateContainerSize() {\n    this.state.gridWidth = this.state.duration * (10 / this.state.zoom);\n    TweenLite.set(\n      this.$container, {\n        height: (this.state.channels.length + this.state.outputs.length) * this.state.gridHeight + 1,\n        width: this.state.gridWidth\n      }\n    );\n  }\n\n  selectChannel(i) {\n    var channel = this.state.channels[i];\n    this.resetObjectSelection();\n    channel.selected = true;\n    this.channelClicked.emit(channel);\n    // console.log(\"Channel clicked: \" + channel);\n  }\n\n  selectItem(item) {\n    //this.resetObjectSelection();\n    this.state.channels\n      .concat(this.state.outputs).map((o) => {\n        o.selected = false;\n      });\n    item.selected = true;\n    item.$el.addClass('ui-selected');\n  }\n\n  selectOutput(i) {\n    var output = this.state.outputs[i];\n    this.resetObjectSelection();\n    output.selected = true;\n\n    this.outputClicked.emit(output);\n    // console.log(\"Output clicked: \" + output);\n  }\n\n  resetObjectSelection() {\n    this.state.channels\n      .concat(this.state.outputs)\n      .map((o) => {\n        o.selected = false;\n      });\n\n    this.resetSelection();\n  }\n\n  deleteChannel(i) {\n    var deleted = this.state.channels.splice(i, 1)[0];\n    deleted.$el.remove();\n\n    this.drawChannels();\n  }\n\n  deleteOutput(i) {\n    var deleted = this.state.outputs.splice(i, 1)[0];\n    deleted.$el.remove();\n\n    // move all existing items on channels up one row\n    this.state.items.filter((item) => item.type == 'channel').map((item) => {\n      this.moveItem(item, item.left, item.top - this.state.gridHeight);\n    });\n\n    this.drawChannels();\n  }\n\n  deleteItem(i) {\n    var deleted = this.state.items.splice(i, 1)[0];\n  }\n\n}\n"
  },
  {
    "path": "src/app/campaigns/timeline-props.ts",
    "content": "import {ChangeDetectorRef, Component} from \"@angular/core\";\nimport {FormBuilder, FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport * as _ from \"lodash\";\nimport {CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {Observable} from \"rxjs\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {simpleRegExp} from \"../../Lib\";\n\n@Component({\n    selector: 'timeline-props',\n    host: {\n        '(input-blur)': 'onFormChange($event)'\n    },\n    template: `\n        <div>\n            <form novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n                <div class=\"row\">\n                    <div class=\"inner userGeneral\">\n                        <div class=\"panel panel-default tallPanel\">\n                            <div class=\"panel-heading\">\n                                <small class=\"release\">timeline properties\n                                    <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                                </small>\n                                <small class=\"debug\">{{me}}</small>\n                            </div>\n                            <ul class=\"list-group\">\n                                <li class=\"list-group-item\">\n                                    <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == '1'\">\n                                        <h4><i class=\"fa fa-calendar\"></i>playback mode: scheduler</h4>\n                                    </div>\n                                    <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == '0'\">\n                                        <h4><i class=\"fa fa fa-repeat\"></i>playback mode: sequencer</h4>\n                                    </div>\n                                </li>\n                                <li *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == '0'\" class=\"list-group-item\">\n                                    <h4>timeline length: {{m_duration}}</h4>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <div class=\"input-group\">\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                                        <input [formControl]=\"m_contGroup.controls['timeline_name']\" required\n                                               type=\"text\" class=\"form-control\" maxlength=\"50\"\n                                               placeholder=\"timeline name\">\n                                    </div>\n                                    <br/>\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n            </form>\n        </div>\n        <div *ngIf=\"(m_campaignModel$ | async)?.getCampaignPlaylistMode() == '1'\">\n            <campaign-sched-props></campaign-sched-props>\n        </div>\n    `,\n    styles: [`\n        input.ng-invalid {\n            border-right: 10px solid red;\n        }\n\n        .material-switch {\n            position: relative;\n            padding-top: 10px;\n        }\n\n        .input-group {\n            padding-top: 10px;\n        }\n\n        i {\n            width: 20px;\n        }\n    `]\n})\nexport class TimelineProps extends Compbaser {\n\n    private timelineModel: CampaignTimelinesModel;\n    private formInputs = {};\n    m_duration: string = '00:00:00'\n    m_contGroup: FormGroup;\n    m_campaignModel$: Observable<CampaignsModelExt>;\n\n    constructor(private fb: FormBuilder, private ngmslibService: NgmslibService, private yp: YellowPepperService, private rp: RedPepperService, private cd: ChangeDetectorRef) {\n        super();\n        this.m_contGroup = fb.group({\n            'timeline_name': ['', [Validators.required, Validators.pattern(simpleRegExp)]],\n        });\n        _.forEach(this.m_contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.m_contGroup.controls[key] as FormControl;\n        })\n        this.m_campaignModel$ = this.yp.listenCampaignValueChanged()\n\n        this.cancelOnDestroy(\n            this.yp.listenTimelineSelected()\n                .subscribe((i_timelineModel: CampaignTimelinesModel) => {\n                    this.timelineModel = i_timelineModel;\n                    var totalDuration = parseInt(i_timelineModel.getTimelineDuration())\n                    var xdate = new XDate();\n                    this.m_duration = xdate.clearTime().addSeconds(totalDuration).toString('HH:mm:ss');\n                    this.renderFormInputs();\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        );\n\n    }\n\n    private onFormChange(event) {\n        this.updateSore();\n    }\n\n    @timeout()\n    private updateSore() {\n        // con(this.m_contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.m_contGroup.value)));\n        this.rp.setCampaignTimelineRecord(this.timelineModel.getCampaignTimelineId(), 'timeline_name', this.m_contGroup.value.timeline_name);\n        this.rp.reduxCommit()\n    }\n\n    private renderFormInputs() {\n        if (!this.timelineModel)\n            return;\n        _.forEach(this.formInputs, (value, key: string) => {\n            let data = this.timelineModel.getKey(key);\n            data = StringJS(data).booleanToNumber();\n            this.formInputs[key].setValue(data)\n        });\n    };\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/campaigns/timeline-ruler/timeline-ruler.component.css",
    "content": "#ruler {\n  border: 1px solid black;\n}\n\n#ruler-container {\n  height: 50px;\n}\n"
  },
  {
    "path": "src/app/campaigns/timeline-ruler/timeline-ruler.component.html",
    "content": "<div id=\"ruler-container\">\n  <canvas id=\"ruler\"></canvas>\n</div>\n"
  },
  {
    "path": "src/app/campaigns/timeline-ruler/timeline-ruler.component.spec.ts",
    "content": "/* tslint:disable:no-unused-variable */\nimport { async, ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { DebugElement } from '@angular/core';\n\nimport { TimelineRulerComponent } from './timeline-ruler.component';\n\ndescribe('TimelineRulerComponent', () => {\n  let component: TimelineRulerComponent;\n  let fixture: ComponentFixture<TimelineRulerComponent>;\n\n  beforeEach(async(() => {\n    TestBed.configureTestingModule({\n      declarations: [ TimelineRulerComponent ]\n    })\n    .compileComponents();\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TimelineRulerComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should create', () => {\n    expect(component).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/app/campaigns/timeline-ruler/timeline-ruler.component.ts",
    "content": "import { Component, OnInit, Input, OnChanges } from '@angular/core';\n\n@Component({\n  selector: 'app-timeline-ruler',\n  templateUrl: './timeline-ruler.component.html',\n  styleUrls: ['./timeline-ruler.component.css']\n})\nexport class TimelineRulerComponent implements OnInit, OnChanges {\n  @Input() width;\n  @Input() height;\n  @Input() scale : number = 1.0 / 10;\n  @Input() position : number;\n\n  canvas : any;\n  ctx;\n\n  constructor() { }\n\n  ngOnInit() {\n    this.drawScale();\n\n    window.onresize = () => this.drawScale();\n  }\n\n  ngOnChanges() {\n    this.drawScale();\n  }\n\n  drawScale() {\n    this.canvas = document.getElementById('ruler');\n    this.ctx = this.canvas.getContext('2d');\n\n    this.width = parseInt(this.width);\n\n        this.canvas.width = Math.min(document.getElementById(\"ruler-container\").offsetWidth, this.width);\n        this.canvas.height = this.height;\n\n        this.ctx.fillStyle = 'rgb(50, 50, 50)';\n        this.ctx.fillRect(0, 0, this.width, this.height);\n\n        var minorStep = 10;\n        var majorStep = 100;\n        var minorLineHeight = 10;\n        var majorLineHeight = 25;\n\n        var pos = Number(this.position);\n\n        var startPos;\n\n        for (let i = -100; i <= 0;++i) {\n          if ((pos + i) % majorStep == 0 || (pos + i) % minorStep == 0) {\n            startPos = i;\n            break;\n          }\n        }\n\n        this.ctx.fillStyle = 'rgb(250, 250, 250)';\n        this.ctx.font = '12px verdana';\n\n        for (let i = startPos; i <= startPos + this.width + 100; i += minorStep) {\n          var realPosition = pos + i;\n\n          if (realPosition % majorStep == 0) { // draw major step\n            this.ctx.fillRect(i, 50 - majorLineHeight, 1, majorLineHeight);\n            var totalSeconds = realPosition * this.scale;\n            var hours = Math.floor(totalSeconds / 60 / 60);\n            totalSeconds -= hours * 3600;\n            var minutes = Math.floor(totalSeconds / 60);\n            totalSeconds -= minutes * 60;\n            var seconds = totalSeconds;\n\n            var displayHours = hours,\n                displayMinutes = minutes < 10 ? \"0\" + +minutes : minutes,\n                displaySeconds = seconds < 10 ? \"0\" + +seconds : seconds;\n\n            // draw text\n\n            this.ctx.fillText(`${displayHours}:${displayMinutes}:${displaySeconds}`, i, 15);\n          } else if (realPosition % minorStep == 0) { // draw minor step\n\n            this.ctx.fillRect(i, 50 - minorLineHeight, 1, minorLineHeight);\n          }\n        }\n  }\n\n}\n"
  },
  {
    "path": "src/app/dashboard/dash-panel-mini.html",
    "content": "<small class=\"debug\">{{me}}</small>\n<hr/>\n<Logo class=\"pull-left\" *ngIf=\"isBrandingDisabled\" style=\"padding-left: 5px; padding-top: 5px\"></Logo>\n<reseller-logo class=\"pull-left\" *ngIf=\"!isBrandingDisabled\" style=\"padding-left: 5px; padding-top: 5px\"></reseller-logo>\n<span style=\"font-size: 16px; padding-top: 7px; padding-left: 4px\" class=\"pull-left\">{{resellerName}}</span>\n<div class=\"clearfix\"></div>\n<hr/>\n<h4>{{clock$ | async | date:'medium'}}</h4>\n<hr/>\n<h3 style=\"color: green\"><i class=\"fa fa-check-circle\"></i> mode: online</h3>\n<div *ngIf=\"isBrandingDisabled\">\n    <hr/>\n    <h5>Quick help:</h5>\n    <ul class=\"user-controls\">\n        <li><a target=\"_blank\" href=\"http://www.digitalsignage.com\"><span style=\"margin-left:3px;\" class=\"fa fa-link\"></span> DigitalSignage.com</a></li>\n        <li><a target=\"_blank\" href=\"http://www.digitalsignage.com/_html/signage_video.html\"><span style=\"margin-left:3px;\" class=\"fa fa-link\"></span> Videos</a></li>\n        <li><a target=\"_blank\" href=\"http://www.digitalsignage.com/_html/webinar_registration.html\"><span style=\"margin-left:3px;\" class=\"fa fa-link\"></span> Webinar</a></li>\n        <li><a target=\"_blank\" href=\"http://script.digitalsignage.com/forum/index.php\"><span style=\"margin-left:3px;\" class=\"fa fa-link\"></span> Forum</a></li>\n    </ul>\n</div>\n<hr/>\n<h5>User: {{(m_userModel$ | async).getUser()}}</h5>\n<h5>Business id: {{(m_userModel$ | async).businessId()}}</h5>\n<h5>server : {{(m_userModel$ | async).getPartialDomain()}}</h5>\n<h5>app version: {{version}}</h5>\n<h5>framework version: {{ngVersion}}</h5>\n<hr/>\n"
  },
  {
    "path": "src/app/dashboard/dash-panel-mini.ts",
    "content": "import {AfterViewInit, Component, VERSION} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Observable} from \"rxjs/Observable\";\nimport * as packageJson from \"../../../package.json\";\n\n@Component({\n    selector: 'dash-panel-mini',\n    styles: [`\n        a {\n            font-size: 1.1em;\n        }\n\n        li {\n            list-style-type: none;\n        }\n\n    `],\n    templateUrl: './dash-panel-mini.html'\n})\nexport class DashPanelMini extends Compbaser implements AfterViewInit {\n    clock$;\n    m_userModel$;\n    offlineDevMode: any = window['offlineDevMode'];\n    version = packageJson.version;\n    isBrandingDisabled: boolean = false;\n    ngVersion = VERSION.full;\n    resellerName = 'MediasSignage Inc.';\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n\n        this.clock$ = Observable\n            .interval(300)\n            .startWith(1)\n            .map(() => new Date());\n\n        this.m_userModel$ = this.yp.listenUserModel();\n        this.cancelOnDestroy(\n            this.yp.isBrandingDisabled()\n                .subscribe((v) => {\n                    this.isBrandingDisabled = v;\n                    if (!this.isBrandingDisabled)\n                        this.resellerName = this.rp.getUserData().resellerName;\n                }, (e) => console.error(e))\n        )\n    }\n\n    ngAfterViewInit() {\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/dashboard/dash-panel.html",
    "content": "<small class=\"debug\">{{me}}</small>\n\n<div class=\"row\">\n    <br/>\n    <div class=\"col-sm-4 col-lg-2\">\n        <Infobox [value1]=\"(m_campaigns$ | async)?.size\" [value3]=\"'total campaigns'\" [icon]=\"'fa-bars'\"></Infobox>\n    </div>\n    <div class=\"col-sm-4 col-lg-2\">\n        <Infobox [value1]=\"(m_resources$ | async)?.size\" [value3]=\"'total resources'\" [icon]=\"'fa-certificate'\"></Infobox>\n    </div>\n    <div class=\"col-sm-4 col-lg-2\">\n        <Infobox [value1]=\"(m_scenes$ | async)?.length\" [value3]=\"'total scenes'\" [icon]=\"'fa-crosshairs'\"></Infobox>\n    </div>\n    <div class=\"col-sm-4 col-lg-2\">\n        <Infobox [value1]=\"(m_timelines$ | async)?.size\" [value3]=\"'total timelines'\" [icon]=\"'fa-list'\"></Infobox>\n    </div>\n    <div class=\"col-sm-4 col-lg-2\">\n        <Infobox [value1]=\"(m_lines$ | async)?.size\" [value3]=\"'fasterq lines'\" [icon]=\"'fa-user-o'\"></Infobox>\n    </div>\n    <div class=\"col-sm-4 col-lg-2\">\n        <Infobox [value1]=\"(m_userModel$ | async)?.getRememberMe() == true ? 'ON' : 'OFF'\" [value3]=\"'auto login'\" [icon]=\"'fa-circle-o'\"></Infobox>\n    </div>\n</div>\n\n<div class=\"row\">\n    <br/>\n    <div class=\"col-sm-6 col-lg-4\">\n        <server-avg style=\"width: 100%\"></server-avg>\n    </div>\n    <div class=\"col-sm-6 col-lg-4\">\n        <storage-used style=\"width: 100%\"></storage-used>\n    </div>\n    <div class=\"responsive-pad-top col-sm-12 col-lg-4\">\n        <div class=\"row\">\n            <div class=\"col-xm-12\">\n                <Infobox style=\"color: green\" [value1]=\"m_totalStationsConnected\" [value3]=\"'stations connected'\" icon=\"fa-tv\"></Infobox>\n            </div>\n            <div class=\"col-xm-12\">\n                <Infobox style=\"color: red\" [value1]=\"m_totalStationsDisconnected\" [value3]=\"'stations disconnected'\" icon=\"fa-tv\"></Infobox>\n            </div>\n        </div>\n    </div>\n</div>\n\n<div class=\"row\" >\n    <br/>\n    <div *ngIf=\"(isBrandingDisabled | async)==true\" class=\"col-sm-12 col-lg-4\">\n        <a class=\"twitter-timeline\" href=\"https://twitter.com/MediaSignage\" data-widget-id=\"378653740623863808\">Tweets by @MediaSignage</a>\n        <!--<div *ngIf=\"(isBrandingDisabled | async)==false\" style=\"border: 1px solid #dbdbdb; background-color: #fafafa; height: 400px\">AAAA</div>-->\n    </div>\n    <div [ngClass]=\"{'col-sm-12':true, 'col-lg-8': (isBrandingDisabled | async)==true}\">\n        <div class=\"row\">\n            <div class=\"col-sm-12 col-lg-6\">\n                <Infobox [value1]=\"(m_userModel$ | async)?.user()\" [value3]=\"'business id ' + (m_userModel$ | async)?.businessId()\" [icon]=\"'fa-user-circle-o'\"></Infobox>\n            </div>\n            <div class=\"col-sm-12 col-lg-6\">\n                <Infobox [value1]=\"(m_lastSave$ | async)\" [value3]=\"'last save'\" [icon]=\"'fa-save'\"></Infobox>\n            </div>\n        </div>\n        <div class=\"row\" style=\"margin: 0px 0px 10px 0px\">\n            <div class=\"col-xs-12\" style=\"border: 1px solid #dbdbdb; background-color: #fafafa; height: 275px; padding: 0\">\n                <div style=\"overflow-x: scroll\">\n                    <div style=\"width: 100%; height: 250px\">\n                        <simpleGridTable #simpleGrid>\n                            <thead>\n                            <tr>\n                                <th>time</th>\n                                <th>action</th>\n                            </tr>\n                            </thead>\n                            <tbody>\n                            <tr class=\"simpleGridRecord\" simpleGridRecord *ngFor=\"let item of m_liveLog; let index=index\" [item]=\"item\" [index]=\"index\">\n                                <td simpleGridData style=\"width: 20%\" [editable]=\"false\" field=\"date\" [item]=\"item\"></td>\n                                <td simpleGridData style=\"width: 80%\" [editable]=\"false\" field=\"event\" [item]=\"item\"></td>\n                            </tr>\n                            </tbody>\n                        </simpleGridTable>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n\n\n"
  },
  {
    "path": "src/app/dashboard/dash-panel.ts",
    "content": "import {AfterViewInit, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {EFFECT_LOAD_FASTERQ_LINES, EFFECT_LOAD_STATIONS} from \"../../store/effects/appdb.effects\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {List} from \"immutable\";\nimport {StationModel} from \"../../models/StationModel\";\nimport {Observable} from \"rxjs/Observable\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\nimport {ACTION_LIVELOG_UPDATE} from \"../../store/actions/appdb.actions\";\n\n@Component({\n    selector: 'dash-panel',\n    styles: [`\n        .twitter-timeline {\n            width: 100% !important;\n        }\n\n        iframe {\n            width: 100% !important;\n        }\n    `],\n    templateUrl: './dash-panel.html'\n})\nexport class DashPanel extends Compbaser implements AfterViewInit {\n    m_totalStationsConnected = 0;\n    m_totalStationsDisconnected = 0;\n    m_lastSave$;\n    m_userModel$;\n    m_scenes$;\n    m_campaigns$;\n    m_resources$;\n    m_lines$;\n    m_timelines$;\n    m_liveLog:List<LiveLogModel>;\n    isBrandingDisabled: Observable<boolean>;\n\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.m_lastSave$ = this.yp.ngrxStore.select(store => store.appDb.uiState.appSaved)\n        this.m_userModel$ = this.yp.listenUserModel();\n        this.m_scenes$ = this.yp.getScenes();\n        this.m_campaigns$ = this.yp.getCampaigns();\n        this.m_resources$ = this.yp.getResources();\n        this.m_lines$ = this.yp.listenFasterqLines();\n        this.m_timelines$ = this.yp.getTimelines();\n        this.isBrandingDisabled = this.yp.isBrandingDisabled();\n        this._listenStationsConnection();\n        this._listenLoadLines();\n        this._listenLiveLog();\n    }\n\n    _listenLiveLog() {\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.liveLog)\n                .subscribe((i_liveLog) => {\n                    this.m_liveLog = i_liveLog;\n                }, (e) => console.error(e))\n        )\n    }\n\n    _listenLoadLines() {\n        this.yp.ngrxStore.dispatch({type: EFFECT_LOAD_FASTERQ_LINES, payload: {}})\n        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'updating remote stations status'})}));\n    }\n\n    _listenStationsConnection() {\n        this.cancelOnDestroy(\n            this.yp.listenStations()\n                .map((i_stationModels: List<StationModel>) => {\n                    i_stationModels.forEach(i_stationModel => {\n                        if (i_stationModel.connection == 0) {\n                            this.m_totalStationsDisconnected++;\n                        } else {\n                            this.m_totalStationsConnected++;\n                        }\n                    });\n                    return i_stationModels;\n                }).subscribe(() => {\n            }, (e) => console.error(e))\n        );\n        this._loadStationData();\n    }\n\n    ngAfterViewInit() {\n        var twitter = function (d: any, s, id) {\n            var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https';\n            // if (!d.getElementById(id)) {\n            js = d.createElement(s);\n            js.id = id;\n            js.src = p + \"://platform.twitter.com/widgets.js\";\n            js.setAttribute('onload', \"twttr.events.bind('rendered',function(e) {});\");\n            fjs.parentNode.insertBefore(js, fjs);\n            // }\n        }(document, \"script\", \"twitter-wjs\");\n        this.setTwitterWidth();\n\n    }\n\n    _loadStationData() {\n        this.yp.ngrxStore.dispatch({type: EFFECT_LOAD_STATIONS, payload: {userData: this.rp.getUserData()}});\n    }\n\n    setTwitterWidth() {\n        Observable.interval(400)\n            .take(5)\n            .subscribe(() => {\n                jQuery('.twitter-timeline').css({width: '100%'});\n            })\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/dashboard/dashboard-navigation.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\n@Component({\n    selector: 'Dashboard',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <h2 i18n>account dashboard</h2>\n        <dash-panel></dash-panel>\n    `\n})\nexport class Dashboard implements AfterViewInit {\n\n    constructor(private toastr: ToastsManager) {\n    }\n\n    ngAfterViewInit(){\n        this.clearToasts();\n    }\n\n    @timeout(1000)\n    clearToasts(){\n        this.toastr.clearAllToasts();\n    }\n}"
  },
  {
    "path": "src/app/dashboard/server-avg.ts",
    "content": "import {ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {Http} from \"@angular/http\";\nimport * as _ from 'lodash';\nimport {Observable} from \"rxjs/Observable\";\nimport {Compbaser} from \"ng-mslib\";\n\n@Component({\n    selector: 'server-avg',\n    styles: [`\n        chart {\n            width: 100% !important;\n            margin: 0 auto;\n            display: block;\n        }\n    `],\n    template: `\n        <div style=\"width: 100%; height: 150px\">\n            <loading *ngIf=\"!_ready\" [size]=\"'50px'\" [style]=\"{'margin-top': '150px'}\"></loading>\n            <div style=\"width: 100%\" *ngIf=\"_ready\">\n                <chart [options]=\"_options\" (load)=\"saveInstance($event.context)\">></chart>\n            </div>\n        </div>\n    `\n})\nexport class ServerAvg extends Compbaser {\n    _options;\n    _chart: any;\n    _ready = false;\n\n    constructor(private _http: Http, private cd:ChangeDetectorRef) {\n        super();\n        this.serverStatus();\n        this._options = {\n            chart: {\n                type: 'spline',\n                height: 228,\n                borderColor: '#d9d9d9',\n                borderWidth: 1,\n                marginRight: 10,\n            },\n            responsive: {\n                rules: [{\n                    condition: {\n                        maxWidth: 500\n                    },\n                    chartOptions: {\n                        legend: {\n                            align: 'center',\n                            verticalAlign: 'bottom',\n                            layout: 'horizontal'\n                        },\n                        yAxis: {\n                            labels: {\n                                align: 'left',\n                                x: 0,\n                                y: -5\n                            },\n                            title: {\n                                text: null\n                            }\n                        },\n                        subtitle: {\n                            text: null\n                        },\n                        credits: {\n                            enabled: false\n                        }\n                    }\n                }]\n            },\n            title: {\n                text: ''\n            },\n\n            xAxis: {\n                labels: {\n                    enabled: false\n                },\n                categories: []\n            },\n            credits: {\n                enabled: false\n            },\n            yAxis: [{\n                min: 0,\n                title: {  \n                    text: 'average cloud response'\n                }\n            }, {\n                title: {\n                    text: 'measured in milliseconds'\n                },\n                opposite: true\n            }],\n            legend: {\n                enabled: false,\n                shadow: false\n            },\n            tooltip: {\n                shared: true\n            },\n            plotOptions: {\n                column: {\n                    grouping: false,\n                    shadow: false,\n                    borderWidth: 0\n                }\n            },\n            series: [{data: [0]}]\n        };\n    }\n\n    saveInstance(chartInstance) {\n        this._chart = chartInstance;\n    }\n\n    public serverStatus() {\n        this.cancelOnDestroy(\n            Observable.interval(2000)\n                .startWith(0)\n                .switchMap(() =>\n                    this._http.get(`https://secure.digitalsignage.com/msPingServersGuest`)\n                        .map(result => {\n                            this._ready = true;\n                            this.cd.markForCheck();\n                            result = result.json();\n                            var avg = 0, t = 0;\n                            _.forEach(result, (stats) => {\n                                t++;\n                                avg = Number(stats) + avg;\n                            });\n                            if (!this._chart)\n                                return 0;\n                            return avg / t;\n                        })\n                )\n                .subscribe((value) => {\n                if (!this._chart)\n                    return;\n                    var series = this._chart.series[0],\n                        shift = series.data.length > 20;\n                    this._chart.series[0].addPoint(value, true, shift);\n                }, (e) => console.error(e))\n        );\n    }\n}"
  },
  {
    "path": "src/app/dashboard/storage-used.ts",
    "content": "import {ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {Http} from \"@angular/http\";\nimport * as _ from 'lodash';\nimport {Observable} from \"rxjs/Observable\";\nimport {Compbaser} from \"ng-mslib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Lib} from \"../../Lib\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\nimport {ACTION_LIVELOG_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\n@Component({\n    selector: 'storage-used',\n    styles: [`\n        chart {\n            width: 100% !important;\n            margin: 0 auto;\n            display: block;\n        }\n    `],\n    template: `\n        <div style=\"width: 100%; height: 150px\">\n            <loading *ngIf=\"!_ready\" [size]=\"'50px'\" [style]=\"{'margin-top': '150px'}\"></loading>\n            <div style=\"width: 100%\" *ngIf=\"_ready\">\n                <chart [options]=\"_options\" (load)=\"saveInstance($event.context)\">></chart>\n            </div>\n        </div>\n    `\n})\nexport class StorageUsed extends Compbaser {\n    _options;\n    _chart: any;\n    _ready = false;\n\n\n    constructor(private yp: YellowPepperService, private cd:ChangeDetectorRef, private rp:RedPepperService) {\n        super();\n        var totalCapacity = this.rp.getUserData().resellerID == 1 ? 1000 : 25000;\n        var gigs = totalCapacity / 1000 + 'GB';\n        var bytesTotal = 0;\n        this.rp.getResources().forEach((recResources)=>{\n            if (recResources['change_type'] != 3)\n                bytesTotal = bytesTotal + parseInt(recResources['resource_bytes_total']);\n        });\n        var used = Lib.ParseToFloatDouble((Math.ceil(bytesTotal / 1000000) / totalCapacity) * 100);\n        var free = 100 - used;\n\n        // if (String(mbTotalPercentRounded).length == 1 && String(mbTotalPercentRounded) != '0')\n        //     mbTotalPercentRounded = '0' + mbTotalPercentRounded;\n        // console.log(`Used %${mbTotalPercentRounded} of ${gigs}gb` );\n        this._options = {\n            chart: {\n                type: 'pie',\n                height: 228,\n                borderColor: '#d9d9d9',\n                borderWidth: 1,\n                marginRight: 10,\n            },\n            responsive: {\n                rules: [{\n                    condition: {\n                        maxWidth: 500\n                    },\n                    chartOptions: {\n                        legend: {\n                            align: 'center',\n                            verticalAlign: 'bottom',\n                            layout: 'horizontal'\n                        },\n                        yAxis: {\n                            labels: {\n                                align: 'left',\n                                x: 0,\n                                y: -5\n                            },\n                            title: {\n                                text: null\n                            }\n                        },\n                        subtitle: {\n                            text: null\n                        },\n                        credits: {\n                            enabled: false\n                        }\n                    }\n                }]\n            },\n            title: {\n                text: ''\n            },\n\n            xAxis: {\n                labels: {\n                    enabled: false\n                },\n                categories: []\n            },\n            credits: {\n                enabled: false\n            },\n            yAxis: [{\n                min: 0,\n                title: {\n                    text: 'average response time'\n                }\n            }, {\n                title: {\n                    text: 'measured in milliseconds'\n                },\n                opposite: true\n            }],\n            legend: {\n                enabled: false,\n                shadow: false\n            },\n            tooltip: {\n                shared: true\n            },\n            plotOptions: {\n                column: {\n                    grouping: false,\n                    shadow: false,\n                    borderWidth: 0\n                }\n            },\n            series: [{\n                name: 'cloud storage',\n                colorByPoint: true,\n                data: [{\n                    name: '% storage used',\n                    y: used\n                }, {\n                    name: '% storage free',\n                    y: free,\n                    sliced: true,\n                    selected: true\n                }]\n            }]\n        };\n        this._ready = true;\n    }\n\n    saveInstance(chartInstance) {\n        this._chart = chartInstance;\n        this.cd.markForCheck();\n\n    }\n\n    // public serverStatus() {\n    //     this.cancelOnDestroy(\n    //         Observable.interval(2000)\n    //             .startWith(0)\n    //             .switchMap(() =>\n    //                 this._http.get(`https://secure.digitalsignage.com/msPingServersGuest`)\n    //                     .map(result => {\n    //                         this._ready = true;\n    //                         this.cd.markForCheck();\n    //                         result = result.json();\n    //                         var avg = 0, t = 0;\n    //                         _.forEach(result, (stats) => {\n    //                             t++;\n    //                             avg = Number(stats) + avg;\n    //                         });\n    //                         if (!this._chart)\n    //                             return 0;\n    //                         return avg / t;\n    //                     })\n    //             )\n    //             .subscribe((value) => {\n    //                 if (!this._chart)\n    //                     return;\n    //                 var series = this._chart.series[0],\n    //                     shift = series.data.length > 20;\n    //                 this._chart.series[0].addPoint(value, true, shift);\n    //             }, (e) => console.error(e))\n    //     );\n    // }\n}"
  },
  {
    "path": "src/app/fasterq/fasterq-editor.html",
    "content": "<small class=\"debug\">{{me}}</small>\n<div id=\"fasterQManagerContainer\">\n    <button (click)=\"_openRemoteStatus()\" i18n style=\"margin-right: 100px; position: relative; top: -30px\" id=\"fqOpenCustomerRemoteStatus\" class=\"pull-right btn btn-primary\">remote status</button>\n    <h5>Line: {{m_fasterqLineModel?.lineName}}</h5>\n    <h5>Service id: {{m_selectedServiceId > 0 ? m_selectedServiceId : 'none'}}</h5>\n    <div>\n        <br/>\n        <br/>\n        <br/>\n        <div style=\"margin: 0 20px 0 -9px\" class=\"row fqStats\">\n            <div class=\"col-xs-6 col-sm-3\" style=\"margin-top: 0; padding: 0;\">\n                <div class=\"fakeVerticalLineDivL\" style=\"height: 58px; width: 100%; float: left\">\n                    <span><strong>called customer: </strong></span><br/>\n                    <span id=\"fqTimeWithCustomer\">{{m_stopTimer}}</span>\n                </div>\n            </div>\n            <div class=\"col-xs-6 col-sm-3\" style=\"margin-top: 0; padding: 0\">\n                <div class=\"fakeVerticalLineDivL\" style=\"height: 58px; width: 100%; float: left\">\n                    <span><strong>last you serviced</strong></span><br/>\n                    <span id=\"fqLastServiced\">{{m_fqLastServiced}}</span>\n                </div>\n            </div>\n            <div class=\"col-xs-6 col-sm-3\" style=\"margin-top: 0; padding: 0\">\n                <div class=\"fakeVerticalLineDivL\" style=\"height: 58px; width: 100%; float: left\">\n                    <span><strong>last you called</strong></span><br/>\n                    <span id=\"fqLastCalled\">{{m_lastCalled}}</span>\n                </div>\n            </div>\n            <div class=\"col-xs-6 col-sm-3\" style=\"margin-top: 0; padding: 0;\">\n                <div class=\"fakeVerticalLineDivL\" style=\"height: 58px; width: 100%; float: left\">\n                    <span><strong>total to be serviced</strong></span><br/>\n                    <span id=\"fqTotalToBeServiced\">{{m_totalToBeServiced}}</span>\n                </div>\n            </div>\n        </div>\n        <div style=\"margin: 0 20px 0 -9px\" class=\"row fqStats\">\n            <div class=\"col-xs-4\" style=\"margin-top: 0; padding: 0;\">\n                <div class=\"fakeVerticalLineDivL\" style=\"width: 100%; float: left\">\n                    <span><strong>avg customer service time (minutes): </strong></span><br/>\n                    <h1 id=\"fqAvgCustomerService\">{{m_avgServiceTimeCalc}}</h1>\n                </div>\n            </div>\n            <div class=\"col-xs-4\" style=\"margin-top: 0; padding: 0\">\n                <div class=\"fakeVerticalLineDivL\" style=\"width: 100%; float: left\">\n                    <span><strong>avg customer wait time (minutes):</strong></span><br/>\n                    <h1 id=\"fqAvgCustomerWait\">{{m_avgCalledTimeCalc}}</h1>\n                </div>\n            </div>\n            <div class=\"col-xs-4\" style=\"margin-top: 0; padding: 0;\">\n                <div class=\"fakeVerticalLineDivL\" style=\"width: 100%; float: left\">\n                    <span><strong>now servicing: </strong></span><br/>\n                    <h1 id=\"fqNowServicing\">Latest: {{m_nowServicing}}</h1>\n                </div>\n            </div>\n        </div>\n        <br/>\n        <div id=\"fqLineQueueComponentWrap\">\n            <div id=\"fqSelectedCustomer\"></div>\n            <div id=\"fqLineQueueComponentContainer\">\n                <div id=\"fqLineQueueComponent\">\n                    <div *ngFor=\"let queue of m_queues; let i = index\" class=\"personInLine\" (click)=\"_onQueueSelected(queue)\" [ngClass]=\"{serviced: queue.serviced, called: queue.called}\">\n                        <div *ngIf=\"queue.lineId != -1\">\n                            <i style=\"font-size: 90px\" class=\"fa fa-male\"></i>\n                            <h3 style=\"position: relative; left: 6px\">{{queue.serviceId}}</h3>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <div style=\"text-align: center; width: 100%;\" class=\"centerElement\">\n            <button (click)=\"_onCall()\" id=\"fqLineCompCall\" type=\"button\" data-localize-tooltip=\"back\" data-localize=\"empty\" title=\"back\" class=\"lineComponentButtons btn btn-default btn-sm\">\n                <span class=\"fa fa-bullhorn\"></span> Call\n            </button>\n            <button (click)=\"_onService()\" id=\"fqLineCompServiced\" type=\"button\" data-localize-tooltip=\"back\" data-localize=\"empty\" title=\"back\" class=\"lineComponentButtons btn btn-default btn-sm\">\n                <span class=\"fa fa-thumbs-up\"></span> Serviced\n            </button>\n            <button (click)=\"_onPrev()\" id=\"fqLineCompPrev\" type=\"button\" data-localize-tooltip=\"back\" data-localize=\"empty\" title=\"back\" class=\"lineComponentButtons btn btn-default btn-sm\">\n                <span class=\"glyphicon glyphicon-chevron-left\"></span> Previous\n            </button>\n            <span>\n      <button (click)=\"_onGoTo()\" id=\"fqLineGoTo\" type=\"button\" data-localize-tooltip=\"goTo\" data-localize=\"empty\" title=\"go to\" class=\"lineComponentButtons btn btn-default btn-sm\">\n      Go to <input  [(ngModel)]=\"m_gotoModel\" id=\"fqGoToLineInput\">\n      </button>\n      </span>\n            <button (click)=\"_onNext()\" id=\"fqLineCompNext\" type=\"button\" data-localize-tooltip=\"back\" data-localize=\"empty\" title=\"back\" class=\"lineComponentButtons btn btn-default btn-sm\">\n                Next\n                <span class=\"glyphicon glyphicon-chevron-right\"></span>\n            </button>\n        </div>\n    </div>\n</div>"
  },
  {
    "path": "src/app/fasterq/fasterq-editor.ts",
    "content": "import {AfterViewInit, ChangeDetectorRef, Component, ElementRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {FasterqQueueModel} from \"../../models/fasterq-queue-model\";\nimport {FasterqLineModel} from \"../../models/fasterq-line-model\";\nimport {FasterqAnalyticsModel} from \"../../models/fasterq-analytics\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {EFFECT_LOAD_FASTERQ_ANALYTICS, EFFECT_LOAD_FASTERQ_QUEUES, EFFECT_QUEUE_CALL_SAVE, EFFECT_QUEUE_POLL_SERVICE, EFFECT_QUEUE_SERVICE_SAVE} from \"../../store/effects/appdb.effects\";\nimport {CommBroker} from \"../../services/CommBroker\";\nimport {FASTERQ_QUEUE_CALL_CANCLED} from \"../../interfaces/Consts\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {List} from \"immutable\";\nimport {Lib} from \"../../Lib\";\nimport * as _ from \"lodash\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\nexport interface IQueueSave {\n    queue_id: number;\n    queue: FasterqQueueModel;\n    serviced?: string;\n    called?: string;\n    called_by?: string;\n    called_by_override?: boolean;\n}\n\n@Component({\n    selector: 'fasterq-editor',\n    styles: [`\n        .personInLine {\n            margin: 10px;\n            padding: 0;\n            float: left;\n            width: 40px;\n            height: 100px;\n            cursor: pointer;\n            color: #D0D0D0;\n        }\n\n        .called {\n            color: #BE6734;\n        }\n\n        .serviced {\n            color: #ACFD89;\n        }\n    `],\n    templateUrl: './fasterq-editor.html'\n})\nexport class FasterqEditor extends Compbaser {\n\n    QUEUE_OFFSET = 8;\n    m_gotoModel = 0;\n    m_stopWatchHandle: any = new Stopwatch();\n    m_stopTimer = '00:00:00';\n    m_fasterqLineModel: FasterqLineModel;\n    m_selectedServiceId = -1;\n    m_queues: List<FasterqQueueModel> = List([]);\n    m_analytics: List<FasterqAnalyticsModel> = List([]);\n    m_offsetPosition = 0;\n    m_avgServiceTimeCalc: any = '00:00:00';\n    m_avgCalledTimeCalc: any = '00:00:00';\n    m_lastCalled: any = 0;\n    m_nowServicing: any = 0;\n    m_totalToBeServiced = 0;\n    m_fqLastServiced = '';\n    m_liveUpdateHandler;\n    appBaseUrlServices;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private commBroker: CommBroker, private el: ElementRef, private cd: ChangeDetectorRef) {\n        super();\n        this._pollServices();\n\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.appBaseUrlServices)\n                .subscribe((i_appBaseUrlServices) => {\n                    this.appBaseUrlServices = i_appBaseUrlServices;\n                })\n        )\n\n        this.cancelOnDestroy(\n            this.commBroker.onEvent(FASTERQ_QUEUE_CALL_CANCLED)\n                .subscribe((data: any) => {\n                    bootbox.confirm('Customer already called by user' + data.message.called_by + ' <br/><br/>Would you like to call the customer again?', (result) => {\n                        if (result) {\n                            data.message['called_by_override'] = true;\n                            this.yp.ngrxStore.dispatch({type: EFFECT_QUEUE_CALL_SAVE, payload: data.message})\n                        }\n                    });\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqQueueLastServicedPolled()\n                .subscribe((i_fasterqNowServicing) => {\n                    this.m_nowServicing = i_fasterqNowServicing;\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqQueueSelected()\n                .subscribe((i_serviceId) => {\n                    this.m_selectedServiceId = i_serviceId\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqLineSelected()\n                .subscribe((i_fasterqLineModel) => {\n                    this.m_fasterqLineModel = i_fasterqLineModel;\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqQueues()\n                .subscribe((i_queues: List<FasterqQueueModel>) => {\n                    this.m_queues = List([]);\n                    for (var i = (0 - this.QUEUE_OFFSET); i < 0; i++) {\n                        i_queues = i_queues.unshift(new FasterqQueueModel({line_id: -1}))\n                    }\n                    this.m_queues = i_queues;\n                    this._selectFirst();\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqAnalytics()\n                .subscribe((i_analytics: List<FasterqAnalyticsModel>) => {\n                    this.m_analytics = i_analytics;\n                    this._calcAverages();\n                    this.cd.markForCheck();\n                }, (e) => console.error(e))\n        )\n\n        this._selectFirst();\n    }\n\n    _openRemoteStatus() {\n        window.open(this._buildURL(), \"_blank\", \"toolbar=yes, scrollbars=yes, resizable=yes, top=10, left=10, width=400, height=400\");\n    }\n\n    /**\n     Create URL string to load customer terminal UI for FasterQ queue generation\n     @method _buildURL\n     @return {String} URL\n     **/\n    _buildURL() {\n        var data = {\n            line_id: this.m_fasterqLineModel.lineId,\n            business_id: this.m_fasterqLineModel.businessId,\n            call_type: 'QR'\n        };\n        data = $.base64.encode(JSON.stringify(data));\n        return `${this.appBaseUrlServices}/studioweb/index.html?mode=remoteStatus&param=${data}`;\n    }\n\n    @timeout(1000)\n    _selectFirst() {\n        if (this.m_queues.size != this.QUEUE_OFFSET + 1)\n            return;\n        this.m_selectedServiceId = this.m_queues.get(this.QUEUE_OFFSET).serviceId;\n        this._onQueueSelected(this.m_queues.get(this.QUEUE_OFFSET));\n    }\n\n    _pollServices() {\n        this.m_liveUpdateHandler = setInterval(() => {\n            this.yp.ngrxStore.dispatch({type: EFFECT_QUEUE_POLL_SERVICE, payload: {business_id: this.rp.getUserData().businessID, line_id: this.m_fasterqLineModel.lineId}})\n            this.yp.ngrxStore.dispatch(({type: EFFECT_LOAD_FASTERQ_QUEUES, payload: {line_id: this.m_fasterqLineModel.lineId}}))\n            this.yp.ngrxStore.dispatch(({type: EFFECT_LOAD_FASTERQ_ANALYTICS, payload: {line_id: this.m_fasterqLineModel.lineId}}))\n            this._updateTotalToBeServiced();\n            // todo: increase from 5 sec to 25sec 7-6-2018\n        }, 25000);\n    }\n\n    /**\n     Update the total number of queues left to be serviced\n     @method _updateTotalToBeServiced\n     **/\n    _updateTotalToBeServiced() {\n        var total = 0;\n        this.m_queues.forEach((i_asterqQueueModel: FasterqQueueModel) => {\n            if (_.isNull(i_asterqQueueModel.serviced))\n                total++;\n            this.m_totalToBeServiced = total;\n        });\n    }\n\n    _onQueueSelected(i_queue: FasterqQueueModel) {\n        this.m_selectedServiceId = i_queue.serviceId;\n        var index = this._getQueueIndexByServiceId();\n        var uiState: IUiState = {\n            uiSideProps: SideProps.fasterqQueueProps,\n            fasterq: {\n                fasterqQueueSelected: this.m_selectedServiceId\n            }\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this._scrollTo(index);\n    }\n\n    _getQueueIndexByServiceId(): number {\n        if (this.m_selectedServiceId == -1)\n            return this.m_selectedServiceId;\n        return this.m_queues.findIndex((i_fasterqQueueModel) => {\n            return i_fasterqQueueModel.serviceId == this.m_selectedServiceId;\n        })\n    }\n\n    /**\n     Scroll to position of selected queue / UI person\n     @method _scrollTo\n     @param {Element} i_element\n     **/\n    _scrollTo(i_index) {\n        this._watchStop();\n        var el = $('#fqLineQueueComponent', this.el.nativeElement).children().eq(i_index);\n        var scrollXPos = $(el).position().left;\n        // console.log('current offset ' + scrollXPos + ' ' + 'going to index ' + $(i_element).index() + ' service_id ' + i_serviceId);\n        this.m_offsetPosition = $('#fqLineQueueComponentContainer', this.el.nativeElement).scrollLeft();\n        scrollXPos += this.m_offsetPosition;\n        var final = scrollXPos - 480;\n        TweenLite.to('#fqLineQueueComponentContainer', 2, {\n            scrollTo: {x: final, y: 0},\n            ease: Power4['easeOut']\n        });\n    }\n\n    _getQueueFromSelectedIndex(): FasterqQueueModel {\n        return this.m_queues.find(i_fasterqQueueModel => {\n            return i_fasterqQueueModel.serviceId == this.m_selectedServiceId;\n        })\n    }\n\n    _selectIfDefault() {\n        if (this.m_queues.size >= this.QUEUE_OFFSET + 1 && this.m_selectedServiceId == -1)\n            this.m_selectedServiceId = this.m_queues.get(this.QUEUE_OFFSET).serviceId;\n    }\n\n    /**\n     Listen to queue being called, mark on UI and post to server\n     @method _listenCalled\n     **/\n    _onCall() {\n        this._selectIfDefault();\n        if (this.m_queues.size == this.QUEUE_OFFSET) return;\n        if (!_.isNull(this._getQueueFromSelectedIndex().serviced))\n            return bootbox.alert('customer has already been serviced');\n        this._watchStart();\n        this.m_lastCalled = this._getQueueFromSelectedIndex().serviceId;\n        var d = new XDate();\n        var payload: IQueueSave = {\n            queue_id: this._getQueueFromSelectedIndex().queueId,\n            called: d.toString('M/d/yyyy hh:mm:ss TT'),\n            called_by: this.rp.getUserData().userName,\n            called_by_override: false,\n            queue: this._getQueueFromSelectedIndex()\n        }\n        this.yp.ngrxStore.dispatch({type: EFFECT_QUEUE_CALL_SAVE, payload: payload})\n    }\n\n    /**\n     Listen to queue being serviced, mark on UI and post to server\n     @method _listenServiced\n     **/\n    _onService() {\n        this._selectIfDefault();\n        if (this.m_queues.size == this.QUEUE_OFFSET) return;\n        this._watchStop();\n        if (_.isNull(this._getQueueFromSelectedIndex().called)) {\n            bootbox.alert('customer has not been called yet');\n            return;\n        }\n        if (!_.isNull(this._getQueueFromSelectedIndex().serviced)) {\n            bootbox.alert('customer has already been serviced');\n            return;\n        }\n        this.m_fqLastServiced = this._getQueueFromSelectedIndex().serviceId;\n        var d = new XDate();\n        var payload: IQueueSave = {\n            queue_id: this._getQueueFromSelectedIndex().queueId,\n            serviced: d.toString('M/d/yyyy hh:mm:ss TT'),\n            queue: this._getQueueFromSelectedIndex()\n        }\n        this.yp.ngrxStore.dispatch({type: EFFECT_QUEUE_SERVICE_SAVE, payload: payload})\n    }\n\n    /**\n     Calculate average respond and service line times\n     @method _calcAverages\n     **/\n    _calcAverages() {\n        var avgServiceTime = [];\n        var avgCalledTime = [];\n        this.m_analytics.forEach((i_model: FasterqAnalyticsModel) => {\n            var entered = i_model.entered;\n            var serviced = i_model.serviced;\n            var called = i_model.called;\n            if (_.isNull(called)) {\n                // customer not called, do nothing\n            } else if (!_.isNull(serviced)) {\n                // customer called & serviced\n                var xEntered = new XDate(entered);\n                var minFromEnteredToCalled = xEntered.diffMinutes(called);\n                if (minFromEnteredToCalled < 0)\n                    minFromEnteredToCalled = 1;\n                avgCalledTime.push(minFromEnteredToCalled);\n\n                var xCalled = new XDate(called);\n                var minFromCalledToServiced = xCalled.diffMinutes(serviced);\n                avgServiceTime.push(minFromCalledToServiced);\n\n            } else {\n\n                // customer called not serviced\n                var xEntered = new XDate(entered);\n                var minFromEnteredToCalled = xEntered.diffMinutes(called);\n                if (minFromEnteredToCalled < 0)\n                    minFromEnteredToCalled = 1;\n                avgCalledTime.push(minFromEnteredToCalled);\n            }\n        });\n\n        this.m_avgServiceTimeCalc = _.reduce(avgServiceTime, function (memo, num) {\n                return memo + num;\n            }, 0) / (avgServiceTime.length === 0 ? 1 : avgServiceTime.length);\n        this.m_avgServiceTimeCalc = Lib.ParseToFloatDouble(this.m_avgServiceTimeCalc);\n\n        this.m_avgCalledTimeCalc = _.reduce(avgCalledTime, function (memo, num) {\n                return memo + num;\n            }, 0) / (avgCalledTime.length === 0 ? 1 : avgCalledTime.length);\n        this.m_avgCalledTimeCalc = Lib.ParseToFloatDouble(this.m_avgCalledTimeCalc)\n    }\n\n    _onPrev() {\n        if (this._getQueueIndexByServiceId() == this.QUEUE_OFFSET)\n            return;\n        this._onQueueSelected(this.m_queues.get(this._getQueueIndexByServiceId() - 1));\n    }\n\n    _onNext() {\n        if (this._getQueueIndexByServiceId() + 1 == this.m_queues.size || this.m_queues.size <= this.QUEUE_OFFSET + 1)\n            return;\n        if (this._getQueueIndexByServiceId() == -1)\n            return this._onQueueSelected(this.m_queues.get(this.QUEUE_OFFSET));\n        this._onQueueSelected(this.m_queues.get(this._getQueueIndexByServiceId() + 1));\n    }\n\n    _onGoTo() {\n        var queue = this.m_queues.find((i_fasterqQueueModel: FasterqQueueModel) => {\n            var serviceId = i_fasterqQueueModel.serviceId;\n            var selectedId = Lib.PadZeros(this.m_gotoModel, 3, 0);\n            return serviceId == selectedId;\n        })\n        if (queue)\n            this._onQueueSelected(queue);\n    }\n\n    /**\n     Start the stop watch UI\n     @method _watchStart\n     **/\n    _watchStart() {\n        this.m_stopWatchHandle.setListener((e) => {\n            this.m_stopTimer = this.m_stopWatchHandle.toString();\n            this.cd.markForCheck();\n        });\n        this.m_stopWatchHandle.start();\n    }\n\n    /**\n     Stop the stop watch UI\n     @method _watchStop\n     **/\n    _watchStop() {\n        this.m_stopWatchHandle.stop();\n        this.m_stopWatchHandle.reset();\n        this.m_stopTimer = '00:00:00';\n    }\n\n    destroy() {\n        clearInterval(this.m_liveUpdateHandler);\n        var uiState: IUiState = {\n            uiSideProps: SideProps.miniDashboard,\n            fasterq: {\n                fasterqQueueSelected: -1\n            }\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n}\n"
  },
  {
    "path": "src/app/fasterq/fasterq-line-props.ts",
    "content": "import {Component, ChangeDetectionStrategy, AfterViewInit} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {FasterqLineModel} from \"../../models/fasterq-line-model\";\nimport {FormBuilder, FormGroup} from \"@angular/forms\";\nimport {SideProps} from \"../../store/actions/appdb.actions\";\nimport {Observable} from \"rxjs/Observable\";\nimport {EFFECT_RESET_FASTERQ_LINE, EFFECT_UPDATE_FASTERQ_LINE} from \"../../store/effects/appdb.effects\";\nimport * as _ from 'lodash';\nimport {FasterqQueueModel} from \"../../models/fasterq-queue-model\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Lib} from \"../../Lib\";\n\n@Component({\n    selector: 'fasterq-line-props',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    styles: [`\n        input.ng-invalid {\n            border-right: 10px solid red;\n        }\n\n        .material-switch {\n            position: relative;\n            padding-top: 10px;\n        }\n\n        .input-group {\n            padding-top: 10px;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div [ngSwitch]=\"m_sideProps$ | async\">\n            <div *ngSwitchCase=\"m_sidePropsEnum.fasterqLineProps\">\n                <form novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n                    <div class=\"row\">\n                        <div class=\"inner userGeneral\">\n                            <ul class=\"list-group\">\n                                <!--<li class=\"list-group-item\">-->\n                                <!--<span i18n>line name: </span>-->\n                                <!--{{m_selectedLine?.lineName}}-->\n                                <!--</li>-->\n                                <li class=\"list-group-item\">\n                                    <span i18n>selected line</span>\n                                    <div class=\"input-group\">\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-paper-plane\"></i></span>\n                                        <input formControlName=\"line_name\" required\n                                               type=\"text\" class=\"form-control\" maxlength=\"50\"\n                                               placeholder=\"line name\">\n                                    </div>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <span i18n>reminder ahead of people</span>\n                                    <div class=\"input-group\">\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-lightbulb-o\"></i></span>\n                                        <input max=\"100\" min=\"1\" formControlName=\"reminder\" required\n                                               type=\"number\" class=\"form-control\"\n                                               placeholder=\"send reminder\">\n                                    </div>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <button (click)=\"_onOpenTerminal()\" class=\"btn btn-primary inliner\" i18n>open terminal</button>\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <button (click)=\"_onResetLine()\" class=\"btn btn-primary inliner\" i18n>reset line</button>\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </form>\n            </div>\n            <div *ngSwitchCase=\"m_sidePropsEnum.miniDashboard\">\n                <dash-panel-mini></dash-panel-mini>\n            </div>\n            <div *ngSwitchCase=\"m_sidePropsEnum.fasterqQueueProps\">\n                <div class=\"inner\">\n                    <h4 i18n>Queue properties</h4>\n                    <ul class=\"list-group\">\n                        <li class=\"list-group-item\">\n                            <span i18n>selected customer: </span><span> {{m_customer}}</span>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <span i18n>verification: </span><span> {{m_verification}}</span>\n                        </li>\n                        <li class=\"list-group-item\">\n                            <span i18n>called by: </span><span> {{m_calledBy}}</span>\n                        </li>\n                    </ul>\n                </div>\n            </div>\n        </div>\n    `,\n})\nexport class FasterqLineProps extends Compbaser implements AfterViewInit {\n\n    m_selectedLine: FasterqLineModel;\n    m_selectedQueue: FasterqQueueModel;\n    m_contGroup: FormGroup;\n    m_sideProps$: Observable<SideProps>;\n    m_sidePropsEnum = SideProps;\n    m_customer = '';\n    m_verification = '';\n    m_calledBy: ''\n    appBaseUrlServices\n\n    constructor(private fb: FormBuilder, private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.m_sideProps$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n        this.m_contGroup = fb.group({\n            'line_name': [''],\n            'reminder': [0]\n        });\n\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.appBaseUrlServices)\n                .subscribe((i_appBaseUrlServices) => {\n                    this.appBaseUrlServices = i_appBaseUrlServices;\n                })\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqLineSelected()\n                .subscribe((i_lineSelected: FasterqLineModel) => {\n                    this.m_selectedLine = i_lineSelected;\n                    this.m_contGroup.controls.line_name.setValue(this.m_selectedLine.lineName)\n                    this.m_contGroup.controls.reminder.setValue(this.m_selectedLine.reminder)\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.listenFasterqQueueModelSelected()\n                .subscribe((i_queueSelected: FasterqQueueModel) => {\n                    this.m_selectedQueue = i_queueSelected;\n                    this.m_customer = this.m_selectedQueue.serviceId;\n                    this.m_verification = this.m_selectedQueue.verification == -1 ? 'print out' : this.m_selectedQueue.verification;\n                    this.m_calledBy = (_.isNull(this.m_selectedQueue.calledBy) ? 'none' : this.m_selectedQueue.calledBy);\n                }, (e) => console.error(e))\n        )\n    }\n\n    saveToStore() {\n        this.yp.ngrxStore.dispatch({\n            type: EFFECT_UPDATE_FASTERQ_LINE,\n            payload: {\n                id: this.m_selectedLine.lineId,\n                name: this.m_contGroup.controls.line_name.value,\n                reminder: _.isNumber(this.m_contGroup.controls.reminder.value) ? this.m_contGroup.controls.reminder.value : 1\n            }\n        })\n    }\n\n    _onResetLine() {\n        bootbox.prompt('are you sure you want to reset the counter? (enter YES)', (i_password) => {\n            if (i_password != 'YES') return;\n            this.yp.ngrxStore.dispatch({\n                type: EFFECT_RESET_FASTERQ_LINE,\n                payload: {\n                    business_id: this.rp.getUserData().businessID,\n                    line_id: this.m_selectedLine.lineId,\n                    counter: 1\n                }\n            });\n        });\n    }\n\n    /**\n     Listen to open customer terminal\n     @method _listenOpenCustomerTerminal\n     **/\n    _onOpenTerminal() {\n        var data = {\n            call_type: 'CUSTOMER_TERMINAL',\n            business_id: this.rp.getUserData().businessID,\n            line_id: this.m_selectedLine.lineId,\n            line_name: this.m_selectedLine.lineName\n        };\n        var rc4v2 = new RC4V2();\n        var rcData: any = rc4v2.encrypt(JSON.stringify(data), '8547963624824263');\n        var url;\n        if (Lib.DevMode()) {\n            url = `http://localhost:4208/index.html?data=${rcData}`;\n        } else {\n            url = `${this.appBaseUrlServices}/studioweb/index.html?data=${rcData}`;\n        }\n\n        window.open(url, '_blank');\n    }\n\n    ngAfterViewInit() {\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/fasterq/fasterq-manager.ts",
    "content": "import {Component, EventEmitter, Output} from \"@angular/core\";\nimport {Observable} from \"rxjs\";\nimport {Compbaser} from \"ng-mslib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ACTION_LIVELOG_UPDATE, ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {EFFECT_ADD_FASTERQ_LINE, EFFECT_LOAD_FASTERQ_ANALYTICS, EFFECT_LOAD_FASTERQ_LINES, EFFECT_LOAD_FASTERQ_QUEUES, EFFECT_REMOVE_FASTERQ_LINE} from \"../../store/effects/appdb.effects\";\nimport {FasterqLineModel} from \"../../models/fasterq-line-model\";\nimport {List} from \"immutable\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\n\n@Component({\n    selector: 'fasterq-manager',\n    template: `\n        <small class=\"debug\" style=\"padding-left: 30px\">{{me}}</small>\n        <div style=\"padding-bottom: 10px\">\n            <span i18n style=\"font-size: 1.8em;\" i18n>scene selection</span>\n        </div>\n        <div>\n            <div class=\"btn-group\">\n                <button (click)=\"_createNew()\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-rocket\"></i>\n                    <span i18n>new line</span>\n                </button>\n                <button (click)=\"_remove()\" [disabled]=\"!m_selectedLine\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-trash-o\"></i>\n                    <span i18n>remove line</span>\n                </button>\n            </div>\n        </div>\n        <!-- move scroller to proper offset -->\n        <div class=\"responsive-pad-right\">\n            <div matchBodyHeight=\"350\" style=\"overflow: scroll\">\n                <ul (click)=\"$event.preventDefault()\" class=\"appList list-group\">\n                    <a *ngFor=\"let line of lines$ | async; let i = index\" (click)=\"_onLineSelected($event, line, i)\"\n                       [ngClass]=\"{'selectedItem': selectedIdx == i}\" href=\"#\" class=\"list-group-item\">\n                        <div class=\"peopleInGroup\">\n                            <i class=\"peopleInLine fa fa-male\"></i>\n                            <i class=\"peopleInLine fa fa-male\"></i>\n                            <i class=\"peopleInLine fa fa-male\"></i>\n                            <i class=\"peopleInLine fa fa-male\"></i>\n                        </div>\n                        <h4 style=\"display: inline-block; position: relative; left: -85px\">{{line.lineName}} (id: {{line.lineId}}) </h4>\n                        <p class=\"list-group-item-text\">Reminder ahead of people: {{line.reminder}} </p>\n                        <div class=\"openProps\">\n                            <button type=\"button\" class=\"props btn btn-default btn-sm\"><i style=\"font-size: 1.5em\" class=\"props fa fa-gear\"></i></button>\n                        </div>\n                    </a>\n                </ul>\n            </div>\n        </div>\n    `\n})\nexport class FasterqManager extends Compbaser {\n\n    selectedIdx = -1;\n    m_selectedLine: FasterqLineModel;\n    lines$: Observable<List<FasterqLineModel>>\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private toastr: ToastsManager) {\n        super();\n        this.preventRedirect(true);\n        this.yp.ngrxStore.dispatch({type: EFFECT_LOAD_FASTERQ_LINES, payload: {}})\n        this.lines$ = this.yp.listenFasterqLines();\n        var uiState: IUiState = {fasterq: {fasterqLineSelected: -1}};\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    @Output()\n    slideToFasterqEditor: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onLineSelected: EventEmitter<any> = new EventEmitter<any>();\n\n    _onLineSelected(event: MouseEvent, i_fasterqLineModel: FasterqLineModel, index) {\n        // event.stopPropagation();\n        // event.preventDefault();\n        this.selectedIdx = index;\n        let uiState: IUiState;\n        if (jQuery(event.target).hasClass('props')) {\n            uiState = {\n                uiSideProps: SideProps.fasterqLineProps,\n                fasterq: {\n                    fasterqLineSelected: i_fasterqLineModel.lineId\n                }\n            }\n            this.onLineSelected.emit(uiState)\n        } else {\n            uiState = {\n                fasterq: {\n                    fasterqLineSelected: i_fasterqLineModel.lineId\n                }\n            }\n            this.slideToFasterqEditor.emit();\n            // this.onCampaignSelected.emit(uiState)\n        }\n        this.m_selectedLine = i_fasterqLineModel;\n        this.yp.ngrxStore.dispatch(({type: EFFECT_LOAD_FASTERQ_QUEUES, payload: {line_id: i_fasterqLineModel.lineId}}))\n        this.yp.ngrxStore.dispatch(({type: EFFECT_LOAD_FASTERQ_ANALYTICS, payload: {line_id: i_fasterqLineModel.lineId}}))\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _createNew() {\n        this.yp.ngrxStore.dispatch({\n            type: EFFECT_ADD_FASTERQ_LINE,\n            payload: {name: 'new line', business_id: this.rp.getUserData().businessID}\n        })\n        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'created new fasterq line'})}));\n    }\n\n    _remove() {\n        bootbox.confirm(\"Are you sure you want to remove the Line and associated queues?\", (result) => {\n            if (!result)\n                return;\n            this.yp.ngrxStore.dispatch({\n                type: EFFECT_REMOVE_FASTERQ_LINE,\n                payload: {id: this.m_selectedLine.lineId}\n            })\n            var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n            this.m_selectedLine = null;\n            this.selectedIdx = -1;\n            this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'removed fasterq line id: ' + this.m_selectedLine.lineId})}));\n        });\n    }\n\n    destroy() {\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n}\n"
  },
  {
    "path": "src/app/fasterq/fasterq-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    providers: [],\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <small class=\"debug\">scene-navigation</small>\n        <panel-split-container>\n            <panel-split-main>\n                <fasterq></fasterq>\n            </panel-split-main>\n            <panel-split-side>\n                <fasterq-line-props></fasterq-line-props>\n            </panel-split-side>\n        </panel-split-container>\n    `\n})\n\nexport class FasterqNavigation extends Compbaser {\n}\n\n"
  },
  {
    "path": "src/app/fasterq/fasterq-terminal.ts",
    "content": "import {AfterViewInit, Component, ElementRef, NgZone} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {ActivatedRoute} from \"@angular/router\";\nimport {FasterqLineModel} from \"../../models/fasterq-line-model\";\nimport {EFFECT_LOAD_FASTERQ_LINE, EFFECT_LOADED_FASTERQ_LINE, EFFECT_QUEUE_CALL_SAVE} from \"../../store/effects/appdb.effects\";\nimport * as _ from 'lodash';\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Http, RequestMethod, RequestOptionsArgs, Response} from \"@angular/http\";\nimport {Lib} from \"../../Lib\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {LocalStorage} from \"../../services/LocalStorage\";\n\n@Component({\n    selector: 'fasterq-terminal',\n    styles: [`\n        .largeFont2em {\n            font-size: 2em;\n        }\n\n        .lPad {\n            padding-left: 20px;\n        }\n\n        .carousel-inner {\n            height: 400px;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n\n        <div *ngIf=\"m_appMode=='REMOTE_STATUS'\" id=\"fqRemoteStatus\" style=\"font-size: 2em; text-align: center\">\n            <h1>now serving {{m_currentlyServing}}</h1>\n\n            <h3>you are {{m_fasterqLineModel.serviceId}} in line</h3>\n\n            <h3>line name: {{m_fasterqLineModel?.lineName}}</h3>\n\n            <h3>your verification number is {{m_fasterqLineModel?.verification}}</h3>\n\n            <button (click)=\"_releaseSpot()\" id=\"fqReleaseSpot\" style=\"float: right; width: 50%\" class=\"tn btn-lg btn-primary\">release number</button>\n            <button (click)=\"_getNewSpot()\" id=\"fqGetNewNumber\" style=\"float: right; width: 50%;\" class=\"tn btn-lg btn-primary\">renew number</button>\n        </div>\n\n        <div *ngIf=\"m_appMode=='CUSTOMER_TERMINAL'\" id=\"fasterqCustomerTerminal\">\n            <div style=\"width: 100%\">\n                <h1 id=\"fqTakeNumberLineName\" style=\"font-size: 10em; text-align: center\" class=\"centerElement\">{{m_fasterqLineModel?.lineName}}</h1>\n            </div>\n\n            <hr/>\n            <h1 id=\"fasterQLineName\"></h1>\n            <hr/>\n\n            <div id=\"printDiag\" style=\"display: none\">\n                <h1>You number is 123</h1>\n                <h3 id=\"printData\">Oct 1 1973</h3>\n            </div>\n\n            <div id=\"terminalCarousel\" class=\"carousel slide\" data-interval=\"false\" data-ride=\"carousel\">\n                <div class=\"carousel-inner\">\n                    <!--<div id=\"hiddenPrint\" *ngIf=\"m_printing\" >-->\n                        <!--<h2>{{m_serviceId}}</h2>-->\n                        <!--<h2>{{m_lineName}}</h2>-->\n                    <!--</div>-->\n                    <div class=\"item active\">\n                        <div style=\"width: 100%; text-align: center\">\n                            <i style=\"font-size: 3em; padding-right: 40px\" class=\"carouselLargeHeader fa fa-print\"></i>\n                            <span class=\"carouselLargeHeader\" style=\"font-size: 3em\">Print your queue number</span>\n                            <br/>\n                            <br/>\n                            <br/>\n                            \n                            <a (click)=\"_onPrint($event)\" id=\"fqPrintNumber\" style=\"padding-left: 40px; padding-right: 40px; padding-top: 20px; padding-bottom: 20px\" class=\"btn btn-large btn-danger\" type=\"button\" href=\"#\">\n                                <span class=\"largeFont2em\" data-localize=\"printIt\">PRINT IT</span>\n                            </a>\n                            <div id=\"printArea\" *ngIf=\"m_printing\">\n                                <h2 id=\"fqDisplayPrintNumber\">Your line#: {{m_displayServiceId}}</h2>\n                                <h2>Line name: {{m_lineName}}</h2>\n                            </div>\n                            <br/>\n                            <br/>\n                            <br/>\n                        </div>\n                    </div>\n\n                    <div class=\"item\">\n                        <div style=\"width: 100%; text-align: center\">\n                            <i style=\"font-size: 3em; padding-right: 40px\" class=\"carouselLargeHeader fa fa-qrcode\"></i>\n                            <span class=\"carouselLargeHeader\" data-localize=\"scanMobile\" style=\"font-size: 3em\">Scan with your mobile device</span>\n                            <br/>\n\n                            <div class=\"centerElement\" id=\"qrcode\" style=\"text-align: center; width: 200px; height: 200px; margin-top:15px;\"></div>\n                            <br/>\n                            <br/>\n                            <br/>\n                        </div>\n                    </div>\n\n                    <div class=\"item\">\n                        <div style=\"width: 100%; text-align: center\">\n                            <i style=\"font-size: 3em; padding-right: 40px\" class=\"carouselLargeHeader fa fa-paper-plane\"></i>\n                            <span class=\"carouselLargeHeader\" data-localize=\"notifyEmail\" style=\"font-size: 3em\">Notify via email</span>\n                            <br/>\n                            <br/>\n\n                            <div style=\"text-align: center; width: 500px\" class=\"centerElement\">\n                                <input [(ngModel)]=\"emailAddress\" id=\"fqEnterEmail\" type=\"text\" style=\"font-size: 3em; height: 2em; text-align: center\" class=\"form-control\" data-localize=\"enterEmail\" placeholder=\"enter email\">\n                            </div>\n                            <br/>\n                            <a (click)=\"_onSend($event)\" id=\"fqSenditButton\" style=\"padding-left: 40px; padding-right: 40px; padding-top: 20px; padding-bottom: 20px\" class=\"btn btn-large btn-danger\" type=\"button\" href=\"#\">\n                                <span class=\"largeFont2em\">SEND IT</span>\n                            </a>\n                            <br/>\n\n                            <h1 id=\"fqDisplayEmailSent\"></h1>\n                            <br/>\n                        </div>\n                    </div>\n\n                    <div class=\"item\">\n                        <div style=\"width: 100%; text-align: center\">\n                            <i style=\"font-size: 3em; padding-right: 40px\" class=\"carouselLargeHeader fa fa-phone\"></i>\n                            <span class=\"carouselLargeHeader\" style=\"font-size: 3em\">Notify via Text Message</span>\n                            <br/>\n                            <br/>\n\n                            <div style=\"text-align: center; width: 500px\" class=\"centerElement\">\n                                <input [(ngModel)]=\"sms\" id=\"fqEnterSMS\" type=\"text\" style=\"font-size: 3em; height: 2em; text-align: center\" class=\"form-control\" data-localize=\"enterSMS\" placeholder=\"enter your phone number\">\n                            </div>\n                            <br/>\n                            <br/>\n                            <a (click)=\"_onCall($event)\" id=\"fqCallIt\" style=\"padding-left: 40px; padding-right: 40px; padding-top: 20px; padding-bottom: 20px\" class=\"btn btn-large btn-danger\" type=\"button\" href=\"#\">\n                                <span class=\"largeFont2em\" data-localize=\"printIt\">CALL IT</span>\n\n                            </a>\n\n                            <h1 id=\"fqDisplaySMSSent\"></h1>\n                            <br/>\n                        </div>\n                    </div>\n                </div>\n                <ul id=\"carouselItems\" class=\"nav nav-pills nav-justified\" style=\"border: 1px solid #9c9c9c\">\n                    <li data-target=\"#terminalCarousel\" data-slide-to=\"0\">\n                        <a href=\"#\"><i class=\"largeFont2em fa fa-print\"></i><span class=\"lPad largeFont2em fasterQCarouselButtons\">PRINT</span>\n                        </a>\n                    </li>\n                    <li data-target=\"#terminalCarousel\" data-slide-to=\"1\">\n                        <a href=\"#\"><i class=\"largeFont2em fa fa-qrcode\"></i><span class=\"lPad largeFont2em fasterQCarouselButtons\">SCAN</span>\n                        </a>\n                    </li>\n                    <li data-target=\"#terminalCarousel\" data-slide-to=\"2\">\n                        <a href=\"#\"><i class=\"largeFont2em fa fa-paper-plane\"></i><span class=\"lPad largeFont2em fasterQCarouselButtons\">E-MAIL</span>\n                        </a>\n                    </li>\n                    <li data-target=\"#terminalCarousel\" data-slide-to=\"3\">\n                        <a href=\"#\"><i class=\"largeFont2em fa fa-phone\"></i><span class=\"lPad largeFont2em fasterQCarouselButtons\">Text Message</span>\n                        </a>\n                    </li>\n                </ul>\n            </div>\n        </div>\n    `\n})\nexport class FasterqTerminal extends Compbaser implements AfterViewInit {\n\n    m_fasterqLineModel: FasterqLineModel;\n    m_displayServiceId = '';\n    appBaseUrlServices;\n    emailAddress = ''\n    m_appMode = '';\n    m_baseUrl\n    sms = ''\n    m_remoteStatusServiceId;\n    m_remoteStatusVerification;\n    m_statusHandler;\n    m_currentlyServing = 0;\n    m_printing = false;\n    m_serviceId = 0;\n    m_lineName = '';\n\n    constructor(private toastr: ToastsManager, private http: Http, private yp: YellowPepperService, private router: ActivatedRoute, private el: ElementRef, private zone: NgZone, private simplestorage: LocalStorage) {\n        super();\n        // this.preventRedirect(true);\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.fasterq.terminal)\n                .filter(v => !_.isNull(v))\n                .subscribe((i_fasterqLineModel: FasterqLineModel) => {\n                    this.m_fasterqLineModel = i_fasterqLineModel;\n                    switch (this.m_appMode) {\n                        case 'CUSTOMER_TERMINAL': {\n                            this._createQRcode();\n                            break;\n                        }\n                        case 'REMOTE_STATUS': {\n                            this.m_baseUrl = `${this.appBaseUrlServices}?mode=remoteStatus&param=`;\n                            this._getServerDateTime(this._initServices);\n                            // this._releaseSpot();\n                            // this._getNewSpot();\n                            break;\n                        }\n                        default: {\n                            console.log('fasterq problem, did not get line id');\n                        }\n                    }\n\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.appBaseUrlServices)\n                .subscribe((i_appBaseUrlServices) => {\n                    this.appBaseUrlServices = i_appBaseUrlServices;\n                })\n        )\n    }\n\n    ngOnInit() {\n        this.cancelOnDestroy(\n            this.router.params\n                .take(1)\n                .subscribe(i_params => {\n                    if (i_params.id.indexOf('data') > -1) {\n                        /** Terminal mode, coming from Studio link **/\n                        var params = i_params['id'].split('=')[1] + '==';\n                        var rc4v2 = new RC4V2();\n                        var rcData: any = rc4v2.decrypt(params.replace(/=/ig, ''), '8547963624824263');\n                        var data = JSON.parse(rcData);\n                        this.m_appMode = 'CUSTOMER_TERMINAL';\n                        this.yp.ngrxStore.dispatch({type: EFFECT_LOAD_FASTERQ_LINE, payload: {lineId: data.line_id, businessId: data.business_id}})\n                    } else {\n                        /** Remote status mode, coming server short url **/\n                        var params: string = i_params['id'].split('=')[2].replace(/%3D/ig, '=');\n                        var rcData = $.base64.decode(params);\n                        var data = JSON.parse(rcData);\n                        this.m_appMode = 'REMOTE_STATUS';\n                        this.yp.ngrxStore.dispatch({type: EFFECT_LOADED_FASTERQ_LINE, payload: new FasterqLineModel(data)})\n\n                    }\n                }, (e) => console.error(e))\n        )\n    }\n\n    ngAfterViewInit() {\n    }\n\n    /**\n     Get current server date / time\n     @method _getServerDateTime server:getDateTime\n     @param {Function} i_cb\n     **/\n    _getServerDateTime(i_cb) {\n        var self = this;\n        $.ajax({\n            url: `${self.appBaseUrlServices}/GetDateTime`,\n            success: function (dateTime) {\n                $.proxy(i_cb, self)(dateTime);\n            },\n            error: function (e) {\n                console.log('error ajax ' + e);\n            },\n            dataType: 'json'\n        });\n    }\n\n    /**\n     Check if service id exists in local storage, if not get one from server\n     @method _initServices\n     **/\n    _initServices(i_dateTime) {\n        // STORAGE FIRST\n\n        //debug; //this.simplestorage.removeItem('data');\n        var storage = this.simplestorage.getItem('data');\n        if (!_.isUndefined(storage)) {\n            var storedDate = storage.date;\n            if (storedDate != i_dateTime.date) {\n                this.simplestorage.removeItem('data');\n            } else {\n                this.m_remoteStatusServiceId = storage.service_id;\n                this.m_remoteStatusVerification = storage.verification;\n                this._pollNowServicing();\n                return;\n            }\n        }\n\n        // EMAIL OR SMS\n        var call_type = this.m_fasterqLineModel.callType;\n\n        if (call_type == 'SMS' || call_type == 'EMAIL') {\n            if (i_dateTime.date != this.m_fasterqLineModel.date) {\n                bootbox.alert('your number expired on ' + this.m_fasterqLineModel.date + ', so we generated a new number for you...');\n                this._getServiceID();\n                return;\n            }\n            this._createStorage(this.m_fasterqLineModel.serviceId, this.m_fasterqLineModel.verification, this.m_fasterqLineModel.date);\n            this._pollNowServicing();\n        }\n\n        // QR\n        if (call_type == 'QR') {\n            this._getServiceID();\n        }\n    }\n\n    _createStorage(i_service_id, i_verification, i_date) {\n        this.simplestorage.setItem('data', {\n            service_id: i_service_id,\n            date: i_date,\n            verification: i_verification\n        });\n    }\n\n    /**\n     Forget spot in line\n     @method _getNewSpot\n     **/\n    _getNewSpot() {\n        bootbox.prompt('are you sure you want to get a new number (type yes or no)?', (i_answer) => {\n            if (i_answer) {\n                if (i_answer.toLowerCase() == 'yes') {\n                    this.simplestorage.removeItem('data');\n                    window.clearInterval(this.m_statusHandler);\n                    var url = this._buildURL();\n                    jQuery(location).attr('href', url);\n                }\n            }\n        })\n    }\n\n    /**\n     Forget spot in line\n     @method _releaseSpot\n     **/\n    _releaseSpot() {\n        bootbox.prompt('are you sure you want to let go of your spot (type yes or no)?', (i_answer) => {\n            if (i_answer) {\n                if (i_answer.toLowerCase() == 'yes') {\n                    jQuery('#appEntry').html('<h1 style=\"text-align: center; padding: 100px\">have a nice day</h1>');\n                    this.simplestorage.removeItem('data');\n                    window.clearInterval(this.m_statusHandler);\n                }\n            }\n        })\n    }\n\n    /**\n     Create queue in table as well as matching data in analytics\n     @method _getServiceID server:setQueue\n     **/\n    _getServiceID() {\n        var options: RequestOptionsArgs = this.createOptionArgs('/Queue', RequestMethod.Post, {\n            line_id: this.m_fasterqLineModel.lineId,\n            business_id: this.m_fasterqLineModel.businessId,\n            email: this.m_fasterqLineModel.email,\n            call_type: this.m_fasterqLineModel.callType,\n        })\n        return this.http.get(options.url, options)\n            .catch((err) => {\n                // return Observable.throw(err);\n                return err;\n            })\n            .finally(() => {\n            }).take(1)\n            .subscribe((i_response: Response) => {\n                var jData = i_response.json()\n                var fasterqLineModel: FasterqLineModel = new FasterqLineModel(jData)\n                this._createStorage(fasterqLineModel.serviceId, fasterqLineModel.verification, fasterqLineModel.date);\n                this.yp.ngrxStore.dispatch({type: EFFECT_LOADED_FASTERQ_LINE, payload: fasterqLineModel})\n                // this._populateCustomerInfo();\n                this._pollNowServicing();\n            }, (e) => console.error(e));\n    }\n\n    /**\n     Get the last called service_id for line\n     @method _pollNowServicing server:LastCalledQueue\n     **/\n    _pollNowServicing() {\n        var self = this;\n        var lastCalledQueue = () => {\n            $.ajax({\n                url: `${this.appBaseUrlServices}/LastCalledQueue`,\n                data: {\n                    business_id: this.m_fasterqLineModel.businessId,\n                    line_id: this.m_fasterqLineModel.lineId\n                },\n                success: function (i_model) {\n                    self.m_currentlyServing = i_model.service_id;\n\n                },\n                error: function (e) {\n                    console.log('error ajax ' + e);\n                },\n                dataType: 'json'\n            });\n        };\n        this.m_statusHandler = setInterval(function () {\n            lastCalledQueue();\n        }, 5000);\n        lastCalledQueue();\n    }\n\n    _isValidEmail(email) {\n        var re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n        return re.test(email);\n    }\n\n    /**\n     Listen to custom selection on queue id creator via QR scan\n     @method _createQRcode\n     **/\n    @timeout(1000)\n    _createQRcode() {\n        jQuery('.carousel').carousel()\n        var q: any = jQuery(\"#qrcode\", this.el.nativeElement);\n        q = q[0];\n        var qrcode = new QRCode(q, {width: 200, height: 200});\n        var url = this._buildURL();\n        qrcode.makeCode(url);\n    }\n\n    _onCall($event) {\n        event.stopImmediatePropagation();\n        event.preventDefault();\n        const baseUrl = `${this.appBaseUrlServices}/studioweb/index.html?mode=remoteStatus&param=`;\n        if (this.sms.length < 6)\n            return this.toastr.error('The phone number entered is invalid');\n        $.ajax({\n            url: `${this.appBaseUrlServices}/SendQueueSMSEmail`,\n            data: {\n                business_id: this.m_fasterqLineModel.businessId,\n                line_id: this.m_fasterqLineModel.lineId,\n                line_name: this.m_fasterqLineModel.lineName,\n                sms: this.sms,\n                call_type: 'SMS',\n                url: baseUrl\n            },\n            success: (e) => {\n                this.toastr.info('Thank you')\n                setTimeout(() => {\n                    this.sms = ''\n                }, 4000)\n            },\n            error: (e) => {\n                console.log('error ajax ' + e);\n            },\n            dataType: 'json'\n        });\n    }\n\n    _onSend($event) {\n        event.stopImmediatePropagation();\n        event.preventDefault();\n        const baseUrl = `${this.appBaseUrlServices}/studioweb/index.html?mode=remoteStatus&param=`;\n        if (!this._isValidEmail(this.emailAddress))\n            return this.toastr.error('The email address entered is invalid');\n        $.ajax({\n            url: `${this.appBaseUrlServices}/SendQueueSMSEmail`,\n            data: {\n                business_id: this.m_fasterqLineModel.businessId,\n                line_id: this.m_fasterqLineModel.lineId,\n                line_name: this.m_fasterqLineModel.lineName,\n                email: this.emailAddress,\n                call_type: 'EMAIL',\n                url: baseUrl\n            },\n            success: (e) => {\n                this.toastr.info('Thank you')\n                setTimeout(() => {\n                    this.emailAddress = ''\n                }, 4000)\n            },\n            error: (e) => {\n                console.log('error ajax ' + e);\n            },\n            dataType: 'json'\n        });\n\n    }\n\n    _onPrint(event) {\n        event.stopImmediatePropagation();\n        event.preventDefault();\n\n        // this.printToCart('printSectionId');\n        // urlRoot: BB.CONSTS.ROOT_URL + '/',\n        //     idAttribute: 'queue_id'\n        // var url = `${this.appBaseUrlServices}/`;\n\n        var options: RequestOptionsArgs = this.createOptionArgs('/Queue', RequestMethod.Post, {line_id: this.m_fasterqLineModel.lineId, business_id: this.m_fasterqLineModel.businessId})\n        return this.http.get(options.url, options)\n            .catch((err) => {\n                // return Observable.throw(err);\n                return err;\n            })\n            .finally(() => {\n            }).take(1)\n            .subscribe((i_response: Response) => {\n                var jData = i_response.json()\n                this.m_displayServiceId = jData.service_id;\n                this.m_serviceId = jData.service_id;\n                this.m_lineName = jData.name;\n                this.m_printing = true;\n                setTimeout(()=>{\n                    printJS('printArea', 'html')\n                },1000);\n                setTimeout(()=>{\n                    this.m_printing = false;\n                },2000)\n\n                return;\n\n                // this._printNumber(jData.service_id, jData.name);\n            }, (e) => console.error(e));\n    }\n\n\n    /**\n     Print current customer service id\n     @method _printNumber\n     @param {Number} i_service_id\n     **/\n    _printNumber(i_service_id, name) {\n        this.zone.runOutsideAngular(() => {\n            var $printDiag = jQuery('#printDiag');\n            //var div = document.getElementById(\"printerDiv\");\n            var p = function () {\n                jQuery('body').append('<h2></h2>')\n            }\n            var arg = Lib.Base64Encode(i_service_id + ':_:' + name)\n            // $printDiag.html('<iframe src=\"print.html?serviceId=' + arg + '\" onload=\"this.contentWindow.print();\"></iframe>');\n            $printDiag.html('<iframe src=\"print.html?serviceId=' + arg + '\"></iframe>');\n        })\n\n        // $printDiag.find('h1').text('your number is ' + i_service_id);\n        // $printDiag.find('h3').text('created on ' + moment().format('MMMM Do YYYY, h:mm:ss a'));\n        // var divContents = jQuery(Elements.PRINT_DIAG).html();\n        // var printWindow = window.open('', '', 'height=250,width=450');\n        // printWindow.document.write('<html><head><title>' + self.model.get('name') + '</title>');\n        // printWindow.document.write('</head><body><center>');\n        // printWindow.document.write(divContents);\n        // printWindow.document.write('</center></body></html>');\n        // printWindow.document.close();\n        // printWindow.print();\n    }\n\n    private createOptionArgs(i_urlEndPoint, i_method, i_body): RequestOptionsArgs {\n        var url = `${this.appBaseUrlServices}${i_urlEndPoint}`;\n        return {\n            url: url,\n            method: i_method,\n            body: i_body\n        };\n    }\n\n    /**\n     Create URL string to load customer terminal UI for FasterQ queue generation\n     @method _buildURL\n     @return {String} URL\n     **/\n    _buildURL() {\n        var data = {\n            line_id: this.m_fasterqLineModel.lineId,\n            business_id: this.m_fasterqLineModel.businessId,\n            call_type: 'QR'\n        };\n        data = $.base64.encode(JSON.stringify(data));\n        return `${this.appBaseUrlServices}/studioweb/index.html?mode=remoteStatus&param=${data}`;\n    }\n\n\n}\n"
  },
  {
    "path": "src/app/fasterq/fasterq.ts",
    "content": "import {ChangeDetectionStrategy, Component, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {ISliderItemData, Slideritem} from \"../../comps/sliderpanel/Slideritem\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'fasterq',\n    template: `\n        <small class=\"debug\" style=\"padding-right: 25px\">{{me}}</small>\n        <Sliderpanel>\n            <Slideritem [templateRef]=\"a\" #sliderFqLineManager class=\"page center fqList selected\" [showToButton]=\"false\" [toDirection]=\"'right'\" [to]=\"'fqEditor'\">\n                <ng-template #a>\n                    <fasterq-manager (slideToFasterqEditor)=\"sliderFqLineManager.slideTo('fqEditor','right')\"></fasterq-manager>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"b\" #sliderItemCampaignEditor (onChange)=\"_onSlideChange($event)\" [showFromButton]=\"true\" class=\"page left fqEditor\" [fromDirection]=\"'left'\" [from]=\"'fqList'\">\n                <ng-template #b>\n                    <fasterq-editor (onGoBack)=\"sliderItemCampaignEditor.slideTo('fqList','left')\"></fasterq-editor>\n                </ng-template>\n            </Slideritem>\n        </Sliderpanel>\n    `\n})\nexport class Fasterq extends Compbaser {\n\n    private m_placement = PLACEMENT_SCENE;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenLocationMapLoad()\n                .subscribe((v) => {\n                    if (v){\n                        this.sliderSceneCreator.slideTo('locationMap','right')\n                    }\n                }, (e) => console.error(e))\n\n        )\n\n    }\n\n    @ViewChild('sliderSceneCreator')\n    sliderSceneCreator:Slideritem;\n\n\n    _onLocationMapClosed(){\n        this.sliderSceneCreator.slideTo('fqEditor','left')\n\n    }\n\n    _onSlideChange(event: ISliderItemData) {\n        if (event.direction == 'left' && event.to == 'fqList') {\n            var uiState:IUiState = {\n                uiSideProps: SideProps.miniDashboard,\n                scene: {sceneSelected: -1}\n            }\n            return this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        }\n        // if (event.direction == 'right' && event.to == 'campaignEditor')\n        //     return this._createCampaign();\n    }\n}\n\n"
  },
  {
    "path": "src/app/fasterq/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {FasterqNavigation} from \"./fasterq-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {Fasterq} from \"./fasterq\";\nimport {FasterqManager} from \"./fasterq-manager\";\nimport {FasterqEditor} from \"./fasterq-editor\";\nimport {FasterqLineProps} from \"./fasterq-line-props\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: FasterqNavigation},\n    {path: ':folder/:id', component: FasterqNavigation},\n    {path: '**', component: FasterqNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [FasterqNavigation, Fasterq, FasterqManager, FasterqEditor, FasterqLineProps]\n})\nexport class FasterqLazyModule {\n}"
  },
  {
    "path": "src/app/help/help-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {MediaPlayer} from \"../../comps/media-player/media-player\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Observable} from \"rxjs/Observable\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        button {\n            padding: 8px;\n            margin: 8px;\n            width: 200px\n        }\n    `],\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <div id=\"helpPanel\">\n            <!-- video tutorials -->\n            <h3 data-localize=\"videoTutorial\">Video tutorial</h3>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/StudioLite.mp4')\">\n                <span data-localize=\"basicIntroductionVideo\">basic introduction</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/SceneComponentsLite.mp4')\">\n                <span data-localize=\"sceneAndComponents\">Scenes and components</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/StudioLiteAdv.mp4')\">\n                <span data-localize=\"advancedConfigurationVideo\">advanced configuration</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/LiteSeqVsSched.mp4')\">\n                <span data-localize=\"seqVsSchedVideo2\">sequencer vs scheduler</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/LiteCollection.mp4')\">\n                <span data-localize=\"collectionComponent\">collection component</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/LocationBased.mp4')\">\n                <span data-localize=\"locationBasedComponent\">location based component</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/LiteGoogleCalendar.mp4')\">\n                <span data-localize=\"googleCalendarComponent\">Google Calendar</span>\n            </button>\n            <button class=\"videos btn btn-primary btn-lg\" (click)=\"_onPlay('http://s3.signage.me/business1000/resources/FasterQv2.mp4')\">\n                <span>FasterQue line management</span>\n            </button>\n            <hr/>\n            <div>\n                <div class=\"reshid\">\n                    <h3 i18n> links</h3>\n                    <div *ngIf=\"isBrandingDisabled | async\">\n                        <li>\n                            <a class=\"helpLinks\" target=\"_blank\" href=\"http://lite.digitalsignage.com\" data-localize=\"studioLitePage\">StudioLite page</a>\n                        </li>\n                        <li>\n                            <a class=\"helpLinks\" target=\"_blank\" href=\"http://script.digitalsignage.com/forum/index.php\" data-localize=\"supportForum\">Support forum</a>\n                        </li>\n                        <li>\n                            <a class=\"helpLinks\" target=\"_blank\" href=\"http://git.digitalsignage.com\" data-localize=\"openSource\">StudioLite as open source (GitHub)</a>\n                        </li>\n                        <li>\n                            <a class=\"helpLinks\" target=\"_blank\" href=\"http://script.digitalsignage.com/cgi-bin/webinar.cgi\" data-localize=\"webinar\">Webinar</a>\n                        </li>\n                        <li>\n                            <a class=\"helpLinks\" target=\"_blank\" href=\"http://www.digitalsignage.com/_html/faqs.html\" data-localize=\"faq\">FAQs</a>\n                        </li>\n                        <li>\n                            <a class=\"helpLinks\" target=\"_blank\" href=\"http://www.digitalsignage.com/support/upload/index.php?/Knowledgebase/List\" data-localize=\"knowledgeBase\">Knowledge base</a>\n                        </li>\n                    </div>\n                    <li>\n                        <a class=\"helpLinks\" target=\"_blank\" href=\"http://www.signage.me/files/FQ_PrinterSetup.pdf\">Setting up FasterQ printer</a>\n                    </li>\n                </div>\n                <hr/>\n                <div *ngIf=\"isBrandingDisabled | async\" class=\"reshid\">\n                    <h3>Contact us</h3>\n                    <contact-us></contact-us>\n                </div>\n            </div>\n            <div class=\"clearFloat\"></div>\n            <hr/>\n            <div class=\"pull-left\">\n                <h5 i18n>Powered by Google's Angular framework</h5>\n                <a class=\"helpLinks\" target=\"_blank\" href=\"https://angular.io/\">\n                    <img src=\"./assets/angular.png\"/>\n                </a>\n            </div>\n\n        </div>\n        <modal (onDismiss)=\"_onClose()\" (onClose)=\"_onClose()\" [size]=\"'lg'\" #modal>\n            <modal-header [show-close]=\"true\">\n            </modal-header>\n            <modal-body>\n                <media-player *ngIf=\"m_playing\" [autoPlay]=\"true\" #mediaPlayer [playResource]=\"m_playResource\"></media-player>\n            </modal-body>\n            <modal-footer [show-default-buttons]=\"false\"></modal-footer>\n        </modal>\n    `\n})\nexport class HelpNavigation extends Compbaser {\n\n    m_playResource\n    m_playing = false;\n    isBrandingDisabled: Observable<boolean>;\n\n    @ViewChild('modal')\n    modal: ModalComponent;\n\n    @ViewChild('mediaPlayer')\n    media: MediaPlayer;\n\n    constructor(private yp: YellowPepperService) {\n        super();\n        this.isBrandingDisabled = this.yp.isBrandingDisabled()\n    }\n\n    _onClose() {\n        this.m_playing = false;\n    }\n\n    _onPlay(i_path) {\n        this.m_playResource = i_path;\n        this.modal.open('lg')\n        this.m_playing = true;\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/help/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {HelpNavigation} from \"./help-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {ContactUs} from \"../../comps/contact-us/contact-us\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: HelpNavigation},\n    {path: ':folder/:id', component: HelpNavigation},\n    {path: '**', component: HelpNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [HelpNavigation, ContactUs]\n})\nexport class HelpLazyModule {\n}"
  },
  {
    "path": "src/app/index.ts",
    "content": "export * from './app-component';\nexport * from './app-module';\n"
  },
  {
    "path": "src/app/install/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {InstallNavigation} from \"./install-navigation\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: InstallNavigation},\n    {path: ':folder/:id', component: InstallNavigation},\n    {path: '**', component: InstallNavigation}\n];\n\n@NgModule({\n    imports: [SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [InstallNavigation]\n})\nexport class InstallLazyModule {\n}"
  },
  {
    "path": "src/app/install/install-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {BlockFactoryService} from \"../../services/block-factory-service\";\nimport {PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    providers: [BlockService, BlockFactoryService, {\n        provide: \"BLOCK_PLACEMENT\",\n        useValue: PLACEMENT_SCENE\n    }],\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <div id=\"installPanel\">\n            <h3 data-localize=\"installSignagePlayer\">Install the Signage Player</h3>\n            <h5 data-localize=\"chooseVersion\">\n                <b>Choose which version of the SignagePlayer you would like to get</b>\n            </h5>\n            <span style=\"padding-top: 20px; padding-right: 20px; margin-bottom: 20px\" data-localize=\"recDevice\">We recommend that you purchase our device as it is optimized for the signage software. It also has a built in watch-dog and the software comes pre-installed, so you will not need to download anything at all.</span><br/>\n            <br/>\n\n            <div>\n                <div class=\"panel-group\" id=\"accordion\">\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseOne\">\n                                    <i class=\"installs fa fa-cubes\"></i><span data-localize=\"playerPreInstall\">SignagePlayer pre-installed</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseOne\" class=\"panel-collapse collapse in\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li>\n                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"purchaseOne\"> purchase one of our devices: </span>\n                                        <button data-localize=\"orderNow\" type=\"button\" (click)=\"_openInNewTab('http://www.digitalsignage.com/_html/mediaplayer.html')\" class=\"helpLinks btn btn-primary btn-xs\">order now\n                                        </button>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"regDevice\"> register the device with your user </span>&nbsp;<span class=\"userName\"></span>&nbsp;<span data-localize=\"andPass\"> and password</span>&nbsp;\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step3\">Step 3:</b><span data-localize=\"remoteManage\"> begin remote managing your device from the </span>&nbsp;<u data-localize=\"navStation\"> Stations </u>&nbsp;<span data-localize=\"secApp\"> section of this application</span>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseTwo\">\n                                    <i class=\"installs fa fa-android\"></i><span data-localize=\"signageAndroid\">SignagePlayer for Android</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseTwo\" class=\"panel-collapse collapse\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li>\n                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"downloadAndroid\"> download player from Google play store: </span>\n                                        <button (click)=\"_openInNewTab('http://android.digitalsignage.com')\" type=\"button\" data-localize=\"download\" class=\"helpLinks btn btn-primary btn-xs\">download\n                                        </button>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"regDevice\"> register the device with your user </span>&nbsp;<span class=\"userName\"></span>&nbsp;<span data-localize=\"andPass\"> and password</span>&nbsp;\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step3\">Step 3:</b><span data-localize=\"remoteManage\"> begin remote managing your device from the </span>&nbsp;<u data-localize=\"navStation\"> Stations </u>&nbsp;<span data-localize=\"secApp\"> section of this application</span>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseThree\">\n                                    <i class=\"installs fa fa-windows\"></i><span data-localize=\"signageWindows\">SignagePlayer for Windows</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseThree\" class=\"panel-collapse collapse\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li>\n                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"downloadSignagePlayerExe\"> download the SignagePlayer EXE app: </span>\n                                        <button (click)=\"_openInNewTab('http://galaxy.signage.me/Code/install/exe/CloudSignagePlayerSetup.exe')\" type=\"button\" data-localize=\"download\" class=\"helpLinks btn btn-primary btn-xs\">\n                                            download\n                                        </button>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"regDevice\"> register the device with your user </span>&nbsp;<span class=\"userName\"></span>&nbsp;<span data-localize=\"andPass\"> and password</span>&nbsp;\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step3\">Step 3:</b><span data-localize=\"remoteManage\"> begin remote managing your device from the </span>&nbsp;<u data-localize=\"navStation\"> Stations </u>&nbsp;<span data-localize=\"secApp\"> section of this application</span>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseFour\">\n                                    <i class=\"installs fa fa-apple\"></i><span data-localize=\"signageMac\">SignagePlayer for Mac</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseFour\" class=\"panel-collapse collapse\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li>\n                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"downloadAIR\"> download Adobe AIR runtime: </span>\n                                        <button type=\"button\" (click)=\"_openInNewTab('http://get.adobe.com/air/')\" data-localize=\"download\" class=\"helpLinks btn btn-primary btn-xs\">download\n                                        </button>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"downloadSignagePlayer\"> download the SignagePlayer AIR app: </span>\n                                        <button (click)=\"_openInNewTab('http://galaxy.signage.me/Code/Install/air/CloudSignagePlayer.air')\" type=\"button\" data-localize=\"download\" class=\"helpLinks btn btn-primary btn-xs\">\n                                            download\n                                        </button>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step3\">Step 3:</b><span data-localize=\"regDevice\"> register the device with your user </span>&nbsp;<span class=\"userName\"></span>&nbsp;<span data-localize=\"andPass\"> and password</span>&nbsp;\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step4\">Step 4:</b><span data-localize=\"remoteManage\"> begin remote managing your device from the </span>&nbsp;<u data-localize=\"navStation\"> Stations </u>&nbsp;<span data-localize=\"secApp\"> section of this application</span>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseFive\">\n                                    <i class=\"installs fa fa-apple\"></i><span data-localize=\"signageIOS\">SignagePlayer for iOS</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseFive\" class=\"panel-collapse collapse\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li>\n                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"downloadIOS\"> download player from the App store: </span>\n                                        <button (click)=\"_openInNewTab('http://ios.digitalsignage.com')\" type=\"button\" data-localize=\"download\" class=\"helpLinks btn btn-primary btn-xs\">download\n                                        </button>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"regDevice\"> register the device with your user </span>&nbsp;<span class=\"userName\"></span>&nbsp;<span data-localize=\"andPass\"> and password</span>&nbsp;\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step3\">Step 3:</b><span data-localize=\"remoteManage\"> begin remote managing your device from the </span>&nbsp;<u data-localize=\"navStation\"> Stations </u>&nbsp;<span data-localize=\"secApp\"> section of this application</span>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n    `\n})\nexport class InstallNavigation extends Compbaser {\n\n    _openInNewTab(url, event?:MouseEvent) {\n        if (event){\n            event.stopImmediatePropagation();\n            event.preventDefault();\n        }\n        var win = window.open(url, '_blank');\n        win.focus();\n    }\n\n}\n\n"
  },
  {
    "path": "src/app/live-preview/live-preview.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {CampaignTimelinesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {ISceneData} from \"../blocks/block-service\";\nimport {CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {MainAppShowStateEnum} from \"../app-component\";\n\nexport enum PreviewModeEnum {\n    NONE,\n    SCENE,\n    CAMPAIGN,\n    TIMELINE\n}\n\n@Component({\n    selector: 'live-preview',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        .btn-group {\n            position: relative;\n            top: -25px;\n            left: 20px;\n        }\n\n        #iFramePreview {\n            width: 100%;\n            height: 100%;\n            float: left;\n            text-align: center;\n            background-color: #222222;\n        }\n\n        #iFrameEmbedded {\n            width: 1920px;\n            height: 1080px;\n            margin: 0 auto;\n        }\n    `],\n    template: `\n        <div class=\"btn-group\">\n            <button (click)=\"_onExit()\" type=\"button\" title=\"back\" class=\"openPropsButton btn btn-default btn-lg\">\n                <span class=\"fa fa-power-off\"></span>\n            </button>\n        </div>\n        <div id=\"iFramePreview\">\n            <IFRAME id=\"iFrameEmbedded\"></IFRAME>\n        </div>\n    `,\n})\nexport class LivePreview extends Compbaser implements AfterViewInit {\n\n    constructor(private cd:ChangeDetectorRef, private yp: YellowPepperService, private rp: RedPepperService, private el: ElementRef) {\n        super();\n        cd.detach();\n    }\n\n    ngAfterViewInit() {\n        if (!this.checkFlash())\n            return;\n        this.yp.getPreviewMode()\n            .mergeMap((i_previewMode: PreviewModeEnum) => {\n                switch (i_previewMode) {\n                    case PreviewModeEnum.SCENE: {\n                        return this.yp.listenSceneSelected()\n                            .map((i_sceneData: ISceneData) => {\n                                return this.launchScene(i_sceneData.scene_id);\n                            })\n                    }\n                    case PreviewModeEnum.TIMELINE: {\n                        return this.yp.listenTimelineSelected()\n                            .take(1)\n                            .map((i_campaignTimelinesModel: CampaignTimelinesModel) => {\n                                return this.launchTimeline(i_campaignTimelinesModel.getCampaignId(), i_campaignTimelinesModel.getCampaignTimelineId());\n                            })\n                    }\n                    case PreviewModeEnum.CAMPAIGN: {\n                        return this.yp.listenCampaignSelected()\n                            .take(1)\n                            .map((i_campaignsModelExt: CampaignsModelExt) => {\n                                return this.launchCampaign(i_campaignsModelExt.getCampaignId());\n                            })\n                    }\n                }\n            }).subscribe((v) => {\n            console.log(v);\n        }, (e) => console.error(e))\n    }\n\n    _onExit() {\n        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.NORMAL, previewMode: PreviewModeEnum.NONE}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    checkFlash() {\n        if (!FlashDetect.installed || !FlashDetect.versionAtLeast(13)) {\n            bootbox.alert({\n                message: 'Flash is not enabled, in Chrome go to the URL: chrome://settings/content to enable'\n            });\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     Listen to live preview launch\n     @method launch\n     **/\n    launchScene(i_sceneId) {\n        var url = this.rp.livePreviewScene(i_sceneId, 0);\n        $('#iFrameEmbedded').attr('src', url);\n    }\n\n    /**\n     Listen to live preview launch\n     @method launch  i_campaignTimelineNativeID\n     **/\n    launchTimeline(i_campaignID, i_campaignTimelineID) {\n        var url = this.rp.livePreviewTimeline(i_campaignID, i_campaignTimelineID, 0);\n        $('#iFrameEmbedded').attr('src', url);\n    }\n\n    /**\n     Listen to live view launch\n     @method launch\n     **/\n    launchCampaign(i_campaignID) {\n        var url = this.rp.livePreviewCampaign(i_campaignID, 0);\n        $('#iFrameEmbedded').attr('src', url);\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/locale-selector/local-selector.css",
    "content": "ul {\n    width: 290px;\n    padding-left: 0px;\n    padding-top: 50px;\n}\n\ntr {\n    cursor: pointer;\n    opacity: 1;\n}\n\ntr:hover {\n    opacity: 0.8;\n}\n\n.f32 {\n    cursor: pointer;\n}\n\nli {\n    opacity: 0.3;\n}\n\nli:hover {\n    opacity: 1;\n}\n\n.f32 .flag {\n    display: inline-block;\n    height: 32px;\n    width: 32px;\n    vertical-align: text-top;\n    line-height: 32px;\n    background: url(../../assets/flags32.png) no-repeat;\n}\n\n.f32 .flag2 {\n    height: 32px;\n    width: 32px;\n    vertical-align: text-top;\n    line-height: 32px;\n    background: url(../../assets/flags32.png) no-repeat;\n}\n\n\n.f32 ._African_Union {\n    background-position: 0 -32px;\n}\n\n.f32 ._Arab_League {\n    background-position: 0 -64px;\n}\n\n.f32 ._ASEAN {\n    background-position: 0 -96px;\n}\n\n.f32 ._CARICOM {\n    background-position: 0 -128px;\n}\n\n.f32 ._CIS {\n    background-position: 0 -160px;\n}\n\n.f32 ._Commonwealth {\n    background-position: 0 -192px;\n}\n\n.f32 ._England {\n    background-position: 0 -224px;\n}\n\n.f32 ._European_Union, .f32 .eu {\n    background-position: 0 -256px;\n}\n\n.f32 ._Islamic_Conference {\n    background-position: 0 -288px;\n}\n\n.f32 ._Kosovo {\n    background-position: 0 -320px;\n}\n\n.f32 ._NATO {\n    background-position: 0 -352px;\n}\n\n.f32 ._Northern_Cyprus {\n    background-position: 0 -384px;\n}\n\n.f32 ._Northern_Ireland {\n    background-position: 0 -416px;\n}\n\n.f32 ._Olimpic_Movement {\n    background-position: 0 -448px;\n}\n\n.f32 ._OPEC {\n    background-position: 0 -480px;\n}\n\n.f32 ._Red_Cross {\n    background-position: 0 -512px;\n}\n\n.f32 ._Scotland {\n    background-position: 0 -544px;\n}\n\n.f32 ._Somaliland {\n    background-position: 0 -576px;\n}\n\n.f32 ._Tibet {\n    background-position: 0 -608px;\n}\n\n.f32 ._United_Nations {\n    background-position: 0 -640px;\n}\n\n.f32 ._Wales {\n    background-position: 0 -672px;\n}\n\n.f32 .ad {\n    background-position: 0 -704px;\n}\n\n.f32 .ae {\n    background-position: 0 -736px;\n}\n\n.f32 .af {\n    background-position: 0 -768px;\n}\n\n.f32 .ag {\n    background-position: 0 -800px;\n}\n\n.f32 .ai {\n    background-position: 0 -832px;\n}\n\n.f32 .al {\n    background-position: 0 -864px;\n}\n\n.f32 .am {\n    background-position: 0 -896px;\n}\n\n.f32 .ao {\n    background-position: 0 -928px;\n}\n\n.f32 .aq {\n    background-position: 0 -960px;\n}\n\n.f32 .ar {\n    background-position: 0 -992px;\n}\n\n.f32 .as {\n    background-position: 0 -1024px;\n}\n\n.f32 .at {\n    background-position: 0 -1056px;\n}\n\n.f32 .au {\n    background-position: 0 -1088px;\n}\n\n.f32 .aw {\n    background-position: 0 -1120px;\n}\n\n.f32 .ax {\n    background-position: 0 -1152px;\n}\n\n.f32 .az {\n    background-position: 0 -1184px;\n}\n\n.f32 .ba {\n    background-position: 0 -1216px;\n}\n\n.f32 .bb {\n    background-position: 0 -1248px;\n}\n\n.f32 .bd {\n    background-position: 0 -1280px;\n}\n\n.f32 .be {\n    background-position: 0 -1312px;\n}\n\n.f32 .bf {\n    background-position: 0 -1344px;\n}\n\n.f32 .bg {\n    background-position: 0 -1376px;\n}\n\n.f32 .bh {\n    background-position: 0 -1408px;\n}\n\n.f32 .bi {\n    background-position: 0 -1440px;\n}\n\n.f32 .bj {\n    background-position: 0 -1472px;\n}\n\n.f32 .bm {\n    background-position: 0 -1504px;\n}\n\n.f32 .bn {\n    background-position: 0 -1536px;\n}\n\n.f32 .bo {\n    background-position: 0 -1568px;\n}\n\n.f32 .br {\n    background-position: 0 -1600px;\n}\n\n.f32 .bs {\n    background-position: 0 -1632px;\n}\n\n.f32 .bt {\n    background-position: 0 -1664px;\n}\n\n.f32 .bw {\n    background-position: 0 -1696px;\n}\n\n.f32 .by {\n    background-position: 0 -1728px;\n}\n\n.f32 .bz {\n    background-position: 0 -1760px;\n}\n\n.f32 .ca {\n    background-position: 0 -1792px;\n}\n\n.f32 .cd {\n    background-position: 0 -1824px;\n}\n\n.f32 .cf {\n    background-position: 0 -1856px;\n}\n\n.f32 .cg {\n    background-position: 0 -1888px;\n}\n\n.f32 .ch {\n    background-position: 0 -1920px;\n}\n\n.f32 .ci {\n    background-position: 0 -1952px;\n}\n\n.f32 .ck {\n    background-position: 0 -1984px;\n}\n\n.f32 .cl {\n    background-position: 0 -2016px;\n}\n\n.f32 .cm {\n    background-position: 0 -2048px;\n}\n\n.f32 .cn {\n    background-position: 0 -2080px;\n}\n\n.f32 .co {\n    background-position: 0 -2112px;\n}\n\n.f32 .cr {\n    background-position: 0 -2144px;\n}\n\n.f32 .cu {\n    background-position: 0 -2176px;\n}\n\n.f32 .cv {\n    background-position: 0 -2208px;\n}\n\n.f32 .cy {\n    background-position: 0 -2240px;\n}\n\n.f32 .cz {\n    background-position: 0 -2272px;\n}\n\n.f32 .de {\n    background-position: 0 -2304px;\n}\n\n.f32 .dj {\n    background-position: 0 -2336px;\n}\n\n.f32 .dk {\n    background-position: 0 -2368px;\n}\n\n.f32 .dm {\n    background-position: 0 -2400px;\n}\n\n.f32 .do {\n    background-position: 0 -2432px;\n}\n\n.f32 .dz {\n    background-position: 0 -2464px;\n}\n\n.f32 .ec {\n    background-position: 0 -2496px;\n}\n\n.f32 .ee {\n    background-position: 0 -2528px;\n}\n\n.f32 .eg {\n    background-position: 0 -2560px;\n}\n\n.f32 .eh {\n    background-position: 0 -2592px;\n}\n\n.f32 .er {\n    background-position: 0 -2624px;\n}\n\n.f32 .es {\n    background-position: 0 -2656px;\n}\n\n.f32 .et {\n    background-position: 0 -2688px;\n}\n\n.f32 .fi {\n    background-position: 0 -2720px;\n}\n\n.f32 .fj {\n    background-position: 0 -2752px;\n}\n\n.f32 .fm {\n    background-position: 0 -2784px;\n}\n\n.f32 .fo {\n    background-position: 0 -2816px;\n}\n\n.f32 .fr {\n    background-position: 0 -2848px;\n}\n\n.f32 .bl, .f32 .cp, .f32 .mf, .f32 .yt {\n    background-position: 0 -2848px;\n}\n\n.f32 .ga {\n    background-position: 0 -2880px;\n}\n\n.f32 .gb {\n    background-position: 0 -2912px;\n}\n\n.f32 .sh {\n    background-position: 0 -2912px;\n}\n\n.f32 .gd {\n    background-position: 0 -2944px;\n}\n\n.f32 .ge {\n    background-position: 0 -2976px;\n}\n\n.f32 .gg {\n    background-position: 0 -3008px;\n}\n\n.f32 .gh {\n    background-position: 0 -3040px;\n}\n\n.f32 .gi {\n    background-position: 0 -3072px;\n}\n\n.f32 .gl {\n    background-position: 0 -3104px;\n}\n\n.f32 .gm {\n    background-position: 0 -3136px;\n}\n\n.f32 .gn {\n    background-position: 0 -3168px;\n}\n\n.f32 .gp {\n    background-position: 0 -3200px;\n}\n\n.f32 .gq {\n    background-position: 0 -3232px;\n}\n\n.f32 .gr {\n    background-position: 0 -3264px;\n}\n\n.f32 .gt {\n    background-position: 0 -3296px;\n}\n\n.f32 .gu {\n    background-position: 0 -3328px;\n}\n\n.f32 .gw {\n    background-position: 0 -3360px;\n}\n\n.f32 .gy {\n    background-position: 0 -3392px;\n}\n\n.f32 .hk {\n    background-position: 0 -3424px;\n}\n\n.f32 .hn {\n    background-position: 0 -3456px;\n}\n\n.f32 .hr {\n    background-position: 0 -3488px;\n}\n\n.f32 .ht {\n    background-position: 0 -3520px;\n}\n\n.f32 .hu {\n    background-position: 0 -3552px;\n}\n\n.f32 .id {\n    background-position: 0 -3584px;\n}\n\n.f32 .mc {\n    background-position: 0 -3584px;\n}\n\n.f32 .ie {\n    background-position: 0 -3616px;\n}\n\n.f32 .il {\n    background-position: 0 -3648px;\n}\n\n.f32 .im {\n    background-position: 0 -3680px;\n}\n\n.f32 .in {\n    background-position: 0 -3712px;\n}\n\n.f32 .iq {\n    background-position: 0 -3744px;\n}\n\n.f32 .ir {\n    background-position: 0 -3776px;\n}\n\n.f32 .is {\n    background-position: 0 -3808px;\n}\n\n.f32 .it {\n    background-position: 0 -3840px;\n}\n\n.f32 .je {\n    background-position: 0 -3872px;\n}\n\n.f32 .jm {\n    background-position: 0 -3904px;\n}\n\n.f32 .jo {\n    background-position: 0 -3936px;\n}\n\n.f32 .jp {\n    background-position: 0 -3968px;\n}\n\n.f32 .ke {\n    background-position: 0 -4000px;\n}\n\n.f32 .kg {\n    background-position: 0 -4032px;\n}\n\n.f32 .kh {\n    background-position: 0 -4064px;\n}\n\n.f32 .ki {\n    background-position: 0 -4096px;\n}\n\n.f32 .km {\n    background-position: 0 -4128px;\n}\n\n.f32 .kn {\n    background-position: 0 -4160px;\n}\n\n.f32 .kp {\n    background-position: 0 -4192px;\n}\n\n.f32 .kr {\n    background-position: 0 -4224px;\n}\n\n.f32 .kw {\n    background-position: 0 -4256px;\n}\n\n.f32 .ky {\n    background-position: 0 -4288px;\n}\n\n.f32 .kz {\n    background-position: 0 -4320px;\n}\n\n.f32 .la {\n    background-position: 0 -4352px;\n}\n\n.f32 .lb {\n    background-position: 0 -4384px;\n}\n\n.f32 .lc {\n    background-position: 0 -4416px;\n}\n\n.f32 .li {\n    background-position: 0 -4448px;\n}\n\n.f32 .lk {\n    background-position: 0 -4480px;\n}\n\n.f32 .lr {\n    background-position: 0 -4512px;\n}\n\n.f32 .ls {\n    background-position: 0 -4544px;\n}\n\n.f32 .lt {\n    background-position: 0 -4576px;\n}\n\n.f32 .lu {\n    background-position: 0 -4608px;\n}\n\n.f32 .lv {\n    background-position: 0 -4640px;\n}\n\n.f32 .ly {\n    background-position: 0 -4672px;\n}\n\n.f32 .ma {\n    background-position: 0 -4704px;\n}\n\n.f32 .md {\n    background-position: 0 -4736px;\n}\n\n.f32 .me {\n    background-position: 0 -4768px;\n}\n\n.f32 .mg {\n    background-position: 0 -4800px;\n}\n\n.f32 .mh {\n    background-position: 0 -4832px;\n}\n\n.f32 .mk {\n    background-position: 0 -4864px;\n}\n\n.f32 .ml {\n    background-position: 0 -4896px;\n}\n\n.f32 .mm {\n    background-position: 0 -4928px;\n}\n\n.f32 .mn {\n    background-position: 0 -4960px;\n}\n\n.f32 .mo {\n    background-position: 0 -4992px;\n}\n\n.f32 .mq {\n    background-position: 0 -5024px;\n}\n\n.f32 .mr {\n    background-position: 0 -5056px;\n}\n\n.f32 .ms {\n    background-position: 0 -5088px;\n}\n\n.f32 .mt {\n    background-position: 0 -5120px;\n}\n\n.f32 .mu {\n    background-position: 0 -5152px;\n}\n\n.f32 .mv {\n    background-position: 0 -5184px;\n}\n\n.f32 .mw {\n    background-position: 0 -5216px;\n}\n\n.f32 .mx {\n    background-position: 0 -5248px;\n}\n\n.f32 .my {\n    background-position: 0 -5280px;\n}\n\n.f32 .mz {\n    background-position: 0 -5312px;\n}\n\n.f32 .na {\n    background-position: 0 -5344px;\n}\n\n.f32 .nc {\n    background-position: 0 -5376px;\n}\n\n.f32 .ne {\n    background-position: 0 -5408px;\n}\n\n.f32 .ng {\n    background-position: 0 -5440px;\n}\n\n.f32 .ni {\n    background-position: 0 -5472px;\n}\n\n.f32 .nl {\n    background-position: 0 -5504px;\n}\n\n.f32 .bq {\n    background-position: 0 -5504px;\n}\n\n.f32 .no {\n    background-position: 0 -5536px;\n}\n\n.f32 .bv, .f32 .nq, .f32 .sj {\n    background-position: 0 -5536px;\n}\n\n.f32 .np {\n    background-position: 0 -5568px;\n}\n\n.f32 .nr {\n    background-position: 0 -5600px;\n}\n\n.f32 .nz {\n    background-position: 0 -5632px;\n}\n\n.f32 .om {\n    background-position: 0 -5664px;\n}\n\n.f32 .pa {\n    background-position: 0 -5696px;\n}\n\n.f32 .pe {\n    background-position: 0 -5728px;\n}\n\n.f32 .pf {\n    background-position: 0 -5760px;\n}\n\n.f32 .pg {\n    background-position: 0 -5792px;\n}\n\n.f32 .ph {\n    background-position: 0 -5824px;\n}\n\n.f32 .pk {\n    background-position: 0 -5856px;\n}\n\n.f32 .pl {\n    background-position: 0 -5888px;\n}\n\n.f32 .pr {\n    background-position: 0 -5920px;\n}\n\n.f32 .ps {\n    background-position: 0 -5952px;\n}\n\n.f32 .pt {\n    background-position: 0 -5984px;\n}\n\n.f32 .pw {\n    background-position: 0 -6016px;\n}\n\n.f32 .py {\n    background-position: 0 -6048px;\n}\n\n.f32 .qa {\n    background-position: 0 -6080px;\n}\n\n.f32 .re {\n    background-position: 0 -6112px;\n}\n\n.f32 .ro {\n    background-position: 0 -6144px;\n}\n\n.f32 .rs {\n    background-position: 0 -6176px;\n}\n\n.f32 .ru {\n    background-position: 0 -6208px;\n}\n\n.f32 .rw {\n    background-position: 0 -6240px;\n}\n\n.f32 .sa {\n    background-position: 0 -6272px;\n}\n\n.f32 .sb {\n    background-position: 0 -6304px;\n}\n\n.f32 .sc {\n    background-position: 0 -6336px;\n}\n\n.f32 .sd {\n    background-position: 0 -6368px;\n}\n\n.f32 .se {\n    background-position: 0 -6400px;\n}\n\n.f32 .sg {\n    background-position: 0 -6432px;\n}\n\n.f32 .si {\n    background-position: 0 -6464px;\n}\n\n.f32 .sk {\n    background-position: 0 -6496px;\n}\n\n.f32 .sl {\n    background-position: 0 -6528px;\n}\n\n.f32 .sm {\n    background-position: 0 -6560px;\n}\n\n.f32 .sn {\n    background-position: 0 -6592px;\n}\n\n.f32 .so {\n    background-position: 0 -6624px;\n}\n\n.f32 .sr {\n    background-position: 0 -6656px;\n}\n\n.f32 .st {\n    background-position: 0 -6688px;\n}\n\n.f32 .sv {\n    background-position: 0 -6720px;\n}\n\n.f32 .sy {\n    background-position: 0 -6752px;\n}\n\n.f32 .sz {\n    background-position: 0 -6784px;\n}\n\n.f32 .tc {\n    background-position: 0 -6816px;\n}\n\n.f32 .td {\n    background-position: 0 -6848px;\n}\n\n.f32 .tg {\n    background-position: 0 -6880px;\n}\n\n.f32 .th {\n    background-position: 0 -6912px;\n}\n\n.f32 .tj {\n    background-position: 0 -6944px;\n}\n\n.f32 .tl {\n    background-position: 0 -6976px;\n}\n\n.f32 .tm {\n    background-position: 0 -7008px;\n}\n\n.f32 .tn {\n    background-position: 0 -7040px;\n}\n\n.f32 .to {\n    background-position: 0 -7072px;\n}\n\n.f32 .tr {\n    background-position: 0 -7104px;\n}\n\n.f32 .tt {\n    background-position: 0 -7136px;\n}\n\n.f32 .tv {\n    background-position: 0 -7168px;\n}\n\n.f32 .tw {\n    background-position: 0 -7200px;\n}\n\n.f32 .tz {\n    background-position: 0 -7232px;\n}\n\n.f32 .ua {\n    background-position: 0 -7264px;\n}\n\n.f32 .ug {\n    background-position: 0 -7296px;\n}\n\n.f32 .us {\n    background-position: 0 -7328px;\n}\n\n.f32 .uy {\n    background-position: 0 -7360px;\n}\n\n.f32 .uz {\n    background-position: 0 -7392px;\n}\n\n.f32 .va {\n    background-position: 0 -7424px;\n}\n\n.f32 .vc {\n    background-position: 0 -7456px;\n}\n\n.f32 .ve {\n    background-position: 0 -7488px;\n}\n\n.f32 .vg {\n    background-position: 0 -7520px;\n}\n\n.f32 .vi {\n    background-position: 0 -7552px;\n}\n\n.f32 .vn {\n    background-position: 0 -7584px;\n}\n\n.f32 .vu {\n    background-position: 0 -7616px;\n}\n\n.f32 .ws {\n    background-position: 0 -7648px;\n}\n\n.f32 .ye {\n    background-position: 0 -7680px;\n}\n\n.f32 .za {\n    background-position: 0 -7712px;\n}\n\n.f32 .zm {\n    background-position: 0 -7744px;\n}\n\n.f32 .zw {\n    background-position: 0 -7776px;\n}\n\n.f32 .sx {\n    background-position: 0 -7808px;\n}\n\n.f32 .cw {\n    background-position: 0 -7840px;\n}\n\n.f32 .ss {\n    background-position: 0 -7872px;\n}\n\n.f32 .nu {\n    background-position: 0 -7904px;\n}"
  },
  {
    "path": "src/app/locale-selector/local-selector.ts",
    "content": "import {ChangeDetectionStrategy, EventEmitter, Component, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\n@Component({\n    selector: 'locale-selector',\n    styleUrls: ['./local-selector.css'],\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div *ngIf=\"m_orientation=='inline'\">\n            <ul class=\"f32\">\n                <li (click)=\"redirect(locale)\" *ngFor=\"let locale of locales\" class=\"flag {{locale.flag}}\">\n                </li>\n            </ul>\n        </div>\n        <div *ngIf=\"m_orientation=='modal'\">\n            <h4 style=\"display: inline-block\">Selected language: {{m_selectedLocale?.name}}</h4>\n            <button [disabled]=\"!m_selectedLocale\" (click)=\"_saveAndReload()\" class=\"btn btn-primary pull-right\">Save and reload language</button>\n            <table class=\"f32 table\">\n                <thead>\n                <tr>\n                    <th></th>\n                    <th></th>\n                </tr>\n                </thead>\n                <tbody>\n                <tr (click)=\"_onSelected(locale)\" *ngFor=\"let locale of locales; let i = index\" class=\"flag2\">\n                    <td class=\"flag2 {{locale.flag}}\"></td>\n                    <td>{{locale.name}}</td>\n                </tr>\n                </tbody>\n            </table>\n        </div>\n    `\n})\nexport class LocaleSelector extends Compbaser {\n\n    m_selectedLocale;\n    m_orientation;\n\n    /**\n     locale info:\n\n     project: https://github.com/lafeber/world-flags-sprite\n     flags codes: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2\n     google codes: https://cloud.google.com/translate/docs/languages\n     docs: https://angular.io/docs/ts/latest/cookbook/i18n.html\n\n     **/\n\n    locales = [\n        {flag: 'us', locale: 'en', name: 'English'},\n        {flag: 'cn', locale: 'zh-CN', name: 'Chinese'},\n        {flag: 'in', locale: 'bn', name: 'Bengali'},\n        {flag: 'es', locale: 'es', name: 'Spanish'},\n        {flag: 'in', locale: 'hi', name: 'Hindi'},\n        {flag: 'jo', locale: 'ar', name: 'Arabic'},\n        {flag: 'il', locale: 'iw', name: 'Hebrew'},\n        {flag: 'br', locale: 'pt', name: 'Portuguese'},\n        {flag: 'de', locale: 'de', name: 'German'},\n        {flag: 'jp', locale: 'ja', name: 'Japanese'},\n        {flag: 'ru', locale: 'ru', name: 'Russian'},\n        {flag: 'ph', locale: 'tl', name: 'Filipino'},\n        {flag: 'fr', locale: 'fr', name: 'French'},\n        {flag: 'gr', locale: 'el', name: 'Greek'},\n        {flag: 'kr', locale: 'ko', name: 'Korean'},\n        {flag: 'th', locale: 'th', name: 'Thai'},\n        {flag: 'my', locale: 'ms', name: 'Malay'},\n        {flag: 'it', locale: 'it', name: 'Italian'}\n    ]\n\n    constructor(private yp: YellowPepperService) {\n        super();\n    }\n\n    @Input()\n    set orientation(i_orientation: 'inline' | 'modal') {\n        this.m_orientation = i_orientation;\n    }\n\n    @Output()\n    onLocaleChanged: EventEmitter<any> = new EventEmitter<any>();\n\n    _saveAndReload() {\n        this.onLocaleChanged.emit(this.m_selectedLocale);\n    }\n\n    _onSelected(i_locale) {\n        this.m_selectedLocale = i_locale;\n    }\n\n    public redirect(i_locale) {\n        window.onbeforeunload = () => {\n        };\n        window.location.replace(`https://secure.digitalsignage.com/studioweb/locale/${i_locale.locale}/`);\n    }\n\n    destroy() {\n    }\n}\n\n"
  },
  {
    "path": "src/app/location/location-map.html",
    "content": "<small class=\"debug\">{{me}}</small>\n<button (click)=\"_close()\" type=\"button\" class=\"openPropsButton btn btn-default btn-sm\">\n    <span class=\"glyphicon glyphicon-chevron-left\"></span>\n</button>\n<form novalidate autocomplete=\"off\" [formGroup]=\"contGroup\">\n    <div class=\"clearFloat\"></div>\n    <hr/>\n    <div id=\"simModeContainer\">\n        <div class=\"material-switch pull-right\">\n            <input #simMode (change)=\"_toggleSimMode()\"\n                   id=\"simMode\"\n                   name=\"simMode\" type=\"checkbox\"/>\n            <label for=\"simMode\" class=\"label-primary\"></label>\n        </div>\n        <span class=\"pull-right\" i18n>simulation mode</span>\n        <div class=\"clearFloat\"></div>\n        <div *ngIf=\"inSimMode\" class=\"locationSimulationProps pull-right\">\n            <button id=\"refresh\" (click)=\"_loadStationList()\" type=\"button\" class=\"btn btn-default\">\n                <i class=\"fa fa-refresh\"></i>\n                refresh\n            </button>\n            <select formControlName=\"stations\" (change)=\"_onStationSelected($event)\" style=\"height: 31px; width: 170px; border: solid #cbcbcb 1px\">\n                <option [ngValue]=\"station\" *ngFor=\"let station of m_stations\">{{station.stationName}}</option>\n            </select>\n            <select formControlName=\"postMode\" style=\"height: 31px; border: solid #cbcbcb 1px\">\n                <option value=\"local\">Local post</option>\n                <option value=\"remote\">Remote post</option>\n            </select>\n            <h5>{{m_simStatus}}</h5>\n            <h5 [ngClass]=\"{'green': m_inRange == true}\">Latitude: {{m_simulatedLat}}</h5>\n            <h5 [ngClass]=\"{'green': m_inRange == true}\">longitude: {{m_simulatedLng}}</h5>\n            <h5 (click)=\"_openSimUrl($event)\" style=\"font-size: 7px; cursor: pointer\">{{m_simUrl}}</h5>\n        </div>\n    </div>\n    <input id=\"addressLookup\" class=\"list-group-item\" #address type=\"text\"/>\n</form>\n\n<div class=\"row map\">\n    <!--<sebm-google-map class=\"center-block\" #googleMaps [disableDefaultUI]=\"false\" [latitude]=\"38.2500\" [longitude]=\"-96.7500\"></sebm-google-map>-->\n\n    <sebm-google-map #googleMaps class=\"center-block\"\n                     [latitude]=\"lat\"\n                     [longitude]=\"lng\"\n                     [zoom]=\"zoom\"\n                     [disableDefaultUI]=\"false\"\n                     [zoomControl]=\"false\"\n                     (mapClick)=\"mapClicked($event)\">\n\n        <!--<sebm-google-map-marker-->\n        <!--*ngFor=\"let m of markers; let i = index\"-->\n        <!--(markerClick)=\"clickedMarker(m, i)\"-->\n        <!--[latitude]=\"m.lat\"-->\n        <!--[longitude]=\"m.lng\"                        -->\n        <!--[label]=\"m.label\"-->\n        <!--[markerDraggable]=\"m.draggable\"-->\n        <!--(dragEnd)=\"markerDragEnd(m, $event)\">-->\n\n        <!--<sebm-google-map-info-window>-->\n        <!--<strong>InfoWindow content</strong>-->\n        <!--</sebm-google-map-info-window>-->\n\n        <!--</sebm-google-map-marker>-->\n        <sebm-google-map-circle *ngFor=\"let m of markers; let i = index\"\n                                (circleClick)=\"clickedMarker(m, i)\"\n                                [latitude]=\"m.lat\"\n                                [fillOpacity]=\"0.6\"\n                                (dragEnd)=\"markerDragEnd(m, $event)\"\n                                [longitude]=\"m.lng\"\n                                [radius]=\"m.radius\"\n                                [fillColor]=\"'red'\"\n                                [circleDraggable]=\"false\"\n                                [editable]=\"false\">\n        </sebm-google-map-circle>\n\n    </sebm-google-map>\n\n</div>\n\n<!--<sebm-google-map #googleMaps style=\"width: 100% ; height: 100%\"-->\n<!--(mapClick)=\"mapClicked($event)\"-->\n<!--[latitude]=\"38.2500\"-->\n<!--[longitude]=\"-96.7500\"-->\n<!--[zoom]=\"zoom\"-->\n<!--[disableDefaultUI]=\"false\"-->\n<!--[zoomControl]=\"false\">-->\n\n<!--<sebm-google-map-marker style=\"width: 300px ; height: 400px\"-->\n<!--*ngFor=\"let m of markers; let i = index\"-->\n<!--(markerClick)=\"clickedMarker(m, i)\"-->\n<!--[latitude]=\"m.lat\"-->\n<!--[longitude]=\"m.lng\"-->\n<!--[iconUrl]=\"getMarkerIcon(m)\"-->\n<!--[label]=\"m.label\">-->\n<!--&lt;!&ndash;<sebm-google-map-info-window>&ndash;&gt;-->\n<!--&lt;!&ndash;<strong>InfoWindow content</strong>&ndash;&gt;-->\n<!--&lt;!&ndash;</sebm-google-map-info-window>&ndash;&gt;-->\n\n<!--</sebm-google-map-marker>-->\n<!--</sebm-google-map>-->"
  },
  {
    "path": "src/app/location/location-map.ts",
    "content": "import {AfterViewInit, ChangeDetectorRef, Component, EventEmitter, Inject, NgZone, Output, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {SebmGoogleMap} from \"angular2-google-maps/esm/core\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {MapsAPILoader} from \"angular2-google-maps/core\";\nimport {BlockService, IBlockData, ISceneData} from \"../blocks/block-service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {PLACEMENT_CHANNEL, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {CampaignTimelineChanelPlayersModel} from \"../../store/imsdb.interfaces_auto\";\nimport {LocationMarkModel} from \"../../models/LocationMarkModel\";\nimport {FormBuilder, FormGroup} from \"@angular/forms\";\nimport * as _ from 'lodash';\n\nexport declare var google: any;\n\n/**\n *  examples:\n *  http://embed.plnkr.co/YX7W20/\n *  http://plnkr.co/edit/NtfCPol50mlwGoiB8UZu?p=preview\n *\n * **/\n\n@Component({\n    selector: 'location-map',\n    styles: [`\n        .sebm-google-map-container {\n            height: 700px;\n            width: 1700px;\n        }\n\n        .green {\n            background-color: green;\n            color: white;\n        }\n\n        .locationSimulationProps {\n            width: 420px;\n            height: 160px;\n            border: 1px dotted gray;\n            padding: 6px;\n        }\n\n        #simModeContainer {\n            padding: 0 20px 20px 0;\n            position: relative;\n            top: -20px;\n        }\n\n        #addressLookup {\n            z-index: 1;\n            position: relative;\n            top: 50px;\n            width: 300px;\n        }\n\n        #refresh {\n            position: relative;\n            top: -1px;\n            height: 31px;\n        }\n\n    `],\n    templateUrl: './location-map.html'\n})\nexport class LocationMap extends Compbaser implements AfterViewInit {\n\n    zoom: any = 8;\n    lat: any = 51.673858;\n    lng: any = 7.815982;\n    markers: LocationMarkModel[] = [];\n    m_stations = [];\n    inSimMode = false;\n    m_inRange = false;\n    m_simStatus = 'status: waiting...'\n    m_simulatedLat = 0;\n    m_simulatedLng = 0;\n    m_simUrl = '';\n    m_blockData: IBlockData;\n    contGroup: FormGroup;\n\n\n    constructor(private yp: YellowPepperService, private cd: ChangeDetectorRef, private m_mapsAPILoader: MapsAPILoader, private fb: FormBuilder,\n                private zone: NgZone, private bs: BlockService, @Inject('BLOCK_PLACEMENT') private blockPlacement: string, private rp: RedPepperService) {\n        super();\n        this.contGroup = fb.group({\n            'stations': [],\n            'postMode': []\n        });\n    }\n\n    @ViewChild('address')\n    address;\n\n    @ViewChild('googleMaps')\n    googleMaps: SebmGoogleMap;\n\n    @Output()\n    onClose: EventEmitter<any> = new EventEmitter<any>();\n\n    ngAfterViewInit() {\n\n        // Google Place Autocomplete\n        var autocomplete: any;\n        // var inputAddress = document.getElementById(\"address\");\n\n        this.m_mapsAPILoader.load().then(() => {\n            console.log('google script loaded');\n\n            autocomplete = new google.maps.places.Autocomplete(this.address.nativeElement, {});\n            google.maps.event.addListener(autocomplete, 'place_changed', () => {\n\n                this.zone.run(() => {\n                    /*\n                     \"Zone.run\" allows the map to be immediately updated.\n                     Without it, you would have to click the map to observe\n                     the new lat and lng\n                     */\n                    var place = autocomplete.getPlace();\n                    if (!place || !place.geometry) return;\n                    var lat = place.geometry.location.lat();\n                    var lng = place.geometry.location.lng();\n                    this.setCenter(lat, lng)\n                });\n\n            });\n\n            // var geocoder = new google.maps.Geocoder();\n        });\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenLocationMarkerSelected()\n                .subscribe((i_marker: LocationMarkModel) => {\n                    this.setCenter(i_marker.lat, i_marker.lng)\n                }, (e) => console.error(e))\n        )\n\n        if (this.blockPlacement == PLACEMENT_CHANNEL)\n            this._listenOnChannels();\n        if (this.blockPlacement == PLACEMENT_SCENE)\n            this._listenOnScenes();\n    }\n\n    _toggleSimMode() {\n        this.inSimMode = !this.inSimMode;\n        if (!this.inSimMode) {\n            this.m_simulatedLat = 0;\n            this.m_simulatedLng = 0;\n            this.m_inRange = false;\n        } else {\n            this._loadStationList();\n            this.contGroup.controls.postMode.setValue('local');\n        }\n        this.cd.markForCheck();\n    }\n\n    /**\n     Load and refresh the station list so we can pull station id for simulation\n     @method _loadStationList\n     **/\n    _loadStationList() {\n        var self = this;\n        this.m_stations = [];\n        this.contGroup.controls.stations.setValue('');\n        var userData = this.rp.getUserData();\n        var url = window.g_protocol + userData.domain + '/WebService/getStatus.ashx?user=' + userData.userName + '&password=' + userData.userPass + '&callback=?';\n        $.getJSON(url, (data) => {\n            var s64 = data['ret'];\n            var str = jQuery.base64.decode(s64);\n            var xml = jXML.parseXML(str);\n            $(xml).find('Station').each((key, value) => {\n                var stationId = $(value).attr('id');\n                var stationName = $(value).attr('name');\n                var stationPort = $(value).attr('localPort') || 9999;\n                var stationIp = $(value).attr('localAddress');\n                self.m_stations.push({stationIp, stationId, stationName, stationPort});\n            });\n            self.cd.markForCheck();\n        });\n    }\n\n    _onStationSelected(event) {\n        console.log(this.contGroup.value);\n    }\n\n    /**\n     Simulate a trigger event of GPS coordinates by user clicks within the google map\n     @method _simulateEvent\n     @param {Number} lat\n     @param {Number} lng\n     @param {Boolean} inRange true if clicked within a marked circle radius\n     **/\n    private _simulateEvent(i_marker: LocationMarkModel, i_inRange) {\n        this.m_inRange = i_inRange;\n        this.m_simulatedLat = i_marker.lat;\n        this.m_simulatedLng = i_marker.lng;\n\n        var selected = this.contGroup.value.stations;\n        if (_.isNull(selected) || _.isEmpty(selected))\n            return bootbox.alert('no station selected...');\n        var postMode = this.contGroup.value.postMode;\n        var msg = (postMode == 'local') ? 'click link below to send post...' : 'sending post...';\n\n        var id = this.contGroup.value.stations.stationId;\n        var ip = this.contGroup.value.stations.stationIp;\n        var stationRecord = this.rp.getStationRecord(id);\n        var port = stationRecord.lan_server_port;\n        var url = this.rp.sendLocalEventGPS(postMode, this.m_simulatedLat, this.m_simulatedLng, id, ip, port, function (e) {\n            console.log(e);\n        });\n        this.m_simStatus = msg;\n        this.m_simUrl = url;\n    }\n\n    _openSimUrl() {\n        if (this.contGroup.value.postMode != 'local') return;\n        var id = this.contGroup.value.stations.stationId;\n        var ip = this.contGroup.value.stations.stationIp;\n        var stationRecord = this.rp.getStationRecord(id);\n        var port = stationRecord.lan_server_port;\n        var url = this.rp.sendLocalEventGPS('local', this.m_simulatedLat, this.m_simulatedLng, id, ip, port, function (e) {\n            console.log(e);\n        });\n        window.open(url, '_blank');\n    }\n\n    private _listenOnChannels() {\n        this.cancelOnDestroy(\n            //\n            this.yp.listenBlockChannelSelectedOrChanged()\n                .mergeMap((i_campaignTimelineChanelPlayersModel: CampaignTimelineChanelPlayersModel) => {\n                    return this.bs.getBlockData(i_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId())\n                })\n                .subscribe((blockData: IBlockData) => {\n                    this.m_blockData = blockData;\n                    this.render();\n\n                }, (e) => console.error(e))\n        )\n    }\n\n    private _listenOnScenes() {\n        this.cancelOnDestroy(\n            //\n            this.yp.listenSceneOrBlockSelectedChanged()\n                .mergeMap((i_sceneData: ISceneData) => {\n                    return this.bs.getBlockDataInScene(i_sceneData)\n                })\n                .subscribe((blockData: IBlockData) => {\n                    this.m_blockData = blockData;\n                    this.render();\n                }, (e) => console.error(e))\n        )\n    }\n\n    render() {\n        this.markers = [];\n        var domPlayerData = this.bs.getBlockPlayerData(this.m_blockData)\n        $(domPlayerData).find('GPS').children().each((k, v) => {\n            var marker: LocationMarkModel = new LocationMarkModel({\n                draggable: false,\n                label: '',\n                lat: parseFloat(jXML(v).attr('lat')),\n                lng: parseFloat(jXML(v).attr('lng')),\n                radius: parseFloat(jXML(v).attr('radios')) * 1000, // convert to meters\n            });\n            this.markers.push(marker);\n            //map.points.push(point);\n\n        });\n        if (this.markers.length > 0)\n            this.setCenter(this.markers[0].lat, this.markers[0].lng);\n        this.forceUpdateUi()\n    }\n\n    clickedMarker(i_marker: LocationMarkModel, index: number) {\n        if (this.inSimMode)\n            return this._simulateEvent(i_marker, true);\n        // con(`clicked the marker: ${i_marker.label || index}`)\n        var uiState: IUiState = {locationMap: {locationMarkerSelected: i_marker}}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    mapClicked($event: MouseEvent) {\n        let marker: LocationMarkModel = new LocationMarkModel({\n            id: Math.random(),\n            radius: 10000,\n            lat: $event['coords'].lat,\n            lng: $event['coords'].lng,\n            draggable: true,\n            new: true\n        });\n\n        if (this.inSimMode)\n            return this._simulateEvent(marker, false);\n\n        // enable code below if you wish to add new marker and not through reactive\n        // this.markers.push(marker);\n        // this.forceUpdateUi();\n        var uiState: IUiState = {locationMap: {locationMarkerSelected: marker}}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    markerDragEnd(m: LocationMarkModel, $event: MouseEvent) {\n        console.log('dragEnd', m, $event);\n    }\n\n    _close() {\n        var uiState: IUiState = {\n            locationMap: {\n                loadLocationMap: false\n            }\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.onClose.emit()\n    }\n\n    public forceUpdateUi() {\n        this.cd.detach();\n        setTimeout(() => {\n            this.cd.reattach();\n            this.googleMaps.triggerResize();\n            this.cd.markForCheck();\n        }, 300)\n    }\n\n    public setCenter(lat, lng) {\n        // for private access to all APIs do:\n        this.googleMaps['_mapsWrapper'].setCenter({\n            lat: lat,\n            lng: lng,\n        });\n        this.forceUpdateUi();\n    }\n\n    destroy() {\n    }\n}\n\n\n/**\n Create the google map and listen to corresponding events such map clicks (not within a circle or marker)\n as well as the Search box find input etc\n @method _createMap\n **/\n// _createMap() {\n//     var self = this;\n//     google.maps.LatLng.prototype.destinationPoint = function (brng, dist) {\n//         dist = dist / 6371;\n//         brng = brng.toRad();\n//\n//         var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();\n//\n//         var lat2:any = Math.asin(Math.sin(lat1) * Math.cos(dist) +\n//             Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));\n//\n//         var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *\n//                 Math.cos(lat1),\n//                 Math.cos(dist) - Math.sin(lat1) *\n//                 Math.sin(lat2));\n//\n//         if (isNaN(lat2) || isNaN(lon2)) return null;\n//\n//         return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());\n//     };\n//\n//     var pointA = new google.maps.LatLng(34.155260, -118.787163);   // Circle center\n//     var radius = 1; // 10km\n//\n//     var mapOpt = {\n//         mapTypeId: google.maps.MapTypeId.TERRAIN,\n//         center: pointA,\n//         zoom: 10\n//     };\n//     var map = $('.map', self.el.nativeElement);\n//     // self.m_map = new google.maps.Map(map[0], mapOpt);\n//     console.log(this.googleMaps);\n\n/*\n\n // Create the search box and link it to the UI element.\n //var input = $('#pac-input', self.el)[0];\n var c = $('.inputPlacement', self.el);\n $(c).append('<input class=\"pac-input\" class=\"controls\" type=\"text\" placeholder=\"Search Box\">');\n var input = $(c).find('input')[0];\n\n\n var searchBox = new google.maps.places.SearchBox(input);\n self.m_map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);\n\n // Bias the SearchBox results towards current map's viewport.\n self.m_map.addListener('bounds_changed', function () {\n searchBox.setBounds(self.m_map.getBounds());\n });\n\n var markers = [];\n // Listen for the event fired when the user selects a prediction and retrieve details for location\n searchBox.addListener('places_changed', function () {\n var places = searchBox.getPlaces();\n\n if (places.length == 0) {\n return;\n }\n\n // Clear out the old markers.\n markers.forEach(function (marker) {\n marker.setMap(null);\n });\n markers = [];\n\n // For each place, get the icon, name and location.\n var bounds = new google.maps.LatLngBounds();\n places.forEach(function (place) {\n var icon = {\n url: place.icon,\n size: new google.maps.Size(71, 71),\n origin: new google.maps.Point(0, 0),\n anchor: new google.maps.Point(17, 34),\n scaledSize: new google.maps.Size(25, 25)\n };\n\n // Create a marker for each place.\n markers.push(new google.maps.Marker({\n map: self.m_map,\n icon: icon,\n title: place.name,\n position: place.geometry.location\n }));\n\n if (place.geometry.viewport) {\n // Only geocodes have viewport.\n bounds.union(place.geometry.viewport);\n } else {\n bounds.extend(place.geometry.location);\n }\n });\n self.m_map.fitBounds(bounds);\n });\n\n google.maps.event.addListener(self.m_map, 'click', function (event) {\n var lat = event.latLng.lat();\n var lng = event.latLng.lng();\n if (self._getSimulationMode()) {\n console.log('out of range ' + lat + ' ' + lng);\n self._simulateEvent(lat, lng, false);\n return;\n }\n if (self.m_markerOnClick) {\n self.addPoint(event.latLng, 0.10);\n self.m_markerOnClick = false;\n BB.comBroker.fire(BB.EVENTS.ADD_LOCATION_POINT, self, null, {lat: lat, lng: lng});\n }\n });\n */\n//}\n\n\n// export interface IMarker {\n//     lat: number;\n//     lng: number;\n//     radius: number;\n//     draggable: boolean;\n//     new:boolean;\n// }\n\n"
  },
  {
    "path": "src/app/resources/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {ResourcesNavigation} from \"./resources-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {Orders} from \"./orders\";\nimport {ResourcePropsManager} from \"./resource-props-manager\";\nimport {Resources} from \"./resources\";\nimport {ResourcesList} from \"./resources-list\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: ResourcesNavigation},\n    {path: ':folder/:id', component: ResourcesNavigation},\n    {path: '**', component: ResourcesNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [ResourcesNavigation, Orders, ResourcePropsManager, Resources, ResourcesList]\n})\nexport class ResourcesLazyModule {\n}"
  },
  {
    "path": "src/app/resources/orders.ts",
    "content": "import {Component, ChangeDetectionStrategy} from \"@angular/core\";\n\n@Component({\n    selector: 'orders',\n    styles: [`\n        .page {\n            padding-left: 100px;\n            padding-top: 40px;\n        }\n    `],\n    template: `\n               <Sliderpanel style=\"padding: 200px\">\n                  <div>\n                    <Slideritem class=\"page center order1 selected\" [toDirection]=\"'left'\" [to]=\"'order2'\">\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                      <h1>Order 1</h1>\n                    </Slideritem>\n                    <Slideritem class=\"page right order2\" class=\"page right order2\" [toDirection]=\"'left'\" [fromDirection]=\"'right'\" [from]=\"'order1'\" [to]=\"'order3'\">\n                      <h1>Order 2</h1>\n                    </Slideritem>\n                    <Slideritem class=\"page right order3\" [fromDirection]=\"'right'\" [from]=\"'order2'\" >\n                      <h1>Order 3</h1>\n                    </Slideritem>\n                  </div>\n                </Sliderpanel>\n    `,\n    changeDetection: ChangeDetectionStrategy.OnPush\n})\n\nexport class Orders {\n}\n\n"
  },
  {
    "path": "src/app/resources/resource-props-manager.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Observable} from \"rxjs\";\nimport {SideProps} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {ResourcesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {Lib} from \"../../Lib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\n\n@Component({\n    selector: 'resource-props-manager',\n    styles: [`\n        ul {\n            padding: 0\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <hr/>\n        <ul matchBodyHeight=\"50\" style=\"overflow-y: auto; overflow-x: hidden\" [ngSwitch]=\"m_sideProps$ | async\">\n            <div *ngSwitchCase=\"m_sidePropsEnum.resourceProps\">\n                <h5><i class=\"fa fa-{{m_formatIcon}}\"></i>resource property</h5>\n                <input class=\"form-control\" inlength=\"1\" placeholder=\"resource name\" (blur)=\"_onUpdateResourceName($event)\" [(ngModel)]=\"m_resourceName\" type=\"text\"/>\n                <br/>\n                <div [ngSwitch]=\"m_resourceType\">\n                    <div *ngSwitchCase=\"'image'\">\n                        <img style=\"width: 100%\" class=\"img-responsive\" [src]=\"m_imagePath\"/>\n                    </div>\n                    <div *ngSwitchCase=\"'svg'\">\n                        <svg-icon style=\"padding-left: 30px\" [height]=\"'300'\" [width]=\"'260'\" [path]=\"m_svgPath\"></svg-icon>\n                        \n                    </div>\n                </div>\n                <div [ngSwitch]=\"m_resourceType\">\n                    <div *ngSwitchCase=\"'video'\">\n                        <div style=\"width: 100%; height: 200px\">\n                            <media-player [playResource]=\"m_playResource\"></media-player>\n                        </div>\n                    </div>\n                </div>\n                <div [ngSwitch]=\"m_resourceType\">\n                    <div *ngSwitchCase=\"'swf'\">\n                        <p>Flash swf content</p>\n                        <div class=\"col-xs-4\"></div>\n                        <i style=\"color: red\" class=\"fa-5x col-xs-4 fa fa-flash\"></i>\n                        <div class=\"col-xs-4\"></div>\n                    </div>\n                </div>\n\n            </div>\n\n            <div *ngSwitchCase=\"m_sidePropsEnum.miniDashboard\">\n                <dash-panel-mini></dash-panel-mini>\n            </div>\n\n        </ul>\n\n\n\n    `,\n})\nexport class ResourcePropsManager extends Compbaser {\n\n    m_resourceType;\n    m_sideProps$: Observable<SideProps>;\n    m_sidePropsEnum = SideProps;\n    m_uiUserFocusItem$: Observable<SideProps>;\n    m_formatIcon = '';\n    m_resourceName = '';\n    m_selectedResource: ResourcesModel;\n    m_playResource = '';\n    m_svgPath = '';\n    m_imagePath = '';\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.m_uiUserFocusItem$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n        this.m_sideProps$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenResourceSelected()\n                .subscribe((i_resource: ResourcesModel) => {\n                    this.m_selectedResource = i_resource;\n                    this.m_resourceName = this.m_selectedResource.getResourceName();\n                    switch (this.m_selectedResource.getResourceType()) {\n                        case 'svg':{\n                            this.m_formatIcon = 'spinner';\n                            this.m_resourceType = 'svg';\n\n\n                            path = window['g_protocol'] + this.rp.getUserData().domain + '/Resources/business' + this.rp.getUserData().businessID + '/resources/' + this.rp.getResourceNativeID(this.m_selectedResource.getResourceId()) + '.' + 'svg';\n                            path = $.base64.encode(path);\n                            // var path = window['g_protocol'] + 's3.signage.me/business' + this.rp.getUserData().businessID + '/resources/' + this.rp.getResourceNativeID(this.m_selectedResource.getResourceId()) + '.' + this.m_selectedResource.getResourceType();\n                            // var urlPath = $.base64.encode(path);\n                            // this.m_svgPath = 'https://secure.digitalsignage.com/proxyRequest/' + path;\n                            // console.log(this.m_svgPath);\n                            this.m_svgPath = 'https://secure.digitalsignage.com/proxyRequest/' + path;\n                            // this.m_svgPath = 'https://secure.digitalsignage.com/proxyRequest/aHR0cHM6Ly9wbHV0by5zaWduYWdlLm1lL1Jlc291cmNlcy9idXNpbmVzczM1ODYxMy9yZXNvdXJjZXMvMzQuc3Zn';\n                            break;\n                        }\n                        case 'jpg':\n                        case 'png': {\n                            this.m_formatIcon = 'image';\n                            this.m_resourceType = 'image';\n                            var path = 'http://' + 's3.signage.me/business' + this.rp.getUserData().businessID + '/resources/' + this.rp.getResourceNativeID(this.m_selectedResource.getResourceId()) + '.' + this.m_selectedResource.getResourceType();\n                            this.m_imagePath = path;\n                            break;\n                        }\n                        case 'm4v':\n                        case 'mp4':\n                        case 'flv': {\n                            this.m_formatIcon = 'video-camera';\n                            this.m_resourceType = 'video';\n                            var path = 'http://' + 's3.signage.me/business' + this.rp.getUserData().businessID + '/resources/' + this.rp.getResourceNativeID(this.m_selectedResource.getResourceId()) + '.' + this.m_selectedResource.getResourceType();\n                            this.m_playResource = path;\n                            // path = window['g_protocol'] + BB.Pepper.getUserData().domain + '/Resources/business' +  BB.Pepper.getUserData().businessID + '/resources/' + BB.Pepper.getResourceNativeID(i_recResource['resource_id']) + '.' + ext;\n                            console.log(path);\n                            break;\n                        }\n                        case 'swf': {\n                            this.m_formatIcon = 'bolt';\n                            this.m_resourceType = 'swf';\n                            break;\n                        }\n                    }\n                }, (e) => console.error(e))\n        )\n\n    }\n\n    _onUpdateResourceName(event) {\n        var text = Lib.CleanProbCharacters(this.m_resourceName, 1);\n        this.rp.setResourceRecord(this.m_selectedResource.getResourceId(), 'resource_name', text);\n        this.rp.reduxCommit();\n        // var elem = self.$el.find('[data-resource_id=\"' + this.m_selectedResource.getResourceId() + '\"]');\n        // elem.find('span').text(text);\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/resources/resources-list.ts",
    "content": "import {ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {ResourcesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {List} from \"immutable\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {IUiState} from \"../../store/store.data\";\nimport {SideProps} from \"../../store/actions/appdb.actions\";\n\n@Component({\n    selector: 'resources-list',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <ul style=\"padding: 10px\" (click)=\"$event.preventDefault()\" class=\"appList list-group\">\n            <a *ngFor=\"let resource of m_resources; let i = index\" (click)=\"_onSelected($event, resource, i)\"\n               [class.hidden]=\"resource | FilterModelPipe:filter:resource:'getResourceName'\"\n               [ngClass]=\"{'selectedItem': selectedIdx == i}\" href=\"#\" class=\"list-group-item resourcesListItems\">\n                <h4>{{resource.getResourceName()}}</h4>\n                <i class=\"pull-left fa {{bs.getFontAwesome(resource.getResourceType())}}\"></i>\n                <p class=\"pull-left list-group-item-text\">file type: {{resource.getResourceType()}} </p>         \n                <span class=\"clearfix\"></span>\n                <!--<div class=\"openProps\">-->\n                <!--<button type=\"button\" class=\"props btn btn-default btn-sm\"><i style=\"font-size: 1.5em\" class=\"props fa fa-gear\"></i></button>-->\n                <!--</div>-->\n            </a>\n        </ul>\n    `,\n})\nexport class ResourcesList extends Compbaser {\n    selectedIdx = -1;\n    m_resources: List<ResourcesModel>;\n    m_selected;\n\n    constructor(public bs: BlockService, private el: ElementRef) {\n        super();\n    }\n\n    @Input()\n    set resources(i_resources: List<ResourcesModel>) {\n        this.m_resources = i_resources;\n    }\n\n    \n    @Input() filter;\n\n    @Input()\n    set setViewMode(i_viewMode: 'grid' | 'list') {\n        if (i_viewMode == 'list') {\n            var query = $('.resourcesListItems', this.el.nativeElement);\n            $(query).addClass('col-xs-12');\n            $(query).removeClass('col-xs-3');\n        }\n\n        if (i_viewMode == 'grid') {\n            var query = $('.resourcesListItems', this.el.nativeElement);\n            $(query).addClass('col-xs-3');\n            $(query).removeClass('col-xs-12');\n        }\n    }\n\n\n    @Output()\n    onSelected: EventEmitter<ResourcesModel> = new EventEmitter<ResourcesModel>();\n\n    _onSelected(event: MouseEvent, i_resource: ResourcesModel, index) {\n        this.selectedIdx = index;\n        this.onSelected.emit(i_resource)\n        this.m_selected = i_resource;\n    }\n\n    resetSelection() {\n        this.selectedIdx = -1;\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/resources/resources-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {Compbaser} from \"ng-mslib\";\nimport {BlockService} from \"../blocks/block-service\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    providers: [BlockService, {\n        provide: \"BLOCK_PLACEMENT\",\n        useValue: ''\n    }\n    ],\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <small class=\"debug\">resource-navigation</small>\n        <panel-split-container>\n            <panel-split-main>\n                <resources>\n                </resources>\n            </panel-split-main>\n            <panel-split-side>\n                <resource-props-manager></resource-props-manager>\n            </panel-split-side>\n        </panel-split-container>\n    `,\n})\nexport class ResourcesNavigation extends Compbaser {\n\n    constructor() {\n        super();\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/resources/resources.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ResourcesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {List} from \"immutable\";\nimport {Observable} from \"rxjs\";\nimport {Compbaser} from \"ng-mslib\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_LIVELOG_UPDATE, ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\n\n@Component({\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'resources',\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div id=\"resourcesPanel\">\n            <label class=\"myFile\">\n                <button type=\"button\" class=\"btn btn-danger\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-plus\"></i>\n                    <span i18n>upload files</span>\n                </button>\n                <input id=\"file\"(change)=\"_onFileUpload($event)\" type=\"file\" title=\"add files\" data-filename-placement=\"inside\" multiple data-role=\"none\" accept=\".flv,.mp4,.jpg,.png,.swf,.svg\"/>\n                <!--<input id=\"file\" name=\"file\" type=\"file\" accept=\".flv,.mp4,.jpg,.png,.swf,.svg\" class=\"btn-primary\" title=\"add files\" data-filename-placement=\"inside\" multiple data-role=\"none\">-->\n            </label>\n            <div class=\"btn-group\">\n                <button (click)=\"_onRemove()\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-minus\"></i>\n                    <span i18n>remove</span>\n                </button>\n                <button (click)=\"m_viewMode='list'\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-list\"></i>\n                    <span i18n>list</span>\n                </button>\n                <button (click)=\"m_viewMode='grid'\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-table\"></i>\n                    <span i18n>grid</span>\n                </button>\n                <input [(ngModel)]=\"m_filter\" style=\"width: 200px\" id=\"resourcesFilterList\" class=\"form-control\" placeholder=\"search for\" required=\"\">\n            </div>\n            <h5 i18n>supported files: flv, mp4, jpg, png, swf and svg</h5>\n            <div id=\"resourceLibListWrap\">\n                <ul id=\"resourceLibList\" class=\"list-group row\"></ul>\n            </div>\n        </div>\n        <!-- move scroller to proper offset -->\n        <div class=\"responsive-pad-right\">\n            <div matchBodyHeight=\"150\" style=\"overflow: scroll\">\n                <resources-list [filter]=\"m_filter\" [setViewMode]=\"m_viewMode\" [resources]=\"m_resourceModels$ | async\" (onSelected)=\"_onSelected($event)\">\n                </resources-list>\n            </div>\n        </div>\n    `,\n    styles: [`\n\n        /*:host /deep/ vg-player {*/\n        /*background-color: transparent;*/\n        /*margin: 30px;*/\n        /*width: 30%;*/\n        /*height: calc(100% - 60px);*/\n        /*}*/\n\n        /*:host /deep/ vg-player {*/\n        /*background-color: transparent;*/\n        /*margin: 30px;*/\n        /*width: 30%;*/\n        /*height: calc(100% - 60px);*/\n        /*}*/\n\n        * {\n            border-radius: 0 !important;\n        }\n\n        vg-player {\n            background-color: transparent;\n            margin: 30px;\n            width: 30%;\n            height: calc(100% - 60px);\n        }\n\n        vg-controls {\n            padding: 30px;\n            transition: all 1s;\n        }\n\n        #resourcesPanel {\n            padding: 10px;\n        }\n\n        .myFile {\n            position: relative;\n            overflow: hidden;\n            float: left;\n            clear: left;\n        }\n\n        .myFile input[type=\"file\"] {\n            display: block;\n            position: absolute;\n            top: 0;\n            right: 0;\n            opacity: 0;\n            font-size: 100px;\n            filter: alpha(opacity=0);\n            cursor: pointer;\n        }\n    `]\n})\n\nexport class Resources extends Compbaser {\n\n    m_filter;\n    m_resourceModel: ResourcesModel;\n    m_viewMode = 'list';\n    m_resourceModels$: Observable<List<ResourcesModel>>;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private bs: BlockService) {\n        super();\n        this.m_resourceModels$ = this.yp.listenResources();\n        this.cancelOnDestroy(\n            //\n            this.yp.listenResourceSelected()\n                .subscribe((i_resources: ResourcesModel) => {\n                    this.m_resourceModel = i_resources;\n                }, (e) => console.error(e))\n        )\n    }\n\n    _onRemove() {\n        bootbox.confirm(`are you sure you want to remove ${this.m_resourceModel.getResourceName()}`, (i_result) => {\n            if (!i_result) return;\n            this.rp.removeResource(this.m_resourceModel.getResourceId());\n            this.rp.removeBlocksWithResourceID(this.m_resourceModel.getResourceId());\n            this.rp.removeResourceFromBlockCollectionInScenes(this.m_resourceModel.getResourceId());\n            this.rp.removeResourceFromBlockLocationInScenes(this.m_resourceModel.getResourceId());\n            this.rp.removeResourceFromBlockCollectionsInChannel(this.m_resourceModel.getResourceId());\n            this.rp.removeResourceFromBlockLocationInChannel(this.m_resourceModel.getResourceId());\n            this.rp.removeAllScenePlayersWithResource(this.m_resourceModel.getResourceId());\n            this.rp.reduxCommit();\n            let uiState: IUiState = {\n                uiSideProps: SideProps.miniDashboard,\n                resources: {resourceSelected: -1}\n            }\n            this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        });\n    }\n\n    _onFileUpload(event) {\n        var status: any = this.rp.uploadResources('file', this.bs);\n        if (status.length == 0) {\n            bootbox.alert('The file format is not supported');\n            return -1;\n        }\n        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'uploaded resource'})}));\n    }\n\n    _onSelected(i_resource: ResourcesModel) {\n        let uiState: IUiState = {\n            uiSideProps: SideProps.resourceProps,\n            resources: {resourceSelected: i_resource.getResourceId()}\n        }\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n}\n\n"
  },
  {
    "path": "src/app/route-animation.ts",
    "content": "// import {trigger, state, animate, style, transition} from '@angular/core';\n//\n// export function routerTransition() {\n//     return animateRoute();\n// }\n//\n// function animateRoute() {\n//     return trigger('routerTransition', [\n//         state('*', style({opacity: 1})),\n//         transition('void => *', [\n//             style({opacity: 0}),\n//             animate(333)\n//         ]),\n//         transition('* => void', animate(333, style({opacity: 0})))\n//     ]);\n// }"
  },
  {
    "path": "src/app/scenes/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {ScenesNavigation} from \"./scenes-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {ScenePropsManager} from \"./scene-props-manager\";\nimport {SceneList} from \"./scene-list\";\nimport {SceneManager} from \"./scene-manager\";\nimport {Scenes} from \"./scenes\";\nimport {SceneEditor} from \"./scene-editor\";\nimport {SceneToolbar} from \"./scene-toolbar\";\nimport {BlockPropPosition} from \"../blocks/block-prop-position\";\nimport {Ng2Bs3ModalModule} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {SceneCreator} from \"./scene-creator\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: ScenesNavigation},\n    {path: ':folder/:id', component: ScenesNavigation},\n    {path: '**', component: ScenesNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, Ng2Bs3ModalModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [Scenes, SceneEditor, SceneCreator, SceneToolbar, ScenesNavigation, ScenePropsManager, SceneManager, SceneList, BlockPropPosition]\n})\nexport class ScenesLazyModule {\n}"
  },
  {
    "path": "src/app/scenes/scene-creator.css",
    "content": "\n.profileCard {\n    margin-bottom: 20px;\n}\n\n.profileCard {\n    border-radius: 2px;\n    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);\n    padding: 15px;\n    margin-top: 60px;\n    float: left;\n    height: 333px;\n    background-color: #FFF;\n    cursor: pointer;\n    position: relative;\n    top:0;\n    left: 0;\n    /*transition-property: top, left, box-shadow;*/\n    transition-property: top;\n    transition-duration: 0.3s;\n}\n\n.sceneImportThumb {\n    width: 139px;\n    height: 78px;\n    border: solid 2px gray;\n    cursor: pointer;\n    transition: all .2s ease-in-out;\n}\n\n.sceneImportThumb:hover {\n    transform: scale(1.1);\n}\n\n\n.profileCard:hover {\n    top: -7px;\n    /*left: 4px;*/\n    /*z-index: 200;*/\n    /*-webkit-box-shadow: 18px 24px 16px -3px rgba(0,0,0,0.25);*/\n    /*-moz-box-shadow: 18px 24px 16px -3px rgba(0,0,0,0.25);*/\n    /*box-shadow: 18px 24px 16px -3px rgba(0,0,0,0.25);*/\n\n}\n\n.profileCard .pImg {\n    background-color: #40a5ec;\n    border-radius: 50% !important;\n    display: table;\n    height: 100px;\n    margin: 0 auto;\n    width: 100px;\n    margin-top: -60px;\n}\n\n.profileCard .pImg span {\n    color: #fff;\n    display: table-cell;\n    text-align: center;\n    vertical-align: middle;\n}\n\n.profileCard1 .pDes > p {\n    color: #717171;\n    font-size: 13px;\n    padding-top: 10px;\n    text-align: justify;\n}\n\n.profileCard1 .pDes > a {\n    background-color: #03a9f4;\n    border-radius: 2px;\n    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);\n    color: #fff;\n    transition: all 0.5s ease 0s;\n    position: absolute;\n    top: 285px;\n    opacity: 0.3;\n\n\n}\n\n.profileCard1 .pDes > a {\n    background-color: #03a9f4;\n    border-radius: 2px;\n    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);\n    color: #fff;\n    transition: all 0.5s ease 0s;\n}\n\n.profileCard1 .pDes > a:hover {\n    background-color: #0288d1;\n    box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.16), 0 2px 5px 0 rgba(0, 0, 0, 0.12);\n    color: #fff;\n    transition: all 0.5s ease 0s;\n}\n"
  },
  {
    "path": "src/app/scenes/scene-creator.ts",
    "content": "import {Component, ChangeDetectionStrategy, AfterViewInit, Output, EventEmitter, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {BlockService} from \"../blocks/block-service\";\nimport * as _ from 'lodash';\nimport {Lib} from \"../../Lib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_LIVELOG_UPDATE, ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {PLACEMENT_IS_SCENE} from \"../../interfaces/Consts\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\n\n@Component({\n    selector: 'scene-creator',\n    styleUrls: ['./scene-creator.css'],\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <button (click)=\"_goBack()\" type=\"button\" style=\"margin-left: 8px\" title=\"add new timeline\" class=\"btn btn-default btn-sm\">\n            <span class=\"glyphicon glyphicon-chevron-left\"></span>\n        </button>\n        <div class=\"clearfix\"></div>\n        <div *ngIf=\"m_selectTypeMode\" style=\"padding: 5px 20px 0px 15px\">\n            <div *ngFor=\"let category of m_sceneCategories\" (click)=\"_onAddScene(category)\" class=\"col-xs-12 col-sm-6 col-md-6 col-lg-4 profileCard\">\n                <div class=\"profileCard1\">\n                    <div class=\"pImg\">\n                        <span class=\"fa {{category.icon}} fa-4x\"></span>\n                    </div>\n                    <div class=\"pDes\">\n                        <h1 class=\"text-center\">{{category.name}}</h1>\n                        <p>{{category.description}}</p>\n                        <a class=\"btn btn-md\">\n                            <span class=\"fa fa-plus fa-2x\"></span>\n                        </a>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <div *ngIf=\"!m_selectTypeMode\" style=\"padding: 20px\">\n            <div (click)=\"_onTemplateSelected(account)\" *ngFor=\"let account of m_sceneAccounts\" class=\"col-xs-1\" style=\"margin: 10px\">\n                <img class=\"sceneImportThumb\" src=\"https://secure.digitalsignage.com/studioweb/assets/scenes/{{account.sceneName}}.jpg\"/>\n                <!--<img class=\"sceneImportThumb\" src=\"../assets/scenes/{{account.sceneName}}.jpg\"/>-->\n            </div>\n        </div>\n        <modal (onClose)=\"_onSceneImport()\" #modal>\n            <modal-header [show-close]=\"true\">\n                <h4 i18n class=\"modal-title\">import template</h4>\n            </modal-header>\n            <modal-body>\n                <img [src]=\"m_largePreview\" style=\"width: 512px; height: 286px; position: relative; left: 28px\">\n            </modal-body>\n            <modal-footer [close-button-label]=\"'download'\" [show-default-buttons]=\"true\"></modal-footer>\n        </modal>\n    `,\n})\nexport class SceneCreator extends Compbaser implements AfterViewInit {\n\n    m_selectedAccount;\n    m_largePreview = '';\n    m_sceneCategories = [];\n    m_sceneAccounts = [];\n    m_selectTypeMode = true;\n    m_sceneTemplates;\n    m_selectedSceneMime: string;\n\n    constructor(private yp: YellowPepperService, private bs: BlockService, private rp: RedPepperService, private toastr: ToastsManager) {\n        super();\n        this._initSceneTemplates();\n    }\n\n    @ViewChild(ModalComponent)\n    modal: ModalComponent;\n\n    @Output()\n    onGoBack: EventEmitter<any> = new EventEmitter<any>();\n\n    ngAfterViewInit() {\n\n        this.m_sceneCategories = [\n            {\n                name: 'from empty',\n                mimeType: 'blank',\n                icon: 'fa-star',\n                description: 'Create your own design, simply start with a blank scene and mix in your favorite images, videos, SVG graphics and even smart components. Get all the power to design your own custom scene.'\n            },\n            {\n                name: 'from template',\n                mimeType: 'template',\n                icon: 'fa-paint-brush',\n                description: 'With hundreds of beautiful pre-made designs you are sure to find something you like. The scene templates are preloaded with images and labels so its a great way to get started'\n            }\n        ];\n\n        var blocks = (this.bs.getBlocks());\n        _.forEach(blocks, (block: any) => {\n            if (block.mimeType) {\n                this.m_sceneCategories.push({\n                    name: block.description,\n                    mimeType: block.mimeType,\n                    icon: block.fontAwesome,\n                    description: block.jsonItemLongDescription\n                });\n            }\n        });\n\n        this.cancelOnDestroy(\n            this.yp.listenMainAppState()\n                .skip(1)\n                .subscribe(i_status => {\n                    if (i_status == MainAppShowStateEnum.SAVED) {\n                        this.toastr.info('scene imported and is available in scene list');\n                        this._goBack();\n                    }\n                })\n        )\n\n    }\n\n    _onSceneImport() {\n        this.rp.loaderManager.importScene(this.m_selectedAccount.businessId, this.m_selectedAccount.nativeId, (i_SceneId) => {\n            this.rp.injectPseudoScenePlayersIDs(i_SceneId);\n            let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE}\n            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n            this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'scene imported id: ' + i_SceneId})}));\n        });\n    }\n\n    _onTemplateSelected(account) {\n        this.m_selectedAccount = account;\n        this.m_largePreview = `http://s3.signage.me/business1000/resources/scenes_snaps/${account.sceneName}.png`\n        this.modal.open();\n    }\n\n    private _getTemplates() {\n        this.m_sceneAccounts = [];\n        for (var sceneName in this.m_sceneTemplates) {\n            var sceneConfig = this.m_sceneTemplates[sceneName];\n\n            switch (this.m_selectedSceneMime) {\n                case 'Json.digg': {\n                    if (sceneName.indexOf('Digg') == -1)\n                        continue;\n                    break;\n                }\n                case 'Json.twitter': {\n                    if (sceneName.indexOf('Twitter') == -1)\n                        continue;\n                    break;\n                }\n                case 'Json.instagram': {\n                    if (sceneName.indexOf('Instagram') == -1)\n                        continue;\n                    break;\n                }\n                case 'Json.calendar': {\n                    if (sceneName.indexOf('Calendar') == -1)\n                        continue;\n                    break;\n                }\n                case 'Json.spreadsheet': {\n                    if (sceneName.indexOf('Sheet') == -1)\n                        continue;\n                    break;\n                }\n                case 'Json.weather': {\n                    if (sceneName.indexOf('Weather') == -1)\n                        continue;\n                    break;\n                }\n                default: {\n                }\n            }\n            this.m_sceneAccounts.push({\n                nativeId: sceneConfig[2],\n                sceneName: sceneName,\n                businessId: sceneConfig[0],\n                src: `_assets/scenes/'${sceneName}.jpg`\n            })\n        }\n        this.m_sceneAccounts.pop();\n    }\n\n    _onAddScene(category) {\n        switch (category.mimeType) {\n            case 'blank': {\n                this._nameScene((i_name) => {\n                    if (_.isUndefined(i_name) || i_name.length == 0)\n                        return;\n                    var player_data = this.bs.getBlockBoilerplate('3510').getDefaultPlayerData(PLACEMENT_IS_SCENE);\n                    var sceneId = this.rp.createScene(player_data, '', i_name);\n                    this.rp.reduxCommit();\n                    this.toastr.info('scene imported and is available in scene list');\n                    this._goBack();\n                });\n                return;\n            }\n            case 'template': {\n\n                this.m_selectedSceneMime = 'all';\n                break;\n            }\n            case 'Json.digg': {\n                this.m_selectedSceneMime = 'Json.digg';\n                break;\n            }\n            case 'Json.twitter': {\n                this.m_selectedSceneMime = 'Json.twitter';\n                break;\n            }\n            case 'Json.instagram.feed': {\n                this.m_selectedSceneMime = 'Json.instagram';\n                break;\n            }\n            case 'Json.calendar': {\n                this.m_selectedSceneMime = 'Json.calendar';\n                break;\n            }\n            case 'Json.weather': {\n                this.m_selectedSceneMime = 'Json.weather';\n                break;\n            }\n            case 'Json.spreadsheet': {\n                this.m_selectedSceneMime = 'Json.spreadsheet';\n                break;\n            }\n\n        }\n        this._getTemplates();\n        this.m_selectTypeMode = false;\n\n\n    }\n\n    _goBack() {\n        this.onGoBack.emit()\n    }\n\n    private _nameScene(i_cb) {\n        bootbox.prompt(\"Give your scene a name:\", (result) => {\n            if (result === null) {\n                i_cb();\n            } else {\n                result = Lib.CleanChar(result);\n                i_cb(result);\n            }\n        });\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n\n    private _initSceneTemplates() {\n        this.m_sceneTemplates = {\n            Template21: [396594, 'ida.signage.me', 50],\n            Template18: [396594, 'ida.signage.me', 47],\n            Template23: [396594, 'ida.signage.me', 52],\n            Template24: [396594, 'ida.signage.me', 53],\n            Template22: [396594, 'ida.signage.me', 51],\n            Template6: [396594, 'ida.signage.me', 34],\n            Template13: [396594, 'ida.signage.me', 42],\n            Template8: [396594, 'ida.signage.me', 36],\n            Template10: [396594, 'ida.signage.me', 39],\n            Template12: [396594, 'ida.signage.me', 41],\n            Template1: [396594, 'ida.signage.me', 29],\n            Template4: [396594, 'ida.signage.me', 32],\n            Template5: [396594, 'ida.signage.me', 33],\n            Template7: [396594, 'ida.signage.me', 35],\n            Template3: [396594, 'ida.signage.me', 31],\n            Template9: [396594, 'ida.signage.me', 38],\n            Template2: [396594, 'ida.signage.me', 30],\n            Template11: [396594, 'ida.signage.me', 40],\n            Template15: [396594, 'ida.signage.me', 44],\n            Template16: [396594, 'ida.signage.me', 45],\n            Template14: [396594, 'ida.signage.me', 43],\n            Template17: [396594, 'ida.signage.me', 46],\n            Template19: [396594, 'ida.signage.me', 48],\n            Template20: [396594, 'ida.signage.me', 49],\n            Template26: [396595, 'ida.signage.me', 4],\n            Template40: [396595, 'ida.signage.me', 18],\n            Template42: [396595, 'ida.signage.me', 21],\n            Template34: [396595, 'ida.signage.me', 12],\n            Template27: [396595, 'ida.signage.me', 5],\n            Template38: [396595, 'ida.signage.me', 16],\n            Template35: [396595, 'ida.signage.me', 13],\n            Template37: [396595, 'ida.signage.me', 15],\n            Template39: [396595, 'ida.signage.me', 17],\n            Template36: [396595, 'ida.signage.me', 14],\n            Template29: [396595, 'ida.signage.me', 7],\n            Template44: [396595, 'ida.signage.me', 23],\n            Template43: [396595, 'ida.signage.me', 22],\n            Template32: [396595, 'ida.signage.me', 10],\n            Template46: [396595, 'ida.signage.me', 24],\n            Template41: [396595, 'ida.signage.me', 19],\n            Template45: [396595, 'ida.signage.me', 25],\n            Template47: [396595, 'ida.signage.me', 20],\n            Template48: [396595, 'ida.signage.me', 26],\n            Template25: [396595, 'ida.signage.me', 3],\n            Template28: [396595, 'ida.signage.me', 6],\n            Template30: [396595, 'ida.signage.me', 8],\n            Template31: [396595, 'ida.signage.me', 9],\n            Template33: [396595, 'ida.signage.me', 11],\n            Template57: [396596, 'ida.signage.me', 14],\n            Template59: [396596, 'ida.signage.me', 16],\n            Template58: [396596, 'ida.signage.me', 15],\n            Template62: [396596, 'ida.signage.me', 19],\n            Template61: [396596, 'ida.signage.me', 18],\n            Template53: [396596, 'ida.signage.me', 10],\n            Template65: [396596, 'ida.signage.me', 22],\n            Template63: [396596, 'ida.signage.me', 20],\n            Template66: [396596, 'ida.signage.me', 23],\n            Template67: [396596, 'ida.signage.me', 24],\n            Template64: [396596, 'ida.signage.me', 21],\n            Template68: [396596, 'ida.signage.me', 25],\n            Template70: [396596, 'ida.signage.me', 27],\n            Template72: [396596, 'ida.signage.me', 29],\n            Template51: [396596, 'ida.signage.me', 8],\n            Template52: [396596, 'ida.signage.me', 9],\n            Template50: [396596, 'ida.signage.me', 7],\n            Template71: [396596, 'ida.signage.me', 28],\n            Template49: [396596, 'ida.signage.me', 6],\n            Template54: [396596, 'ida.signage.me', 11],\n            Template55: [396596, 'ida.signage.me', 12],\n            Template56: [396596, 'ida.signage.me', 13],\n            Template60: [396596, 'ida.signage.me', 17],\n            Template69: [396596, 'ida.signage.me', 26],\n            Template81: [396597, 'ida.signage.me', 25],\n            Template73: [396597, 'ida.signage.me', 17],\n            Template78: [396597, 'ida.signage.me', 22],\n            Template79: [396597, 'ida.signage.me', 23],\n            Template84: [396597, 'ida.signage.me', 28],\n            Template76: [396597, 'ida.signage.me', 20],\n            Template77: [396597, 'ida.signage.me', 21],\n            Template86: [396597, 'ida.signage.me', 30],\n            Template87: [396597, 'ida.signage.me', 31],\n            Template85: [396597, 'ida.signage.me', 29],\n            Template83: [396597, 'ida.signage.me', 27],\n            Template90: [396597, 'ida.signage.me', 34],\n            Template91: [396597, 'ida.signage.me', 35],\n            Template92: [396597, 'ida.signage.me', 36],\n            Template89: [396597, 'ida.signage.me', 33],\n            Template95: [396597, 'ida.signage.me', 40],\n            Template94: [396597, 'ida.signage.me', 38],\n            Template88: [396597, 'ida.signage.me', 32],\n            Template75: [396597, 'ida.signage.me', 19],\n            Template93: [396597, 'ida.signage.me', 37],\n            Template74: [396597, 'ida.signage.me', 18],\n            Template82: [396597, 'ida.signage.me', 26],\n            Template80: [396597, 'ida.signage.me', 24],\n            Template96: [396598, 'ida.signage.me', 12],\n            Template98: [396598, 'ida.signage.me', 14],\n            Template99: [396598, 'ida.signage.me', 15],\n            Template100: [396598, 'ida.signage.me', 16],\n            Template97: [396598, 'ida.signage.me', 13],\n            Template116: [401213, 'ida.signage.me', 21],\n            Template117: [401213, 'ida.signage.me', 22],\n            Template102: [401213, 'ida.signage.me', 6],\n            Template105: [401213, 'ida.signage.me', 9],\n            Template109: [401213, 'ida.signage.me', 13],\n            Template101: [401213, 'ida.signage.me', 5],\n            Template108: [401213, 'ida.signage.me', 12],\n            Template111: [401213, 'ida.signage.me', 15],\n            Template110: [401213, 'ida.signage.me', 14],\n            Template113: [401213, 'ida.signage.me', 17],\n            Template112: [401213, 'ida.signage.me', 16],\n            Template115: [401213, 'ida.signage.me', 20],\n            Template119: [401213, 'ida.signage.me', 24],\n            Template114: [401213, 'ida.signage.me', 19],\n            Template106: [401213, 'ida.signage.me', 10],\n            Template103: [401213, 'ida.signage.me', 7],\n            Template104: [401213, 'ida.signage.me', 8],\n            Template107: [401213, 'ida.signage.me', 11],\n            Template120: [401213, 'ida.signage.me', 25],\n            Template118: [401213, 'ida.signage.me', 23],\n            Template127: [402393, 'ida.signage.me', 13],\n            Template123: [402393, 'ida.signage.me', 9],\n            Template122: [402393, 'ida.signage.me', 8],\n            Template121: [402393, 'ida.signage.me', 7],\n            Template124: [402393, 'ida.signage.me', 10],\n            Template125: [402393, 'ida.signage.me', 11],\n            Template126: [402393, 'ida.signage.me', 12],\n            Template128: [402393, 'ida.signage.me', 14],\n            Template130: [402393, 'ida.signage.me', 16],\n            Template129: [402393, 'ida.signage.me', 15],\n            Template140: [402394, 'ida.signage.me', 13],\n            Template132: [402394, 'ida.signage.me', 5],\n            Template137: [402394, 'ida.signage.me', 10],\n            Template138: [402394, 'ida.signage.me', 11],\n            Template135: [402394, 'ida.signage.me', 8],\n            Template136: [402394, 'ida.signage.me', 9],\n            Template131: [402394, 'ida.signage.me', 4],\n            Template133: [402394, 'ida.signage.me', 6],\n            Template134: [402394, 'ida.signage.me', 7],\n            Template139: [402394, 'ida.signage.me', 12],\n            Template142: [402395, 'ida.signage.me', 10],\n            Template146: [402395, 'ida.signage.me', 14],\n            Template141: [402395, 'ida.signage.me', 9],\n            Template144: [402395, 'ida.signage.me', 12],\n            Template145: [402395, 'ida.signage.me', 13],\n            Template143: [402395, 'ida.signage.me', 11],\n            Template148: [402395, 'ida.signage.me', 16],\n            Template147: [402395, 'ida.signage.me', 15],\n            Template149: [402395, 'ida.signage.me', 17],\n            Template150: [402395, 'ida.signage.me', 18],\n            Template155: [402397, 'ida.signage.me', 22],\n            Template154: [402397, 'ida.signage.me', 21],\n            Template151: [402397, 'ida.signage.me', 18],\n            Template152: [402397, 'ida.signage.me', 19],\n            Template153: [402397, 'ida.signage.me', 20],\n            Template156: [402397, 'ida.signage.me', 23],\n            Template157: [402397, 'ida.signage.me', 24],\n            Template158: [402397, 'ida.signage.me', 25],\n            Template159: [402397, 'ida.signage.me', 26],\n            Template160: [402397, 'ida.signage.me', 27],\n            Template168: [402398, 'ida.signage.me', 25],\n            Template169: [402398, 'ida.signage.me', 26],\n            Template161: [402398, 'ida.signage.me', 18],\n            Template162: [402398, 'ida.signage.me', 19],\n            Template164: [402398, 'ida.signage.me', 20],\n            Template163: [402398, 'ida.signage.me', 21],\n            Template165: [402398, 'ida.signage.me', 22],\n            Template167: [402398, 'ida.signage.me', 24],\n            Template166: [402398, 'ida.signage.me', 23],\n            Template170: [402398, 'ida.signage.me', 27],\n            Template171: [402399, 'ida.signage.me', 12],\n            Template174: [402399, 'ida.signage.me', 15],\n            Template172: [402399, 'ida.signage.me', 13],\n            Template176: [402399, 'ida.signage.me', 17],\n            Template173: [402399, 'ida.signage.me', 14],\n            Template178: [402399, 'ida.signage.me', 19],\n            Template177: [402399, 'ida.signage.me', 18],\n            Template179: [402399, 'ida.signage.me', 20],\n            Template180: [402399, 'ida.signage.me', 21],\n            Template175: [402399, 'ida.signage.me', 16],\n            Template187: [402400, 'ida.signage.me', 16],\n            Template188: [402400, 'ida.signage.me', 17],\n            Template181: [402400, 'ida.signage.me', 10],\n            Template182: [402400, 'ida.signage.me', 11],\n            Template183: [402400, 'ida.signage.me', 12],\n            Template184: [402400, 'ida.signage.me', 13],\n            Template185: [402400, 'ida.signage.me', 14],\n            Template186: [402400, 'ida.signage.me', 15],\n            Template190: [402400, 'ida.signage.me', 19],\n            Template189: [402400, 'ida.signage.me', 18],\n            Template192: [402401, 'ida.signage.me', 9],\n            Template193: [402401, 'ida.signage.me', 11],\n            Template194: [402401, 'ida.signage.me', 12],\n            Template197: [402401, 'ida.signage.me', 16],\n            Template198: [402401, 'ida.signage.me', 17],\n            Template199: [402401, 'ida.signage.me', 18],\n            Template200: [402401, 'ida.signage.me', 19],\n            Template191: [402401, 'ida.signage.me', 8],\n            Template195: [402401, 'ida.signage.me', 13],\n            Template196: [402401, 'ida.signage.me', 14],\n            Template204: [402402, 'ida.signage.me', 20],\n            Template206: [402402, 'ida.signage.me', 22],\n            Template201: [402402, 'ida.signage.me', 17],\n            Template202: [402402, 'ida.signage.me', 18],\n            Template203: [402402, 'ida.signage.me', 19],\n            Template205: [402402, 'ida.signage.me', 21],\n            Template207: [402402, 'ida.signage.me', 23],\n            Template208: [402402, 'ida.signage.me', 24],\n            Template209: [402402, 'ida.signage.me', 25],\n            Template210: [402402, 'ida.signage.me', 26],\n            Template214: [402444, 'ida.signage.me', 13],\n            Template213: [402444, 'ida.signage.me', 12],\n            Template212: [402444, 'ida.signage.me', 11],\n            Template219: [402444, 'ida.signage.me', 18],\n            Template211: [402444, 'ida.signage.me', 10],\n            Template215: [402444, 'ida.signage.me', 14],\n            Template216: [402444, 'ida.signage.me', 15],\n            Template217: [402444, 'ida.signage.me', 16],\n            Template218: [402444, 'ida.signage.me', 17],\n            Template220: [402444, 'ida.signage.me', 19],\n            Template227: [402446, 'ida.signage.me', 16],\n            Template222: [402446, 'ida.signage.me', 11],\n            Template224: [402446, 'ida.signage.me', 13],\n            Template230: [402446, 'ida.signage.me', 19],\n            Template221: [402446, 'ida.signage.me', 10],\n            Template223: [402446, 'ida.signage.me', 12],\n            Template225: [402446, 'ida.signage.me', 14],\n            Template226: [402446, 'ida.signage.me', 15],\n            Template228: [402446, 'ida.signage.me', 17],\n            Template229: [402446, 'ida.signage.me', 18],\n            Template238: [405214, 'ida.signage.me', 10],\n            Template231: [405214, 'ida.signage.me', 3],\n            Template232: [405214, 'ida.signage.me', 4],\n            Template233: [405214, 'ida.signage.me', 5],\n            Template236: [405214, 'ida.signage.me', 8],\n            Template237: [405214, 'ida.signage.me', 9],\n            Template239: [405214, 'ida.signage.me', 11],\n            Template240: [405214, 'ida.signage.me', 12],\n            Template235: [405214, 'ida.signage.me', 7],\n            Template234: [405214, 'ida.signage.me', 6],\n            Template241: [405215, 'ida.signage.me', 10],\n            Template247: [405215, 'ida.signage.me', 16],\n            Template248: [405215, 'ida.signage.me', 17],\n            Template242: [405215, 'ida.signage.me', 11],\n            Template243: [405215, 'ida.signage.me', 12],\n            Template244: [405215, 'ida.signage.me', 13],\n            Template245: [405215, 'ida.signage.me', 14],\n            Template246: [405215, 'ida.signage.me', 15],\n            Template249: [405215, 'ida.signage.me', 18],\n            Template250: [405215, 'ida.signage.me', 19],\n            Template258: [405216, 'ida.signage.me', 14],\n            Template253: [405216, 'ida.signage.me', 9],\n            Template256: [405216, 'ida.signage.me', 12],\n            Template257: [405216, 'ida.signage.me', 13],\n            Template251: [405216, 'ida.signage.me', 7],\n            Template254: [405216, 'ida.signage.me', 10],\n            Template255: [405216, 'ida.signage.me', 11],\n            Template259: [405216, 'ida.signage.me', 15],\n            Template252: [405216, 'ida.signage.me', 8],\n            Template260: [405216, 'ida.signage.me', 16],\n            Template267: [405217, 'ida.signage.me', 20],\n            Template261: [405217, 'ida.signage.me', 14],\n            Template262: [405217, 'ida.signage.me', 15],\n            Template268: [405217, 'ida.signage.me', 21],\n            Template266: [405217, 'ida.signage.me', 19],\n            Template265: [405217, 'ida.signage.me', 18],\n            Template270: [405217, 'ida.signage.me', 23],\n            Template263: [405217, 'ida.signage.me', 16],\n            Template264: [405217, 'ida.signage.me', 17],\n            Template269: [405217, 'ida.signage.me', 22],\n            Template273: [405218, 'ida.signage.me', 20],\n            Template274: [405218, 'ida.signage.me', 21],\n            Template275: [405218, 'ida.signage.me', 22],\n            Template279: [405218, 'ida.signage.me', 26],\n            Template271: [405218, 'ida.signage.me', 18],\n            Template272: [405218, 'ida.signage.me', 19],\n            Template278: [405218, 'ida.signage.me', 25],\n            Template276: [405218, 'ida.signage.me', 23],\n            Template277: [405218, 'ida.signage.me', 24],\n            Template280: [405218, 'ida.signage.me', 27],\n            Template283: [405219, 'ida.signage.me', 19],\n            Template284: [405219, 'ida.signage.me', 20],\n            Template286: [405219, 'ida.signage.me', 22],\n            Template281: [405219, 'ida.signage.me', 17],\n            Template282: [405219, 'ida.signage.me', 18],\n            Template285: [405219, 'ida.signage.me', 21],\n            Template287: [405219, 'ida.signage.me', 23],\n            Template288: [405219, 'ida.signage.me', 24],\n            Template289: [405219, 'ida.signage.me', 25],\n            Template290: [405219, 'ida.signage.me', 26],\n            Template294: [405220, 'ida.signage.me', 15],\n            Template295: [405220, 'ida.signage.me', 16],\n            Template293: [405220, 'ida.signage.me', 14],\n            Template297: [405220, 'ida.signage.me', 18],\n            Template291: [405220, 'ida.signage.me', 12],\n            Template292: [405220, 'ida.signage.me', 13],\n            Template296: [405220, 'ida.signage.me', 17],\n            Template298: [405220, 'ida.signage.me', 19],\n            Template299: [405220, 'ida.signage.me', 20],\n            Template300: [405220, 'ida.signage.me', 21],\n            Template306: [405221, 'ida.signage.me', 10],\n            Template307: [405221, 'ida.signage.me', 11],\n            Template309: [405221, 'ida.signage.me', 13],\n            Template301: [405221, 'ida.signage.me', 5],\n            Template302: [405221, 'ida.signage.me', 6],\n            Template303: [405221, 'ida.signage.me', 7],\n            Template304: [405221, 'ida.signage.me', 8],\n            Template305: [405221, 'ida.signage.me', 9],\n            Template308: [405221, 'ida.signage.me', 12],\n            Template310: [405221, 'ida.signage.me', 14],\n            Template311: [405222, 'ida.signage.me', 24],\n            Template313: [405222, 'ida.signage.me', 26],\n            Template314: [405222, 'ida.signage.me', 27],\n            Template315: [405222, 'ida.signage.me', 28],\n            Template312: [405222, 'ida.signage.me', 25],\n            Template317: [405222, 'ida.signage.me', 30],\n            Template316: [405222, 'ida.signage.me', 29],\n            Template319: [405222, 'ida.signage.me', 32],\n            Template318: [405222, 'ida.signage.me', 31],\n            Template320: [405222, 'ida.signage.me', 34],\n            Template321: [405223, 'ida.signage.me', 21],\n            Template326: [405223, 'ida.signage.me', 26],\n            Template325: [405223, 'ida.signage.me', 25],\n            Template329: [405223, 'ida.signage.me', 30],\n            Template324: [405223, 'ida.signage.me', 24],\n            Template328: [405223, 'ida.signage.me', 29],\n            Template322: [405223, 'ida.signage.me', 22],\n            Template323: [405223, 'ida.signage.me', 23],\n            Template327: [405223, 'ida.signage.me', 28],\n            //Template340: [405223,'ida.signage.me',32],\n            Template331: [405224, 'ida.signage.me', 27],\n            Template332: [405224, 'ida.signage.me', 28],\n            Template338: [405224, 'ida.signage.me', 35],\n            Template339: [405224, 'ida.signage.me', 36],\n            Template335: [405224, 'ida.signage.me', 32],\n            Template337: [405224, 'ida.signage.me', 34],\n            Template334: [405224, 'ida.signage.me', 31],\n            Template340: [405224, 'ida.signage.me', 37],\n            Template336: [405224, 'ida.signage.me', 33],\n            Template333: [405224, 'ida.signage.me', 30],\n            Template341: [407718, 'ida.signage.me', 4],\n            Template344: [407718, 'ida.signage.me', 7],\n            Template345: [407718, 'ida.signage.me', 8],\n            Template346: [407718, 'ida.signage.me', 9],\n            Template348: [407718, 'ida.signage.me', 11],\n            Template343: [407718, 'ida.signage.me', 6],\n            Template342: [407718, 'ida.signage.me', 5],\n            Template347: [407718, 'ida.signage.me', 10],\n            Template349: [407718, 'ida.signage.me', 12],\n            Template350: [407718, 'ida.signage.me', 13],\n            Template351: [407720, 'ida.signage.me', 5],\n            Template353: [407720, 'ida.signage.me', 7],\n            Template352: [407720, 'ida.signage.me', 6],\n            Template355: [407720, 'ida.signage.me', 9],\n            Template356: [407720, 'ida.signage.me', 11],\n            Template354: [407720, 'ida.signage.me', 10],\n            Template357: [407720, 'ida.signage.me', 12],\n            Template360: [407720, 'ida.signage.me', 15],\n            Template358: [407720, 'ida.signage.me', 13],\n            Template359: [407720, 'ida.signage.me', 14],\n            Template362: [407721, 'ida.signage.me', 6],\n            Template364: [407721, 'ida.signage.me', 8],\n            Template367: [407721, 'ida.signage.me', 11],\n            Template361: [407721, 'ida.signage.me', 5],\n            Template368: [407721, 'ida.signage.me', 12],\n            Template370: [407721, 'ida.signage.me', 14],\n            Template365: [407721, 'ida.signage.me', 9],\n            Template369: [407721, 'ida.signage.me', 13],\n            Template363: [407721, 'ida.signage.me', 7],\n            Template366: [407721, 'ida.signage.me', 10],\n            Template371: [407722, 'ida.signage.me', 15],\n            Template373: [407722, 'ida.signage.me', 16],\n            Template372: [407722, 'ida.signage.me', 17],\n            Template374: [407722, 'ida.signage.me', 18],\n            Template375: [407722, 'ida.signage.me', 19],\n            Template378: [407722, 'ida.signage.me', 21],\n            Template376: [407722, 'ida.signage.me', 20],\n            Template379: [407722, 'ida.signage.me', 23],\n            Template377: [407722, 'ida.signage.me', 22],\n            Template380: [407722, 'ida.signage.me', 24],\n            Template382: [407723, 'ida.signage.me', 28],\n            Template384: [407723, 'ida.signage.me', 30],\n            Template385: [407723, 'ida.signage.me', 31],\n            Template381: [407723, 'ida.signage.me', 27],\n            Template388: [407723, 'ida.signage.me', 34],\n            Template387: [407723, 'ida.signage.me', 33],\n            Template386: [407723, 'ida.signage.me', 32],\n            Template389: [407723, 'ida.signage.me', 35],\n            Template390: [407723, 'ida.signage.me', 36],\n            Template383: [407723, 'ida.signage.me', 29],\n            Template392: [407725, 'ida.signage.me', 17],\n            Template397: [407725, 'ida.signage.me', 22],\n            Template400: [407725, 'ida.signage.me', 25],\n            Template398: [407725, 'ida.signage.me', 23],\n            Template399: [407725, 'ida.signage.me', 24],\n            Template391: [407725, 'ida.signage.me', 16],\n            Template393: [407725, 'ida.signage.me', 18],\n            Template394: [407725, 'ida.signage.me', 19],\n            Template395: [407725, 'ida.signage.me', 20],\n            Template396: [407725, 'ida.signage.me', 21],\n            Template401: [407726, 'ida.signage.me', 18],\n            Template404: [407726, 'ida.signage.me', 21],\n            Template405: [407726, 'ida.signage.me', 22],\n            Template406: [407726, 'ida.signage.me', 23],\n            Template403: [407726, 'ida.signage.me', 20],\n            Template407: [407726, 'ida.signage.me', 24],\n            Template408: [407726, 'ida.signage.me', 25],\n            Template402: [407726, 'ida.signage.me', 19],\n            Template409: [407726, 'ida.signage.me', 26],\n            Template410: [407726, 'ida.signage.me', 27],\n            Template411: [407727, 'ida.signage.me', 8],\n            Template413: [407727, 'ida.signage.me', 10],\n            Template415: [407727, 'ida.signage.me', 12],\n            Template414: [407727, 'ida.signage.me', 11],\n            Template416: [407727, 'ida.signage.me', 13],\n            Template417: [407727, 'ida.signage.me', 14],\n            Template419: [407727, 'ida.signage.me', 16],\n            Template418: [407727, 'ida.signage.me', 15],\n            Template412: [407727, 'ida.signage.me', 9],\n            Template420: [407727, 'ida.signage.me', 17],\n            Template428: [407728, 'ida.signage.me', 17],\n            Template429: [407728, 'ida.signage.me', 18],\n            Template421: [407728, 'ida.signage.me', 10],\n            Template422: [407728, 'ida.signage.me', 11],\n            Template423: [407728, 'ida.signage.me', 12],\n            Template424: [407728, 'ida.signage.me', 13],\n            Template425: [407728, 'ida.signage.me', 14],\n            Template426: [407728, 'ida.signage.me', 15],\n            Template427: [407728, 'ida.signage.me', 16],\n            Template430: [407728, 'ida.signage.me', 19],\n            Template434: [407729, 'ida.signage.me', 22],\n            Template439: [407729, 'ida.signage.me', 27],\n            Template433: [407729, 'ida.signage.me', 21],\n            Template438: [407729, 'ida.signage.me', 26],\n            Template431: [407729, 'ida.signage.me', 19],\n            Template432: [407729, 'ida.signage.me', 20],\n            Template435: [407729, 'ida.signage.me', 23],\n            Template436: [407729, 'ida.signage.me', 24],\n            Template437: [407729, 'ida.signage.me', 25],\n            Template440: [407729, 'ida.signage.me', 28],\n            Template442: [407730, 'ida.signage.me', 13],\n            Template443: [407730, 'ida.signage.me', 14],\n            Template444: [407730, 'ida.signage.me', 15],\n            Template446: [407730, 'ida.signage.me', 17],\n            Template445: [407730, 'ida.signage.me', 16],\n            Template448: [407730, 'ida.signage.me', 19],\n            Template449: [407730, 'ida.signage.me', 20],\n            Template441: [407730, 'ida.signage.me', 12],\n            Template447: [407730, 'ida.signage.me', 18],\n            Template450: [407730, 'ida.signage.me', 21],\n            Template454: [411108, 'ida.signage.me', 7],\n            Template455: [411108, 'ida.signage.me', 8],\n            Template453: [411108, 'ida.signage.me', 6],\n            Template456: [411108, 'ida.signage.me', 9],\n            Template457: [411108, 'ida.signage.me', 10],\n            Template458: [411108, 'ida.signage.me', 11],\n            Template459: [411108, 'ida.signage.me', 12],\n            Template452: [411108, 'ida.signage.me', 5],\n            Template460: [411108, 'ida.signage.me', 13],\n            Template451: [411108, 'ida.signage.me', 4],\n            Template461: [411110, 'ida.signage.me', 12],\n            Template463: [411110, 'ida.signage.me', 14],\n            Template462: [411110, 'ida.signage.me', 13],\n            Template465: [411110, 'ida.signage.me', 16],\n            Template466: [411110, 'ida.signage.me', 17],\n            Template467: [411110, 'ida.signage.me', 18],\n            Template464: [411110, 'ida.signage.me', 15],\n            Template469: [411110, 'ida.signage.me', 20],\n            Template470: [411110, 'ida.signage.me', 21],\n            Template468: [411110, 'ida.signage.me', 19],\n            Template471: [411111, 'ida.signage.me', 10],\n            Template473: [411111, 'ida.signage.me', 12],\n            Template474: [411111, 'ida.signage.me', 13],\n            Template475: [411111, 'ida.signage.me', 14],\n            Template476: [411111, 'ida.signage.me', 15],\n            Template472: [411111, 'ida.signage.me', 11],\n            Template479: [411111, 'ida.signage.me', 18],\n            Template480: [411111, 'ida.signage.me', 19],\n            Template478: [411111, 'ida.signage.me', 17],\n            Template477: [411111, 'ida.signage.me', 16],\n            Template483: [411112, 'ida.signage.me', 7],\n            Template481: [411112, 'ida.signage.me', 5],\n            Template484: [411112, 'ida.signage.me', 8],\n            Template486: [411112, 'ida.signage.me', 10],\n            Template482: [411112, 'ida.signage.me', 6],\n            Template485: [411112, 'ida.signage.me', 9],\n            Template488: [411112, 'ida.signage.me', 12],\n            Template489: [411112, 'ida.signage.me', 13],\n            Template487: [411112, 'ida.signage.me', 11],\n            Template490: [411112, 'ida.signage.me', 14],\n            Template491: [411113, 'ida.signage.me', 17],\n            Template493: [411113, 'ida.signage.me', 19],\n            Template494: [411113, 'ida.signage.me', 20],\n            Template497: [411113, 'ida.signage.me', 23],\n            Template492: [411113, 'ida.signage.me', 18],\n            Template495: [411113, 'ida.signage.me', 21],\n            Template496: [411113, 'ida.signage.me', 22],\n            Template498: [411113, 'ida.signage.me', 24],\n            Template499: [411113, 'ida.signage.me', 25],\n            Template500: [411113, 'ida.signage.me', 26],\n            Digg9: [411115, 'ida.signage.me', 21],\n            Digg6: [411115, 'ida.signage.me', 18],\n            Digg10: [411115, 'ida.signage.me', 22],\n            Digg11: [411115, 'ida.signage.me', 23],\n            Digg12: [411115, 'ida.signage.me', 24],\n            Digg8: [411115, 'ida.signage.me', 20],\n            Digg14: [411115, 'ida.signage.me', 26],\n            Digg13: [411115, 'ida.signage.me', 25],\n            Digg15: [411115, 'ida.signage.me', 27],\n            Digg16: [411115, 'ida.signage.me', 28],\n            Digg17: [411115, 'ida.signage.me', 29],\n            Digg18: [411115, 'ida.signage.me', 30],\n            Digg19: [411115, 'ida.signage.me', 31],\n            Digg20: [411115, 'ida.signage.me', 32],\n            Digg1: [411115, 'ida.signage.me', 12],\n            Digg2: [411115, 'ida.signage.me', 14],\n            Digg3: [411115, 'ida.signage.me', 15],\n            Digg4: [411115, 'ida.signage.me', 16],\n            Digg5: [411115, 'ida.signage.me', 17],\n            Digg7: [411115, 'ida.signage.me', 19],\n            Digg21: [434454, 'jupiter.signage.me', 6],\n            Sheet6: [411116, 'ida.signage.me', 24],\n            Sheet7: [411116, 'ida.signage.me', 25],\n            Sheet5: [411116, 'ida.signage.me', 23],\n            Sheet12: [411116, 'ida.signage.me', 30],\n            Sheet13: [411116, 'ida.signage.me', 31],\n            Sheet15: [411116, 'ida.signage.me', 33],\n            Sheet9: [411116, 'ida.signage.me', 27],\n            Sheet16: [411116, 'ida.signage.me', 34],\n            Sheet10: [411116, 'ida.signage.me', 28],\n            Sheet17: [411116, 'ida.signage.me', 35],\n            Sheet19: [411116, 'ida.signage.me', 37],\n            Sheet14: [411116, 'ida.signage.me', 32],\n            Sheet18: [411116, 'ida.signage.me', 36],\n            Sheet11: [411116, 'ida.signage.me', 29],\n            Sheet8: [411116, 'ida.signage.me', 26],\n            Sheet1: [411116, 'ida.signage.me', 19],\n            //Calendar1: [411116,'ida.signage.me',17],\n            Sheet2: [411116, 'ida.signage.me', 20],\n            Sheet3: [411116, 'ida.signage.me', 21],\n            Sheet4: [411116, 'ida.signage.me', 22],\n            Sheet20: [411116, 'ida.signage.me', 38],\n            Sheet21: [434454, 'jupiter.signage.me', 8],\n            Calendar11: [411117, 'ida.signage.me', 22],\n            Calendar10: [411117, 'ida.signage.me', 24],\n            Calendar12: [411117, 'ida.signage.me', 25],\n            //Twitter1: [411117,'ida.signage.me',12],\n            Calendar3: [411117, 'ida.signage.me', 15],\n            Calendar13: [411117, 'ida.signage.me', 26],\n            Calendar15: [411117, 'ida.signage.me', 28],\n            Calendar5: [411117, 'ida.signage.me', 17],\n            Calendar9: [411117, 'ida.signage.me', 21],\n            Calendar14: [411117, 'ida.signage.me', 27],\n            Calendar6: [411117, 'ida.signage.me', 18],\n            Calendar16: [411117, 'ida.signage.me', 29],\n            Calendar4: [411117, 'ida.signage.me', 16],\n            Calendar17: [411117, 'ida.signage.me', 30],\n            Calendar7: [411117, 'ida.signage.me', 19],\n            Calendar18: [411117, 'ida.signage.me', 31],\n            Calendar8: [411117, 'ida.signage.me', 20],\n            Calendar1: [411117, 'ida.signage.me', 13],\n            Calendar2: [411117, 'ida.signage.me', 14],\n            Calendar19: [411117, 'ida.signage.me', 32],\n            Calendar20: [411117, 'ida.signage.me', 33],\n            Calendar21: [434454, 'jupiter.signage.me', 5],\n            Twitter1: [411119, 'ida.signage.me', 24],\n            Twitter2: [411119, 'ida.signage.me', 25],\n            Twitter4: [411119, 'ida.signage.me', 27],\n            Twitter3: [411119, 'ida.signage.me', 26],\n            Twitter6: [411119, 'ida.signage.me', 29],\n            Twitter7: [411119, 'ida.signage.me', 30],\n            Twitter5: [411119, 'ida.signage.me', 28],\n            Twitter8: [411119, 'ida.signage.me', 31],\n            Twitter9: [411119, 'ida.signage.me', 32],\n            Twitter10: [411119, 'ida.signage.me', 33],\n            Twitter12: [411119, 'ida.signage.me', 35],\n            Twitter11: [411119, 'ida.signage.me', 34],\n            Twitter13: [411119, 'ida.signage.me', 36],\n            Twitter14: [411119, 'ida.signage.me', 37],\n            Twitter16: [411119, 'ida.signage.me', 39],\n            Twitter17: [411119, 'ida.signage.me', 40],\n            Twitter19: [411119, 'ida.signage.me', 42],\n            Twitter15: [411119, 'ida.signage.me', 38],\n            Twitter20: [411119, 'ida.signage.me', 43],\n            Twitter18: [411119, 'ida.signage.me', 41],\n            Weather1: [411114, 'ida.signage.me', 12],\n            Weather2: [411114, 'ida.signage.me', 13],\n            Weather3: [411114, 'ida.signage.me', 14],\n            Weather13: [411114, 'ida.signage.me', 24],\n            Weather10: [411114, 'ida.signage.me', 21],\n            Weather11: [411114, 'ida.signage.me', 22],\n            Weather16: [411114, 'ida.signage.me', 27],\n            Weather17: [411114, 'ida.signage.me', 28],\n            Weather18: [411114, 'ida.signage.me', 29],\n            Weather19: [411114, 'ida.signage.me', 30],\n            Weather4: [411114, 'ida.signage.me', 15],\n            Weather20: [411114, 'ida.signage.me', 31],\n            Weather5: [411114, 'ida.signage.me', 16],\n            Weather12: [411114, 'ida.signage.me', 23],\n            Weather14: [411114, 'ida.signage.me', 25],\n            Weather15: [411114, 'ida.signage.me', 26],\n            Weather6: [411114, 'ida.signage.me', 17],\n            Weather7: [411114, 'ida.signage.me', 18],\n            Weather8: [411114, 'ida.signage.me', 19],\n            Weather9: [411114, 'ida.signage.me', 20],\n            Weather23: [411120, 'ida.signage.me', 20],\n            Weather22: [411120, 'ida.signage.me', 19],\n            Weather26: [411120, 'ida.signage.me', 23],\n            Weather21: [411120, 'ida.signage.me', 18],\n            Weather27: [411120, 'ida.signage.me', 24],\n            Weather29: [411120, 'ida.signage.me', 26],\n            Weather24: [411120, 'ida.signage.me', 21],\n            Weather25: [411120, 'ida.signage.me', 22],\n            Weather28: [411120, 'ida.signage.me', 25],\n            Weather30: [411120, 'ida.signage.me', 27],\n            Weather31: [411120, 'ida.signage.me', 28],\n            Weather32: [411120, 'ida.signage.me', 30],\n            Weather33: [411120, 'ida.signage.me', 31],\n            Weather34: [411120, 'ida.signage.me', 32],\n            Weather35: [411120, 'ida.signage.me', 33],\n            Weather36: [411120, 'ida.signage.me', 34],\n            Weather37: [411120, 'ida.signage.me', 35],\n            Weather38: [411120, 'ida.signage.me', 36],\n            Weather39: [411120, 'ida.signage.me', 38],\n            Weather40: [411120, 'ida.signage.me', 39],\n            Weather41: [411120, 'ida.signage.me', 40],\n            Weather42: [411120, 'ida.signage.me', 42],\n            Weather43: [411120, 'ida.signage.me', 41],\n            Weather44: [411120, 'ida.signage.me', 43],\n            Weather46: [434454, 'jupiter.signage.me', 7]\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/app/scenes/scene-editor.ts",
    "content": "import {AfterViewInit, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {BlockService, ISceneData} from \"../blocks/block-service\";\nimport {CommBroker, IMessage} from \"../../services/CommBroker\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Consts, PLACEMENT_IS_SCENE, PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {BlockFactoryService} from \"../../services/block-factory-service\";\nimport {BlockFabric} from \"../blocks/block-fabric\";\nimport * as _ from \"lodash\";\nimport {PlayerDataModelExt} from \"../../store/model/msdb-models-extended\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {IAddContents} from \"../../interfaces/IAddContent\";\nimport {PreviewModeEnum} from \"../live-preview/live-preview\";\nimport {AddContent} from \"../campaigns/add-content\";\nimport {Lib} from \"../../Lib\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {PlayerDataModel} from \"../../store/imsdb.interfaces_auto\";\n\nexport const ADD_NEW_BLOCK_SCENE = 'ADD_NEW_BLOCK_SCENE';\nexport const SCENE_BLOCK_CHANGE = 'SCENE_BLOCK_CHANGE';\nexport const SCENE_CHANGE = 'SCENE_CHANGE';\n\nconst JSON_EVENT_ROW_CHANGED = 'JSON_EVENT_ROW_CHANGED';\nconst STATIONS_POLL_TIME_CHANGED = 'STATIONS_POLL_TIME_CHANGED';\nconst THEME_CHANGED = 'THEME_CHANGED';\nconst SELECTED_STACK_VIEW = 'SELECTED_STACK_VIEW';\nconst BLOCK_SELECTED = 'BLOCK_SELECTED';\nconst SCENE_BLOCKS_RENDERED = 'SCENE_BLOCKS_RENDERED';\nconst SCENE_EDITOR_REMOVE = 'SCENE_EDITOR_REMOVE';\nconst SCENE_ITEM_REMOVE = 'SCENE_ITEM_REMOVE';\nconst SCENE_CANVAS_SELECTED = 'SCENE_CANVAS_SELECTED';\nconst SCENE_SELECT_NEXT = 'SCENE_SELECT_NEXT';\nconst WIZARD_EXIT = 'WIZARD_EXIT';\nconst NEW_SCENE_ADD = 'NEW_SCENE_ADD';\nconst SCENE_LIST_UPDATED = 'SCENE_LIST_UPDATED';\nconst SCENE_UNDO = 'SCENE_UNDO';\nconst SCENE_REDO = 'SCENE_REDO';\nconst REMOVING_SCENE = 'REMOVING_SCENE';\nconst REMOVED_SCENE = 'REMOVED_SCENE';\nconst REMOVING_RESOURCE = 'REMOVING_RESOURCE';\nconst REMOVED_RESOURCE = 'REMOVED_RESOURCE';\nconst ADDED_RESOURCE = 'ADDED_RESOURCE';\nconst MOUSE_ENTERS_CANVAS = 'MOUSE_ENTERS_CANVAS';\nconst FONT_SELECTION_CHANGED = 'FONT_SELECTION_CHANGED';\nconst CAMPAIGN_LIST_LOADING = 'CAMPAIGN_LIST_LOADED';\n\n@Component({\n    selector: 'scene-editor',\n    styles: [`\n        a {\n            outline: none;\n        }\n    `],\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <scene-toolbar [blocks]=\"m_canvasBlocks\" (onItemSelected)=\"_onItemSelectedFromToolbar($event)\" (onToolbarAction)=\"_onToolbarAction($event)\"></scene-toolbar>\n        <loading *ngIf=\"m_isLoading\" [size]=\"'50px'\" [style]=\"{'margin-top': '150px'}\"></loading>\n        <div [ngClass]=\"{hidden: m_isLoading}\">\n            <div id=\"sceneCanvasContainer\" data-toggle=\"context\" data-target=\"#sceneContextMenu\" class=\"yScroll context sceneElements\" style=\" overflow-x: visible\" align=\"center\"></div>\n        </div>\n        <div id=\"sceneContextMenu\">\n            <ul id=\"sceneContext\" class=\"dropdown-menu\" role=\"menu\">\n                <li>\n                    <a tabindex=\"-1\" class=\"blocksOnly\" name=\"cut\" data-localize=\"cut\">cut</a>\n                </li>\n                <li>\n                    <a tabindex=\"-1\" class=\"blocksOnly\" name=\"copy\" data-localize=\"copy\">copy</a>\n                </li>\n                <li>\n                    <a tabindex=\"-1\" name=\"paste\" data-localize=\"paste\">paste</a>\n                </li>\n                <li>\n                    <a tabindex=\"-1\" name=\"remove\" class=\"blocksOnly\" data-localize=\"remove\">remove</a>\n                </li>\n            </ul>\n        </div>\n\n        <modal #modal>\n            <modal-header [show-close]=\"true\">\n                <h4 i18n class=\"modal-title\">add content to scene</h4>\n            </modal-header>\n            <modal-body>\n                <add-content #addContent [placement]=\"m_PLACEMENT_SCENE\" (onClosed)=\"_onClosed()\" (onAddContentSelected)=\"_onAddedNewBlock()\"></add-content>\n            </modal-body>\n            <modal-footer [show-default-buttons]=\"true\"></modal-footer>\n        </modal>\n\n    `\n})\nexport class SceneEditor extends Compbaser implements AfterViewInit {\n\n    m_PLACEMENT_SCENE = PLACEMENT_SCENE;\n    m_activeAddContent = false;\n    m_isLoading = true;\n    m_selectedSceneID = undefined;\n    m_sceneScrollTop = 0;\n    m_sceneScrollLeft = 0;\n    m_objectScaling = 0;\n    m_mouseX: any = 0;\n    m_mouseY: any = 0;\n    m_gridMagneticMode = 0;\n    m_rendering = false;\n    m_memento = {};\n    m_canvas: any;\n    m_canvasBlocks = [];\n    _sceneBlockModified;\n    m_sceneBlock;\n    m_canvasMouseState = 0;\n    m_copiesObjects = [];\n    m_canvasScale = 1;\n    SCALE_FACTOR = 1.2;\n    PUSH_TOP = 1;\n    PUSH_BOTTOM = 0;\n    m_blocks = {\n        blocksPre: [],\n        blocksPost: {},\n        blockSelected: undefined\n    };\n\n    constructor(private zone: NgZone, private blockFactory: BlockFactoryService, private rp: RedPepperService, private el: ElementRef, private yp: YellowPepperService, private cd: ChangeDetectorRef, private bs: BlockService, private commBroker: CommBroker) {\n        super();\n        // this.cd.detach();\n    }\n\n    @ViewChild(ModalComponent)\n    modal: ModalComponent;\n\n    @ViewChild('addContent')\n    addContent: AddContent;\n\n    ngAfterViewInit() {\n        this.m_selectedSceneID = undefined;\n        this.m_sceneScrollTop = 0;\n        this.m_sceneScrollLeft = 0;\n        this.m_objectScaling = 0;\n        this.m_mouseX = 0;\n        this.m_mouseY = 0;\n        this.m_gridMagneticMode = 0;\n        this.m_rendering = false;\n        this.m_memento = {};\n        this.m_canvasMouseState = 0;\n        this.m_copiesObjects = [];\n        this.PUSH_TOP = 1;\n        this.PUSH_BOTTOM = 0;\n        this.m_blocks = {\n            blocksPre: [],\n            blocksPost: {},\n            blockSelected: undefined\n        };\n        this.m_canvas = undefined;\n        this.m_canvasScale = 1;\n        this.SCALE_FACTOR = 1.2;\n        this._listenSceneSelection();\n        this._listenTotalBlocksModified();\n        this._listenAddBlockWizard();\n        this._listenToCanvasScroll();\n        this._listenSceneChanged();\n        this._listenContextMenu();\n        this._listenSelectNextBlock();\n        // this._listenSceneBlockRemove();\n        this._listenSceneNew();\n        this._listenAppResized();\n        this._listenBlockSelected();\n        this._delegateSceneBlockModified();\n        this._notifyScaleChange();\n\n        // this.addContent.setPlacement(1);\n    }\n\n    ngOnInit() {\n    }\n\n    @Output()\n    onGoBack: EventEmitter<any> = new EventEmitter<any>();\n\n    _onClosed() {\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _notifyScaleChange() {\n        let uiState: IUiState = {scene: {fabric: {scale: this.m_canvasScale}}}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _onToolbarAction(event) {\n        con('toolbar ' + event);\n        switch (event) {\n            case 'back': {\n                let uiState: IUiState = {uiSideProps: SideProps.miniDashboard, scene: {blockSelected: -1}}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                this.onGoBack.emit();\n                break;\n            }\n            case 'add': {\n                this.m_activeAddContent = true;\n                this.modal.open();\n                break;\n            }\n            case 'removeItem': {\n                this._onContentMenuSelection('remove');\n                break;\n            }\n            case 'playPreview': {\n                let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE_AND_PREVIEW, previewMode: PreviewModeEnum.SCENE}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                break;\n            }\n            case 'pushItemToTopButtonToolTip': {\n                if (_.isUndefined(this.m_selectedSceneID))\n                    return;\n                var block = this.m_canvas.getActiveObject();\n                if (_.isNull(block)) {\n                    this._discardSelections();\n                    return;\n                }\n                this.m_canvas.bringToFront(block);\n                this._updateZorder(this.PUSH_TOP, block);\n                this._mementoAddState();\n                break;\n            }\n            case 'pushItemToBottomButtonToolTip': {\n                if (_.isUndefined(this.m_selectedSceneID))\n                    return;\n                var block = this.m_canvas.getActiveObject();\n                if (_.isNull(block)) {\n                    this._discardSelections();\n                    return;\n                }\n                this.m_canvas.sendToBack(block);\n                this._updateZorder(this.PUSH_BOTTOM, block);\n                this._mementoAddState();\n                break;\n            }\n            case 'sceneZoomIn': {\n                this._zoomIn();\n                this._discardSelections();\n                this._resetAllObjectScale();\n                this.m_canvas.renderAll();\n                break;\n            }\n            case 'sceneZoomOut': {\n                this._zoomOut();\n                this._discardSelections();\n                this._resetAllObjectScale();\n                this.m_canvas.renderAll();\n                break;\n            }\n            case 'sceneZoomReset': {\n                this._zoomReset();\n                this._resetAllObjectScale();\n                this.m_canvas.renderAll();\n                break;\n            }\n            case 'undo': {\n                if (this.m_rendering)\n                    return;\n                this.m_blocks.blockSelected = undefined;\n                this._discardSelections();\n                this._mementoLoadState('undo');\n                break;\n            }\n            case 'redo': {\n                if (this.m_rendering)\n                    return;\n                this.m_blocks.blockSelected = undefined;\n                this._discardSelections();\n                this._mementoLoadState('redo');\n                break;\n            }\n            case 'magneticGrid': {\n                if (this.m_rendering || _.isUndefined(this.m_canvas))\n                    return;\n                switch (this.m_gridMagneticMode) {\n                    case 0: {\n                        this.m_gridMagneticMode = 1;\n                        break;\n                    }\n                    case 1: {\n                        this.m_gridMagneticMode = 2;\n                        break;\n                    }\n                    case 2: {\n                        this.m_gridMagneticMode = 0;\n                        break;\n                    }\n                }\n                this.m_sceneBlock.setCanvas(this.m_canvas, this.m_gridMagneticMode);\n                break;\n            }\n        }\n    }\n\n    /**\n     Listen to changes in a new scene selection\n     @method _listenSceneSelection\n     **/\n    _listenSceneSelection() {\n        this.cancelOnDestroy(\n            //\n            this.yp.listenSceneSelected(true)\n                .delay(1000)\n                .subscribe((sceneData: ISceneData) => {\n                    if (!sceneData) {\n                        this.m_isLoading = true;\n                        this.cd.markForCheck();\n                        return;\n                    }\n                    this.m_selectedSceneID = sceneData.scene_id_pseudo_id;\n                    this._loadScene();\n                    this._sceneCanvasSelected();\n                    if (this._mementoInit())\n                        this._mementoAddState();\n                }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Listen to changes in a new scene selection\n     @method _listenSceneSelection\n     **/\n    _listenBlockSelected() {\n        var sceneData: ISceneData = {\n            scene_id: null,\n            scene_id_pseudo_id: null,\n            scene_native_id: null,\n            block_pseudo_id: null,\n            playerDataModel: null,\n            domPlayerData: null,\n            domPlayerDataJson: null,\n            domPlayerDataXml: null\n        }\n\n        this.cancelOnDestroy(\n            this.yp.listenSceneOrBlockSelectedChanged()\n                .startWith(sceneData)\n                .pairwise()\n                .filter((v: Array<ISceneData | any>) => {\n                    if (v[0].scene_id == null)\n                        return false;\n                    if (v[0].block_pseudo_id != v[1].block_pseudo_id)\n                        return false;\n                    if (Lib.IsEqual(v[0].domPlayerDataJson, v[1].domPlayerDataJson))\n                        return false;\n                    delete v[\"0\"].domPlayerDataJson.Player.Data.Layout;\n                    delete v[\"1\"].domPlayerDataJson.Player.Data.Layout;\n                    if (Lib.IsEqual(v[0].domPlayerDataJson, v[1].domPlayerDataJson))\n                        return false;\n                    return true;\n                })\n                .subscribe((v) => {\n                    this.commBroker.fire({event: SCENE_BLOCK_CHANGE, fromInstance: this, message: [v[1].block_pseudo_id]})\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            this.commBroker.onEvent(BLOCK_SELECTED)\n                .skip(1)\n                .subscribe((e: IMessage) => {\n                    let uiState: IUiState = {uiSideProps: SideProps.sceneBlock, scene: {blockSelected: e.message}};\n                    this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                }, (e) => console.error(e))\n        )\n    }\n\n    @timeout(500)\n    _updateBlocksCount() {\n        if (!this.m_canvas) return;\n        this.m_canvasBlocks = [{id: 'SCENE', name: '[Scene canvas]'}];\n        this.m_canvas.getObjects().forEach((block: BlockFabric) => {\n            this.m_canvasBlocks.push({\n                id: block.getBlockData().blockID,\n                name: block.getBlockData().blockName,\n            })\n        })\n        this.cd.markForCheck();\n    }\n\n    /**\n     Bring the scene into view\n     @method _sceneActive\n     **/\n    _sceneActive() {\n        // $('#sceneToolbar').fadeIn();\n        // $('#sceneToolbar').fadeTo(500, 1);\n    }\n\n    /**\n     Init a new canvas and listen to even changes on that new canvas\n     @method _initializeCanvas\n     @param {Number} w width\n     @param {Number} h height\n     **/\n    _initializeCanvas(w, h) {\n        $('#sceneCanvasContainer', this.el.nativeElement).empty();\n        $('#sceneCanvasContainer', this.el.nativeElement).append(`<canvas id=\"sceneCanvas\" width=\"${w}px\" height=\"${h}px\"/>`);\n        this.m_canvas = new fabric.Canvas('sceneCanvas');\n        this.m_canvas.renderOnAddRemove = false;\n        $('#sceneCanvas', this.el.nativeElement).addClass('basicBorder');\n        this._listenBlockModified();\n        this._listenCanvasSelections();\n        this._listenKeyboard();\n    }\n\n    /**\n     Init a new scene and subclass off a standard Block\n     @method _initializeScene\n     **/\n    _initializeScene(i_selectedSceneID) {\n        var scene_player_data = this.rp.getScenePlayerdata(i_selectedSceneID);\n        this.m_sceneBlock = this.blockFactory.createBlock(i_selectedSceneID, scene_player_data);\n        this.m_sceneBlock.setCanvas(this.m_canvas, this.m_gridMagneticMode);\n        ////_.extend(this.m_canvas, this.m_sceneBlock);\n    }\n\n    /**\n     Load a new scene and dispose of any previous ones\n     @return {Number} Unique clientId.\n     **/\n    _loadScene() {\n        if (_.isUndefined(this.m_selectedSceneID))\n            return -1;\n        this.m_isLoading = true;\n        this._disposeBlocks();\n        this.disposeScene();\n        this._zoomReset();\n        // this.m_property.resetPropertiesView();\n        var domPlayerData = this.rp.getScenePlayerdataDom(this.m_selectedSceneID);\n        var l = $(domPlayerData).find('Layout').eq(0);\n        var w = $(l).attr('width');\n        var h = $(l).attr('height');\n        this._initializeCanvas(w, h);\n        this._initializeScene(this.m_selectedSceneID);\n        this._preRender(domPlayerData);\n    }\n\n    /**\n     Listen to selection of next block\n     @method _listenSelectNextDivision\n     **/\n    _listenSelectNextBlock() {\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent(SCENE_SELECT_NEXT)\n                .subscribe((e: IMessage) => {\n                    if (_.isUndefined(this.m_selectedSceneID))\n                        return;\n                    var viewer = this.m_canvas.getActiveObject();\n                    var viewIndex = this.m_canvas.getObjects().indexOf(viewer);\n                    var totalViews = this.m_canvas.getObjects().length;\n                    var blockID = undefined;\n                    if (viewIndex == totalViews - 1) {\n                        this.m_canvas.setActiveObject(this.m_canvas.item(0));\n                        blockID = this.m_canvas.getActiveObject().getBlockData().blockID;\n                        this.commBroker.fire({event: BLOCK_SELECTED, fromInstance: this, message: blockID});\n                    } else {\n                        this.m_canvas.setActiveObject(this.m_canvas.item(viewIndex + 1));\n                        blockID = this.m_canvas.getActiveObject().getBlockData().blockID;\n                        this.commBroker.fire({event: BLOCK_SELECTED, fromInstance: this, message: blockID});\n                    }\n                }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Listen to when a user selects to delete a block\n     @method _listenSceneBlockRemove\n     **/\n    // _listenSceneBlockRemove() {\n    //     this.cancelOnDestroy(\n    //         //\n    //         this.commBroker.onEvent(SCENE_ITEM_REMOVE)\n    //             .subscribe((msg: IMessage) => {\n    //                 this._onContentMenuSelection('remove');\n    //             }, (e) => console.error(e))\n    //     )\n    // }\n\n    /**\n     Listen to keyboard events\n     @method _listenKeyboard\n     **/\n    _listenKeyboard() {\n        // if (_.isUndefined(this.m_canvas))\n        //     return;\n        // $('canvas',this.el.nativeElement).attr('tabindex', '1');\n        // var keyDown = _.debounce( (e) => {\n        //     if (this.m_objectScaling)\n        //         return;\n        //     if (this.m_canvasMouseState)\n        //         return;\n        //     var block = this.m_canvas.getActiveObject();\n        //     if (_.isNull(block))\n        //         return;\n        //     var dimensionProps = BB.comBroker.getService(BB.SERVICES['DIMENSION_PROPS_LAYOUT']);\n        //     var values = dimensionProps.getValues();\n        //     var val = e.shiftKey ? 25 : 1;\n        //     switch (e.keyCode) {\n        //         case 38: {\n        //             values.y = values.y - val;\n        //             break;\n        //         }\n        //         case 40: {\n        //             values.y = values.y + val;\n        //             break;\n        //         }\n        //         case 37: {\n        //             values.x = values.x - val;\n        //             break;\n        //         }\n        //         case 39: {\n        //             values.x = values.x + val;\n        //             break;\n        //         }\n        //     }\n        //     dimensionProps.setValues(values, true);\n        //     return false;\n        // }, 100);\n        // $('.upper-canvas').keydown(keyDown);\n    }\n\n    /**\n     Listen to user selection of new scene\n     @method _listenSceneNew\n     **/\n    _listenSceneNew() {\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent(NEW_SCENE_ADD)\n                .subscribe((msg: IMessage) => {\n                    var player_data = this.bs.getBlockBoilerplate('3510').getDefaultPlayerData(PLACEMENT_IS_SCENE);\n                    this.createScene(player_data, false, true, msg.message.mimeType, msg.message.name);\n                }, (e) => console.error(e))\n        )\n    }\n\n    // /**\n    //  Listen when mouse enters canvas wrapper and announce it\n    //  @method _listenMouseEnterCanvas\n    //  **/\n    // _listenMouseEnterCanvas() {\n    //     $('#sceneCanvasContainer', this.el.nativeElement).on(\"mouseover\", (e) => {\n    //         this.commBroker.fire({event: MOUSE_ENTERS_CANVAS, fromInstance: this});\n    //     });\n    // }\n\n    _listenTotalBlocksModified() {\n        this.cancelOnDestroy(\n            this.yp.listenSelectedSceneChanged()\n                .pairwise()\n                .map((i_playerDataModelsExt: Array<PlayerDataModelExt | PlayerDataModel>) => {\n                    var a0 = i_playerDataModelsExt[0].getPlayerDataValue();\n                    var a1 = $.parseXML(a0);\n                    var a2 = $(a1).find('Players').children('Player')\n                        .map((i, player) => $(player).attr('id'))\n                    var previousBlockIds = $.makeArray(a2);\n                    var b0 = i_playerDataModelsExt[1].getPlayerDataValue();\n                    var b1 = $.parseXML(b0);\n                    var b2 = $(b1).find('Players').children('Player')\n                        .map((i, player) => $(player).attr('id'))\n                    var currentBlockIds = $.makeArray(b2);\n                    return !_.isEqual(currentBlockIds, previousBlockIds);\n                }).filter(v => v)\n                .subscribe(() => {\n                    this._updateBlocksCount();\n                }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Listen to the event of scene changes which normally comes from a block that modified its data\n     and re-render all scene content\n     @method _listenSceneChanged\n     **/\n    _listenSceneChanged() {\n\n        var message: IMessage = {\n            event: '',\n            fromInstance: null\n        }\n\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent(SCENE_BLOCK_CHANGE)\n                .subscribe((msg: IMessage) => {\n                    if (this.m_rendering)\n                        return;\n                    var blockIDs = msg.message;\n                    con('block(s) edited ' + blockIDs);\n                    var domPlayerData = this.rp.getScenePlayerdataDom(this.m_selectedSceneID);\n                    this.m_blocks.blockSelected = blockIDs[0];\n                    this._preRender(domPlayerData, blockIDs);\n                    this._mementoAddState();\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent(SCENE_CHANGE)\n                .subscribe((msg: IMessage) => {\n                    if (this.m_rendering)\n                        return;\n                    this.m_sceneBlock.fabricSceneBg(msg);\n                    this._mementoAddState();\n                }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Listen to any canvas right click\n     @method _listenContextMenu\n     **/\n    /**\n     Listen to any canvas right click\n     @method _listenContextMenu\n     **/\n    _listenContextMenu() {\n        var self = this;\n        jQueryAny('#sceneCanvasContainer', this.el.nativeElement).contextmenu({\n            target: '#sceneContextMenu',\n            before: function (e, element, target) {\n                e.preventDefault();\n                // no canvas\n                if (_.isUndefined(self.m_canvas)) {\n                    this.closemenu();\n                    return false;\n                }\n                // remember right click position for pasting\n                self.m_mouseX = e.offsetX;\n                self.m_mouseY = e.offsetY;\n\n                // group selected\n                var active = self.m_canvas.getActiveGroup();\n                if (active) {\n                    $('.blocksOnly', '#sceneContextMenu').show();\n                    return true;\n                }\n                // scene selected\n                var block = self.m_canvas.getActiveObject();\n                if (_.isNull(block)) {\n                    $('.blocksOnly', '#sceneContextMenu').hide();\n                    return true;\n                }\n                // object selected\n                $('.blocksOnly', '#sceneContextMenu').show();\n                return true;\n            },\n            onItem: function (context, e) {\n                self._onContentMenuSelection($(e.target).attr('name'))\n            }\n        });\n    }\n\n    /**\n     On Scene right click context menu selection command\n     @method _onContentMenuSelection\n     @param {String} i_command\n     **/\n    _onContentMenuSelection(i_command) {\n        var blocks = [];\n\n        var contextCmd = (i_blocks) => {\n            switch (i_command) {\n                case 'copy': {\n                    this.m_copiesObjects = [];\n                    _.each(i_blocks, (selectedObject:any) => {\n                        var blockPlayerData = selectedObject.getBlockData().blockData;\n                        blockPlayerData = this.rp.stripPlayersID(blockPlayerData);\n                        this.m_copiesObjects.push(blockPlayerData);\n                    });\n                    break;\n                }\n\n                case 'cut': {\n                    let uiState: IUiState = {scene: {blockSelected: -1}}\n                    this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                    this.m_copiesObjects = [];\n                    _.each(i_blocks, (selectedObject:any) => {\n                        var blockData = selectedObject.getBlockData();\n                        var blockPlayerData = blockData.blockData;\n                        this._discardSelections();\n                        this.rp.removeScenePlayer(this.m_selectedSceneID, blockData.blockID);\n                        this._disposeBlocks(blockData.blockID);\n                        blockPlayerData = this.rp.stripPlayersID(blockPlayerData);\n                        this.m_copiesObjects.push(blockPlayerData);\n                    });\n                    this.m_canvas.renderAll();\n                    this.commBroker.fire({event: SCENE_ITEM_REMOVE, fromInstance: this})\n                    // this._updateBlockCount();\n                    this.rp.reduxCommit();\n                    break;\n                }\n\n                case 'remove': {\n                    let uiState: IUiState = {scene: {blockSelected: -1}}\n                    this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                    _.each(i_blocks, (selectedObject:any) => {\n                        var blockData = selectedObject.getBlockData();\n                        this._discardSelections();\n                        this.rp.removeScenePlayer(this.m_selectedSceneID, blockData.blockID);\n                        this._disposeBlocks(blockData.blockID);\n                    });\n                    this.m_canvas.renderAll();\n                    this.commBroker.fire({event: SCENE_ITEM_REMOVE, fromInstance: this})\n                    // this._updateBlockCount();\n                    this.rp.reduxCommit();\n                    break;\n                }\n\n                case 'paste': {\n                    if (this.m_copiesObjects.length == 0)\n                        return;\n                    var x: any, y: any, blockID, origX: any, origY: any, blockIDs = [];\n                    _.each(this.m_copiesObjects, (domPlayerData, i: any) => {\n                        blockID = this.rp.generateSceneId();\n                        $(domPlayerData).attr('id', blockID);\n                        blockIDs.push(blockID);\n                        var layout: any = $(domPlayerData).find('Layout');\n                        if (i == 0) {\n                            origX = parseInt(layout.attr('x'));\n                            origY = parseInt(layout.attr('y'));\n                            x = this.m_mouseX;\n                            y = this.m_mouseY;\n                        } else {\n                            var a: any = layout.attr('x') - origX;\n                            var b: any = layout.attr('y') - origY;\n                            x = this.m_mouseX + a;\n                            y = this.m_mouseY + b;\n                        }\n                        layout.attr('x', x);\n                        layout.attr('y', y);\n                        var player_data = (new XMLSerializer()).serializeToString(domPlayerData);\n                        this.rp.appendScenePlayerBlock(this.m_selectedSceneID, player_data);\n                    });\n                    this._discardSelections();\n                    if (this.m_copiesObjects.length == 1) {\n                        this.commBroker.fire({event: SCENE_BLOCK_CHANGE, fromInstance: this, message: [blockID]});\n                    } else {\n                        this.commBroker.fire({event: SCENE_BLOCK_CHANGE, fromInstance: this, message: blockIDs});\n                    }\n                    // this._updateBlockCount();\n                    this.rp.reduxCommit();\n                    break;\n                }\n            }\n        };\n\n        // no canvas\n        if (_.isUndefined(this.m_canvas)) {\n            return;\n        }\n        // group selected\n        var group = this.m_canvas.getActiveGroup();\n        if (group) {\n            con(i_command + ' on group');\n            blocks = [];\n            _.each(group.objects, (selectedObject) => {\n                blocks.push(selectedObject);\n            });\n            contextCmd(blocks);\n            return;\n        }\n        // scene selected\n        var block = this.m_canvas.getActiveObject();\n        if (_.isNull(block)) {\n            con(i_command + ' on scene');\n            contextCmd(null);\n            return;\n        }\n        // object selected\n        con(i_command + ' on object');\n        blocks = [];\n        blocks.push(block);\n        contextCmd(blocks);\n        return true;\n    }\n\n    /**\n     Listen to canvas scrolling\n     @method _listenToCanvasScroll\n     **/\n    _listenToCanvasScroll() {\n        var self = this;\n        var sceneScrolling = _.debounce(() => {\n            $('#sceneCanvasContainer', this.el.nativeElement).scroll((e) => {\n                self.m_sceneScrollTop = $('#scenesPanel').scrollTop();\n                self.m_sceneScrollLeft = $('#scenesPanel').scrollLeft();\n                self.m_canvas.calcOffset();\n            });\n        }, 500);\n        $('#sceneCanvasContainer', this.el.nativeElement).scroll(sceneScrolling);\n    }\n\n    /**\n     Listen to and add new component / resources to scene\n     @method _listenAddBlockWizard\n     @param {event} e\n     **/\n    _listenAddBlockWizard() {\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent(ADD_NEW_BLOCK_SCENE)\n                .subscribe((msg: IMessage) => {\n                    var addContents: IAddContents = msg.message;\n                    var blockID = this.rp.generateSceneId();\n                    var player_data = this.bs.getBlockBoilerplate(addContents.blockCode).getDefaultPlayerData(PLACEMENT_SCENE, addContents.resourceId);\n                    var domPlayerData = $.parseXML(player_data);\n                    $(domPlayerData).find('Player').attr('id', blockID);\n                    player_data = (new XMLSerializer()).serializeToString(domPlayerData);\n                    this.rp.appendScenePlayerBlock(this.m_selectedSceneID, player_data);\n                    this.rp.reduxCommit();\n                    this.commBroker.fire({event: SCENE_BLOCK_CHANGE, fromInstance: this, message: [blockID]});\n                }, (e) => console.error(e))\n        )\n    }\n\n    _onAddedNewBlock() {\n        this.modal.close()\n        this.m_activeAddContent = false;\n    }\n\n    /**\n     @method _sceneProcessing\n     **/\n    _sceneProcessing(i_status, i_callBack, from ?) {\n        if (i_status) {\n            $('#sceneProcessing', this.el.nativeElement).css({\n                width: $('#scenePanelWrap').width(),\n                height: $('#scenePanelWrap').height()\n            })\n            $('#sceneProcessing', this.el.nativeElement).fadeTo('fast', 0.7, i_callBack);\n        } else {\n            this.m_isLoading = false;\n            this.cd.markForCheck();\n            $('#sceneProcessing', this.el.nativeElement).fadeOut('slow', i_callBack);\n        }\n    }\n\n    /**\n     Init a undo / redo via memento pattern\n     @method _mementoInit\n     @return {Boolean} return true if memento created false if one already existed\n     **/\n    _mementoInit() {\n        if (_.isUndefined(this.m_memento[this.m_selectedSceneID])) {\n            this.m_memento[this.m_selectedSceneID] = {\n                playerData: [],\n                cursor: -1\n            };\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     Remember current memento state\n     @method _mementoAddState\n     **/\n    _mementoAddState() {\n        const MAX = 100;\n        if (_.isUndefined(this.m_selectedSceneID))\n            return;\n        this._mementoInit();\n\n        // maintain memento to stack MAX value\n        if (this.m_memento[this.m_selectedSceneID].playerData.length > MAX)\n            this.m_memento[this.m_selectedSceneID].playerData.shift();\n\n        // if undo / redo was executed, remove ahead mementos\n        if (this.m_memento[this.m_selectedSceneID].cursor != this.m_memento[this.m_selectedSceneID].playerData.length - 1)\n            this.m_memento[this.m_selectedSceneID].playerData.splice(this.m_memento[this.m_selectedSceneID].cursor + 1);\n\n        var player_data = this.rp.getScenePlayerdata(this.m_selectedSceneID);\n        this.m_memento[this.m_selectedSceneID].playerData.push(player_data);\n        this.m_memento[this.m_selectedSceneID].cursor = this.m_memento[this.m_selectedSceneID].playerData.length - 1;\n    }\n\n    /**\n     Remember current memento state\n     @method _mementoLoadState\n     **/\n    _mementoLoadState(i_direction) {\n        if (_.isUndefined(this.m_selectedSceneID))\n            return;\n        this._mementoInit();\n        if (this.m_memento[this.m_selectedSceneID].playerData.length == 0)\n            return;\n\n        switch (i_direction) {\n            case 'undo': {\n                var cursor = this.m_memento[this.m_selectedSceneID].cursor;\n                if (cursor == 0)\n                    return;\n                this.m_memento[this.m_selectedSceneID].cursor--;\n                cursor = this.m_memento[this.m_selectedSceneID].cursor;\n                break;\n            }\n            case 'redo': {\n                var cursor = this.m_memento[this.m_selectedSceneID].cursor;\n                if (cursor == this.m_memento[this.m_selectedSceneID].playerData.length - 1)\n                    return;\n                this.m_memento[this.m_selectedSceneID].cursor++;\n                cursor = this.m_memento[this.m_selectedSceneID].cursor;\n                break;\n            }\n        }\n        var player_data = this.m_memento[this.m_selectedSceneID].playerData[cursor];\n        this.rp.setScenePlayerData(this.m_selectedSceneID, player_data);\n        this._loadScene();\n        this.rp.reduxCommit();\n        this.commBroker.fire({event: SCENE_LIST_UPDATED, fromInstance: this});\n    }\n\n    /**\n     Update the z-order index of an object\n     @method _updateZorder\n     @param {String} i_pushDirection\n     @param {Object} i_block\n     **/\n    _updateZorder(i_pushDirection, i_block) {\n        if (_.isUndefined(this.m_selectedSceneID))\n            return;\n        var active = this.m_canvas.getActiveGroup();\n        if (active)\n            return;\n        var blockID = i_block.getBlockData().blockID;\n        var sceneDomPlayerData = this.rp.getScenePlayerdataDom(this.m_selectedSceneID);\n        var domBlockData = $(sceneDomPlayerData).find('[id=\"' + blockID + '\"]');\n        switch (i_pushDirection) {\n            case this.PUSH_TOP: {\n                $(sceneDomPlayerData).find('Players').append($(domBlockData));\n                break;\n            }\n            case this.PUSH_BOTTOM: {\n                $(sceneDomPlayerData).find('Players').prepend($(domBlockData));\n                break;\n            }\n        }\n        this.rp.setScenePlayerData(this.m_selectedSceneID, (new XMLSerializer()).serializeToString(sceneDomPlayerData));\n        this.rp.reduxCommit();\n    }\n\n    /**\n     Pre render creates all of the Fabric blocks that will later get added when we call _render\n     This allows for smooth (non flickering) rendering since when we are ready to render, the blocks have\n     already been instantiated and ready to be added to canvas\n     @method _preRender\n     @param {Object} i_domPlayerData\n     @param {Object} [i_blockIDs] optionally render only a single block\n     **/\n    _preRender(i_domPlayerData, i_blockIDs ?) {\n        var zIndex = -1;\n        if (i_blockIDs) {\n            if (i_blockIDs.indexOf(this.m_selectedSceneID) > -1)\n                return;\n        }\n        this._renderPause();\n        this.m_blocks.blocksPre = [];\n        this.m_blocks.blocksPost = {};\n        con('pre-rendering new blocks');\n\n        // if rendering specific blocks instead of entire canvas\n        if (i_blockIDs) {\n            $(i_domPlayerData).find('Players').children('Player').each((i, player) => {\n                zIndex++;\n                var blockID = $(player).attr('id');\n                if (_.indexOf(i_blockIDs, blockID) > -1) {\n                    var block = {\n                        blockID: blockID,\n                        blockType: $(player).attr('player'),\n                        zIndex: zIndex,\n                        player_data: (new XMLSerializer()).serializeToString(player)\n                    };\n                    this.m_blocks.blocksPre.push(block);\n                }\n            });\n        } else {\n            $(i_domPlayerData).find('Players').children('Player').each((i, player) => {\n                var block = {\n                    blockID: $(player).attr('id'),\n                    blockType: $(player).attr('player'),\n                    zIndex: -1,\n                    player_data: (new XMLSerializer()).serializeToString(player)\n\n                };\n                this.m_blocks.blocksPre.push(block);\n            });\n        }\n        this._createBlock(i_blockIDs);\n    }\n\n    /**\n     Render the pre created blocks (via _preRender) and add all blocks to fabric canvas\n     @method _render\n     **/\n    _render(i_blockIDs) {\n        if (!this.m_canvas)\n            return;\n        var nZooms = Math.round(Math.log(1 / this.m_canvasScale) / Math.log(1.2));\n        var selectedBlockID = this.m_blocks.blockSelected;\n        var createAll = i_blockIDs[0] == undefined ? true : false; // if to re-render entire canvas\n\n        if (createAll) {\n            this._disposeBlocks();\n            this._zoomReset();\n        } else {\n            // if to re-render only changed blocks\n            for (var i = 0; i < i_blockIDs.length; i++)\n                this._disposeBlocks(i_blockIDs[i]);\n        }\n        _.forEach(this.m_blocks.blocksPost, (i_block) => {\n            this.m_canvas.add(i_block);\n        });\n        if (createAll) {\n            this._resetAllObjectScale();\n            this._zoomTo(nZooms);\n            this._updateBlocksCount();\n        } else {\n            // if to re-render only changed blocks\n            _.forEach(this.m_blocks.blocksPost, (i_block: any) => {\n                var zIndex = i_block.getZindex();\n                if (zIndex > -1)\n                    i_block.moveTo(zIndex);\n                this.m_canvas.setActiveObject(i_block);\n                this._zoomToBlock(nZooms, i_block);\n                this._resetObjectScale(i_block);\n            });\n        }\n        this._scrollTo(this.m_sceneScrollTop, this.m_sceneScrollLeft);\n        this.m_canvas.renderAll();\n        this._sceneProcessing(false, () => {\n        });\n        this._renderContinue();\n        // if (createAll)\n        //     this._updateBlockCount();\n\n        // select previous selection\n        if (_.isUndefined(selectedBlockID))\n            return;\n        if (createAll) {\n            for (var i = 0; i < this.m_canvas.getObjects().length; i++) {\n                if (selectedBlockID == this.m_canvas.item(i).getBlockData().blockID) {\n                    this._blockSelected(this.m_canvas.item(i));\n                    break;\n                }\n            }\n        } else {\n            var block = this.m_blocks.blocksPost[Object.keys(this.m_blocks.blocksPost)[0]];\n            this._blockSelected(block);\n        }\n    }\n\n    /**\n     Prevent rendering of canvas to continue and remove canvas listeners\n     @method _renderPause\n     **/\n    _renderPause() {\n        this.m_rendering = true;\n        if (_.isUndefined(this.m_canvas))\n            return;\n        this.m_canvas.removeListeners();\n    }\n\n    /**\n     Allow rendering of canvas to continue and add canvas listeners\n     @method _renderContinue\n     **/\n    _renderContinue() {\n        this.m_rendering = false;\n        if (_.isUndefined(this.m_canvas))\n            return;\n        this.m_canvas._initEventListeners();\n    }\n\n    /**\n     Create all the blocks that have been pre injected to m_blocks.blocksPre and after each block\n     is created created the next block; thus creating blocks sequentially due to fabric bug. When no\n     more blocks are to be created (m_blocks.blocksPre queue is empty) we _render the canvas\n     @method _createBlock\n     @param {Array} [i_blockIDs] optional array of block ids to render, or non if we render the entire canvas\n     **/\n    _createBlock(i_blockIDs) {\n        var blockData = this.m_blocks.blocksPre.shift();\n        if (blockData == undefined) {\n            this._render([i_blockIDs]);\n            return;\n        }\n        var newBlock = this.blockFactory.createBlock(blockData.blockID, blockData.player_data, this.m_selectedSceneID);\n        newBlock.setZindex(blockData.zIndex);\n        var blockID = newBlock.getBlockData().blockID;\n        newBlock.fabricateBlock(this.m_canvasScale, () => {\n            this.m_blocks.blocksPost[blockID] = newBlock;\n            this._createBlock(i_blockIDs);\n        });\n    }\n\n    /**\n     Announce to all that scene was re-rendered but do it via debounce\n     @method _delegateSceneBlockModified\n     **/\n    _delegateSceneBlockModified() {\n        var self = this;\n        self._sceneBlockModified = _.debounce(function (e) {\n            self.commBroker.fire({event: SCENE_BLOCKS_RENDERED, fromInstance: self.m_canvas, message: ''});\n            self._mementoAddState();\n            // self._drawGrid();\n        }, 200);\n    }\n\n\n    /**\n     Listen to when the app is resized so we can re-render\n     @method _listenAppResized\n     **/\n    _listenAppResized() {\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent(Consts.Events().WIN_SIZED).subscribe((msg: IMessage) => {\n                if (_.isUndefined(this.m_canvas))\n                    return;\n                this.m_canvas.calcOffset();\n            }, (e) => console.error(e))\n        )\n    }\n\n    /**\n     Scene block scales via mouse UI\n     @method _sceneBlockScaled\n     @param {Event} e\n     **/\n    _sceneBlockScaled(e) {\n        var self = this;\n        if (self.m_objectScaling)\n            return;\n        self.m_objectScaling = 1;\n        var block = e.target;\n        if (_.isUndefined(block))\n            return;\n        self.zone.runOutsideAngular(() => {\n            block.on('modified', function () {\n                setTimeout(function () {\n                    block.off('modified');\n                    if (!(block instanceof BlockFabric))\n                        return;\n                    var blockID = block.getBlockData().blockID;\n                    self.commBroker.fire({event: SCENE_BLOCK_CHANGE, fromInstance: this, message: [blockID]});\n                    self.m_objectScaling = 0;\n                }, 15)\n            });\n        });\n    }\n\n    /**\n     Scene block moving\n     @method _sceneBlockMoving\n     @param {Object} i_options\n     **/\n    _sceneBlockMoving(i_options) {\n        var grid = 0;\n        if (i_options.target.lockMovementX)\n            return;\n        if (this.m_gridMagneticMode == 0)\n            return;\n        if (this.m_gridMagneticMode == 1)\n            grid = 5;\n        if (this.m_gridMagneticMode == 2)\n            grid = 10;\n        i_options.target.set({\n            left: Math.round(i_options.target.left / grid) * grid,\n            top: Math.round(i_options.target.top / grid) * grid\n        });\n    }\n\n    /**\n     Listen to changes in scale so we can reset back to non-zoom on any block object\n     @method _listenBlockModified\n     **/\n    _listenBlockModified() {\n        var self = this;\n        self.zone.runOutsideAngular(() => {\n            self.m_canvas.on({\n                //'object:moving': self.m_objectScaleHandler,\n                //'object:selected': self.m_objectScaleHandler,\n                'object:modified': () => {\n                    self._sceneBlockModified();\n                },\n                'object:scaling': $.proxy(self._sceneBlockScaled, self)\n            });\n            self.m_canvas.on('object:moving', $.proxy(self._sceneBlockMoving, self));\n        });\n    }\n\n    _drawGrid() {\n        this.m_canvas.setBackgroundColor('', this.m_canvas.renderAll.bind(this.m_canvas));\n        var c: any = $(this.m_canvas)[0];\n        var context = c.getContext(\"2d\");\n        var h = 600;\n        var w = 700;\n        for (var x = 0.5; x < (w + 1); x += 10) {\n            context.moveTo(x, 0);\n            context.lineTo(x, (h + 1));\n        }\n        for (var y = 0.5; y < (h + 1); y += 10) {\n            context.moveTo(0, y);\n            context.lineTo(w, y);\n        }\n        context.globalAlpha = 0.1;\n        context.strokeStyle = \"black\";\n        context.stroke();\n        context.globalAlpha = 1;\n    }\n\n    /**\n     Listen to canvas user selections\n     @method _listenCanvasSelections\n     **/\n    _listenCanvasSelections() {\n        this.zone.runOutsideAngular(() => {\n            //this.m_canvas.on('object:selected',  (e) => {\n            //    var blockID = e.target.m_blockType;\n            //    BB.comBroker.fire(BB.EVENTS.BLOCK_SELECTED, this, null, blockID);\n            //});\n\n            this.m_canvas.on('mouse:down', (options) => {\n                this.m_canvasMouseState = 1;\n            });\n\n            this.m_canvas.on('mouse:up', (options) => {\n                this.m_canvasMouseState = 0;\n                var active = this.m_canvas.getActiveObject();\n                var group = this.m_canvas.getActiveGroup();\n\n                //options.e.stopImmediatePropagation();\n                //options.e.preventDefault();\n\n                //// Group\n                if (group) {\n                    con('group selected');\n                    var selectedGroup = options.target || group;\n                    _.each(group.objects, (selectedObject:any) => {\n                        var objectPos = {\n                            x: (selectedGroup.left + (selectedObject.left)),\n                            y: (selectedGroup.top + (selectedObject.top))\n                        };\n                        if (objectPos.x < 0 && objectPos.y < 0) {\n                            // objectPos.x = objectPos.x * -1;\n                            // objectPos.y = objectPos.y * -1;\n                            return;\n                        }\n                        var blockID = selectedObject.getBlockData().blockID;\n                        con('object: ' + selectedObject.m_blockType + ' ' + blockID);\n                        this._updateBlockCords(selectedObject, true, objectPos.x, objectPos.y, selectedObject.currentWidth, selectedObject.currentHeight, selectedObject.angle);\n                        // this._updateZorder();\n                    });\n                    // this._mementoAddState();\n                    selectedGroup.hasControls = false;\n                    // this.m_property = BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']).resetPropertiesView();\n                    return;\n                }\n\n                //// Object\n                if (options.target || active) {\n                    var block = options.target || active;\n                    this._blockSelected(block);\n                    return;\n                }\n\n                //// Scene\n                this._sceneCanvasSelected();\n                con('scene: ' + this.m_selectedSceneID);\n                // log('object ' + options.e.clientX + ' ' + options.e.clientY + ' ' + options.target.m_blockType);\n\n            });\n        });\n    }\n\n    /**\n     Select a block object on the canvas\n     @method _blockSelected\n     @param {Object} i_block\n     **/\n    _blockSelected(i_block) {\n        this.m_canvas.setActiveObject(i_block);\n        var blockID = i_block.getBlockData().blockID;\n        // con('object: ' + i_block.m_blockType + ' ' + blockID);\n        this._updateBlockCords(i_block, true, i_block.left, i_block.top, i_block.currentWidth, i_block.currentHeight, i_block.angle);\n        this.commBroker.fire({event: BLOCK_SELECTED, fromInstance: this, message: blockID});\n    }\n\n    /**\n     Deselect current group and or block selections\n     @method _canvasDiscardSelections\n     **/\n    _discardSelections() {\n        if (!this.m_canvas)\n            return;\n        this.m_canvas.discardActiveGroup();\n        this.m_canvas.discardActiveObject();\n    }\n\n    /**\n     Set the scene (i.e.: Canvas) as the selected block\n     @method _sceneCanvasSelected\n     **/\n    _sceneCanvasSelected() {\n        var self = this;\n        if (_.isUndefined(self.m_selectedSceneID))\n            return;\n        self._discardSelections();\n        this.commBroker.fire({event: BLOCK_SELECTED, fromInstance: this, message: self.m_selectedSceneID});\n    }\n\n    _onItemSelectedFromToolbar(blockID) {\n        if (blockID == 'SCENE')\n            return this._sceneCanvasSelected();\n\n        for (var i = 0; i < this.m_canvas.getObjects().length; i++) {\n            if (this.m_canvas.item(i).getBlockData().blockID == blockID) {\n                this._blockSelected(this.m_canvas.item(i));\n                break;\n            }\n        }\n    }\n\n    /**\n     Update the coordinates of a block in pepper db, don't allow below w/h MIN_SIZE\n     **/\n    _updateBlockCords(i_block, i_calcScale, x, y, w, h, a) {\n\n        var blockID = i_block.getBlockData().blockID;\n        var blockMinWidth = i_block.getBlockData().blockMinWidth;\n        var blockMinHeight = i_block.getBlockData().blockMinHeight;\n\n        if (i_calcScale) {\n            var sy = 1 / this.m_canvasScale;\n            var sx = 1 / this.m_canvasScale;\n            h = h * sy;\n            w = w * sx;\n            x = x * sx;\n            y = y * sy;\n        }\n        if (h < blockMinHeight)\n            h = blockMinHeight;\n        if (w < blockMinWidth)\n            w = blockMinWidth;\n\n        var domPlayerData = this.rp.getScenePlayerdataBlock(this.m_selectedSceneID, blockID);\n        var layout = $(domPlayerData).find('Layout');\n        layout.attr('rotation', parseInt(a));\n        layout.attr('x', parseInt(x));\n        layout.attr('y', parseInt(y));\n        layout.attr('width', parseInt(w));\n        layout.attr('height', parseInt(h));\n        var player_data = (new XMLSerializer()).serializeToString(domPlayerData);\n        this.rp.setScenePlayerdataBlock(this.m_selectedSceneID, blockID, player_data);\n        this.rp.reduxCommit();\n    }\n\n    /**\n     Reset all canvas objects to their scale is set to 1\n     @method _resetAllObjectScale\n     **/\n    _resetAllObjectScale() {\n        if (_.isUndefined(this.m_selectedSceneID))\n            return;\n        _.each(this.m_canvas.getObjects(), (obj) => {\n            this._resetObjectScale(obj);\n        });\n        // this.m_canvas.renderAll();\n    }\n\n    /**\n     Reset a canvas object so its scale is set to 1\n     @method _resetObjectScale\n     **/\n    _resetObjectScale(i_target) {\n        if (_.isNull(i_target))\n            return;\n        if (i_target.width != i_target.currentWidth || i_target.height != i_target.currentHeight) {\n            i_target.width = i_target.currentWidth;\n            i_target.height = i_target.currentHeight;\n            i_target.scaleX = 1;\n            i_target.scaleY = 1;\n        }\n    }\n\n    /**\n     Remove all block instances\n     @method _disposeBlocks\n     @params {Number} [i_blockID] optional to remove only a single block\n     **/\n    _disposeBlocks(i_blockID ?) {\n        var i;\n        if (_.isUndefined(this.m_canvas))\n            return;\n        var totalObjects = this.m_canvas.getObjects().length;\n        var c = -1;\n        for (i = 0; i < totalObjects; i++) {\n            c++;\n            var block = this.m_canvas.item(c);\n            // single block\n            if (i_blockID) {\n                if (block.getBlockData().blockID == i_blockID) {\n                    block.selectable = false; // fix fabric scale block bug\n                    this.m_canvas.remove(block);\n                    block.deleteBlock();\n                    break;\n                }\n            } else {\n                // all blocks\n                block.selectable = false; // fix fabric scale block bug\n                this.m_canvas.remove(block);\n                if (block) {\n                    block.deleteBlock();\n                    c--;\n                }\n            }\n        }\n        if (!i_blockID)\n            this.m_canvas.clear();\n    }\n\n    _canvasUnselectable() {\n        var i;\n        if (_.isUndefined(this.m_canvas))\n            return;\n        this.m_canvas.removeListeners();\n        //this.m_canvas.interactive = false;\n        // this.m_canvas.selection = false;\n        var totalObjects = this.m_canvas.getObjects().length;\n        var c = -1;\n        for (i = 0; i < totalObjects; i++) {\n            c++;\n            var block = this.m_canvas.item(c);\n            block.selectable = false;\n            if (block)\n                c--;\n        }\n    }\n\n    /**\n     Zoom to scale size\n     **/\n    _zoomTo(nZooms) {\n        var i;\n        if (nZooms > 0) {\n            for (i = 0; i < nZooms; i++)\n                this._zoomOut();\n        } else {\n            for (i = 0; i > nZooms; nZooms++)\n                this._zoomIn();\n        }\n    }\n\n    /**\n     Zoom to scale size\n     **/\n    _zoomToBlock(nZooms, block) {\n        var i;\n        if (nZooms > 0) {\n            for (i = 0; i < nZooms; i++)\n                this._zoomOutBlock(block);\n        } else {\n            for (i = 0; i > nZooms; nZooms++)\n                this._zoomInBlock(block);\n        }\n    }\n\n    /**\n     Scroll canvas to set position\n     **/\n    _scrollTo(i_top, i_left) {\n        var self = this;\n        $('#scenesPanel', this.el.nativeElement).scrollTop(i_top);\n        $('#scenesPanel', this.el.nativeElement).scrollLeft(i_left);\n    }\n\n    /**\n     Zoom scene in\n     @method _zoomIn\n     **/\n    _zoomIn() {\n        if (_.isUndefined(this.m_selectedSceneID))\n            return;\n        this.m_canvasScale = this.m_canvasScale * this.SCALE_FACTOR;\n        this.m_canvas.setHeight(this.m_canvas.getHeight() * this.SCALE_FACTOR);\n        this.m_canvas.setWidth(this.m_canvas.getWidth() * this.SCALE_FACTOR);\n        this._notifyScaleChange();\n        var objects = this.m_canvas.getObjects();\n        for (var i in objects) {\n            if (_.isNull(objects[i]))\n                return;\n            this._zoomInBlock(objects[i]);\n        }\n    }\n\n    /**\n     Zoom scene in\n     @method _zoomIn\n     **/\n    _zoomInBlock(i_block) {\n        var scaleX = i_block.scaleX;\n        var scaleY = i_block.scaleY;\n        var left = i_block.left;\n        var top = i_block.top;\n        var tempScaleX = scaleX * this.SCALE_FACTOR;\n        var tempScaleY = scaleY * this.SCALE_FACTOR;\n        var tempLeft = left * this.SCALE_FACTOR;\n        var tempTop = top * this.SCALE_FACTOR;\n\n        i_block['canvasScale'] = this.m_canvasScale;\n        i_block.scaleX = tempScaleX;\n        i_block.scaleY = tempScaleY;\n        i_block.left = tempLeft;\n        i_block.top = tempTop;\n        i_block.setCoords();\n\n        if (i_block.forEachObject != undefined) {\n            i_block.forEachObject((obj) => {\n                var scaleX = obj.scaleX;\n                var scaleY = obj.scaleY;\n                var left = obj.left;\n                var top = obj.top;\n                var tempScaleX = scaleX * this.SCALE_FACTOR;\n                var tempScaleY = scaleY * this.SCALE_FACTOR;\n                var tempLeft = left * this.SCALE_FACTOR;\n                var tempTop = top * this.SCALE_FACTOR;\n                obj['canvasScale'] = this.m_canvasScale;\n                obj.scaleX = tempScaleX;\n                obj.scaleY = tempScaleY;\n                obj.left = tempLeft;\n                obj.top = tempTop;\n                obj.setCoords();\n            });\n        }\n    }\n\n    /**\n     Zoom scene out\n     @method _zoomOut\n     **/\n    _zoomOutBlock(i_block) {\n        var scaleX = i_block.scaleX;\n        var scaleY = i_block.scaleY;\n        var left = i_block.left;\n        var top = i_block.top;\n        var tempScaleX = scaleX * (1 / this.SCALE_FACTOR);\n        var tempScaleY = scaleY * (1 / this.SCALE_FACTOR);\n        var tempLeft = left * (1 / this.SCALE_FACTOR);\n        var tempTop = top * (1 / this.SCALE_FACTOR);\n        i_block['canvasScale'] = this.m_canvasScale;\n        i_block.scaleX = tempScaleX;\n        i_block.scaleY = tempScaleY;\n        i_block.left = tempLeft;\n        i_block.top = tempTop;\n        i_block.setCoords();\n\n        if (i_block.forEachObject != undefined) {\n            i_block.forEachObject((obj) => {\n                var scaleX = obj.scaleX;\n                var scaleY = obj.scaleY;\n                var left = obj.left;\n                var top = obj.top;\n                var tempScaleX = scaleX * (1 / this.SCALE_FACTOR);\n                var tempScaleY = scaleY * (1 / this.SCALE_FACTOR);\n                var tempLeft = left * (1 / this.SCALE_FACTOR);\n                var tempTop = top * (1 / this.SCALE_FACTOR);\n                obj['canvasScale'] = this.m_canvasScale;\n                obj.scaleX = tempScaleX;\n                obj.scaleY = tempScaleY;\n                obj.left = tempLeft;\n                obj.top = tempTop;\n                obj.setCoords();\n            });\n        }\n    }\n\n    /**\n     Zoom scene out\n     @method _zoomOut\n     **/\n    _zoomOut() {\n        if (_.isUndefined(this.m_selectedSceneID))\n            return;\n        this.m_canvasScale = this.m_canvasScale / this.SCALE_FACTOR;\n        this.m_canvas.setHeight(this.m_canvas.getHeight() * (1 / this.SCALE_FACTOR));\n        this.m_canvas.setWidth(this.m_canvas.getWidth() * (1 / this.SCALE_FACTOR));\n        this._notifyScaleChange();\n        var objects = this.m_canvas.getObjects();\n        for (var i in objects) {\n            if (_.isNull(objects[i]))\n                return;\n            this._zoomOutBlock(objects[i]);\n        }\n    }\n\n    /**\n     Zoom reset back to scale 1\n     @method _zoomReset\n     **/\n    _zoomReset() {\n        if (_.isUndefined(this.m_selectedSceneID) || _.isUndefined(this.m_canvas)) {\n            this.m_canvasScale = 1;\n            this._notifyScaleChange();\n            return;\n        }\n        this._discardSelections();\n        this.m_canvas.setHeight(this.m_canvas.getHeight() * (1 / this.m_canvasScale));\n        this.m_canvas.setWidth(this.m_canvas.getWidth() * (1 / this.m_canvasScale));\n        var objects = this.m_canvas.getObjects();\n        for (var i in objects) {\n            if (_.isNull(objects[i]))\n                return;\n            var scaleX = objects[i].scaleX;\n            var scaleY = objects[i].scaleY;\n            var left = objects[i].left;\n            var top = objects[i].top;\n            var tempScaleX = scaleX * (1 / this.m_canvasScale);\n            var tempScaleY = scaleY * (1 / this.m_canvasScale);\n            var tempLeft = left * (1 / this.m_canvasScale);\n            var tempTop = top * (1 / this.m_canvasScale);\n            objects[i].scaleX = tempScaleX;\n            objects[i].scaleY = tempScaleY;\n            objects[i].left = tempLeft;\n            objects[i].top = tempTop;\n            objects[i].setCoords();\n            objects[i]['canvasScale'] = 1;\n\n            if (objects[i].forEachObject != undefined) {\n                objects[i].forEachObject((obj) => {\n                    var scaleX = obj.scaleX;\n                    var scaleY = obj.scaleY;\n                    var left = obj.left;\n                    var top = obj.top;\n                    var tempScaleX = scaleX * (1 / this.m_canvasScale);\n                    var tempScaleY = scaleY * (1 / this.m_canvasScale);\n                    var tempLeft = left * (1 / this.m_canvasScale);\n                    var tempTop = top * (1 / this.m_canvasScale);\n                    obj.scaleX = tempScaleX;\n                    obj.scaleY = tempScaleY;\n                    obj.left = tempLeft;\n                    obj.top = tempTop;\n                    obj.setCoords();\n                    obj['canvasScale'] = 1;\n                });\n            }\n        }\n        this.m_canvasScale = 1;\n        this._notifyScaleChange();\n    }\n\n    /**\n     Remove a Scene and cleanup after\n     @method disposeScene\n     **/\n    disposeScene() {\n        if (_.isUndefined(this.m_canvas))\n            return;\n        this.m_canvas.off('mouse:up');\n        this.m_canvas.off('mouse:down');\n        this.m_canvas.off('object:modified');\n        this.m_canvas.off('object:moving');\n        this.m_canvas.off('object:scaling');\n        this.m_canvas.off();\n        this.m_blocks.blocksPost = {};\n        this._disposeBlocks();\n        this.m_sceneBlock.deleteBlock();\n        this.m_canvas.dispose();\n        this.m_canvas = undefined;\n        // this.m_property.resetPropertiesView();\n    }\n\n    /**\n     Create a new scene based on player_data and strip injected IDs if arged\n     @method createScene\n     @param {String} i_scenePlayerData\n     @optional {Boolean} i_stripIDs\n     @optional {Boolean} i_loadScene\n     @optional {String} i_mimeType\n     @optional {String} i_name\n     **/\n    createScene(i_scenePlayerData, i_stripIDs, i_loadScene, i_mimeType, i_name) {\n        if (i_stripIDs)\n            i_scenePlayerData = this.rp.stripPlayersID(i_scenePlayerData);\n        this.m_selectedSceneID = this.rp.createScene(i_scenePlayerData, i_mimeType, i_name);\n        // BB.comBroker.fire(BB.EVENTS.NEW_SCENE_ADDED, this, null, this.m_selectedSceneID);\n        if (i_loadScene)\n            this._loadScene();\n        this.commBroker.fire({event: SCENE_LIST_UPDATED, fromInstance: this});\n        this.rp.reduxCommit();\n    }\n\n    /**\n     Get currently selected scene id\n     @method getSelectedSceneID\n     @return {Number} scene id\n     **/\n    getSelectedSceneID() {\n        return this.m_selectedSceneID;\n    }\n\n    destroy() {\n        // removed since we need to keep this data in store when adding new LocationBlock\n        // let uiState: IUiState = {\n        //     scene: {\n        //         sceneSelected: -1,\n        //         blockSelected: -1\n        //     }\n        // }\n        // this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.disposeScene();\n        this.m_canvasScale = -1;\n        this._notifyScaleChange();\n    }\n}\n\n\n// }\n\n// /**\n//  Listen to undo and redo\n//  @method _listenMemento\n//  **/\n// _listenMemento() {\n//     this.commBroker.onEvent(SCENE_UNDO).subscribe((msg: IMessage) => {\n//         if (this.m_rendering)\n//             return;\n//         this.m_blocks.blockSelected = undefined;\n//         this._discardSelections();\n//         this._mementoLoadState('undo');\n//     });\n//     this.commBroker.onEvent(SCENE_REDO).subscribe((msg: IMessage) => {\n//         if (this.m_rendering)\n//             return;\n//         this.m_blocks.blockSelected = undefined;\n//         this._discardSelections();\n//         this._mementoLoadState('redo');\n//     });\n// }\n\n// _initDimensionProps() {\n// var self = this;\n// require(['DimensionProps'],  (DimensionProps) => {\n//     self.m_dimensionProps = new DimensionProps({\n//         appendTo: Elements.SCENE_BLOCK_PROPS,\n//         showAngle: true,\n//         showLock: true,\n//         hideSpinners: true\n//     });\n//     // self.m_dimensionProps.hideSpinners();\n//     BB.comBroker.setService(BB.SERVICES['DIMENSION_PROPS_LAYOUT'], self.m_dimensionProps);\n//     $(self.m_dimensionProps).on('changed',  (e) => {\n//         var block = self.m_canvas.getActiveObject();\n//         if (_.isNull(block))\n//             return;\n//         var props = e.target.getValues();\n//         var block_id = block.getBlockData().blockID;\n//         self._updateBlockCords(block, false, props.x, props.y, props.w, props.h, props.a);\n//         BB.comBroker.fire(BB.EVENTS['SCENE_BLOCK_CHANGE'], self, null, [block_id]);\n//     });\n//     self._sceneActive();\n// })\n// }\n\n\n// this._sceneProcessing(true, jQueryAny.proxy(function () {\n//     self._disposeBlocks();\n//     self.disposeScene();\n//     self._zoomReset();\n//     // self.m_property.resetPropertiesView();\n//     var domPlayerData = self.rp.getScenePlayerdataDom(self.m_selectedSceneID);\n//     var l = $(domPlayerData).find('Layout').eq(0);\n//     var w = $(l).attr('width');\n//     var h = $(l).attr('height');\n//     self._initializeCanvas(w, h);\n//     // self._initializeScene(self.m_selectedSceneID);\n//     self._initializeScene();\n//     self._preRender(domPlayerData);\n// }), this);\n\n\n// /**\n//  Listen to re-order of screen division, putting selected on top\n//  @method _listenPushToTop\n//  **/\n// _listenPushToTop() {\n//     this.commBroker.onEvent(SCENE_PUSH_TOP).subscribe((msg: IMessage) => {\n//         if (_.isUndefined(this.m_selectedSceneID))\n//             return;\n//         var block = this.m_canvas.getActiveObject();\n//         if (_.isNull(block)) {\n//             this._discardSelections();\n//             return;\n//         }\n//         this.m_canvas.bringToFront(block);\n//         this._updateZorder(this.PUSH_TOP, block);\n//         this._mementoAddState();\n//     });\n// }\n\n// /**\n//  Listen to re-order of screen division, putting selected at bottom\n//  @method _listenPushToBottom\n//  **/\n// _listenPushToBottom() {\n//     this.commBroker.onEvent(SCENE_PUSH_BOTTOM).subscribe((msg: IMessage) => {\n//         if (_.isUndefined(this.m_selectedSceneID))\n//             return;\n//         var block = this.m_canvas.getActiveObject();\n//         if (_.isNull(block)) {\n//             this._discardSelections();\n//             return;\n//         }\n//         this.m_canvas.sendToBack(block);\n//         this._updateZorder(this.PUSH_BOTTOM, block);\n//         this._mementoAddState();\n//     });\n// }\n\n// /**\n//  Listen grid magnet when dragging objects\n//  @method _listenGridMagnet\n//  **/\n// _listenGridMagnet() {\n//     $('#sceneGridMagnet', this.el.nativeElement).on('click', () => {\n//         if (this.m_rendering || _.isUndefined(this.m_canvas))\n//             return;\n//         switch (this.m_gridMagneticMode) {\n//             case 0: {\n//                 this.m_gridMagneticMode = 1;\n//                 break;\n//             }\n//             case 1: {\n//                 this.m_gridMagneticMode = 2;\n//                 break;\n//             }\n//             case 2: {\n//                 this.m_gridMagneticMode = 0;\n//                 break;\n//             }\n//         }\n//         this.m_sceneBlock.setCanvas(this.m_canvas, this.m_gridMagneticMode);\n//     });\n// }\n\n// _listenStackViewSelected() {\n// var appContentFaderView = BB.comBroker.getService(BB.SERVICES['APP_CONTENT_FADER_VIEW']);\n// appContentFaderView.on(BB.EVENTS.SELECTED_STACK_VIEW,  (e) => {\n//     if (e == BB.comBroker.getService(BB.SERVICES['SCENES_LOADER_VIEW'])) {\n//         setTimeout( () => {\n//             if (_.isUndefined(this.m_canvas))\n//                 return;\n//             this.m_canvas.calcOffset();\n//         }, 500);\n//     }\n// });\n// }\n\n\n// /**\n//  Listen to all zoom events via wiring the UI\n//  @method _listenZoom\n//  **/\n// _listenZoom() {\n//     this.commBroker.onEvent(SCENE_ZOOM_IN).subscribe((msg: IMessage) => {\n//         // this.m_property = BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']).resetPropertiesView();\n//         this._zoomIn();\n//         this._discardSelections();\n//         this._resetAllObjectScale();\n//         this.m_canvas.renderAll();\n//     });\n//\n//     this.commBroker.onEvent(SCENE_ZOOM_OUT).subscribe((msg: IMessage) => {\n//         // this.m_property = BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']).resetPropertiesView();\n//         this._zoomOut();\n//         this._discardSelections();\n//         this._resetAllObjectScale();\n//         this.m_canvas.renderAll();\n//     });\n//\n//     this.commBroker.onEvent(SCENE_ZOOM_RESET).subscribe((msg: IMessage) => {\n//         // this.m_property = BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']).resetPropertiesView();\n//         this._zoomReset();\n//         this._resetAllObjectScale();\n//         this.m_canvas.renderAll();\n//     });\n// }\n\n// /**\n//  Announce that block count changed with block array of ids\n//  @method self._updateBlockCount();\n//  **/\n// _updateBlockCount() {\n//     setTimeout(() => {\n//         this.m_sceneBlockIds = List([{id: 'SCENE', name: '[Scene canvas]'}]);\n//         var objects = this.m_canvas.getObjects().length;\n//         for (var i = 0; i < objects; i++) {\n//             this.m_sceneBlockIds = this.m_sceneBlockIds.push({\n//                 id: this.m_canvas.item(i).m_block_id,\n//                 name: this.m_canvas.item(i).m_blockName\n//             });\n//         }\n//         // con('NEW LIST CREATED');\n//         // this.sceneToolbar.updateBlocks(this.m_sceneBlockIds);\n//     }, 1000)\n//\n// }\n\n\n\n"
  },
  {
    "path": "src/app/scenes/scene-list.ts",
    "content": "import {Component, ChangeDetectionStrategy, Input, Output, EventEmitter} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {IUiState} from \"../../store/store.data\";\nimport {SideProps} from \"../../store/actions/appdb.actions\";\nimport {BlockService, ISceneData} from \"../blocks/block-service\";\n\n@Component({\n    selector: 'scene-list',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <ul (click)=\"$event.preventDefault()\" class=\"appList list-group\">\n\n            <a *ngFor=\"let scene of m_scenes; let i = index\" (click)=\"_onSceneSelected($event, scene, i)\"\n               [ngClass]=\"{'selectedItem': selectedIdx == i}\" href=\"#\" class=\"list-group-item\">\n                <h4>{{scene?.playerDataModel.getSceneName}}</h4>\n                <!-- todo: build local array from playerDataModel on use it as data source so we can remove XML processing from getSceneName and show font awesome -->\n                <!--<i class=\"fa {{item.blockFontAwesome}}\"></i>-->\n                <p class=\"list-group-item-text\">scene type: {{scene?.playerDataModel.getSceneMime}} </p>\n                <div class=\"openProps\">\n                    <button type=\"button\" class=\"props btn btn-default btn-sm\"><i style=\"font-size: 1.5em\" class=\"props fa fa-gear\"></i></button>\n                </div>\n            </a>\n        </ul>\n    `,\n})\nexport class SceneList extends Compbaser {\n    selectedIdx = -1;\n    m_scenes: Array<ISceneData>;\n    m_selectedScene: ISceneData;\n\n    constructor(private bs: BlockService) {\n        super();\n    }\n\n    @Input()\n    set scenes(i_scenes: Array<ISceneData>) {\n        this.m_scenes = i_scenes;\n    }\n\n    @Output()\n    slideToSceneEditor: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    slideToSceneName: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onSceneSelected: EventEmitter<any> = new EventEmitter<any>();\n\n    _onSceneSelected(event: MouseEvent, scene: ISceneData, index) {\n        this.selectedIdx = index;\n        let uiState: IUiState;\n        if (jQuery(event.target).hasClass('props')) {\n            uiState = {\n                uiSideProps: SideProps.sceneProps,\n                scene: {sceneSelected: scene.scene_id}\n            }\n            this.onSceneSelected.emit(uiState)\n        } else {\n            uiState = {\n                uiSideProps: SideProps.miniDashboard,\n                scene: {sceneSelected: scene.scene_id}\n            }\n            this.slideToSceneEditor.emit();\n            this.onSceneSelected.emit(uiState)\n        }\n        this.m_selectedScene = scene;\n    }\n\n    resetSelection(){\n        this.selectedIdx = -1;\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/scenes/scene-manager.ts",
    "content": "import {Component, ElementRef, EventEmitter, Output, ViewChild} from \"@angular/core\";\nimport {Observable} from \"rxjs\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Router} from \"@angular/router\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {ISceneData} from \"../blocks/block-service\";\nimport {SceneList} from \"./scene-list\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {WizardService} from \"../../services/wizard-service\";\n\n@Component({\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'scene-manager',\n    template: `\n        <small class=\"debug\" style=\"padding-left: 30px\">{{me}}</small>\n        <div style=\"padding-bottom: 10px\">\n            <span id=\"sceneSelection\"style=\"font-size: 1.8em;\" i18n>scene selection</span>\n        </div>\n        <div>\n            <div class=\"btn-group\">\n                <button id=\"newScene\" (click)=\"_newScene()\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-rocket\"></i>\n                    <span i18n>new scene</span>\n                </button>\n                <button (click)=\"_removeScene()\" [disabled]=\"(sceneSelected$ | async) == -1\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-trash-o\"></i>\n                    <span i18n>remove</span>\n                </button>\n                <button (click)=\"_duplicateScene()\" [disabled]=\"(sceneSelected$ | async) == -1\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-files-o\"></i>\n                    <span i18n>duplicate</span>\n                </button>\n            </div>\n        </div>\n        <!-- move scroller to proper offset -->\n        <div class=\"responsive-pad-right\">\n            <div id=\"sceneListItems\" matchBodyHeight=\"350\" style=\"overflow: scroll\">\n                <scene-list [scenes]=\"scenes$ | async\" (slideToSceneEditor)=\"slideToSceneEditor.emit($event)\" (onSceneSelected)=\"_onSceneSelected($event)\">\n                </scene-list>\n            </div>\n        </div>\n    `\n})\nexport class SceneManager extends Compbaser {\n\n    sceneSelected$;\n    public scenes$: Observable<Array<ISceneData>>\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private toastr: ToastsManager, private wizardService:WizardService) {\n        super();\n        this.preventRedirect(true);\n        this.scenes$ = this.yp.listenScenes()\n        this.sceneSelected$ = this.yp.ngrxStore.select(store => store.appDb.uiState.scene.sceneSelected)\n        this._notifyResetSceneSelection();\n\n        // setTimeout(()=>{\n        //     this.wizardService.inModule('scenes');\n        // },4000)\n    }\n\n    @ViewChild(SceneList)\n    sceneList:SceneList;\n\n    @Output()\n    sceneCreate: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    slideToSceneEditor: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    slideToCampaignName: EventEmitter<any> = new EventEmitter<any>();\n\n    _notifyResetSceneSelection(){\n        var uiState: IUiState = {scene: {sceneSelected: -1}}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    _removeScene() {\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.uiState.scene.sceneSelected)\n                .take(1)\n                .subscribe(scene_id => {\n                    bootbox.confirm('Are you sure you want to remove the selected scene', (result) => {\n                        if (result == true) {\n                            this._notifyResetSceneSelection();\n                            this.rp.removeBlocksWithSceneID(scene_id);\n                            this.rp.removeSceneFromBlockCollectionInScenes(scene_id);\n                            this.rp.removeSceneFromBlockCollectionsInChannels(scene_id);\n                            this.rp.removeSceneFromBlockLocationInScenes(scene_id);\n                            this.rp.removeSceneFromBlockLocationInChannels(scene_id);\n                            this.rp.removeScene(scene_id);\n                            this.rp.reduxCommit();\n                            this.sceneList.resetSelection();\n                            this.toastr.info('scene removed from scene list');\n                        }\n                    });\n                })\n        )\n    }\n\n    _duplicateScene() {\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.uiState.scene.sceneSelected)\n                .take(1)\n                .subscribe(scene_id => {\n                    var scenePlayerData = this.rp.getScenePlayerdata(scene_id);\n                    this.createScene(scenePlayerData, true, '');\n                    this.toastr.info('scene duplicated and is available in scene list');\n                })\n        )\n    }\n\n    /**\n     Create a new scene based on player_data and strip injected IDs if arged\n     @method createScene\n     @param {String} i_scenePlayerData\n     @optional {Boolean} i_stripIDs\n     @optional {Boolean} i_loadScene\n     @optional {String} i_mimeType\n     @optional {String} i_name\n     **/\n    private createScene(i_scenePlayerData, i_stripIDs, i_mimeType, i_name?) {\n        if (i_stripIDs)\n            i_scenePlayerData = this.rp.stripPlayersID(i_scenePlayerData);\n        var sceneId = this.rp.createScene(i_scenePlayerData, i_mimeType, i_name);\n        this.rp.reduxCommit();\n    }\n\n    private save() {\n        con('saving...');\n        this.rp.save((result) => {\n            if (result.status == true) {\n                bootbox.alert('saved');\n            } else {\n                alert(JSON.stringify(result));\n            }\n        });\n    }\n\n    _onSceneSelected(i_uiState: IUiState) {\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: i_uiState}))\n    }\n\n    _newScene() {\n        this.sceneCreate.emit();\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        this.slideToCampaignName.emit();\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/scenes/scene-props-manager.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Observable} from \"rxjs\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {BlockService, IBlockData, ISceneData} from \"../blocks/block-service\";\nimport {IUiState} from \"../../store/store.data\";\nimport * as _ from 'lodash';\nimport {CommBroker} from \"../../services/CommBroker\";\n\n@Component({\n    selector: 'scene-props-manager',\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        ul {\n            padding: 0\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <ul matchBodyHeight=\"50\" style=\"overflow-y: auto; overflow-x: hidden\" [ngSwitch]=\"m_sideProps$ | async\">\n            <div *ngSwitchCase=\"m_sidePropsEnum.sceneEditor\">\n                <h5>scene editor</h5>\n            </div>\n            <div *ngSwitchCase=\"m_sidePropsEnum.sceneProps\">\n                <block-prop-scene [setBlockData]=\"m_blockData\"></block-prop-scene>\n            </div>\n            <div *ngSwitchCase=\"m_sidePropsEnum.sceneBlock\">\n                <block-prop-position></block-prop-position>\n                <block-prop-container></block-prop-container>\n            </div>\n            <div *ngSwitchCase=\"m_sidePropsEnum.miniDashboard\">\n                <dash-panel-mini></dash-panel-mini>\n            </div>\n        </ul>\n    `,\n})\nexport class ScenePropsManager extends Compbaser {\n\n    m_blockData: IBlockData;\n\n    constructor(private yp: YellowPepperService, private bs: BlockService, private commBroker: CommBroker) {\n        super();\n        this.m_sideProps$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n\n        this.cancelOnDestroy(\n            //\n            this.commBroker.onEvent('SCENE_ITEM_REMOVE')\n                .subscribe(() => {\n                    var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n                    this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                })\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenSceneSelected(true)\n                .mergeMap((i_sceneData: ISceneData) => {\n                    return this.bs.getBlockDataInScene(i_sceneData);\n                }).subscribe((i_blockData) => {\n                this.m_blockData = i_blockData;\n            }, (e) => console.error(e))\n        )\n    }\n\n    m_sidePropsEnum = SideProps;\n    m_sideProps$: Observable<SideProps>;\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/scenes/scene-toolbar.ts",
    "content": "import {Component, ChangeDetectionStrategy, AfterViewInit, Output, EventEmitter, Input, ChangeDetectorRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {FormBuilder, FormGroup} from \"@angular/forms\";\nimport * as _ from 'lodash';\nimport {PlayerDataModelExt} from \"../../store/model/msdb-models-extended\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\n@Component({\n    selector: 'scene-toolbar',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <form novalidate autocomplete=\"off\" class=\"inner5\" [formGroup]=\"m_contGroup\">\n            <div id=\"sceneToolbar\">\n                <div class=\"btn-group\">\n                    <button (click)=\"_goBack()\" type=\"button\" title=\"back\" class=\"openPropsButton btn btn-default btn-sm\">\n                        <span class=\"glyphicon glyphicon-chevron-left\"></span>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('add')\" type=\"button\" title=\"add item\" class=\"sceneAddNew btn btn-default btn-sm\">\n                        <i style=\"font-size: 1em\" class=\"fa fa-plus\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('removeItem')\" type=\"button\" title=\"remove item\" class=\"sceneRemoves btn btn-default btn-sm\">\n                        <i style=\"font-size: 1em\" class=\"fa fa-minus\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('playPreview')\" id=\"scenePlayPreview\" type=\"button\" title=\"play preview\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1em\" class=\"fa fa-play\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('pushItemToTopButtonToolTip')\" id=\"sceneEditorPushTop\" title=\"push item to top\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1em\" class=\"fa fa-angle-double-up\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('pushItemToBottomButtonToolTip')\" id=\"sceneEditorPushBottom\" title=\"push item to bottom\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1em\" class=\"fa fa-angle-double-down\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('sceneZoomIn')\" id=\"sceneZoomIn\" type=\"button\" title=\"zoom in\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1.3em\" class=\"fa fa-search-plus\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('sceneZoomOut')\" id=\"sceneZoomOut\" type=\"button\" title=\"zoom out\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1.3em\" class=\"fa fa-search-minus\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('sceneZoomReset')\" id=\"sceneZoomReset\" type=\"button\" title=\"zoom reset\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1.3em\" class=\"fa fa-search\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('undo')\" id=\"sceneUndo\" type=\"button\" title=\"undo\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1.3em\" class=\"fa fa-reply\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('redo')\" id=\"sceneRedo\" type=\"button\" title=\"redo\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1.3em\" class=\"fa fa-share\"> </i>\n                    </button>\n                    <button (click)=\"onToolbarAction.emit('magneticGrid')\" id=\"sceneGridMagnet\" type=\"button\" title=\"magnetic grid\" class=\"btn btn-default btn-sm\">\n                        <i style=\"font-size: 1.3em\" class=\"fa fa-th-large\"> </i>\n                    </button>\n                    <div class=\"input-group\" style=\"margin-left: 0px; position: relative; top: -10px\">\n                        <select #sceneSelection style=\"height: 30px; max-width: 150px; width: 150px\" (change)=\"_onBlockSelected($event)\" formControlName=\"blocks\">\n                            <option [value]=\"block.id\" *ngFor=\"let block of m_blocks\">{{block.name}}</option>\n                        </select>\n                    </div>\n                </div>\n            </div>\n        </form>\n\n    `,\n})\nexport class SceneToolbar extends Compbaser {\n\n    m_formInputs = {};\n    m_contGroup: FormGroup;\n    m_blocks = [];\n\n    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef) {\n        super();\n        this.m_contGroup = fb.group({\n            'blocks': []\n        });\n    }\n\n    @Input()\n    set blocks(i_blocks) {\n        this.m_blocks = i_blocks;\n    }\n\n    @Output()\n    onToolbarAction: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onItemSelected: EventEmitter<string> = new EventEmitter<string>();\n\n    @timeout(100)\n    _goBack(){\n        this.onToolbarAction.emit('back')\n    }\n    \n    _onBlockSelected(event) {\n        this.onItemSelected.emit(event.target.value);\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/app/scenes/scenes-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {BlockFactoryService} from \"../../services/block-factory-service\";\nimport {PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {AppdbAction, AuthenticateFlags} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    providers: [BlockService, BlockFactoryService, {\n        provide: \"BLOCK_PLACEMENT\",\n        useValue: PLACEMENT_SCENE\n    }],\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <small class=\"debug\">scene-navigation</small>\n        <div *ngIf=\"(userModel$ | async).getAccountType() == m_AuthenticateFlags.USER_ACCOUNT_PRO; else fullAccess\">\n            <limited-access></limited-access>\n        </div>\n        <ng-template #fullAccess>\n            <panel-split-container>\n                <panel-split-main>\n                    <scenes>\n                    </scenes>\n                </panel-split-main>\n                <panel-split-side>\n                    <scene-props-manager></scene-props-manager>\n                </panel-split-side>\n            </panel-split-container>\n        </ng-template>\n    `\n})\nexport class ScenesNavigation extends Compbaser {\n    userModel$;\n    m_AuthenticateFlags = AuthenticateFlags;\n\n    constructor(private yp: YellowPepperService) {\n        super();\n        this.userModel$ = this.yp.listenUserModel();\n    }\n}\n\n"
  },
  {
    "path": "src/app/scenes/scenes.ts",
    "content": "import {ChangeDetectionStrategy, Component, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {PLACEMENT_SCENE} from \"../../interfaces/Consts\";\nimport {ISliderItemData, Slideritem} from \"../../comps/sliderpanel/Slideritem\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'scenes',\n    template: `\n        <small class=\"debug\" style=\"padding-right: 25px\">{{me}}</small>\n        <Sliderpanel>\n            <Slideritem [templateRef]=\"a\" #sliderItemSceneManager class=\"page center sceneList selected\" [showToButton]=\"false\" [toDirection]=\"'right'\" [to]=\"'sceneEditor'\">\n                <ng-template #a>\n                    <scene-manager (sceneCreate)=\"sliderItemSceneManager.slideTo('sceneCreator','right')\" (slideToSceneEditor)=\"sliderItemSceneManager.onNext()\"></scene-manager>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"b\" #sliderItemCampaignEditor (onChange)=\"_onSlideChange($event)\" [showFromButton]=\"false\" class=\"page left sceneEditor\" [fromDirection]=\"'left'\" [from]=\"'sceneList'\">\n                <ng-template #b>\n                    <scene-editor #sceneEditor (onGoBack)=\"sliderItemCampaignEditor.slideTo('sceneList','left')\">\n                    </scene-editor>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"c\" #sliderSceneCreator [showFromButton]=\"false\" class=\"page left sceneCreator\" [fromDirection]=\"'left'\" [from]=\"'sceneList'\">\n                <ng-template #c>\n                    <scene-creator (onGoBack)=\"sliderSceneCreator.slideTo('sceneList','left')\"></scene-creator>\n                </ng-template>\n            </Slideritem>\n            <Slideritem [templateRef]=\"d\" #sliderLocation [showFromButton]=\"false\" class=\"page left locationMap\" [fromDirection]=\"'right'\" [from]=\"'sceneEditor'\">\n                <ng-template #d>\n                    <location-map (onClose)=\"_onLocationMapClosed()\"></location-map>\n                </ng-template>\n            </Slideritem>\n        </Sliderpanel>\n    `\n})\nexport class Scenes extends Compbaser {\n\n    private m_placement = PLACEMENT_SCENE;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        var uiState: IUiState = {uiSideProps: SideProps.miniDashboard}\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenLocationMapLoad()\n                .subscribe((v) => {\n                    if (v){\n                        this.sliderSceneCreator.slideTo('locationMap','right')\n                    }\n                }, (e) => console.error(e))\n\n        )\n\n    }\n\n    @ViewChild('sliderSceneCreator')\n    sliderSceneCreator:Slideritem;\n\n\n    _onLocationMapClosed(){\n        this.sliderSceneCreator.slideTo('sceneEditor','left')\n\n    }\n\n    _onSlideChange(event: ISliderItemData) {\n        if (event.direction == 'left' && event.to == 'sceneList') {\n            var uiState:IUiState = {\n                uiSideProps: SideProps.miniDashboard,\n                scene: {sceneSelected: -1}\n            }\n            return this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        }\n        // if (event.direction == 'right' && event.to == 'campaignEditor')\n        //     return this._createCampaign();\n    }\n}\n\n"
  },
  {
    "path": "src/app/settings/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {SettingsNavigation} from \"./settings-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {Twofactor} from \"./twofactor\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: SettingsNavigation},\n    {path: ':folder/:id', component: SettingsNavigation},\n    {path: '**', component: SettingsNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [SettingsNavigation, Twofactor]\n})\nexport class SettingsLazyModule {\n}"
  },
  {
    "path": "src/app/settings/settings-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <!-- not using two factor for now -->\n        <!--<Twofactor></Twofactor>-->\n    `,\n})\nexport class SettingsNavigation extends Compbaser {\n\n    constructor() {\n        super();\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/settings/twofactor.ts",
    "content": "import {Component, ChangeDetectionStrategy, ElementRef, ViewChild, ChangeDetectorRef} from \"@angular/core\";\nimport {FormControl, FormGroup, FormBuilder} from \"@angular/forms\";\nimport * as _ from \"lodash\";\nimport {LocalStorage} from \"../../services/LocalStorage\";\nimport {AppdbAction, AuthenticateFlags} from \"../../store/actions/appdb.actions\";\nimport {UserModel} from \"../../models/UserModel\";\nimport {Map} from \"immutable\";\nimport {EFFECT_TWO_FACTOR_UPDATING} from \"../../store/effects/appdb.effects\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\n\n@Component({\n    selector: 'Twofactor',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <div>\n            <form novalidate autocomplete=\"off\" [formGroup]=\"contGroup\">\n                <div class=\"row\">\n                    <div class=\"inner userGeneral\">\n                        <div class=\"panel panel-default tallPanel\">\n                            <div class=\"panel-heading\">\n                                <small class=\"release\">general properties\n                                    <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                                </small>\n                            </div>\n                            <ul class=\"list-group\">\n                                <li *ngIf=\"twoFactorStatus\" class=\"list-group-item\">\n                                    Two factor login with Google Authenticator\n                                    <div class=\"material-switch pull-right\">\n                                        <input (change)=\"onChangeStatus(customerNetwork2.checked)\"\n                                               [formControl]=\"contGroup.controls['TwofactorCont']\"\n                                               id=\"customerNetwork2\" #customerNetwork2\n                                               name=\"customerNetwork2\" type=\"checkbox\"/>\n                                        <label for=\"customerNetwork2\" class=\"label-primary\"></label>\n                                    </div>\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n            </form>\n        </div>\n        <div>\n            <div *ngIf=\"!twoFactorStatus\">\n                <input #activate type=\"text\" class=\"longInput form-control\" placeholder=\"scan with Google Authenticator and enter token\">\n                <button (click)=\"onActivate()\" style=\"margin-top: 5px\" class=\"btn btn-primary pull-right\">activate</button>\n            </div>\n        </div>\n    `,\n    styles: [`.material-switch {\n        position: relative;\n        padding-top: 10px;\n    }`]\n})\nexport class Twofactor extends Compbaser {\n    constructor(private fb: FormBuilder,\n                private localStorage: LocalStorage,\n                private el: ElementRef,\n                private cd: ChangeDetectorRef,\n                private appdbAction: AppdbAction,\n                private yp: YellowPepperService) {\n        super();\n        this.contGroup = fb.group({\n            'TwofactorCont': ['']\n        });\n        _.forEach(this.contGroup.controls, (value, key: string) => {\n            this.formInputs[key] = this.contGroup.controls[key] as FormControl;\n        })\n        this.yp.ngrxStore.select(store => store.appDb.userModel).subscribe((userModel: UserModel) => {\n            this.twoFactorStatus = userModel.getTwoFactorRequired();\n            this.changeTwoFactorStatus();\n        }, (e) => {\n            console.error(e)\n        })\n        this.renderFormInputs();\n        this.listenEvents();\n    }\n\n    @ViewChild('activate')\n    activateToken;\n\n    twoFactorStatus: boolean;\n    contGroup: FormGroup;\n    formInputs = {};\n\n    private listenEvents() {\n        this.cancelOnDestroy(\n            this.yp.ngrxStore.select(store => store.appDb.appAuthStatus).skip(1).subscribe((i_authStatus: Map<string,AuthenticateFlags>) => {\n                let authStatus: AuthenticateFlags = i_authStatus.get('authStatus')\n                switch (authStatus) {\n                    case AuthenticateFlags.TWO_FACTOR_UPDATE_PASS: {\n                        bootbox.alert('Congratulations, activated');\n                        break;\n                    }\n                    case AuthenticateFlags.TWO_FACTOR_UPDATE_FAIL: {\n                        bootbox.alert('wrong token entered');\n                        break;\n                    }\n                }\n            }, (e) => {\n                console.error(e)\n            }))\n    }\n\n    private changeTwoFactorStatus() {\n        if (this.twoFactorStatus) {\n            this.twoFactorStatus = true;\n            this.removeQrCode();\n            this.cd.markForCheck();\n            this.localStorage.removeItem('remember_me_studioweb');\n            this.renderFormInputs();\n        } else {\n            // this.removeQrCode();\n            this.cd.markForCheck();\n        }\n    }\n\n    private onActivate() {\n        if (this.activateToken.nativeElement.value.length < 6)\n            return bootbox.alert('token is too short');\n        this.yp.ngrxStore.dispatch({\n            type: EFFECT_TWO_FACTOR_UPDATING,\n            payload: {\n                token: this.activateToken.nativeElement.value,\n                enable: true\n            }\n        })\n    }\n\n    private addQrCode() {\n        this.removeQrCode();\n        this.appdbAction.getQrCodeTwoFactor().take(1).subscribe((qrCode) => {\n            this.removeQrCode();\n            jQuery(this.el.nativeElement).append(qrCode);\n            var svg = jQuery(this.el.nativeElement).find('svg').get(0);\n            // var w = svg.width.baseVal.value;\n            // var h = svg.height.baseVal.value;\n            svg.setAttribute('viewBox', '0 0 ' + 100 + ' ' + 100);\n            svg.setAttribute('width', '40%');\n            // svg.setAttribute('height', '100%');\n        }, (e) => console.error(e));\n    }\n\n    private removeQrCode() {\n        jQuery(this.el.nativeElement).find('svg').remove();\n    }\n\n    private onChangeStatus(i_twoFactorStatus: boolean) {\n        this.twoFactorStatus = i_twoFactorStatus;\n        if (this.twoFactorStatus) {\n            this.removeQrCode();\n        } else {\n            this.addQrCode();\n            bootbox.alert('Token removed, be sure to delete the entry now from Google Authenticator as it is no longer valid');\n        }\n    }\n\n    private renderFormInputs() {\n        this.formInputs['TwofactorCont'].setValue(this.twoFactorStatus);\n        if (this.twoFactorStatus) {\n            this.removeQrCode();\n        } else {\n            this.addQrCode();\n        }\n    }\n\n}"
  },
  {
    "path": "src/app/stations/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {StationsNavigation} from \"./stations-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\nimport {Stations} from \"./stations\";\nimport {StationsList} from \"./stations-list\";\nimport {StationsPropsManager} from \"./stations-props-manager\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: StationsNavigation},\n    {path: ':folder/:id', component: StationsNavigation},\n    {path: '**', component: StationsNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [StationsNavigation, Stations, StationsList, StationsPropsManager]\n})\nexport class StationsLazyModule {\n}"
  },
  {
    "path": "src/app/stations/stations-list.ts",
    "content": "import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {List} from \"immutable\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {StationModel} from \"../../models/StationModel\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\n@Component({\n    selector: 'stations-list',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        input[type=\"checkbox\"] {\n            transform: scale(2, 2);\n            position: relative;\n            top: -40px;\n        }\n\n        .green {\n            color: green;\n        }\n\n        .red {\n            color: red;\n        }\n\n        .yellow {\n            color: yellow;\n        }\n\n        span {\n            background-color: transparent;\n            -webkit-text-stroke: 1px black;\n            text-shadow: 1px 1px 0 #000,\n            -1px -1px 0 #000,\n            1px -1px 0 #000,\n            -1px 1px 0 #000,\n            1px 1px 0 #000;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <ul style=\"padding: 10px\" (click)=\"$event.preventDefault()\" class=\"appList list-group\">\n            <a *ngFor=\"let station of m_stations; let i = index\" (click)=\"_onSelected($event, station, i)\"\n               [class.hidden]=\"station | FilterModelPipe:filter:station:'getStationName'\"\n               [ngClass]=\"{'selectedItem': selectedIdx == i}\" href=\"#\" class=\"list-group-item resourcesListItems\">\n                <span [ngClass]=\"{'green': station.connection == '1', 'red': station.connection == '0', 'yellow': station.connection == '2'}\" class=\"pull-left fa fa-4x fa-circle\"></span>\n                <div style=\"position: relative; left: 20px\">\n                    <h4>{{station.name}}</h4>\n                    <h5>os: {{station.os}}</h5>\n                </div>\n                <input type=\"checkbox\" (click)=\"_onCheckedChange(station)\" [checked]=\"m_checked[station.id] == true\" class=\"pull-right\"/>\n                <!--<i class=\"pull-left fa {{station.airVersion}}\"></i>-->\n                <!--<p class=\"pull-left list-group-item-text\">file type: {{station.os}} </p>-->\n                <!--<span class=\"clearfix\"></span>-->\n                <!--<div class=\"openProps\">-->\n                <!--<button type=\"button\" class=\"props btn btn-default btn-sm\"><i style=\"font-size: 1.5em\" class=\"props fa fa-gear\"></i></button>-->\n                <!--</div>-->\n            </a>\n        </ul>\n    `,\n})\nexport class StationsList extends Compbaser {\n    selectedIdx = -1;\n    m_stations: List<StationModel>;\n    m_checked = {};\n\n    constructor(private bs: BlockService, private el: ElementRef, private cd:ChangeDetectorRef) {\n        super();\n    }\n\n    @Input()\n    set stations(i_stations: List<StationModel>) {\n        this.m_stations = i_stations;\n    }\n\n    @Input() filter;\n\n    @Output()\n    onSelected: EventEmitter<StationModel> = new EventEmitter<StationModel>();\n\n    @Output()\n    onMultiSelected: EventEmitter<any> = new EventEmitter<any>();\n\n    @timeout()\n    _onCheckedChange(station: StationModel) {\n        if (!this.m_checked[station.id]){\n            this.m_checked[station.id] = true;\n        } else {\n            this.m_checked[station.id] = !this.m_checked[station.id];\n        }\n        this.cd.markForCheck();\n        this.onMultiSelected.emit(this.m_checked)\n    }\n\n\n    _onSelected(event: MouseEvent, i_station: StationModel, index) {\n        this.selectedIdx = index;\n        this.onSelected.emit(i_station)\n        // this.cd.markForCheck();\n        // this.m_selected = i_resource;\n    }\n\n    resetSelection() {\n        this.selectedIdx = -1;\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/stations/stations-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {BlockService} from \"../blocks/block-service\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    providers: [BlockService, {\n        provide: \"BLOCK_PLACEMENT\",\n        useValue: ''\n    }\n    ],\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <small class=\"debug\">station-navigation</small>\n        <panel-split-container>\n            <panel-split-main>\n                <stations>\n                </stations>\n            </panel-split-main>\n            <panel-split-side>\n                <stations-props-manager></stations-props-manager>\n            </panel-split-side>\n        </panel-split-container>\n    `\n})\nexport class StationsNavigation extends Compbaser {\n\n    constructor() {\n        super();\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/stations/stations-props-manager.html",
    "content": "<small class=\"debug\">{{me}}</small>\n<hr/>\n<form matchBodyHeight=\"150\" style=\"overflow-y: auto; overflow-x: hidden\" novalidate autocomplete=\"off\" [formGroup]=\"contGroup\">\n    <ul [ngSwitch]=\"m_sideProps$ | async\">\n        <div *ngSwitchCase=\"m_sidePropsEnum.stationProps\">\n            <div id=\"stationProperties\">\n                <img *ngIf=\"m_totalStationsSelected.length <= 1\" lazyImage class=\"center-block\" style=\"width: 229px; height: 130px\"\n                     [loadingImage]=\"'https://secure.digitalsignage.com/studioweb/assets/screen_loading.png'\"\n                     [defaultImage]=\"'https://secure.digitalsignage.com/studioweb/assets/screen.png'\"\n                     [errorImage]=\"'https://secure.digitalsignage.com/studioweb/assets/screen_error.png'\"\n                     [retry]=\"5\"\n                     [delay]=\"1500\"\n                     (loaded)=\"_onLoaded()\"\n                     (error)=\"_onError()\"\n                     (completed)=\"_onCompleted()\">\n\n                <!--<div id=\"snapShotWrap\">-->\n                <!--<img lazyImage [url]=\"'http://s3-us-west-2.amazonaws.com/oregon-signage-snapshots/business358613/station75/_1491055107002.jpg'\">-->\n                <!--<div style=\"text-align: center\">-->\n                <!--<svg style=\"width: 250px\" xmlns=\"http://www.w3.org/2000/svg\">-->\n                <!--<g>-->\n                <!--<rect stroke-width=\"10\" stroke=\"#191919\" height=\"120\" width=\"220\" y=\"9.5\" x=\"10\" fill=\"#cccccc\"></rect>-->\n                <!--</g>-->\n                <!--</svg>-->\n                <!--</div>-->\n                <!--<div style=\"text-align: center\">-->\n                <!--<loading class=\"loading\" [size]=\"'50px'\" *ngIf=\"m_loading\"></loading>-->\n                <!--</div>-->\n                <!--<div *ngIf=\"m_snapPath != ''\" style=\"text-align: center\">-->\n                <!--<img (error)=\"_onImageError($event)\" [src]=\"m_snapPath\"/>-->\n                <!--</div>-->\n                <!--</div>-->\n\n                <hr/>\n                <div id=\"propWrap\">\n                    <div *ngIf=\"m_totalStationsSelected.length <= 1\" id=\"stationcontrol\" class=\"btn-group\">\n                        <button (click)=\"_onCommand('snap')\" [disabled]=\"m_disabled\" type=\"button\" class=\"btn btn-default\">\n                            <span class=\"glyphicon  glyphicon glyphicon-picture\"></span>\n                        </button>\n                        <button (click)=\"_onCommand('play')\" [disabled]=\"m_disabled\" type=\"button\" class=\"btn btn-default\">\n                            <span class=\"glyphicon glyphicon glyphicon-play\"></span>\n                        </button>\n                        <button (click)=\"_onCommand('stop')\" [disabled]=\"m_disabled\" type=\"button\" class=\"btn btn-default\">\n                            <span class=\"glyphicon glyphicon glyphicon-stop\"></span>\n                        </button>\n                        <button (click)=\"_onCommand('off')\" [disabled]=\"m_disabled\" type=\"button\" class=\"btn btn-default\">\n                            <span class=\"fa fa-power-off\"></span>\n                        </button>\n                    </div>\n                    <select (change)=\"saveToStore()\" formControlName=\"m_campaignsControl\" id=\"stationSelectionCampaign\" class=\"form-control\">\n                        <option [value]=\"campaign.getCampaignId()\" *ngFor=\"let campaign of m_campaigns\">{{campaign.getCampaignName()}}</option>\n                    </select>\n                    <br/>\n                    <div *ngIf=\"m_totalStationsSelected.length > 1\">\n                        <select formControlName=\"m_campaignsMultiControl\" class=\"form-control\">\n                            <option [value]=\"options\" *ngFor=\"let options of m_multiOptions\">{{options}}</option>\n                        </select>\n                        <br/>\n                        <button class=\"btn btn-danger center-block\" (click)=\"_onMultiChangeCampaign()\">apply selections</button>\n                    </div>\n                    <div *ngIf=\"m_totalStationsSelected.length <= 1\">\n                        <Label>Station name</Label>\n                        <input (change)=\"_onStationRename()\" (focus)=\"_onFocus(true)\" (blur)=\"_onFocus(false)\" formControlName=\"m_stationName\" type=\"text\">\n                    </div>\n                    <hr/>\n                    <div *ngIf=\"m_totalStationsSelected.length <= 1\" id=\"stationInfo\">\n                        <ul *ngIf=\"m_selectedStation\">\n                            <li>\n                                <span>Name </span>: {{m_selectedStation.name}}\n                            </li>\n                            <li>\n                                <span>Station id: </span>: {{m_selectedStation.id}}\n                            </li>\n                            <li>\n                                <span>OS </span>: {{m_selectedStation.os}}\n                            </li>\n                            <li>\n                                <span>AIR </span>: {{m_selectedStation.airVersion}}\n                            </li>\n                            <li>\n                                <span>App version: </span>: {{m_selectedStation.appVersion}}\n                            </li>\n                            <li>\n                                <span>Peak memory: </span>: {{m_selectedStation.peakMemory}}\n                            </li>\n                            <li>\n                                <span>Total memory: </span>: {{m_selectedStation.totalMemory}}\n                            </li>\n                            <li>\n                                <span>Running: </span>: {{m_selectedStation.runningTime}}\n                            </li>\n                            <li>\n                                <span>Watchdog: </span>: {{m_selectedStation.watchDogConnection == \"1\" ? 'ON' : 'OFF'}}\n                            </li>\n                            <li>\n                                <span>Last update: </span>: {{m_selectedStation.lastUpdate}}\n                            </li>\n                        </ul>\n                    </div>\n                    <br/>\n                    <br/>\n                    <div *ngIf=\"m_totalStationsSelected.length <= 1\">\n                        <Label>Station events</Label>\n                        <input formControlName=\"m_eventValue\" type=\"text\" name=\"eventName\" data-localize=\"eventName\" placeholder=\"event name\" id=\"stationSendEventValue\" value=\"\">\n\n                        <p></p>\n                        <button (click)=\"_onSendEvent()\" [@toggleState]=\"shouldToggle\" id=\"stationEventSendCommand\" class=\"btn btn-primary\"><i class=\"fa fa-paper-plane\"></i> Send event to remote station\n                        </button>\n                        <hr/>\n                        <div>\n                            <label class=\"pull-left\" data-localize=\"serverMode\">server mode (listen to local\n                                events)</label>\n\n                            <div class=\"clearfix\" style=\"padding-bottom: 13px\"></div>\n                            <div style=\"position: relative; top: -12px\" class=\"material-switch pull-left\">\n                                <input (change)=\"saveToStore()\" formControlName=\"m_enableLan\" id=\"stationServerMode\" name=\"someSwitchOption001\" type=\"checkbox\"/>\n                                <label for=\"stationServerMode\" class=\"label-primary\"></label>\n                            </div>\n                        </div>\n                        <div class=\"clearfix\"></div>\n                        <div *ngIf=\"m_selectedBranchStation && m_selectedBranchStation.getLanEnabled\" class=\"row\">\n                            <ul class=\"list-group\">\n                                <li class=\"list-group-item\">\n                                    <span i18n class=\"inliner\">ip address</span>\n                                    <input (focus)=\"_onFocus(true)\" (blur)=\"_onFocus(false)\" formControlName=\"m_ip\" type=\"text\" class=\"numStepper inliner\">\n                                </li>\n                                <li class=\"list-group-item\">\n                                    <span i18n class=\"inliner\">port</span>\n                                    <input (focus)=\"_onFocus(true)\" (blur)=\"_onFocus(false)\" formControlName=\"m_port\" type=\"number\" step=\"1\" class=\"numStepper inliner\">\n                                </li>\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div *ngSwitchCase=\"m_sidePropsEnum.miniDashboard\">\n            <dash-panel-mini></dash-panel-mini>\n        </div>\n\n    </ul>\n</form>\n\n\n"
  },
  {
    "path": "src/app/stations/stations-props-manager.ts",
    "content": "import {ChangeDetectorRef, Component, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Observable} from \"rxjs\";\nimport {ACTION_LIVELOG_UPDATE, ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {StationModel} from \"../../models/StationModel\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {FormBuilder, FormGroup} from \"@angular/forms\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {BranchStationsModelExt, CampaignsModelExt} from \"../../store/model/msdb-models-extended\";\nimport {List} from \"immutable\";\nimport {LazyImage} from \"../../comps/lazy-image/lazy-image\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\nimport * as _ from 'lodash';\nimport {IUiState} from \"../../store/store.data\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {PreviewModeEnum} from \"../live-preview/live-preview\";\n\n@Component({\n    selector: 'stations-props-manager',\n    host: {\n        '(input-blur)': 'saveToStore($event)'\n    },\n    animations: [\n        trigger('toggleState', [\n            state('true', style({})),\n            state('false', style({maxHeight: 0, padding: 0, display: 'none'})),\n            // transition\n            transition('* => *', animate('300ms')),\n        ])\n    ],\n    styles: [`\n        ul {\n            padding: 0px;\n        }\n\n        #stationcontrol {\n            width: 100%;\n        }\n\n        #stationcontrol button {\n            width: 25%;\n        }\n\n        /*.loading {*/\n        /*float: left;*/\n        /*position: relative;*/\n        /*top: -106px;*/\n        /*left: calc((100% / 2) - 30px);*/\n        /*}*/\n\n        /*img {*/\n        /*float: left;*/\n        /*position: relative;*/\n        /*width: 210px;*/\n        /*top: -140px;*/\n        /*left: calc((100% / 2) - 109px);*/\n        /*}*/\n\n        /*#propWrap {*/\n        /*position: fixed;*/\n        /*padding-left: 20px;*/\n        /*}*/\n    `],\n    templateUrl: './stations-props-manager.html'\n})\nexport class StationsPropsManager extends Compbaser {\n\n    contGroup: FormGroup;\n    m_sideProps$: Observable<SideProps>;\n    m_sidePropsEnum = SideProps;\n    m_uiUserFocusItem$: Observable<SideProps>;\n    m_selectedStation: StationModel;\n    m_selectedBranchStation: BranchStationsModelExt;\n    m_selectedCampaignId = -1;\n    m_loading = false;\n    m_totalStationsSelected = [];\n    m_snapPath = '';\n    shouldToggle = true;\n    m_disabled = true;\n    m_port = '';\n    m_campaigns: List<CampaignsModelExt>;\n    m_ip = '';\n    m_inFocus = false;\n    m_multiOptions = ['change campaigns, no save','change campaigns & save','change campaigns, save & restart station']\n\n    constructor(private toast: ToastsManager, private fb: FormBuilder, private yp: YellowPepperService, private rp: RedPepperService, private cd: ChangeDetectorRef) {\n        super();\n        this.m_uiUserFocusItem$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n        this.m_sideProps$ = this.yp.ngrxStore.select(store => store.appDb.uiState.uiSideProps);\n\n\n        this.contGroup = fb.group({\n            'm_campaignsControl': [''],\n            'm_campaignsMultiControl': [''],\n            'm_stationName': [''],\n            'm_eventValue': [''],\n            'm_enableLan': [],\n            'm_ip': [],\n            'm_port': []\n        });\n\n        this.cancelOnDestroy(\n            //\n            this.yp.getMultiSelectedStations()\n                .map(i_stations => {\n                    var jStationsData = i_stations.toJSON();\n                    this.m_totalStationsSelected =  [];\n                    _.forEach(jStationsData, (i_selected, i_stationId) => {\n                        if (i_selected)\n                            this.m_totalStationsSelected.push(i_stationId)\n                    })\n                    return this.m_totalStationsSelected;\n                })\n                .subscribe((i_stationsIds) => {\n                    console.log(i_stationsIds);\n                }, (e) => console.error(e))\n        )\n\n        this.cancelOnDestroy(\n            //\n            this.yp.getCampaigns()\n                .subscribe((i_campaigns: List<CampaignsModelExt>) => {\n                    this.m_campaigns = i_campaigns;\n                }, (e) => console.error(e))\n        )\n        this.cancelOnDestroy(\n            //\n            this.yp.listenStationBranchSelected()\n                .map((i_station: StationModel) => {\n                    this.m_snapPath = '';\n                    if (this.m_selectedStation && this.m_selectedStation.id != i_station.id)\n                        this._resetSnapshotSelection();\n                    this.m_selectedStation = i_station;\n                    this.m_disabled = this.m_selectedStation.connection == \"0\";\n                    return this.m_selectedStation.id;\n                })\n                .mergeMap(i_station_id => {\n                    return this.yp.getStationCampaignID(i_station_id)\n                        .map((i_campaign_id) => {\n                            return {i_station_id, i_campaign_id};\n                        })\n\n                })\n                .mergeMap(({i_station_id, i_campaign_id}) => {\n                    this.m_selectedCampaignId = i_campaign_id;\n                    return this.yp.listenStationRecord(i_station_id)\n                })\n                .subscribe((i_branchStationsModel) => {\n                    this.m_selectedBranchStation = i_branchStationsModel;\n                    this._render()\n\n                }, (e) => console.error(e))\n        )\n    }\n\n    @ViewChild(LazyImage)\n    lazyImage: LazyImage;\n\n    loadImage(imagePath: string): Observable<HTMLImageElement> {\n        return Observable\n            .create(observer => {\n                const img = new Image();\n                try {\n                    img.src = imagePath;\n                    img.onload = () => {\n                        observer.next(imagePath);\n                        observer.complete();\n                    };\n                    img.onerror = err => {\n                        observer.error(null);\n                    };\n                }\n                catch (e) {\n                    console.log('some error ' + e);\n                }\n\n\n            });\n    }\n\n    _resetSnapshotSelection() {\n        if (this.lazyImage)\n            this.lazyImage.resetToDefault();\n    }\n\n    _onMultiChangeCampaign(){\n        this.m_totalStationsSelected.forEach((i_stationId)=>{\n            this.rp.setStationCampaignID(i_stationId, this.contGroup.value.m_campaignsControl);\n        });\n        switch (this.contGroup.value.m_campaignsMultiControl) {\n            case 'change campaigns, no save': {\n                break;\n            }\n            case 'change campaigns & save': {\n                let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE, previewMode: PreviewModeEnum.NONE}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                break;\n            }\n            case 'change campaigns, save & restart station': {\n                let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE, previewMode: PreviewModeEnum.NONE}\n                this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n                this.yp.listenMainAppState()\n                    .skip(1)\n                    .take(1)\n                    .subscribe(i_status => {\n                        if (i_status == MainAppShowStateEnum.SAVED) {\n                            this.m_totalStationsSelected.forEach((i_stationId)=>{\n                                this.rp.sendCommand('rebootPlayer', i_stationId, () => {\n                                // this.rp.sendCommand('rebootPlayer', -1, () => {\n                                });\n                            });\n                        }\n                    })\n                break;\n            }\n\n        }\n\n\n        this.rp.reduxCommit();\n\n        // bootbox.alert('next, restart selected stations to have them play your newly selected campaign');\n    }\n\n    _render() {\n        if (!this.m_selectedBranchStation)\n            return;\n\n        this.contGroup.controls.m_campaignsControl.setValue(this.m_selectedCampaignId);\n        this.contGroup.controls.m_enableLan.setValue(this.m_selectedBranchStation.getLanEnabled);\n        if (this.m_inFocus)\n            return;\n        this.contGroup.controls.m_stationName.setValue(this.m_selectedBranchStation.getStationName());\n        this.contGroup.controls.m_ip.setValue(this.m_selectedBranchStation.getLanServerIp());\n        this.contGroup.controls.m_port.setValue(this.m_selectedBranchStation.getLanServerPort());\n    }\n\n    _onFocus(i_value) {\n        this.m_inFocus = i_value;\n    }\n\n    _onStationRename() {\n        this.toast.info('Station name will apply a few minutes after you save Studio changes, click [Save]');\n    }\n\n    _onCommand(i_command) {\n        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'send station event ' + i_command})}));\n        switch (i_command) {\n            case 'play': {\n                this.rp.sendCommand('start', this.m_selectedStation.id, () => {\n                });\n                break;\n            }\n            case 'stop': {\n                this.rp.sendCommand('stop', this.m_selectedStation.id, () => {\n                });\n                break;\n            }\n            case 'snap': {\n                this._takeSnapshot();\n                break;\n            }\n            case 'off': {\n                this.rp.sendCommand('rebootPlayer', this.m_selectedStation.id, () => {\n                });\n                break;\n            }\n        }\n    }\n\n    _onLoaded() {\n        console.log('img loaded');\n    }\n\n    _onError() {\n        console.log('img error');\n    }\n\n    _onCompleted() {\n        console.log('img completed');\n    }\n\n    _takeSnapshot() {\n        var d = new Date().getTime();\n        this.m_snapPath = '';\n        this.m_loading = true;\n        var path = this.rp.sendSnapshot(d, 0.2, this.m_selectedStation.id, () => {\n            this.m_snapPath = path;\n            this.lazyImage.urls = [path];\n        });\n        setTimeout(() => {\n            this.loadImage(path)\n                .subscribe(v => {\n                    // console.log(v);\n                })\n        }, 100)\n\n        setTimeout(() => {\n            this.m_loading = false;\n            this.m_snapPath = path;\n            // console.log('loading image from ' + this.m_snapPath);\n        }, 100);\n\n    }\n\n    _onSendEvent() {\n        this.shouldToggle != this.shouldToggle;\n        this.rp.sendEvent(this.contGroup.controls.m_eventValue.value, this.m_selectedStation.id, function () {\n        });\n        this.yp.dispatch(({type: ACTION_LIVELOG_UPDATE, payload: new LiveLogModel({event: 'send station event ' + this.contGroup.controls.m_eventValue.value})}));\n    }\n\n    @timeout()\n    private saveToStore() {\n        // console.log(this.contGroup.status + ' ' + JSON.stringify(this.ngmslibService.cleanCharForXml(this.contGroup.value)));\n        if (this.contGroup.status != 'VALID')\n            return;\n        if (this.contGroup.value.m_ip.match(/\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b/))\n            this.rp.setStationRecordValue(this.m_selectedStation.id, 'lan_server_ip', this.contGroup.value.m_ip);\n        this.rp.setStationCampaignID(this.m_selectedStation.id, this.contGroup.value.m_campaignsControl);\n        this.rp.setStationRecordValue(this.m_selectedStation.id, 'lan_server_enabled', this.contGroup.value.m_enableLan == true ? 'True' : 'False');\n        this.rp.setStationRecordValue(this.m_selectedStation.id, 'lan_server_port', this.contGroup.value.m_port);\n        this.rp.setStationName(this.m_selectedStation.id, this.contGroup.value.m_stationName);\n        this.rp.reduxCommit();\n        this.cd.markForCheck();\n    }\n\n    destroy() {\n    }\n}\n\n"
  },
  {
    "path": "src/app/stations/stations.ts",
    "content": "import {ChangeDetectionStrategy, Component} from \"@angular/core\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {ResourcesModel} from \"../../store/imsdb.interfaces_auto\";\nimport {List, Map} from \"immutable\";\nimport {Observable} from \"rxjs\";\nimport {Compbaser} from \"ng-mslib\";\nimport {IUiState} from \"../../store/store.data\";\nimport {ACTION_UISTATE_UPDATE, SideProps} from \"../../store/actions/appdb.actions\";\nimport {BlockService} from \"../blocks/block-service\";\nimport {MainAppShowStateEnum} from \"../app-component\";\nimport {EFFECT_LOAD_STATIONS} from \"../../store/effects/appdb.effects\";\nimport {StationModel} from \"../../models/StationModel\";\nimport * as _ from 'lodash';\n\n@Component({\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'stations',\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div id=\"resourcesPanel\">\n            <div class=\"btn-group\">\n                <button (click)=\"_loadData()\" type=\"button\" class=\"btn btn-danger\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-refresh\"></i>\n                    <span i18n>reload</span>\n                </button>\n                <button (click)=\"_removeStation()\" type=\"button\" class=\"btn btn-default\">\n                    <i style=\"font-size: 1em\" class=\"fa fa-minus\"></i>\n                    <span i18n>remove</span>\n                </button>\n                <input [(ngModel)]=\"m_filter\" style=\"width: 200px\" id=\"resourcesFilterList\" class=\"form-control\" placeholder=\"search for\" required=\"\">\n            </div>\n            <!--<h5 i18n>supported files: flv, mp4, jpg, png, swf and svg</h5>-->\n            <div id=\"resourceLibListWrap\">\n                <ul id=\"resourceLibList\" class=\"list-group row\"></ul>\n            </div>\n        </div>\n        <!-- move scroller to proper offset -->\n        <div class=\"responsive-pad-right\">\n            <div id=\"stationsPanel\" matchBodyHeight=\"150\" style=\"overflow: scroll\">\n                <stations-list [filter]=\"m_filter\" [stations]=\"m_stationModels$ | async\" (onMultiSelected)=\"_onMultiSelected($event)\" (onSelected)=\"_onSelected($event)\">\n                </stations-list>\n            </div>\n        </div>\n    `,\n    styles: [`\n\n        /*:host /deep/ vg-player {*/\n        /*background-color: transparent;*/\n        /*margin: 30px;*/\n        /*width: 30%;*/\n        /*height: calc(100% - 60px);*/\n        /*}*/\n\n        /*:host /deep/ vg-player {*/\n        /*background-color: transparent;*/\n        /*margin: 30px;*/\n        /*width: 30%;*/\n        /*height: calc(100% - 60px);*/\n        /*}*/\n\n        * {\n            border-radius: 0 !important;\n        }\n\n        vg-player {\n            background-color: transparent;\n            margin: 30px;\n            width: 30%;\n            height: calc(100% - 60px);\n        }\n\n        vg-controls {\n            padding: 30px;\n            transition: all 1s;\n        }\n\n        #resourcesPanel {\n            padding: 10px;\n        }\n\n        .myFile {\n            position: relative;\n            overflow: hidden;\n            float: left;\n            clear: left;\n        }\n\n        .myFile input[type=\"file\"] {\n            display: block;\n            position: absolute;\n            top: 0;\n            right: 0;\n            opacity: 0;\n            font-size: 100px;\n            filter: alpha(opacity=0);\n            cursor: pointer;\n        }\n    `]\n})\n\nexport class Stations extends Compbaser {\n\n    m_filter;\n    m_stationModel: StationModel;\n    m_stationModels$: Observable<List<StationModel>>;\n    m_loadStationsHandle;\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService, private bs: BlockService) {\n        super();\n        this._loadData();\n        this.m_stationModels$ = this.yp.listenStations();\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenStationSelected()\n                .subscribe((i_stationModel: StationModel) => {\n                    this.m_stationModel = i_stationModel;\n                }, (e) => console.error(e))\n        );\n\n        this.cancelOnDestroy(\n            //\n            this.yp.listenMainAppState()\n                .subscribe((i_value: MainAppShowStateEnum) => {\n                    switch (i_value) {\n                        case MainAppShowStateEnum.SAVED: {\n                            this._loadData();\n                            break;\n                        }\n                    }\n                }, (e) => console.error(e))\n        );\n    }\n\n    _loadData() {\n        this.yp.ngrxStore.dispatch({type: EFFECT_LOAD_STATIONS, payload: {userData: this.rp.getUserData()}});\n        if (_.isUndefined(this.m_loadStationsHandle)) {\n            this.m_loadStationsHandle = setInterval(() => {\n                this._loadData();\n            }, 4000);\n        }\n    }\n\n    _removeStation() {\n        if (_.isUndefined(this.m_stationModel)) {\n            bootbox.dialog({\n                message: 'No station selected...',\n                buttons: {\n                    danger: {\n                        label: 'close',\n                        className: \"btn-danger\",\n                        callback: function () {\n                        }\n                    }\n                }\n            });\n            return false;\n        }\n        bootbox.confirm('Are you sure you want to uninstall the selected station?', (result) => {\n            if (!result) return;\n\n            this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: {uiSideProps: SideProps.miniDashboard}}));\n            this.rp.removeStation(this.m_stationModel.id);\n            // this.rp.sendCommand('rebootStation', this.m_stationModel.id, () => {});\n            this.rp.sendCommand('rebootPlayer', this.m_stationModel.id, () => {});\n            this.rp.sendCommand('rebootPlayer', this.m_stationModel.id, () => {});\n            this.rp.sendCommand('rebootPlayer', this.m_stationModel.id, () => {});\n            var uiState: IUiState = {uiSideProps: SideProps.miniDashboard, stations: {stationSelected: -1}};\n            this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n            this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: {mainAppState: MainAppShowStateEnum.SAVE}}));\n        });\n    }\n\n    _onSelected(i_station: StationModel) {\n        const uiState: IUiState = {\n            uiSideProps: SideProps.stationProps,\n            stations: {stationSelected: i_station.id}\n        };\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n    }\n\n    _onMultiSelected(i_stations: any) {\n        const uiState: IUiState = {\n            multiStationSelected:  {\n                stations: Map(i_stations)\n            }\n        };\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n    }\n\n    destroy() {\n        clearInterval(this.m_loadStationsHandle);\n        var uiState: IUiState = {stations: {stationSelected: -1}};\n        this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n    }\n}\n\n"
  },
  {
    "path": "src/app/studiopro/index.ts",
    "content": "import {NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {RouterModule} from \"@angular/router\";\nimport {StudioProNavigation} from \"./studiopro-navigation\";\nimport {DropdownModule as DropdownModulePrime} from \"primeng/primeng\";\nimport {SharedModule} from \"../../modules/shared.module\";\n\nexport const LAZY_ROUTES = [\n    {path: ':folder', component: StudioProNavigation},\n    {path: ':folder/:id', component: StudioProNavigation},\n    {path: '**', component: StudioProNavigation}\n];\n\n@NgModule({\n    imports: [DropdownModulePrime, SharedModule, CommonModule, RouterModule.forChild(LAZY_ROUTES)],\n    declarations: [StudioProNavigation]\n})\nexport class StudioProLazyModule {\n}"
  },
  {
    "path": "src/app/studiopro/pro-upgrade.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {FormBuilder, FormGroup, Validators} from \"@angular/forms\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {NGValidators} from \"ng-validators\";\nimport {equalValueValidator} from \"../../Lib\";\n\n@Component({\n    selector: 'pro-upgrade',\n    templateUrl: './pro-upgrades.html',\n    styles: [`\n        input.ng-invalid {\n            border-right: 10px solid red;\n        }\n\n        .material-switch {\n            position: relative;\n            padding-top: 10px;\n        }\n\n        .input-group {\n            padding-top: 10px;\n        }\n\n        i {\n            width: 20px;\n        }\n    `]\n})\nexport class ProUpgrade extends Compbaser {\n\n    formInputs = {};\n    m_contGroup: FormGroup;\n\n    constructor(private fb: FormBuilder, private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.m_contGroup = this.fb.group({\n                'userName': ['', [Validators.required]],\n                'creditCard': ['', [NGValidators.isCreditCard()]],\n                'month': ['', [NGValidators.isNumeric()]],\n                'year': ['', [NGValidators.isNumeric()]],\n                'cv': ['', [NGValidators.isNumeric()]],\n                'password': ['', [Validators.required, Validators.minLength(3)]],\n                'confirmPassword': ['', [Validators.required, Validators.minLength(3)]]\n            },\n            {validator: equalValueValidator('password', 'confirmPassword')}\n        );\n    }\n\n    private showMessage(i_title: string, i_msg: string, i_status: boolean): void {\n        bootbox.hideAll();\n        bootbox.dialog({\n            closeButton: true,\n            title: i_title,\n            message: `<br/><br/><br/>\n                        <center>\n                            ${i_status == true ? '<i style=\"color: green; font-size: 6em; padding:30px\" class=\"fa fa-thumbs-up\"></i>' : '<i style=\"color: red; font-size: 4em; padding: 30px\" class=\"fa fa-thumbs-down\"></i>'}\n                            <h4>${i_msg}</h4>\n                            <br/><br/><br/>\n                        </center>`\n\n        });\n    }\n\n\n\n    _detectCardType(number) {\n        var re = {\n            electron: /^(4026|417500|4405|4508|4844|4913|4917)\\d+$/,\n            maestro: /^(5018|5020|5038|5612|5893|6304|6759|6761|6762|6763|0604|6390)\\d+$/,\n            dankort: /^(5019)\\d+$/,\n            interpayment: /^(636)\\d+$/,\n            unionpay: /^(62|88)\\d+$/,\n            visa: /^4[0-9]{12}(?:[0-9]{3})?$/,\n            mastercard: /^5[1-5][0-9]{14}$/,\n            amex: /^3[47][0-9]{13}$/,\n            diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,\n            discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/,\n            jcb: /^(?:2131|1800|35\\d{3})\\d{11}$/\n        };\n        if (re.electron.test(number)) {\n            return 'ELECTRON';\n        } else if (re.maestro.test(number)) {\n            return 'MAESTRO';\n        } else if (re.dankort.test(number)) {\n            return 'DANKORT';\n        } else if (re.interpayment.test(number)) {\n            return 'INTERPAYMENT';\n        } else if (re.unionpay.test(number)) {\n            return 'UNIONPAY';\n        } else if (re.visa.test(number)) {\n            return 'VISA';\n        } else if (re.mastercard.test(number)) {\n            return 'MASTERCARD';\n        } else if (re.amex.test(number)) {\n            return 'AMEX';\n        } else if (re.diners.test(number)) {\n            return 'DINERS';\n        } else if (re.discover.test(number)) {\n            return 'DISCOVER';\n        } else if (re.jcb.test(number)) {\n            return 'JCB';\n        } else {\n            return undefined;\n        }\n    }\n\n    _onStartSubscription() {\n        if (this.m_contGroup.status != 'VALID')\n            return bootbox.alert('Please fix the fields marked in red');\n\n        const cardType = this._detectCardType(this.m_contGroup.controls.creditCard.value);\n        const userName = this.rp.getUserData().userName;\n        const userPass = this.rp.getUserData().userPass;\n        const year = this.m_contGroup.controls.year.value.length == 2 ? '20' + this.m_contGroup.controls.year.value : this.m_contGroup.controls.year.value;\n        const month = this.m_contGroup.controls.month.value.replace(/^0+/, '');\n        var card;\n        switch (cardType) {\n            case 'VISA': {\n                card = '0';\n                break;\n            }\n            case 'MASTERCARD': {\n                card = '1';\n                break;\n            }\n            case 'DISCOVER': {\n                card = '2';\n                break;\n            }\n            case 'AMEX': {\n                card = '3';\n                break;\n            }\n            default: {\n                card = '-1';\n            }\n        }\n\n        var url = `https://galaxy.signage.me/WebService/UpgradeToResellerAccount.ashx?userName=${userName}&userPassword=${userPass}&resellerUserName=${this.m_contGroup.controls.userName.value}&resellerPassword=${this.m_contGroup.controls.password.value}&cardType=${card}&cardNumber=${this.m_contGroup.controls.creditCard.value}&expirationMonth=${month}&expirationYear=${year}&securityCode=${this.m_contGroup.controls.cv.value}&callback=?`;\n        $.getJSON(url, (e) => {\n            var msg = '';\n            console.log('Credit card status ' + e.result);\n            switch (e.result) {\n                case -4: {\n                    msg = 'This user is already under a subscription account';\n                    this.showMessage(e.status, msg, false);\n                    return;\n                }\n                case -5: {\n                    msg = 'Enterprise use name is taken, please pick a different name';\n                    this.showMessage(e.status, msg, false);\n                    return;\n                }\n                case -3: {\n                }\n                case -2: {\n                }\n                case -1: {\n                    msg = 'Problem with credit card, please use a different card';\n                    this.showMessage(e.status, msg, false);\n                    return;\n                }\n                default: {\n                    if (e.result > 100) {\n                        bootbox.hideAll();\n                        $('.modal').modal('hide');\n                        //var snippet = `Congratulations, be sure to checkout the <a href=\"http://www.digitalsignage.com/_html/video_tutorials.html?videoNumber=liteUpgrade\" target=\"_blank\">video tutorial</a> on how to install your newly available components from the mediaSTORE`;\n                        var snippet = `Congratulations, be sure to go to the mediaSTORE and install your newly available components...`;\n                        this.showMessage('success', snippet, true);\n                        return;\n                    } else {\n                        msg = 'Problem with credit card, please use a different card';\n                        this.showMessage(e.status, msg, false);\n                    }\n                }\n            }\n        }).done((e) => {\n        }).fail((e) => {\n            this.showMessage(e.status, 'Could not complete, something went wrong on server side', false);\n        }).always(() => {\n        });\n    }\n\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app/studiopro/pro-upgrades.html",
    "content": "<form novalidate autocomplete=\"off\" [formGroup]=\"m_contGroup\">\n    <div class=\"row\">\n        <div class=\"inner userGeneral\">\n            <div class=\"panel-heading\">\n                <small class=\"release\">target properties\n                    <i style=\"font-size: 1.4em\" class=\"fa fa-cog pull-right\"></i>\n                </small>\n                <small class=\"debug\">{{me}}</small>\n            </div>\n            <a style=\"padding: 10px\" i18n href=\"http://www.digitalsignage.com/_html/benefits.html\" target=\"_blank\">\n                Learn more about Enterprise\n            </a>\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading\">\n                    <h3 class=\"panel-title\">\n                        <img src=\"assets/accepted_c22e0.png\">\n                    </h3>\n                </div>\n                <div class=\"panel-body\">\n                    <form role=\"form\" id=\"payment-form\">\n                        <div class=\"row\">\n                            <div class=\"col-xs-12\">\n                                <div class=\"form-group\">\n                                    <label for=\"newName\">Pick a new enterprise user name</label>\n                                    <div class=\"input-group\">\n                                        <input id=\"newName\" [formControl]=\"m_contGroup.controls['userName']\" type=\"text\" class=\"form-control\" name=\"newName\"/>\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-user-circle\"></i></span>\n                                    </div>\n                                </div>\n                                <div class=\"form-group\">\n                                    <label for=\"newPass\">Pick an enterprise password</label>\n                                    <div class=\"input-group\">\n                                        <input id=\"newPass\" [formControl]=\"m_contGroup.controls['password']\" id=\"upgPass\" type=\"password\" class=\"form-control\" name=\"newPass\"/>\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-key\"></i></span>\n                                    </div>\n                                </div>\n                                <div class=\"form-group\">\n                                    <label for=\"newPass2\">Repeat your new password</label>\n                                    <div class=\"input-group\">\n                                        <input id=\"newPass2\" [formControl]=\"m_contGroup.controls['confirmPassword']\" id=\"upgPass2\" type=\"password\" class=\"form-control\" name=\"newPass2\"/>\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-key\"></i></span>\n                                    </div>\n                                </div>\n                            </div>\n                            <div class=\"col-xs-12\">\n                                <div class=\"form-group\">\n                                    <label for=\"cardNumber\">CARD NUMBER</label>\n                                    <div class=\"input-group\">\n                                        <input id=\"cardNumber\" [formControl]=\"m_contGroup.controls['creditCard']\" id=\"upgCredit\" type=\"text\" class=\"form-control\" name=\"cardNumber\" placeholder=\"Valid Card Number\" required autofocus data-stripe=\"number\"/>\n                                        <span class=\"input-group-addon\"><i class=\"fa fa-credit-card\"></i></span>\n                                    </div>\n                                </div>\n                            </div>\n                        </div>\n                        <div class=\"row\">\n                            <div class=\"col-xs-7 col-md-7\">\n                                <div class=\"form-group\">\n                                    <div class=\"col-xs-6 col-lg-6 pl-ziro\">\n                                        <input [formControl]=\"m_contGroup.controls['month']\" type=\"text\" class=\"form-control\" name=\"expMonth\" placeholder=\"MM\" required data-stripe=\"exp_month\"/>\n                                    </div>\n                                    <div class=\"col-xs-6 col-lg-6 pl-ziro\">\n                                        <input [formControl]=\"m_contGroup.controls['year']\" type=\"text\" class=\"form-control\" name=\"expYear\" placeholder=\"YYYY\" required data-stripe=\"exp_year\"/>\n                                    </div>\n                                </div>\n                            </div>\n                            <div class=\"col-xs-5 col-md-5 pull-right\">\n                                <div class=\"form-group\">\n                                    <input [formControl]=\"m_contGroup.controls['cv']\" class=\"form-control\" name=\"cvCode\" placeholder=\"CV\" required data-stripe=\"cvc\"/>\n                                </div>\n                            </div>\n                        </div>\n                        <div class=\"row\">\n                            <div class=\"col-xs-12\">\n                                <button (click)=\"_onStartSubscription()\" class=\"startUpgrade btn btn-success btn-lg btn-block\" type=\"submit\">Start Subscription</button>\n                            </div>\n                        </div>\n                        <div class=\"row\" style=\"display:none;\">\n                            <div class=\"col-xs-12\">\n                                <p class=\"payment-errors\"></p>\n                            </div>\n                        </div>\n                    </form>\n                </div>\n            </div>\n        </div>\n    </div>\n</form>"
  },
  {
    "path": "src/app/studiopro/studiopro-navigation.ts",
    "content": "import {ChangeDetectionStrategy, Component, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {animate, state, style, transition, trigger} from \"@angular/animations\";\nimport {ModalComponent} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Observable} from \"rxjs/Observable\";\nimport {UserModel} from \"../../models/UserModel\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n\n        .dottedHR {\n            height: 6px;\n            width: 1500px;\n            opacity: 0.6;\n            position: relative;\n            border-top: 12px dotted #c1c1c1;\n            padding-bottom: 7px;\n            top: 20px;\n        }\n\n        .activated {\n            background-color: #428bca;\n            color: white;\n        }\n\n        .headerPropIcon {\n            position: fixed !important;\n            top: 0px !important;\n            color: #f5f5f5;\n            right: 50px !important;\n            z-index: 1500;\n            background-color: #151515;\n            float: right;\n            border: black;\n        }\n\n        .whiteFont {\n            color: white;\n        }\n\n        .pricingContainer {\n            padding-top: 40px;\n        }\n\n        .price {\n            font-size: 25px;\n            float: left;\n        }\n\n        .faHeader {\n            font-size: 1.9em !important;\n            color: #bababa;\n        }\n\n        .faHeader:hover {\n            color: white;\n        }\n\n        .pricing_header1 {\n            background: none repeat scroll 0% 0% rgb(0, 181, 255);\n            border-radius: 5px 5px 0px 0px;\n        }\n\n        .pricing_header2 {\n            background: none repeat scroll 0% 0% rgb(0, 121, 171);\n            border-radius: 5px 5px 0px 0px;\n        }\n\n        .pricing_header3 {\n            background: none repeat scroll 0% 0% rgb(0, 81, 115);\n            border-radius: 5px 5px 0px 0px;\n        }\n\n        .pricing_headerh2 {\n            text-align: center;\n            line-height: 25px;\n            padding: 15px 0px;\n            margin: 0px;\n            font-size: 1.5em;\n            font-weight: 400;\n            color: white;\n        }\n\n    `],\n    host: {\n        '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    animations: [\n        trigger('routeAnimation', [\n            state('*', style({opacity: 1})),\n            transition('void => *', [\n                style({opacity: 0}),\n                animate(333)\n            ]),\n            transition('* => void', animate(333, style({opacity: 0})))\n        ])\n    ],\n    template: `\n        <div id=\"proStudioPanel\">\n            <h3 i18n data-localize=\"theRightPackage\">Choose the package that's right for you</h3>\n            <!-- price & service -->\n            <div class=\"pricingContainer\">\n                <div class=\"row\"></div>\n                <br>\n\n                <div id=\"pricingTableWrap\" style=\"overflow-x: hidden; overflow-y: scroll; height: 100%\">\n                    <div class=\"col-md-4\" id=\"home-box\">\n                        <div class=\"pricing_header1\">\n                            <h2 class=\"pricing_headerh2\" data-localize=\"studioLiteFree\">\n                                <i class=\"fa fa-plus\"></i>\n                                StudioLite\n                            </h2>\n\n                            <div class=\"space\"></div>\n                        </div>\n                        <ul class=\"list-group\">\n                            <li *ngIf=\"isBrandingDisabled | async\" class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span>\n                                <span data-localize=\"onehundredFree\"> 100% FREE</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span>\n                                <span data-localize=\"simpleInterface\"> simple to use interface</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"campaignManager\"> Campaign manager</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"timelineManagement\"> Timeline management</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"screenTemplates\"> Screen templates</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"screenEditor\"> Screen editor</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"StationManager\"> Station Manager</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"supportComponents\"> Support 10 components</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"sceneEditor\"> Scene editor (coming)</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"filesVIF\"> Files: videos/images/flash</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"tabletsPhones\"> Run on Tablets and phones</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"openSourceGitHub\"> Open source (GitHub)</span>\n                            </li>\n                        </ul>\n                        <div *ngIf=\"isBrandingDisabled | async\" class=\"try\">\n                            <p class=\"price\">$0.00</p>\n                            <button class=\"pull-right btnPrice btn btn-default\" disabled=\"disabled\" href=\"#\" type=\"button\" data-localize=\"youAreHere\">you are here\n                            </button>\n                        </div>\n                    </div>\n                    <div class=\"col-md-4\" id=\"home-box\">\n                        <div class=\"pricing_header2\">\n                            <h2 class=\"pricing_headerh2\" data-localize=\"studioProFree\">\n                                <i class=\"fa fa-desktop\"></i>\n                                StudioPro (FREE)\n                            </h2>\n\n                            <div class=\"space\"></div>\n                        </div>\n                        <ul class=\"list-group\">\n                            <li *ngIf=\"isBrandingDisabled | async\" class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"onehundredFree\"> 100% FREE</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"higherLearningCurve\"> Higher learning curve</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"professionalEditor\"> Professional editor</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"campaignManager\"> Campaign manager</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"timelineManagement\"> Timeline management</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"channelManagement\"> Channel management</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"schedulerSequencer\"> Scheduler / sequencer</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"richSceneEditor\"> Rich scene editor</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"supportMoreComponents\"> Support more components</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"advanceStationManager\"> Advance Station Manager</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"runDesktopWeb\"> Runs on Desktop and Web</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"muchMore\"> and much more...</span>\n                            </li>\n                        </ul>\n                        <div *ngIf=\"isBrandingDisabled | async\" class=\"try\">\n                            <p class=\"price\">$0.00</p>\n                            <a (click)=\"_onConvert($event)\" id=\"convertAccount\" class=\"pull-right btnPrice btn-primary btn btn-default\" href=\"#\" type=\"button\" data-localize=\"convert\">Convert</a>\n                        </div>\n                    </div>\n                    <div class=\"col-md-4\" id=\"home-box\">\n                        <div class=\"pricing_header3\">\n                            <h2 class=\"pricing_headerh2\" data-localize=\"StudioEnterprise\">\n                                <i class=\"fa fa-cloud-upload\"></i>\n                                StudioEnterprise</h2>\n\n                            <div class=\"space\"></div>\n                        </div>\n                        <ul class=\"list-group\">\n                            <li *ngIf=\"isBrandingDisabled | async\" class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"nintynine\"> $99 a month (flat)</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"everythingFromLiteAndPro\"> Everything from Lite & Pro</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"whiteLabel\"> White label / branding</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"supportAllComponents\"> Support all components</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"transitions\"> Transitions / Effects</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"multiUserManagement\"> Multi user management</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"advertisingManager\"> Advertising manager</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"accessControl\"> Access control</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"unlimitedCloudStorage\"> Unlimited cloud storage</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"phoneSupport\"> Phone support</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"hardwareDiscounts\"> Hardware discounts</span>\n                            </li>\n                            <li class=\"list-group-item\">\n                                <span class=\"glyphicon glyphicon-ok\"></span><span data-localize=\"muchMore\"> and much more...</span>\n                            </li>\n                        </ul>\n                        <div class=\"try\">\n                            <p *ngIf=\"isBrandingDisabled | async\" class=\"price\">$99/<span data-localize=\"month\">month</span>\n                            </p>\n                            <button *ngIf=\"isBrandingDisabled | async\" (click)=\"_onSubscribe($event)\" id=\"subscribeAccount\" class=\"pull-right showUpgradeModal btnPrice btn-primary btn btn-default\" href=\"#\" type=\"button\" data-localize=\"subscribe\"> Subscribe\n                            </button>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <modal #modal>\n            <modal-header [show-close]=\"true\">\n                <h4 i18n class=\"modal-title\">Upgrade to Enterprise - $99.00 per month</h4>\n            </modal-header>\n            <modal-body>\n                <pro-upgrade></pro-upgrade>\n            </modal-body>\n            <modal-footer [show-default-buttons]=\"false\"></modal-footer>\n        </modal>\n    `\n})\nexport class StudioProNavigation extends Compbaser {\n\n    @ViewChild(ModalComponent)\n    modal: ModalComponent;\n\n    subAccount = false;\n    isBrandingDisabled: Observable<boolean>\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n        this.isBrandingDisabled = this.yp.isBrandingDisabled()\n    }\n\n    _initCustomer() {\n        if (this.rp.getUserData().resellerID == 1 || this.rp.getUserData().whiteLabel == false) {\n            this.subAccount = false;\n        } else {\n            this.subAccount = true;\n        }\n    }\n\n    _onConvert(event) {\n        window.open('http://galaxy.mediasignage.com/WebService/signagestudio.aspx?mode=login&v=4&eri=f7bee07a7e79c8efdb961c4d30d20e10c66442110de03d6141', '_blank');\n    }\n\n    _onSubscribe(event) {\n        this.modal.open();\n    }\n\n    ngOnInit() {\n        this.preventRedirect(true);\n        this._initCustomer();\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/app-routes.ts",
    "content": "import {PreloadAllModules, RouterModule, Routes} from \"@angular/router\";\nimport {LoginPanel} from \"./comps/entry/LoginPanel\";\nimport {Logout} from \"./comps/logout/Logout\";\nimport {AuthService} from \"./services/AuthService\";\nimport {AutoLogin} from \"./comps/entry/AutoLogin\";\nimport {Dashboard} from \"./app/dashboard/dashboard-navigation\";\nimport {Appwrap} from \"./app/appwrap\";\nimport {FasterqTerminal} from \"./app/fasterq/fasterq-terminal\";\n\nconst routes: Routes = [\n    {path: 'index.html', data: {title: 'Login'}, component: AutoLogin},\n    {path: 'AutoLogin', data: {title: 'Login'}, component: AutoLogin},\n    {path: 'FasterqTerminal/:id', data: {title: 'FasterqTerminal'}, component: FasterqTerminal},\n    {path: 'UserLogin', data: {title: 'Login'}, component: LoginPanel},\n    {path: 'UserLogin/:twoFactor', data: {title: 'Login'}, component: LoginPanel},\n    {path: 'UserLogin/:twoFactor/:user/:pass', data: {title: 'Login'}, component: LoginPanel},\n    {path: 'Logout', component: Logout},\n    {path: '', pathMatch: 'full', redirectTo: '/App1/Dashboard'},\n    {path: 'studioweb', pathMatch: 'full', redirectTo: '/App1/Dashboard'},  // IE/FF compatibility\n    {path: 'studioweb/index.html', pathMatch: 'full', redirectTo: '/App1/Dashboard'},  // IE 11\n    {\n        path: 'App1', component: Appwrap,\n        children: [\n            {path: '', component: Appwrap, canActivate: [AuthService]},\n            {path: 'Dashboard', component: Dashboard, data: {title: 'Dashboard'}, canActivate: [AuthService]},\n            {path: 'Campaigns', loadChildren: '../app/campaigns/index#CampaignsLazyModule', data: {title: 'Campaigns'}, canActivate: [AuthService]},\n            {path: 'Fasterq', loadChildren: '../app/fasterq/index#FasterqLazyModule', data: {title: 'Fasterq'}, canActivate: [AuthService]},\n            {path: 'Scenes', loadChildren: '../app/scenes/index#ScenesLazyModule', data: {title: 'Scenes'}, canActivate: [AuthService]},\n            {path: 'Resources', loadChildren: '../app/resources/index#ResourcesLazyModule', data: {title: 'Resources'}, canActivate: [AuthService]},\n            {path: 'Help', loadChildren: '../app/help/index#HelpLazyModule', data: {title: 'Help'}, canActivate: [AuthService]},\n            {path: 'Install', loadChildren: '../app/install/index#InstallLazyModule', data: {title: 'Install'}, canActivate: [AuthService]},\n            {path: 'Settings', loadChildren: '../app/settings/index#SettingsLazyModule', data: {title: 'Settings'}, canActivate: [AuthService]},\n            {path: 'Stations', loadChildren: '../app/stations/index#StationsLazyModule', data: {title: 'Stations'}, canActivate: [AuthService]},\n            {path: 'Studiopro', loadChildren: '../app/studiopro/index#StudioProLazyModule', data: {title: 'Studiopro'}, canActivate: [AuthService]},\n            {path: 'Logout', component: Logout, data: {title: 'Logout'}, canActivate: [AuthService]},\n            {path: '**', redirectTo: 'Dashboard'}\n        ]\n    }\n];\n\nexport const routing = RouterModule.forRoot(routes, {enableTracing: false, preloadingStrategy: PreloadAllModules});\n\n\n"
  },
  {
    "path": "src/assets/geojson.json",
    "content": "{\n  \"type\": \"FeatureCollection\",\n  \"crs\": {\n    \"type\": \"name\",\n    \"properties\": {\n      \"name\": \"urn:ogc:def:crs:EPSG::31493\"\n    }\n  },\n  \"features\": [\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"2\",\n        \"adm1_code\": \"DEU-1579\",\n        \"OBJECTID_1\": \"942\",\n        \"diss_me\": \"1579\",\n        \"adm1_cod_1\": \"DEU-1579\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"6\",\n        \"name\": \"Schleswig-Holstein\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.SH\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"3\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"SH\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"18\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM10\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345490\",\n        \"woe_label\": \"Schleswig-Holstein, DE, Germany\",\n        \"woe_name\": \"Schleswig-Holstein\",\n        \"latitude\": \"54.1315\",\n        \"longitude\": \"9.84605\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2838632\",\n        \"gn_name\": \"Land Schleswig-Holstein\",\n        \"gns_id\": \"-1858348\",\n        \"gns_name\": \"Schleswig-Holstein\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.10\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM10\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"MultiPolygon\",\n        \"coordinates\": [\n          [\n            [\n              [\n                3457361.6953271437,\n                6064537.3175473278\n              ],\n              [\n                3473831.1032281509,\n                6066454.707440001\n              ],\n              [\n                3458254.2756455722,\n                6054378.8800201574\n              ],\n              [\n                3454292.4301971514,\n                6059770.7031057561\n              ],\n              [\n                3454356.6117983218,\n                6084731.7034898801\n              ],\n              [\n                3457361.6953271437,\n                6064537.3175473278\n              ]\n            ]\n          ],\n          [\n            [\n              [\n                3588249.9672536696,\n                5922981.0870051431\n              ],\n              [\n                3578686.4275546414,\n                5933125.8551333752\n              ],\n              [\n                3577703.2560399352,\n                5938504.9128987873\n              ],\n              [\n                3580874.49823714,\n                5945222.0506500695\n              ],\n              [\n                3576943.630466254,\n                5950819.015340128\n              ],\n              [\n                3578862.6937927571,\n                5955081.5497373492\n              ],\n              [\n                3572137.6137213707,\n                5954711.580675493\n              ],\n              [\n                3570371.6708244649,\n                5950301.8162747147\n              ],\n              [\n                3554853.9405998117,\n                5940794.9144034721\n              ],\n              [\n                3550830.3006076724,\n                5944304.1125011407\n              ],\n              [\n                3549069.0712087429,\n                5937985.4088263968\n              ],\n              [\n                3536429.5426071933,\n                5944772.404340459\n              ],\n              [\n                3526016.6806122339,\n                5966561.8734104037\n              ],\n              [\n                3519393.374612669,\n                5968304.8412422938\n              ],\n              [\n                3512239.2302019894,\n                5970199.5365770916\n              ],\n              [\n                3500514.2646667375,\n                5973331.8574014464\n              ],\n              [\n                3489082.291314546,\n                5989366.3785155555\n              ],\n              [\n                3499819.4056466105,\n                5988660.6677569058\n              ],\n              [\n                3498517.1762036402,\n                6001512.9417701392\n              ],\n              [\n                3490893.0391698242,\n                5999239.2651538216\n              ],\n              [\n                3489548.1277326951,\n                6013751.9056054596\n              ],\n              [\n                3497601.9580049324,\n                6020646.9336849805\n              ],\n              [\n                3477324.3183245538,\n                6015942.557420373\n              ],\n              [\n                3477174.6819570824,\n                6030585.0076404512\n              ],\n              [\n                3490956.4413303267,\n                6031361.2477700273\n              ],\n              [\n                3489931.1912721554,\n                6043152.005285589\n              ],\n              [\n                3499099.8590448922,\n                6044205.2552816924\n              ],\n              [\n                3479952.2035088921,\n                6067179.7789988136\n              ],\n              [\n                3478240.9941294421,\n                6085109.2448926223\n              ],\n              [\n                3488727.8879079837,\n                6086138.8696871242\n              ],\n              [\n                3529021.0772972321,\n                6075584.8843934499\n              ],\n              [\n                3537230.3970351499,\n                6081868.5508470545\n              ],\n              [\n                3553025.9213487152,\n                6069833.4444824299\n              ],\n              [\n                3558853.4378033783,\n                6073742.2482397221\n              ],\n              [\n                3566668.0124271861,\n                6060682.9319272507\n              ],\n              [\n                3566001.9292511554,\n                6046527.0230161548\n              ],\n              [\n                3557272.6619548667,\n                6037087.2706446396\n              ],\n              [\n                3572862.5690058409,\n                6041055.569442112\n              ],\n              [\n                3615633.3602376087,\n                6021826.8104329733\n              ],\n              [\n                3636653.86664266,\n                6031065.0210786732\n              ],\n              [\n                3630020.1589864371,\n                6039286.8314314149\n              ],\n              [\n                3637283.7395728445,\n                6047018.1667916644\n              ],\n              [\n                3650216.1204284448,\n                6033819.9766713399\n              ],\n              [\n                3635081.4884479907,\n                6025376.2926454805\n              ],\n              [\n                3634893.8065267834,\n                6007738.1217093375\n              ],\n              [\n                3614788.5216621999,\n                5991603.5560405627\n              ],\n              [\n                3625082.7900508232,\n                5982662.9355227295\n              ],\n              [\n                3625050.7337689409,\n                5979329.7269153669\n              ],\n              [\n                3628805.8970855772,\n                5977389.3176590335\n              ],\n              [\n                3626024.1404369744,\n                5976110.5464679133\n              ],\n              [\n                3623841.3356328616,\n                5977945.1403433578\n              ],\n              [\n                3615980.348949628,\n                5971721.3096266175\n              ],\n              [\n                3615255.5018173298,\n                5969260.8856087131\n              ],\n              [\n                3616689.3777262997,\n                5963752.7563475929\n              ],\n              [\n                3616154.1812646016,\n                5958546.736402004\n              ],\n              [\n                3619138.4221999128,\n                5958008.8936667377\n              ],\n              [\n                3623189.4327053195,\n                5953513.3434927408\n              ],\n              [\n                3628029.4118883419,\n                5951954.0380383944\n              ],\n              [\n                3629467.0720780403,\n                5938790.4934651023\n              ],\n              [\n                3621108.1006804346,\n                5938712.2612650106\n              ],\n              [\n                3620734.103808559,\n                5932842.580161592\n              ],\n              [\n                3608645.9904428972,\n                5924805.5896682888\n              ],\n              [\n                3606560.2346579311,\n                5916586.2707823943\n              ],\n              [\n                3601710.25338207,\n                5916543.2227652604\n              ],\n              [\n                3588249.9672536696,\n                5922981.0870051431\n              ]\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"6\",\n        \"adm1_code\": \"DEU-1599\",\n        \"OBJECTID_1\": \"2334\",\n        \"diss_me\": \"1599\",\n        \"adm1_cod_1\": \"DEU-1599\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Berlin\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.BE\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"7\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"BE\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"9\",\n        \"labelrank\": \"9\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"6\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM16\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345496\",\n        \"woe_label\": \"Berlin, DE, Germany\",\n        \"woe_name\": \"Berlin\",\n        \"latitude\": \"52.5131\",\n        \"longitude\": \"13.4213\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2950157\",\n        \"gn_name\": \"Land Berlin\",\n        \"gns_id\": \"-1746445\",\n        \"gns_name\": \"Berlin\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.16\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM16\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3804566.4152815924,\n              5843865.692704617\n            ],\n            [\n              3804934.6433777702,\n              5840168.5899853837\n            ],\n            [\n              3809716.679845443,\n              5835249.9865113907\n            ],\n            [\n              3815207.714945185,\n              5832907.5054032393\n            ],\n            [\n              3814140.9994099671,\n              5827006.7575231045\n            ],\n            [\n              3816712.9457131149,\n              5827478.2731477637\n            ],\n            [\n              3822865.3678980898,\n              5823472.4171997104\n            ],\n            [\n              3820320.890532007,\n              5814819.0171839539\n            ],\n            [\n              3816409.7180140801,\n              5810966.0266671684\n            ],\n            [\n              3815681.7293974063,\n              5814709.1505647963\n            ],\n            [\n              3803208.3688719897,\n              5818473.9252682505\n            ],\n            [\n              3801245.3895061575,\n              5814373.9040043866\n            ],\n            [\n              3792079.8344209795,\n              5817614.5021004295\n            ],\n            [\n              3782830.3462029067,\n              5815037.8793154648\n            ],\n            [\n              3778418.5104975295,\n              5817224.1775639663\n            ],\n            [\n              3780958.9744146601,\n              5829146.268900374\n            ],\n            [\n              3781589.121700428,\n              5837662.7537919097\n            ],\n            [\n              3785070.6277251416,\n              5836354.5125904409\n            ],\n            [\n              3785707.312560183,\n              5840767.7494266415\n            ],\n            [\n              3791058.6585779274,\n              5844454.8433719436\n            ],\n            [\n              3796466.9763708967,\n              5841442.4283941165\n            ],\n            [\n              3802213.9156131558,\n              5845930.8582165847\n            ],\n            [\n              3804566.4152815924,\n              5843865.692704617\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"10\",\n        \"adm1_code\": \"DEU-3488\",\n        \"OBJECTID_1\": \"3312\",\n        \"diss_me\": \"3488\",\n        \"adm1_cod_1\": \"DEU-3488\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"5\",\n        \"name\": \"Mecklenburg-Vorpommern\",\n        \"name_alt\": \"Mecklenburg-West Pomerania\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.MV\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"30001\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"MV\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"22\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM12\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345492\",\n        \"woe_label\": \"Mecklenburg-Vorpommern, DE, Germany\",\n        \"woe_name\": \"Mecklenburg-Vorpommern\",\n        \"latitude\": \"53.7528\",\n        \"longitude\": \"12.5647\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2872567\",\n        \"gn_name\": \"Land Mecklenburg-Vorpommern\",\n        \"gns_id\": \"-1824278\",\n        \"gns_name\": \"Mecklenburg-Vorpommern\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.12\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM12\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"MultiPolygon\",\n        \"coordinates\": [\n          [\n            [\n              [\n                3765978.7018767856,\n                6054368.3792266808\n              ],\n              [\n                3777435.6134433611,\n                6053854.901303824\n              ],\n              [\n                3782368.591728467,\n                6059205.16406429\n              ],\n              [\n                3786974.612363453,\n                6049178.2954727663\n              ],\n              [\n                3791952.7030979348,\n                6048995.307912183\n              ],\n              [\n                3790982.149199931,\n                6056628.7616059249\n              ],\n              [\n                3782166.0009250576,\n                6062203.9922618233\n              ],\n              [\n                3776325.3208203837,\n                6056130.6553788381\n              ],\n              [\n                3776858.0248962715,\n                6065718.7575505488\n              ],\n              [\n                3774350.7781503876,\n                6067627.8759364616\n              ],\n              [\n                3783033.4912099959,\n                6070747.65958957\n              ],\n              [\n                3783858.2782364748,\n                6061451.222502646\n              ],\n              [\n                3788686.5434686914,\n                6058680.8391875532\n              ],\n              [\n                3799870.6040519727,\n                6060388.0503517305\n              ],\n              [\n                3802580.9076147829,\n                6055519.6901947297\n              ],\n              [\n                3796496.4780506194,\n                6047458.1686205128\n              ],\n              [\n                3799128.0083435532,\n                6041146.6738467803\n              ],\n              [\n                3809821.4347207304,\n                6034166.5356042059\n              ],\n              [\n                3792493.4405632792,\n                6033025.5237082997\n              ],\n              [\n                3784186.8438639143,\n                6023359.0631650677\n              ],\n              [\n                3778032.6959456238,\n                6022255.4613743341\n              ],\n              [\n                3767578.4113822468,\n                6030737.7075944003\n              ],\n              [\n                3769494.9703409448,\n                6035222.8034836464\n              ],\n              [\n                3776065.5893489686,\n                6036691.2679821067\n              ],\n              [\n                3769692.2806164096,\n                6040765.0543835247\n              ],\n              [\n                3776060.2697977475,\n                6045791.7914314782\n              ],\n              [\n                3765978.7018767856,\n                6054368.3792266808\n              ]\n            ]\n          ],\n          [\n            [\n              [\n                3858958.4675184065,\n                5924746.6905517764\n              ],\n              [\n                3850096.8967003031,\n                5915716.2145906379\n              ],\n              [\n                3840283.6437742342,\n                5916498.3542627199\n              ],\n              [\n                3848470.2881636913,\n                5929329.4855594682\n              ],\n              [\n                3848307.6588879293,\n                5934358.7847815678\n              ],\n              [\n                3826929.8373607565,\n                5932832.0742536131\n              ],\n              [\n                3822905.9499626607,\n                5941589.9501121677\n              ],\n              [\n                3812528.0683271405,\n                5937242.9811624223\n              ],\n              [\n                3801803.8451427119,\n                5927759.7186010573\n              ],\n              [\n                3793795.8883584146,\n                5913641.643195576\n              ],\n              [\n                3777112.0423970157,\n                5910922.5465983907\n              ],\n              [\n                3767480.0978048071,\n                5900151.2545123501\n              ],\n              [\n                3763845.3670365461,\n                5903055.9980064519\n              ],\n              [\n                3728791.1339836149,\n                5909381.6571826441\n              ],\n              [\n                3712076.1365221734,\n                5919807.300273018\n              ],\n              [\n                3703941.6063928884,\n                5918019.7483437611\n              ],\n              [\n                3700755.786590965,\n                5911583.242706717\n              ],\n              [\n                3683284.378220486,\n                5901519.8736129059\n              ],\n              [\n                3680200.6158619821,\n                5905056.4653345328\n              ],\n              [\n                3669396.6476244526,\n                5899831.1085491451\n              ],\n              [\n                3670935.6606098032,\n                5893318.19994\n              ],\n              [\n                3660311.8800712302,\n                5888738.7558573624\n              ],\n              [\n                3652231.3320433423,\n                5889511.3574547973\n              ],\n              [\n                3643302.4959958429,\n                5895374.819350563\n              ],\n              [\n                3639785.0696396269,\n                5892100.1719632307\n              ],\n              [\n                3606560.2346579311,\n                5916586.2707823943\n              ],\n              [\n                3608645.9904428972,\n                5924805.5896682888\n              ],\n              [\n                3620734.103808559,\n                5932842.580161592\n              ],\n              [\n                3621108.1006804346,\n                5938712.2612650106\n              ],\n              [\n                3629467.0720780403,\n                5938790.4934651023\n              ],\n              [\n                3628029.4118883419,\n                5951954.0380383944\n              ],\n              [\n                3623189.4327053195,\n                5953513.3434927408\n              ],\n              [\n                3619138.4221999128,\n                5958008.8936667377\n              ],\n              [\n                3616154.1812646016,\n                5958546.736402004\n              ],\n              [\n                3616689.3777262997,\n                5963752.7563475929\n              ],\n              [\n                3615255.5018173298,\n                5969260.8856087131\n              ],\n              [\n                3615980.348949628,\n                5971721.3096266175\n              ],\n              [\n                3623841.3356328616,\n                5977945.1403433578\n              ],\n              [\n                3626024.1404369744,\n                5976110.5464679133\n              ],\n              [\n                3628805.8970855772,\n                5977389.3176590335\n              ],\n              [\n                3625050.7337689409,\n                5979329.7269153669\n              ],\n              [\n                3625082.7900508232,\n                5982662.9355227295\n              ],\n              [\n                3642541.5708868173,\n                5989491.9165221117\n              ],\n              [\n                3647245.3665982271,\n                5981531.2007794483\n              ],\n              [\n                3653174.0782078085,\n                5983522.0033757631\n              ],\n              [\n                3661492.4592031753,\n                5977652.8750231266\n              ],\n              [\n                3655820.8028928475,\n                5985889.7743025105\n              ],\n              [\n                3663350.6954817097,\n                5988433.0763060879\n              ],\n              [\n                3678217.7285471754,\n                6006380.5903663486\n              ],\n              [\n                3702468.7811940378,\n                6009068.5689904485\n              ],\n              [\n                3707700.6256526238,\n                6017070.9558728579\n              ],\n              [\n                3717497.3602633895,\n                6024278.7813600069\n              ],\n              [\n                3726955.9006420602,\n                6043652.8382368414\n              ],\n              [\n                3732879.1080247746,\n                6041514.9281786047\n              ],\n              [\n                3751573.5256050769,\n                6042181.2297516\n              ],\n              [\n                3751194.3818650926,\n                6038592.5262381751\n              ],\n              [\n                3739667.4854723434,\n                6039851.6737545151\n              ],\n              [\n                3729144.6259276099,\n                6032464.1750187948\n              ],\n              [\n                3724343.3351603751,\n                6034435.6926388405\n              ],\n              [\n                3718792.9118886008,\n                6025039.0342627419\n              ],\n              [\n                3722354.2783105765,\n                6018654.7492071465\n              ],\n              [\n                3726227.3404115206,\n                6027813.5854513822\n              ],\n              [\n                3738785.27984973,\n                6035167.4210286662\n              ],\n              [\n                3751847.0466833659,\n                6032895.4936694633\n              ],\n              [\n                3761685.9547273475,\n                6041061.5307539245\n              ],\n              [\n                3767918.6873595146,\n                6024278.3875305923\n              ],\n              [\n                3779544.7257449995,\n                6019867.6876431284\n              ],\n              [\n                3791982.7664662367,\n                6005478.7560929675\n              ],\n              [\n                3792719.4913930758,\n                6008509.8053144859\n              ],\n              [\n                3806813.9026390165,\n                6012547.7583060171\n              ],\n              [\n                3813624.1933684391,\n                6008114.9790483778\n              ],\n              [\n                3814273.5260422458,\n                6015341.28071272\n              ],\n              [\n                3826245.4298891709,\n                6004732.7182455854\n              ],\n              [\n                3841931.3593487581,\n                5991047.874779541\n              ],\n              [\n                3841857.4827590617,\n                5984285.0268656248\n              ],\n              [\n                3820735.1401745877,\n                5978971.9858000716\n              ],\n              [\n                3823658.5330290105,\n                6004032.5048946002\n              ],\n              [\n                3812743.7630230263,\n                5998386.4246438835\n              ],\n              [\n                3813388.7445945316,\n                6005505.544981841\n              ],\n              [\n                3810809.0447827573,\n                5999782.8875678834\n              ],\n              [\n                3821994.1922710077,\n                5990116.933645878\n              ],\n              [\n                3816749.3601884744,\n                5982489.2711326405\n              ],\n              [\n                3828446.727039618,\n                5971682.0152686974\n              ],\n              [\n                3836719.1779422434,\n                5968847.9592408147\n              ],\n              [\n                3844529.3000683878,\n                5971131.5817635488\n              ],\n              [\n                3851718.7367773792,\n                5943706.1401673108\n              ],\n              [\n                3858958.4675184065,\n                5924746.6905517764\n              ]\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"14\",\n        \"adm1_code\": \"DEU-1575\",\n        \"OBJECTID_1\": \"1518\",\n        \"diss_me\": \"1575\",\n        \"adm1_cod_1\": \"DEU-1575\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Bremen\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.HB\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"5\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"HB\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"9\",\n        \"labelrank\": \"9\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"6\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM03\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345483\",\n        \"woe_label\": \"Bremen, DE, Germany\",\n        \"woe_name\": \"Bremen\",\n        \"latitude\": \"53.1211\",\n        \"longitude\": \"8.742990000000001\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2944387\",\n        \"gn_name\": \"Bremen\",\n        \"gns_id\": \"-1752235\",\n        \"gns_name\": \"Bremen\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.03\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM03\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"MultiPolygon\",\n        \"coordinates\": [\n          [\n            [\n              [\n                3470648.2738475171,\n                5897758.2648433764\n              ],\n              [\n                3482994.3597778352,\n                5895366.5686806049\n              ],\n              [\n                3494135.47721026,\n                5889523.4182940461\n              ],\n              [\n                3498339.9930427396,\n                5889002.5856371522\n              ],\n              [\n                3498170.5207677865,\n                5879865.4094565529\n              ],\n              [\n                3494265.4796796911,\n                5876757.5917747803\n              ],\n              [\n                3491011.2500537927,\n                5879309.938417878\n              ],\n              [\n                3480045.6539797694,\n                5879745.4698925437\n              ],\n              [\n                3480079.7036048737,\n                5882942.5270079691\n              ],\n              [\n                3473997.6676363903,\n                5894121.7778715324\n              ],\n              [\n                3467459.3721810151,\n                5896352.760481637\n              ],\n              [\n                3470648.2738475171,\n                5897758.2648433764\n              ]\n            ]\n          ],\n          [\n            [\n              [\n                3470633.9099116446,\n                5931964.1095968718\n              ],\n              [\n                3471219.9106471892,\n                5934938.2581426231\n              ],\n              [\n                3467778.8065959434,\n                5942795.0136931287\n              ],\n              [\n                3475199.3643792034,\n                5941403.5468862616\n              ],\n              [\n                3476062.7607371015,\n                5931567.9643862806\n              ],\n              [\n                3473640.484591655,\n                5928668.0521080317\n              ],\n              [\n                3470633.9099116446,\n                5931964.1095968718\n              ]\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"1\",\n        \"adm1_code\": \"DEU-1578\",\n        \"OBJECTID_1\": \"1520\",\n        \"diss_me\": \"1578\",\n        \"adm1_cod_1\": \"DEU-1578\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Hamburg\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.HH\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"21\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"HH\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"9\",\n        \"labelrank\": \"9\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"7\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM04\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345484\",\n        \"woe_label\": \"Hamburg, DE, Germany\",\n        \"woe_name\": \"Hamburg\",\n        \"latitude\": \"53.559\",\n        \"longitude\": \"10.0344\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2911297\",\n        \"gn_name\": \"Freie und Hansestadt Hamburg\",\n        \"gns_id\": \"-1785435\",\n        \"gns_name\": \"Hamburg\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.04\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM04\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3550632.9068574295,\n              5935231.2751757316\n            ],\n            [\n              3554307.569858544,\n              5936267.8784428686\n            ],\n            [\n              3549069.0712087429,\n              5937985.4088263968\n            ],\n            [\n              3550830.3006076724,\n              5944304.1125011407\n            ],\n            [\n              3554853.9405998117,\n              5940794.9144034721\n            ],\n            [\n              3570371.6708244649,\n              5950301.8162747147\n            ],\n            [\n              3572137.6137213707,\n              5954711.580675493\n            ],\n            [\n              3578862.6937927571,\n              5955081.5497373492\n            ],\n            [\n              3576943.630466254,\n              5950819.015340128\n            ],\n            [\n              3580874.49823714,\n              5945222.0506500695\n            ],\n            [\n              3577703.2560399352,\n              5938504.9128987873\n            ],\n            [\n              3578686.4275546414,\n              5933125.8551333752\n            ],\n            [\n              3588249.9672536696,\n              5922981.0870051431\n            ],\n            [\n              3578903.5037427521,\n              5919670.0220713178\n            ],\n            [\n              3571948.8982978156,\n              5924735.9639584571\n            ],\n            [\n              3565509.5510616428,\n              5920653.881467809\n            ],\n            [\n              3556965.7078730096,\n              5922524.892838276\n            ],\n            [\n              3550632.9068574295,\n              5935231.2751757316\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"3\",\n        \"adm1_code\": \"DEU-1580\",\n        \"OBJECTID_1\": \"2331\",\n        \"diss_me\": \"1580\",\n        \"adm1_cod_1\": \"DEU-1580\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Rheinland-Pfalz\",\n        \"name_alt\": \"Rhineland-Palatinate\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.RP\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"16\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"RP\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"15\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM08\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345488\",\n        \"woe_label\": \"Rhineland-Palatinate, DE, Germany\",\n        \"woe_name\": \"Rheinland-Pfalz\",\n        \"latitude\": \"49.8685\",\n        \"longitude\": \"7.36974\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2847618\",\n        \"gn_name\": \"Rheinland-Pfalz\",\n        \"gns_id\": \"-1849325\",\n        \"gns_name\": \"Rheinland-Pfalz\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.08\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM08\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3441413.1035388974,\n              5424738.8449200103\n            ],\n            [\n              3421909.7072348008,\n              5433496.2339400193\n            ],\n            [\n              3400206.9816703415,\n              5434171.874666106\n            ],\n            [\n              3381263.1691697384,\n              5448827.7981531238\n            ],\n            [\n              3375749.5360028311,\n              5453286.6340999817\n            ],\n            [\n              3382812.5808065045,\n              5467779.9515374238\n            ],\n            [\n              3372832.7086474616,\n              5480162.0484409798\n            ],\n            [\n              3377452.9388920865,\n              5484425.9351314809\n            ],\n            [\n              3374726.1658796789,\n              5494845.4324212102\n            ],\n            [\n              3371185.6562408176,\n              5493263.5940849595\n            ],\n            [\n              3365049.947543317,\n              5497693.0631523961\n            ],\n            [\n              3350931.1909566126,\n              5500859.6144528091\n            ],\n            [\n              3334486.4385668249,\n              5492783.5487769293\n            ],\n            [\n              3326657.9711445286,\n              5490789.7013586788\n            ],\n            [\n              3308089.9034189489,\n              5490864.744018699\n            ],\n            [\n              3313667.5787480427,\n              5506768.1633549016\n            ],\n            [\n              3319085.3295557285,\n              5510024.6220939485\n            ],\n            [\n              3320036.2148178266,\n              5520422.1984197628\n            ],\n            [\n              3313918.6219594479,\n              5521855.0304813217\n            ],\n            [\n              3300451.1426753607,\n              5531427.5120395822\n            ],\n            [\n              3292075.331599589,\n              5549727.9406546457\n            ],\n            [\n              3296390.0855788519,\n              5567982.1229122831\n            ],\n            [\n              3304168.46299545,\n              5572448.5800253376\n            ],\n            [\n              3307664.7511126897,\n              5578120.7324183807\n            ],\n            [\n              3312983.7700960236,\n              5579512.6769915028\n            ],\n            [\n              3316745.7783426233,\n              5580422.3833581302\n            ],\n            [\n              3314942.5281778327,\n              5586140.8450016081\n            ],\n            [\n              3319084.6380793764,\n              5581296.9993137084\n            ],\n            [\n              3328285.0183701818,\n              5585040.4950274136\n            ],\n            [\n              3330605.1985471123,\n              5582020.31771647\n            ],\n            [\n              3337596.2249325705,\n              5580760.0248874584\n            ],\n            [\n              3343107.5339642386,\n              5582155.4682631167\n            ],\n            [\n              3341011.5040215962,\n              5595025.0052518947\n            ],\n            [\n              3350093.4458034495,\n              5595426.0479528448\n            ],\n            [\n              3350049.3700410733,\n              5600448.5200936021\n            ],\n            [\n              3362065.5903108316,\n              5607751.5255306438\n            ],\n            [\n              3369368.6827267488,\n              5608763.7309827879\n            ],\n            [\n              3372459.6357410736,\n              5612603.93168246\n            ],\n            [\n              3378474.6462449804,\n              5610514.4526037313\n            ],\n            [\n              3384825.5188038861,\n              5613016.2159250593\n            ],\n            [\n              3386058.8756050379,\n              5619783.1269912859\n            ],\n            [\n              3401137.3966407343,\n              5622790.962612764\n            ],\n            [\n              3408249.7846913603,\n              5628022.5903055705\n            ],\n            [\n              3406666.4940470285,\n              5631204.3429187089\n            ],\n            [\n              3413201.5977249132,\n              5634040.7961232988\n            ],\n            [\n              3412628.2518007741,\n              5642375.6446921304\n            ],\n            [\n              3419827.9681884986,\n              5643501.2928428715\n            ],\n            [\n              3418700.2280780436,\n              5639011.3647475801\n            ],\n            [\n              3425511.3029791312,\n              5633355.6262931069\n            ],\n            [\n              3433322.8712637313,\n              5617549.7121808697\n            ],\n            [\n              3438838.0181758674,\n              5616717.762588284\n            ],\n            [\n              3440788.8477046415,\n              5605767.4036669126\n            ],\n            [\n              3436698.9808041384,\n              5599221.561436912\n            ],\n            [\n              3429406.6760302559,\n              5598670.4881470185\n            ],\n            [\n              3427486.3471034807,\n              5584796.3907665983\n            ],\n            [\n              3432385.6108222404,\n              5582006.6984252753\n            ],\n            [\n              3437471.8600296136,\n              5571557.030202195\n            ],\n            [\n              3423056.5161700593,\n              5563089.1127727879\n            ],\n            [\n              3422876.6023717704,\n              5552937.0920662321\n            ],\n            [\n              3418083.6548039587,\n              5553784.5111388061\n            ],\n            [\n              3412023.655965697,\n              5546950.898131174\n            ],\n            [\n              3422434.0216260618,\n              5537934.5923802424\n            ],\n            [\n              3440828.5246273172,\n              5545698.4037055941\n            ],\n            [\n              3444709.495428592,\n              5544811.9771885592\n            ],\n            [\n              3452319.9802185413,\n              5536002.3603432896\n            ],\n            [\n              3452586.3951217886,\n              5528367.2193213543\n            ],\n            [\n              3458495.5004734448,\n              5514559.1553209331\n            ],\n            [\n              3453841.9804025455,\n              5503159.6692345878\n            ],\n            [\n              3457830.8811206338,\n              5493673.0699443156\n            ],\n            [\n              3463300.0906483554,\n              5478415.3615263375\n            ],\n            [\n              3462173.0401205476,\n              5462228.3351949146\n            ],\n            [\n              3441413.1035388974,\n              5424738.8449200103\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"4\",\n        \"adm1_code\": \"DEU-1581\",\n        \"OBJECTID_1\": \"2332\",\n        \"diss_me\": \"1581\",\n        \"adm1_cod_1\": \"DEU-1581\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Saarland\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.SL\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"12\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"SL\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"8\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM09\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345489\",\n        \"woe_label\": \"Saarland, DE, Germany\",\n        \"woe_name\": \"Saarland\",\n        \"latitude\": \"49.4026\",\n        \"longitude\": \"6.86625\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2842635\",\n        \"gn_name\": \"Saarland\",\n        \"gns_id\": \"-1854333\",\n        \"gns_name\": \"Saarland\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.09\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM09\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3381263.1691697384,\n              5448827.7981531238\n            ],\n            [\n              3373557.3606479331,\n              5442263.874895405\n            ],\n            [\n              3342161.1407189239,\n              5454623.4918628894\n            ],\n            [\n              3340179.5116371857,\n              5447601.5385523606\n            ],\n            [\n              3332385.342399545,\n              5450840.3922064183\n            ],\n            [\n              3318304.2294849427,\n              5480523.8351349905\n            ],\n            [\n              3307562.3294992363,\n              5483097.0605111523\n            ],\n            [\n              3308089.9034189489,\n              5490864.744018699\n            ],\n            [\n              3326657.9711445286,\n              5490789.7013586788\n            ],\n            [\n              3334486.4385668249,\n              5492783.5487769293\n            ],\n            [\n              3350931.1909566126,\n              5500859.6144528091\n            ],\n            [\n              3365049.947543317,\n              5497693.0631523961\n            ],\n            [\n              3371185.6562408176,\n              5493263.5940849595\n            ],\n            [\n              3374726.1658796789,\n              5494845.4324212102\n            ],\n            [\n              3377452.9388920865,\n              5484425.9351314809\n            ],\n            [\n              3372832.7086474616,\n              5480162.0484409798\n            ],\n            [\n              3382812.5808065045,\n              5467779.9515374238\n            ],\n            [\n              3375749.5360028311,\n              5453286.6340999817\n            ],\n            [\n              3381263.1691697384,\n              5448827.7981531238\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"5\",\n        \"adm1_code\": \"DEU-1591\",\n        \"OBJECTID_1\": \"2333\",\n        \"diss_me\": \"1591\",\n        \"adm1_cod_1\": \"DEU-1591\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Bayern\",\n        \"name_alt\": \"Bavaria\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.BY\",\n        \"note\": null,\n        \"hasc_maybe\": \"DE.TH|DEU-BYR\",\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"14\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"BY\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"6\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM02\",\n        \"fips_alt\": \"GM15\",\n        \"woe_id\": \"2345482\",\n        \"woe_label\": \"Bavaria, DE, Germany\",\n        \"woe_name\": \"Bayern\",\n        \"latitude\": \"49.0056\",\n        \"longitude\": \"11.3966\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2951839\",\n        \"gn_name\": \"Freistaat Bayern\",\n        \"gns_id\": \"-1744755\",\n        \"gns_name\": \"Bayern\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.02\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM02\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3720854.929931188,\n              5579802.1671278924\n            ],\n            [\n              3719631.2211950263,\n              5571814.3670201534\n            ],\n            [\n              3732520.2786687785,\n              5550332.2352868849\n            ],\n            [\n              3748749.2603212004,\n              5542736.809619463\n            ],\n            [\n              3753100.7648904314,\n              5535668.0080291722\n            ],\n            [\n              3743829.3417696748,\n              5517178.9862410398\n            ],\n            [\n              3762324.3291879585,\n              5492080.2687983979\n            ],\n            [\n              3764245.5673894449,\n              5483218.791022324\n            ],\n            [\n              3775995.855328233,\n              5472471.210996354\n            ],\n            [\n              3790870.3988914737,\n              5469570.8132270994\n            ],\n            [\n              3804947.7173350696,\n              5450646.8378275726\n            ],\n            [\n              3813933.9184407792,\n              5448396.0162059972\n            ],\n            [\n              3828298.2930317265,\n              5431829.4757764423\n            ],\n            [\n              3837496.0529524805,\n              5433331.9746355461\n            ],\n            [\n              3853922.3040218116,\n              5414298.7288533179\n            ],\n            [\n              3854027.9231568337,\n              5397041.137897308\n            ],\n            [\n              3848317.1758256047,\n              5386640.727975281\n            ],\n            [\n              3833446.5846785088,\n              5392755.7269397127\n            ],\n            [\n              3826289.9515585969,\n              5369140.3878430389\n            ],\n            [\n              3816994.2940813755,\n              5360866.1018757839\n            ],\n            [\n              3799346.7957504704,\n              5355056.062758225\n            ],\n            [\n              3778767.4968754789,\n              5338084.6226216014\n            ],\n            [\n              3780201.3775204262,\n              5331942.0280900477\n            ],\n            [\n              3798665.6127939913,\n              5308605.0331156831\n            ],\n            [\n              3791934.1650316818,\n              5294492.4678504989\n            ],\n            [\n              3801583.7247173521,\n              5293802.7550295144\n            ],\n            [\n              3806028.2541264431,\n              5283947.7214670992\n            ],\n            [\n              3804167.7842186769,\n              5269432.0791578349\n            ],\n            [\n              3797155.9113819273,\n              5266557.9084208813\n            ],\n            [\n              3784369.5568754105,\n              5275318.431105678\n            ],\n            [\n              3782489.4718682836,\n              5287708.8790438846\n            ],\n            [\n              3765869.8159498828,\n              5282967.6688195048\n            ],\n            [\n              3757000.8567382093,\n              5289276.9764530305\n            ],\n            [\n              3738359.0559389209,\n              5290070.1350489352\n            ],\n            [\n              3737999.8904091902,\n              5278714.7879365459\n            ],\n            [\n              3720699.45624005,\n              5278787.4608982084\n            ],\n            [\n              3697068.2414810816,\n              5275593.9712792682\n            ],\n            [\n              3692138.5890133549,\n              5266976.1832740316\n            ],\n            [\n              3681727.3248318103,\n              5265798.1394534484\n            ],\n            [\n              3670484.2581564616,\n              5253737.0374460649\n            ],\n            [\n              3649428.9658668973,\n              5252031.1020079171\n            ],\n            [\n              3634830.2636962491,\n              5265638.6508152951\n            ],\n            [\n              3606391.2058383985,\n              5271384.9862124128\n            ],\n            [\n              3609508.0145107368,\n              5256512.8726171581\n            ],\n            [\n              3598748.4894922166,\n              5241134.8247360373\n            ],\n            [\n              3587417.9932788452,\n              5237698.0592393083\n            ],\n            [\n              3589919.3672567643,\n              5249560.5825826228\n            ],\n            [\n              3571438.51553459,\n              5265428.8433407042\n            ],\n            [\n              3545727.4155536136,\n              5271763.9444706095\n            ],\n            [\n              3551119.3500004988,\n              5274925.3375281552\n            ],\n            [\n              3553760.0831742487,\n              5274202.1924148183\n            ],\n            [\n              3564921.0598903387,\n              5282095.2396906596\n            ],\n            [\n              3571596.2949043298,\n              5280467.0692903223\n            ],\n            [\n              3579419.406908934,\n              5282654.3130722083\n            ],\n            [\n              3580805.8182427208,\n              5279501.6412465433\n            ],\n            [\n              3582086.3286339194,\n              5282857.9677951159\n            ],\n            [\n              3584928.4473972623,\n              5283809.5219843267\n            ],\n            [\n              3583494.2047532503,\n              5292617.613166254\n            ],\n            [\n              3580930.5669586663,\n              5294773.3959587673\n            ],\n            [\n              3584580.1453866977,\n              5298103.7145693144\n            ],\n            [\n              3582134.3343479666,\n              5304897.8270773264\n            ],\n            [\n              3582885.1004398358,\n              5311565.5902857054\n            ],\n            [\n              3581170.5874427473,\n              5314040.8154020924\n            ],\n            [\n              3584271.0151908011,\n              5322385.9982684879\n            ],\n            [\n              3584603.1174242902,\n              5330438.8159838542\n            ],\n            [\n              3582536.9707668643,\n              5334936.9094386967\n            ],\n            [\n              3578187.6194506902,\n              5352316.3667016691\n            ],\n            [\n              3572624.432680374,\n              5360747.4124220517\n            ],\n            [\n              3578955.5050633829,\n              5370940.3940610792\n            ],\n            [\n              3583771.9889397854,\n              5372636.0281001786\n            ],\n            [\n              3585285.3429935728,\n              5370319.6556346128\n            ],\n            [\n              3592397.2803958142,\n              5374804.8767391955\n            ],\n            [\n              3597104.90080478,\n              5377768.9604256051\n            ],\n            [\n              3596820.2459671348,\n              5386336.2469680198\n            ],\n            [\n              3598254.0374123072,\n              5388042.2132638032\n            ],\n            [\n              3594990.0970565821,\n              5390440.2955783168\n            ],\n            [\n              3593537.9326087711,\n              5394395.9917849256\n            ],\n            [\n              3595531.1762953508,\n              5396915.3128908044\n            ],\n            [\n              3601043.7237907918,\n              5392675.2968838485\n            ],\n            [\n              3604817.5383069692,\n              5396914.4062103806\n            ],\n            [\n              3605494.6288470197,\n              5393679.6094944002\n            ],\n            [\n              3610040.9729735483,\n              5396732.7561689578\n            ],\n            [\n              3605288.9192014784,\n              5404018.894093167\n            ],\n            [\n              3607096.9641639437,\n              5411585.8563470664\n            ],\n            [\n              3606859.6900644084,\n              5423359.0073309727\n            ],\n            [\n              3599011.9484724626,\n              5433669.2124226196\n            ],\n            [\n              3593147.1400163225,\n              5435435.6389526604\n            ],\n            [\n              3592245.8891499159,\n              5443944.4963075556\n            ],\n            [\n              3583564.5297398535,\n              5452545.6756128054\n            ],\n            [\n              3582413.875438883,\n              5459974.4160899296\n            ],\n            [\n              3584382.777422816,\n              5460337.6364304721\n            ],\n            [\n              3581463.7540525994,\n              5470771.6749604018\n            ],\n            [\n              3585018.2661472317,\n              5472469.5360561004\n            ],\n            [\n              3582846.7077056891,\n              5477603.5611078702\n            ],\n            [\n              3580825.872080544,\n              5478633.7955291895\n            ],\n            [\n              3581644.3427704326,\n              5486557.8843275979\n            ],\n            [\n              3578523.3819369273,\n              5490167.6813984727\n            ],\n            [\n              3577176.3558150646,\n              5486245.6809542198\n            ],\n            [\n              3573881.9593119058,\n              5482987.1144731594\n            ],\n            [\n              3567840.6018891246,\n              5483063.8994000871\n            ],\n            [\n              3566013.3375535863,\n              5493864.1031941669\n            ],\n            [\n              3561886.1846542899,\n              5489700.4107388947\n            ],\n            [\n              3560708.0498845158,\n              5490710.2006405825\n            ],\n            [\n              3563761.6499401266,\n              5497211.0637213998\n            ],\n            [\n              3560208.8010403323,\n              5502015.7024308359\n            ],\n            [\n              3560005.6028370573,\n              5506214.9098258298\n            ],\n            [\n              3557139.2306370987,\n              5509661.1895087473\n            ],\n            [\n              3552489.5273762518,\n              5505757.5850912258\n            ],\n            [\n              3551176.5391815607,\n              5509357.2814978566\n            ],\n            [\n              3548880.8715447127,\n              5506083.0556571763\n            ],\n            [\n              3545480.2621061597,\n              5506998.8894933118\n            ],\n            [\n              3546539.9080542442,\n              5516416.3428387139\n            ],\n            [\n              3543354.8998105251,\n              5514967.3727186071\n            ],\n            [\n              3535345.8245763546,\n              5517624.6485599363\n            ],\n            [\n              3525335.9484673571,\n              5516510.933784782\n            ],\n            [\n              3522498.7099780627,\n              5514265.6125144539\n            ],\n            [\n              3522607.3664702717,\n              5510533.3209668808\n            ],\n            [\n              3530810.1855651978,\n              5507912.8665117286\n            ],\n            [\n              3529207.3879846265,\n              5500329.3255963055\n            ],\n            [\n              3527193.7326927111,\n              5501474.0234873584\n            ],\n            [\n              3520685.2364013265,\n              5498793.0887854239\n            ],\n            [\n              3518325.600151998,\n              5493330.7812480545\n            ],\n            [\n              3508004.7275028112,\n              5493032.8392732944\n            ],\n            [\n              3505250.4010145608,\n              5497006.3185954299\n            ],\n            [\n              3508038.9263903359,\n              5500227.9951685322\n            ],\n            [\n              3509617.7330651209,\n              5506477.500841843\n            ],\n            [\n              3510146.6536235306,\n              5516639.2130606221\n            ],\n            [\n              3505048.3221994299,\n              5521439.4779663766\n            ],\n            [\n              3501918.8327689632,\n              5529980.5791802146\n            ],\n            [\n              3501924.5455787638,\n              5545078.5930615086\n            ],\n            [\n              3498323.6014661267,\n              5546150.3840967752\n            ],\n            [\n              3500735.6345797917,\n              5551049.7819365254\n            ],\n            [\n              3507714.830290556,\n              5554233.6068744743\n            ],\n            [\n              3510910.1904314789,\n              5552779.3399014063\n            ],\n            [\n              3516350.8844319284,\n              5556299.1656100359\n            ],\n            [\n              3523525.7989939875,\n              5555823.0760990549\n            ],\n            [\n              3529102.3323403024,\n              5550628.9499717057\n            ],\n            [\n              3536241.2263133698,\n              5552425.6098567126\n            ],\n            [\n              3537768.1315709203,\n              5559166.6873750146\n            ],\n            [\n              3535646.7908835602,\n              5560063.0808881437\n            ],\n            [\n              3536454.1115450612,\n              5566675.5268396242\n            ],\n            [\n              3547168.3691143082,\n              5566552.8579348298\n            ],\n            [\n              3548486.4890143084,\n              5571588.4039183576\n            ],\n            [\n              3553322.554148009,\n              5574531.7938179336\n            ],\n            [\n              3554503.9289892185,\n              5585281.3163722064\n            ],\n            [\n              3561061.3854291611,\n              5585008.1051580943\n            ],\n            [\n              3571078.9444448808,\n              5590634.6929859295\n            ],\n            [\n              3574817.4056062475,\n              5598257.4420703379\n            ],\n            [\n              3579781.59930187,\n              5603487.1175612584\n            ],\n            [\n              3584213.7888737433,\n              5602032.7751879171\n            ],\n            [\n              3587805.4131642585,\n              5597748.057573312\n            ],\n            [\n              3593561.5613371767,\n              5595872.3240806991\n            ],\n            [\n              3599433.8822761257,\n              5588255.5182174174\n            ],\n            [\n              3599920.250670508,\n              5585260.6331641655\n            ],\n            [\n              3603043.3838240071,\n              5585677.0623686798\n            ],\n            [\n              3606720.0805508858,\n              5580673.1137679294\n            ],\n            [\n              3610451.0868479265,\n              5581336.1181971366\n            ],\n            [\n              3613301.3204261549,\n              5577745.2251591412\n            ],\n            [\n              3615378.8061682819,\n              5566488.7467001993\n            ],\n            [\n              3623231.2025344539,\n              5565109.5173362065\n            ],\n            [\n              3623502.8652153891,\n              5568663.640977269\n            ],\n            [\n              3631250.6056273249,\n              5568820.599108696\n            ],\n            [\n              3631003.5069937492,\n              5572109.5285800658\n            ],\n            [\n              3622115.8301066705,\n              5577492.5262480676\n            ],\n            [\n              3622821.4798547197,\n              5581827.2477174671\n            ],\n            [\n              3627205.3913595304,\n              5584768.6555711003\n            ],\n            [\n              3638188.6970979096,\n              5585165.1007029591\n            ],\n            [\n              3641467.2303942246,\n              5581085.1458215769\n            ],\n            [\n              3645868.0769925839,\n              5580963.0357561549\n            ],\n            [\n              3650284.4903703765,\n              5583030.593772362\n            ],\n            [\n              3653432.929886797,\n              5578485.1134469826\n            ],\n            [\n              3652087.5666547911,\n              5576864.6365224905\n            ],\n            [\n              3656266.8897332451,\n              5572781.6523313411\n            ],\n            [\n              3660745.4664473836,\n              5573283.5300583346\n            ],\n            [\n              3662238.810322443,\n              5582653.1846054439\n            ],\n            [\n              3659605.2232868215,\n              5595262.2291009063\n            ],\n            [\n              3664336.9864799059,\n              5597622.3606871739\n            ],\n            [\n              3666404.0989981135,\n              5600603.8442229992\n            ],\n            [\n              3672121.9713641307,\n              5600160.7438294999\n            ],\n            [\n              3671958.3111791341,\n              5592357.348135368\n            ],\n            [\n              3675994.001566703,\n              5590758.7787582632\n            ],\n            [\n              3676626.67844284,\n              5587664.6132867765\n            ],\n            [\n              3680049.0477793319,\n              5585432.8105548657\n            ],\n            [\n              3698749.3649529289,\n              5590010.1434312938\n            ],\n            [\n              3701124.6336581926,\n              5587599.6888292851\n            ],\n            [\n              3706456.6357335709,\n              5590490.103557012\n            ],\n            [\n              3712475.9410972646,\n              5583643.9742964255\n            ],\n            [\n              3720854.929931188,\n              5579802.1671278924\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"8\",\n        \"adm1_code\": \"DEU-1601\",\n        \"OBJECTID_1\": \"2336\",\n        \"diss_me\": \"1601\",\n        \"adm1_cod_1\": \"DEU-1601\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Sachsen\",\n        \"name_alt\": \"Saxony\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.SN\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"13\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"SN\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"7\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM13\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345493\",\n        \"woe_label\": \"Saxony, DE, Germany\",\n        \"woe_name\": \"Sachsen\",\n        \"latitude\": \"51.0053\",\n        \"longitude\": \"13.4596\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2842566\",\n        \"gn_name\": \"Freistaat Sachsen\",\n        \"gns_id\": \"-1854402\",\n        \"gns_name\": \"Sachsen\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.13\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM13\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3895729.9823607644,\n              5727122.6007731473\n            ],\n            [\n              3913070.5398604777,\n              5718259.5309541589\n            ],\n            [\n              3920360.2740866155,\n              5695097.0156875188\n            ],\n            [\n              3917262.6324534719,\n              5675524.3458810057\n            ],\n            [\n              3906855.3511170237,\n              5646619.4597514132\n            ],\n            [\n              3895163.1054948336,\n              5649360.6450482514\n            ],\n            [\n              3896125.4075728473,\n              5656567.4818767738\n            ],\n            [\n              3885322.9184645279,\n              5667742.8164319936\n            ],\n            [\n              3870722.8689866588,\n              5668920.658955303\n            ],\n            [\n              3867706.1925043422,\n              5662631.8681641854\n            ],\n            [\n              3876123.3069151207,\n              5651812.8112209244\n            ],\n            [\n              3844935.6204190049,\n              5638502.4966573529\n            ],\n            [\n              3841262.8713556938,\n              5631926.33240279\n            ],\n            [\n              3824931.3167273672,\n              5629596.8108225381\n            ],\n            [\n              3814830.689602342,\n              5616161.0174571536\n            ],\n            [\n              3799673.1328355772,\n              5613571.7049376061\n            ],\n            [\n              3795090.3541931743,\n              5603831.5304041319\n            ],\n            [\n              3784445.6694856659,\n              5602760.9429713953\n            ],\n            [\n              3778486.0135767977,\n              5592711.3187929457\n            ],\n            [\n              3771699.906899136,\n              5596372.6104919445\n            ],\n            [\n              3749573.2997890264,\n              5589410.5125307078\n            ],\n            [\n              3737872.9533890621,\n              5574367.7266012002\n            ],\n            [\n              3734558.6914271559,\n              5563483.4667501887\n            ],\n            [\n              3730459.2210461572,\n              5574098.141054092\n            ],\n            [\n              3720854.929931188,\n              5579802.1671278924\n            ],\n            [\n              3712475.9410972646,\n              5583643.9742964255\n            ],\n            [\n              3706456.6357335709,\n              5590490.103557012\n            ],\n            [\n              3707593.3788553113,\n              5598689.8272855673\n            ],\n            [\n              3711847.4358901861,\n              5605288.3101831255\n            ],\n            [\n              3716102.6109797498,\n              5603841.3164922409\n            ],\n            [\n              3722819.9620642923,\n              5607572.8059453368\n            ],\n            [\n              3725457.3308588881,\n              5614794.9990650406\n            ],\n            [\n              3730125.0831804471,\n              5614992.2367806258\n            ],\n            [\n              3734759.1665375163,\n              5620512.1446339721\n            ],\n            [\n              3728832.1004670118,\n              5625615.0790818483\n            ],\n            [\n              3729672.7793026781,\n              5633487.7130454583\n            ],\n            [\n              3741232.331247753,\n              5637557.6046812981\n            ],\n            [\n              3748218.9617048698,\n              5643708.7736610528\n            ],\n            [\n              3756509.8321495252,\n              5646715.3534608511\n            ],\n            [\n              3748992.2363486462,\n              5654296.6612281911\n            ],\n            [\n              3744176.9108976396,\n              5663770.8769144556\n            ],\n            [\n              3728697.3410449172,\n              5665894.003271156\n            ],\n            [\n              3725736.6071475316,\n              5666344.9610057147\n            ],\n            [\n              3720493.4261422371,\n              5675145.0456173113\n            ],\n            [\n              3718449.0036664321,\n              5688621.3779614437\n            ],\n            [\n              3721730.6767142406,\n              5692441.5749404654\n            ],\n            [\n              3719417.8191738939,\n              5706182.4262456577\n            ],\n            [\n              3724304.7276911819,\n              5719002.5429664785\n            ],\n            [\n              3737782.7113693953,\n              5720766.2362732422\n            ],\n            [\n              3738522.3460328085,\n              5724031.9576492552\n            ],\n            [\n              3753662.7909530257,\n              5724768.6707163947\n            ],\n            [\n              3761788.6117216963,\n              5728031.8281768858\n            ],\n            [\n              3767113.5430716942,\n              5732917.2825115556\n            ],\n            [\n              3781244.7607806674,\n              5727749.173669612\n            ],\n            [\n              3789159.7458350016,\n              5722743.0719234683\n            ],\n            [\n              3791429.4246440106,\n              5702687.0541994385\n            ],\n            [\n              3806709.1660082862,\n              5707620.2425152455\n            ],\n            [\n              3814794.8146041944,\n              5702036.2389156315\n            ],\n            [\n              3831961.9311943511,\n              5701008.7637389079\n            ],\n            [\n              3846067.6576036941,\n              5703199.0928839929\n            ],\n            [\n              3857862.6325678141,\n              5722744.2213756908\n            ],\n            [\n              3870467.4319547503,\n              5721757.1183289066\n            ],\n            [\n              3881910.1924875081,\n              5727851.2041914547\n            ],\n            [\n              3895729.9823607644,\n              5727122.6007731473\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"7\",\n        \"adm1_code\": \"DEU-1600\",\n        \"OBJECTID_1\": \"2335\",\n        \"diss_me\": \"1600\",\n        \"adm1_cod_1\": \"DEU-1600\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Sachsen-Anhalt\",\n        \"name_alt\": \"Saxony-Anhalt\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.ST\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"18\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"ST\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"14\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM14\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345494\",\n        \"woe_label\": \"Saxony-Anhalt, DE, Germany\",\n        \"woe_name\": \"Sachsen-Anhalt\",\n        \"latitude\": \"51.9338\",\n        \"longitude\": \"11.6796\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2842565\",\n        \"gn_name\": \"Land Sachsen-Anhalt\",\n        \"gns_id\": \"-1854403\",\n        \"gns_name\": \"Sachsen-Anhalt\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.14\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM14\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3781244.7607806674,\n              5727749.173669612\n            ],\n            [\n              3767113.5430716942,\n              5732917.2825115556\n            ],\n            [\n              3761788.6117216963,\n              5728031.8281768858\n            ],\n            [\n              3753662.7909530257,\n              5724768.6707163947\n            ],\n            [\n              3738522.3460328085,\n              5724031.9576492552\n            ],\n            [\n              3737782.7113693953,\n              5720766.2362732422\n            ],\n            [\n              3724304.7276911819,\n              5719002.5429664785\n            ],\n            [\n              3719417.8191738939,\n              5706182.4262456577\n            ],\n            [\n              3721730.6767142406,\n              5692441.5749404654\n            ],\n            [\n              3718449.0036664321,\n              5688621.3779614437\n            ],\n            [\n              3720493.4261422371,\n              5675145.0456173113\n            ],\n            [\n              3725736.6071475316,\n              5666344.9610057147\n            ],\n            [\n              3728697.3410449172,\n              5665894.003271156\n            ],\n            [\n              3729823.6229192242,\n              5657699.0347429402\n            ],\n            [\n              3724984.3058717526,\n              5648366.5871077562\n            ],\n            [\n              3721967.7634851355,\n              5650922.120966264\n            ],\n            [\n              3711102.7786706178,\n              5650136.7946595009\n            ],\n            [\n              3700671.5497429045,\n              5657917.8290444724\n            ],\n            [\n              3691711.4629774042,\n              5657002.0672275824\n            ],\n            [\n              3688360.598657859,\n              5665165.5228766529\n            ],\n            [\n              3670003.9710097802,\n              5665298.3177191904\n            ],\n            [\n              3669281.7923881463,\n              5672052.1862729536\n            ],\n            [\n              3662981.3890735451,\n              5678154.1523908963\n            ],\n            [\n              3671078.403472946,\n              5684562.7217747746\n            ],\n            [\n              3661128.3753905562,\n              5696690.098692731\n            ],\n            [\n              3639072.4658529945,\n              5698871.2434897516\n            ],\n            [\n              3632504.2172296499,\n              5716768.8556063659\n            ],\n            [\n              3634798.3906453014,\n              5719458.0870596841\n            ],\n            [\n              3617510.6850254778,\n              5723772.3194554569\n            ],\n            [\n              3615012.1854641521,\n              5731490.6919269329\n            ],\n            [\n              3609394.947188708,\n              5739233.3662485098\n            ],\n            [\n              3608880.3975983351,\n              5746675.8150769975\n            ],\n            [\n              3612899.5315223499,\n              5751066.7033877522\n            ],\n            [\n              3610948.6257142145,\n              5755584.0213080486\n            ],\n            [\n              3613030.801248,\n              5759432.3883808982\n            ],\n            [\n              3607797.4707193407,\n              5764671.3332481934\n            ],\n            [\n              3613361.9478737903,\n              5768780.5365629746\n            ],\n            [\n              3626913.4232676532,\n              5769958.5594496056\n            ],\n            [\n              3634968.6410203772,\n              5771763.776092371\n            ],\n            [\n              3633454.749544749,\n              5775329.8780293567\n            ],\n            [\n              3639545.4940197729,\n              5779363.0596436961\n            ],\n            [\n              3638079.8541451683,\n              5785463.3934184005\n            ],\n            [\n              3642306.9390903679,\n              5789843.2179832282\n            ],\n            [\n              3637457.8965149773,\n              5796638.6178118531\n            ],\n            [\n              3636231.0192434615,\n              5802737.3780365922\n            ],\n            [\n              3641160.67654408,\n              5806181.3832803816\n            ],\n            [\n              3631772.1436179769,\n              5815934.1879419796\n            ],\n            [\n              3635920.4080108143,\n              5820057.3019131161\n            ],\n            [\n              3632514.9164062119,\n              5825233.8930791495\n            ],\n            [\n              3633938.0988071673,\n              5832809.371821166\n            ],\n            [\n              3630000.1103232088,\n              5833404.7902165819\n            ],\n            [\n              3624130.2654388198,\n              5843359.7207674412\n            ],\n            [\n              3621666.099287462,\n              5844655.1274119448\n            ],\n            [\n              3618514.5615372388,\n              5851704.8690217081\n            ],\n            [\n              3618718.1755545707,\n              5857485.6109101465\n            ],\n            [\n              3632019.5397876874,\n              5860810.2693054294\n            ],\n            [\n              3635509.5308777369,\n              5866108.0874277316\n            ],\n            [\n              3648934.7473273841,\n              5864932.535072092\n            ],\n            [\n              3651333.2684875731,\n              5862791.5747473724\n            ],\n            [\n              3662276.0322155575,\n              5866329.1451455932\n            ],\n            [\n              3668159.9163241819,\n              5870732.0661629066\n            ],\n            [\n              3668261.3414150965,\n              5877081.257549637\n            ],\n            [\n              3671922.8545249584,\n              5878200.7057062704\n            ],\n            [\n              3673094.9477649452,\n              5881900.7282523569\n            ],\n            [\n              3685470.527182492,\n              5877043.1175059043\n            ],\n            [\n              3690394.3300075424,\n              5869785.5474416316\n            ],\n            [\n              3699574.5929267807,\n              5865363.214592156\n            ],\n            [\n              3708117.6930525554,\n              5866440.6340229502\n            ],\n            [\n              3715667.1928544352,\n              5863903.8374439515\n            ],\n            [\n              3717929.5001302152,\n              5858476.4293313287\n            ],\n            [\n              3715469.8620647853,\n              5849748.085141778\n            ],\n            [\n              3718214.6508923629,\n              5844431.1891566208\n            ],\n            [\n              3711850.4436102621,\n              5829091.543895375\n            ],\n            [\n              3717622.3749302062,\n              5827795.9666623687\n            ],\n            [\n              3723223.1986584924,\n              5821704.5994157083\n            ],\n            [\n              3720737.934966553,\n              5816927.2713739648\n            ],\n            [\n              3718959.61734682,\n              5798644.4757761015\n            ],\n            [\n              3721757.2971702325,\n              5795806.4581173742\n            ],\n            [\n              3718700.9173543877,\n              5789151.6860899935\n            ],\n            [\n              3723228.6656669825,\n              5782040.1035374934\n            ],\n            [\n              3734812.1546247685,\n              5769569.3694657935\n            ],\n            [\n              3737897.7987304418,\n              5770821.5788534619\n            ],\n            [\n              3747886.3812362328,\n              5765052.4747153148\n            ],\n            [\n              3751784.0961636314,\n              5768485.2524125446\n            ],\n            [\n              3766349.8402684638,\n              5760146.1772142258\n            ],\n            [\n              3771836.8357371399,\n              5759778.7603498688\n            ],\n            [\n              3780081.7644681148,\n              5754179.0442536157\n            ],\n            [\n              3791815.5008474807,\n              5755165.8817298934\n            ],\n            [\n              3787186.3117421567,\n              5747485.4105568705\n            ],\n            [\n              3788950.7222997635,\n              5738608.6159806\n            ],\n            [\n              3781244.7607806674,\n              5727749.173669612\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"9\",\n        \"adm1_code\": \"DEU-3487\",\n        \"OBJECTID_1\": \"3562\",\n        \"diss_me\": \"3487\",\n        \"adm1_cod_1\": \"DEU-3487\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Brandenburg\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.\",\n        \"note\": null,\n        \"hasc_maybe\": \"DE.BE|DEU-BRN\",\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"17\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"BE\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"11\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM11\",\n        \"fips_alt\": \"GM16\",\n        \"woe_id\": \"2345491\",\n        \"woe_label\": \"Brandenburg, DE, Germany\",\n        \"woe_name\": \"Brandenburg\",\n        \"latitude\": \"52.8156\",\n        \"longitude\": \"12.9206\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2945356\",\n        \"gn_name\": \"Land Brandenburg\",\n        \"gns_id\": \"-1751262\",\n        \"gns_name\": \"Brandenburg\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.11\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM11\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3858958.4675184065,\n              5924746.6905517764\n            ],\n            [\n              3863006.6963384282,\n              5915868.9256445663\n            ],\n            [\n              3858145.8362342203,\n              5892787.8486107616\n            ],\n            [\n              3845536.6696635247,\n              5881951.7849794067\n            ],\n            [\n              3845024.9412794961,\n              5869707.4513760619\n            ],\n            [\n              3882462.763382134,\n              5841922.4558948586\n            ],\n            [\n              3876679.8774116514,\n              5824138.593258542\n            ],\n            [\n              3894793.9838867425,\n              5786961.4449581495\n            ],\n            [\n              3885105.1970240651,\n              5755706.9621667564\n            ],\n            [\n              3895439.295541347,\n              5742171.3496038476\n            ],\n            [\n              3895729.9823607644,\n              5727122.6007731473\n            ],\n            [\n              3881910.1924875081,\n              5727851.2041914547\n            ],\n            [\n              3870467.4319547503,\n              5721757.1183289066\n            ],\n            [\n              3857862.6325678141,\n              5722744.2213756908\n            ],\n            [\n              3846067.6576036941,\n              5703199.0928839929\n            ],\n            [\n              3831961.9311943511,\n              5701008.7637389079\n            ],\n            [\n              3814794.8146041944,\n              5702036.2389156315\n            ],\n            [\n              3806709.1660082862,\n              5707620.2425152455\n            ],\n            [\n              3791429.4246440106,\n              5702687.0541994385\n            ],\n            [\n              3789159.7458350016,\n              5722743.0719234683\n            ],\n            [\n              3781244.7607806674,\n              5727749.173669612\n            ],\n            [\n              3788950.7222997635,\n              5738608.6159806\n            ],\n            [\n              3787186.3117421567,\n              5747485.4105568705\n            ],\n            [\n              3791815.5008474807,\n              5755165.8817298934\n            ],\n            [\n              3780081.7644681148,\n              5754179.0442536157\n            ],\n            [\n              3771836.8357371399,\n              5759778.7603498688\n            ],\n            [\n              3766349.8402684638,\n              5760146.1772142258\n            ],\n            [\n              3751784.0961636314,\n              5768485.2524125446\n            ],\n            [\n              3747886.3812362328,\n              5765052.4747153148\n            ],\n            [\n              3737897.7987304418,\n              5770821.5788534619\n            ],\n            [\n              3734812.1546247685,\n              5769569.3694657935\n            ],\n            [\n              3723228.6656669825,\n              5782040.1035374934\n            ],\n            [\n              3718700.9173543877,\n              5789151.6860899935\n            ],\n            [\n              3721757.2971702325,\n              5795806.4581173742\n            ],\n            [\n              3718959.61734682,\n              5798644.4757761015\n            ],\n            [\n              3720737.934966553,\n              5816927.2713739648\n            ],\n            [\n              3723223.1986584924,\n              5821704.5994157083\n            ],\n            [\n              3717622.3749302062,\n              5827795.9666623687\n            ],\n            [\n              3711850.4436102621,\n              5829091.543895375\n            ],\n            [\n              3718214.6508923629,\n              5844431.1891566208\n            ],\n            [\n              3715469.8620647853,\n              5849748.085141778\n            ],\n            [\n              3717929.5001302152,\n              5858476.4293313287\n            ],\n            [\n              3715667.1928544352,\n              5863903.8374439515\n            ],\n            [\n              3708117.6930525554,\n              5866440.6340229502\n            ],\n            [\n              3699574.5929267807,\n              5865363.214592156\n            ],\n            [\n              3690394.3300075424,\n              5869785.5474416316\n            ],\n            [\n              3685470.527182492,\n              5877043.1175059043\n            ],\n            [\n              3673094.9477649452,\n              5881900.7282523569\n            ],\n            [\n              3661924.2617668891,\n              5885747.2731848815\n            ],\n            [\n              3652231.3320433423,\n              5889511.3574547973\n            ],\n            [\n              3660311.8800712302,\n              5888738.7558573624\n            ],\n            [\n              3670935.6606098032,\n              5893318.19994\n            ],\n            [\n              3669396.6476244526,\n              5899831.1085491451\n            ],\n            [\n              3680200.6158619821,\n              5905056.4653345328\n            ],\n            [\n              3683284.378220486,\n              5901519.8736129059\n            ],\n            [\n              3700755.786590965,\n              5911583.242706717\n            ],\n            [\n              3703941.6063928884,\n              5918019.7483437611\n            ],\n            [\n              3712076.1365221734,\n              5919807.300273018\n            ],\n            [\n              3728791.1339836149,\n              5909381.6571826441\n            ],\n            [\n              3763845.3670365461,\n              5903055.9980064519\n            ],\n            [\n              3767480.0978048071,\n              5900151.2545123501\n            ],\n            [\n              3777112.0423970157,\n              5910922.5465983907\n            ],\n            [\n              3793795.8883584146,\n              5913641.643195576\n            ],\n            [\n              3801803.8451427119,\n              5927759.7186010573\n            ],\n            [\n              3812528.0683271405,\n              5937242.9811624223\n            ],\n            [\n              3822905.9499626607,\n              5941589.9501121677\n            ],\n            [\n              3826929.8373607565,\n              5932832.0742536131\n            ],\n            [\n              3848307.6588879293,\n              5934358.7847815678\n            ],\n            [\n              3848470.2881636913,\n              5929329.4855594682\n            ],\n            [\n              3840283.6437742342,\n              5916498.3542627199\n            ],\n            [\n              3850096.8967003031,\n              5915716.2145906379\n            ],\n            [\n              3858958.4675184065,\n              5924746.6905517764\n            ]\n          ],\n          [\n            [\n              3804566.4152815924,\n              5843865.692704617\n            ],\n            [\n              3802213.9156131558,\n              5845930.8582165847\n            ],\n            [\n              3796466.9763708967,\n              5841442.4283941165\n            ],\n            [\n              3791058.6585779274,\n              5844454.8433719436\n            ],\n            [\n              3785707.312560183,\n              5840767.7494266415\n            ],\n            [\n              3785070.6277251416,\n              5836354.5125904409\n            ],\n            [\n              3781589.121700428,\n              5837662.7537919097\n            ],\n            [\n              3780958.9744146601,\n              5829146.268900374\n            ],\n            [\n              3778418.5104975295,\n              5817224.1775639663\n            ],\n            [\n              3782830.3462029067,\n              5815037.8793154648\n            ],\n            [\n              3792079.8344209795,\n              5817614.5021004295\n            ],\n            [\n              3801245.3895061575,\n              5814373.9040043866\n            ],\n            [\n              3803208.3688719897,\n              5818473.9252682505\n            ],\n            [\n              3815681.7293974063,\n              5814709.1505647963\n            ],\n            [\n              3816409.7180140801,\n              5810966.0266671684\n            ],\n            [\n              3820320.890532007,\n              5814819.0171839539\n            ],\n            [\n              3822865.3678980898,\n              5823472.4171997104\n            ],\n            [\n              3816712.9457131149,\n              5827478.2731477637\n            ],\n            [\n              3814140.9994099671,\n              5827006.7575231045\n            ],\n            [\n              3815207.714945185,\n              5832907.5054032393\n            ],\n            [\n              3809716.679845443,\n              5835249.9865113907\n            ],\n            [\n              3804934.6433777702,\n              5840168.5899853837\n            ],\n            [\n              3804566.4152815924,\n              5843865.692704617\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"11\",\n        \"adm1_code\": \"DEU-1572\",\n        \"OBJECTID_1\": \"1515\",\n        \"diss_me\": \"1572\",\n        \"adm1_cod_1\": \"DEU-1572\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Nordrhein-Westfalen\",\n        \"name_alt\": \"North Rhine-Westphalia\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.NW\",\n        \"note\": null,\n        \"hasc_maybe\": \"DE.NI|DEU-NWS\",\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"11\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"NW\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"19\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM07\",\n        \"fips_alt\": \"GM06\",\n        \"woe_id\": \"2345487\",\n        \"woe_label\": \"North Rhine-Westphalia, DE, Germany\",\n        \"woe_name\": \"Nordrhein-Westfalen\",\n        \"latitude\": \"51.6146\",\n        \"longitude\": \"7.65708\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2861876\",\n        \"gn_name\": \"Land Nordrhein-Westfalen\",\n        \"gns_id\": \"-1835009\",\n        \"gns_name\": \"Nordrhein-Westfalen\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.07\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM07\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3438838.0181758674,\n              5616717.762588284\n            ],\n            [\n              3433322.8712637313,\n              5617549.7121808697\n            ],\n            [\n              3425511.3029791312,\n              5633355.6262931069\n            ],\n            [\n              3418700.2280780436,\n              5639011.3647475801\n            ],\n            [\n              3419827.9681884986,\n              5643501.2928428715\n            ],\n            [\n              3412628.2518007741,\n              5642375.6446921304\n            ],\n            [\n              3413201.5977249132,\n              5634040.7961232988\n            ],\n            [\n              3406666.4940470285,\n              5631204.3429187089\n            ],\n            [\n              3408249.7846913603,\n              5628022.5903055705\n            ],\n            [\n              3401137.3966407343,\n              5622790.962612764\n            ],\n            [\n              3386058.8756050379,\n              5619783.1269912859\n            ],\n            [\n              3384825.5188038861,\n              5613016.2159250593\n            ],\n            [\n              3378474.6462449804,\n              5610514.4526037313\n            ],\n            [\n              3372459.6357410736,\n              5612603.93168246\n            ],\n            [\n              3369368.6827267488,\n              5608763.7309827879\n            ],\n            [\n              3362065.5903108316,\n              5607751.5255306438\n            ],\n            [\n              3350049.3700410733,\n              5600448.5200936021\n            ],\n            [\n              3350093.4458034495,\n              5595426.0479528448\n            ],\n            [\n              3341011.5040215962,\n              5595025.0052518947\n            ],\n            [\n              3343107.5339642386,\n              5582155.4682631167\n            ],\n            [\n              3337596.2249325705,\n              5580760.0248874584\n            ],\n            [\n              3330605.1985471123,\n              5582020.31771647\n            ],\n            [\n              3328285.0183701818,\n              5585040.4950274136\n            ],\n            [\n              3319084.6380793764,\n              5581296.9993137084\n            ],\n            [\n              3314942.5281778327,\n              5586140.8450016081\n            ],\n            [\n              3316745.7783426233,\n              5580422.3833581302\n            ],\n            [\n              3312983.7700960236,\n              5579512.6769915028\n            ],\n            [\n              3311015.0402032044,\n              5597166.2959220903\n            ],\n            [\n              3301286.5663866308,\n              5598571.7062137835\n            ],\n            [\n              3300452.0495598861,\n              5612535.5799334673\n            ],\n            [\n              3286562.4368676911,\n              5631605.5381454192\n            ],\n            [\n              3293515.8540427848,\n              5645328.8087019995\n            ],\n            [\n              3289593.1201755358,\n              5652859.9777060952\n            ],\n            [\n              3280490.6418140358,\n              5652305.5355140213\n            ],\n            [\n              3283946.8383823703,\n              5659327.0333167221\n            ],\n            [\n              3300441.7297592955,\n              5672312.375694558\n            ],\n            [\n              3295054.930980491,\n              5681365.4637364801\n            ],\n            [\n              3305673.7855360452,\n              5698330.3926210487\n            ],\n            [\n              3305185.7435152312,\n              5711900.5580570772\n            ],\n            [\n              3298151.4557415806,\n              5721776.7622817336\n            ],\n            [\n              3299248.1908475813,\n              5727184.30292344\n            ],\n            [\n              3288593.3455453222,\n              5737357.14206855\n            ],\n            [\n              3288166.3396910564,\n              5745714.5100391265\n            ],\n            [\n              3302277.8919111043,\n              5755163.8046153989\n            ],\n            [\n              3319581.1853357637,\n              5746810.0729826046\n            ],\n            [\n              3349540.1338124895,\n              5760629.0532384655\n            ],\n            [\n              3340479.231191908,\n              5769175.6678363914\n            ],\n            [\n              3365215.7405231372,\n              5791134.4245591592\n            ],\n            [\n              3384012.9715766446,\n              5794350.67907946\n            ],\n            [\n              3392025.9757624478,\n              5798862.5502476348\n            ],\n            [\n              3404900.1974876495,\n              5809887.5124256918\n            ],\n            [\n              3405503.5945286378,\n              5816570.4759445861\n            ],\n            [\n              3420259.1575914957,\n              5803751.5274206437\n            ],\n            [\n              3425492.757720896,\n              5805288.4202747019\n            ],\n            [\n              3430006.2427960923,\n              5797970.8222356346\n            ],\n            [\n              3424868.898425628,\n              5786447.4626845969\n            ],\n            [\n              3432793.2771179159,\n              5782578.7181442473\n            ],\n            [\n              3430848.1481474047,\n              5776941.4217684427\n            ],\n            [\n              3424043.0116273453,\n              5773317.3629900236\n            ],\n            [\n              3429320.229406042,\n              5767538.2512281965\n            ],\n            [\n              3443866.3179077418,\n              5772309.6550858961\n            ],\n            [\n              3449806.276862137,\n              5777869.5358370543\n            ],\n            [\n              3458464.1366839507,\n              5775302.8801533738\n            ],\n            [\n              3465646.1563843205,\n              5783918.4884388642\n            ],\n            [\n              3463355.0737599577,\n              5785668.4196412982\n            ],\n            [\n              3461024.8513124967,\n              5803711.8401982216\n            ],\n            [\n              3454665.8384169149,\n              5807279.4963338831\n            ],\n            [\n              3452513.9193353336,\n              5813170.6235983437\n            ],\n            [\n              3462486.1358933239,\n              5813475.3430145392\n            ],\n            [\n              3465828.1105889371,\n              5819223.8873425638\n            ],\n            [\n              3475033.4589592386,\n              5821106.0705908509\n            ],\n            [\n              3479867.1735936282,\n              5816213.7362615485\n            ],\n            [\n              3480044.9075819287,\n              5808105.8626193544\n            ],\n            [\n              3488204.8196057775,\n              5806021.1578105967\n            ],\n            [\n              3497362.7964672055,\n              5808264.4660474733\n            ],\n            [\n              3505512.7507341616,\n              5818113.1914334437\n            ],\n            [\n              3508734.1906899149,\n              5808202.5161512913\n            ],\n            [\n              3501228.9466671981,\n              5800697.4286702024\n            ],\n            [\n              3498856.9730779752,\n              5792231.21404994\n            ],\n            [\n              3504814.6166028902,\n              5789111.4519898761\n            ],\n            [\n              3499183.6395015051,\n              5783721.9442453487\n            ],\n            [\n              3499759.3356492291,\n              5777670.6405627411\n            ],\n            [\n              3509276.9756461484,\n              5777434.9458997874\n            ],\n            [\n              3513012.1422050977,\n              5771107.5125731593\n            ],\n            [\n              3511749.4542092225,\n              5761204.0843012407\n            ],\n            [\n              3519653.3203679961,\n              5759759.9832918076\n            ],\n            [\n              3517560.304288995,\n              5754143.8004587572\n            ],\n            [\n              3523025.290853254,\n              5752320.4393789358\n            ],\n            [\n              3522181.9700715416,\n              5746808.8859115178\n            ],\n            [\n              3531347.6256220187,\n              5748185.8522464707\n            ],\n            [\n              3530138.6548991445,\n              5737303.7716195555\n            ],\n            [\n              3525818.084766577,\n              5723573.9568773992\n            ],\n            [\n              3530455.4859661362,\n              5723798.1047803881\n            ],\n            [\n              3528924.4766209414,\n              5721351.5218874197\n            ],\n            [\n              3523070.5236526416,\n              5719044.8562405137\n            ],\n            [\n              3524603.0147794806,\n              5717491.2277388889\n            ],\n            [\n              3520561.9854983916,\n              5709122.9644377604\n            ],\n            [\n              3515576.2447461095,\n              5705707.6914275726\n            ],\n            [\n              3514925.1214373852,\n              5702549.6671367111\n            ],\n            [\n              3510983.0960355494,\n              5700337.8754208274\n            ],\n            [\n              3507554.9044111446,\n              5700780.0367017193\n            ],\n            [\n              3505875.6567809652,\n              5705238.8299312703\n            ],\n            [\n              3501068.9273003335,\n              5708144.4145278726\n            ],\n            [\n              3493481.3893631604,\n              5705006.7893563118\n            ],\n            [\n              3495486.2723003584,\n              5695033.5096952291\n            ],\n            [\n              3487092.8830240588,\n              5693984.3327005329\n            ],\n            [\n              3478098.1711568064,\n              5691979.9560178882\n            ],\n            [\n              3470564.1349909166,\n              5682285.2168887602\n            ],\n            [\n              3472321.6289579044,\n              5678561.7930466589\n            ],\n            [\n              3480242.9781700782,\n              5681704.1365179941\n            ],\n            [\n              3482531.6234846874,\n              5670756.3682026779\n            ],\n            [\n              3478703.4031630475,\n              5666065.6576269772\n            ],\n            [\n              3479299.5390543016,\n              5663197.6244847337\n            ],\n            [\n              3476066.6090996503,\n              5661389.358788928\n            ],\n            [\n              3466708.3078764328,\n              5661993.1278259987\n            ],\n            [\n              3468070.104050932,\n              5653902.1312206704\n            ],\n            [\n              3460909.0517494865,\n              5642310.59995\n            ],\n            [\n              3455235.7066972801,\n              5636303.2577909315\n            ],\n            [\n              3450712.3612730294,\n              5638488.3772231052\n            ],\n            [\n              3443440.0761954072,\n              5632575.1928710276\n            ],\n            [\n              3439308.1902859993,\n              5627939.3903268781\n            ],\n            [\n              3441783.7754965182,\n              5623139.8062560717\n            ],\n            [\n              3438838.0181758674,\n              5616717.762588284\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"12\",\n        \"adm1_code\": \"DEU-1573\",\n        \"OBJECTID_1\": \"1516\",\n        \"diss_me\": \"1573\",\n        \"adm1_cod_1\": \"DEU-1573\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Baden-WÃ¼rttemberg\",\n        \"name_alt\": null,\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.BW\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"15\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"BW\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"17\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM01\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345481\",\n        \"woe_label\": \"Baden-Wurttemberg, DE, Germany\",\n        \"woe_name\": \"Baden-WÃ¼rttemberg\",\n        \"latitude\": \"48.59\",\n        \"longitude\": \"9.00328\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2953481\",\n        \"gn_name\": \"Baden-Wuerttemberg\",\n        \"gns_id\": \"-1743106\",\n        \"gns_name\": \"Baden-Wurttemberg\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.01\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM01\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3441413.1035388974,\n              5424738.8449200103\n            ],\n            [\n              3462173.0401205476,\n              5462228.3351949146\n            ],\n            [\n              3463300.0906483554,\n              5478415.3615263375\n            ],\n            [\n              3457830.8811206338,\n              5493673.0699443156\n            ],\n            [\n              3463711.7080498426,\n              5492955.3966393284\n            ],\n            [\n              3468596.5891445591,\n              5487801.5832253546\n            ],\n            [\n              3472314.7994839814,\n              5489979.6376655754\n            ],\n            [\n              3471193.28598797,\n              5497091.6041746819\n            ],\n            [\n              3476270.1188411755,\n              5498354.3952498306\n            ],\n            [\n              3479600.3046743623,\n              5489358.4316641716\n            ],\n            [\n              3492069.8971853391,\n              5485360.722180808\n            ],\n            [\n              3489052.2447243668,\n              5482837.3566248845\n            ],\n            [\n              3486398.2881462742,\n              5474042.1804142566\n            ],\n            [\n              3488841.5516411392,\n              5473151.6657701498\n            ],\n            [\n              3496055.1333653242,\n              5479681.4650302604\n            ],\n            [\n              3496946.0138544249,\n              5485085.7153924536\n            ],\n            [\n              3502541.2115189768,\n              5484821.1008404233\n            ],\n            [\n              3509069.49997,\n              5486471.6288755341\n            ],\n            [\n              3505792.5326571916,\n              5492886.3640927905\n            ],\n            [\n              3508004.7275028112,\n              5493032.8392732944\n            ],\n            [\n              3518325.600151998,\n              5493330.7812480545\n            ],\n            [\n              3520685.2364013265,\n              5498793.0887854239\n            ],\n            [\n              3527193.7326927111,\n              5501474.0234873584\n            ],\n            [\n              3529207.3879846265,\n              5500329.3255963055\n            ],\n            [\n              3530810.1855651978,\n              5507912.8665117286\n            ],\n            [\n              3522607.3664702717,\n              5510533.3209668808\n            ],\n            [\n              3522498.7099780627,\n              5514265.6125144539\n            ],\n            [\n              3525335.9484673571,\n              5516510.933784782\n            ],\n            [\n              3535345.8245763546,\n              5517624.6485599363\n            ],\n            [\n              3543354.8998105251,\n              5514967.3727186071\n            ],\n            [\n              3546539.9080542442,\n              5516416.3428387139\n            ],\n            [\n              3545480.2621061597,\n              5506998.8894933118\n            ],\n            [\n              3548880.8715447127,\n              5506083.0556571763\n            ],\n            [\n              3551176.5391815607,\n              5509357.2814978566\n            ],\n            [\n              3552489.5273762518,\n              5505757.5850912258\n            ],\n            [\n              3557139.2306370987,\n              5509661.1895087473\n            ],\n            [\n              3560005.6028370573,\n              5506214.9098258298\n            ],\n            [\n              3560208.8010403323,\n              5502015.7024308359\n            ],\n            [\n              3563761.6499401266,\n              5497211.0637213998\n            ],\n            [\n              3560708.0498845158,\n              5490710.2006405825\n            ],\n            [\n              3561886.1846542899,\n              5489700.4107388947\n            ],\n            [\n              3566013.3375535863,\n              5493864.1031941669\n            ],\n            [\n              3567840.6018891246,\n              5483063.8994000871\n            ],\n            [\n              3573881.9593119058,\n              5482987.1144731594\n            ],\n            [\n              3577176.3558150646,\n              5486245.6809542198\n            ],\n            [\n              3578523.3819369273,\n              5490167.6813984727\n            ],\n            [\n              3581644.3427704326,\n              5486557.8843275979\n            ],\n            [\n              3580825.872080544,\n              5478633.7955291895\n            ],\n            [\n              3582846.7077056891,\n              5477603.5611078702\n            ],\n            [\n              3585018.2661472317,\n              5472469.5360561004\n            ],\n            [\n              3581463.7540525994,\n              5470771.6749604018\n            ],\n            [\n              3584382.777422816,\n              5460337.6364304721\n            ],\n            [\n              3582413.875438883,\n              5459974.4160899296\n            ],\n            [\n              3583564.5297398535,\n              5452545.6756128054\n            ],\n            [\n              3592245.8891499159,\n              5443944.4963075556\n            ],\n            [\n              3593147.1400163225,\n              5435435.6389526604\n            ],\n            [\n              3599011.9484724626,\n              5433669.2124226196\n            ],\n            [\n              3606859.6900644084,\n              5423359.0073309727\n            ],\n            [\n              3607096.9641639437,\n              5411585.8563470664\n            ],\n            [\n              3605288.9192014784,\n              5404018.894093167\n            ],\n            [\n              3610040.9729735483,\n              5396732.7561689578\n            ],\n            [\n              3605494.6288470197,\n              5393679.6094944002\n            ],\n            [\n              3604817.5383069692,\n              5396914.4062103806\n            ],\n            [\n              3601043.7237907918,\n              5392675.2968838485\n            ],\n            [\n              3595531.1762953508,\n              5396915.3128908044\n            ],\n            [\n              3593537.9326087711,\n              5394395.9917849256\n            ],\n            [\n              3594990.0970565821,\n              5390440.2955783168\n            ],\n            [\n              3598254.0374123072,\n              5388042.2132638032\n            ],\n            [\n              3596820.2459671348,\n              5386336.2469680198\n            ],\n            [\n              3597104.90080478,\n              5377768.9604256051\n            ],\n            [\n              3592397.2803958142,\n              5374804.8767391955\n            ],\n            [\n              3585285.3429935728,\n              5370319.6556346128\n            ],\n            [\n              3583771.9889397854,\n              5372636.0281001786\n            ],\n            [\n              3578955.5050633829,\n              5370940.3940610792\n            ],\n            [\n              3572624.432680374,\n              5360747.4124220517\n            ],\n            [\n              3578187.6194506902,\n              5352316.3667016691\n            ],\n            [\n              3582536.9707668643,\n              5334936.9094386967\n            ],\n            [\n              3584603.1174242902,\n              5330438.8159838542\n            ],\n            [\n              3584271.0151908011,\n              5322385.9982684879\n            ],\n            [\n              3581170.5874427473,\n              5314040.8154020924\n            ],\n            [\n              3582885.1004398358,\n              5311565.5902857054\n            ],\n            [\n              3582134.3343479666,\n              5304897.8270773264\n            ],\n            [\n              3584580.1453866977,\n              5298103.7145693144\n            ],\n            [\n              3580930.5669586663,\n              5294773.3959587673\n            ],\n            [\n              3583494.2047532503,\n              5292617.613166254\n            ],\n            [\n              3584928.4473972623,\n              5283809.5219843267\n            ],\n            [\n              3582086.3286339194,\n              5282857.9677951159\n            ],\n            [\n              3580805.8182427208,\n              5279501.6412465433\n            ],\n            [\n              3579419.406908934,\n              5282654.3130722083\n            ],\n            [\n              3571596.2949043298,\n              5280467.0692903223\n            ],\n            [\n              3564921.0598903387,\n              5282095.2396906596\n            ],\n            [\n              3553760.0831742487,\n              5274202.1924148183\n            ],\n            [\n              3551119.3500004988,\n              5274925.3375281552\n            ],\n            [\n              3545727.4155536136,\n              5271763.9444706095\n            ],\n            [\n              3538108.586976225,\n              5278216.6571631031\n            ],\n            [\n              3524201.4871307504,\n              5282560.200732233\n            ],\n            [\n              3505381.2646053382,\n              5297500.5593641382\n            ],\n            [\n              3513744.3973849737,\n              5281261.0549703501\n            ],\n            [\n              3501245.2564575989,\n              5282187.1291832635\n            ],\n            [\n              3492954.4217438856,\n              5279178.0382866459\n            ],\n            [\n              3470156.9156570975,\n              5295126.922488031\n            ],\n            [\n              3459797.2292908044,\n              5291776.8305603499\n            ],\n            [\n              3454288.3872752469,\n              5280872.8088062005\n            ],\n            [\n              3467574.511019954,\n              5280502.1190058449\n            ],\n            [\n              3458547.4047226133,\n              5271815.2668946693\n            ],\n            [\n              3438287.8564351345,\n              5275499.0383446272\n            ],\n            [\n              3431325.8307742607,\n              5270193.2645433815\n            ],\n            [\n              3418142.7353061661,\n              5269604.711872451\n            ],\n            [\n              3411241.1816176744,\n              5273572.6100377999\n            ],\n            [\n              3400901.6777409539,\n              5268058.8002021173\n            ],\n            [\n              3389002.1904692957,\n              5282303.4787578518\n            ],\n            [\n              3389551.2422212488,\n              5294829.8907658765\n            ],\n            [\n              3396957.1488953112,\n              5319103.1428725459\n            ],\n            [\n              3393692.7435733448,\n              5329429.7595380237\n            ],\n            [\n              3407518.0857715937,\n              5358145.5869738301\n            ],\n            [\n              3406601.0067125871,\n              5363861.6629127022\n            ],\n            [\n              3412357.6879469999,\n              5376321.143464623\n            ],\n            [\n              3412286.4552563648,\n              5386948.5981052546\n            ],\n            [\n              3424287.4372463357,\n              5402595.5740310866\n            ],\n            [\n              3434119.715337595,\n              5409591.547999708\n            ],\n            [\n              3441413.1035388974,\n              5424738.8449200103\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"13\",\n        \"adm1_code\": \"DEU-1574\",\n        \"OBJECTID_1\": \"1517\",\n        \"diss_me\": \"1574\",\n        \"adm1_cod_1\": \"DEU-1574\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"Hessen\",\n        \"name_alt\": \"Hesse\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.HE\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"19\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"HE\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"6\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM05\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345485\",\n        \"woe_label\": \"Hesse, DE, Germany\",\n        \"woe_name\": \"Hessen\",\n        \"latitude\": \"50.6098\",\n        \"longitude\": \"8.958729999999999\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2905330\",\n        \"gn_name\": \"Land Hessen\",\n        \"gns_id\": \"-1791414\",\n        \"gns_name\": \"Hessen\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.05\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM05\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3574817.4056062475,\n              5598257.4420703379\n            ],\n            [\n              3571078.9444448808,\n              5590634.6929859295\n            ],\n            [\n              3561061.3854291611,\n              5585008.1051580943\n            ],\n            [\n              3554503.9289892185,\n              5585281.3163722064\n            ],\n            [\n              3553322.554148009,\n              5574531.7938179336\n            ],\n            [\n              3548486.4890143084,\n              5571588.4039183576\n            ],\n            [\n              3547168.3691143082,\n              5566552.8579348298\n            ],\n            [\n              3536454.1115450612,\n              5566675.5268396242\n            ],\n            [\n              3535646.7908835602,\n              5560063.0808881437\n            ],\n            [\n              3537768.1315709203,\n              5559166.6873750146\n            ],\n            [\n              3536241.2263133698,\n              5552425.6098567126\n            ],\n            [\n              3529102.3323403024,\n              5550628.9499717057\n            ],\n            [\n              3523525.7989939875,\n              5555823.0760990549\n            ],\n            [\n              3516350.8844319284,\n              5556299.1656100359\n            ],\n            [\n              3510910.1904314789,\n              5552779.3399014063\n            ],\n            [\n              3507714.830290556,\n              5554233.6068744743\n            ],\n            [\n              3500735.6345797917,\n              5551049.7819365254\n            ],\n            [\n              3498323.6014661267,\n              5546150.3840967752\n            ],\n            [\n              3501924.5455787638,\n              5545078.5930615086\n            ],\n            [\n              3501918.8327689632,\n              5529980.5791802146\n            ],\n            [\n              3505048.3221994299,\n              5521439.4779663766\n            ],\n            [\n              3510146.6536235306,\n              5516639.2130606221\n            ],\n            [\n              3509617.7330651209,\n              5506477.500841843\n            ],\n            [\n              3508038.9263903359,\n              5500227.9951685322\n            ],\n            [\n              3505250.4010145608,\n              5497006.3185954299\n            ],\n            [\n              3508004.7275028112,\n              5493032.8392732944\n            ],\n            [\n              3505792.5326571916,\n              5492886.3640927905\n            ],\n            [\n              3509069.49997,\n              5486471.6288755341\n            ],\n            [\n              3502541.2115189768,\n              5484821.1008404233\n            ],\n            [\n              3496946.0138544249,\n              5485085.7153924536\n            ],\n            [\n              3496055.1333653242,\n              5479681.4650302604\n            ],\n            [\n              3488841.5516411392,\n              5473151.6657701498\n            ],\n            [\n              3486398.2881462742,\n              5474042.1804142566\n            ],\n            [\n              3489052.2447243668,\n              5482837.3566248845\n            ],\n            [\n              3492069.8971853391,\n              5485360.722180808\n            ],\n            [\n              3479600.3046743623,\n              5489358.4316641716\n            ],\n            [\n              3476270.1188411755,\n              5498354.3952498306\n            ],\n            [\n              3471193.28598797,\n              5497091.6041746819\n            ],\n            [\n              3472314.7994839814,\n              5489979.6376655754\n            ],\n            [\n              3468596.5891445591,\n              5487801.5832253546\n            ],\n            [\n              3463711.7080498426,\n              5492955.3966393284\n            ],\n            [\n              3457830.8811206338,\n              5493673.0699443156\n            ],\n            [\n              3453841.9804025455,\n              5503159.6692345878\n            ],\n            [\n              3458495.5004734448,\n              5514559.1553209331\n            ],\n            [\n              3452586.3951217886,\n              5528367.2193213543\n            ],\n            [\n              3452319.9802185413,\n              5536002.3603432896\n            ],\n            [\n              3444709.495428592,\n              5544811.9771885592\n            ],\n            [\n              3440828.5246273172,\n              5545698.4037055941\n            ],\n            [\n              3422434.0216260618,\n              5537934.5923802424\n            ],\n            [\n              3412023.655965697,\n              5546950.898131174\n            ],\n            [\n              3418083.6548039587,\n              5553784.5111388061\n            ],\n            [\n              3422876.6023717704,\n              5552937.0920662321\n            ],\n            [\n              3423056.5161700593,\n              5563089.1127727879\n            ],\n            [\n              3437471.8600296136,\n              5571557.030202195\n            ],\n            [\n              3432385.6108222404,\n              5582006.6984252753\n            ],\n            [\n              3427486.3471034807,\n              5584796.3907665983\n            ],\n            [\n              3429406.6760302559,\n              5598670.4881470185\n            ],\n            [\n              3436698.9808041384,\n              5599221.561436912\n            ],\n            [\n              3440788.8477046415,\n              5605767.4036669126\n            ],\n            [\n              3438838.0181758674,\n              5616717.762588284\n            ],\n            [\n              3441783.7754965182,\n              5623139.8062560717\n            ],\n            [\n              3439308.1902859993,\n              5627939.3903268781\n            ],\n            [\n              3443440.0761954072,\n              5632575.1928710276\n            ],\n            [\n              3450712.3612730294,\n              5638488.3772231052\n            ],\n            [\n              3455235.7066972801,\n              5636303.2577909315\n            ],\n            [\n              3460909.0517494865,\n              5642310.59995\n            ],\n            [\n              3468070.104050932,\n              5653902.1312206704\n            ],\n            [\n              3466708.3078764328,\n              5661993.1278259987\n            ],\n            [\n              3476066.6090996503,\n              5661389.358788928\n            ],\n            [\n              3479299.5390543016,\n              5663197.6244847337\n            ],\n            [\n              3478703.4031630475,\n              5666065.6576269772\n            ],\n            [\n              3482531.6234846874,\n              5670756.3682026779\n            ],\n            [\n              3480242.9781700782,\n              5681704.1365179941\n            ],\n            [\n              3472321.6289579044,\n              5678561.7930466589\n            ],\n            [\n              3470564.1349909166,\n              5682285.2168887602\n            ],\n            [\n              3478098.1711568064,\n              5691979.9560178882\n            ],\n            [\n              3487092.8830240588,\n              5693984.3327005329\n            ],\n            [\n              3495486.2723003584,\n              5695033.5096952291\n            ],\n            [\n              3493481.3893631604,\n              5705006.7893563118\n            ],\n            [\n              3501068.9273003335,\n              5708144.4145278726\n            ],\n            [\n              3505875.6567809652,\n              5705238.8299312703\n            ],\n            [\n              3507554.9044111446,\n              5700780.0367017193\n            ],\n            [\n              3510983.0960355494,\n              5700337.8754208274\n            ],\n            [\n              3514925.1214373852,\n              5702549.6671367111\n            ],\n            [\n              3515576.2447461095,\n              5705707.6914275726\n            ],\n            [\n              3520561.9854983916,\n              5709122.9644377604\n            ],\n            [\n              3524603.0147794806,\n              5717491.2277388889\n            ],\n            [\n              3523070.5236526416,\n              5719044.8562405137\n            ],\n            [\n              3528924.4766209414,\n              5721351.5218874197\n            ],\n            [\n              3530455.4859661362,\n              5723798.1047803881\n            ],\n            [\n              3534226.8905062792,\n              5721936.5230261441\n            ],\n            [\n              3538023.0338339861,\n              5722871.9953770936\n            ],\n            [\n              3543159.0281349747,\n              5721711.6281607887\n            ],\n            [\n              3547558.9102820596,\n              5715352.1442766832\n            ],\n            [\n              3544642.9489397793,\n              5715322.7546808505\n            ],\n            [\n              3541427.0530289891,\n              5708583.377967434\n            ],\n            [\n              3544378.4200985883,\n              5703761.8090163535\n            ],\n            [\n              3544011.9748935108,\n              5696296.3759464175\n            ],\n            [\n              3540504.4158721655,\n              5696031.611479966\n            ],\n            [\n              3539668.6032787417,\n              5689741.4874358121\n            ],\n            [\n              3547588.8435190055,\n              5686762.122029556\n            ],\n            [\n              3549624.2787566381,\n              5684174.2859604955\n            ],\n            [\n              3553132.3127446934,\n              5686190.0345269963\n            ],\n            [\n              3549697.4774175971,\n              5692215.0098583559\n            ],\n            [\n              3557474.3696721108,\n              5696424.5482411729\n            ],\n            [\n              3559629.6316318894,\n              5693246.9378643679\n            ],\n            [\n              3560024.2843798888,\n              5697322.0626973845\n            ],\n            [\n              3562896.1835305644,\n              5698276.577285951\n            ],\n            [\n              3566077.5702712322,\n              5694404.3259839863\n            ],\n            [\n              3564312.7318813005,\n              5691987.1708498131\n            ],\n            [\n              3566034.6785900695,\n              5685742.3244812824\n            ],\n            [\n              3573198.2449193862,\n              5682792.5178340524\n            ],\n            [\n              3575528.1127700228,\n              5676892.8194844155\n            ],\n            [\n              3586006.8405960761,\n              5672728.1137020076\n            ],\n            [\n              3583764.4426440145,\n              5665075.652521369\n            ],\n            [\n              3582117.5519434675,\n              5668271.7900177678\n            ],\n            [\n              3578798.7772993003,\n              5667248.2472233446\n            ],\n            [\n              3581851.2486287467,\n              5665001.7837908594\n            ],\n            [\n              3580088.3767739702,\n              5658270.1789641948\n            ],\n            [\n              3583664.5405275868,\n              5657171.22150579\n            ],\n            [\n              3583383.0604236061,\n              5651698.8799884953\n            ],\n            [\n              3573767.2356044655,\n              5652811.9528761469\n            ],\n            [\n              3571869.1755224951,\n              5650014.132858675\n            ],\n            [\n              3573185.653422052,\n              5645450.4846842652\n            ],\n            [\n              3567177.6235405561,\n              5645472.6461312221\n            ],\n            [\n              3568515.6242985181,\n              5641517.5843244502\n            ],\n            [\n              3570742.7824758831,\n              5643197.4355528848\n            ],\n            [\n              3574302.524281817,\n              5638981.32835175\n            ],\n            [\n              3571762.6630286835,\n              5633277.0861994652\n            ],\n            [\n              3566901.1734591089,\n              5631378.4425946446\n            ],\n            [\n              3566734.0008735228,\n              5627081.9127885103\n            ],\n            [\n              3564520.4169722269,\n              5617718.1240404369\n            ],\n            [\n              3562073.2358358465,\n              5612230.2116798423\n            ],\n            [\n              3566738.0713194893,\n              5610456.5903575188\n            ],\n            [\n              3567228.3343895781,\n              5614423.7075280305\n            ],\n            [\n              3570507.0136910323,\n              5615967.2634153562\n            ],\n            [\n              3574366.9579191515,\n              5615279.0739612924\n            ],\n            [\n              3576134.9967648848,\n              5610012.6024658671\n            ],\n            [\n              3574029.2307750289,\n              5608145.7005352741\n            ],\n            [\n              3574817.4056062475,\n              5598257.4420703379\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"15\",\n        \"adm1_code\": \"DEU-1576\",\n        \"OBJECTID_1\": \"6321\",\n        \"diss_me\": \"1576\",\n        \"adm1_cod_1\": \"DEU-1576\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"4\",\n        \"name\": \"Niedersachsen\",\n        \"name_alt\": \"Lower Saxony\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.NI\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"4\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"NI\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"13\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM06\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345486\",\n        \"woe_label\": \"Lower Saxony, DE, Germany\",\n        \"woe_name\": \"Niedersachsen\",\n        \"latitude\": \"52.775\",\n        \"longitude\": \"8.861840000000001\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2862926\",\n        \"gn_name\": \"Land Niedersachsen\",\n        \"gns_id\": \"-1833951\",\n        \"gns_name\": \"Niedersachsen\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.06\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM06\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3550632.9068574295,\n              5935231.2751757316\n            ],\n            [\n              3556965.7078730096,\n              5922524.892838276\n            ],\n            [\n              3565509.5510616428,\n              5920653.881467809\n            ],\n            [\n              3571948.8982978156,\n              5924735.9639584571\n            ],\n            [\n              3578903.5037427521,\n              5919670.0220713178\n            ],\n            [\n              3588249.9672536696,\n              5922981.0870051431\n            ],\n            [\n              3601710.25338207,\n              5916543.2227652604\n            ],\n            [\n              3606560.2346579311,\n              5916586.2707823943\n            ],\n            [\n              3639785.0696396269,\n              5892100.1719632307\n            ],\n            [\n              3643302.4959958429,\n              5895374.819350563\n            ],\n            [\n              3652231.3320433423,\n              5889511.3574547973\n            ],\n            [\n              3661924.2617668891,\n              5885747.2731848815\n            ],\n            [\n              3673094.9477649452,\n              5881900.7282523569\n            ],\n            [\n              3671922.8545249584,\n              5878200.7057062704\n            ],\n            [\n              3668261.3414150965,\n              5877081.257549637\n            ],\n            [\n              3668159.9163241819,\n              5870732.0661629066\n            ],\n            [\n              3662276.0322155575,\n              5866329.1451455932\n            ],\n            [\n              3651333.2684875731,\n              5862791.5747473724\n            ],\n            [\n              3648934.7473273841,\n              5864932.535072092\n            ],\n            [\n              3635509.5308777369,\n              5866108.0874277316\n            ],\n            [\n              3632019.5397876874,\n              5860810.2693054294\n            ],\n            [\n              3618718.1755545707,\n              5857485.6109101465\n            ],\n            [\n              3618514.5615372388,\n              5851704.8690217081\n            ],\n            [\n              3621666.099287462,\n              5844655.1274119448\n            ],\n            [\n              3624130.2654388198,\n              5843359.7207674412\n            ],\n            [\n              3630000.1103232088,\n              5833404.7902165819\n            ],\n            [\n              3633938.0988071673,\n              5832809.371821166\n            ],\n            [\n              3632514.9164062119,\n              5825233.8930791495\n            ],\n            [\n              3635920.4080108143,\n              5820057.3019131161\n            ],\n            [\n              3631772.1436179769,\n              5815934.1879419796\n            ],\n            [\n              3641160.67654408,\n              5806181.3832803816\n            ],\n            [\n              3636231.0192434615,\n              5802737.3780365922\n            ],\n            [\n              3637457.8965149773,\n              5796638.6178118531\n            ],\n            [\n              3642306.9390903679,\n              5789843.2179832282\n            ],\n            [\n              3638079.8541451683,\n              5785463.3934184005\n            ],\n            [\n              3639545.4940197729,\n              5779363.0596436961\n            ],\n            [\n              3633454.749544749,\n              5775329.8780293567\n            ],\n            [\n              3634968.6410203772,\n              5771763.776092371\n            ],\n            [\n              3626913.4232676532,\n              5769958.5594496056\n            ],\n            [\n              3613361.9478737903,\n              5768780.5365629746\n            ],\n            [\n              3607797.4707193407,\n              5764671.3332481934\n            ],\n            [\n              3613030.801248,\n              5759432.3883808982\n            ],\n            [\n              3610948.6257142145,\n              5755584.0213080486\n            ],\n            [\n              3612899.5315223499,\n              5751066.7033877522\n            ],\n            [\n              3608880.3975983351,\n              5746675.8150769975\n            ],\n            [\n              3609394.947188708,\n              5739233.3662485098\n            ],\n            [\n              3615012.1854641521,\n              5731490.6919269329\n            ],\n            [\n              3617510.6850254778,\n              5723772.3194554569\n            ],\n            [\n              3611631.7745252792,\n              5716427.2014618823\n            ],\n            [\n              3605003.1711668326,\n              5714474.0370600866\n            ],\n            [\n              3598512.0890342994,\n              5718303.0865497692\n            ],\n            [\n              3595277.3502693637,\n              5717559.7764455471\n            ],\n            [\n              3594658.1928674169,\n              5712729.2957265247\n            ],\n            [\n              3586116.3035516692,\n              5704751.2523524342\n            ],\n            [\n              3582986.9514478082,\n              5705509.9902624423\n            ],\n            [\n              3579943.6412702766,\n              5700165.6181104556\n            ],\n            [\n              3572713.6175525445,\n              5700091.8007927611\n            ],\n            [\n              3566077.5702712322,\n              5694404.3259839863\n            ],\n            [\n              3562896.1835305644,\n              5698276.577285951\n            ],\n            [\n              3560024.2843798888,\n              5697322.0626973845\n            ],\n            [\n              3559629.6316318894,\n              5693246.9378643679\n            ],\n            [\n              3557474.3696721108,\n              5696424.5482411729\n            ],\n            [\n              3549697.4774175971,\n              5692215.0098583559\n            ],\n            [\n              3553132.3127446934,\n              5686190.0345269963\n            ],\n            [\n              3549624.2787566381,\n              5684174.2859604955\n            ],\n            [\n              3547588.8435190055,\n              5686762.122029556\n            ],\n            [\n              3539668.6032787417,\n              5689741.4874358121\n            ],\n            [\n              3540504.4158721655,\n              5696031.611479966\n            ],\n            [\n              3544011.9748935108,\n              5696296.3759464175\n            ],\n            [\n              3544378.4200985883,\n              5703761.8090163535\n            ],\n            [\n              3541427.0530289891,\n              5708583.377967434\n            ],\n            [\n              3544642.9489397793,\n              5715322.7546808505\n            ],\n            [\n              3547558.9102820596,\n              5715352.1442766832\n            ],\n            [\n              3543159.0281349747,\n              5721711.6281607887\n            ],\n            [\n              3538023.0338339861,\n              5722871.9953770936\n            ],\n            [\n              3534226.8905062792,\n              5721936.5230261441\n            ],\n            [\n              3530455.4859661362,\n              5723798.1047803881\n            ],\n            [\n              3525818.084766577,\n              5723573.9568773992\n            ],\n            [\n              3530138.6548991445,\n              5737303.7716195555\n            ],\n            [\n              3531347.6256220187,\n              5748185.8522464707\n            ],\n            [\n              3522181.9700715416,\n              5746808.8859115178\n            ],\n            [\n              3523025.290853254,\n              5752320.4393789358\n            ],\n            [\n              3517560.304288995,\n              5754143.8004587572\n            ],\n            [\n              3519653.3203679961,\n              5759759.9832918076\n            ],\n            [\n              3511749.4542092225,\n              5761204.0843012407\n            ],\n            [\n              3513012.1422050977,\n              5771107.5125731593\n            ],\n            [\n              3509276.9756461484,\n              5777434.9458997874\n            ],\n            [\n              3499759.3356492291,\n              5777670.6405627411\n            ],\n            [\n              3499183.6395015051,\n              5783721.9442453487\n            ],\n            [\n              3504814.6166028902,\n              5789111.4519898761\n            ],\n            [\n              3498856.9730779752,\n              5792231.21404994\n            ],\n            [\n              3501228.9466671981,\n              5800697.4286702024\n            ],\n            [\n              3508734.1906899149,\n              5808202.5161512913\n            ],\n            [\n              3505512.7507341616,\n              5818113.1914334437\n            ],\n            [\n              3497362.7964672055,\n              5808264.4660474733\n            ],\n            [\n              3488204.8196057775,\n              5806021.1578105967\n            ],\n            [\n              3480044.9075819287,\n              5808105.8626193544\n            ],\n            [\n              3479867.1735936282,\n              5816213.7362615485\n            ],\n            [\n              3475033.4589592386,\n              5821106.0705908509\n            ],\n            [\n              3465828.1105889371,\n              5819223.8873425638\n            ],\n            [\n              3462486.1358933239,\n              5813475.3430145392\n            ],\n            [\n              3452513.9193353336,\n              5813170.6235983437\n            ],\n            [\n              3454665.8384169149,\n              5807279.4963338831\n            ],\n            [\n              3461024.8513124967,\n              5803711.8401982216\n            ],\n            [\n              3463355.0737599577,\n              5785668.4196412982\n            ],\n            [\n              3465646.1563843205,\n              5783918.4884388642\n            ],\n            [\n              3458464.1366839507,\n              5775302.8801533738\n            ],\n            [\n              3449806.276862137,\n              5777869.5358370543\n            ],\n            [\n              3443866.3179077418,\n              5772309.6550858961\n            ],\n            [\n              3429320.229406042,\n              5767538.2512281965\n            ],\n            [\n              3424043.0116273453,\n              5773317.3629900236\n            ],\n            [\n              3430848.1481474047,\n              5776941.4217684427\n            ],\n            [\n              3432793.2771179159,\n              5782578.7181442473\n            ],\n            [\n              3424868.898425628,\n              5786447.4626845969\n            ],\n            [\n              3430006.2427960923,\n              5797970.8222356346\n            ],\n            [\n              3425492.757720896,\n              5805288.4202747019\n            ],\n            [\n              3420259.1575914957,\n              5803751.5274206437\n            ],\n            [\n              3405503.5945286378,\n              5816570.4759445861\n            ],\n            [\n              3404900.1974876495,\n              5809887.5124256918\n            ],\n            [\n              3392025.9757624478,\n              5798862.5502476348\n            ],\n            [\n              3384012.9715766446,\n              5794350.67907946\n            ],\n            [\n              3365215.7405231372,\n              5791134.4245591592\n            ],\n            [\n              3362238.7512589549,\n              5814902.0341639277\n            ],\n            [\n              3343415.361510009,\n              5818165.0608863141\n            ],\n            [\n              3349108.9968962353,\n              5836405.5838817265\n            ],\n            [\n              3367138.1978925127,\n              5836588.6911443137\n            ],\n            [\n              3377978.5938670379,\n              5871789.2388360733\n            ],\n            [\n              3379497.5438460801,\n              5902801.0457823742\n            ],\n            [\n              3386958.4166595987,\n              5912384.9993838463\n            ],\n            [\n              3368491.1976311509,\n              5917721.1951329885\n            ],\n            [\n              3373321.4256524909,\n              5941022.1998136546\n            ],\n            [\n              3382766.2664820482,\n              5949643.7128865141\n            ],\n            [\n              3430791.1632321044,\n              5954859.5760023473\n            ],\n            [\n              3444864.3727772231,\n              5935897.0754981693\n            ],\n            [\n              3437552.1160068554,\n              5930291.0044142148\n            ],\n            [\n              3447162.8743102439,\n              5920011.8600732181\n            ],\n            [\n              3454923.7023514169,\n              5930895.0261556925\n            ],\n            [\n              3450845.0647243001,\n              5941532.4429137409\n            ],\n            [\n              3470633.9099116446,\n              5931964.1095968718\n            ],\n            [\n              3473640.484591655,\n              5928668.0521080317\n            ],\n            [\n              3476062.7607371015,\n              5931567.9643862806\n            ],\n            [\n              3475199.3643792034,\n              5941403.5468862616\n            ],\n            [\n              3467778.8065959434,\n              5942795.0136931287\n            ],\n            [\n              3471923.858467692,\n              5969539.9600837333\n            ],\n            [\n              3512239.2302019894,\n              5970199.5365770916\n            ],\n            [\n              3518067.5505578616,\n              5970323.7222689753\n            ],\n            [\n              3519393.374612669,\n              5968304.8412422938\n            ],\n            [\n              3537537.0645105471,\n              5940886.6664245054\n            ],\n            [\n              3550632.9068574295,\n              5935231.2751757316\n            ]\n          ],\n          [\n            [\n              3470648.2738475171,\n              5897758.2648433764\n            ],\n            [\n              3467459.3721810151,\n              5896352.760481637\n            ],\n            [\n              3473997.6676363903,\n              5894121.7778715324\n            ],\n            [\n              3480079.7036048737,\n              5882942.5270079691\n            ],\n            [\n              3480045.6539797694,\n              5879745.4698925437\n            ],\n            [\n              3491011.2500537927,\n              5879309.938417878\n            ],\n            [\n              3494265.4796796911,\n              5876757.5917747803\n            ],\n            [\n              3498170.5207677865,\n              5879865.4094565529\n            ],\n            [\n              3498339.9930427396,\n              5889002.5856371522\n            ],\n            [\n              3494135.47721026,\n              5889523.4182940461\n            ],\n            [\n              3482994.3597778352,\n              5895366.5686806049\n            ],\n            [\n              3470648.2738475171,\n              5897758.2648433764\n            ]\n          ]\n        ]\n      }\n    },\n    {\n      \"type\": \"Feature\",\n      \"properties\": {\n        \"cat\": \"16\",\n        \"adm1_code\": \"DEU-1577\",\n        \"OBJECTID_1\": \"1519\",\n        \"diss_me\": \"1577\",\n        \"adm1_cod_1\": \"DEU-1577\",\n        \"iso_3166_2\": \"DE-\",\n        \"wikipedia\": null,\n        \"iso_a2\": \"DE\",\n        \"adm0_sr\": \"1\",\n        \"name\": \"ThÃ¼ringen\",\n        \"name_alt\": \"Thuringia\",\n        \"name_local\": null,\n        \"type\": \"Land\",\n        \"type_en\": \"State\",\n        \"code_local\": null,\n        \"code_hasc\": \"DE.TH\",\n        \"note\": null,\n        \"hasc_maybe\": null,\n        \"region\": null,\n        \"region_cod\": null,\n        \"provnum_ne\": \"20\",\n        \"gadm_level\": \"1\",\n        \"check_me\": \"20\",\n        \"scalerank\": \"3\",\n        \"datarank\": \"3\",\n        \"abbrev\": null,\n        \"postal\": \"TH\",\n        \"area_sqkm\": \"0\",\n        \"sameascity\": \"-99\",\n        \"labelrank\": \"3\",\n        \"featurecla\": \"Admin-1 scale rank\",\n        \"name_len\": \"9\",\n        \"mapcolor9\": \"5\",\n        \"mapcolor13\": \"1\",\n        \"fips\": \"GM15\",\n        \"fips_alt\": null,\n        \"woe_id\": \"2345495\",\n        \"woe_label\": \"Thuringia, DE, Germany\",\n        \"woe_name\": \"ThÃ¼ringen\",\n        \"latitude\": \"50.9052\",\n        \"longitude\": \"11.0976\",\n        \"sov_a3\": \"DEU\",\n        \"adm0_a3\": \"DEU\",\n        \"adm0_label\": \"2\",\n        \"admin\": \"Germany\",\n        \"geonunit\": \"Germany\",\n        \"gu_a3\": \"DEU\",\n        \"gn_id\": \"2822542\",\n        \"gn_name\": \"Freistaat Thuringen\",\n        \"gns_id\": \"-1874498\",\n        \"gns_name\": \"Thuringen\",\n        \"gn_level\": \"1\",\n        \"gn_region\": null,\n        \"gn_a1_code\": \"DE.15\",\n        \"region_sub\": null,\n        \"sub_code\": null,\n        \"gns_level\": \"1\",\n        \"gns_lang\": \"zho\",\n        \"gns_adm1\": \"GM15\",\n        \"gns_region\": null\n      },\n      \"geometry\": {\n        \"type\": \"Polygon\",\n        \"coordinates\": [\n          [\n            [\n              3728697.3410449172,\n              5665894.003271156\n            ],\n            [\n              3744176.9108976396,\n              5663770.8769144556\n            ],\n            [\n              3748992.2363486462,\n              5654296.6612281911\n            ],\n            [\n              3756509.8321495252,\n              5646715.3534608511\n            ],\n            [\n              3748218.9617048698,\n              5643708.7736610528\n            ],\n            [\n              3741232.331247753,\n              5637557.6046812981\n            ],\n            [\n              3729672.7793026781,\n              5633487.7130454583\n            ],\n            [\n              3728832.1004670118,\n              5625615.0790818483\n            ],\n            [\n              3734759.1665375163,\n              5620512.1446339721\n            ],\n            [\n              3730125.0831804471,\n              5614992.2367806258\n            ],\n            [\n              3725457.3308588881,\n              5614794.9990650406\n            ],\n            [\n              3722819.9620642923,\n              5607572.8059453368\n            ],\n            [\n              3716102.6109797498,\n              5603841.3164922409\n            ],\n            [\n              3711847.4358901861,\n              5605288.3101831255\n            ],\n            [\n              3707593.3788553113,\n              5598689.8272855673\n            ],\n            [\n              3706456.6357335709,\n              5590490.103557012\n            ],\n            [\n              3701124.6336581926,\n              5587599.6888292851\n            ],\n            [\n              3698749.3649529289,\n              5590010.1434312938\n            ],\n            [\n              3680049.0477793319,\n              5585432.8105548657\n            ],\n            [\n              3676626.67844284,\n              5587664.6132867765\n            ],\n            [\n              3675994.001566703,\n              5590758.7787582632\n            ],\n            [\n              3671958.3111791341,\n              5592357.348135368\n            ],\n            [\n              3672121.9713641307,\n              5600160.7438294999\n            ],\n            [\n              3666404.0989981135,\n              5600603.8442229992\n            ],\n            [\n              3664336.9864799059,\n              5597622.3606871739\n            ],\n            [\n              3659605.2232868215,\n              5595262.2291009063\n            ],\n            [\n              3662238.810322443,\n              5582653.1846054439\n            ],\n            [\n              3660745.4664473836,\n              5573283.5300583346\n            ],\n            [\n              3656266.8897332451,\n              5572781.6523313411\n            ],\n            [\n              3652087.5666547911,\n              5576864.6365224905\n            ],\n            [\n              3653432.929886797,\n              5578485.1134469826\n            ],\n            [\n              3650284.4903703765,\n              5583030.593772362\n            ],\n            [\n              3645868.0769925839,\n              5580963.0357561549\n            ],\n            [\n              3641467.2303942246,\n              5581085.1458215769\n            ],\n            [\n              3638188.6970979096,\n              5585165.1007029591\n            ],\n            [\n              3627205.3913595304,\n              5584768.6555711003\n            ],\n            [\n              3622821.4798547197,\n              5581827.2477174671\n            ],\n            [\n              3622115.8301066705,\n              5577492.5262480676\n            ],\n            [\n              3631003.5069937492,\n              5572109.5285800658\n            ],\n            [\n              3631250.6056273249,\n              5568820.599108696\n            ],\n            [\n              3623502.8652153891,\n              5568663.640977269\n            ],\n            [\n              3623231.2025344539,\n              5565109.5173362065\n            ],\n            [\n              3615378.8061682819,\n              5566488.7467001993\n            ],\n            [\n              3613301.3204261549,\n              5577745.2251591412\n            ],\n            [\n              3610451.0868479265,\n              5581336.1181971366\n            ],\n            [\n              3606720.0805508858,\n              5580673.1137679294\n            ],\n            [\n              3603043.3838240071,\n              5585677.0623686798\n            ],\n            [\n              3599920.250670508,\n              5585260.6331641655\n            ],\n            [\n              3599433.8822761257,\n              5588255.5182174174\n            ],\n            [\n              3593561.5613371767,\n              5595872.3240806991\n            ],\n            [\n              3587805.4131642585,\n              5597748.057573312\n            ],\n            [\n              3584213.7888737433,\n              5602032.7751879171\n            ],\n            [\n              3579781.59930187,\n              5603487.1175612584\n            ],\n            [\n              3574817.4056062475,\n              5598257.4420703379\n            ],\n            [\n              3574029.2307750289,\n              5608145.7005352741\n            ],\n            [\n              3576134.9967648848,\n              5610012.6024658671\n            ],\n            [\n              3574366.9579191515,\n              5615279.0739612924\n            ],\n            [\n              3570507.0136910323,\n              5615967.2634153562\n            ],\n            [\n              3567228.3343895781,\n              5614423.7075280305\n            ],\n            [\n              3566738.0713194893,\n              5610456.5903575188\n            ],\n            [\n              3562073.2358358465,\n              5612230.2116798423\n            ],\n            [\n              3564520.4169722269,\n              5617718.1240404369\n            ],\n            [\n              3566734.0008735228,\n              5627081.9127885103\n            ],\n            [\n              3566901.1734591089,\n              5631378.4425946446\n            ],\n            [\n              3571762.6630286835,\n              5633277.0861994652\n            ],\n            [\n              3574302.524281817,\n              5638981.32835175\n            ],\n            [\n              3570742.7824758831,\n              5643197.4355528848\n            ],\n            [\n              3568515.6242985181,\n              5641517.5843244502\n            ],\n            [\n              3567177.6235405561,\n              5645472.6461312221\n            ],\n            [\n              3573185.653422052,\n              5645450.4846842652\n            ],\n            [\n              3571869.1755224951,\n              5650014.132858675\n            ],\n            [\n              3573767.2356044655,\n              5652811.9528761469\n            ],\n            [\n              3583383.0604236061,\n              5651698.8799884953\n            ],\n            [\n              3583664.5405275868,\n              5657171.22150579\n            ],\n            [\n              3580088.3767739702,\n              5658270.1789641948\n            ],\n            [\n              3581851.2486287467,\n              5665001.7837908594\n            ],\n            [\n              3578798.7772993003,\n              5667248.2472233446\n            ],\n            [\n              3582117.5519434675,\n              5668271.7900177678\n            ],\n            [\n              3583764.4426440145,\n              5665075.652521369\n            ],\n            [\n              3586006.8405960761,\n              5672728.1137020076\n            ],\n            [\n              3575528.1127700228,\n              5676892.8194844155\n            ],\n            [\n              3573198.2449193862,\n              5682792.5178340524\n            ],\n            [\n              3566034.6785900695,\n              5685742.3244812824\n            ],\n            [\n              3564312.7318813005,\n              5691987.1708498131\n            ],\n            [\n              3566077.5702712322,\n              5694404.3259839863\n            ],\n            [\n              3572713.6175525445,\n              5700091.8007927611\n            ],\n            [\n              3579943.6412702766,\n              5700165.6181104556\n            ],\n            [\n              3582986.9514478082,\n              5705509.9902624423\n            ],\n            [\n              3586116.3035516692,\n              5704751.2523524342\n            ],\n            [\n              3594658.1928674169,\n              5712729.2957265247\n            ],\n            [\n              3595277.3502693637,\n              5717559.7764455471\n            ],\n            [\n              3598512.0890342994,\n              5718303.0865497692\n            ],\n            [\n              3605003.1711668326,\n              5714474.0370600866\n            ],\n            [\n              3611631.7745252792,\n              5716427.2014618823\n            ],\n            [\n              3617510.6850254778,\n              5723772.3194554569\n            ],\n            [\n              3634798.3906453014,\n              5719458.0870596841\n            ],\n            [\n              3632504.2172296499,\n              5716768.8556063659\n            ],\n            [\n              3639072.4658529945,\n              5698871.2434897516\n            ],\n            [\n              3661128.3753905562,\n              5696690.098692731\n            ],\n            [\n              3671078.403472946,\n              5684562.7217747746\n            ],\n            [\n              3662981.3890735451,\n              5678154.1523908963\n            ],\n            [\n              3669281.7923881463,\n              5672052.1862729536\n            ],\n            [\n              3670003.9710097802,\n              5665298.3177191904\n            ],\n            [\n              3688360.598657859,\n              5665165.5228766529\n            ],\n            [\n              3691711.4629774042,\n              5657002.0672275824\n            ],\n            [\n              3700671.5497429045,\n              5657917.8290444724\n            ],\n            [\n              3711102.7786706178,\n              5650136.7946595009\n            ],\n            [\n              3721967.7634851355,\n              5650922.120966264\n            ],\n            [\n              3724984.3058717526,\n              5648366.5871077562\n            ],\n            [\n              3729823.6229192242,\n              5657699.0347429402\n            ],\n            [\n              3728697.3410449172,\n              5665894.003271156\n            ]\n          ]\n        ]\n      }\n    }\n  ]\n}"
  },
  {
    "path": "src/comps/blurforwarder/BlurForwarder.ts",
    "content": "import {Directive, ElementRef, Renderer} from \"@angular/core\";\n@Directive({\n    selector: 'input,select,textarea',\n    host: {\n        '(blur)': 'onBlur($event)'\n    }\n})\nexport class BlurForwarder {\n    constructor(private elRef: ElementRef) {\n    }\n\n    onBlur($event) {\n        // this.renderer.invokeElementMethod(this.elRef.nativeElement, 'dispatchEvent', [new CustomEvent('input-blur', {bubbles: true})]);\n        // or just\n        // don't error out on older browsers just fail silently\n        try {\n            this.elRef.nativeElement.dispatchEvent(new CustomEvent('input-blur', { bubbles: true }));\n        } catch (e){\n\n        }\n\n        // you don't care about webworker compatibility\n    }\n}"
  },
  {
    "path": "src/comps/connect-form/connect-form.ts",
    "content": "import {Directive, EventEmitter, Input, Output} from '@angular/core';\nimport {FormGroupDirective} from '@angular/forms';\nimport {Subscription} from 'rxjs/Subscription';\nimport {Actions} from '@ngrx/effects';\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport * as _ from 'lodash';\nimport {ACTION_FORM_UPDATE} from \"../../store/actions/appdb.actions\";\n\nconst FORM_SUBMIT_SUCCESS = 'FORM_SUBMIT_SUCCESS';\nconst FORM_SUBMIT_ERROR = 'FORM_SUBMIT_ERROR';\n\nexport const formSuccessAction = path => ({\n    type: FORM_SUBMIT_SUCCESS,\n    payload: {\n        path\n    }\n});\n\nexport const formErrorAction = (path, error) => ({\n    type: FORM_SUBMIT_ERROR,\n    payload: {\n        path,\n        error\n    }\n});\n\n@Directive({\n    selector: '[connectForm]'\n})\nexport class ConnectFormDirective {\n    @Input('connectForm') path: string;\n    @Input() debounce: number = 300;\n    @Output() error = new EventEmitter();\n    @Output() success = new EventEmitter();\n    formChange: Subscription;\n    formSuccess: Subscription;\n    formError: Subscription;\n\n    constructor(private formGroupDirective: FormGroupDirective,\n                private actions$: Actions,\n                private yp: YellowPepperService) {\n    }\n\n    ngOnInit() {\n        this.yp.ngrxStore.select(state => _.get(state, this.path))\n            .take(1)\n            .subscribe((val: Map<any, any>) => {\n                this.formGroupDirective.form.patchValue(val.toJSON());\n            });\n\n        this.formChange = this.formGroupDirective.form.valueChanges\n            .debounceTime(this.debounce)\n            .subscribe(value => {\n                // remove the first level of store path, i.e 'appDb.contact' becomes just 'connect'\n                this.yp.ngrxStore.dispatch({\n                    type: ACTION_FORM_UPDATE,\n                    payload: {\n                        value,\n                        path: this.path.split('.').slice(1, this.path.length - 1).join(),\n                    }\n                });\n            });\n\n        this.formSuccess = this.actions$\n            .ofType(FORM_SUBMIT_SUCCESS)\n            .filter(({payload}) => payload.path === this.path)\n            .subscribe(() => {\n                this.formGroupDirective.form.reset();\n                this.success.emit();\n            });\n\n        this.formError = this.actions$\n            .ofType(FORM_SUBMIT_ERROR)\n            .filter(({payload}) => payload.path === this.path)\n            .subscribe(({payload}) => {\n                return this.error.emit(payload.error)\n            })\n    }\n\n    ngOnDestroy() {\n        this.formChange.unsubscribe();\n        this.formError.unsubscribe();\n        this.formSuccess.unsubscribe();\n    }\n\n}"
  },
  {
    "path": "src/comps/contact-us/contact-us.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {FormControl, FormGroup, Validators} from \"@angular/forms\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {EFFECT_CONTACT_US} from \"../../store/effects/appdb.effects\";\n\n@Component({\n    selector: 'contact-us',\n    template: `\n        <div class=\"container pull-left\" style=\"width: 400px\">\n            <form [formGroup]=\"contactForm\"\n                  (submit)=\"submit($event)\"\n                  (success)=\"onSuccess($event)\"\n                  (error)=\"onError($event)\"\n                  connectForm=\"appDb.contact\">\n\n                <div class=\"form-group\">\n                    <input type=\"text\" formControlName=\"email\" class=\"form-control\" placeholder=\"email address\">\n                </div>\n\n                <div class=\"form-group\">\n                <textarea formControlName=\"message\"\n                          placeholder=\"your question\"\n                          cols=\"10\" rows=\"3\" class=\"form-control\"></textarea>\n                </div>\n\n                <!--<div class=\"form-group\">-->\n                <!--<input type=\"checkbox\" formControlName=\"draft\"> Draft-->\n                <!--</div>-->\n\n                <select formControlName=\"category\" [compareWith]=\"compareFn\">\n                    <option *ngFor=\"let option of options\" [ngValue]=\"option.id\">{{option.label}}</option>\n                </select>\n                <br/>\n                <button style=\"margin-top: 20px\" (click)=\"submit($event)\" [disabled]=\"contactForm.invalid\" class=\"btn btn-primary\" type=\"button\">Submit</button>\n\n            </form>\n\n            <div class=\"alert alert-success\" *ngIf=\"success\">Success!</div>\n            <div class=\"alert alert-danger\" *ngIf=\"error\">{{error}}</div>\n\n        </div>\n    `\n})\nexport class ContactUs {\n    options = [{id: 1, label: 'Support'}, {id: 2, label: 'Sales'}]\n    error;\n    success;\n    contactForm: FormGroup;\n\n    constructor(private yp: YellowPepperService) {\n    }\n\n    onError(error) {\n        this.error = error;\n    }\n\n    onSuccess(e) {\n        this.success = true;\n    }\n\n    ngOnInit() {\n        this.contactForm = new FormGroup({\n            email: new FormControl(null, Validators.email),\n            message: new FormControl(null, Validators.required),\n            category: new FormControl(this.options[1].id, Validators.required)\n            // ,draft: new FormControl(false)\n        });\n\n    }\n\n    // blog ref: https://netbasal.com/understanding-the-comparefn-input-in-angular-v4-4a401ef4fc4c\n    // the trackBy Input is for performance optimization, and the compareFn used to identify specific member\n    compareFn(optionOne, optionTwo): boolean {\n        return optionOne === optionTwo;\n    }\n\n    submit(e) {\n        this.success = false;\n        this.yp.ngrxStore.dispatch({\n            type: EFFECT_CONTACT_US\n        })\n    }\n}"
  },
  {
    "path": "src/comps/disable-control/disable-control.ts",
    "content": "import {NgControl} from '@angular/forms';\nimport {Directive, Input} from \"@angular/core\";\n\n@Directive({\n    selector: '[disableControl]'\n})\nexport class DisableControlDirective {\n\n    @Input()\n    set disableControl(condition: boolean) {\n        const action = condition ? 'disable' : 'enable';\n        this.ngControl.control[action]();\n    }\n\n    constructor(private ngControl: NgControl) {\n    }\n\n}"
  },
  {
    "path": "src/comps/draggable-list/draggable-list.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, TemplateRef} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {List} from \"immutable\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\n@Component({\n    selector: 'draggable-list',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        .dragch {\n            float: right;\n            padding-right: 10px;\n            position: relative;\n            top: 5px;\n        }\n\n        .lengthTimer {\n            float: right;\n            padding-right: 10px;\n        }\n\n        .listItems {\n            cursor: pointer;\n        }\n\n        .listItems a i {\n            display: inline;\n            font-size: 40px;\n            padding-right: 20px;\n        }\n\n        .listItems a span {\n            display: inline;\n            font-size: 1.5em;\n            position: relative;\n            top: -12px;\n        }\n    `],\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div>\n            <div *ngIf=\"customTemplate\">\n                <div class=\"sortableList\">\n                    <li (click)=\"_onItemSelected(item, $event, i)\" *ngFor=\"let item of m_items; let i = index\" class=\"listItems list-group-item\" [ngClass]=\"{'selectedItem': m_selectedIdx == i}\">\n                        <ng-template [ngTemplateOutlet]=\"customTemplate\" [ngOutletContext]=\"{$implicit: item}\">\n                        </ng-template>\n                    </li>\n                </div>\n            </div>\n            <div *ngIf=\"!customTemplate\">\n                <div class=\"sortableList\">\n                    <li (click)=\"_onItemSelected(item, $event, i)\" *ngFor=\"let item of m_items; let i = index\" class=\".listItems list-group-item\" [ngClass]=\"{'selectedItem': m_selectedIdx == i}\">\n                        <a href=\"#\">\n                            {{item}}\n                        </a>\n                    </li>\n                </div>\n            </div>\n        </div>\n    `,\n})\nexport class DraggableList extends Compbaser implements AfterViewInit {\n\n    private m_draggables;\n    private target;\n    private y;\n\n    constructor(private el: ElementRef) {\n        super();\n    }\n\n    m_items: List<any>\n    m_selectedIdx = -1;\n\n    @Input() customTemplate: TemplateRef<Object>;\n\n    @Input()\n    set items(i_items: List<any>) {\n        // this.m_selectedIdx = -1;\n        this.m_items = i_items;\n        this.createSortable();\n    }\n\n    public deselect() {\n        this.m_selectedIdx = -1;\n    }\n\n    @Output()\n    onDragComplete: EventEmitter<any> = new EventEmitter<any>();\n\n    @Output()\n    onItemSelected: EventEmitter<any> = new EventEmitter<any>();\n\n    private _onItemSelected(item, event, i) {\n        this.m_selectedIdx = i;\n        this.onItemSelected.emit({item, event, i})\n    }\n\n    /**\n     Create a draggable sortable list\n     @method _createSortable\n     @param {String} i_selector\n     **/\n    @timeout(300)\n    public createSortable() {\n        var self = this;\n\n        var selector = '.sortableList';\n        if (jQuery(selector).children().length == 0) return;\n        var sortable = document.querySelector(selector);\n        if (this.m_draggables) {\n            this.m_draggables.forEach((drag) => {\n                drag.kill()\n            });\n            // var a = Draggable.get(\".sortableList\");\n            // var sortable = document.querySelector(selector);\n            // var a = Draggable.get(sortable);\n            // con(a);\n            // Draggable.get(\".sortableList\").kill();\n        }\n\n        self.m_draggables = Draggable.create(sortable.children, {\n            type: \"y\",\n            bounds: sortable,\n            dragClickables: true,\n            edgeResistance: 1,\n            onPress: self._sortablePress,\n            onDragStart: self._sortableDragStart,\n            onDrag: self._sortableDrag,\n            liveSnap: self._sortableSnap,\n            onDragEnd: function () {\n                self.m_selectedIdx = -1;\n                var t = this.target,\n                    max = t.kids.length - 1,\n                    newIndex = Math.round(this.y / t.currentHeight);\n                newIndex += (newIndex < 0 ? -1 : 0) + t.currentIndex;\n                if (newIndex === max) {\n                    t.parentNode.appendChild(t);\n                } else {\n                    t.parentNode.insertBefore(t, t.kids[newIndex + 1]);\n                }\n                TweenLite.set(t.kids, {yPercent: 0, overwrite: \"all\"});\n                TweenLite.set(t, {y: 0, color: \"\"});\n                var items = jQuery('.sortableList', self.el.nativeElement).children();\n                self.onDragComplete.emit(items)\n\n                //_.each(self.m_draggables, function(i){\n                //    this.enabled(false);\n                //});\n            }\n        });\n    }\n\n\n    /**\n     Sortable list on press\n     @method _sortablePress\n     **/\n    _sortablePress() {\n        var t = this.target,\n            i = 0,\n            child = t;\n        while (child = child.previousSibling)\n            if (child.nodeType === 1) i++;\n        t.currentIndex = i;\n        t.currentHeight = t.offsetHeight;\n        t.kids = [].slice.call(t.parentNode.children); // convert to array\n    }\n\n    /**\n     Sortable drag list on press\n     @method _sortableDragStart\n     **/\n    _sortableDragStart() {\n        TweenLite.set(this.target, {color: \"#88CE02\"});\n    }\n\n    /**\n     Sortable drag list\n     @method _sortableDrag\n     **/\n    _sortableDrag() {\n        var t = this.target,\n            elements = t.kids.slice(), // clone\n            indexChange = Math.round(this.y / t.currentHeight),\n            bound1 = t.currentIndex,\n            bound2 = bound1 + indexChange;\n        if (bound1 < bound2) { // moved down\n            TweenLite.to(elements.splice(bound1 + 1, bound2 - bound1), 0.15, {yPercent: -100});\n            TweenLite.to(elements, 0.15, {yPercent: 0});\n        } else if (bound1 === bound2) {\n            elements.splice(bound1, 1);\n            TweenLite.to(elements, 0.15, {yPercent: 0});\n        } else { // moved up\n            TweenLite.to(elements.splice(bound2, bound1 - bound2), 0.15, {yPercent: 100});\n            TweenLite.to(elements, 0.15, {yPercent: 0});\n        }\n    }\n\n    /**\n     snap to set rounder values\n     @method _sortableSnap\n     **/\n    _sortableSnap(y) {\n        return y;\n        // enable code below to enable snapinnes on dragging\n        // var h = this.target.currentHeight;\n        // return Math.round(y / h) * h;\n    }\n\n    ngAfterViewInit() {\n\n\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n        if (this.m_draggables) {\n            this.m_draggables.forEach((drag) => {\n                drag.kill()\n            });\n        }\n        this.m_draggables = null;\n    }\n}"
  },
  {
    "path": "src/comps/duration-input/duration-input.component.css",
    "content": "div {\n    display: inline-block;\n}\n\ninput {\n    width: 22px;\n    border: none;\n    outline: 0;\n}\n\n.btn.active.focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn:active:focus, .btn:focus {\n    outline: 0;\n}\n\na {\n    height: 12px;\n    width: 12px;\n    cursor: pointer;\n}\n\ni {\n    font-size: 8px;\n    position: relative;\n    top: -5px;\n    left: 5px;\n    color: black;\n}\n\n.wrap {\n    background-color: white;\n    height: 35px;\n    width: 100px;\n    margin: 5px;\n    padding: 5px;\n    border: solid #cccccc 1px;\n    height: 30px;\n}\n"
  },
  {
    "path": "src/comps/duration-input/duration-input.component.html",
    "content": "<div class=\"wrap\">\n    <div (mouseleave)=\"notifyChanges()\">\n        <div style=\"float: left\">\n            <input type=\"text\" name=\"hour\" [(ngModel)]=\"hoursOutput\" (focus)=\"setFocus($event, 'hour')\" (keypress)=\"inputTime($event)\" (keyup)=\"keyUp($event)\" />\n            <input type=\"text\" name=\"minute\" [(ngModel)]=\"minutesOutput\" (focus)=\"setFocus($event, 'minute')\" (keypress)=\"inputTime($event)\" (keyup)=\"keyUp($event)\" />\n            <input type=\"text\" name=\"second\" [(ngModel)]=\"secondsOutput\" (focus)=\"setFocus($event, 'second')\" (keypress)=\"inputTime($event)\" (keyup)=\"keyUp($event)\" />\n        </div>\n        <div style=\"float: left\">\n            <a style=\"display: block\" (mousedown)=\"mouseDownIncrement()\" (mouseup)=\"mouseUpIncrement()\">\n                <i class=\"fa fa-plus\"></i>\n            </a>\n            <a style=\"display: block\" (mousedown)=\"mouseDownDecrement()\" (mouseup)=\"mouseUpDecrement()\">\n                <i class=\"fa fa-minus\"></i>\n            </a>\n        </div>\n\n    </div>\n</div>\n"
  },
  {
    "path": "src/comps/duration-input/duration-input.component.spec.ts",
    "content": "/* tslint:disable:no-unused-variable */\nimport { async, ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { DebugElement } from '@angular/core';\n\nimport { DurationInputComponent } from './duration-input.component';\n\ndescribe('DurationInputComponent', () => {\n  let component: DurationInputComponent;\n  let fixture: ComponentFixture<DurationInputComponent>;\n\n  beforeEach(async(() => {\n    TestBed.configureTestingModule({\n      declarations: [ DurationInputComponent ]\n    })\n    .compileComponents();\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(DurationInputComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should create', () => {\n    expect(component).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/comps/duration-input/duration-input.component.ts",
    "content": "import {Component, EventEmitter, Input, OnInit, Output} from \"@angular/core\";\n\n@Component({\n    selector: 'app-duration-input',\n    templateUrl: './duration-input.component.html',\n    styleUrls: ['./duration-input.component.css']\n})\nexport class DurationInputComponent implements OnInit {\n    hours = 0;\n    minutes = 0;\n    seconds = 1;\n    hoursOutput = \"00\";\n    minutesOutput = \"00\";\n    secondsOutput = \"01\";\n    focus = \"second\";\n    focusedItem;\n    timer;\n    duration = 0;\n    prevDuration = 0;\n\n    @Input()\n    set setDuration(i_duration: number) {\n        i_duration = Math.round(i_duration);\n        if (this.duration == i_duration || i_duration == -1) return;\n        console.log(`>>>>>>>> setting new duration old ${this.duration} > ${i_duration}`);\n        this.duration = i_duration;\n        this.calcSeconds();\n        this.updateDisplay();\n    }\n\n    @Output() durationChange = new EventEmitter<Object>();\n\n    constructor() {\n    }\n\n    ngOnInit() {\n        document.body.onmouseup = () => {\n            clearInterval(this.timer);\n        }\n        this.calcSeconds();\n        this.updateDisplay();\n    }\n\n    calcSeconds() {\n        var totalSeconds = this.duration;\n        this.hours = Math.floor(totalSeconds / 3600);\n        totalSeconds -= this.hours * 3600;\n        this.minutes = Math.floor(totalSeconds / 60);\n        totalSeconds -= this.minutes * 60;\n        this.seconds = totalSeconds;\n    }\n\n    increment() {\n        // console.log('increment');\n        if (this.focusedItem) {\n            this.focusedItem.focus();\n        }\n        switch (this.focus) {\n            case \"hour\":\n                ++this.hours;\n                break;\n            case \"minute\":\n                ++this.minutes;\n                break;\n            case \"second\":\n                ++this.seconds;\n                break;\n            default:\n                break;\n        }\n        if (this.seconds == 60) {\n            this.seconds = 0;\n            this.minutes++;\n        }\n        if (this.minutes == 60) {\n            this.minutes = 0;\n            this.hours++;\n        }\n        if (this.hours > 24) {\n            this.hours = 0;\n        }\n        this.updateDisplay();\n    }\n\n    decrement() {\n        // console.log('decrement');\n        switch (this.focus) {\n            case \"hour\":\n                if (--this.hours < 0) {\n                    this.hours = 24;\n                }\n                break;\n            case \"minute\":\n                if (this.minutes == 0 && this.hours == 0) break;\n                if (--this.minutes == -1) {\n                    this.minutes = 59;\n                    this.hours--;\n                }\n                break;\n            case \"second\":\n                if (this.seconds == 0 && this.minutes == 0 && this.hours == 0) break;\n                if (--this.seconds == -1) {\n                    this.seconds = 59;\n                    if (--this.minutes == -1) {\n                        this.minutes = 59;\n                        this.hours--;\n                    }\n                }\n                break;\n            default:\n                break;\n        }\n        this.updateDisplay();\n    }\n\n    notifyChanges() {\n        const newDuration = this.hours * 60 * 60 + this.minutes * 60 + this.seconds;\n        if (newDuration != this.prevDuration) {\n            this.prevDuration = newDuration;\n            // console.log('change emitted ' + newDuration);\n            this.durationChange.emit(newDuration);\n        }\n\n    }\n\n    updateDisplay() {\n        this.secondsOutput = this.padLeft(this.seconds);\n        this.minutesOutput = this.padLeft(this.minutes);\n        this.hoursOutput = this.padLeft(this.hours);\n    }\n\n    inputTime(e) {\n        if (!/[0-9]/.test(e.key)) {\n            e.preventDefault();\n        } else {\n\n        }\n    }\n\n    keyUp(e) {\n        this.seconds = +this.secondsOutput;\n        this.minutes = +this.minutesOutput;\n        this.hours = +this.hoursOutput;\n        if (!this.hours) {\n            this.hours = 0;\n        }\n        if (this.hours > 24) {\n            this.hours = 24;\n        }\n\n        if (!this.minutes) {\n            this.minutes = 0;\n        }\n        if (this.minutes > 59) {\n            this.minutes = 59;\n        }\n\n        if (!this.seconds) {\n            this.seconds = 0;\n        }\n        if (this.seconds > 59) {\n            this.seconds = 59;\n        }\n        this.updateDisplay();\n    }\n\n    setFocus(event, field) {\n        this.focus = field;\n        this.focusedItem = event.target;\n    }\n\n    mouseDownIncrement() {\n        this.increment();\n        // this.timer = setInterval(() => this.increment(), 150);\n    }\n\n    mouseUpIncrement() {\n        // clearInterval(this.timer);\n    }\n\n    mouseDownDecrement() {\n        this.decrement();\n        // this.timer = setInterval(() => this.decrement(), 150);\n    }\n\n    mouseUpDecrement() {\n        clearInterval(this.timer);\n    }\n\n    padLeft(n) {\n        n = n.toString();\n        n = \"00\".substring(0, 2 - n.length) + \"\" + n.toString();\n        n = n.substring(n.length - 2);\n        return n;\n    }\n\n\n}\n"
  },
  {
    "path": "src/comps/entry/AutoLogin.ts",
    "content": "import {Component, ChangeDetectionStrategy} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\n\n@Component({\n    selector: 'AutoLogin',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `<h5 style=\"padding-left: 10px\"><span class=\"fa fa-key\"></span>\n                <span i18n>verifying access...</span>\n                </h5>`\n})\nexport class AutoLogin extends Compbaser {\n}"
  },
  {
    "path": "src/comps/entry/LoginPanel.ts",
    "content": "import {Component, ElementRef, Injectable, ViewChild} from \"@angular/core\";\nimport {animate, keyframes, state, style, transition, trigger} from \"@angular/animations\";\nimport {ActivatedRoute} from \"@angular/router\";\nimport {LocalStorage} from \"../../services/LocalStorage\";\nimport {AuthService} from \"../../services/AuthService\";\nimport {Map} from \"immutable\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {ApplicationState} from \"../../store/application.state\";\nimport {Store} from \"@ngrx/store\";\nimport {UserModel} from \"../../models/UserModel\";\nimport {AuthenticateFlags} from \"../../store/actions/appdb.actions\";\nimport {Compbaser, NgmslibService} from \"ng-mslib\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {Lib} from \"../../Lib\";\n\nenum ViewMod {\n    LOGIN,\n    FORGOT_PASSWORD,\n    CHANGE_PASSWORD,\n    CHANGE_BUSINESS_NAME\n}\n\n@Injectable()\n@Component({\n    selector: 'LoginPanel',\n    providers: [LocalStorage],\n    animations: [\n\n        trigger('loginState', [\n            state('inactive', style({\n                backgroundColor: 'red',\n                transform: 'scale(1)',\n                alpha: 0\n            })),\n            state('default', style({\n                backgroundColor: '#313131',\n                transform: 'scale(1)',\n                alpha: 1\n            })),\n            state('active', style({\n                backgroundColor: 'green',\n                transform: 'scale(0.98)'\n            })),\n            transition('* => active', animate('600ms ease-out')),\n            transition('* => inactive', animate('2000ms ease-out'))\n        ]),\n        trigger('showTwoFactor', [\n            state('true', style({\n                transform: 'scale(1)'\n            })),\n            transition(':enter', [\n                animate('1s 2s cubic-bezier(0.455,0.03,0.515,0.955)', keyframes([\n                    style({\n                        opacity: 0,\n                        transform: 'translateX(-400px)'\n                    }),\n                    style({\n                        opacity: 1,\n                        transform: 'translateX(0)'\n                    })\n                ]))\n            ]),\n            transition(':leave', animate('500ms cubic-bezier(.17,.67,.83,.67)'))\n        ])\n    ],\n    styles: [`\n        a {\n            color: gray;\n        }\n\n        a:visited {\n            color: #b9b9b9;\n        }\n\n        a:hover {\n            color: #b9b9b9;\n        }\n    `],\n    template: `        \n        <ul [@loginState]=\"loginState\" class=\"login-page\" id=\"appLogin\">\n            <br/>\n            <br/>\n            <br/>\n            <br/>\n            <form class=\"form-signin\" role=\"form\">\n                <ul [ngSwitch]=\"m_currentViewMode\">\n\n                    \n                    \n                    <div *ngSwitchCase=\"m_viewMod.LOGIN\">\n                        <h2 class=\"form-signin-heading\"></h2>\n                        <input (keyup.enter)=\"passFocus()\" #userName id=\"userName\" spellcheck=\"false\" type=\"text\" name=\"m_user\" [(ngModel)]=\"m_user\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"user name or email\" required autofocus>\n                        <input (keyup.enter)=\"onClickedLogin()\" #userPass id=\"userPass\" type=\"password\" [(ngModel)]=\"m_pass\" name=\"m_pass\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"password\" required>\n                        <div [@showTwoFactor]=\"m_showTwoFactor\" *ngIf=\"m_showTwoFactor\">\n                            <br/>\n                            <br/>\n                            <span style=\"color: #989898; position: relative; left: -40px; top: 34px\" class=\"fa fa-key fa-2x pull-right\"></span>\n                            <input #twoFactor spellcheck=\"false\" type=\"text\" name=\"m_twoFactor\" [(ngModel)]=\"m_twoFactor\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"enter two factor key\" required autofocus>\n                            <br/>\n                            <br/>\n                        </div>\n                        <br/>\n                        <a i18n id=\"loginButton\" style=\"width: 280px\" (click)=\"onClickedLogin()\" type=\"submit\" class=\"btn rounded-btn\"> login to your account\n                            <!--<span *ngIf=\"m_showTwoFactor\" style=\"font-size: 9px; max-height: 15px; display: block; padding: 0; margin: 0; position: relative; top: -20px\">with Google authenticator</span>-->\n                        </a>&nbsp;\n\n                        <br/>\n                        <div style=\"width: 280px; position: relative\">\n                            <div class=\"pull-left\" *ngIf=\"!m_showTwoFactor\">\n                                <label class=\"checkbox\" style=\"padding-left: 20px\">\n                                    <input #rememberMe type=\"checkbox\" [checked]=\"m_rememberMe\" (change)=\"m_rememberMe = rememberMe.checked\"/>\n                                    <span i18n style=\"color: gray\"> remember me </span>\n                                </label>\n                            </div>\n                            <div style=\"text-align: right\" id=\"loginExtras\" class=\"pull-right\">\n                                <a id=\"forgotPassword\" i18n (click)=\"$event.preventDefault(); m_currentViewMode = m_viewMod.FORGOT_PASSWORD\" href=\"#\">forgot password</a>\n                                <br/>\n                                <a id=\"changePassword\" i18n (click)=\"$event.preventDefault(); m_currentViewMode = m_viewMod.CHANGE_PASSWORD\" href=\"#\">change password</a>\n                                <br/>\n                                <a id=\"changeBusiness\" i18n (click)=\"$event.preventDefault(); m_currentViewMode = m_viewMod.CHANGE_BUSINESS_NAME\" href=\"#\">change business name</a>\n                            </div>\n                             <br/>\n                        </div>\n                        <div class=\"clearFloat\"></div>\n                        <locale-selector [orientation]=\"'inline'\"></locale-selector>\n                        <br/>\n                        <a i18n style=\"padding-left: 20px\" href=\"https://secure.digitalsignage.com/msgetstarted/#selectStudioLite\">Don't have an account? create one</a>\n                    </div>\n\n                    <div *ngSwitchCase=\"m_viewMod.CHANGE_PASSWORD\">\n                        <h2 class=\"form-signin-heading\"></h2>\n                        <input spellcheck=\"false\" type=\"text\" name=\"m_user\" [(ngModel)]=\"m_user\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"user name / email\" required autofocus>\n                        <input type=\"password\" [(ngModel)]=\"m_pass\" name=\"m_pass\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"old password\" required>\n                        <input type=\"password\" [(ngModel)]=\"m_passNew\" name=\"m_pass\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"new password\" required>\n                        <input type=\"password\" [(ngModel)]=\"m_passRepeat\" name=\"m_pass\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"repeat new password\" required>\n                        <br/>\n                        <a style=\"width: 280px\" (click)=\"onChangePassword()\" type=\"submit\" class=\"btn rounded-btn\"> change password\n                            <span *ngIf=\"m_showTwoFactor\" style=\"font-size: 9px; max-height: 15px; display: block; padding: 0; margin: 0; position: relative; top: -20px\">with Google authenticator</span>\n                        </a>\n                        <br/>\n                        <a class=\"pull-left\" (click)=\"$event.preventDefault(); m_currentViewMode = m_viewMod.LOGIN\" href=\"#\"><i class=\"fa fa-arrow-circle-left\"></i> back</a>\n\n                    </div>\n\n                    <div *ngSwitchCase=\"m_viewMod.FORGOT_PASSWORD\">\n                        <h2 class=\"form-signin-heading\"></h2>\n                        <input (keyup.enter)=\"passFocus()\" #userName id=\"userName\" spellcheck=\"false\" type=\"text\" name=\"m_user\" [(ngModel)]=\"m_user\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"user name / email\" required autofocus>\n                        <br/>\n                        <a style=\"width: 280px\" (click)=\"onResetPassword()\" type=\"submit\" class=\"btn rounded-btn\"> reset your password\n                            <span *ngIf=\"m_showTwoFactor\" style=\"font-size: 9px; max-height: 15px; display: block; padding: 0; margin: 0; position: relative; top: -20px\">with Google authenticator</span>\n                        </a>\n                        <a class=\"pull-left\" (click)=\"$event.preventDefault(); m_currentViewMode = m_viewMod.LOGIN\" href=\"#\"><i class=\"fa fa-arrow-circle-left\"></i> back</a>\n                        <br/>\n                    </div>\n\n                    <div *ngSwitchCase=\"m_viewMod.CHANGE_BUSINESS_NAME\">\n                        <h2 class=\"form-signin-heading\"></h2>\n                        <input spellcheck=\"false\" type=\"text\" name=\"m_user\" [(ngModel)]=\"m_user\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"user name / email\" required autofocus>\n                        <input type=\"password\" [(ngModel)]=\"m_pass\" name=\"m_pass\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"password\" required>\n                        <input type=\"text\" name=\"m_businessName\" [(ngModel)]=\"m_businessName\" class=\"input-underline input-lg form-control\" i18n-placeholder placeholder=\"new business name\" required>\n                        <br/>\n                        <a style=\"width: 280px\" (click)=\"onChangeBusinessName()\" type=\"submit\" class=\"btn rounded-btn\"> change business name\n                            <span *ngIf=\"m_showTwoFactor\" style=\"font-size: 9px; max-height: 15px; display: block; padding: 0; margin: 0; position: relative; top: -20px\">with Google authenticator</span>\n                        </a>\n                        <br/>\n                        <a class=\"pull-left\" (click)=\"$event.preventDefault(); m_currentViewMode = m_viewMod.LOGIN\" href=\"#\"><i class=\"fa fa-arrow-circle-left\"></i> back</a>\n\n                    </div>\n                </ul>\n            </form>\n        </ul>\n    `\n})\nexport class LoginPanel extends Compbaser {\n    m_viewMod = ViewMod;\n    m_currentViewMode = ViewMod.LOGIN;\n    public m_user: string = '';\n    public m_pass: string = '';\n    public m_passNew: string = '';\n    public m_passRepeat: string = '';\n    public m_businessName: string = '';\n    public m_twoFactor: string;\n    public m_showTwoFactor: boolean = false;\n    public m_rememberMe: any;\n    public loginState: string = '';\n    public userModel: UserModel;\n\n    constructor(private ngmslibService: NgmslibService, private store: Store<ApplicationState>,\n                private toast: ToastsManager,\n                private rp: RedPepperService,\n                private activatedRoute: ActivatedRoute,\n                private authService: AuthService) {\n        super();\n        this.listenEvents();\n    }\n\n    @ViewChild('userPass') userPass: ElementRef;\n\n    private listenEvents() {\n\n        this.cancelOnDestroy(\n            this.store.select(store => store.appDb.userModel)\n                .subscribe((userModel: UserModel) => {\n                    this.userModel = userModel\n                }, (e) => {\n                    console.error(e)\n                })\n        )\n\n        this.cancelOnDestroy(\n            this.store.select(store => store.appDb.appAuthStatus).subscribe((i_authStatus: Map<string, AuthenticateFlags>) => {\n                let authStatus = i_authStatus.get('authStatus')\n                if (this.isAccessAllowed(authStatus) == false)\n                    return;\n                switch (authStatus) {\n                    case AuthenticateFlags.TWO_FACTOR_ENABLED: {\n                        this.m_showTwoFactor = true;\n                        break;\n                    }\n                    case AuthenticateFlags.TWO_FACTOR_PASS: {\n                        this.loginState = 'active';\n                        break;\n                    }\n                    case AuthenticateFlags.AUTH_PASS_NO_TWO_FACTOR: {\n                        this.loginState = 'active';\n                        break;\n                    }\n                }\n            }, (e) => {\n                console.error(e)\n            })\n        )\n\n        this.cancelOnDestroy(\n            this.activatedRoute.params.subscribe(params => {\n                if (params['twoFactor']) {\n                    this.m_user = this.ngmslibService.base64().decode(params['user']);\n                    this.m_pass = this.ngmslibService.base64().decode(params['pass']);\n                    this.m_showTwoFactor = true;\n                }\n            }, (e) => console.error(e))\n        )\n    }\n\n    passFocus() {\n        // this.renderer.invokeElementMethod(this.userPass.nativeElement, 'focus', [])\n        jQuery(this.userPass.nativeElement).focus();\n    }\n\n    onChangeBusinessName(){\n        this.rp.changeBusinessName(this.m_user, this.m_pass, this.m_businessName, (value) => {\n            if (!value.result)\n                return bootbox.alert('Sorry there was a problem authenticating');\n            bootbox.alert('Your business name has been renamed successfully');\n            this.m_currentViewMode = ViewMod.LOGIN;\n        })\n    }\n\n    onResetPassword() {\n        if (!Lib.ValidateEmail(this.m_user))\n            return bootbox.alert('user name must be in the form of an email address');\n        this.rp.resetPassword(this.m_user, (value) => {\n            if (!value.result)\n                return bootbox.alert('Sorry no account found');\n            bootbox.alert('Please check your email for a new password');\n            this.m_currentViewMode = ViewMod.LOGIN;\n        })\n    }\n\n    onChangePassword() {\n        if (this.m_passNew != this.m_passRepeat)\n            return bootbox.alert('passwords do not match')\n        if (this.m_user.length < 2)\n            return bootbox.alert('user name is too short')\n        this.rp.changePassword(this.m_user, this.m_pass, this.m_passNew, (value) => {\n            if (value.result == -1)\n                return bootbox.alert('authentication for password change failed, try again');\n            bootbox.alert('Password changed successfully');\n            this.m_currentViewMode = ViewMod.LOGIN;\n        })\n    }\n\n    onClickedLogin() {\n        if (this.m_showTwoFactor) {\n            // this.toast.warning('Authenticating Two factor...');\n            this.authService.authServerTwoFactor(this.m_twoFactor);\n        } else {\n            // this.toast.info('Authenticating...');\n            this.authService.authUser(this.m_user, this.m_pass, this.m_rememberMe);\n        }\n    }\n\n    private isAccessAllowed(i_reason: AuthenticateFlags): boolean {\n        let msg1: string;\n        let msg2: string;\n        // this.loginState = 'default';\n        switch (i_reason) {\n            case AuthenticateFlags.WRONG_PASS: {\n                msg1 = 'User or password are incorrect...'\n                msg2 = 'Please try again or click forgot password to reset your credentials'\n                this.showMessage(msg1, msg2);\n                this.loginState = 'inactive';\n                return false;\n            }\n            case AuthenticateFlags.WRONG_TWO_FACTOR: {\n                msg1 = 'Invalid token'\n                msg2 = 'Wrong token entered or the 60 seconds limit may have exceeded, try again...'\n                this.showMessage(msg1, msg2);\n                this.loginState = 'inactive';\n                return false;\n            }\n            case AuthenticateFlags.TWO_FACTOR_CHECK: {\n                return false;\n            }\n            case AuthenticateFlags.TWO_FACTOR_FAIL: {\n                msg1 = 'Two factor failed'\n                msg2 = 'please try again...'\n                this.showMessage(msg1, msg2);\n                this.loginState = 'inactive';\n                return false;\n            }\n            case AuthenticateFlags.TWO_FACTOR_PASS: {\n                this.loginState = 'active';\n                return true;\n            }\n        }\n    }\n\n    private showMessage(title, message) {\n        setTimeout(() => {\n            bootbox.dialog({\n                closeButton: true,\n                title: title,\n                message: message\n            });\n        }, 200);\n    }\n}"
  },
  {
    "path": "src/comps/font-selector/font-selector.ts",
    "content": "import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Subject} from \"rxjs\";\nimport {FontLoaderService} from \"../../services/font-loader-service\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {Lib} from \"../../Lib\";\n\nexport interface IFontSelector {\n    bold: boolean;\n    italic: boolean;\n    underline: boolean;\n    alignment: 'left' | 'center' | 'right',\n    font: string;\n    color: string;\n    size: number;\n}\n\n@Component({\n    selector: 'font-selector',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <small class=\"debug\">{{me}}</small>\n        <div id=\"fontSelectorTemplate\">\n            <div class=\"form-group\">\n                <select (change)=\"_onFontChanged($event)\" name=\"fontSelection\" class=\"fontSelection propControlWidth form-control\">\n                    <option [selected]=\"font==m_config.font\" *ngFor=\"let font of m_fonts\">\n                        {{font}}\n                    </option>\n                </select>\n                <div>\n                    <div class=\"btn-group\" role=\"group\" aria-label=\"...\">\n                        <button (click)=\"_onFontStyleToggle('bold')\" type=\"button\" name=\"bold\" class=\"fontFormatter btn btn-default btn-sm\" [ngClass]=\"{active: m_config.bold}\">\n                            <i class=\"gencons fa fa-bold\"></i>\n                        </button>\n                        <button (click)=\"_onFontStyleToggle('underline')\" type=\"button\" name=\"underline\" class=\"fontFormatter btn btn-default btn-sm\" [ngClass]=\"{active: m_config.underline}\">\n                            <i class=\"gencons fa fa-underline\"></i>\n                        </button>\n                        <button (click)=\"_onFontStyleToggle('italic')\" type=\"button\" name=\"italic\" class=\"fontFormatter btn btn-default btn-sm\" [ngClass]=\"{active: m_config.italic}\">\n                            <i class=\"gencons fa fa-italic\"></i>\n                        </button>\n                        <button (click)=\"_moveColorPicker()\" #borderColor (colorPickerChange)=\"m_borderColorChanged.next($event)\"\n                                [cpOKButton]=\"true\" [cpOKButtonClass]=\"'btn btn-primary btn-xs'\"\n                                [(colorPicker)]=\"m_config.color\"\n                                [cpPosition]=\"'left'\"\n                                [cpWidth]=\"'230px'\"\n                                [cpAlphaChannel]=\"'disabled'\" class=\"colorPicker offSet\"\n                                [cpFallbackColor]=\"'#123'\"\n                                [style.background]=\"m_config.color\" [value]=\"m_config.color\">\n                        </button>\n                    </div>\n                    <div class=\"btn-group\" role=\"group\" aria-label=\"...\">\n                        <button (click)=\"_onAlignmentChange('left')\" type=\"button\" name=\"alignLeft\" class=\"fontAlignment btn btn-default btn-sm\" [ngClass]=\"{active: m_config.alignment == 'left'}\">\n                            <i class=\"gencons fa fa-align-left\"></i>\n                        </button>\n                        <button (click)=\"_onAlignmentChange('center')\" type=\"button\" name=\"alignCenter\" class=\"fontAlignment btn btn-default btn-sm\" [ngClass]=\"{active: m_config.alignment == 'center'}\">\n                            <i class=\"gencons fa fa-align-center\"></i>\n                        </button>\n                        <button (click)=\"_onAlignmentChange('right')\" type=\"button\" name=\"alignRight\" class=\"fontAlignment btn btn-default btn-sm\" [ngClass]=\"{active: m_config.alignment == 'right'}\">\n                            <i class=\"gencons fa fa-align-right\"></i>\n                        </button>\n                        <input (change)=\"_onFontSizeChanged(fontSize.value)\" #fontSize class=\"offSet\" name=\"fontSizeInput\" type=\"number\" [(ngModel)]=\"m_config.size\" style=\"width: 60px\">\n\n                    </div>\n                </div>\n                <div style=\"clear: both; padding: 3px\"></div>\n                <div>\n                </div>\n            </div>\n        </div>\n\n    `,\n    styles: [`\n        /*:host /deep/ .color-picker {*/\n        /*position: relative;*/\n        /*} */\n\n        .fontSelection {\n            width: 200px;\n        }\n\n        .offSet {\n            position: relative;\n            top: 5px;\n        }\n\n        input {\n            height: 30px;\n        }\n\n        button {\n            margin: 5px;\n            height: 30px;\n        }\n\n        .colorPicker {\n            width: 20px;\n            float: left;\n            display: inline-block;\n            margin: 0 10px 0 0;\n            padding: 15px 45px;\n            border-radius: 0;\n            border: 1px solid gray;\n            background: #ffffff;\n            padding: 10px 20px 10px 20px;\n            text-decoration: none;\n        }\n    `]\n\n})\nexport class FontSelector extends Compbaser implements AfterViewInit {\n\n    bold: boolean;\n    italic: boolean;\n    underline: boolean;\n    alignment: 'left' | 'center' | 'right';\n    m_fonts: Array<string>;\n    m_borderColorChanged = new Subject();\n    m_moveColorPickerOnce = false;\n\n    m_config: IFontSelector = {\n        size: 12,\n        alignment: 'right',\n        bold: true,\n        italic: true,\n        font: 'Lora',\n        underline: true,\n        color: '#ff0000',\n    }\n\n    constructor(private fontService: FontLoaderService, private el: ElementRef) {\n        super();\n        this.m_fonts = this.fontService.getFonts();\n        this._listenColorChanged();\n    }\n\n    @Input()\n    set setConfig(i_config: IFontSelector) {\n        if (!i_config) return;\n        if (Lib.ColorToDecimal(i_config.color)==0){\n            i_config.color = '#ffffff';\n        };\n        this.m_config = i_config\n    }\n\n    @Output()\n    onChange: EventEmitter<IFontSelector> = new EventEmitter<IFontSelector>();\n\n    _listenColorChanged() {\n        this.cancelOnDestroy(\n            //\n            this.m_borderColorChanged\n                .debounceTime(500)\n                .filter(v => v != '#123')\n                .skip(1)\n                .subscribe((i_color) => {\n                    this.m_config.color = String(i_color);\n                    this.onChange.emit(this.m_config);\n                }, (e) => console.error(e))\n        )\n    }\n\n    @timeout(1)\n    _moveColorPicker() {\n        if (this.m_moveColorPickerOnce) return;\n        this.m_moveColorPickerOnce = true;\n        jQuery(\".color-picker\", this.el.nativeElement).css(\"left\", \"+=100\").css(\"top\", \"-=100\");\n        ;\n    }\n\n    _onFontChanged(e) {\n        this.m_config.font = e.target.value;\n        this.onChange.emit(this.m_config);\n    }\n\n    _onFontSizeChanged(i_value) {\n        this.m_config.size = i_value;\n        this.onChange.emit(this.m_config);\n    }\n\n    _onFontStyleToggle(i_style) {\n        this.m_config[i_style] = !this.m_config[i_style];\n        this.onChange.emit(this.m_config);\n    }\n\n    _onAlignmentChange(direction: 'left' | 'center' | 'right') {\n        this.m_config.alignment = direction;\n        this.onChange.emit(this.m_config);\n    }\n\n    ngAfterViewInit() {\n\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/comps/hour-counter/hour-counter.ts",
    "content": "import {Component, ChangeDetectionStrategy, AfterViewInit, ElementRef, ViewChild, Input} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\n\n@Component({\n    selector: 'hour-counter',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <input #hour type=\"text\" name=\"hour\" id=\"hour\" value=\"00\" (focus)=\"setFocus('hour')\" (keyup)=\"validate()\">\n        <input #minute type=\"text\" name=\"minute\" id=\"minute\" value=\"00\" (focus)=\"setFocus('minute')\" (keyup)=\"validate()\">\n        <input #second type=\"text\" name=\"second\" id=\"second\" value=\"01\" (focus)=\"setFocus('second')\" (keyup)=\"validate()\">\n        <input #up type=\"button\" name=\"increment\" id=\"increment\" value=\"+\" (mousedown)=\"intIncrementStart()\" (mouseup)=\"intIncrementEnd()\">\n        <input #down type=\"button\" name=\"decrement\" id=\"decrement\" value=\"-\" (mousedown)=\"intDecrementStart()\" (mouseup)=\"intDecrementEnd()\">\n\n        <!--<input type=\"button\" name=\"increment\" id=\"increment\" value=\"+\" onmousedown=\"intIncrement=setInterval(increment,80)\" onmouseup=\"clearInterval(intIncrement)\">-->\n        <!--<input type=\"button\" name=\"decrement\" id=\"decrement\" value=\"-\" onmousedown=\"intDecrement=setInterval(decrement,80)\" onmouseup=\"clearInterval(intDecrement)\">-->\n\n    `,\n})\nexport class HourCounter {\n\n    constructor(private el: ElementRef) {\n        document.body.onmouseup = () => {\n            clearInterval(this.intIncrement);\n            clearInterval(this.intDecrement);\n        }\n\n    }\n\n    @ViewChild('hour')\n    inputHour;\n\n    @ViewChild('minute')\n    inputMinute:ElementRef;\n\n    @ViewChild('second')\n    inputSeconds:ElementRef;\n\n    @ViewChild('up')\n    up:ElementRef;\n\n    @ViewChild('down')\n    down:ElementRef;\n\n\n\n    intIncrement;\n    intDecrement;\n    currentFocus = 'second';\n\n    setFocus(id) {\n        this.currentFocus = id;\n        this.inputHour.nativeElement.value;\n    }\n\n    intIncrementStart() {\n        setInterval(this.increment,80);\n    }\n\n    intIncrementEnd() {\n        clearInterval(this.intIncrement);\n    }\n\n    intDecrementStart() {\n        setInterval(this.decrement,80)\n    }\n\n    intDecrementEnd() {\n        clearInterval(this.intDecrement)\n    }\n\n    increment() {\n        // document.getElementById(this.currentFocus).focus();\n        var hr = this.inputHour.nativeElement.value;\n        var min = this.inputMinute.nativeElement.value;\n        var sec = this.inputSeconds.nativeElement.value;\n        // var hr = document.getElementById('hour').value;\n        // var min = document.getElementById('minute').value;\n        // var sec = document.getElementById('second').value;\n        // if (this.currentFocus == \"second\") {\n        //\n        //     sec++;\n        //\n        //     if (sec == 60) {\n        //         sec = 0;\n        //         min++;\n        //         if (min == 60) {\n        //             min = 0;\n        //             hr++;\n        //         }\n        //     }\n        //\n        // }\n        // else if (this.currentFocus == \"minute\") {\n        //     min++;\n        //     if (min == 60) {\n        //         min = 0;\n        //         hr++;\n        //     }\n        // }\n        // else if (this.currentFocus == \"hour\") {\n        //     hr++;\n        // }\n        // document.getElementById('hour').value = this.padLeft(hr);\n        // document.getElementById('minute').value = this.padLeft(min);\n        // document.getElementById('second').value = this.padLeft(sec);\n        // this.validate();\n    }\n\n    decrement() {\n        // document.getElementById(this.currentFocus).focus();\n        // var hr = document.getElementById('hour').value;\n        // var min = document.getElementById('minute').value;\n        // var sec = document.getElementById('second').value;\n        // if (this.currentFocus == \"second\") {\n        //     if (hr == 0 && min == 0 && sec == 1) {\n        //         return;\n        //     }\n        //     sec--;\n        //     if (sec == -1) {\n        //         sec = 59;\n        //         min--;\n        //         if (min == -1) {\n        //             min = 59;\n        //             hr--;\n        //         }\n        //     }\n        // }\n        // else if (this.currentFocus == \"minute\") {\n        //     min--;\n        //     if (min == -1) {\n        //         min = 59;\n        //         hr--;\n        //     }\n        // }\n        // else if (this.currentFocus == \"hour\") {\n        //     hr--;\n        // }\n        // document.getElementById('hour').value = padLeft(hr);\n        // document.getElementById('minute').value = padLeft(min);\n        // document.getElementById('second').value = padLeft(sec);\n        // this.validate();\n    }\n\n\n    padLeft(n) {\n        n = n.toString();\n        n = \"00\".substring(0, 2 - n.length) + \"\" + n.toString();\n        n = n.substring(n.length - 2);\n        return n;\n    }\n\n    validate() {\n        // var val = document.getElementById(this.currentFocus).value;\n        // if (isNaN(val)) {\n        //     document.getElementById(this.currentFocus).value = \"00\";\n        // }\n        // var hr = document.getElementById('hour').value;\n        // var min = document.getElementById('minute').value;\n        // var sec = document.getElementById('second').value;\n        // if (hr > 24)\n        //     hr = 24;\n        // if (hr < 0)\n        //     hr = 0;\n        // if (min < 0)\n        //     min = 0;\n        // if (min > 59)\n        //     min = 59;\n        // if (sec < 0)\n        //     sec = 0;\n        // if (sec > 59)\n        //     sec = 59;\n        // document.getElementById('hour').value = this.padLeft(hr);\n        // document.getElementById('minute').value = this.padLeft(min);\n        // document.getElementById('second').value = this.padLeft(sec);\n    }\n}\n"
  },
  {
    "path": "src/comps/imgloader/ImgLoader.ts",
    "content": "import {Component, ChangeDetectionStrategy, ChangeDetectorRef, Input} from '@angular/core';\nimport 'rxjs/add/observable/fromEvent';\nimport 'rxjs/add/operator/do';\nimport 'rxjs/add/operator/merge';\nimport 'rxjs/add/operator/distinctUntilChanged';\nimport {Lib} from \"../../Lib\";\n\n@Component({\n    selector: 'imgLoader',\n    changeDetection: ChangeDetectionStrategy.Default,\n    template: `\n            <div *ngIf=\"defaultImage\"> \n              <img [ngStyle]=\"_style.img\" [ngClass]=\"{'img-circle': circle}\" [src]=\"getImageUrl()\" (load)=\"onImageLoaded()\" (error)=\"onImageError()\" />\n            </div>\n    `\n})\n\nexport class ImgLoader {\n\n    constructor(private cdr:ChangeDetectorRef) {\n    }\n\n    @Input('style')\n    _style:any = {};\n\n    @Input()\n    defaultImage:string = '';\n\n    @Input()\n    circle:boolean = false;\n\n    @Input()\n    images:Array<string> = [];\n\n    private imageRetries:number = 0;\n\n    private getImageUrl() {\n        if (this.images.length == 0)\n            return this.defaultImage;\n        if (this.images[this.imageRetries] == undefined)\n            return this.defaultImage;\n        var url = this.images[this.imageRetries] + (Lib.DevMode() ? '?random=xyz' : `?random=' ${Math.random()}`);\n        return url;\n    }\n\n    private onImageLoaded() {\n        this.cdr.detach();\n    }\n\n    private onImageError() {\n        this.imageRetries++;\n    }\n\n    public reloadImage(){\n        this.imageRetries = 0;\n        this.cdr.reattach();\n    }\n\n}"
  },
  {
    "path": "src/comps/infobox/Infobox.ts",
    "content": "import {Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnChanges, SimpleChange} from '@angular/core'\n\n@Component({\n    selector: 'Infobox',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        .panel-footer {\n          padding: 5px 3px;\n          background-color: #fafafa;\n          border: 1px solid #e2e2e2;\n          border-bottom-right-radius: 2px;\n          border-bottom-left-radius: 2px;\n        }\n        .br-a {\n            border: 1px solid #eeeeee !important;\n        }\n        .br-grey {\n             border-color: #d9d9d9 !important;\n        }\n    `],\n    template: `\n              <div class=\"panel panel-tile text-center br-a br-grey\">\n                 <div *ngIf=\"value1 == null\">\n                    <br/>\n                    <img src=\"assets/preload2.gif\">\n                    <br/>\n                    <br/>\n                 </div>\n                 <div *ngIf=\"value1 != null\">\n                      <div>\n                        <h1>{{value1}}</h1>\n                        <h6 class=\"text-system\">{{value2}}</h6>\n                    </div>\n                    <div class=\"panel-footer br-t p12\">\n                      <span class=\"fs11\">\n                        <i class=\"fa {{icon}} pr5\"></i>\n                        {{value3}}\n                      </span>\n                    </div>\n                  </div>                \n              </div>\n    `\n})\nexport class Infobox {\n    @Input()\n    style:string = 'basic'\n    @Input()\n    value1:string = null;\n    @Input()\n    value2:string = '';\n    @Input()\n    value3:string = '';\n    @Input()\n    icon:string = 'fa-plus';\n\n}\n\n"
  },
  {
    "path": "src/comps/lazy-image/lazy-image.ts",
    "content": "import {Directive, ElementRef, EventEmitter, Input, NgZone, Output} from \"@angular/core\";\nimport {Observable} from \"rxjs/Observable\";\nimport {Subject} from \"rxjs/Subject\";\n\n/**\n *  Usage\n *\n\n directive that allows you to load images which are deferred (not available right away)\n so image will be polled. While image is polled we can show default image as well as\n as loading image.\n\n usage:\n\n <img lazyImage class=\"center-block\" style=\"width: 229px; height: 130px\"\n [url]=\"['https://secure.digitalsignage.com/studioweb/assets/some_lazy1.png','https://secure.digitalsignage.com/studioweb/assets/some_lazy2.png']\"\n [loadingImage]=\"'https://secure.digitalsignage.com/studioweb/assets/screen_loading.png'\"\n [defaultImage]=\"'https://secure.digitalsignage.com/studioweb/assets/screen.png'\"\n [errorImage]=\"'https://secure.digitalsignage.com/studioweb/assets/screen_error.png'\"\n [retry]=\"5\"\n [delay]=\"1500\"\n (loaded)=\"_onLoaded()\"\n (error)=\"_onError()\"\n (completed)=\"_onCompleted()\">\n\n or to use via API\n\n ...\n\n @ViewChild(LazyImage)\n lazyImage: LazyImage;\n\n _lazyLoad() {\n     this.lazyImage.setUrl(['https://secure.digitalsignage.com/studioweb/assets/some_lazy.png']);\n }\n\n _resetSnapshotSelection() {\n    if (this.lazyImage)\n         this.lazyImage.resetToDefault();\n }\n\n _takeSnapshot() {\n     this.lazyImage.url = 'http://example.com/foo.png;\n }\n\n ...\n\n */\n\n@Directive({\n    selector: '[lazyImage]'\n})\nexport class LazyImage {\n\n    private m_urls: Array<string> = [];\n    private m_index = 0;\n    private cancel$ = new Subject();\n\n    constructor(private el: ElementRef, private ngZone: NgZone) {\n    }\n\n    // @Input('lazyImage') lazyImage;   // to change support to directive of: <img lazyImage=\"'http://www...'\" ...\n\n    @Output() loaded: EventEmitter<any> = new EventEmitter<any>();\n    @Output() completed: EventEmitter<any> = new EventEmitter<any>();\n    @Output() errored: EventEmitter<any> = new EventEmitter<any>();\n    @Input() defaultImage: string;\n    @Input() loadingImage: string;\n    @Input() errorImage: string;\n    @Input() retry: number = 5;\n    @Input() delay: number = 1000;\n\n    @Input()\n    set urls(i_urls: Array<string>) {\n        this.setUrls(i_urls)\n    }\n\n    setUrls(i_urls: Array<string>) {\n        this.m_index = 0;\n        this.m_urls = i_urls;\n        this.loadImage(i_urls);\n    }\n\n    public resetToDefault() {\n        this.setImage(this.el.nativeElement, this.defaultImage);\n        this.cancel$.next({})\n    }\n\n    ngAfterViewInit() {\n        this.setImage(this.el.nativeElement, this.defaultImage);\n    }\n\n    ngOnInit() {\n    }\n\n    setImage(element: HTMLElement, i_url) {\n        // const isImgNode = element.nodeName.toLowerCase() === 'img';\n        // if (isImgNode) {\n        // } else {\n        //     element.style.backgroundImage = `url('${imagePath}')`;\n        // }\n        (<HTMLImageElement>element).src = i_url;\n        return element;\n    }\n\n    loadImage(i_urls) {\n        const pollAPI$ = Observable.defer(() => {\n            return new Promise((resolve, reject) => {\n                const img = new Image();\n                var url;\n                if (i_urls[this.m_index]){\n                    url =  i_urls[this.m_index];\n                    this.m_index++;\n                } else {\n                    this.m_index = 0;\n                    url =  i_urls[this.m_index];\n                }\n                img.src = url;\n                img.onload = () => {\n                    resolve(url);\n                };\n                img.onerror = err => {\n                    this.setImage(this.el.nativeElement, this.loadingImage);\n                    reject(err)\n                };\n            })\n        }).retryWhen(err => {\n            return err.scan((errorCount, err) => {\n                if (errorCount >= this.retry) {\n                    throw err;\n                }\n                return errorCount + 1;\n            }, 0)\n                .delay(this.delay);\n        })\n            .takeUntil(this.cancel$)\n\n        pollAPI$.subscribe((v) => {\n            this.setImage(this.el.nativeElement, v)\n            this.loaded.emit();\n        }, (e) => {\n            this.setImage(this.el.nativeElement, this.errorImage);\n            this.errored.emit();\n            // console.error(e)\n        }, () => {\n            this.completed.emit();\n        })\n\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/comps/limited-access/limited-access.ts",
    "content": "import {Component, ChangeDetectionStrategy, AfterViewInit} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\n\n@Component({\n    selector: 'limited-access',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <h3>Limited access:</h3>\n        <hr/>\n        <div id=\"installPanel\">\n            <h4>You are login in to StudioLite with StudioPro credentials</h4>\n            <h5>\n                <b>This will result in limited functionality, please proceed to download StudioPro below...</b>\n            </h5>\n            <br/>\n            <div>\n                <div class=\"panel-group\" id=\"accordion\">\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseThree\">\n                                    <i class=\"installs fa fa-windows\"></i><span data-localize=\"signageWindows\">StudioPro for Windows</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseThree\" class=\"panel-collapse collapse\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li style=\"padding-top: 10px\">\n                                        <a href=\"http://galaxy.signage.me/code/install/exe/CloudSignageStudioSetup.exe\" class=\"helpLinks btn btn-primary btn-xl\">download now </a>\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h4 class=\"panel-title\">\n                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseFour\">\n                                    <i class=\"installs fa fa-apple\"></i><span data-localize=\"signageMac\">StudioPro for Mac</span></a>\n                            </h4>\n                        </div>\n                        <div id=\"collapseFour\" class=\"panel-collapse collapse\">\n                            <div class=\"panel-body\">\n                                <ul class=\"installopts\">\n                                    <li>\n                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"downloadAIR\"> download Adobe AIR runtime</span>\n                                        <a href=\"http://get.adobe.com/air/\" target=\"_blank\" class=\"helpLinks btn btn-primary btn-xs\">download</a>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"downloadSignagePlayer\"> download StudioPro for Mac</span>\n                                        <a target=\"_blank\" href=\"http://galaxy.signage.me/Code/Install/air/CloudSignageStudio.air\" type=\"button\" class=\"helpLinks btn btn-primary btn-xs\">\n                                            download\n                                        </a>\n                                    </li>\n                                    <li>\n                                        <b data-localize=\"step3\">Step 3:</b>\n                                        Install the runtime and proceed with installing StudioPro for Mac\n                                    </li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    `\n})\n\nexport class LimitedAccess {\n\n\n}\n"
  },
  {
    "path": "src/comps/loading/loading.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy} from '@angular/core'\n\n@Component({\n    selector: 'loading',\n    styles: [`\n        .spinner {\n            display: inline-block;\n            opacity: 1;\n            border: 3px solid rgba(0,0,0,.3);\n            border-radius: 50%;\n            border-top-color: #fff;\n            animation: spin 1s ease-in-out infinite;\n            -webkit-animation: spin 1s ease-in-out infinite;\n            height: 100px;\n            width: 100px;\n        }\n        @keyframes spin {\n            to { -webkit-transform: rotate(360deg); }\n        }\n        @-webkit-keyframes spin {\n            to { -webkit-transform: rotate(360deg); }\n        }\n        .center {\n            text-align: center\n        }\n    `],\n    template: `\n        <div class=\"center\" [ngStyle]=\"_style\">\n            <div [ngStyle]=\"_size\" class=\"spinner\"></div>\n        </div>\n    `,\n    changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class Loading {\n\n    _style: Object;\n    _size: Object;\n\n    @Input()\n    src: string = '';\n\n    @Input('style')\n    set style(i_style: Object) {\n        this._style = i_style;\n    }\n\n    @Input('size')\n    set size(i_size) {\n        this._size = {\n            opacity: 1,\n            height: i_size,\n            width: i_size\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/comps/logo/Logo.ts",
    "content": "import {Component, ElementRef, ChangeDetectionStrategy} from '@angular/core';\nimport {Observable} from \"rxjs/Observable\";\nimport 'rxjs/add/observable/of';\nimport 'rxjs/add/observable/fromEvent';\nimport 'rxjs/add/operator/do';\nimport 'rxjs/add/operator/merge';\nimport 'rxjs/add/operator/distinctUntilChanged';\n\n/**\n * Logo component for Application header\n * activated via elementRef and listen to mouse events via angular\n * adapter interface\n **/\n@Component({\n    selector: 'Logo',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <div id=\"logoContainer\" class=\"reshid flip\">\n            <div class=\"flipcard\">\n                <div class=\"face front\">\n                    <img class=\"img-responsive\" src=\"assets/logo_s.png\"/>\n                </div>\n                <div class=\"face back\">\n                    <img class=\"img-responsive\" src=\"assets/logo_b.png\"/>\n                </div>\n            </div>\n        </div>\n    `\n})\n\nexport class Logo {\n    constructor(private elementRef: ElementRef) {\n        this.listenMouse();\n    }\n\n    listenMouse(): void {\n        var over: Observable<any> = Observable.fromEvent(this.elementRef.nativeElement, 'mouseover').map(e => {\n            return Observable.of(1)\n        });\n        var out: Observable<any> = Observable.fromEvent(this.elementRef.nativeElement, 'mouseout').map(e => {\n            return Observable.of(0)\n        });\n        over.merge(out).distinctUntilChanged().subscribe(events => {\n            if (events.value) {\n                jQuery(this.elementRef.nativeElement).find('.flipcard').addClass('flipped');\n            } else {\n                jQuery(this.elementRef.nativeElement).find('.flipcard').removeClass('flipped');\n            }\n        }, (e) => console.error(e));\n    }\n}"
  },
  {
    "path": "src/comps/logo/reseller-logo.ts",
    "content": "import {Component, ChangeDetectionStrategy, AfterViewInit, ViewChild} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {LazyImage} from \"../lazy-image/lazy-image\";\nimport {UserModel} from \"../../models/UserModel\";\nimport {Observable} from \"rxjs/Observable\";\n\n@Component({\n    selector: 'reseller-logo',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <img lazyImage style=\"width: 43px; height: 25px;\"\n             [loadingImage]=\"'https://secure.digitalsignage.com/studioweb/assets/default_logo.png'\"\n             [defaultImage]=\"'https://secure.digitalsignage.com/studioweb/assets/default_logo.png'\"\n             [errorImage]=\"'https://secure.digitalsignage.com/studioweb/assets/default_logo.png'\"\n             [retry]=\"3\"\n             [delay]=\"500\"\n             (loaded)=\"_onLoaded()\"\n             (error)=\"_onError()\"\n             (completed)=\"_onCompleted()\">\n    `\n})\nexport class ResellerLogo extends Compbaser implements AfterViewInit {\n\n\n    constructor(private yp: YellowPepperService, private rp: RedPepperService) {\n        super();\n    }\n\n    @ViewChild(LazyImage)\n    lazyImage: LazyImage;\n\n    _onLoaded() {\n        // console.log('img loaded');\n    }\n\n    _onError() {\n        console.log('img error');\n    }\n\n    _onCompleted() {\n        // console.log('img completed');\n    }\n\n    ngAfterViewInit() {\n        this.cancelOnDestroy(\n            this.yp.listenUserModel()\n                .take(1)\n                .subscribe((i_userModel: UserModel) => {\n                    if (i_userModel.resellerId == 1)\n                        return;\n                    var urls = [\n                        `http://galaxy.signage.me/Resources/Resellers/${i_userModel.resellerId}/Logo.png`,\n                        `http://galaxy.signage.me/Resources/Resellers/${i_userModel.resellerId}/Logo.jpg`\n                    ];\n                    this.lazyImage.setUrls(urls);\n                }, (e) => console.error(e))\n        )\n\n    }\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}\n"
  },
  {
    "path": "src/comps/logout/Logout.ts",
    "content": "import {Component} from \"@angular/core\";\nimport {LocalStorage} from \"../../services/LocalStorage\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {MainAppShowStateEnum} from \"../../app/app-component\";\nimport {ACTION_UISTATE_UPDATE} from \"../../store/actions/appdb.actions\";\nimport {IUiState} from \"../../store/store.data\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {Compbaser} from \"ng-mslib\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\n@Component({\n    selector: 'Logout',\n    providers: [LocalStorage],\n    styles: [`\n        .fa {\n            display: inline-table;\n        }\n        .btn-xlarge {\n            vertical-align: center;\n            margin: 30px;\n            /*width: 100%;*/\n            padding: 48px 48px;\n            font-size: 22px;\n            color: white;\n            text-align: center;\n            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);\n            background: #62b1d0;\n            border: 0;\n            border-bottom: 3px solid #9FE8EF;\n            cursor: pointer;\n            -webkit-box-shadow: inset 0 -3px #9FE8EF;\n            box-shadow: inset 0 -3px #9FE8EF;\n            width: 250px;\n        }\n\n        .btn-xlarge:active {\n            top: 2px;\n            outline: none;\n            -webkit-box-shadow: none;\n            box-shadow: none;\n        }\n\n        .btn-xlarge:hover {\n            background: #a9a9a9;\n        }\n    `],\n    template: `\n        <div class=\"row\">\n            <div style=\"width: 700px; padding-top: 100px\" class=\"center-block\">\n                <button href=\"#\" (click)=\"_onSaveChangesLogout()\" class=\"btn btn-xlarge\"><i class=\"fa fa-floppy-o fa-4x\" ></i><h4 i18n>Save & Logout</h4></button>\n                <button href=\"#\" (click)=\"_onLogout()\" class=\"btn btn-xlarge\"><i class=\"fa fa-power-off fa-4x\" ></i><h4 i18n>Just Logout</h4></button>\n            </div>\n        </div>\n        `\n})\n\nexport class Logout extends Compbaser {\n    constructor(private localStorage: LocalStorage, private rp: RedPepperService, private yp:YellowPepperService) {\n        super();\n        this.cancelOnDestroy(\n            this.yp.listenMainAppState()\n                .subscribe((i_value: MainAppShowStateEnum) => {\n                    switch (i_value) {\n                        case MainAppShowStateEnum.SAVED: {\n                            this._onLogout();\n                            break;\n                        }\n                    }\n                }, (e) => console.error(e))\n        )\n    }\n\n    _onSaveChangesLogout(){\n        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.SAVE};\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}));\n    }\n\n    @timeout(500)\n    _onLogout() {\n        window.onbeforeunload = () => {\n        };\n        this.localStorage.removeItem('remember_me_studioweb');\n        this.localStorage.removeItem('no_show_limited');\n        let uiState: IUiState = {mainAppState: MainAppShowStateEnum.GOODBYE}\n        this.yp.ngrxStore.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        if (this.rp.getUserData().resellerID == 1)\n            jQuery('body').fadeOut(1000, function () {\n                window.location.replace('http://www.digitalsignage.com');\n            });\n    }\n}\n"
  },
  {
    "path": "src/comps/match-body-height/match-body-height.ts",
    "content": "import {Directive, ElementRef, HostListener, Input, AfterContentInit} from \"@angular/core\";\n\n@Directive({\n    selector: '[matchBodyHeight]'\n})\nexport class MatchBodyHeight implements AfterContentInit {\n\n    constructor(private el: ElementRef) {\n    }\n\n    // offset total height\n    @Input() matchBodyHeight:number = 50;\n\n    ngAfterContentInit() {\n        this.onResize();\n    }\n\n    @HostListener('window:resize')\n    onResize() {\n        var bodyHeight = jQuery('body').height() - this.matchBodyHeight;\n        jQuery(this.el.nativeElement).height(bodyHeight);\n    }\n\n    ngOnDestroy(){\n        // console.log('dest matchBodyHeight');\n    }\n}\n\n// import {timeout} from \"../../decorators/timeout-decorator\";\n// constructor { this.enableScroller() }\n// @timeout(500)\n// private enableScroller() {\n//     // jQuery('.ng-content-wrapper', this.el.nativeElement).css('overflow-y', 'scroll');\n// }\n// @HostBinding('style.overflow')\n// overFlow;\n//     jQuery('.ng-content-wrapper', this.el.nativeElement)\n//         .delay(500)\n//         .queue(function (next) {\n//             $(this).css('overflow-y', 'scroll');\n//             next();\n//         });"
  },
  {
    "path": "src/comps/media-player/media-player.ts",
    "content": "import {Component, Input} from \"@angular/core\";\nimport {VgAPI} from \"videogular2/core\";\n\n@Component({\n    selector: 'media-player',\n    template: `\n        <!--<button (click)=\"onSwap('https://s3.signage.me/business1000/resources/SceneComponentsLite.mp4','video/mp4')\">swap</button>-->\n\n        <vg-player (onPlayerReady)=\"onPlayerReady($event)\" style=\"width: 100%; height: 100%\">\n            <vg-overlay-play></vg-overlay-play>\n            <vg-buffering></vg-buffering>\n\n            <vg-scrub-bar>\n                <vg-scrub-bar-current-time></vg-scrub-bar-current-time>\n                <vg-scrub-bar-buffering-time></vg-scrub-bar-buffering-time>\n            </vg-scrub-bar>\n\n            <vg-controls [vgAutohide]=\"true\" [vgAutohideTime]=\"1.5\">\n                <vg-play-pause></vg-play-pause>\n                <vg-playback-button></vg-playback-button>\n\n                <vg-time-display vgProperty=\"current\" vgFormat=\"mm:ss\"></vg-time-display>\n\n                <vg-scrub-bar style=\"pointer-events: none;\"></vg-scrub-bar>\n\n                <vg-time-display vgProperty=\"left\" vgFormat=\"mm:ss\"></vg-time-display>\n                <vg-time-display vgProperty=\"total\" vgFormat=\"mm:ss\"></vg-time-display>\n\n                <vg-track-selector></vg-track-selector>\n                <vg-mute></vg-mute>\n                <vg-fullscreen></vg-fullscreen>\n                <vg-volume></vg-volume>\n\n\n            </vg-controls>\n\n            <video width=\"100%\" height=\"100%\" [vgMedia]=\"media\" #media id=\"singleVideo\" preload=\"auto\"> <!-- crossorigin -->\n                <source *ngFor=\"let video of sources\" [src]=\"video.src\" [type]=\"video.type\">\n                <!--<track kind=\"subtitles\" label=\"English\" src=\"http://static.videogular.com/assets/subs/pale-blue-dot.vtt\" srclang=\"en\" default>-->\n                <!--<track kind=\"subtitles\" label=\"Español\" src=\"http://static.videogular.com/assets/subs/pale-blue-dot-es.vtt\" srclang=\"es\">-->\n            </video>\n        </vg-player>\n    `\n})\nexport class MediaPlayer {\n    sources: Array<any>;\n    api: VgAPI\n\n    constructor() {\n        this.sources = [\n            {\n                src: \"http://s3.signage.me/business1000/resources/OfflineUpdate.mp4\",\n                type: \"video/mp4\"\n            }\n        ];\n    }\n\n    @Input()\n    set playResource(i_resource: string) {\n        this.onSwap(i_resource, 'video/mp4')\n    }\n\n    @Input() autoPlay:boolean = false;\n\n    onSwap(source: string, type: string) {\n        if (this.api) this.api.pause();\n        this.sources = new Array<Object>();\n        this.sources.push({\n            src: source,\n            type: type\n        });\n        setTimeout(() => {\n            this.api.getDefaultMedia().currentTime = 0;\n            if (this.api && this.autoPlay)\n                this.api.play();\n        }, 300)\n\n\n    }\n\n    getApi(): VgAPI {\n        return this.api;\n    }\n\n    onPlayerReady(i_api: VgAPI) {\n        this.api = i_api;\n        // this.api.fsAPI.toggleFullscreen()\n        // this.api.getDefaultMedia().subscriptions.ended.subscribe(\n        //     () => {\n        //         // Set the video to the beginning\n        //         this.api.getDefaultMedia().currentTime = 0;\n        //     }\n        // );\n    }\n}\n\n"
  },
  {
    "path": "src/comps/ng-menu/ng-menu-item.ts",
    "content": "import {Component, ChangeDetectionStrategy, Input} from \"@angular/core\";\nimport {NgMenu} from \"./ng-menu\";\nimport {Compbaser} from \"ng-mslib\";\n\n@Component({\n    selector: 'ng-menu-item',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n            \n           `,\n})\nexport class NgMenuItem extends Compbaser {\n\n    constructor(private ngMenu:NgMenu) {\n        super();\n        this.ngMenu.addMenuItem(this);\n    }\n\n    @Input() fontawesome:string;\n    @Input() title:string;\n    @Input() name:string;\n\n    get getTitle(): string {\n        return this.title;\n    }\n\n    get getName(): string {\n        return this.name;\n    }\n\n    get getFontAwesome(): string {\n        return this.fontawesome;\n    }\n\n\n    ngOnInit() {\n    }\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/comps/ng-menu/ng-menu.ts",
    "content": "import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from \"@angular/core\";\nimport {NgMenuItem} from \"./ng-menu-item\";\nimport {CommBroker, IMessage} from \"../../services/CommBroker\";\nimport {Router} from \"@angular/router\";\nimport {Compbaser} from \"ng-mslib\";\nimport {Consts} from \"../../interfaces/Consts\";\n\n@Component({\n    selector: 'ng-menu',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <ng-container *ngIf=\"fileMenuMode\">\n            <div class=\"row\">\n                <section id=\"appNavigatorWasp\" class=\"appMenu fill hidden-xs hidden-sm hidden-md col-lg-1\">\n                    <li *ngFor=\"let item of items\" (click)=\"listenMenuSelected(item, $event)\" data-ripple-color=\"white\" class=\"btn btn-default list-group-item navicons\">\n                        <i *ngIf=\"!m_hidden\" (click)=\"listenMenuSelected(item, $event)\" class=\"iconSize fa {{item.getFontAwesome}}\"></i>\n                        <span (click)=\"listenMenuSelected(item, $event)\">{{item.getTitle}}</span>\n                    </li>\n                </section>\n            </div>\n\n        </ng-container>\n        <ng-container *ngIf=\"!fileMenuMode\">\n            <div>\n                <div class=\"m_fileMenuWrap\">\n                    <ul class=\"nav navbar-nav\">\n                        <li id=\"commonFileMenu\" class=\"hidden-lg\" dropdown>\n                            <a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">Menu<b class=\"caret\"></b></a>\n                            <ul class=\"dropdown-menu\">\n                                <li class=\"divider\"></li>\n                                <li *ngFor=\"let item of items\" (click)=\"listenMenuSelected(item, $event)\">\n                                    <a href=\"#\" (click)=\"listenMenuSelected(item,$event)\">{{item.getTitle}}</a>\n                                </li>\n                                <li class=\"divider\"></li>\n                            </ul>\n                        </li>\n                    </ul>\n                </div>\n            </div>\n        </ng-container>\n\n    `,\n    styles: [`\n        .appMenu {\n            background: #3e3f48;\n        }\n\n        .navicons {\n            font-size: 0.9em;\n            position: relative;\n            top: 2px;\n            left: 0px;\n            text-align: left;\n            padding-right: 5px;\n        }\n\n        .iconSize {\n            font-size: 1.3em;\n            padding-right: 20px;\n        }\n    `]\n})\nexport class NgMenu extends Compbaser {\n\n    constructor(private router: Router, private commBroker: CommBroker, private cd: ChangeDetectorRef) {\n        super();\n    }\n\n    ngOnInit() {\n        this.m_hidden = false;\n        this.listenWinResize()\n    }\n\n    @Input() fileMenuMode: boolean = true;\n    @Input() routePrefix: string = '';\n\n    public items: Array<NgMenuItem> = [];\n    public m_hidden: boolean = true;\n\n    private listenWinResize() {\n        this.commBroker.onEvent(Consts.Events().WIN_SIZED).subscribe((e: IMessage) => {\n            if (e.message.width < Consts.Values().MENU_MIN_ICON_SHOW) {\n                this.m_hidden = true;\n            } else {\n                this.m_hidden = false;\n            }\n            this.cd.markForCheck();\n        }, (e) => console.error(e));\n    }\n\n    private listenMenuSelected(ngMenuItem:NgMenuItem, event: MouseEvent) {\n        event.preventDefault();\n        this.router.navigate([`/${this.routePrefix}/${ngMenuItem.name}`]);\n    }\n\n    public addMenuItem(i_item: NgMenuItem): void {\n        this.items.push(i_item);\n    }\n\n\n    destroy() {\n    }\n}"
  },
  {
    "path": "src/comps/panel-split/panel-split-container.ts",
    "content": "import {Component, ChangeDetectionStrategy, ElementRef, ContentChild, AfterViewInit} from \"@angular/core\";\nimport {PanelSplitMain} from \"./panel-split-main\";\nimport {PanelSplitSide} from \"./panel-split-side\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'panel-split-container',\n    template: `\n            <div class=\"row\">            \n                <ng-content></ng-content>\n            </div>\n    `\n})\nexport class PanelSplitContainer implements AfterViewInit {\n    constructor(private el: ElementRef) {\n    }\n\n    @ContentChild(PanelSplitMain)\n    panelSpiltMain: PanelSplitMain\n\n    @ContentChild(PanelSplitSide)\n    panelSplitSide: PanelSplitSide\n\n    ngAfterViewInit() {\n        if (!this.panelSpiltMain || !this.panelSplitSide)\n            throw new Error('panel-split-container requires main and side children');\n        this.panelSplitSide.onToggle.subscribe((value: boolean) => {\n            this.panelSpiltMain.setFullScreen(value)\n        }, (e) => console.error(e))\n    }\n\n}\n\n"
  },
  {
    "path": "src/comps/panel-split/panel-split-main.ts",
    "content": "import {Component, ChangeDetectionStrategy, ElementRef} from \"@angular/core\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'panel-split-main',\n\n    styles: [`\n        .mainPanelWrap {\n            -webkit-transition: width 1s ease, margin 1s ease;\n            -moz-transition: width 1s ease, margin 1s ease;\n            -o-transition: width 1s ease, margin 1s ease;\n            transition: width 1s ease, margin 1s ease;\n        }\n        button {\n            width: 200px;\n            margin: 5px;\n        }\n        .mainPanelWrap {\n            padding: 0;\n            margin: 0;\n        }\n      \n    `],\n    template: `\n            <div #parentdiv class=\"col-xs-7 col-sm-8 col-md-9 col-lg-10 mainPanelWrap\">\n                <div class=\"ng-content-wrapper\">\n                    <ng-content></ng-content>\n                </div>\n            </div>\n    `\n})\nexport class PanelSplitMain {\n\n    constructor(private el: ElementRef) {\n    }\n\n    setFullScreen(value) {\n        if (!value) {\n            // full screen\n            jQuery(this.el.nativeElement).find('.mainPanelWrap').removeClass('col-xs-7 col-sm-8 col-md-9 col-lg-10')\n            jQuery(this.el.nativeElement).find('.mainPanelWrap').addClass('col-xs-12')\n        } else {\n            jQuery(this.el.nativeElement).find('.mainPanelWrap').addClass('col-xs-7 col-sm-8 col-md-9 col-lg-10')\n            jQuery(this.el.nativeElement).find('.mainPanelWrap').removeClass('col-xs-12')\n        }\n    }\n}\n\n\n;"
  },
  {
    "path": "src/comps/panel-split/panel-split-side.ts",
    "content": "import {Component, ChangeDetectionStrategy, ElementRef, Output, EventEmitter} from \"@angular/core\";\n\n@Component({\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    selector: 'panel-split-side',\n    styles: [`\n        .propPanelWrap {\n            position: fixed;\n            /*min-height: 100%;*/\n            /*max-height: 100%;*/\n            right: 0;\n            top: 0;\n            height: 100%;\n            overflow: hidden;\n            -webkit-transition: width 1s ease, margin 1s ease;\n            -moz-transition: width 1s ease, margin 1s ease;\n            -o-transition: width 1s ease, margin 1s ease;\n            transition: width 1s ease, margin 1s ease;\n            background-color: #ffffff;\n            margin: 0;\n            z-index: 200;\n            border-left: 2px #c9c9c9 solid;\n        }\n\n        .toggleArrow {\n            font-size: 1.5em;\n            color: #313335\n        }\n\n        .restorePanel {\n            position: absolute;\n            right: 0;\n            top: 3px;\n        }\n\n        .fa-arrow-circle-right {\n            padding-top: 60px;\n        }\n    `],\n    template: `\n        <!--<div class=\"hidden-xs hidden-sm restorePanel\" *ngIf=\"!showSidePanel\">-->\n        <div class=\"restorePanel\" *ngIf=\"!showSidePanel\">\n            <a href=\"#\" class=\"toggleArrow btn fa fa-arrow-circle-left\" (click)=\"_toggle($event)\"></a>\n        </div>\n\n        <!--<div class=\"hidden-xs hidden-sm col-md-2 col-lg-2 propPanelWrap\">-->\n        <div class=\"col-xs-5 col-sm-4 col-md-3 col-lg-2 propPanelWrap\">\n            <a href=\"#\" class=\"toggleArrow btn fa fa-arrow-circle-right\" (click)=\"_toggle($event)\"></a>\n            <ng-content></ng-content>\n        </div>\n    `\n})\nexport class PanelSplitSide {\n\n    constructor(private el: ElementRef) {\n    }\n\n    @Output()\n    onToggle: EventEmitter<boolean> = new EventEmitter<boolean>();\n\n    showSidePanel: boolean = true;\n\n    _toggle(event: MouseEvent) {\n        event.preventDefault();\n        this.showSidePanel = !this.showSidePanel;\n        this.onToggle.emit(this.showSidePanel);\n        if (this.showSidePanel) {\n            jQuery(this.el.nativeElement).find('.propPanelWrap').addClass('col-xs-7 col-sm-8 col-md-9 col-lg-10')\n            jQuery(this.el.nativeElement).find('.propPanelWrap').fadeIn('50')\n        } else {\n            jQuery(this.el.nativeElement).find('.propPanelWrap').fadeOut(0)\n            jQuery(this.el.nativeElement).find('.propPanelWrap').removeClass('col-xs-7 col-sm-8 col-md-9 col-lg-10')\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/comps/screen-template/screen-template.ts",
    "content": "/**\n The class generates the UI for a template (a.k.a Screen Division) that is\n a selectable widget including the drawing of each viewer (division) within\n the screen, as well as firing related click events on action.\n @param {object} i_screenTemplateData hold data as instructions for factory creation component\n @param {String} i_type the type of widget that we will create. This includes\n VIEWER_SELECTABLE as well as ENTIRE_SELECTABLE with respect to the ability to select the components viewers individually\n or the entire screen division\n @param {object} i_owner the owner of this class (parent) that we can query at the listening end, to examine if the event is\n of any interest to the listener.\n\n\n This is a key event in the framework as many different instances subscribe to ON_VIEWER_SELECTED to reconfigure\n themselves. The event is fired when a viewer (i.e.: a screen division) is selected inside a Template (i.e. Screen).\n The key to remember is that the Factory instance (this) is always created with respect to it's owner (i_owner),\n so when ON_VIEWER_SELECTED is fired, the owner is carried with the event so listeners can act accordingly, and only if the owner\n is of interest to a subscribed listener.\n **/\n\nimport {ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output} from \"@angular/core\";\nimport {Compbaser} from \"ng-mslib\";\nimport * as _ from \"lodash\";\nimport {Lib} from \"../../Lib\";\nimport {OrientationEnum} from \"../../app/campaigns/campaign-orientation\";\nimport {IScreenTemplateData} from \"../../interfaces/IScreenTemplate\";\n\n\n@Component({\n    selector: 'screen-template',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `<!--<small class=\"debug\">{{me}}</small>-->`,\n})\nexport class ScreenTemplate extends Compbaser {\n\n    private created = false;\n    private m_mouseHoverEffect = false;\n    private m_campaign_timeline_id = -1;\n\n    constructor(private el: ElementRef) {\n        super();\n    }\n\n    ngAfterViewInit(){\n        if (this.m_mouseHoverEffect)\n            this._mouseOverEffect()\n        this.m_mouseHoverEffect = false;\n    }\n\n    @Output()\n    onDivisionDoubleClicked: EventEmitter<any> = new EventEmitter<any>();\n\n    @Input()\n    set mouseHoverEffect(i_value) {\n        this.m_mouseHoverEffect = i_value;\n    }\n\n    @Input()\n    set setTemplate(i_screenTemplateData: IScreenTemplateData) {\n        if (this.created) return\n        this.created = true;\n        // this.m_selfDestruct = i_screenTemplateData.i_selfDestruct;\n        this.m_myElementID = 'svgScreenLayout' + '_' + _.uniqueId();\n        this.m_screenTemplateData = i_screenTemplateData;\n        this.m_orientation = i_screenTemplateData['orientation'];\n        this.m_resolution = i_screenTemplateData['resolution'];\n        this.m_screenProps = i_screenTemplateData['screenProps'];\n        this.m_scale = i_screenTemplateData['scale'];\n        this.m_svgWidth = (this.m_resolution.split('x')[0]) / this.m_scale;\n        this.m_svgHeight = (this.m_resolution.split('x')[1]) / this.m_scale;\n        this.m_useLabels = false;\n        this._create()\n        // this.selectableFrame();\n\n        this._mouseDoubleClickDivision();\n    }\n\n    m_selfDestruct;\n    m_screenTemplateData;\n    m_myElementID;\n    m_orientation;\n    m_resolution;\n    m_screenProps;\n    m_scale;\n    m_svgWidth;\n    m_svgHeight;\n    m_useLabels;\n\n    /**\n     Method is called when an entire screen frame of the UI is clicked, in contrast to when a single viewer is selected.\n     The difference in dispatch of the event depends on how the factory created this instance.\n     @method _onViewSelected\n     @param {Event} e\n     @param {Object} i_caller\n     @return {Boolean} false\n     **/\n    private _onViewSelected(e, i_caller) {\n        var self = i_caller;\n        var element = e.target;\n\n        var campaign_timeline_board_viewer_id = jQuery(element).data('campaign_timeline_board_viewer_id');\n        var campaign_timeline_id = jQuery(element).data('campaign_timeline_id');\n\n        var screenData = {\n            sd: jQuery(element).data('sd'),\n            elementID: i_caller.m_myElementID,\n            // owner: i_caller.getOwner(),\n            campaign_timeline_board_viewer_id: campaign_timeline_board_viewer_id,\n            campaign_timeline_id: campaign_timeline_id,\n            screenTemplateData: self.m_screenTemplateData\n        };\n        self._deselectViewers();\n        // BB.comBroker.fire(BB.EVENTS.ON_VIEWER_SELECTED, this, screenData);\n    }\n\n    /**\n     Deselect all viewers, thus change their colors back to default.\n     @method _deselectViewers\n     @return none\n     **/\n    private _deselectViewers() {\n        var self = this;\n        jQuery('.screenDivisionClass', self.el.nativeElement).each(function () {\n            if (jQuery(this).is('rect')) {\n                jQuery(this).css({'fill': 'rgb(230,230,230)'});\n            }\n        });\n    }\n\n\n    /**\n     When enabled, _mouseOverEffect will highlight viewers when mouse is hovered over them.\n     @method _mouseOverEffect\n     @return none\n     **/\n    private _mouseOverEffect() {\n        var self = this;\n        // var a = jQuery('#' + self.m_myElementID);\n        // var b = jQuery('#' + self.m_myElementID).find('rect');\n        jQuery('#' + self.m_myElementID, self.el.nativeElement).find('rect').each(function () {\n            jQuery(this).on('mouseover', function () {\n                jQuery(this).css({'fill': 'rgb(190,190,190)'});\n            }).mouseout(function () {\n                jQuery(this).css({'fill': 'rgb(230,230,230)'});\n            });\n        });\n    }\n\n    private _mouseDoubleClickDivision() {\n        var self = this;\n        // var a = jQuery('#' + self.m_myElementID);\n        // var b = jQuery('#' + self.m_myElementID).find('rect');\n\n        jQuery('#' + self.m_myElementID, self.el.nativeElement).find('rect').each(function () {\n            jQuery(this).on('dblclick', function () {\n                var e = jQuery(this).data('campaign_timeline_board_viewer_id');\n                self.onDivisionDoubleClicked.emit(e)\n            });\n        });\n    }\n\n\n    // Get the owner (parent) of this instance, i.e., the one who created this.\n    // We use the owner attribute as a way to distinguish what type of instance this was created as.\n    // @method getOwner\n    // @return {Object} m_owner\n    //\n    // getOwner() {\n    //     var self = this;\n    //     return self.m_owner;\n    // }\n    //\n    /**\n     Create all the screen divisions (aka viewers) as svg snippets and push them into an array\n     @method getDivisions\n     @return {array} f array of all svg divisions\n     **/\n    getDivisions() {\n        var self = this;\n        var svg = self._create();\n        return $(svg).find('rect');\n\n        // var f = $(svg).find('rect').map(function (k, v) {\n        //     return '<svg style=\"padding: 0px; margin: 15px\" width=\"20px\" height=\"20px\" xmlns=\"http://www.w3.org/2000/svg\">  ' +\n        //         '<g>' +\n        //         v.outerHTML +\n        //         '</g> ' +\n        //         '</svg>';\n        // });\n        // return f;\n    }\n\n    /**\n     Create will produce the actual SVG based Template (screen) with inner viewers and return HTML snippet to the caller.\n     @method create\n     @return {Object} html element produced by this factory\n     **/\n    private _create() {\n        var self = this;\n        var screensDivisons = '';\n        var screenLabels = '';\n\n        // sort for proper z-order creating the viewers\n        var orderedScreenValues = [], i = 0;\n        for (var screenValues in self.m_screenProps) {\n            var viewOrder = self.m_screenProps[screenValues]['view_order'];\n            viewOrder = _.isUndefined(viewOrder) ? i : viewOrder;\n            orderedScreenValues[viewOrder] = self.m_screenProps[screenValues];\n            i++;\n        }\n\n        // create the viewers\n        i = 0;\n        for (var ordered in orderedScreenValues) {\n            i++;\n            var screenValue = orderedScreenValues[ordered];\n            var x = screenValue['x'] == 0 ? 0 : screenValue['x'] / self.m_scale;\n            var y = screenValue['y'] == 0 ? 0 : screenValue['y'] / self.m_scale;\n            var w = screenValue['w'] == 0 ? 0 : screenValue['w'] / self.m_scale;\n            var h = screenValue['h'] == 0 ? 0 : screenValue['h'] / self.m_scale;\n            var campaign_timeline_board_viewer_id = screenValue['campaign_timeline_board_viewer_id'];\n            var campaign_timeline_id = self.m_campaign_timeline_id = screenValue['campaign_timeline_id'];\n            var sd = screenValues;\n\n            var uniqueID = 'rectSD' + '_' + _.uniqueId();\n            if (self.m_useLabels == true)\n                screenLabels += '<text class=\"screenDivisionClass\"' + '\" data-for=\"' + uniqueID + '\" x=\"' + (x + (w / 2)) + '\" y=\"' + (y + (h / 2)) + '\" font-family=\"sans-serif\" font-size=\"12px\" text-anchor=\"middle\" alignment-baseline=\"middle\" fill=\"#666\">' + i + '</text>';\n\n            screensDivisons += '<rect id=\"' + uniqueID +\n                '\" data-campaign_timeline_board_viewer_id=\"' + campaign_timeline_board_viewer_id +\n                '\" data-campaign_timeline_id=\"' + campaign_timeline_id +\n                '\" x=\"' + x +\n                '\" y=\"' + y +\n                '\" width=\"' + w +\n                '\" height=\"' + h +\n                '\" data-sd=\"' + sd +\n                '\" class=\"screenDivisionClass\"' +\n                '  style=\"fill:rgb(230,230,230);stroke-width:2;stroke:rgb(72,72,72)\"/>';\n        }\n        var snippet = (jQuery('<svg class=\"svgSD\" id=\"' + self.m_myElementID + '\" width=\"' + self.m_svgWidth + '\" height=\"' + self.m_svgHeight + '\" xmlns=\"http://www.w3.org/2000/svg\">  ' +\n            '<g>' +\n            screensDivisons +\n            screenLabels +\n            '</g> ' +\n            '</svg>'));\n        jQuery(self.el.nativeElement).append(snippet);\n        return snippet;\n    }\n\n    /**\n     When enabled, selectableFrame will allow for UI mouse / click of the outer frame of the template (screen) and not\n     individual viewers.\n     @method selectableFrame\n     @return none\n     **/\n    selectableFrame() {\n        var self = this;\n        var applyToSelected = function (e) {\n            jQuery('#' + self.m_myElementID, self.el.nativeElement).parent().find('rect').css({\n                'stroke-width': '2',\n                'stroke': 'rgb(72,72,72)'\n            });\n            jQuery('#' + self.m_myElementID, self.el.nativeElement).find('rect').css({'stroke-width': '2', 'stroke': Lib.GetThemeColor()});\n            self._onViewSelected(e, self);\n        }\n        // listen one\n        if (self.m_selfDestruct) {\n            jQuery('.screenDivisionClass', '#' + self.m_myElementID).one('mouseup contextmenu', function (e) {\n                applyToSelected(e);\n            });\n\n        } else {\n            // listen on\n            jQuery('.screenDivisionClass', '#' + self.m_myElementID).on('mouseup contextmenu', function (e) {\n                applyToSelected(e);\n            });\n        }\n    }\n\n    get campaignTimelineId(){\n        return this.m_campaign_timeline_id;\n    }\n    \n    /**\n     When enabled, selectableFrame will allow for UI mouse / click of the outer frame of the template (screen) and not\n     individual viewers.\n     @method selectableFrame\n     @return none\n     **/\n    selectFrame() {\n        jQuery('#' + this.m_myElementID, this.el.nativeElement).parent().find('rect').css({\n            'stroke-width': '2',\n            'stroke': 'rgb(72,72,72)'\n        });\n        jQuery('#' + this.m_myElementID, this.el.nativeElement).find('rect').css({'stroke-width': '2', 'stroke': Lib.GetThemeColor()});\n        // this._onViewSelected(e, this);\n    }\n\n    deSelectFrame() {\n        jQuery('#' + this.m_myElementID, this.el.nativeElement).parent().find('rect').css({\n            'stroke-width': '2',\n            'stroke': 'rgb(72,72,72)'\n        });\n    }\n\n\n    /**\n     The public method version of _deselectViewers, which de-selects all viewers\n     @method deselectDivisons\n     **/\n    deselectDivisons() {\n        var self = this;\n        self._deselectViewers();\n    }\n\n    /**\n     Select a division (aka viewer) using it's viewer_id, only applicable when class represents an actual timelime > board > viewer_id\n     @method selectDivison\n     @param {Number} i_campaign_timeline_board_viewer_id\n     **/\n    selectDivison(i_campaign_timeline_board_viewer_id) {\n        var self = this;\n        self._deselectViewers();\n        var selectedElement = jQuery('#' + self.m_myElementID, self.el.nativeElement).find('[data-campaign_timeline_board_viewer_id=\"' + i_campaign_timeline_board_viewer_id + '\"]');\n        // jQuery(selectedElement).css({'fill': Lib.GetThemeColor()});\n        jQuery(selectedElement).css({'fill': '#aed0ed'});\n    }\n\n    destroy() {\n        var self = this;\n        jQuery('.screenDivisionClass', '#' + self.m_myElementID).off('mouseup contextmenu');\n        jQuery('.screenDivisionClass', self.el.nativeElement).off('click contextmenu', function (e) {\n            self._onViewSelected(e, self);\n        });\n        jQuery(this).off('mouseover', function () {\n            jQuery(this).css({'fill': 'rgb(190,190,190)'});\n        }).mouseout(function () {\n            jQuery(this).css({'fill': 'rgb(230,230,230)'});\n        });\n\n        jQuery('#' + this.m_myElementID, self.el.nativeElement).find('rect').each(function () {\n            jQuery(this).off();\n        });\n\n        // jQuery.each(self, function (k) {\n        //     self[k] = undefined;\n        // });\n    }\n}"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGrid.css",
    "content": ".simpleTable {\n    background-color: white;\n}\n\n* {\n    font-size: 0.9em;\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGrid.ts",
    "content": "import {SimpleGridData} from \"./SimpleGridData\";\nimport {SimpleGridTable} from \"./SimpleGridTable\";\nimport {SimpleGridSortableHeader} from \"./SimpleGridSortableHeader\";\nimport {SimpleGridRecord} from \"./SimpleGridRecord\";\nimport {SimpleGridDataImage} from \"./SimpleGridDataImage\";\nimport {SimpleGridDataCurrency} from \"./SimpleGridDataCurrency\";\nimport {StoreModel} from \"../../models/StoreModel\";\nimport {SimpleGridDataChecks} from \"./SimpleGridDataChecks\";\nimport {SimpleGridDataDropdown} from \"./SimpleGridDataDropdown\";\n\nexport const SIMPLEGRID_DIRECTIVES:Array<any> = [SimpleGridTable, SimpleGridSortableHeader, SimpleGridRecord, SimpleGridData, SimpleGridDataCurrency, SimpleGridDataImage, SimpleGridDataChecks, SimpleGridDataDropdown];\n\nexport interface ISimpleGridEdit {\n    value:string;\n    item:StoreModel;\n}\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridData.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core'\nimport {StoreModel} from \"../../models/StoreModel\";\nimport {ISimpleGridEdit} from \"./SimpleGrid\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\n\n@Component({\n    selector: 'td[simpleGridData]',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        label {\n            padding: 0;\n            margin: 0;\n        }\n        .editableLabel {\n            cursor: pointer;\n        }\n        input {\n            padding: 0;\n            margin: 0;\n        }\n        a {\n            cursor: pointer;\n        }\n    `],\n    template: `\n         <label [ngClass]=\"{editableLabel: _editable}\" *ngIf=\"!_editing\" (click)=\"onEdit(true)\">{{value}}</label>\n         <span *ngIf=\"_editing\">\n            <input [value]=\"value\" [(ngModel)]=\"value\"/>\n                <a (click)=\"onEdit(false)\" class=\"fa fa-check\"></a>\n         </span>\n         \n         <!--<img src=\"{{ item.iconPath }}\" style=\"width: 40px; height: 40px\"/>-->\n         <!--&lt;!&ndash; <td [innerHtml]=\"item.day\"></td> &ndash;&gt;-->\n    `\n})\nexport class SimpleGridData {\n    value:string = '';\n    private storeModel:StoreModel;\n    private _editable:boolean|string = false;\n    _editing:boolean = false;\n\n    @Input()\n    set item(i_storeModel:StoreModel) {\n        this.storeModel = i_storeModel\n    }\n\n    @Input()\n    set field(i_field) {\n        this.value = this.storeModel.getKey(i_field)\n    }\n\n    @Input()\n    set processField(i_processField:(storeModel:StoreModel)=>string) {\n        this.value = i_processField(this.storeModel)\n    }\n\n    @Input()\n    set editable(i_editable) {\n        this._editable = i_editable;\n    }\n\n    @Output()\n    labelEdited:EventEmitter<any> = new EventEmitter();\n\n    onEdit(isEditing:boolean) {\n        if (this._editable == false || this._editable == 'false')\n            return;\n        this._editing = isEditing;\n        if (this._editing)\n            return;\n        // done editing, so notify\n        var payload:ISimpleGridEdit = {\n            value: this.value,\n            item: this.storeModel\n        }\n        this.labelEdited.emit(payload);\n\n    }\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridDataChecks.ts",
    "content": "import {Component, Input, Output, EventEmitter, ViewChildren, QueryList, ChangeDetectorRef} from \"@angular/core\";\nimport {List} from \"immutable\";\nimport {StoreModel} from \"../../models/StoreModel\";\nimport * as _ from \"lodash\";\n\n@Component({\n    selector: 'td[simpleGridDataChecks]',\n    styles: [`\n        i {\n            cursor: pointer;\n        }\n        .slideMode {\n            padding-top: 8px;\n            padding-right: 20px;\n        }\n    `],\n    template: `\n        <div *ngIf=\"!slideMode\">\n            <div *ngFor=\"let item of m_checkboxes\">\n              <label class=\"pull-left\">{{item.name}}</label>\n              <Input (click)=\"onClick()\" #checkInputs type=\"checkbox\" [checked]=\"item\" value=\"{{item}}\" class=\"pull-left\" style=\"margin-right: 2px\">\n            </div>\n        </div>\n        <div *ngIf=\"slideMode\" class=\"slideMode\">\n            <div *ngFor=\"let item of m_checkboxes\" class=\"material-switch pull-right\">\n              <Input id=\"{{m_checkId}}\"(mouseup)=\"onClick()\" (click)=\"onClick()\" #checkInputs type=\"checkbox\" [checked]=\"item\" value=\"{{item}}\" class=\"pull-left\" style=\"margin-right: 2px\">\n              <label [attr.for]=\"m_checkId\" class=\"label-primary\"></label>\n          </div>\n        </div>\n    `\n})\nexport class SimpleGridDataChecks {\n    constructor(private cdr: ChangeDetectorRef) {\n    }\n\n    m_checkId = _.uniqueId('slideCheck');\n    m_checkboxes: List<any>\n    private m_storeModel: StoreModel;\n\n    @ViewChildren('checkInputs')\n    inputs: QueryList<any>\n\n    @Input()\n    set checkboxes(i_checkboxes: List<any>) {\n        this.m_checkboxes = i_checkboxes\n    }\n\n    @Input()\n    set item(i_storeModel: StoreModel) {\n        this.m_storeModel = i_storeModel\n    }\n\n    @Input()\n    slideMode: boolean = false;\n\n    @Output()\n    changed: EventEmitter<any> = new EventEmitter();\n\n    //@HostListener('click', ['$event'])\n    private onClick(e) {\n        this.cdr.detach();\n        let values = []\n        this.inputs.map(v => {\n            values.push(v.nativeElement.checked);\n        });\n        this.changed.emit({item: this.m_storeModel, value: values});\n        return true;\n    }\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridDataCurrency.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core'\nimport {StoreModel} from \"../../models/StoreModel\";\nimport {ISimpleGridEdit} from \"./SimpleGrid\";\n\n@Component({\n    selector: 'td[simpleGridDataCurrency]',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        label {\n            padding: 0;\n            margin: 0;\n        }\n    `],\n    template: `\n         <label>{{value | currency:'USD':true}}</label>         \n    `\n})\nexport class SimpleGridDataCurrency {\n    value:string = '';\n    storeModel:StoreModel;\n\n    @Input()\n    set item(i_storeModel:StoreModel) {\n        this.storeModel = i_storeModel\n    }\n\n    @Input()\n    set field(i_field) {\n        this.value = this.storeModel.getKey(i_field)\n    }\n\n    @Input()\n    set processField(i_processField:(storeModel:StoreModel)=>string) {\n        this.value = i_processField(this.storeModel)\n    }\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridDataDropdown.ts",
    "content": "import {\n    Component, Input, ChangeDetectionStrategy, Output, EventEmitter, ViewChildren, QueryList, HostListener\n} from '@angular/core'\nimport {List} from \"immutable\";\nimport {StoreModel} from \"../../models/StoreModel\";\n\n@Component({\n    selector: 'td[simpleGridDataDropdown]',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        i {\n            cursor: pointer;\n        }\n\n        .select button {\n            width: 100%;\n            text-align: left;\n        }\n\n        .select .caret {\n            position: absolute;\n            right: 10px;\n            margin-top: 10px;\n        }\n\n        .select:last-child > .btn {\n            border-top-left-radius: 5px;\n            border-bottom-left-radius: 5px;\n        }\n\n        .selected {\n            padding-right: 10px;\n        }\n\n        .option {\n            width: 100%;\n        }\n    `],\n    template: `\n        <div class=\"btn-group\">\n            <!--<select class=\"form-control longInput\" [ngFormControl]=\"notesForm.controls['privileges']\">-->\n            <select (change)=\"onChanges($event)\" class=\"form-control custom longInput\">\n                <option *ngFor=\"let dropItem of m_dropdown\" [selected]=\"getSelected(dropItem)\">{{dropItem.getKey(m_field)}}</option>\n            </select>\n        </div>\n        <!--<div *ngFor=\"let item of m_checkboxes\">-->\n        <!--<label class=\"pull-left\">{{item.name}}</label>-->\n        <!--<Input #checkInputs type=\"checkbox\" [checked]=\"item.checked\" value=\"{{item.value}}\" class=\"pull-left\" style=\"margin-right: 2px\">-->\n        <!--</div>-->\n    `\n})\nexport class SimpleGridDataDropdown {\n\n    m_dropdown: List<StoreModel>\n    m_storeModel: StoreModel;\n    m_field: string = '';\n    value: string = '';\n    m_testSelection: Function;\n\n    @ViewChildren('checkInputs')\n    inputs: QueryList<any>\n\n    @Input()\n    set dropdown(i_dropdown: List<any>) {\n        this.m_dropdown = i_dropdown\n    }\n\n    @Input()\n    set item(i_storeModel: StoreModel) {\n        this.m_storeModel = i_storeModel\n    }\n\n    @Input()\n    set field(i_field) {\n        this.m_field = i_field;\n    }\n\n    @Input()\n    set testSelection(i_testSelection: (dropItem: any, storeModel: StoreModel) => 'checked' | '') {\n        this.m_testSelection = i_testSelection;\n    }\n\n    @Output()\n    changed: EventEmitter<any> = new EventEmitter();\n\n    onChanges(event) {\n        this.changed.emit({item: this.m_storeModel, value: event.target.value});\n    }\n\n    private getSelected(i_dropItem): string {\n        if (this.m_testSelection) {\n            return this.m_testSelection(i_dropItem, this.m_storeModel);\n        }\n        return '';\n    }\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridDataImage.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy} from '@angular/core'\nimport {StoreModel} from \"../../models/StoreModel\";\n\n@Component({\n    selector: 'td[simpleGridDataImage]',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        i {\n            cursor: pointer;\n        }\n    `],\n    template: `\n        <i (click)=\"onClick($event)\" [ngStyle]=\"style\" class=\"fa {{value}}\"></i>\n        <!--<i (click)=\"onClick($event)\" style=\"color: {{color}}; font-size: 1.5em\" class=\"fa {{value}}\"></i>-->\n         <!--<img src=\"{{ value }}\" style=\"width: 40px; height: 40px\"/>-->\n    `\n})\nexport class SimpleGridDataImage {\n    value;\n    style;\n    storeModel:StoreModel;\n\n    @Input()\n    set item(i_storeModel:StoreModel) {\n        this.storeModel = i_storeModel\n    }\n\n    @Input()\n    set field(i_field) {\n        this.value = i_field;\n    }\n    \n    @Input()\n    set color(i_color:string) {\n        this.style = {\n            color: i_color\n        }\n    }\n\n    onClick(event){\n    }\n\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridDraggable.ts",
    "content": "import {\n    ContentChildren,\n    Directive,\n    ElementRef,\n    EventEmitter,\n    forwardRef,\n    Inject,\n    Output,\n    QueryList\n} from \"@angular/core\";\nimport {SimpleGridTable} from \"./SimpleGridTable\";\nimport {timeout} from \"../../decorators/timeout-decorator\";\nimport {SimpleGridRecord} from \"./SimpleGridRecord\";\nimport {Subscription} from \"rxjs\";\nimport {StoreModel} from \"../../models/StoreModel\";\n// import TweenLite = gsap.TweenLite;\n\nexport interface ISimpleGridDraggedData {\n    newIndex: number;\n    currentIndex: number;\n    items: Array<any>;\n}\n\n@Directive({\n    selector: 'tbody[simpleGridDraggable]'\n})\nexport class SimpleGridDraggable {\n\n    // we have to Inject -> forwardRef as SimpleGridTable is not yet due to load order of files\n    constructor(@Inject(forwardRef(() => SimpleGridTable)) i_table: SimpleGridTable, private el: ElementRef) {\n        this.m_table = i_table;\n    }\n\n    private m_table: SimpleGridTable\n    private m_draggables;\n    private target;\n    private y;\n\n    m_items;\n    m_selectedIdx = -1;\n    m_sub: Subscription;\n\n    @ContentChildren(SimpleGridRecord) simpleGridRecords: QueryList<SimpleGridRecord>;\n\n    @Output()\n    dragCompleted: EventEmitter<ISimpleGridDraggedData> = new EventEmitter<ISimpleGridDraggedData>();\n\n    ngAfterViewInit() {\n        this.createSortable();\n        this.m_sub = this.simpleGridRecords\n            .changes.subscribe(v => {\n                this.createSortable();\n            });\n    }\n\n    _cleanSortables() {\n        if (this.m_draggables)\n            this.m_draggables.forEach((drag) => drag.kill());\n    }\n\n    /**\n     Create a draggable sortable list\n     **/\n    @timeout(500)\n    public createSortable() {\n        var self = this;\n        jQueryAny(self.el.nativeElement).children().each((i, child) => jQuery.data(child, \"idx\", i));\n        this.simpleGridRecords.forEach((rec: SimpleGridRecord, i) => rec.index = i);\n\n        if (jQuery(self.el.nativeElement).children().length == 0) return;\n        this._cleanSortables();\n        self.m_draggables = Draggable.create(jQuery(self.el.nativeElement).children(), {\n            type: \"y\",\n            bounds: self.el.nativeElement,\n            dragClickables: false,\n            edgeResistance: 1,\n            onPress: self._sortablePress,\n            onDragStart: self._sortableDragStart,\n            onDrag: self._sortableDrag,\n            liveSnap: self._sortableSnap,\n            onDragEnd: function () {\n                self.m_selectedIdx = -1;\n                var t = this.target\n                var max = t.kids.length - 1;\n                var newIndex = Math.round(this.y / t.currentHeight);\n                newIndex += (newIndex < 0 ? -1 : 0) + t.currentIndex;\n                if (newIndex === max) {\n                    t.parentNode.appendChild(t);\n                } else {\n                    t.parentNode.insertBefore(t, t.kids[newIndex + 1]);\n                }\n                var result:ISimpleGridDraggedData = {\n                    items: [],\n                    newIndex: newIndex < t.currentIndex ? newIndex + 1 : newIndex,\n                    currentIndex: t.currentIndex\n                };\n                TweenLite.set(t.kids, {yPercent: 0, overwrite: \"all\"});\n                TweenLite.set(t, {y: 0, color: \"\"});\n                jQuery(self.el.nativeElement).children().each((i, child) => {\n                    var oldIndex = jQuery.data(child, \"idx\");\n                    var found: SimpleGridRecord = self.simpleGridRecords.find((rec: SimpleGridRecord) => {\n                        return rec.index == oldIndex;\n                    })\n                    // con(i + ' ' + found.item.getKey('event'));\n                    result.items.push(found.item)\n                })\n                self.dragCompleted.emit(result)\n            }\n        });\n    }\n\n    /**\n     Sortable list on press\n     @method _sortablePress\n     **/\n    _sortablePress() {\n        var t = this.target,\n            i = 0,\n            child = t;\n        while (child = child.previousSibling)\n            if (child.nodeType === 1) i++;\n        t.currentIndex = i;\n        t.currentHeight = t.offsetHeight;\n        t.kids = [].slice.call(t.parentNode.children); // convert to array\n    }\n\n    /**\n     Sortable drag list on press\n     @method _sortableDragStart\n     **/\n    _sortableDragStart() {\n        TweenLite.set(this.target, {color: \"#88CE02\"});\n    }\n\n    /**\n     Sortable drag list\n     @method _sortableDrag\n     **/\n    _sortableDrag() {\n        var t = this.target,\n            elements = t.kids.slice(), // clone\n            indexChange = Math.round(this.y / t.currentHeight),\n            bound1 = t.currentIndex,\n            bound2 = bound1 + indexChange;\n        if (bound1 < bound2) { // moved down\n            TweenLite.to(elements.splice(bound1 + 1, bound2 - bound1), 0.15, {yPercent: -100});\n            TweenLite.to(elements, 0.15, {yPercent: 0});\n        } else if (bound1 === bound2) {\n            elements.splice(bound1, 1);\n            TweenLite.to(elements, 0.15, {yPercent: 0});\n        } else { // moved up\n            TweenLite.to(elements.splice(bound2, bound1 - bound2), 0.15, {yPercent: 100});\n            TweenLite.to(elements, 0.15, {yPercent: 0});\n        }\n    }\n\n    /**\n     snap to set rounder values\n     @method _sortableSnap\n     **/\n    _sortableSnap(y) {\n        return y;\n        // enable code below to enable snapinnes on dragging\n        // var h = this.target.currentHeight;\n        // return Math.round(y / h) * h;\n    }\n\n    ngOnDestroy() {\n        this._cleanSortables();\n        this.m_sub.unsubscribe();\n        this.m_draggables = null;\n    }\n}"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridExample.txt",
    "content": "import {\n    Component,\n    ChangeDetectionStrategy,\n    ChangeDetectorRef,\n} from \"@angular/core\";\nimport {AppModel} from \"../../../reseller/AppModel\";\nimport {List} from \"immutable\";\nimport {AppStore} from \"angular2-redux-util\";\nimport {ResellerAction} from \"../../../reseller/ResellerAction\";\n// import {ComponentInstruction} from \"@angular/router\";\n\n@Component({\n    selector: 'apps',\n    host: {\n        // '[@routeAnimation]': 'true',\n        '[style.display]': \"'block'\"\n    },\n    template: `\n        <div *ngIf=\"apps && apps.size > 0\">\n          <simpleGridTable>\n            <thead>\n            <tr>\n              <th>icon</th>\n              <th sortableHeader=\"appName\" [sort]=\"sort\">app name</th>\n              <th>available (off | on)</th>\n            </tr>\n            </thead>\n            <tbody>\n            <tr class=\"simpleGridRecord\" simpleGridRecord *ngFor=\"let item of apps | OrderBy:sort.field:sort.desc; let index=index\" [item]=\"item\" [index]=\"index\">\n              <td style=\"width: 10%\" simpleGridDataImage color=\"dodgerblue\" [field]=\"item.getIcon(item)\" [item]=\"item\"></td> \n              <td style=\"width: 70%\" simpleGridData field=\"appName\" [item]=\"item\"></td>\n              <td style=\"width: 20%\" simpleGridDataChecks slideMode=\"true\" [item]=\"item\" [checkboxes]=\"getInstalledStatus(item)\" (changed)=\"onAppInstalledChange($event,index)\"></td>\n            </tr>\n            </tbody>\n          </simpleGridTable>\n        </div>\n    `,\n    changeDetection: ChangeDetectionStrategy.OnPush\n})\n\nexport class Apps {\n\n    constructor(private appStore: AppStore, private resellerAction: ResellerAction, private ref: ChangeDetectorRef) {\n        var i_reseller = this.appStore.getState().reseller;\n        this.apps = i_reseller.getIn(['apps']);\n        this.unsub = this.appStore.sub((apps) => {\n            this.apps = apps;\n            this.ref.markForCheck();\n        }, 'reseller.apps');\n    }\n\n    private sort: {field: string, desc: boolean} = {field: null, desc: false};\n    private apps: List<AppModel>;\n    private unsub;\n\n    private getInstalledStatus(item: AppModel) {\n        return [Number(item.getInstalled())];\n    }\n\n    private onAppInstalledChange(event, index) {\n      this.appStore.dispatch(this.resellerAction.appStatus(event.item, event.value[\"0\"]));\n    }\n\n    private ngOnDestroy() {\n        this.unsub();\n    }\n\n}\n\n"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridModule.ts",
    "content": "import {SimpleGridData} from \"./SimpleGridData\";\nimport {SimpleGridTable} from \"./SimpleGridTable\";\nimport {SimpleGridSortableHeader} from \"./SimpleGridSortableHeader\";\nimport {SimpleGridRecord} from \"./SimpleGridRecord\";\nimport {SimpleGridDataImage} from \"./SimpleGridDataImage\";\nimport {SimpleGridDataCurrency} from \"./SimpleGridDataCurrency\";\nimport {SimpleGridDataChecks} from \"./SimpleGridDataChecks\";\nimport {SimpleGridDataDropdown} from \"./SimpleGridDataDropdown\";\nimport {\n    NgModule,\n    ModuleWithProviders\n} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {\n    FormsModule,\n    ReactiveFormsModule\n} from \"@angular/forms\";\nimport {SimpleGridDraggable} from \"./SimpleGridDraggable\";\n// import {StoreModel} from \"../../models/StoreModel\";\n\n\nexport const SIMPLEGRID_DIRECTIVES: Array<any> = [SimpleGridTable, SimpleGridSortableHeader, SimpleGridRecord, SimpleGridData, SimpleGridDataCurrency, SimpleGridDataImage, SimpleGridDataChecks, SimpleGridDataDropdown, SimpleGridDraggable];\n\nexport interface ISimpleGridEdit {\n    value: string;\n    item: any;\n}\n\n@NgModule({\n    imports: [CommonModule, FormsModule, ReactiveFormsModule],\n    declarations: SIMPLEGRID_DIRECTIVES,\n    exports: SIMPLEGRID_DIRECTIVES\n})\n\n// here we are loading the providers ONLY when this shared module is loaded by the app and not\n// by a feature or lazy loaded module, this making sure we share a single instance of AuthService\nexport class SimpleGridModule {\n    static forRoot(): ModuleWithProviders {\n        return {\n            ngModule: SimpleGridModule,\n            providers: []\n        };\n    }\n}"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridRecord.ts",
    "content": "import {Component, Input, Output, ChangeDetectionStrategy, HostListener, forwardRef, Inject, HostBinding, EventEmitter} from '@angular/core'\nimport {SimpleGridTable} from \"./SimpleGridTable\";\n\n@Component({\n    selector: 'tr[simpleGridRecord]',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n          <ng-content></ng-content>\n    `\n})\nexport class SimpleGridRecord {\n\n    // we have to Inject -> forwardRef as SimpleGridTable is not yet due to load order of files\n    constructor(@Inject(forwardRef(() => SimpleGridTable)) i_table: SimpleGridTable){\n        this.m_table = i_table;\n    }\n\n    private m_table:SimpleGridTable\n    private m_index;\n\n    @Input()\n    item;\n\n    @Input()\n    selectable:boolean = true;\n\n    // @Input()\n    // set table(i_table) {\n    //     this.m_table = i_table;\n    // }\n\n    @Output()\n    onDoubleClicked:EventEmitter<any> = new EventEmitter();\n\n    @Output()\n    onClicked:EventEmitter<any> = new EventEmitter();\n\n    @HostListener('dblclick', ['$event'])\n    doubleClicked(event) {\n        this.setSelected();\n        this.onDoubleClicked.emit({\n            target: event.target,\n            item: this.item ? this.item : null\n        });\n        return true;\n    }\n\n    @HostListener('click', ['$event'])\n    onSelected() {\n        if (!this.selectable)\n            return;\n        this.setSelected();\n        this.onClicked.emit({\n            target: event.target,\n            item: this.item ? this.item : null\n        });\n        return true;\n    }\n\n    @HostBinding('class.selectedTr')\n    selectedClass:boolean = false;\n\n    @Input()\n    set index(i_index:number) {\n        this.m_index = i_index;\n    }\n\n    get index() {\n        return this.m_index;\n    }\n\n    ngOnInit() {\n        var selected:SimpleGridRecord = this.m_table.getSelected();\n        // even though the index is same as this, the Immutable data propSelectedModel\n        // is out of sync inside table, so we need to update to latest version of this\n        if (selected && selected.m_index == this.index)\n            this.setSelected();\n    }\n\n    private setSelected() {\n        this.m_table.setSelected(this);\n        this.selectedClass = true;\n    }\n}"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridSortableHeader.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy} from '@angular/core';\n\n@Component({\n    selector: 'th[sortableHeader]',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n    <div (click)=\"headerClicked()\">\n      <i class=\"fa fa-sort\" [hidden]=\"sort.field === fieldName\"></i>\n      <i class=\"fa fa-sort-asc\" [hidden]=\"sort.field !== fieldName || sort.desc\"></i>\n      <i class=\"fa fa-sort-desc\" [hidden]=\"sort.field !== fieldName || !sort.desc\"></i>\n      <ng-content></ng-content>\n    </div>\n  `,\n    styles: [`\n        div {\n          cursor: pointer;\n          width: 80px;\n        }\n  `]\n})\nexport class SimpleGridSortableHeader {\n\n    // map the sortableHeader input into a local var named fieldName\n    @Input('sortableHeader') fieldName: string;\n\n    // no mapping just create local reference sort which gets passed in\n    // the sort points to same instance as the one from the host component\n    @Input() sort: {field: string, desc: boolean};\n\n    headerClicked(): void {\n        if (this.sort.field === this.fieldName) {\n            if (this.sort.desc === true) {\n                this.sort.desc = false;\n                this.sort.field = null;\n            } else {\n                this.sort.desc = true;\n            }\n        } else {\n            this.sort.field = this.fieldName;\n            this.sort.desc = false;\n        }\n    }\n\n}"
  },
  {
    "path": "src/comps/simple-grid-module/SimpleGridTable.ts",
    "content": "import {ChangeDetectionStrategy, Component, ContentChild, ContentChildren, Input, QueryList} from \"@angular/core\";\nimport {SimpleGridRecord} from \"./SimpleGridRecord\";\nimport {SimpleGridDraggable} from \"./SimpleGridDraggable\";\n\n@Component({\n    selector: 'simpleGridTable',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [`\n        .simpleTable {\n            background-color: white;\n        }\n\n        * {\n            font-size: 0.9em;\n        }\n    `],\n    template: `\n      <table class=\"table simpleTable\">\n        <ng-content></ng-content>\n      </table>\n    `,\n})\n\nexport class SimpleGridTable {\n    @Input() sort;\n\n    @Input() list;\n\n    private selected;\n\n    @ContentChildren(SimpleGridRecord) simpleGridRecords: QueryList<SimpleGridRecord>;\n    @ContentChild(SimpleGridDraggable) simpleGridDraggable;\n\n    public setSelected(i_selected: SimpleGridRecord) {\n        this.deselect();\n        this.selected = i_selected;\n        // var rec = i_selected.item;\n        // console.log(`user selected ${rec.getBusinessId()}  ${rec.getName()} ${rec.getAccessMask()}`);\n    }\n\n    public deselect() {\n        this.selected = null;\n        if (!this.simpleGridRecords && !this.simpleGridDraggable)\n            return;\n        // content children parsed differently depending if we are using SimpleGridDraggable or not\n        var records: QueryList<SimpleGridRecord> = this.simpleGridRecords.length > 0 ? this.simpleGridRecords : this.simpleGridDraggable.simpleGridRecords;\n        records.map((i_simpleGridRecord: SimpleGridRecord) => {\n            i_simpleGridRecord.selectedClass = false;\n        })\n    }\n\n    public getSelected(): SimpleGridRecord {\n        return this.selected;\n    }\n\n    // ngAfterViewInit() {\n    // if (!this.simpleGridRecords && !this.simpleGridDraggable) return;\n    // var records: QueryList<SimpleGridRecord> = this.simpleGridRecords.length > 0 || this.simpleGridDraggable.simpleGridRecords;\n    // records.changes.subscribe(val => {\n    //     var arr = records.toArray();\n    // });\n    // }\n\n    // public getOrder() {\n    //     if (!this.simpleGridRecords && !this.simpleGridDraggable) return;\n    //     var records: QueryList<SimpleGridRecord> = this.simpleGridRecords.length > 0 || this.simpleGridDraggable.simpleGridRecords;\n    //     records.notifyOnChanges()\n    //     // this.cd.detectChanges();\n    //     records.forEach((s: SimpleGridRecord) => {\n    //         console.log(s.index + ' ' + s.item.getKey('event'));\n    //     });\n    //\n    // }\n}"
  },
  {
    "path": "src/comps/sliderpanel/SliderItemContent.ts",
    "content": "import {ApplicationRef, ChangeDetectorRef, Component, DoCheck, Input, Output, TemplateRef, ViewContainerRef} from \"@angular/core\";\nimport {Sliderpanel} from \"./Sliderpanel\";\nimport {Observable, Subject} from \"rxjs\";\nimport {Compbaser} from \"ng-mslib\";\n\nexport interface ISliderItemData {\n    to: string;\n    direction: string;\n}\n\n@Component({\n    selector: 'SlideritemContent',\n    template: `\n        <button *ngIf=\"fromDirection && showFromButton\" type=\"button\" (click)=\"onPrev()\" class=\"btn btn-default btn-sm\">\n            <span class=\"fa fa-arrow-left \"></span>\n        </button>\n\n        <button *ngIf=\"toDirection && showToButton\" type=\"button\" (click)=\"onNext()\" class=\"btn btn-default btn-sm\">\n            <span class=\"fa fa-arrow-right\"></span>\n        </button>\n        <ng-content></ng-content>\n    `,\n})\nexport class SlideritemContent extends Compbaser {\n\n    private m_onChanges$ = new Subject()\n\n    constructor(private viewContainer: ViewContainerRef, protected sliderPanel: Sliderpanel, private cd: ChangeDetectorRef, ap:ApplicationRef) {\n        super();\n        this.viewContainer.element.nativeElement.classList.add('page');\n        this.sliderPanel.addSlider(this);\n\n        this.cancelOnDestroy(\n            this.m_onChanges$.debounceTime(300)\n                .subscribe((data: any) => {\n                    this.sliderPanel.slideToPage(data.to, data.direction)\n                    this.cd.markForCheck();\n                })\n        )\n    }\n\n    @Input() toDirection: 'left' | 'right';\n    @Input() fromDirection: 'left' | 'right';\n    @Input() to: string;\n    @Input() from: string;\n    @Input() showToButton: boolean = true;\n    @Input() showFromButton: boolean = true;\n    @Output() onChange: Observable<ISliderItemData | {}> = new Subject().delay(300).debounceTime(1000);\n\n    public addClass(i_className) {\n        this.viewContainer.element.nativeElement.classList.add(i_className);\n    }\n\n    public hasClass(i_className) {\n        this.viewContainer.element.nativeElement.classList.contains(i_className);\n    }\n\n    public getNative() {\n        return this.viewContainer.element.nativeElement;\n    }\n\n    public removeClass(i_className) {\n        this.viewContainer.element.nativeElement.classList.remove(i_className);\n    }\n\n    public slideTo(to: string, direction: string) {\n        (this.onChange as Subject<ISliderItemData>).next({\n            to: to,\n            direction: direction\n        })\n        this.m_onChanges$.next({to, direction})\n        // this.sliderPanel.slideToPage(to, direction)\n    }\n\n    public onNext() {\n        this.slideTo(this.to, this.toDirection);\n    }\n\n    public onPrev() {\n        this.slideTo(this.from, this.fromDirection);\n    }\n\n    destroy(){\n        // console.log('dest SliderItem');\n    }\n}\n\n"
  },
  {
    "path": "src/comps/sliderpanel/Slideritem.ts",
    "content": "import {ApplicationRef, ChangeDetectorRef, Component, DoCheck, Input, Output, TemplateRef, ViewContainerRef} from \"@angular/core\";\nimport {Sliderpanel} from \"./Sliderpanel\";\nimport {Observable, Subject} from \"rxjs\";\nimport {Compbaser} from \"ng-mslib\";\n\nexport interface ISliderItemData {\n    to: string;\n    direction: string;\n}\n\n@Component({\n    selector: 'Slideritem',\n    // changeDetection: ChangeDetectionStrategy.OnPush,\n    template: `\n        <button *ngIf=\"fromDirection && showFromButton\" type=\"button\" (click)=\"onPrev()\" class=\"btn btn-default btn-sm\">\n            <span class=\"fa fa-arrow-left \"></span>\n        </button>\n\n        <button *ngIf=\"toDirection && showToButton\" type=\"button\" (click)=\"onNext()\" class=\"btn btn-default btn-sm\">\n            <span class=\"fa fa-arrow-right\"></span>\n        </button>\n\n        <!--<ng-content *ngIf=\"m_render\"></ng-content>-->\n\n        <ng-template *ngIf=\"m_render\" [ngTemplateOutlet]=\"templateRef\"></ng-template>\n    `,\n})\nexport class Slideritem extends Compbaser implements DoCheck {\n\n    m_render: boolean = false;\n    m_onChanges$ = new Subject()\n\n    constructor(private viewContainer: ViewContainerRef, protected sliderPanel: Sliderpanel, private cd: ChangeDetectorRef, ap: ApplicationRef) {\n        super();\n        this.viewContainer.element.nativeElement.classList.add('page');\n        this.sliderPanel.addSlider(this);\n\n        this.cancelOnDestroy(\n            this.m_onChanges$.debounceTime(300)\n                .subscribe((data: any) => {\n                    this.sliderPanel.slideToPage(data.to, data.direction)\n                    this.cd.markForCheck();\n                })\n        )\n    }\n\n    ngDoCheck() {\n        if (this.viewContainer.element.nativeElement.classList.contains('selected')) {\n            if (this.m_render == true)\n                return;\n            this.m_render = true;\n            // console.log('added');\n            this.cd.detectChanges();\n        } else {\n            if (this.m_render == false)\n                return;\n            setTimeout(() => {\n                this.m_render = false;\n                // console.log('removed');\n                this.cd.detectChanges();\n            }, 500)\n        }\n    }\n\n    @Input() templateRef: TemplateRef<any>;\n    @Input() toDirection: 'left' | 'right';\n    @Input() fromDirection: 'left' | 'right';\n    @Input() to: string;\n    @Input() from: string;\n    @Input() showToButton: boolean = true;\n    @Input() showFromButton: boolean = true;\n    @Output() onChange: Observable<ISliderItemData | {}> = new Subject().delay(300).debounceTime(1000);\n\n    public addClass(i_className) {\n        this.viewContainer.element.nativeElement.classList.add(i_className);\n    }\n\n    public hasClass(i_className) {\n        this.viewContainer.element.nativeElement.classList.contains(i_className);\n    }\n\n    public getNative() {\n        return this.viewContainer.element.nativeElement;\n    }\n\n    public removeClass(i_className) {\n        this.viewContainer.element.nativeElement.classList.remove(i_className);\n    }\n\n    public slideTo(to: string, direction: string) {\n        (this.onChange as Subject<ISliderItemData>).next({\n            to: to,\n            direction: direction\n        })\n        this.m_onChanges$.next({to, direction})\n        // this.sliderPanel.slideToPage(to, direction)\n    }\n\n    public onNext() {\n        this.slideTo(this.to, this.toDirection);\n    }\n\n    public onPrev() {\n        this.slideTo(this.from, this.fromDirection);\n    }\n\n    destroy() {\n        // console.log('dest SliderItem');\n    }\n}\n\n"
  },
  {
    "path": "src/comps/sliderpanel/Sliderpanel.ts",
    "content": "import {\n    Component,\n    ViewContainerRef,\n    Inject\n} from '@angular/core';\nimport {DOCUMENT} from '@angular/platform-browser';\nimport {Slideritem} from \"./Slideritem\";\n\n/**\n @class Sliderpanel\n example: this.slideToPage('campaignNameSelectorView', 'left')\n **/\n\n@Component({\n    selector: 'Sliderpanel',\n    template: `<ng-content></ng-content>`\n})\n\nexport class Sliderpanel {\n    private el: any;\n    private viewContainer: ViewContainerRef;\n    private dom: HTMLBodyElement;\n    private sliders: Array<any> = [];\n\n    constructor(viewContainer: ViewContainerRef, @Inject(DOCUMENT) private doc:any) {\n        this.dom = doc.body;\n        this.viewContainer = viewContainer;\n        this.el = viewContainer.element.nativeElement;\n    }\n\n    private getElementByClass(element: string) {\n        var jq: any = jQuery;\n        return jq(this.dom).find('.' + element, this.el)[0];\n    }\n\n    private removeAllClassesFrom(elementClass: any, selected?: boolean) {\n        var element = this.getElementByClass(elementClass);\n        if (selected) {\n            jQuery(element).removeClass('selected');\n            return;\n        }\n        jQuery(element).removeClass('left');\n        jQuery(element).removeClass('right');\n        jQuery(element).removeClass('center');\n        jQuery(element).removeClass('transition');\n    }\n\n    private addClassesTo(elementClass: any, classesToAdd: string[]) {\n        var element = this.getElementByClass(elementClass);\n        for (var i = 0; i < classesToAdd.length; i++) {\n            jQuery(element).addClass(classesToAdd[i])\n        }\n    }\n\n    public slideToPage(toClassName: string, i_direction: string): void {\n        if (toClassName == 'selected')\n            return;\n        // Position the new page at the starting position of the animation\n        this.removeAllClassesFrom(toClassName);\n        this.addClassesTo(toClassName, [\"page\", i_direction]);\n        // Position the new page and the current page at the ending position of their animation with a transition class indicating the duration of the animation and force reflow of page so it renders\n        var parent = jQuery(this.getElementByClass(toClassName)).parent();\n        var grandparent = jQuery(parent).parent();\n        var offsetWidth = jQuery(grandparent).prop('offsetWidth');\n        this.removeAllClassesFrom(toClassName);\n        this.addClassesTo(toClassName, ['page', 'transition', 'center']);\n        this.removeAllClassesFrom('selected');\n        this.addClassesTo('selected', ['page', 'transition', i_direction === 'left' ? 'right' : 'left']);\n        this.removeAllClassesFrom('selected', true);\n        this.addClassesTo(toClassName, ['selected']);\n    }\n\n    public addSlider(i_slider) {\n        this.sliders.push(i_slider);\n    }\n}\n"
  },
  {
    "path": "src/comps/svg-icon/svg-icon.ts",
    "content": "import {Component, Input, ChangeDetectionStrategy, ElementRef, Renderer} from '@angular/core';\nimport {Http, Response} from '@angular/http';\n@Component({\n    selector: 'svg-icon',\n    template: `\n        <ng-content></ng-content>`,\n    changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SvgIcon {\n    @Input()\n    set path(val: string) {\n        this.loadSvg(val);\n    }\n\n    @Input() height;\n    @Input() width;\n    @Input() alt: string;\n\n    constructor(private http: Http, private elementRef: ElementRef) {\n\n    }\n\n    loadSvg(val: string) {\n        // this.http.get(`svgs/${val}.svg`) // grab locally\n        this.http.get(val)\n            .subscribe(\n                res => {\n                    // get our element and clean it out\n                    const element = this.elementRef.nativeElement;\n                    var svgFinal;\n                    element.innerHTML = '';\n                    // get response and build svg element\n                    var response = res.text();\n                    const parser = new DOMParser();\n\n\n                    if (this.height && this.width) {\n                        var svgHeight, svgWidth, re;\n                        svgHeight = response.match(/(height=\")([^\\\"]*)/)[2];\n                        re = new RegExp('height=\"' + svgHeight + '\"', \"ig\");\n                        response = response.replace(re, `height=\"${this.height}\"`);\n\n                        svgWidth = response.match(/(width=\")([^\\\"]*)/)[2];\n                        re = new RegExp('width=\"' + svgWidth + '\"', \"ig\");\n                        response = response.replace(re, `width=\"${this.width}\"`);\n                        // var s = new String(response);\n                    }\n\n                    svgFinal = parser.parseFromString(response, 'image/svg+xml');\n                    element.appendChild(svgFinal.documentElement);\n                    // insert the svg result\n\n                },\n                err => {\n                    console.error(err);\n                });\n    }\n}"
  },
  {
    "path": "src/comps/tabs/tab.ts",
    "content": "import {Component, Host, Output, EventEmitter} from '@angular/core';\nimport {Tabs} from '../tabs/tabs';\n\n@Component({\n    selector: 'tab',\n    inputs: [\n        'title:tabtitle',\n        'active'\n    ],\n    styles: [`\n        .pane {\n            padding: 1em;\n            background-color: white;\n            border-left: 1px solid #dddddd;\n            border-right: 1px solid #dddddd;\n            border-bottom: 1px solid #dddddd;\n        }\n    `],\n    template: `\n        <div [hidden]=\"!_active\" class=\"pane\">\n            <ng-content></ng-content>\n        </div>\n    `\n})\n\n/**\n Add this Tab as part of it's parents Tabs component\n use @Host to make sure we only look for a parent Tabs dependency injector\n and don't go any further to prevent lookup of wrong Tabs under misconfiguration\n **/\nexport class Tab {\n\n    constructor(@Host() private tabs: Tabs) {\n        tabs.addTab(this);\n    }\n\n    @Output()\n    activated: EventEmitter<any> = new EventEmitter<any>();\n\n    public title: string;\n     _active = false;\n     _show = true;\n\n    public set active(value) {\n        this._active = value || false;\n        if (this._active)\n            this.activated.emit(true);\n    }\n\n    public get active() {\n        return this._active;\n    }\n\n    public set show(value) {\n        this._show = value;\n        if (value == false) {\n            this._active = false\n            this.tabs.checkActive();\n        }\n    }\n\n    public get show() {\n        return this._show;\n    }\n\n}\n"
  },
  {
    "path": "src/comps/tabs/tabs.ts",
    "content": "import {Component} from '@angular/core';\n//import {Tab} from 'tab';\n\n@Component({\n    selector: 'tabs',\n    template: `\n        <ul class=\"nav nav-tabs\">\n            <ng-container *ngFor=\"let tab of tabs\">\n                <li *ngIf=\"tab.show == true\" (click)=\"selectTab(tab, $event)\" [class.active]=\"tab.active\">\n                    <a href=\"#\">{{tab.title}}</a>\n                </li>\n            </ng-container>\n        </ul>\n        <ng-content></ng-content>\n    `\n})\nexport class Tabs {\n\n    tabs: any[];\n    removed;\n\n    constructor() {\n        this.tabs = [];\n    }\n\n    private selectTab(tab, event) {\n        event.preventDefault;\n        this.tabs.forEach((tab) => tab.active = false);\n        tab.active = true;\n        return false;\n    }\n\n    /** make sure at least one tab is active **/\n    public checkActive() {\n        var actives = this.tabs.filter((tab) => tab.active == true);\n        actives.length == 0 ? this.tabs[0].active = true : null;\n    }\n\n    addTab(tab: any) {\n        if (this.tabs.length === 0) {\n            tab.active = true;\n        }\n        this.tabs.push(tab);\n    }\n}"
  },
  {
    "path": "src/create_reflection.html",
    "content": "<!--\n\nUsage:\n\nto run this script and generate interface sdkmsdb:\n\nrun live-server inside /cygdrive/c/studiolite/studiotouch\n\nopen browser to:\n\nhttp://127.0.0.1:8080/src/create_reflection.html\n\n-->\n\n<html>\n<script src=\"https://code.jquery.com/jquery-3.1.1.js\" integrity=\"sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=\" crossorigin=\"anonymous\"></script>\n<script type=\"text/javascript\" src=\"https://js.signage.me/SignageSDK_combined.js\"></script>\n<script type=\"text/javascript\" src=\"http://www.digitalsignage.com/js/jquery.base64.js\"></script>\n<script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js\"></script>\n<script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/string.js/3.3.3/string.min.js\"></script>\n<script>\n    var protocol = 'https'\n    window.g_protocol = protocol + \"://\";\n    window.g_sdkDomain = \"js.signage.me\";\n    var server = \"galaxy.signage.me\";\n    var g_masterDomain = server;\n    window.g_masterDomain = server;\n    var loaderManager = new LoaderManager();\n    var msdb = loaderManager.m_dataBaseManager;\n    var buffer = ''\n    var modelFields = {}\n    var breakHr = '\\n//---------------------------------------------------------------------------------------------------------';\n\n    function capitalizeFirstLetter(string) {\n        return string.charAt(0).toUpperCase() + string.slice(1);\n    }\n\n\n    loaderManager.create('d25@ms.com', \"123123\", function (v) {\n\n        function getAargs(func) {\n            return (func + '')\n                .replace(/[/][/].*$/mg,'') // strip single-line comments\n                .replace(/\\s+/g, '') // strip white space\n                .replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments\n                .split('){', 1)[0].replace(/^[^(]*[(]/, '') // extract the parameters\n                .replace(/=[^,]+/g, '') // strip any ES6 defaults\n                .split(',').filter(Boolean); // split & filter [\"\"]\n        }\n\n        var allTables = '\\nexport const TableNames = [\\n';\n        _.forEach(msdb.m_selectedDataBase.m_tableList, (k, v) => {\n            allTables = `    ${allTables}       '${k}',\\n`\n        })\n        allTables = `${allTables}\\n]`\n\n        var campaigns = msdb.table_campaigns();\n        var tableProto = campaigns.__proto__.__proto__;\n\n        var functions = 'm_name:string;\\n';\n        functions = functions + '    fields:Array&lt;any&gt;\\n';\n        _.forEach(tableProto, (func, funcName) => {\n            var args = getAargs(func).join(',');\n            functions = functions + `    ${funcName}: (${args}) => any;\\n`\n        })\n\n        var baseProto = `\nexport interface IBaseProto {\n    ${functions}\n}\n`\n\n\n        // build all redux StoreData\n        var allReduxStores = `\nexport interface ISDK {\n        `;\n        _.forEach(msdb.m_selectedDataBase.m_tableList, (k, v) => {\n            var storeName = capitalizeFirstLetter(S(k).camelize().s) + 'Model';\n            var storeTemplate = `\n        table_${k}?: List&lt;${storeName}&gt;;`;\n            allReduxStores = `${allReduxStores} ${storeTemplate}`\n        });\n        allReduxStores = `${allReduxStores}\n\n}`;\n\n\n        // examples for debug to evaluate proto data\n        var a = msdb.table_campaigns().getAllPrimaryKeys();\n        var b = msdb.table_campaigns().m_name;\n        var c = msdb.table_campaigns().m_fields[2].field\n        var d = msdb.table_campaigns().m_fields[0].isNullAble;\n        var e = msdb.table_campaigns().m_fields[1].field;\n\n\n        // build tables names\n        var tables = '';\n        _.forEach(msdb.__proto__, (tableFunc, table) => {\n            var tableCap = capitalizeFirstLetter(table)\n            if (msdb[table]()) {\n                var fields = msdb[table]().m_fields;\n                modelFields[table] = fields;\n                var f = JSON.stringify(fields)\n            }\n            tables = tables + `export interface I${tableCap} extends IBaseProto {\n    m_fields: ${f}\n}\\n`\n        })\n\n\n        // build tables names\n        var b2 = '';\n        _.forEach(msdb.__proto__, (tableFunc, table) => {\n            var tableCap = capitalizeFirstLetter(table)\n            b2 = `${b2}     ${table}:()=> I${tableCap}\\n`\n        })\n        var DataManager = `\nexport interface IDataManager_proto {\n${b2}\n}\n`\n\n        // build StoreModels\n        var allStores = 'import {StoreModel} from \"../store/model/StoreModel\";\\n';\n        _.forEach(msdb.m_selectedDataBase.m_tableList, (table, v) => {\n            var storeName = capitalizeFirstLetter(S(table).camelize().s) + 'Model';\n            var fields = modelFields['table_' + table];\n            var fieldNames = '';\n            _.forEach(fields, (fieldName) => {\n                var methodGetter = 'get'+capitalizeFirstLetter(S(fieldName.field).camelize().s);\n                var templateField = `\n    public ${methodGetter}() {\n        return this.getKey('${fieldName.field}');\n    }`;\n                fieldNames = `${fieldNames}     ${templateField}\\n`\n            })\n            var storeTemplate = `\nexport class ${storeName} extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n${fieldNames}\n}`;\n            allStores = `${allStores}       ${storeTemplate}`\n        })\n\n\n        buffer = `<pre>\n\n\n// >>>> paste into: store/imsdb.interfaces_auto.ts\n\nimport {List} from 'immutable';\n\n${allStores}\n\n\n${allReduxStores}\n\n${allTables}\n\n${baseProto}\n\n${tables}\n\n${DataManager}\n\n</pre>`;\n\n        $('body').append(buffer);\n    });\n\n</script>\n</html>"
  },
  {
    "path": "src/decorators/once-decorator.ts",
    "content": "import {Subscriber} from \"rxjs\";\nexport function Once(milliseconds: number = 0) {\n    return function (target, key, descriptor) {\n        var originalMethod = descriptor.value;\n        descriptor.value = function (...args) {\n            var sub = originalMethod.apply(this, args);\n            setTimeout(() => {\n                if (sub instanceof Subscriber) {\n                    sub.unsubscribe();\n                } else if (sub instanceof Function) {\n                    sub()\n                } else if (sub === null) {\n                } else {\n                    throw new Error('@Once did not receive something to unsubscribe from, did you forget to return an Observable maybe?');\n                }\n            }, milliseconds);\n        };\n        return descriptor;\n    }\n}"
  },
  {
    "path": "src/decorators/timeout-decorator.ts",
    "content": "// ref: http://blog.wolksoftware.com/decorators-reflection-javascript-typescript\n// ref: https://medium.com/@NetanelBasal/javascript-make-your-code-cleaner-with-decorators-d34fc72af947#.fe9f2rfb8\n\nexport function timeout( milliseconds: number = 0 ) {\n\n    return function( target, key, descriptor ) {\n\n        var originalMethod = descriptor.value;\n\n        descriptor.value = function (...args) {\n\n            setTimeout(() => {\n                originalMethod.apply(this, args);\n            }, milliseconds);\n\n        };\n\n        return descriptor;\n    }\n\n\n}"
  },
  {
    "path": "src/environments/environment.hmr.ts",
    "content": "import {StoreDevtoolsModule} from \"@ngrx/store-devtools\";\nexport const environment = {\n    production: false,\n    hmr: true,\n    imports: [],\n    // imports: [\n    //     StoreDevtoolsModule.instrumentStore({maxAge: 2}),\n    // ]\n};"
  },
  {
    "path": "src/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: true,\n  hmr: false,\n  imports: []\n};\n"
  },
  {
    "path": "src/environments/environment.ts",
    "content": "// The file contents for the current environment will overwrite these during build.\n// The build system defaults to the dev environment which uses `environment.ts`, but if you do\n// `ng build --env=prod` then `environment.prod.ts` will be used instead.\n// The list of which env maps to which file can be found in `angular-cli.json`.\n\nimport {StoreDevtoolsModule} from \"@ngrx/store-devtools\";\nexport const environment = {\n  production: false,\n  hmr: false,\n  imports: [\n    StoreDevtoolsModule.instrumentStore({maxAge: 2}),\n  ]\n};\n"
  },
  {
    "path": "src/filters/filter-model-pipe.ts",
    "content": "import {Pipe, PipeTransform} from '@angular/core';\nimport {StoreModel} from \"../store/model/StoreModel\";\nimport * as _ from 'lodash';\n\n@Pipe({\n    name: 'FilterModelPipe'\n})\nexport class FilterModelPipe implements PipeTransform {\n    transform(model:StoreModel, ...args:any[]):boolean {\n        if (_.isUndefined(args['0']) || _.isEmpty(args['0']))\n            return false;\n        try {\n            var field = args[2];\n            var str1:string = args[0].toLowerCase();\n            var str2:string;\n            if (typeof model[field] === \"function\"){\n                str2 = model[field]().toLowerCase();\n            } else {\n                str2 = model[field].toLowerCase();\n            }\n\n            if (str2.indexOf(str1) > -1)\n                return false;\n            return true;\n        } catch (e) {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "src/hmr.ts",
    "content": "import { NgModuleRef, ApplicationRef } from '@angular/core';\nimport { createNewHosts } from '@angularclass/hmr';\n\nexport const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => {\n    let ngModule: NgModuleRef<any>;\n    module.hot.accept();\n    bootstrap().then(mod => ngModule = mod);\n    module.hot.dispose(() => {\n        let appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);\n        let elements = appRef.components.map(c => c.location.nativeElement);\n        let makeVisible = createNewHosts(elements);\n        ngModule.destroy();\n        makeVisible();\n    });\n};"
  },
  {
    "path": "src/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>Dashboard</title>\n    <base href=\"/\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"assets/images/icons/icon-72x72.png\">\n    <!-- possibly enable line below to avoid security issue with Microsoft Edge -->\n    <!--<meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\" />-->\n    <link rel=\"manifest\" href=\"./manifest.json\">\n    <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n    <meta name=\"theme-color\" content=\"#333333\">\n    <meta name=\"description\" content=\"DigitalSignage.com FREE Digital Signage for everyone. StudioWeb, an open source Digital Signage editor powered by Angular\">\n    <meta name=\"keywords\" content=\"Digital Signage, Kiosk, Digital Kiosk\">\n    <script>window['offlineDevMode'] = false;</script>\n\n    <script type=\"text/javascript\">\n        var origin = window.location.toString();\n        var re = new RegExp(/^(https|http)(:\\/\\/)(.*?)\\//);\n        var protocol = origin.match(re)[1];\n        window.g_protocol = protocol + \"://\";\n        window.g_sdkDomain = \"js.signage.me\";\n        var server = \"galaxy.signage.me\";\n        // PRIVATE_SERVER_START\n        // var server = origin.match(re)[3];\n        // server = 'alpha.example.com/';\n        // window.g_private_hybrid = true;\n        // PRIVATE_SERVER_END\n        window.g_masterDomain = server;\n        document.write('<script type=\"text/javascript\" src=\"' + window.g_protocol + window.g_sdkDomain + '/SignageSDK_combined.js\"></scr' + 'ipt>');\n    </script>\n\n    <style>#loading {\n        padding-top: 130px\n    }\n\n    .spinner {\n        display: inline-block;\n        opacity: 1;\n        border: 3px solid #fff;\n        border-radius: 50%;\n        border-top-color: rgba(0, 0, 0, .3);\n        animation: spin 1s ease-in-out infinite;\n        -webkit-animation: spin 1.5s ease-in-out infinite;\n        height: 50px;\n        width: 50px\n    }\n\n    @keyframes spin {\n        to {\n            -webkit-transform: rotate(360deg)\n        }\n    }\n\n    @-webkit-keyframes spin {\n        to {\n            -webkit-transform: rotate(360deg)\n        }\n    }\n\n    .centerSpinner {\n        text-align: center\n    } </style>\n</head>\n<body>\n<app-root>\n    <div id=\"loading\">\n        <div class=\"centerSpinner spinner\"></div>\n        <!--<img id=\"appLoader\" src=\"assets/loading.svg\" alt=\"Loading icon\"/>-->\n    </div>\n</app-root>\n<script>\n    if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('./service-worker.js').then(function (registration) {\n            console.log('Service Worker registered');\n        }).catch(function (err) {\n            console.error('Service Worker registration failed: ', err);\n        });\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "src/interfaces/BlockTypeEnum.ts",
    "content": "export enum BlockTypeEnum {\n    'COMPONENT',\n    'RESOURCE',\n    'SCENE'\n}\n"
  },
  {
    "path": "src/interfaces/Consts.ts",
    "content": "export const BLOCKS_LOADED = 'BLOCKS_LOADED';\nexport const PLACEMENT_SCENE = 'PLACEMENT_SCENE';\nexport const PLACEMENT_CHANNEL = 'PLACEMENT_CHANNEL';\nexport const PLACEMENT_IS_SCENE = 'PLACEMENT_IS_SCENE';\nexport const PLACEMENT_LISTS = 'PLACEMENT_LISTS';\nexport const FASTERQ_QUEUE_CALL_CANCLED = 'FASTERQ_QUEUE_CALL_CANCLED';\nexport const BLOCK_SERVICE = 'BLOCK_SERVICE';\n\nexport const BlockLabels = {\n    'BLOCKCODE_SCENE': 3510,\n    'BLOCKCODE_COLLECTION': 4100,\n    'BLOCKCODE_TWITTER': 4500,\n    'BLOCKCODE_TWITTER_ITEM': 4505,\n    'BLOCKCODE_JSON': 4300,\n    'BLOCKCODE_JSON_ITEM': 4310,\n    'BLOCKCODE_WORLD_WEATHER': 6010,\n    'BLOCKCODE_GOOGLE_SHEETS': 6022,\n    'BLOCKCODE_CALENDAR': 6020,\n    'BLOCKCODE_TWITTERV3': 6230,\n    'BLOCKCODE_INSTAGRAM': 6050,\n    'BLOCKCODE_DIGG': 6000,\n    'BLOCKCODE_IMAGE': 3130,\n    'BLOCKCODE_SVG': 3140,\n    'BLOCKCODE_VIDEO': 3100,\n    'RSS': 3345,\n    'QR': 3430,\n    'YOUTUBE': 4600,\n    'LOCATION': 4105,\n    'FASTERQ': 6100,\n    'IMAGE': 3160,\n    'EXTERNAL_VIDEO': 3150,\n    'CLOCK': 3320,\n    'HTML': 3235,\n    'LABEL': 3241,\n    'MRSS': 3340\n}\n\nexport class Consts {\n    public static Clas() {\n        return {\n            CLASS_APP_HEIGHT: '.appHeight'\n        };\n    }\n\n    public static Events() {\n        return {\n            WIN_SIZED: 'winSized',\n            MENU_SELECTION: 'menuSelection',\n            STATIONS_NETWORK_ERROR: 'stationsNetworkError',\n            UPGRADE_ENTERPRISE: 'UPGRADE_ENTERPRISE'\n        };\n    }\n\n    public static Values() {\n        return {\n            MENU_MIN_ICON_SHOW: 1550,\n            APP_SIZE: 'AppSize',\n            SERVER_MODE: 'serverMode', // 0 = cloud, 1 = private 2 = hybrid\n            USER_NAME: 'userName',\n            USER_PASS: 'userPass'\n        };\n    }\n\n    public static Services() {\n        return {\n            App: 'Application',\n            Properties: 'Properties',\n            ActionService: 'ActionService'\n        };\n    }\n}\n"
  },
  {
    "path": "src/interfaces/IAddContent.ts",
    "content": "import {BlockTypeEnum} from \"./BlockTypeEnum\";\nimport {ISceneData} from \"../app/blocks/block-service\";\n\nexport interface IAddContents {\n    type:BlockTypeEnum;\n    blockCode: number;\n    name: string;\n    allow: boolean;\n    fa: string;\n    description: string;\n    resourceId?: number;\n    blockId?:number;\n    sceneData?: ISceneData;\n    size?:string;\n    specialJsonItemName?: string;\n    specialJsonItemColor?: string;\n}\n"
  },
  {
    "path": "src/interfaces/IRegisterCaller.ts",
    "content": "export interface IRegisterCaller {\n    registerCaller(caller:any):void;\n}"
  },
  {
    "path": "src/interfaces/IScreenTemplate.ts",
    "content": "import {OrientationEnum} from \"../app/campaigns/campaign-orientation\";\n\nexport interface IScreenTemplateData {\n    resolution: string;\n    screenType: string;\n    orientation: OrientationEnum;\n    screenProps: {};\n    name: string;\n    scale: number;\n    campaignTimelineId?: number,\n    campaignTimelineBoardTemplateId?: number\n}"
  },
  {
    "path": "src/libs/bootstrap-timepicker/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes will be documented in this file.  This project\nsort of conforms to Semantic Versioning. Since we're still pre-1.0,\nit's like the Wild West up in here!\n\n## Unreleased\n### Added (not started)\n- Still planning out how to include i18n data and functionality.\n\n### Deprecated (not started)\n- Incorrect usage of the word \"meridian\" will be deprecated. It should\n  be \"meridiem\".\n- `showWidgetOnAddonClick`'s current behavior is not intuitive. Clicking\n  the input addon should _toggle_ the widget instead of showing it.\n\n## 0.5.2 - 2016-01-02\n### Added\n- Tabbing out of the timepicker widget will now close it.\n- You can specify your own icon classes. See docs for the option.\n\n### Changed\n- Cleaned up `package.json` and `bower.json` files. The npm/bower package\n  should be cleaner now.\n- `timepicker.less` now lives in the `css/` directory of the package.\n- bootstrap-timepicker now uses the latest minor releases for jQuery 2 and\n  Bootstrap 3\n\n### Fixed\n- Fixed bad interaction between `setTime(\"12:00 AM\")` and `showMeridian`\n- Various documentation issues were fixed.\n\n## 0.5.1 - 2015-08-06\n### Changed\n- Critical fix (#279) for bootstrap initialization. If you happened to\n  list your timepicker's classes in an order other than \"input-group\n  bootstrap-timepicker\", you'd be out of luck. Now we use jQuery's\n  `hasClass` method correctly. Yay!\n\n## 0.5 - 2015-07-31\n### Changed\n- Bootstrap 3 support. No more Bootstrap 2 support.\n- setTime sets time better\n- more tests, and they exercise Bootstrap 3 support!\n- snapToStep is a new option, off by default, which snaps times to the\n  nearest step or overflows to 0 if it would otherwise snap to 60 or\n  more.\n- explicitMode is a new option, off by default, which lets you leave\n  out colons when typing times.\n- shift+tab now correctly moves the cursor to the previously\n  highlighted unit, and blurs the timepicker when expected.\n- We have cut out significant amounts of old cruft from the\n  repository.\n- Minified/Uglified code is no longer kept in the repo. Please\n  download a release tarball or zip file to get the compiled and\n  minified CSS and Javascript files.\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/README.md",
    "content": "Timepicker for Twitter Bootstrap\n=======\n[![Build Status](https://travis-ci.org/jdewit/bootstrap-timepicker.svg?branch=gh-pages)](https://travis-ci.org/jdewit/bootstrap-timepicker)\n\nA simple timepicker component for Twitter Bootstrap.\n\nStatus\n======\nPlease take a look at the `CHANGELOG.md` and the issues tab for issues we're\nworking on and their relative priorities.\n\nInstallation\n============\n\nThis project is registered as a <a href=\"http://bower.io\">Bower</a> package,\nand can be installed with the following command:\n\n```bash\nbower install bootstrap-timepicker\n```\n\nYou can also download our latest release (and any previous release) \n<a href=\"https://github.com/jdewit/bootstrap-timepicker/releases\">here</a>.\n\nDemos & Documentation\n=====================\n\nView <a href=\"http://jdewit.github.com/bootstrap-timepicker\">demos & documentation</a>.\n\nSupport\n=======\n\nIf you make money using this timepicker, please consider \nsupporting its development.\n\n<a href=\"http://www.pledgie.com/campaigns/19125\"><img alt=\"Click here to support bootstrap-timepicker!\" src=\"http://www.pledgie.com/campaigns/19125.png?skin_name=chrome\" border=\"0\" target=\"_blank\"/></a> <a class=\"FlattrButton\" style=\"display:none;\" rev=\"flattr;button:compact;\" href=\"http://jdewit.github.com/bootstrap-timepicker\"></a> <noscript><a href=\"http://flattr.com/thing/1116513/Bootstrap-Timepicker\" target=\"_blank\"> <img src=\"http://api.flattr.com/button/flattr-badge-large.png\" alt=\"Flattr this\" title=\"Flattr this\" border=\"0\" /></a></noscript>\n\nContributing\n============\n\n1. Install <a href=\"www.nodejs.org\">NodeJS</a> and <a href=\"www.npmjs.org\">Node Package Manager</a>.\n\n2. Install packages\n\n```bash\nnpm install\n```\n\n3. Use <a href=\"https://github.com/twitter/bower\">Bower</a> to get the dev dependencies.\n\n```bash \nbower install\n```\n\n4. Use <a href=\"www.gruntjs.com\">Grunt</a> to run tests, compress assets, etc. \n\n```bash \ngrunt test // run jshint and jasmine tests\ngrunt watch // run jsHint and Jasmine tests whenever a file is changed\ngrunt compile // minify the js and css files\n```\n\n- Please make it easy on me by covering any new features or issues \n  with <a href=\"http://pivotal.github.com/jasmine\">Jasmine</a> tests.\n- If your changes need documentation, please take the time to update the docs.\n\nAcknowledgements\n================\n\nThanks to everyone who have given feedback and submitted pull requests. A \nlist of all the contributors can be found <a href=\"https://github.com/jdewit/bootstrap-timepicker/graphs/contributors\">here</a>.\n\nSpecial thanks to @eternicode and his <a href=\"https://github.com/eternicode/bootstrap-datepicker\">Twitter Datepicker</a> for inspiration.\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/bower.json",
    "content": "{\n    \"name\": \"bootstrap-timepicker\",\n    \"description\": \"A timepicker component for Twitter Bootstrap\",\n    \"version\": \"0.5.2\",\n    \"main\": \"js/bootstrap-timepicker.js\",\n    \"license\": \"MIT\",\n    \"ignore\": [\n        \"**/.*\",\n        \"_layouts\",\n        \"node_modules\",\n        \"_config.yml\",\n        \"assets\",\n        \"spec\",\n        \"index.html\",\n        \"Gruntfile.js\",\n        \"package.json\",\n        \"composer.json\"\n    ],\n    \"repository\": {\n      \"type\": \"git\",\n      \"url\": \"https://github.com/jdewit/bootstrap-timepicker\"\n    },\n    \"dependencies\": {\n        \"bootstrap\": \"^3.0\",\n        \"jquery\": \"^2.0\"\n    },\n    \"devDependencies\": {\n        \"autotype\": \"https://raw.github.com/mmonteleone/jquery.autotype/master/jquery.autotype.js\"\n    },\n    \"keywords\": [\n        \"widget\",\n        \"timepicker\",\n        \"time\"\n    ]\n}\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/composer.json",
    "content": "{\n\t\"name\"        : \"jdewit/bootstrap-timepicker\",\n\t\"description\" : \"A simple timepicker component for Twitter Bootstrap.\",\n\t\"version\"     : \"0.5.2\",\n\t\"license\"     : \"MIT\",\n\t\"authors\": [\n\t\t{\n\t    \"name\" : \"Joris de Wit\",\n\t    \"email\" : \"joris.w.dewit@gmail.com\"\n\t\t}\n\t]\n\n}\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/css/bootstrap-timepicker.css",
    "content": "/*!\n * Timepicker Component for Twitter Bootstrap\n *\n * Copyright 2013 Joris de Wit\n *\n * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n.bootstrap-timepicker {\n  position: relative;\n}\n.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu {\n  left: auto;\n  right: 0;\n}\n.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before {\n  left: auto;\n  right: 12px;\n}\n.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after {\n  left: auto;\n  right: 13px;\n}\n.bootstrap-timepicker .input-group-addon {\n  cursor: pointer;\n}\n.bootstrap-timepicker .input-group-addon i {\n  display: inline-block;\n  width: 16px;\n  height: 16px;\n}\n.bootstrap-timepicker-widget.dropdown-menu {\n  padding: 4px;\n}\n.bootstrap-timepicker-widget.dropdown-menu.open {\n  display: inline-block;\n}\n.bootstrap-timepicker-widget.dropdown-menu:before {\n  border-bottom: 7px solid rgba(0, 0, 0, 0.2);\n  border-left: 7px solid transparent;\n  border-right: 7px solid transparent;\n  content: \"\";\n  display: inline-block;\n  position: absolute;\n}\n.bootstrap-timepicker-widget.dropdown-menu:after {\n  border-bottom: 6px solid #FFFFFF;\n  border-left: 6px solid transparent;\n  border-right: 6px solid transparent;\n  content: \"\";\n  display: inline-block;\n  position: absolute;\n}\n.bootstrap-timepicker-widget.timepicker-orient-left:before {\n  left: 6px;\n}\n.bootstrap-timepicker-widget.timepicker-orient-left:after {\n  left: 7px;\n}\n.bootstrap-timepicker-widget.timepicker-orient-right:before {\n  right: 6px;\n}\n.bootstrap-timepicker-widget.timepicker-orient-right:after {\n  right: 7px;\n}\n.bootstrap-timepicker-widget.timepicker-orient-top:before {\n  top: -7px;\n}\n.bootstrap-timepicker-widget.timepicker-orient-top:after {\n  top: -6px;\n}\n.bootstrap-timepicker-widget.timepicker-orient-bottom:before {\n  bottom: -7px;\n  border-bottom: 0;\n  border-top: 7px solid #999;\n}\n.bootstrap-timepicker-widget.timepicker-orient-bottom:after {\n  bottom: -6px;\n  border-bottom: 0;\n  border-top: 6px solid #ffffff;\n}\n.bootstrap-timepicker-widget a.btn,\n.bootstrap-timepicker-widget input {\n  border-radius: 4px;\n}\n.bootstrap-timepicker-widget table {\n  width: 100%;\n  margin: 0;\n}\n.bootstrap-timepicker-widget table td {\n  text-align: center;\n  height: 30px;\n  margin: 0;\n  padding: 2px;\n}\n.bootstrap-timepicker-widget table td:not(.separator) {\n  min-width: 30px;\n}\n.bootstrap-timepicker-widget table td span {\n  width: 100%;\n}\n.bootstrap-timepicker-widget table td a {\n  border: 1px transparent solid;\n  width: 100%;\n  display: inline-block;\n  margin: 0;\n  padding: 8px 0;\n  outline: 0;\n  color: #333;\n}\n.bootstrap-timepicker-widget table td a:hover {\n  text-decoration: none;\n  background-color: #eee;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  border-radius: 4px;\n  border-color: #ddd;\n}\n.bootstrap-timepicker-widget table td a i {\n  margin-top: 2px;\n  font-size: 18px;\n}\n.bootstrap-timepicker-widget table td input {\n  width: 25px;\n  margin: 0;\n  text-align: center;\n}\n.bootstrap-timepicker-widget .modal-content {\n  padding: 4px;\n}\n@media (min-width: 767px) {\n  .bootstrap-timepicker-widget.modal {\n    width: 200px;\n    margin-left: -100px;\n  }\n}\n@media (max-width: 767px) {\n  .bootstrap-timepicker {\n    width: 100%;\n  }\n  .bootstrap-timepicker .dropdown-menu {\n    width: 100%;\n  }\n}\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/css/bootstrap-timepicker.min.css",
    "content": "/*!\n * Timepicker Component for Twitter Bootstrap\n *\n * Copyright 2013 Joris de Wit\n *\n * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */.bootstrap-timepicker{position:relative}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu{left:auto;right:0}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before{left:auto;right:12px}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after{left:auto;right:13px}.bootstrap-timepicker .input-group-addon{cursor:pointer}.bootstrap-timepicker .input-group-addon i{display:inline-block;width:16px;height:16px}.bootstrap-timepicker-widget.dropdown-menu{padding:4px}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block}.bootstrap-timepicker-widget.dropdown-menu:before{border-bottom:7px solid rgba(0,0,0,0.2);border-left:7px solid transparent;border-right:7px solid transparent;content:\"\";display:inline-block;position:absolute}.bootstrap-timepicker-widget.dropdown-menu:after{border-bottom:6px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent;content:\"\";display:inline-block;position:absolute}.bootstrap-timepicker-widget.timepicker-orient-left:before{left:6px}.bootstrap-timepicker-widget.timepicker-orient-left:after{left:7px}.bootstrap-timepicker-widget.timepicker-orient-right:before{right:6px}.bootstrap-timepicker-widget.timepicker-orient-right:after{right:7px}.bootstrap-timepicker-widget.timepicker-orient-top:before{top:-7px}.bootstrap-timepicker-widget.timepicker-orient-top:after{top:-6px}.bootstrap-timepicker-widget.timepicker-orient-bottom:before{bottom:-7px;border-bottom:0;border-top:7px solid #999}.bootstrap-timepicker-widget.timepicker-orient-bottom:after{bottom:-6px;border-bottom:0;border-top:6px solid #fff}.bootstrap-timepicker-widget a.btn,.bootstrap-timepicker-widget input{border-radius:4px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{text-align:center;height:30px;margin:0;padding:2px}.bootstrap-timepicker-widget table td:not(.separator){min-width:30px}.bootstrap-timepicker-widget table td span{width:100%}.bootstrap-timepicker-widget table td a{border:1px transparent solid;width:100%;display:inline-block;margin:0;padding:8px 0;outline:0;color:#333}.bootstrap-timepicker-widget table td a:hover{text-decoration:none;background-color:#eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border-color:#ddd}.bootstrap-timepicker-widget table td a i{margin-top:2px;font-size:18px}.bootstrap-timepicker-widget table td input{width:25px;margin:0;text-align:center}.bootstrap-timepicker-widget .modal-content{padding:4px}@media(min-width:767px){.bootstrap-timepicker-widget.modal{width:200px;margin-left:-100px}}@media(max-width:767px){.bootstrap-timepicker{width:100%}.bootstrap-timepicker .dropdown-menu{width:100%}}"
  },
  {
    "path": "src/libs/bootstrap-timepicker/css/timepicker.less",
    "content": "/*!\n * Timepicker Component for Twitter Bootstrap\n *\n * Copyright 2013 Joris de Wit\n *\n * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n.bootstrap-timepicker {\n    position: relative;\n\n    &.pull-right {\n        .bootstrap-timepicker-widget {\n            &.dropdown-menu {\n                left: auto;\n                right: 0;\n\n                &:before {\n                    left: auto;\n                    right: 12px;\n                }\n                &:after {\n                    left: auto;\n                    right: 13px;\n                }\n            }\n        }\n    }\n\n    .input-group-addon {\n        cursor: pointer;\n        i {\n           display: inline-block;\n           width: 16px;\n           height: 16px;\n        }\n    }\n}\n.bootstrap-timepicker-widget {\n    &.dropdown-menu {\n        padding: 4px;\n        &.open {\n            display: inline-block;\n        }\n        &:before {\n            border-bottom: 7px solid rgba(0, 0, 0, 0.2);\n            border-left: 7px solid transparent;\n            border-right: 7px solid transparent;\n            content: \"\";\n            display: inline-block;\n            position: absolute;\n        }\n        &:after {\n            border-bottom: 6px solid #FFFFFF;\n            border-left: 6px solid transparent;\n            border-right: 6px solid transparent;\n            content: \"\";\n            display: inline-block;\n            position: absolute;\n        }\n    }\n    &.timepicker-orient-left {\n        &:before {\n           left: 6px;\n        }\n        &:after {\n           left: 7px;\n        }\n    }\n    &.timepicker-orient-right {\n        &:before {\n           right: 6px;\n        }\n        &:after {\n           right: 7px;\n        }\n    }\n    &.timepicker-orient-top {\n        &:before {\n           top: -7px;\n        }\n        &:after {\n            top: -6px;\n        }\n    }\n    &.timepicker-orient-bottom {\n        &:before {\n            bottom: -7px;\n            border-bottom: 0;\n            border-top: 7px solid #999;\n        }\n        &:after {\n            bottom: -6px;\n            border-bottom: 0;\n            border-top: 6px solid #ffffff;\n        }\n    }\n    a.btn, input {\n        border-radius: 4px;\n    }\n\n    table {\n        width: 100%;\n        margin: 0;\n\n        td {\n            text-align: center;\n            height: 30px;\n            margin: 0;\n            padding: 2px;\n\n            &:not(.separator) {\n                min-width: 30px;\n            }\n\n            span {\n                width: 100%;\n            }\n            a {\n                border: 1px transparent solid;\n                width: 100%;\n                display: inline-block;\n                margin: 0;\n                padding: 8px 0;\n                outline: 0;\n                color: #333;\n\n                &:hover {\n                    text-decoration: none;\n                    background-color: #eee;\n                    -webkit-border-radius: 4px;\n                    -moz-border-radius: 4px;\n                    border-radius: 4px;\n                    border-color: #ddd;\n                }\n\n                i {\n                    margin-top: 2px;\n                    font-size: 18px;\n                }\n            }\n            input {\n                width: 25px;\n                margin: 0;\n                text-align: center;\n            }\n        }\n    }\n}\n\n.bootstrap-timepicker-widget .modal-content {\n    padding: 4px;\n}\n\n@media (min-width: 767px) {\n    .bootstrap-timepicker-widget.modal {\n        width: 200px;\n        margin-left: -100px;\n    }\n}\n\n@media (max-width: 767px) {\n    .bootstrap-timepicker {\n        width: 100%;\n\n        .dropdown-menu {\n            width: 100%;\n        }\n    }\n}\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/js/bootstrap-timepicker.js",
    "content": "/*!\n * Timepicker Component for Twitter Bootstrap\n *\n * Copyright 2013 Joris de Wit and bootstrap-timepicker contributors\n *\n * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n(function($, window, document) {\n  'use strict';\n\n  // TIMEPICKER PUBLIC CLASS DEFINITION\n  var Timepicker = function(element, options) {\n    this.widget = '';\n    this.$element = $(element);\n    this.defaultTime = options.defaultTime;\n    this.disableFocus = options.disableFocus;\n    this.disableMousewheel = options.disableMousewheel;\n    this.isOpen = options.isOpen;\n    this.minuteStep = options.minuteStep;\n    this.modalBackdrop = options.modalBackdrop;\n    this.orientation = options.orientation;\n    this.secondStep = options.secondStep;\n    this.snapToStep = options.snapToStep;\n    this.showInputs = options.showInputs;\n    this.showMeridian = options.showMeridian;\n    this.showSeconds = options.showSeconds;\n    this.template = options.template;\n    this.appendWidgetTo = options.appendWidgetTo;\n    this.showWidgetOnAddonClick = options.showWidgetOnAddonClick;\n    this.icons = options.icons;\n    this.maxHours = options.maxHours;\n    this.explicitMode = options.explicitMode; // If true 123 = 1:23, 12345 = 1:23:45, else invalid.\n\n    this.handleDocumentClick = function (e) {\n      var self = e.data.scope;\n      // This condition was inspired by bootstrap-datepicker.\n      // The element the timepicker is invoked on is the input but it has a sibling for addon/button.\n      if (!(self.$element.parent().find(e.target).length ||\n          self.$widget.is(e.target) ||\n          self.$widget.find(e.target).length)) {\n        self.hideWidget();\n      }\n    };\n\n    this._init();\n  };\n\n  Timepicker.prototype = {\n\n    constructor: Timepicker,\n    _init: function() {\n      var self = this;\n\n      if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-group') && this.$element.parent().hasClass('bootstrap-timepicker'))) {\n        this.$element.parent('.input-group.bootstrap-timepicker').find('.input-group-addon').on({\n          'click.timepicker': $.proxy(this.showWidget, this)\n        });\n        this.$element.on({\n          'focus.timepicker': $.proxy(this.highlightUnit, this),\n          'click.timepicker': $.proxy(this.highlightUnit, this),\n          'keydown.timepicker': $.proxy(this.elementKeydown, this),\n          'blur.timepicker': $.proxy(this.blurElement, this),\n          'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)\n        });\n      } else {\n        if (this.template) {\n          this.$element.on({\n            'focus.timepicker': $.proxy(this.showWidget, this),\n            'click.timepicker': $.proxy(this.showWidget, this),\n            'blur.timepicker': $.proxy(this.blurElement, this),\n            'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)\n          });\n        } else {\n          this.$element.on({\n            'focus.timepicker': $.proxy(this.highlightUnit, this),\n            'click.timepicker': $.proxy(this.highlightUnit, this),\n            'keydown.timepicker': $.proxy(this.elementKeydown, this),\n            'blur.timepicker': $.proxy(this.blurElement, this),\n            'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)\n          });\n        }\n      }\n\n      if (this.template !== false) {\n        this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this));\n      } else {\n        this.$widget = false;\n      }\n\n      if (this.showInputs && this.$widget !== false) {\n        this.$widget.find('input').each(function() {\n          $(this).on({\n            'click.timepicker': function() { $(this).select(); },\n            'keydown.timepicker': $.proxy(self.widgetKeydown, self),\n            'keyup.timepicker': $.proxy(self.widgetKeyup, self)\n          });\n        });\n      }\n\n      this.setDefaultTime(this.defaultTime);\n    },\n\n    blurElement: function() {\n      this.highlightedUnit = null;\n      this.updateFromElementVal();\n    },\n\n    clear: function() {\n      this.hour = '';\n      this.minute = '';\n      this.second = '';\n      this.meridian = '';\n\n      this.$element.val('');\n    },\n\n    decrementHour: function() {\n      if (this.showMeridian) {\n        if (this.hour === 1) {\n          this.hour = 12;\n        } else if (this.hour === 12) {\n          this.hour--;\n\n          return this.toggleMeridian();\n        } else if (this.hour === 0) {\n          this.hour = 11;\n\n          return this.toggleMeridian();\n        } else {\n          this.hour--;\n        }\n      } else {\n        if (this.hour <= 0) {\n          this.hour = this.maxHours - 1;\n        } else {\n          this.hour--;\n        }\n      }\n    },\n\n    decrementMinute: function(step) {\n      var newVal;\n\n      if (step) {\n        newVal = this.minute - step;\n      } else {\n        newVal = this.minute - this.minuteStep;\n      }\n\n      if (newVal < 0) {\n        this.decrementHour();\n        this.minute = newVal + 60;\n      } else {\n        this.minute = newVal;\n      }\n    },\n\n    decrementSecond: function() {\n      var newVal = this.second - this.secondStep;\n\n      if (newVal < 0) {\n        this.decrementMinute(true);\n        this.second = newVal + 60;\n      } else {\n        this.second = newVal;\n      }\n    },\n\n    elementKeydown: function(e) {\n      switch (e.which) {\n      case 9: //tab\n        if (e.shiftKey) {\n          if (this.highlightedUnit === 'hour') {\n            this.hideWidget();\n            break;\n          }\n          this.highlightPrevUnit();\n        } else if ((this.showMeridian && this.highlightedUnit === 'meridian') || (this.showSeconds && this.highlightedUnit === 'second') || (!this.showMeridian && !this.showSeconds && this.highlightedUnit ==='minute')) {\n          this.hideWidget();\n          break;\n        } else {\n          this.highlightNextUnit();\n        }\n        e.preventDefault();\n        this.updateFromElementVal();\n        break;\n      case 27: // escape\n        this.updateFromElementVal();\n        break;\n      case 37: // left arrow\n        e.preventDefault();\n        this.highlightPrevUnit();\n        this.updateFromElementVal();\n        break;\n      case 38: // up arrow\n        e.preventDefault();\n        switch (this.highlightedUnit) {\n        case 'hour':\n          this.incrementHour();\n          this.highlightHour();\n          break;\n        case 'minute':\n          this.incrementMinute();\n          this.highlightMinute();\n          break;\n        case 'second':\n          this.incrementSecond();\n          this.highlightSecond();\n          break;\n        case 'meridian':\n          this.toggleMeridian();\n          this.highlightMeridian();\n          break;\n        }\n        this.update();\n        break;\n      case 39: // right arrow\n        e.preventDefault();\n        this.highlightNextUnit();\n        this.updateFromElementVal();\n        break;\n      case 40: // down arrow\n        e.preventDefault();\n        switch (this.highlightedUnit) {\n        case 'hour':\n          this.decrementHour();\n          this.highlightHour();\n          break;\n        case 'minute':\n          this.decrementMinute();\n          this.highlightMinute();\n          break;\n        case 'second':\n          this.decrementSecond();\n          this.highlightSecond();\n          break;\n        case 'meridian':\n          this.toggleMeridian();\n          this.highlightMeridian();\n          break;\n        }\n\n        this.update();\n        break;\n      }\n    },\n\n    getCursorPosition: function() {\n      var input = this.$element.get(0);\n\n      if ('selectionStart' in input) {// Standard-compliant browsers\n\n        return input.selectionStart;\n      } else if (document.selection) {// IE fix\n        input.focus();\n        var sel = document.selection.createRange(),\n          selLen = document.selection.createRange().text.length;\n\n        sel.moveStart('character', - input.value.length);\n\n        return sel.text.length - selLen;\n      }\n    },\n\n    getTemplate: function() {\n      var template,\n        hourTemplate,\n        minuteTemplate,\n        secondTemplate,\n        meridianTemplate,\n        templateContent;\n\n      if (this.showInputs) {\n        hourTemplate = '<input type=\"text\" class=\"bootstrap-timepicker-hour\" maxlength=\"2\"/>';\n        minuteTemplate = '<input type=\"text\" class=\"bootstrap-timepicker-minute\" maxlength=\"2\"/>';\n        secondTemplate = '<input type=\"text\" class=\"bootstrap-timepicker-second\" maxlength=\"2\"/>';\n        meridianTemplate = '<input type=\"text\" class=\"bootstrap-timepicker-meridian\" maxlength=\"2\"/>';\n      } else {\n        hourTemplate = '<span class=\"bootstrap-timepicker-hour\"></span>';\n        minuteTemplate = '<span class=\"bootstrap-timepicker-minute\"></span>';\n        secondTemplate = '<span class=\"bootstrap-timepicker-second\"></span>';\n        meridianTemplate = '<span class=\"bootstrap-timepicker-meridian\"></span>';\n      }\n\n      templateContent = '<table>'+\n         '<tr>'+\n           '<td><a href=\"#\" data-action=\"incrementHour\"><span class=\"'+ this.icons.up +'\"></span></a></td>'+\n           '<td class=\"separator\">&nbsp;</td>'+\n           '<td><a href=\"#\" data-action=\"incrementMinute\"><span class=\"'+ this.icons.up +'\"></span></a></td>'+\n           (this.showSeconds ?\n             '<td class=\"separator\">&nbsp;</td>'+\n             '<td><a href=\"#\" data-action=\"incrementSecond\"><span class=\"'+ this.icons.up +'\"></span></a></td>'\n           : '') +\n           (this.showMeridian ?\n             '<td class=\"separator\">&nbsp;</td>'+\n             '<td class=\"meridian-column\"><a href=\"#\" data-action=\"toggleMeridian\"><span class=\"'+ this.icons.up +'\"></span></a></td>'\n           : '') +\n         '</tr>'+\n         '<tr>'+\n           '<td>'+ hourTemplate +'</td> '+\n           '<td class=\"separator\">:</td>'+\n           '<td>'+ minuteTemplate +'</td> '+\n           (this.showSeconds ?\n            '<td class=\"separator\">:</td>'+\n            '<td>'+ secondTemplate +'</td>'\n           : '') +\n           (this.showMeridian ?\n            '<td class=\"separator\">&nbsp;</td>'+\n            '<td>'+ meridianTemplate +'</td>'\n           : '') +\n         '</tr>'+\n         '<tr>'+\n           '<td><a href=\"#\" data-action=\"decrementHour\"><span class=\"'+ this.icons.down +'\"></span></a></td>'+\n           '<td class=\"separator\"></td>'+\n           '<td><a href=\"#\" data-action=\"decrementMinute\"><span class=\"'+ this.icons.down +'\"></span></a></td>'+\n           (this.showSeconds ?\n            '<td class=\"separator\">&nbsp;</td>'+\n            '<td><a href=\"#\" data-action=\"decrementSecond\"><span class=\"'+ this.icons.down +'\"></span></a></td>'\n           : '') +\n           (this.showMeridian ?\n            '<td class=\"separator\">&nbsp;</td>'+\n            '<td><a href=\"#\" data-action=\"toggleMeridian\"><span class=\"'+ this.icons.down +'\"></span></a></td>'\n           : '') +\n         '</tr>'+\n       '</table>';\n\n      switch(this.template) {\n      case 'modal':\n        template = '<div class=\"bootstrap-timepicker-widget modal hide fade in\" data-backdrop=\"'+ (this.modalBackdrop ? 'true' : 'false') +'\">'+\n          '<div class=\"modal-header\">'+\n            '<a href=\"#\" class=\"close\" data-dismiss=\"modal\">&times;</a>'+\n            '<h3>Pick a Time</h3>'+\n          '</div>'+\n          '<div class=\"modal-content\">'+\n            templateContent +\n          '</div>'+\n          '<div class=\"modal-footer\">'+\n            '<a href=\"#\" class=\"btn btn-primary\" data-dismiss=\"modal\">OK</a>'+\n          '</div>'+\n        '</div>';\n        break;\n      case 'dropdown':\n        template = '<div class=\"bootstrap-timepicker-widget dropdown-menu\">'+ templateContent +'</div>';\n        break;\n      }\n\n      return template;\n    },\n\n    getTime: function() {\n      if (this.hour === '') {\n        return '';\n      }\n\n      return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : '');\n    },\n\n    hideWidget: function() {\n      if (this.isOpen === false) {\n        return;\n      }\n\n      this.$element.trigger({\n        'type': 'hide.timepicker',\n        'time': {\n          'value': this.getTime(),\n          'hours': this.hour,\n          'minutes': this.minute,\n          'seconds': this.second,\n          'meridian': this.meridian\n        }\n      });\n\n      if (this.template === 'modal' && this.$widget.modal) {\n        this.$widget.modal('hide');\n      } else {\n        this.$widget.removeClass('open');\n      }\n\n      $(document).off('mousedown.timepicker, touchend.timepicker', this.handleDocumentClick);\n\n      this.isOpen = false;\n      // m_show/hide approach taken by datepicker\n      this.$widget.detach();\n    },\n\n    highlightUnit: function() {\n      this.position = this.getCursorPosition();\n      if (this.position >= 0 && this.position <= 2) {\n        this.highlightHour();\n      } else if (this.position >= 3 && this.position <= 5) {\n        this.highlightMinute();\n      } else if (this.position >= 6 && this.position <= 8) {\n        if (this.showSeconds) {\n          this.highlightSecond();\n        } else {\n          this.highlightMeridian();\n        }\n      } else if (this.position >= 9 && this.position <= 11) {\n        this.highlightMeridian();\n      }\n    },\n\n    highlightNextUnit: function() {\n      switch (this.highlightedUnit) {\n      case 'hour':\n        this.highlightMinute();\n        break;\n      case 'minute':\n        if (this.showSeconds) {\n          this.highlightSecond();\n        } else if (this.showMeridian){\n          this.highlightMeridian();\n        } else {\n          this.highlightHour();\n        }\n        break;\n      case 'second':\n        if (this.showMeridian) {\n          this.highlightMeridian();\n        } else {\n          this.highlightHour();\n        }\n        break;\n      case 'meridian':\n        this.highlightHour();\n        break;\n      }\n    },\n\n    highlightPrevUnit: function() {\n      switch (this.highlightedUnit) {\n      case 'hour':\n        if(this.showMeridian){\n          this.highlightMeridian();\n        } else if (this.showSeconds) {\n          this.highlightSecond();\n        } else {\n          this.highlightMinute();\n        }\n        break;\n      case 'minute':\n        this.highlightHour();\n        break;\n      case 'second':\n        this.highlightMinute();\n        break;\n      case 'meridian':\n        if (this.showSeconds) {\n          this.highlightSecond();\n        } else {\n          this.highlightMinute();\n        }\n        break;\n      }\n    },\n\n    highlightHour: function() {\n      var $element = this.$element.get(0),\n          self = this;\n\n      this.highlightedUnit = 'hour';\n\n      if ($element.setSelectionRange) {\n        setTimeout(function() {\n          if (self.hour < 10) {\n            $element.setSelectionRange(0,1);\n          } else {\n            $element.setSelectionRange(0,2);\n          }\n        }, 0);\n      }\n    },\n\n    highlightMinute: function() {\n      var $element = this.$element.get(0),\n          self = this;\n\n      this.highlightedUnit = 'minute';\n\n      if ($element.setSelectionRange) {\n        setTimeout(function() {\n          if (self.hour < 10) {\n            $element.setSelectionRange(2,4);\n          } else {\n            $element.setSelectionRange(3,5);\n          }\n        }, 0);\n      }\n    },\n\n    highlightSecond: function() {\n      var $element = this.$element.get(0),\n          self = this;\n\n      this.highlightedUnit = 'second';\n\n      if ($element.setSelectionRange) {\n        setTimeout(function() {\n          if (self.hour < 10) {\n            $element.setSelectionRange(5,7);\n          } else {\n            $element.setSelectionRange(6,8);\n          }\n        }, 0);\n      }\n    },\n\n    highlightMeridian: function() {\n      var $element = this.$element.get(0),\n          self = this;\n\n      this.highlightedUnit = 'meridian';\n\n      if ($element.setSelectionRange) {\n        if (this.showSeconds) {\n          setTimeout(function() {\n            if (self.hour < 10) {\n              $element.setSelectionRange(8,10);\n            } else {\n              $element.setSelectionRange(9,11);\n            }\n          }, 0);\n        } else {\n          setTimeout(function() {\n            if (self.hour < 10) {\n              $element.setSelectionRange(5,7);\n            } else {\n              $element.setSelectionRange(6,8);\n            }\n          }, 0);\n        }\n      }\n    },\n\n    incrementHour: function() {\n      if (this.showMeridian) {\n        if (this.hour === 11) {\n          this.hour++;\n          return this.toggleMeridian();\n        } else if (this.hour === 12) {\n          this.hour = 0;\n        }\n      }\n      if (this.hour === this.maxHours - 1) {\n        this.hour = 0;\n\n        return;\n      }\n      this.hour++;\n    },\n\n    incrementMinute: function(step) {\n      var newVal;\n\n      if (step) {\n        newVal = this.minute + step;\n      } else {\n        newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep);\n      }\n\n      if (newVal > 59) {\n        this.incrementHour();\n        this.minute = newVal - 60;\n      } else {\n        this.minute = newVal;\n      }\n    },\n\n    incrementSecond: function() {\n      var newVal = this.second + this.secondStep - (this.second % this.secondStep);\n\n      if (newVal > 59) {\n        this.incrementMinute(true);\n        this.second = newVal - 60;\n      } else {\n        this.second = newVal;\n      }\n    },\n\n    mousewheel: function(e) {\n      if (this.disableMousewheel) {\n        return;\n      }\n\n      e.preventDefault();\n      e.stopPropagation();\n\n      var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail,\n          scrollTo = null;\n\n      if (e.type === 'mousewheel') {\n        scrollTo = (e.originalEvent.wheelDelta * -1);\n      }\n      else if (e.type === 'DOMMouseScroll') {\n        scrollTo = 40 * e.originalEvent.detail;\n      }\n\n      if (scrollTo) {\n        e.preventDefault();\n        $(this).scrollTop(scrollTo + $(this).scrollTop());\n      }\n\n      switch (this.highlightedUnit) {\n      case 'minute':\n        if (delta > 0) {\n          this.incrementMinute();\n        } else {\n          this.decrementMinute();\n        }\n        this.highlightMinute();\n        break;\n      case 'second':\n        if (delta > 0) {\n          this.incrementSecond();\n        } else {\n          this.decrementSecond();\n        }\n        this.highlightSecond();\n        break;\n      case 'meridian':\n        this.toggleMeridian();\n        this.highlightMeridian();\n        break;\n      default:\n        if (delta > 0) {\n          this.incrementHour();\n        } else {\n          this.decrementHour();\n        }\n        this.highlightHour();\n        break;\n      }\n\n      return false;\n    },\n\n    /**\n     * Given a segment value like 43, will round and snap the segment\n     * to the nearest \"step\", like 45 if step is 15. Segment will\n     * \"overflow\" to 0 if it's larger than 59 or would otherwise\n     * round up to 60.\n     */\n    changeToNearestStep: function (segment, step) {\n      if (segment % step === 0) {\n        return segment;\n      }\n      if (Math.round((segment % step) / step)) {\n        return (segment + (step - segment % step)) % 60;\n      } else {\n        return segment - segment % step;\n      }\n    },\n\n    // This method was adapted from bootstrap-datepicker.\n    place : function() {\n      if (this.isInline) {\n        return;\n      }\n      var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth =\n        $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop();\n\n      var zIndex = parseInt(this.$element.parents().filter(function() { return $(this).css('z-index') !== 'auto'; }).first().css('z-index'), 10) + 10;\n      var offset = this.component ? this.component.parent().offset() : this.$element.offset();\n      var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false);\n      var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false);\n      var left = offset.left, top = offset.top;\n\n      this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left');\n\n      if (this.orientation.x !== 'auto') {\n        this.$widget.addClass('timepicker-orient-' + this.orientation.x);\n        if (this.orientation.x === 'right') {\n          left -= widgetWidth - width;\n        }\n      } else{\n        // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways\n        // Default to left\n        this.$widget.addClass('timepicker-orient-left');\n        if (offset.left < 0) {\n          left -= offset.left - visualPadding;\n        } else if (offset.left + widgetWidth > windowWidth) {\n          left = windowWidth - widgetWidth - visualPadding;\n        }\n      }\n      // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget\n      var yorient = this.orientation.y, topOverflow, bottomOverflow;\n      if (yorient === 'auto') {\n        topOverflow = -scrollTop + offset.top - widgetHeight;\n        bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight);\n        if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) {\n          yorient = 'top';\n        } else {\n          yorient = 'bottom';\n        }\n      }\n      this.$widget.addClass('timepicker-orient-' + yorient);\n      if (yorient === 'top'){\n        top += height;\n      } else{\n        top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10);\n      }\n\n      this.$widget.css({\n        top : top,\n        left : left,\n        zIndex : zIndex\n      });\n    },\n\n    remove: function() {\n      $('document').off('.timepicker');\n      if (this.$widget) {\n        this.$widget.remove();\n      }\n      delete this.$element.data().timepicker;\n    },\n\n    setDefaultTime: function(defaultTime) {\n      if (!this.$element.val()) {\n        if (defaultTime === 'current') {\n          var dTime = new Date(),\n            hours = dTime.getHours(),\n            minutes = dTime.getMinutes(),\n            seconds = dTime.getSeconds(),\n            meridian = 'AM';\n\n          if (seconds !== 0) {\n            seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep;\n            if (seconds === 60) {\n              minutes += 1;\n              seconds = 0;\n            }\n          }\n\n          if (minutes !== 0) {\n            minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep;\n            if (minutes === 60) {\n              hours += 1;\n              minutes = 0;\n            }\n          }\n\n          if (this.showMeridian) {\n            if (hours === 0) {\n              hours = 12;\n            } else if (hours >= 12) {\n              if (hours > 12) {\n                hours = hours - 12;\n              }\n              meridian = 'PM';\n            } else {\n              meridian = 'AM';\n            }\n          }\n\n          this.hour = hours;\n          this.minute = minutes;\n          this.second = seconds;\n          this.meridian = meridian;\n\n          this.update();\n\n        } else if (defaultTime === false) {\n          this.hour = 0;\n          this.minute = 0;\n          this.second = 0;\n          this.meridian = 'AM';\n        } else {\n          this.setTime(defaultTime);\n        }\n      } else {\n        this.updateFromElementVal();\n      }\n    },\n\n    setTime: function(time, ignoreWidget) {\n      if (!time) {\n        this.clear();\n        return;\n      }\n\n      var timeMode,\n          timeArray,\n          hour,\n          minute,\n          second,\n          meridian;\n\n      if (typeof time === 'object' && time.getMonth){\n        // this is a date object\n        hour    = time.getHours();\n        minute  = time.getMinutes();\n        second  = time.getSeconds();\n\n        if (this.showMeridian){\n          meridian = 'AM';\n          if (hour > 12){\n            meridian = 'PM';\n            hour = hour % 12;\n          }\n\n          if (hour === 12){\n            meridian = 'PM';\n          }\n        }\n      } else {\n        timeMode = ((/a/i).test(time) ? 1 : 0) + ((/p/i).test(time) ? 2 : 0); // 0 = none, 1 = AM, 2 = PM, 3 = BOTH.\n        if (timeMode > 2) { // If both are present, fail.\n          this.clear();\n          return;\n        }\n\n        timeArray = time.replace(/[^0-9\\:]/g, '').split(':');\n\n        hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();\n\n        if(this.explicitMode && hour.length > 2 && (hour.length % 2) !== 0 ) {\n          this.clear();\n          return;\n        }\n\n        minute = timeArray[1] ? timeArray[1].toString() : '';\n        second = timeArray[2] ? timeArray[2].toString() : '';\n\n        // adaptive time parsing\n        if (hour.length > 4) {\n          second = hour.slice(-2);\n          hour = hour.slice(0, -2);\n        }\n\n        if (hour.length > 2) {\n          minute = hour.slice(-2);\n          hour = hour.slice(0, -2);\n        }\n\n        if (minute.length > 2) {\n          second = minute.slice(-2);\n          minute = minute.slice(0, -2);\n        }\n\n        hour = parseInt(hour, 10);\n        minute = parseInt(minute, 10);\n        second = parseInt(second, 10);\n\n        if (isNaN(hour)) {\n          hour = 0;\n        }\n        if (isNaN(minute)) {\n          minute = 0;\n        }\n        if (isNaN(second)) {\n          second = 0;\n        }\n\n        // Adjust the time based upon unit boundary.\n        // NOTE: Negatives will never occur due to time.replace() above.\n        if (second > 59) {\n          second = 59;\n        }\n\n        if (minute > 59) {\n          minute = 59;\n        }\n\n        if (hour >= this.maxHours) {\n          // No day/date handling.\n          hour = this.maxHours - 1;\n        }\n\n        if (this.showMeridian) {\n          if (hour > 12) {\n            // Force PM.\n            timeMode = 2;\n            hour -= 12;\n          }\n          if (!timeMode) {\n            timeMode = 1;\n          }\n          if (hour === 0) {\n            hour = 12; // AM or PM, reset to 12.  0 AM = 12 AM.  0 PM = 12 PM, etc.\n          }\n          meridian = timeMode === 1 ? 'AM' : 'PM';\n        } else if (hour < 12 && timeMode === 2) {\n          hour += 12;\n        } else {\n          if (hour >= this.maxHours) {\n            hour = this.maxHours - 1;\n          } else if ((hour < 0) || (hour === 12 && timeMode === 1)){\n            hour = 0;\n          }\n        }\n      }\n\n      this.hour = hour;\n      if (this.snapToStep) {\n        this.minute = this.changeToNearestStep(minute, this.minuteStep);\n        this.second = this.changeToNearestStep(second, this.secondStep);\n      } else {\n        this.minute = minute;\n        this.second = second;\n      }\n      this.meridian = meridian;\n\n      this.update(ignoreWidget);\n    },\n\n    showWidget: function() {\n      if (this.isOpen) {\n        return;\n      }\n\n      if (this.$element.is(':disabled')) {\n        return;\n      }\n\n      // m_show/hide approach taken by datepicker\n      this.$widget.appendTo(this.appendWidgetTo);\n      $(document).on('mousedown.timepicker, touchend.timepicker', {scope: this}, this.handleDocumentClick);\n\n      this.$element.trigger({\n        'type': 'show.timepicker',\n        'time': {\n          'value': this.getTime(),\n          'hours': this.hour,\n          'minutes': this.minute,\n          'seconds': this.second,\n          'meridian': this.meridian\n        }\n      });\n\n      this.place();\n      if (this.disableFocus) {\n        this.$element.blur();\n      }\n\n      // widget shouldn't be empty on open\n      if (this.hour === '') {\n        if (this.defaultTime) {\n          this.setDefaultTime(this.defaultTime);\n        } else {\n          this.setTime('0:0:0');\n        }\n      }\n\n      if (this.template === 'modal' && this.$widget.modal) {\n        this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this));\n      } else {\n        if (this.isOpen === false) {\n          this.$widget.addClass('open');\n        }\n      }\n\n      this.isOpen = true;\n    },\n\n    toggleMeridian: function() {\n      this.meridian = this.meridian === 'AM' ? 'PM' : 'AM';\n    },\n\n    update: function(ignoreWidget) {\n      this.updateElement();\n      if (!ignoreWidget) {\n        this.updateWidget();\n      }\n\n      this.$element.trigger({\n        'type': 'changeTime.timepicker',\n        'time': {\n          'value': this.getTime(),\n          'hours': this.hour,\n          'minutes': this.minute,\n          'seconds': this.second,\n          'meridian': this.meridian\n        }\n      });\n    },\n\n    updateElement: function() {\n      this.$element.val(this.getTime()).change();\n    },\n\n    updateFromElementVal: function() {\n      this.setTime(this.$element.val());\n    },\n\n    updateWidget: function() {\n      if (this.$widget === false) {\n        return;\n      }\n\n      var hour = this.hour,\n          minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute,\n          second = this.second.toString().length === 1 ? '0' + this.second : this.second;\n\n      if (this.showInputs) {\n        this.$widget.find('input.bootstrap-timepicker-hour').val(hour);\n        this.$widget.find('input.bootstrap-timepicker-minute').val(minute);\n\n        if (this.showSeconds) {\n          this.$widget.find('input.bootstrap-timepicker-second').val(second);\n        }\n        if (this.showMeridian) {\n          this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian);\n        }\n      } else {\n        this.$widget.find('span.bootstrap-timepicker-hour').text(hour);\n        this.$widget.find('span.bootstrap-timepicker-minute').text(minute);\n\n        if (this.showSeconds) {\n          this.$widget.find('span.bootstrap-timepicker-second').text(second);\n        }\n        if (this.showMeridian) {\n          this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian);\n        }\n      }\n    },\n\n    updateFromWidgetInputs: function() {\n      if (this.$widget === false) {\n        return;\n      }\n\n      var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' +\n              this.$widget.find('input.bootstrap-timepicker-minute').val() +\n              (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') +\n              (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '')\n      ;\n\n      this.setTime(t, true);\n    },\n\n    widgetClick: function(e) {\n      e.stopPropagation();\n      e.preventDefault();\n\n      var $input = $(e.target),\n          action = $input.closest('a').data('action');\n\n      if (action) {\n        this[action]();\n      }\n      this.update();\n\n      if ($input.is('input')) {\n        $input.get(0).setSelectionRange(0,2);\n      }\n    },\n\n    widgetKeydown: function(e) {\n      var $input = $(e.target),\n          name = $input.attr('class').replace('bootstrap-timepicker-', '');\n\n      switch (e.which) {\n      case 9: //tab\n        if (e.shiftKey) {\n          if (name === 'hour') {\n            return this.hideWidget();\n          }\n        } else if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {\n          return this.hideWidget();\n        }\n        break;\n      case 27: // escape\n        this.hideWidget();\n        break;\n      case 38: // up arrow\n        e.preventDefault();\n        switch (name) {\n        case 'hour':\n          this.incrementHour();\n          break;\n        case 'minute':\n          this.incrementMinute();\n          break;\n        case 'second':\n          this.incrementSecond();\n          break;\n        case 'meridian':\n          this.toggleMeridian();\n          break;\n        }\n        this.setTime(this.getTime());\n        $input.get(0).setSelectionRange(0,2);\n        break;\n      case 40: // down arrow\n        e.preventDefault();\n        switch (name) {\n        case 'hour':\n          this.decrementHour();\n          break;\n        case 'minute':\n          this.decrementMinute();\n          break;\n        case 'second':\n          this.decrementSecond();\n          break;\n        case 'meridian':\n          this.toggleMeridian();\n          break;\n        }\n        this.setTime(this.getTime());\n        $input.get(0).setSelectionRange(0,2);\n        break;\n      }\n    },\n\n    widgetKeyup: function(e) {\n      if ((e.which === 65) || (e.which === 77) || (e.which === 80) || (e.which === 46) || (e.which === 8) || (e.which >= 48 && e.which <= 57) || (e.which >= 96 && e.which <= 105)) {\n        this.updateFromWidgetInputs();\n      }\n    }\n  };\n\n  //TIMEPICKER PLUGIN DEFINITION\n  $.fn.timepicker = function(option) {\n    var args = Array.apply(null, arguments);\n    args.shift();\n    return this.each(function() {\n      var $this = $(this),\n        data = $this.data('timepicker'),\n        options = typeof option === 'object' && option;\n\n      if (!data) {\n        $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data()))));\n      }\n\n      if (typeof option === 'string') {\n        data[option].apply(data, args);\n      }\n    });\n  };\n\n  $.fn.timepicker.defaults = {\n    defaultTime: 'current',\n    disableFocus: false,\n    disableMousewheel: false,\n    isOpen: false,\n    minuteStep: 15,\n    modalBackdrop: false,\n    orientation: { x: 'auto', y: 'auto'},\n    secondStep: 15,\n    snapToStep: false,\n    showSeconds: false,\n    showInputs: true,\n    showMeridian: true,\n    template: 'dropdown',\n    appendWidgetTo: 'body',\n    showWidgetOnAddonClick: true,\n    icons: {\n      up: 'glyphicon glyphicon-chevron-up',\n      down: 'glyphicon glyphicon-chevron-down'\n    },\n    maxHours: 24,\n    explicitMode: false\n  };\n\n  $.fn.timepicker.Constructor = Timepicker;\n\n  $(document).on(\n    'focus.timepicker.data-api click.timepicker.data-api',\n    '[data-provide=\"timepicker\"]',\n    function(e){\n      var $this = $(this);\n      if ($this.data('timepicker')) {\n        return;\n      }\n      e.preventDefault();\n      // component click requires us to explicitly m_show it\n      $this.timepicker();\n    }\n  );\n\n})(jQuery, window, document);\n"
  },
  {
    "path": "src/libs/bootstrap-timepicker/js/bootstrap-timepicker.min.js",
    "content": "/*! bootstrap-timepicker v0.5.2 \n* http://jdewit.github.com/bootstrap-timepicker \n* Copyright (c) 2016 Joris de Wit and bootstrap-timepicker contributors \n* MIT License \n*/!function(a,b,c){\"use strict\";var d=function(b,c){this.widget=\"\",this.$element=a(b),this.defaultTime=c.defaultTime,this.disableFocus=c.disableFocus,this.disableMousewheel=c.disableMousewheel,this.isOpen=c.isOpen,this.minuteStep=c.minuteStep,this.modalBackdrop=c.modalBackdrop,this.orientation=c.orientation,this.secondStep=c.secondStep,this.snapToStep=c.snapToStep,this.showInputs=c.showInputs,this.showMeridian=c.showMeridian,this.showSeconds=c.showSeconds,this.template=c.template,this.appendWidgetTo=c.appendWidgetTo,this.showWidgetOnAddonClick=c.showWidgetOnAddonClick,this.icons=c.icons,this.maxHours=c.maxHours,this.explicitMode=c.explicitMode,this.handleDocumentClick=function(a){var b=a.data.scope;b.$element.parent().find(a.target).length||b.$widget.is(a.target)||b.$widget.find(a.target).length||b.hideWidget()},this._init()};d.prototype={constructor:d,_init:function(){var b=this;this.showWidgetOnAddonClick&&this.$element.parent().hasClass(\"input-group\")&&this.$element.parent().hasClass(\"bootstrap-timepicker\")?(this.$element.parent(\".input-group.bootstrap-timepicker\").find(\".input-group-addon\").on({\"click.timepicker\":a.proxy(this.showWidget,this)}),this.$element.on({\"focus.timepicker\":a.proxy(this.highlightUnit,this),\"click.timepicker\":a.proxy(this.highlightUnit,this),\"keydown.timepicker\":a.proxy(this.elementKeydown,this),\"blur.timepicker\":a.proxy(this.blurElement,this),\"mousewheel.timepicker DOMMouseScroll.timepicker\":a.proxy(this.mousewheel,this)})):this.template?this.$element.on({\"focus.timepicker\":a.proxy(this.showWidget,this),\"click.timepicker\":a.proxy(this.showWidget,this),\"blur.timepicker\":a.proxy(this.blurElement,this),\"mousewheel.timepicker DOMMouseScroll.timepicker\":a.proxy(this.mousewheel,this)}):this.$element.on({\"focus.timepicker\":a.proxy(this.highlightUnit,this),\"click.timepicker\":a.proxy(this.highlightUnit,this),\"keydown.timepicker\":a.proxy(this.elementKeydown,this),\"blur.timepicker\":a.proxy(this.blurElement,this),\"mousewheel.timepicker DOMMouseScroll.timepicker\":a.proxy(this.mousewheel,this)}),this.template!==!1?this.$widget=a(this.getTemplate()).on(\"click\",a.proxy(this.widgetClick,this)):this.$widget=!1,this.showInputs&&this.$widget!==!1&&this.$widget.find(\"input\").each(function(){a(this).on({\"click.timepicker\":function(){a(this).select()},\"keydown.timepicker\":a.proxy(b.widgetKeydown,b),\"keyup.timepicker\":a.proxy(b.widgetKeyup,b)})}),this.setDefaultTime(this.defaultTime)},blurElement:function(){this.highlightedUnit=null,this.updateFromElementVal()},clear:function(){this.hour=\"\",this.minute=\"\",this.second=\"\",this.meridian=\"\",this.$element.val(\"\")},decrementHour:function(){if(this.showMeridian)if(1===this.hour)this.hour=12;else{if(12===this.hour)return this.hour--,this.toggleMeridian();if(0===this.hour)return this.hour=11,this.toggleMeridian();this.hour--}else this.hour<=0?this.hour=this.maxHours-1:this.hour--},decrementMinute:function(a){var b;b=a?this.minute-a:this.minute-this.minuteStep,0>b?(this.decrementHour(),this.minute=b+60):this.minute=b},decrementSecond:function(){var a=this.second-this.secondStep;0>a?(this.decrementMinute(!0),this.second=a+60):this.second=a},elementKeydown:function(a){switch(a.which){case 9:if(a.shiftKey){if(\"hour\"===this.highlightedUnit){this.hideWidget();break}this.highlightPrevUnit()}else{if(this.showMeridian&&\"meridian\"===this.highlightedUnit||this.showSeconds&&\"second\"===this.highlightedUnit||!this.showMeridian&&!this.showSeconds&&\"minute\"===this.highlightedUnit){this.hideWidget();break}this.highlightNextUnit()}a.preventDefault(),this.updateFromElementVal();break;case 27:this.updateFromElementVal();break;case 37:a.preventDefault(),this.highlightPrevUnit(),this.updateFromElementVal();break;case 38:switch(a.preventDefault(),this.highlightedUnit){case\"hour\":this.incrementHour(),this.highlightHour();break;case\"minute\":this.incrementMinute(),this.highlightMinute();break;case\"second\":this.incrementSecond(),this.highlightSecond();break;case\"meridian\":this.toggleMeridian(),this.highlightMeridian()}this.update();break;case 39:a.preventDefault(),this.highlightNextUnit(),this.updateFromElementVal();break;case 40:switch(a.preventDefault(),this.highlightedUnit){case\"hour\":this.decrementHour(),this.highlightHour();break;case\"minute\":this.decrementMinute(),this.highlightMinute();break;case\"second\":this.decrementSecond(),this.highlightSecond();break;case\"meridian\":this.toggleMeridian(),this.highlightMeridian()}this.update()}},getCursorPosition:function(){var a=this.$element.get(0);if(\"selectionStart\"in a)return a.selectionStart;if(c.selection){a.focus();var b=c.selection.createRange(),d=c.selection.createRange().text.length;return b.moveStart(\"character\",-a.value.length),b.text.length-d}},getTemplate:function(){var a,b,c,d,e,f;switch(this.showInputs?(b='<input type=\"text\" class=\"bootstrap-timepicker-hour\" maxlength=\"2\"/>',c='<input type=\"text\" class=\"bootstrap-timepicker-minute\" maxlength=\"2\"/>',d='<input type=\"text\" class=\"bootstrap-timepicker-second\" maxlength=\"2\"/>',e='<input type=\"text\" class=\"bootstrap-timepicker-meridian\" maxlength=\"2\"/>'):(b='<span class=\"bootstrap-timepicker-hour\"></span>',c='<span class=\"bootstrap-timepicker-minute\"></span>',d='<span class=\"bootstrap-timepicker-second\"></span>',e='<span class=\"bootstrap-timepicker-meridian\"></span>'),f='<table><tr><td><a href=\"#\" data-action=\"incrementHour\"><span class=\"'+this.icons.up+'\"></span></a></td><td class=\"separator\">&nbsp;</td><td><a href=\"#\" data-action=\"incrementMinute\"><span class=\"'+this.icons.up+'\"></span></a></td>'+(this.showSeconds?'<td class=\"separator\">&nbsp;</td><td><a href=\"#\" data-action=\"incrementSecond\"><span class=\"'+this.icons.up+'\"></span></a></td>':\"\")+(this.showMeridian?'<td class=\"separator\">&nbsp;</td><td class=\"meridian-column\"><a href=\"#\" data-action=\"toggleMeridian\"><span class=\"'+this.icons.up+'\"></span></a></td>':\"\")+\"</tr><tr><td>\"+b+'</td> <td class=\"separator\">:</td><td>'+c+\"</td> \"+(this.showSeconds?'<td class=\"separator\">:</td><td>'+d+\"</td>\":\"\")+(this.showMeridian?'<td class=\"separator\">&nbsp;</td><td>'+e+\"</td>\":\"\")+'</tr><tr><td><a href=\"#\" data-action=\"decrementHour\"><span class=\"'+this.icons.down+'\"></span></a></td><td class=\"separator\"></td><td><a href=\"#\" data-action=\"decrementMinute\"><span class=\"'+this.icons.down+'\"></span></a></td>'+(this.showSeconds?'<td class=\"separator\">&nbsp;</td><td><a href=\"#\" data-action=\"decrementSecond\"><span class=\"'+this.icons.down+'\"></span></a></td>':\"\")+(this.showMeridian?'<td class=\"separator\">&nbsp;</td><td><a href=\"#\" data-action=\"toggleMeridian\"><span class=\"'+this.icons.down+'\"></span></a></td>':\"\")+\"</tr></table>\",this.template){case\"modal\":a='<div class=\"bootstrap-timepicker-widget modal hide fade in\" data-backdrop=\"'+(this.modalBackdrop?\"true\":\"false\")+'\"><div class=\"modal-header\"><a href=\"#\" class=\"close\" data-dismiss=\"modal\">&times;</a><h3>Pick a Time</h3></div><div class=\"modal-content\">'+f+'</div><div class=\"modal-footer\"><a href=\"#\" class=\"btn btn-primary\" data-dismiss=\"modal\">OK</a></div></div>';break;case\"dropdown\":a='<div class=\"bootstrap-timepicker-widget dropdown-menu\">'+f+\"</div>\"}return a},getTime:function(){return\"\"===this.hour?\"\":this.hour+\":\"+(1===this.minute.toString().length?\"0\"+this.minute:this.minute)+(this.showSeconds?\":\"+(1===this.second.toString().length?\"0\"+this.second:this.second):\"\")+(this.showMeridian?\" \"+this.meridian:\"\")},hideWidget:function(){this.isOpen!==!1&&(this.$element.trigger({type:\"hide.timepicker\",time:{value:this.getTime(),hours:this.hour,minutes:this.minute,seconds:this.second,meridian:this.meridian}}),\"modal\"===this.template&&this.$widget.modal?this.$widget.modal(\"hide\"):this.$widget.removeClass(\"open\"),a(c).off(\"mousedown.timepicker, touchend.timepicker\",this.handleDocumentClick),this.isOpen=!1,this.$widget.detach())},highlightUnit:function(){this.position=this.getCursorPosition(),this.position>=0&&this.position<=2?this.highlightHour():this.position>=3&&this.position<=5?this.highlightMinute():this.position>=6&&this.position<=8?this.showSeconds?this.highlightSecond():this.highlightMeridian():this.position>=9&&this.position<=11&&this.highlightMeridian()},highlightNextUnit:function(){switch(this.highlightedUnit){case\"hour\":this.highlightMinute();break;case\"minute\":this.showSeconds?this.highlightSecond():this.showMeridian?this.highlightMeridian():this.highlightHour();break;case\"second\":this.showMeridian?this.highlightMeridian():this.highlightHour();break;case\"meridian\":this.highlightHour()}},highlightPrevUnit:function(){switch(this.highlightedUnit){case\"hour\":this.showMeridian?this.highlightMeridian():this.showSeconds?this.highlightSecond():this.highlightMinute();break;case\"minute\":this.highlightHour();break;case\"second\":this.highlightMinute();break;case\"meridian\":this.showSeconds?this.highlightSecond():this.highlightMinute()}},highlightHour:function(){var a=this.$element.get(0),b=this;this.highlightedUnit=\"hour\",a.setSelectionRange&&setTimeout(function(){b.hour<10?a.setSelectionRange(0,1):a.setSelectionRange(0,2)},0)},highlightMinute:function(){var a=this.$element.get(0),b=this;this.highlightedUnit=\"minute\",a.setSelectionRange&&setTimeout(function(){b.hour<10?a.setSelectionRange(2,4):a.setSelectionRange(3,5)},0)},highlightSecond:function(){var a=this.$element.get(0),b=this;this.highlightedUnit=\"second\",a.setSelectionRange&&setTimeout(function(){b.hour<10?a.setSelectionRange(5,7):a.setSelectionRange(6,8)},0)},highlightMeridian:function(){var a=this.$element.get(0),b=this;this.highlightedUnit=\"meridian\",a.setSelectionRange&&(this.showSeconds?setTimeout(function(){b.hour<10?a.setSelectionRange(8,10):a.setSelectionRange(9,11)},0):setTimeout(function(){b.hour<10?a.setSelectionRange(5,7):a.setSelectionRange(6,8)},0))},incrementHour:function(){if(this.showMeridian){if(11===this.hour)return this.hour++,this.toggleMeridian();12===this.hour&&(this.hour=0)}return this.hour===this.maxHours-1?void(this.hour=0):void this.hour++},incrementMinute:function(a){var b;b=a?this.minute+a:this.minute+this.minuteStep-this.minute%this.minuteStep,b>59?(this.incrementHour(),this.minute=b-60):this.minute=b},incrementSecond:function(){var a=this.second+this.secondStep-this.second%this.secondStep;a>59?(this.incrementMinute(!0),this.second=a-60):this.second=a},mousewheel:function(b){if(!this.disableMousewheel){b.preventDefault(),b.stopPropagation();var c=b.originalEvent.wheelDelta||-b.originalEvent.detail,d=null;switch(\"mousewheel\"===b.type?d=-1*b.originalEvent.wheelDelta:\"DOMMouseScroll\"===b.type&&(d=40*b.originalEvent.detail),d&&(b.preventDefault(),a(this).scrollTop(d+a(this).scrollTop())),this.highlightedUnit){case\"minute\":c>0?this.incrementMinute():this.decrementMinute(),this.highlightMinute();break;case\"second\":c>0?this.incrementSecond():this.decrementSecond(),this.highlightSecond();break;case\"meridian\":this.toggleMeridian(),this.highlightMeridian();break;default:c>0?this.incrementHour():this.decrementHour(),this.highlightHour()}return!1}},changeToNearestStep:function(a,b){return a%b===0?a:Math.round(a%b/b)?(a+(b-a%b))%60:a-a%b},place:function(){if(!this.isInline){var c=this.$widget.outerWidth(),d=this.$widget.outerHeight(),e=10,f=a(b).width(),g=a(b).height(),h=a(b).scrollTop(),i=parseInt(this.$element.parents().filter(function(){return\"auto\"!==a(this).css(\"z-index\")}).first().css(\"z-index\"),10)+10,j=this.component?this.component.parent().offset():this.$element.offset(),k=this.component?this.component.outerHeight(!0):this.$element.outerHeight(!1),l=this.component?this.component.outerWidth(!0):this.$element.outerWidth(!1),m=j.left,n=j.top;this.$widget.removeClass(\"timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left\"),\"auto\"!==this.orientation.x?(this.$widget.addClass(\"timepicker-orient-\"+this.orientation.x),\"right\"===this.orientation.x&&(m-=c-l)):(this.$widget.addClass(\"timepicker-orient-left\"),j.left<0?m-=j.left-e:j.left+c>f&&(m=f-c-e));var o,p,q=this.orientation.y;\"auto\"===q&&(o=-h+j.top-d,p=h+g-(j.top+k+d),q=Math.max(o,p)===p?\"top\":\"bottom\"),this.$widget.addClass(\"timepicker-orient-\"+q),\"top\"===q?n+=k:n-=d+parseInt(this.$widget.css(\"padding-top\"),10),this.$widget.css({top:n,left:m,zIndex:i})}},remove:function(){a(\"document\").off(\".timepicker\"),this.$widget&&this.$widget.remove(),delete this.$element.data().timepicker},setDefaultTime:function(a){if(this.$element.val())this.updateFromElementVal();else if(\"current\"===a){var b=new Date,c=b.getHours(),d=b.getMinutes(),e=b.getSeconds(),f=\"AM\";0!==e&&(e=Math.ceil(b.getSeconds()/this.secondStep)*this.secondStep,60===e&&(d+=1,e=0)),0!==d&&(d=Math.ceil(b.getMinutes()/this.minuteStep)*this.minuteStep,60===d&&(c+=1,d=0)),this.showMeridian&&(0===c?c=12:c>=12?(c>12&&(c-=12),f=\"PM\"):f=\"AM\"),this.hour=c,this.minute=d,this.second=e,this.meridian=f,this.update()}else a===!1?(this.hour=0,this.minute=0,this.second=0,this.meridian=\"AM\"):this.setTime(a)},setTime:function(a,b){if(!a)return void this.clear();var c,d,e,f,g,h;if(\"object\"==typeof a&&a.getMonth)e=a.getHours(),f=a.getMinutes(),g=a.getSeconds(),this.showMeridian&&(h=\"AM\",e>12&&(h=\"PM\",e%=12),12===e&&(h=\"PM\"));else{if(c=(/a/i.test(a)?1:0)+(/p/i.test(a)?2:0),c>2)return void this.clear();if(d=a.replace(/[^0-9\\:]/g,\"\").split(\":\"),e=d[0]?d[0].toString():d.toString(),this.explicitMode&&e.length>2&&e.length%2!==0)return void this.clear();f=d[1]?d[1].toString():\"\",g=d[2]?d[2].toString():\"\",e.length>4&&(g=e.slice(-2),e=e.slice(0,-2)),e.length>2&&(f=e.slice(-2),e=e.slice(0,-2)),f.length>2&&(g=f.slice(-2),f=f.slice(0,-2)),e=parseInt(e,10),f=parseInt(f,10),g=parseInt(g,10),isNaN(e)&&(e=0),isNaN(f)&&(f=0),isNaN(g)&&(g=0),g>59&&(g=59),f>59&&(f=59),e>=this.maxHours&&(e=this.maxHours-1),this.showMeridian?(e>12&&(c=2,e-=12),c||(c=1),0===e&&(e=12),h=1===c?\"AM\":\"PM\"):12>e&&2===c?e+=12:e>=this.maxHours?e=this.maxHours-1:(0>e||12===e&&1===c)&&(e=0)}this.hour=e,this.snapToStep?(this.minute=this.changeToNearestStep(f,this.minuteStep),this.second=this.changeToNearestStep(g,this.secondStep)):(this.minute=f,this.second=g),this.meridian=h,this.update(b)},showWidget:function(){this.isOpen||this.$element.is(\":disabled\")||(this.$widget.appendTo(this.appendWidgetTo),a(c).on(\"mousedown.timepicker, touchend.timepicker\",{scope:this},this.handleDocumentClick),this.$element.trigger({type:\"show.timepicker\",time:{value:this.getTime(),hours:this.hour,minutes:this.minute,seconds:this.second,meridian:this.meridian}}),this.place(),this.disableFocus&&this.$element.blur(),\"\"===this.hour&&(this.defaultTime?this.setDefaultTime(this.defaultTime):this.setTime(\"0:0:0\")),\"modal\"===this.template&&this.$widget.modal?this.$widget.modal(\"show\").on(\"hidden\",a.proxy(this.hideWidget,this)):this.isOpen===!1&&this.$widget.addClass(\"open\"),this.isOpen=!0)},toggleMeridian:function(){this.meridian=\"AM\"===this.meridian?\"PM\":\"AM\"},update:function(a){this.updateElement(),a||this.updateWidget(),this.$element.trigger({type:\"changeTime.timepicker\",time:{value:this.getTime(),hours:this.hour,minutes:this.minute,seconds:this.second,meridian:this.meridian}})},updateElement:function(){this.$element.val(this.getTime()).change()},updateFromElementVal:function(){this.setTime(this.$element.val())},updateWidget:function(){if(this.$widget!==!1){var a=this.hour,b=1===this.minute.toString().length?\"0\"+this.minute:this.minute,c=1===this.second.toString().length?\"0\"+this.second:this.second;this.showInputs?(this.$widget.find(\"input.bootstrap-timepicker-hour\").val(a),this.$widget.find(\"input.bootstrap-timepicker-minute\").val(b),this.showSeconds&&this.$widget.find(\"input.bootstrap-timepicker-second\").val(c),this.showMeridian&&this.$widget.find(\"input.bootstrap-timepicker-meridian\").val(this.meridian)):(this.$widget.find(\"span.bootstrap-timepicker-hour\").text(a),this.$widget.find(\"span.bootstrap-timepicker-minute\").text(b),this.showSeconds&&this.$widget.find(\"span.bootstrap-timepicker-second\").text(c),this.showMeridian&&this.$widget.find(\"span.bootstrap-timepicker-meridian\").text(this.meridian))}},updateFromWidgetInputs:function(){if(this.$widget!==!1){var a=this.$widget.find(\"input.bootstrap-timepicker-hour\").val()+\":\"+this.$widget.find(\"input.bootstrap-timepicker-minute\").val()+(this.showSeconds?\":\"+this.$widget.find(\"input.bootstrap-timepicker-second\").val():\"\")+(this.showMeridian?this.$widget.find(\"input.bootstrap-timepicker-meridian\").val():\"\");this.setTime(a,!0)}},widgetClick:function(b){b.stopPropagation(),b.preventDefault();var c=a(b.target),d=c.closest(\"a\").data(\"action\");d&&this[d](),this.update(),c.is(\"input\")&&c.get(0).setSelectionRange(0,2)},widgetKeydown:function(b){var c=a(b.target),d=c.attr(\"class\").replace(\"bootstrap-timepicker-\",\"\");switch(b.which){case 9:if(b.shiftKey){if(\"hour\"===d)return this.hideWidget()}else if(this.showMeridian&&\"meridian\"===d||this.showSeconds&&\"second\"===d||!this.showMeridian&&!this.showSeconds&&\"minute\"===d)return this.hideWidget();break;case 27:this.hideWidget();break;case 38:switch(b.preventDefault(),d){case\"hour\":this.incrementHour();break;case\"minute\":this.incrementMinute();break;case\"second\":this.incrementSecond();break;case\"meridian\":this.toggleMeridian()}this.setTime(this.getTime()),c.get(0).setSelectionRange(0,2);break;case 40:switch(b.preventDefault(),d){case\"hour\":this.decrementHour();break;case\"minute\":this.decrementMinute();break;case\"second\":this.decrementSecond();break;case\"meridian\":this.toggleMeridian()}this.setTime(this.getTime()),c.get(0).setSelectionRange(0,2)}},widgetKeyup:function(a){(65===a.which||77===a.which||80===a.which||46===a.which||8===a.which||a.which>=48&&a.which<=57||a.which>=96&&a.which<=105)&&this.updateFromWidgetInputs()}},a.fn.timepicker=function(b){var c=Array.apply(null,arguments);return c.shift(),this.each(function(){var e=a(this),f=e.data(\"timepicker\"),g=\"object\"==typeof b&&b;f||e.data(\"timepicker\",f=new d(this,a.extend({},a.fn.timepicker.defaults,g,a(this).data()))),\"string\"==typeof b&&f[b].apply(f,c)})},a.fn.timepicker.defaults={defaultTime:\"current\",disableFocus:!1,disableMousewheel:!1,isOpen:!1,minuteStep:15,modalBackdrop:!1,orientation:{x:\"auto\",y:\"auto\"},secondStep:15,snapToStep:!1,showSeconds:!1,showInputs:!0,showMeridian:!0,template:\"dropdown\",appendWidgetTo:\"body\",showWidgetOnAddonClick:!0,icons:{up:\"glyphicon glyphicon-chevron-up\",down:\"glyphicon glyphicon-chevron-down\"},maxHours:24,explicitMode:!1},a.fn.timepicker.Constructor=d,a(c).on(\"focus.timepicker.data-api click.timepicker.data-api\",'[data-provide=\"timepicker\"]',function(b){var c=a(this);c.data(\"timepicker\")||(b.preventDefault(),c.timepicker())})}(jQuery,window,document);"
  },
  {
    "path": "src/libs/bootstrap-timepicker/package.json",
    "content": "{\n  \"name\": \"bootstrap-timepicker\",\n  \"description\": \"Timepicker widget for Twitter Bootstrap\",\n  \"version\": \"0.5.2\",\n  \"license\": \"MIT\",\n  \"homepage\": \"http://jdewit.github.com/bootstrap-timepicker\",\n  \"author\": {\n    \"name\": \"Joris de Wit\",\n    \"email\": \"joris.w.dewit@gmail.com\",\n    \"url\": \"http://jorisdewit.ca\"\n  },\n  \"main\": \"js/bootstrap-timepicker.js\",\n  \"files\": [\"js\", \"css\"],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/jdewit/bootstrap-timepicker\"\n  },\n  \"scripts\": {\n    \"test\": \"bower install; grunt test;\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/jdewit/bootstrap-timepicker/issues\"\n  },\n  \"devDependencies\": {\n    \"grunt-cli\": \"~0.1\",\n    \"grunt\": \"~0.4.1\",\n    \"bower\": \"latest\",\n    \"grunt-contrib-less\": \"~0.5.0\",\n    \"grunt-contrib-jshint\": \"~0.4.3\",\n    \"grunt-contrib-uglify\": \"~0.2.0\",\n    \"grunt-contrib-jasmine\": \"~0.4.2\",\n    \"grunt-contrib-watch\": \"~0.4.3\",\n    \"grunt-shell\": \"~0.2.2\",\n    \"grunt-bump\": \"0.0.11\"\n  }\n}\n"
  },
  {
    "path": "src/libs/contextmenu/bootstrap-contextmenu.js",
    "content": "/*!\n * Bootstrap Context Menu\n * Version: 0.2.0\n * Author: @sydcanem\n * https://github.com/sydcanem/bootstrap-contextmenu\n *\n * Inspired by Twitter Bootstrap's dropdown plugin.\n * Twitter Bootstrap (http://twitter.github.com/bootstrap).\n *\n * Licensed under MIT\n * ========================================================= */\n\n;\n(function ($) {\n\n    'use strict';\n\n    /* CONTEXTMENU CLASS DEFINITION\n     * ============================ */\n    var toggle = '[data-toggle=\"context\"]';\n\n    var ContextMenu = function (element, options) {\n        this.$element = $(element);\n\n        this.before = options.before || this.before;\n        this.onItem = options.onItem || this.onItem;\n        this.scopes = options.scopes || null;\n\n        if (options.target) {\n            this.$element.data('target', options.target);\n        }\n\n        this.listen();\n    };\n\n    ContextMenu.prototype = {\n\n        constructor: ContextMenu, show: function (e) {\n\n            var $menu\n                , evt\n                , tp\n                , items\n                , relatedTarget = { relatedTarget: this };\n\n            if (this.isDisabled()) return;\n\n            this.closemenu();\n\n            if (!this.before.call(this, e, $(e.currentTarget))) return;\n\n            $menu = this.getMenu();\n            $menu.trigger(evt = $.Event('show.bs.context', relatedTarget));\n\n            tp = this.getPosition(e, $menu);\n            items = 'li:not(.divider)';\n            $menu.attr('style', '')\n                .css(tp)\n                .addClass('open')\n                .on('click.context.data-api', items, $.proxy(this.onItem, this, $(e.currentTarget)))\n                .trigger('shown.bs.context', relatedTarget);\n\n            // Delegating the `closemenu` only on the currently opened menu.\n            // This prevents other opened menus from closing.\n            $('html')\n                .on('click.context.data-api', $menu.selector, $.proxy(this.closemenu, this));\n\n            return false;\n        }, closemenu: function (e) {\n            var $menu\n                , evt\n                , items\n                , relatedTarget;\n\n            $menu = this.getMenu();\n\n            if (!$menu.hasClass('open')) return;\n\n            relatedTarget = { relatedTarget: this };\n            $menu.trigger(evt = $.Event('hide.bs.context', relatedTarget));\n\n            items = 'li:not(.divider)';\n            $menu.removeClass('open')\n                .off('click.context.data-api', items)\n                .trigger('hidden.bs.context', relatedTarget);\n\n            $('html')\n                .off('click.context.data-api', $menu.selector);\n            // Don't propagate click event so other currently\n            // opened menus won't close.\n            return false;\n        }, before: function (e) {\n            return true;\n        }, onItem: function (e) {\n            return true;\n        }, listen: function () {\n            this.$element.on('contextmenu.context.data-api', this.scopes, $.proxy(this.show, this));\n            $('html').on('click.context.data-api', $.proxy(this.closemenu, this));\n        }, destroy: function () {\n            this.$element.off('.context.data-api').removeData('context');\n            $('html').off('.context.data-api');\n        }, isDisabled: function () {\n            return this.$element.hasClass('.disabled') ||\n                this.$element.attr('disabled');\n        }, getMenu: function () {\n            var selector = this.$element.data('target')\n                , $menu;\n\n            if (!selector) {\n                selector = this.$element.attr('href');\n                selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, ''); //strip for ie7\n            }\n\n            $menu = $(selector);\n\n            return $menu && $menu.length ? $menu : this.$element.find(selector);\n        }, getPosition: function (e, $menu) {\n            var mouseX = e.clientX\n                , mouseY = e.clientY\n                , boundsX = $(window).width()\n                , boundsY = $(window).height()\n                , menuWidth = $menu.find('.dropdown-menu').outerWidth()\n                , menuHeight = $menu.find('.dropdown-menu').outerHeight()\n                , tp = {\"position\": \"absolute\", \"z-index\": 9999}\n                , Y, X, parentOffset;\n\n            if (mouseY + menuHeight > boundsY) {\n                Y = {\"top\": mouseY - menuHeight + $(window).scrollTop()};\n            } else {\n                Y = {\"top\": mouseY + $(window).scrollTop()};\n            }\n\n            if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {\n                X = {\"left\": mouseX - menuWidth + $(window).scrollLeft()};\n            } else {\n                X = {\"left\": mouseX + $(window).scrollLeft()};\n            }\n\n            // If context-menu's parent is positioned using absolute or relative positioning,\n            // the calculated mouse position will be incorrect.\n            // Adjust the position of the menu by its offset parent position.\n            parentOffset = $menu.offsetParent().offset();\n            X.left = X.left - parentOffset.left;\n            Y.top = Y.top - parentOffset.top;\n\n            return $.extend(tp, Y, X);\n        }\n\n    };\n\n    /* CONTEXT MENU PLUGIN DEFINITION\n     * ========================== */\n\n    $.fn.contextmenu = function (option, e) {\n        return this.each(function () {\n            var $this = $(this)\n                , data = $this.data('context')\n                , options = (typeof option == 'object') && option;\n\n            if (!data) $this.data('context', (data = new ContextMenu($this, options)));\n            if (typeof option == 'string') data[option].call(data, e);\n        });\n    };\n\n    $.fn.contextmenu.Constructor = ContextMenu;\n\n    /* APPLY TO STANDARD CONTEXT MENU ELEMENTS\n     * =================================== */\n\n    $(document)\n        .on('contextmenu.context.data-api', toggle, function (e) {\n            $(this).contextmenu('show', e);\n            e.preventDefault();\n        });\n\n}(jQuery));\n"
  },
  {
    "path": "src/libs/enjoyhint/enjoyhint.js",
    "content": "var EnjoyHint = function (_options) {\n    var that = this;\n    // Some options\n    var defaults = {\n        onStart: function () {\n\n        },\n        onEnd: function () {\n\n        }\n    };\n    var options = $.extend(defaults, _options);\n\n\n    var data = [];\n    var current_step = 0;\n\n    $body = $('body');\n\n    /********************* PRIVAT METHODS ***************************************/\n    var init = function () {\n        if ($('.enjoyhint'))\n            $('.enjoyhint').remove();\n        $('body').css({'overflow':'hidden'});\n        $(document).on(\"touchmove\",lockTouch);\n\n        $body.enjoyhint({\n            onNextClick: function () {\n                current_step++;\n                stepAction();\n            },\n            onSkipClick: function () {\n                var step_data = data[current_step];\n                var $element = $(step_data.selector);\n                off(step_data.event);\n                $element.off(makeEventName(step_data.event));\n                destroyEnjoy();\n            }\n        });\n    };\n\n    var lockTouch = function(e) {\n        e.preventDefault();\n    };\n\n    var destroyEnjoy = function () {\n        $body = $('body');\n        $('.enjoyhint').remove();\n        $(\"body\").css({'overflow':'auto'});\n        $(document).off(\"touchmove\", lockTouch);\n\n    };\n\n    that.clear = function(){\n        //(Remove userClass and set default text)\n        $(\".enjoyhint_next_btn\").removeClass(that.nextUserClass);\n        $(\".enjoyhint_next_btn\").text(\"Next\");\n        $(\".enjoyhint_skip_btn\").removeClass(that.skipUserClass);\n        $(\".enjoyhint_skip_btn\").text(\"Skip\");\n    }\n\n    var $body = $('body');\n\n    var stepAction = function () {\n        if (data && data[current_step]) {\n            $(\".enjoyhint\").removeClass(\"enjoyhint-step-\"+current_step);\n            $(\".enjoyhint\").addClass(\"enjoyhint-step-\"+(current_step+1));\n            var step_data = data[current_step];\n            if (step_data.onBeforeStart && typeof step_data.onBeforeStart === 'function') {\n                step_data.onBeforeStart();\n            }\n            var timeout = step_data.timeout || 0;\n            setTimeout(function () {\n                if (!step_data.selector) {\n                    for (var prop in step_data) {\n                        if (step_data.hasOwnProperty(prop) && prop.split(\" \")[1]) {\n                            step_data.selector = prop.split(\" \")[1];\n                            step_data.event = prop.split(\" \")[0];\n                            if (prop.split(\" \")[0] == 'next' || prop.split(\" \")[0] == 'auto' || prop.split(\" \")[0] == 'custom') {\n                                step_data.event_type = prop.split(\" \")[0];\n                            }\n                            step_data.description = step_data[prop];\n                        }\n                    }\n                }\n                setTimeout(function(){\n                    that.clear();\n                }, 250);\n                $(document.body).scrollTo(step_data.selector, step_data.scrollAnimationSpeed || 250, {offset: -100});\n                setTimeout(function () {\n                    var $element = $(step_data.selector);\n                    var event = makeEventName(step_data.event);\n\n                    $body.enjoyhint('show');\n                    $body.enjoyhint('hide_next');\n                    var $event_element = $element;\n                    if (step_data.event_selector) {\n                        $event_element = $(step_data.event_selector);\n                    }\n                    if (!step_data.event_type && step_data.event == \"key\"){\n                        $element.keydown(function( event ) {\n                            if ( event.which == step_data.keyCode ) {\n                                current_step++;\n                                stepAction();\n                            }\n                        });\n                    }\n                    if (step_data.showNext == true){\n                        $body.enjoyhint('show_next');\n                    }\n                    if (step_data.showSkip == false){\n                        $body.enjoyhint('hide_skip');\n                    }else{\n                        $body.enjoyhint('show_skip');\n                    }\n                    if (step_data.showSkip == true){\n\n                    }\n\n\n                    if (step_data.nextButton){\n                        $(\".enjoyhint_next_btn\").addClass(step_data.nextButton.className || \"\");\n                        $(\".enjoyhint_next_btn\").text(step_data.nextButton.text || \"Next\");\n                        that.nextUserClass = step_data.nextButton.className\n                    }\n\n                    if (step_data.skipButton){\n                        $(\".enjoyhint_skip_btn\").addClass(step_data.skipButton.className || \"\");\n                        $(\".enjoyhint_skip_btn\").text(step_data.skipButton.text || \"Skip\");\n                        that.skipUserClass = step_data.skipButton.className\n                    }\n\n                    if (step_data.event_type) {\n                        switch (step_data.event_type) {\n                            case 'auto':\n                                $element[step_data.event]();\n                                switch (step_data.event) {\n                                    case 'click':\n                                        break;\n                                }\n                                current_step++;\n                                stepAction();\n                                return;\n                                break;\n                            case 'custom':\n                                on(step_data.event, function () {\n                                    current_step++;\n                                    off(step_data.event);\n                                    stepAction();\n                                });\n                                break;\n                            case 'next':\n                                $body.enjoyhint('show_next');\n                                break;\n\n                        }\n\n                    } else {\n                        $event_element.on(event, function (e) {\n                            if (step_data.keyCode && e.keyCode != step_data.keyCode) {\n                                return;\n                            }\n                            current_step++;\n                            $(this).off(event);\n\n                            stepAction();\n                        });\n\n                    }\n                    var max_habarites = Math.max($element.outerWidth(), $element.outerHeight());\n                    var radius = step_data.radius  || Math.round(max_habarites / 2) + 5;\n                    var offset = $element.offset();\n                    var w = $element.outerWidth();\n                    var h = $element.outerHeight();\n                    var shape_margin = (step_data.margin !== undefined) ? step_data.margin : 10;\n                    var coords = {\n                        x: offset.left + Math.round(w / 2) ,\n                        y: offset.top + Math.round(h / 2)  - $(document).scrollTop()\n                    };\n                    var shape_data = {\n                        center_x: coords.x,\n                        center_y: coords.y,\n                        text: step_data.description,\n                        top: step_data.top,\n                        bottom: step_data.bottom,\n                        left: step_data.left,\n                        right: step_data.right,\n                        margin: step_data.margin,\n                        scroll: step_data.scroll\n                    };\n\n                    if (step_data.shape && step_data.shape == 'circle') {\n                        shape_data.shape = 'circle';\n                        shape_data.radius = radius;\n                    } else {\n                        shape_data.radius = 0;\n                        shape_data.width = w + shape_margin;\n                        shape_data.height = h + shape_margin;\n                    }\n                    $body.enjoyhint('render_label_with_shape', shape_data);\n                }, step_data.scrollAnimationSpeed + 20 || 270);\n            }, timeout);\n        } else {\n            $body.enjoyhint('hide');\n            options.onEnd();\n            destroyEnjoy();\n        }\n\n    };\n\n    var makeEventName = function (name, is_custom) {\n        return name + (is_custom ? 'custom' : '') + '.enjoy_hint';\n    };\n\n    var on = function (event_name, callback) {\n        $body.on(makeEventName(event_name, true), callback);\n    };\n    var off = function (event_name) {\n        $body.off(makeEventName(event_name, true));\n    };\n\n    /********************* PUBLIC METHODS ***************************************/\n    that.runScript = function () {\n        current_step = 0;\n        options.onStart();\n        stepAction();\n    };\n\n    this.end = function(){\n        destroyEnjoy();\n    }\n\n    that.resumeScript = function () {\n        stepAction();\n    };\n\n    that.getCurrentStep = function () {\n        return current_step;\n    };\n\n\n    that.trigger = function (event_name) {\n        $body.trigger(makeEventName(event_name, true));\n    };\n\n    that.setScript = function (_data) {\n        if (_data) {\n            data = _data;\n        }\n    };\n\n    //support deprecated API methods\n    that.set = function (_data) {\n        that.setScript(_data);\n    };\n\n    that.setSteps = function (_data) {\n        that.setScript(_data);\n    };\n\n    that.run = function () {\n        that.runScript();\n    };\n\n    that.resume = function () {\n        that.resumeScript();\n    };\n\n\n    init();\n};\n;CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {\n    if (w < 2 * r) r = w / 2;\n    if (h < 2 * r) r = h / 2;\n    this.beginPath();\n    this.moveTo(x + r, y);\n    this.arcTo(x + w, y, x + w, y + h, r);\n    this.arcTo(x + w, y + h, x, y + h, r);\n    this.arcTo(x, y + h, x, y, r);\n    this.arcTo(x, y, x + w, y, r);\n    this.closePath();\n    return this;\n};\n\n(function ($) {\n    var methods = {\n        init: function (options) {\n            console.log(options,'-------------');\n            return this.each(function () {\n                var defaults = {\n                    onNextClick: function () {\n                    },\n                    onSkipClick: function () {\n                    },\n                    animation_time: 800\n                };\n\n\n                this.enjoyhint_obj = {};\n                var that = this.enjoyhint_obj;\n                var $that = $(this);\n                var $body = $('body');\n                that.options = jQuery.extend(defaults, options);\n\n                //general classes\n                that.gcl = {\n                    chooser: 'enjoyhint'\n                };\n\n                // classes\n                that.cl = {\n                    enjoy_hint: 'enjoyhint',\n                    hide: 'enjoyhint_hide',\n                    disable_events_element: 'enjoyhint_disable_events',\n                    btn: 'enjoyhint_btn',\n                    skip_btn: 'enjoyhint_skip_btn',\n                    close_btn: 'enjoyhint_close_btn',\n                    next_btn: 'enjoyhint_next_btn',\n                    main_canvas: 'enjoyhint_canvas',\n                    main_svg: 'enjoyhint_svg',\n                    svg_wrapper: 'enjoyhint_svg_wrapper',\n                    svg_transparent: 'enjoyhint_svg_transparent',\n                    kinetic_container: 'kinetic_container'\n                };\n                function makeSVG(tag, attrs) {\n                    var el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n                    for (var k in attrs)\n                        el.setAttribute(k, attrs[k]);\n                    return el;\n                }\n\n                // =======================================================================\n                // ========================---- enjoyhint ----==============================\n                // =======================================================================\n                that.canvas_size = {\n                    w: $(window).width()*1.4,\n                    h: $(window).height()*1.4\n                };\n                var canvas_id = \"enj_canvas\";\n\n                that.enjoyhint = $('<div>', {'class': that.cl.enjoy_hint + ' ' + that.cl.svg_transparent}).appendTo($that);\n                that.enjoyhint_svg_wrapper = $('<div>', {'class': that.cl.svg_wrapper + ' ' + that.cl.svg_transparent}).appendTo(that.enjoyhint);\n                that.$stage_container = $('<div id=\"' + that.cl.kinetic_container + '\">').appendTo(that.enjoyhint);\n                that.$canvas = $('<canvas id=\"' + canvas_id + '\" width=\"' + that.canvas_size.w + '\" height=\"' + that.canvas_size.h + '\" class=\"' + that.cl.main_canvas + '\">').appendTo(that.enjoyhint);\n                that.$svg = $('<svg width=\"' + that.canvas_size.w + '\" height=\"' + that.canvas_size.h + '\" class=\"' + that.cl.main_canvas + ' ' + that.cl.main_svg + '\">').appendTo(that.enjoyhint_svg_wrapper);\n                var defs = $(makeSVG('defs'));\n                var marker = $(makeSVG('marker', {id: \"arrowMarker\", viewBox: \"0 0 36 21\", refX: \"21\", refY: \"10\", markerUnits: \"strokeWidth\", orient: \"auto\", markerWidth: \"16\", markerHeight: \"12\"}));\n                var polilyne = $(makeSVG('path', {style: \"fill:none; stroke:rgb(255,255,255); stroke-width:2\", d: \"M0,0 c30,11 30,9 0,20\"}));\n                defs.append(marker.append(polilyne)).appendTo(that.$svg);\n                that.kinetic_stage = new Kinetic.Stage({\n                    container: that.cl.kinetic_container,\n                    width: that.canvas_size.w,\n                    height: that.canvas_size.h\n                });\n                console.log(that.enjoyhint);\n\n                that.layer = new Kinetic.Layer();\n                that.rect = new Kinetic.Rect({\n//          x: 0,\n//          y: 0,\n                    fill: 'rgba(0,0,0,0.6)',\n                    width: that.canvas_size.w,\n                    height: that.canvas_size.h\n                });\n\n                var $top_dis_events = $('<div>', {'class': that.cl.disable_events_element}).appendTo(that.enjoyhint);\n                var $bottom_dis_events = $top_dis_events.clone().appendTo(that.enjoyhint);\n                var $left_dis_events = $top_dis_events.clone().appendTo(that.enjoyhint);\n                var $right_dis_events = $top_dis_events.clone().appendTo(that.enjoyhint);\n\n                that.$skip_btn = $('<div>', {'class': that.cl.skip_btn}).appendTo(that.enjoyhint).html('Skip').click(function (e) {\n                    that.hide();\n                    that.options.onSkipClick();\n                });\n                that.$next_btn = $('<div>', {'class': that.cl.next_btn}).appendTo(that.enjoyhint).html('Next').click(function (e) {\n                    that.options.onNextClick();\n                });\n\n                that.$close_btn = $('<div>', {'class': that.cl.close_btn}).appendTo(that.enjoyhint).html('').click(function (e){\n                    that.hide();\n                    that.options.onSkipClick();\n                });\n\n                that.$canvas.mousedown(function (e) {\n                    console.log('cl')\n                    $('canvas').css({left: '4000px'});\n\n                    var BottomElement = document.elementFromPoint(e.clientX, e.clientY);\n                    console.log(BottomElement.tagName)\n                    $('canvas').css({left: '0px'});\n\n                    $(BottomElement).click();\n//          that.$canvas.show();\n                    return false;\n                });\n\n\n                var circle_r = 0;\n                var shape_init_shift = 130;\n                that.shape = new Kinetic.Shape({\n                    radius: circle_r,\n                    center_x: -shape_init_shift,\n                    center_y: -shape_init_shift,\n                    width: 0,\n                    height: 0,\n                    sceneFunc: function (context) {\n                        var ctx = this.getContext(\"2d\")._context;\n                        var pos = this.pos;\n                        var def_comp = ctx.globalCompositeOperation;\n                        ctx.globalCompositeOperation = 'destination-out';\n                        ctx.beginPath();\n\n                        var x = this.attrs.center_x - Math.round(this.attrs.width / 2);\n                        var y = this.attrs.center_y - Math.round(this.attrs.height / 2);\n                        ctx.roundRect(x, y, this.attrs.width, this.attrs.height, this.attrs.radius);\n                        ctx.fillStyle = \"red\";\n                        ctx.fill();\n\n                        ctx.globalCompositeOperation = def_comp;\n                    }\n                });\n                that.shape.radius = circle_r;\n                that.layer.add(that.rect);\n                that.layer.add(that.shape);\n                that.kinetic_stage.add(that.layer);\n\n                var enjoyhint_elements = [\n                    that.enjoyhint,\n                    $top_dis_events,\n                    $bottom_dis_events,\n                    $left_dis_events,\n                    $right_dis_events\n                ];\n\n                that.show = function () {\n                    that.enjoyhint.removeClass(that.cl.hide);\n                };\n\n                that.hide = function () {\n                    that.enjoyhint.addClass(that.cl.hide);\n                    var tween = new Kinetic.Tween({\n                        node: that.shape,\n                        duration: 0.002,\n                        center_x: -shape_init_shift,\n                        center_y: -shape_init_shift\n                    });\n                    tween.play();\n                };\n\n                that.hide();\n\n                that.hideNextBtn = function () {\n                    that.$next_btn.addClass(that.cl.hide);\n                    that.nextBtn = \"hide\";\n                };\n                that.showNextBtn = function () {\n                    that.$next_btn.removeClass(that.cl.hide);\n                    that.nextBtn = \"show\";\n                };\n\n                that.hideSkipBtn = function () {\n                    that.$skip_btn.addClass(that.cl.hide);\n                };\n                that.showSkipBtn = function () {\n                    that.$skip_btn.removeClass(that.cl.hide);\n                };\n\n\n\n\n\n                that.renderCircle = function (data) {\n                    var r = data.r || 0;\n                    var x = data.x || 0;\n                    var y = data.y || 0;\n\n                    var tween = new Kinetic.Tween({\n                        node: that.shape,\n                        duration: 0.2,\n                        center_x: x,\n                        center_y: y,\n                        width: r * 2,\n                        height: r * 2,\n                        radius: r\n                    });\n                    tween.play();\n\n                    var left = x - r;\n                    var right = x + r;\n                    var top = y - r;\n                    var bottom = y + r;\n                    var margin = 20;\n                    return {\n                        x: x,\n                        y: y,\n                        left: left,\n                        right: right,\n                        top: top,\n                        bottom: bottom,\n                        conn: {\n                            left: {\n                                x: left - margin,\n                                y: y\n                            },\n                            right: {\n                                x: right + margin,\n                                y: y\n                            },\n                            top: {\n                                x: x,\n                                y: top - margin\n                            },\n                            bottom: {\n                                x: x,\n                                y: bottom + margin\n                            }\n                        }\n                    };\n\n                };\n\n\n                that.renderRect = function (data) {\n                    var r = data.r || 0;\n                    var x = data.x || 0;\n                    var y = data.y || 0;\n                    var w = data.w || 0;\n                    var h = data.h || 0;\n                    var margin = 20;\n                    var tween = new Kinetic.Tween({\n                        node: that.shape,\n                        duration: 0.2,\n                        center_x: x,\n                        center_y: y,\n                        width: w,\n                        height: h,\n                        radius: r\n                    });\n                    tween.play();\n                    var half_w = Math.round(w / 2);\n                    var half_h = Math.round(h / 2);\n                    var left = x - half_w;\n                    var right = x + half_w;\n                    var top = y - half_h;\n                    var bottom = y + half_h;\n                    return {\n                        x: x,\n                        y: y,\n                        left: left,\n                        right: right,\n                        top: top,\n                        bottom: bottom,\n                        conn: {\n                            left: {\n                                x: left - margin,\n                                y: y\n                            },\n                            right: {\n                                x: right + margin,\n                                y: y\n                            },\n                            top: {\n                                x: x,\n                                y: top - margin\n                            },\n                            bottom: {\n                                x: x,\n                                y: bottom + margin\n                            }\n                        }\n                    };\n\n                };\n                that.renderLabel = function (data) {\n                    var x = data.x || 0;\n                    var y = data.y || 0;\n                    var text = data.text || 0;\n\n                    var label = that.getLabelElement({\n                        x: x,\n                        y: y,\n                        text: data.text\n                    });\n                    var label_w = label.width();\n                    var label_h = label.height();\n                    var label_left = label.offset().left;\n                    var label_right = label.offset().left + label_w;\n                    var label_top = label.offset().top - $(document).scrollTop();;\n                    var label_bottom = label.offset().top + label_h;\n\n                    var margin = 10;\n                    var conn_left = {\n                        x: label_left - margin,\n                        y: label_top + Math.round(label_h / 2)\n                    };\n                    var conn_right = {\n                        x: label_right + margin,\n                        y: label_top + Math.round(label_h / 2)\n                    };\n                    var conn_top = {\n                        x: label_left + Math.round(label_w / 2),\n                        y: label_top - margin\n                    };\n                    var conn_bottom = {\n                        x: label_left + Math.round(label_w / 2),\n                        y: label_bottom + margin\n                    };\n                    label.detach();\n                    setTimeout(function () {\n                        $('#enjoyhint_label').remove();\n                        label.appendTo(that.enjoyhint);\n\n                    }, that.options.animation_time / 2);\n                    return {\n                        label: label,\n                        left: label_left,\n                        right: label_right,\n                        top: label_top,\n                        bottom: label_bottom,\n                        conn: {\n                            left: conn_left,\n                            right: conn_right,\n                            top: conn_top,\n                            bottom: conn_bottom\n                        }\n\n                    };\n                };\n                that.renderArrow = function (data) {\n                    var x_from = data.x_from || 0;\n                    var y_from = data.y_from || 0;\n                    var x_to = data.x_to || 0;\n                    var y_to = data.y_to || 0;\n                    var by_top_side = data.by_top_side;\n                    var control_point_x = 0;\n                    var control_point_y = 0;\n                    if (by_top_side) {\n                        if (y_from >= y_to) {\n                            control_point_y = y_to;\n                            control_point_x = x_from;\n                        } else {\n                            control_point_y = y_from;\n                            control_point_x = x_to;\n                        }\n                    } else {\n                        if (y_from >= y_to) {\n                            control_point_y = y_from;\n                            control_point_x = x_to;\n                        } else {\n                            control_point_y = y_to;\n                            control_point_x = x_from;\n                        }\n                    }\n\n                    var text = data.text || '';\n                    that.enjoyhint.addClass(that.cl.svg_transparent);\n                    setTimeout(function () {\n                        $('#enjoyhint_arrpw_line').remove();\n                        var d = 'M' + x_from + ',' + y_from + ' Q' + control_point_x + ',' + control_point_y + ' ' + x_to + ',' + y_to;\n                        that.$svg.append(makeSVG('path', {style: \"fill:none; stroke:rgb(255,255,255); stroke-width:3\", 'marker-end': \"url(#arrowMarker)\", d: d, id: 'enjoyhint_arrpw_line'}));\n                        that.enjoyhint.removeClass(that.cl.svg_transparent);\n\n                    }, that.options.animation_time / 2);\n                };\n\n\n                that.getLabelElement = function (data) {\n                    return $('<div>', {\"class\": 'enjoy_hint_label', id: 'enjoyhint_label'})\n                        .css({\n                            'top': data.y + 'px',\n                            'left': data.x + 'px'\n                        })\n                        .html(data.text).appendTo(that.enjoyhint);\n\n                };\n\n\n                that.disableEventsNearRect = function (rect) {\n                    $top_dis_events.css({\n                        top: '0',\n                        left: '0'\n                    }).height(rect.top);\n                    $bottom_dis_events.css({\n                        top: rect.bottom + 'px',\n                        left: '0'\n                    });\n                    $left_dis_events.css({\n                        top: '0',\n                        left: 0 + 'px'\n                    }).width(rect.left);\n                    $right_dis_events.css({\n                        top: '0',\n                        left: rect.right + 'px'\n                    });\n                };\n\n\n                that.renderLabelWithShape = function (data) {\n                    var shape_type = data.shape || 'rect';\n                    var shape_data = {};\n\n\n                    var half_w = 0;\n                    var half_h = 0;\n\n                    var shape_offsets = {\n                        top: data.top || 0,\n                        bottom: data.bottom || 0,\n                        left: data.left || 0,\n                        right: data.right || 0\n                    };\n\n                    switch (shape_type) {\n                        case 'circle':\n                            half_w = half_h = data.radius;\n                            var sides_pos = {\n                                top: data.center_y - half_h + shape_offsets.top,\n                                bottom: data.center_y + half_h - shape_offsets.bottom,\n                                left: data.center_x - half_w + shape_offsets.left,\n                                right: data.center_x + half_w - shape_offsets.right\n                            };\n                            var width = sides_pos.right - sides_pos.left;\n                            var height = sides_pos.bottom - sides_pos.top;\n                            data.radius = Math.round(Math.min(width, height) / 2);\n                            //new half habarites\n                            half_w = half_h = Math.round(data.radius / 2);\n\n                            var new_half_w = Math.round(width / 2);\n                            var new_half_h = Math.round(height / 2);\n                            //new center_x and center_y\n                            data.center_x = sides_pos.left + new_half_w;\n                            data.center_y = sides_pos.top + new_half_h;\n\n                            shape_data = that.renderCircle({\n                                x: data.center_x,\n                                y: data.center_y,\n                                r: data.radius\n                            });\n\n                            break;\n                        case 'rect':\n                            half_w = Math.round(data.width / 2);\n                            half_h = Math.round(data.height / 2);\n\n                            var sides_pos = {\n                                top: data.center_y - half_h + shape_offsets.top,\n                                bottom: data.center_y + half_h - shape_offsets.bottom,\n                                left: data.center_x - half_w + shape_offsets.left,\n                                right: data.center_x + half_w - shape_offsets.right\n                            };\n                            data.width = sides_pos.right - sides_pos.left;\n                            data.height = sides_pos.bottom - sides_pos.top;\n\n                            half_w = Math.round(data.width / 2);\n                            half_h = Math.round(data.height / 2);\n                            //new center_x and center_y\n                            data.center_x = sides_pos.left + half_w;\n                            data.center_y = sides_pos.top + half_h;\n                            shape_data = that.renderRect({\n                                x: data.center_x,\n                                y: data.center_y,\n                                w: data.width,\n                                h: data.height,\n                                r: data.radius,\n                            });\n                            break;\n                    }\n\n\n                    var body_size = {\n                        w: that.enjoyhint.width(),\n                        h: that.enjoyhint.height()\n                    };\n\n\n                    var label = that.getLabelElement({\n                        x: 0,\n                        y: 0,\n                        text: data.text\n                    });\n                    var label_width = label.outerWidth();\n                    var label_height = label.outerHeight();\n                    label.remove();\n                    var top_offset = data.center_y - half_h;\n                    var bottom_offset = body_size.h - (data.center_y + half_h);\n                    var left_offset = data.center_x - half_w;\n                    var right_offset = body_size.w - (data.center_x + half_w);\n\n                    var label_hor_side = (body_size.w - data.center_x) < data.center_x ? 'left' : 'right';\n                    var label_ver_side = (body_size.h - data.center_y) < data.center_y ? 'top' : 'bottom';\n                    var label_shift = 150;\n                    var label_margin = 40;\n                    var label_shift_with_label_width = label_shift + label_width + label_margin;\n                    var label_shift_with_label_height = label_shift + label_height + label_margin;\n                    var label_hor_offset = half_w + label_shift;\n                    var label_ver_offset = half_h + label_shift;\n\n                    var label_x = (label_hor_side == 'left') ? data.center_x - label_hor_offset - label_width : data.center_x + label_hor_offset;\n                    var label_y = (label_ver_side == 'top') ? data.center_y - label_ver_offset - label_height : data.center_y + label_ver_offset;\n                    if (top_offset < label_shift_with_label_height && bottom_offset < label_shift_with_label_height) {\n                        label_y = data.center_y + label_margin;\n                    }\n                    if (left_offset < label_shift_with_label_width && right_offset < label_shift_with_label_width) {\n                        label_x = data.center_x;\n                    }\n\n                    var label_data = that.renderLabel({\n                        x: label_x,\n                        y: label_y,\n                        text: data.text\n                    });\n\n                    that.$next_btn.css({\n                        left: label_x,\n                        top: label_y + label_height + 20\n                    });\n                    var left_skip = label_x + that.$next_btn.width() + 10;\n                    console.log(that.nextBtn);\n                    if (that.nextBtn == \"hide\"){\n                        left_skip = label_x;\n                    }\n\n                    that.$skip_btn.css({\n                        left: left_skip,\n                        top: label_y + label_height + 20\n                    });\n                    that.$close_btn.css({\n                        right : 10,\n                        top: 10\n                    });\n\n\n                    that.disableEventsNearRect({\n                        top: shape_data.top,\n                        bottom: shape_data.bottom,\n                        left: shape_data.left,\n                        right: shape_data.right\n                    });\n\n\n                    var x_to = 0;\n                    var y_to = 0;\n                    var arrow_side = false;\n                    var conn_label_side = 'left';\n                    var conn_circle_side = 'left';\n\n                    var is_center = (label_data.left <= shape_data.x && label_data.right >= shape_data.x);\n                    var is_left = (label_data.right < shape_data.x);\n                    var is_right = (label_data.left > shape_data.x);\n\n                    var is_abs_left = (label_data.right < shape_data.left);\n                    var is_abs_right = (label_data.left > shape_data.right);\n\n                    var is_top = (label_data.bottom < shape_data.top);\n                    var is_bottom = (label_data.top > shape_data.bottom);\n                    var is_mid = (label_data.bottom >= shape_data.y && label_data.top <= shape_data.y);\n                    var is_mid_top = (label_data.bottom <= shape_data.y && !is_top);\n                    var is_mid_bottom = (label_data.top >= shape_data.y && !is_bottom);\n\n\n                    function setArrowData(l_s, c_s, a_s) {\n                        conn_label_side = l_s;\n                        conn_circle_side = c_s;\n                        arrow_side = a_s;\n                    }\n\n                    function sideStatements(top_s, mid_top_s, mid_s, mid_bottom_s, bottom_s) {\n                        var statement = [];\n                        if (is_top) {\n                            statement = top_s;\n                        } else if (is_mid_top) {\n                            statement = mid_top_s;\n                        } else if (is_mid) {\n                            statement = mid_s;\n                        } else if (is_mid_bottom) {\n                            statement = mid_bottom_s;\n                        } else {//bottom\n                            statement = bottom_s;\n                        }\n                        if (!statement) {\n                            return;\n                        } else {\n                            setArrowData(statement[0], statement[1], statement[2]);\n                        }\n                    }\n\n\n                    if (is_center) {\n                        if (is_top) {\n                            setArrowData('bottom', 'top', 'top');\n                        } else if (is_bottom) {\n                            setArrowData('top', 'bottom', 'bottom');\n                        } else {\n                            return;\n                        }\n                    } else if (is_left) {\n                        sideStatements(\n                            ['right', 'top', 'top'],//top\n                            ['bottom', 'left', 'bottom'],//mid_top\n                            ['right', 'left', 'top'],//mid\n                            ['top', 'left', 'top'],//mid_bot\n                            ['right', 'bottom', 'bottom']//bot\n                        );\n                    } else {//right\n                        sideStatements(\n                            ['left', 'top', 'top'],//top\n                            ['bottom', 'right', 'bottom'],//mid_top\n                            ['left', 'right', 'top'],//mid\n                            ['top', 'right', 'top'],//mid_bot\n                            ['left', 'bottom', 'bottom']//bot\n                        );\n                    }\n\n                    var label_conn_coordinates = label_data.conn[conn_label_side];\n                    var circle_conn_coordinates = shape_data.conn[conn_circle_side];\n                    var by_top_side = (arrow_side == 'top') ? true : false;\n                    that.renderArrow({\n                        x_from: label_conn_coordinates.x,\n                        y_from: label_conn_coordinates.y,\n                        x_to: circle_conn_coordinates.x,\n                        y_to: circle_conn_coordinates.y,\n                        by_top_side: by_top_side\n                    });\n\n                };\n\n                that.clear = function () {\n                    that.ctx.clearRect(0, 0, 3000, 2000);\n                };\n\n                return this;\n            });\n        },\n\n        set: function (val) {\n            this.each(function () {\n                this.enjoyhint_obj.setValue(val);\n            });\n            return this;\n        },\n\n        show: function () {\n            this.each(function () {\n                this.enjoyhint_obj.show();\n            });\n            return this;\n        },\n\n        hide: function () {\n            this.each(function () {\n                this.enjoyhint_obj.hide();\n            });\n            return this;\n        },\n\n        hide_next: function () {\n            this.each(function () {\n                this.enjoyhint_obj.hideNextBtn();\n            });\n            return this;\n        },\n\n        show_next: function () {\n            this.each(function () {\n                this.enjoyhint_obj.showNextBtn();\n            });\n            return this;\n        },\n\n        hide_skip: function () {\n            this.each(function () {\n                this.enjoyhint_obj.hideSkipBtn();\n            });\n            return this;\n        },\n\n        show_skip: function () {\n            this.each(function () {\n                this.enjoyhint_obj.showSkipBtn();\n            });\n            return this;\n        },\n\n        render_circle: function (x, y, r) {\n            this.each(function () {\n                this.enjoyhint_obj.renderCircle(x, y, r);\n            });\n            return this;\n        },\n\n        render_label: function (x, y, r) {\n            this.each(function () {\n                this.enjoyhint_obj.renderLabel(x, y, r);\n            });\n            return this;\n        },\n\n        render_label_with_shape: function (data) {\n            this.each(function () {\n                this.enjoyhint_obj.renderLabelWithShape(data);\n            });\n            return this;\n        },\n\n        clear: function () {\n            this.each(function () {\n                this.enjoyhint_obj.clear();\n            });\n            return this;\n        },\n\n        close: function (val) {\n            this.each(function () {\n                this.enjoyhint_obj.closePopdown();\n            });\n            return this;\n        }\n    };\n\n    $.fn.enjoyhint = function (method) {\n        console.log(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 $.numinput');\n        }\n        return this;\n    };\n})(window.jQuery);\n\n;/*! KineticJS v5.2.0 2015-01-22 http://lavrton.github.io/KineticJS/ by Eric Rowell @ericdrowell, Anton Lavrenov @lavrton - MIT License https://github.com/lavrton/KineticJS/wiki/License*/\nvar Kinetic={};!function(a){var b=Math.PI/180;Kinetic={version:\"5.2.0\",stages:[],idCounter:0,ids:{},names:{},shapes:{},listenClickTap:!1,inDblClickWindow:!1,enableTrace:!1,traceArrMax:100,dblClickWindow:400,pixelRatio:void 0,dragDistance:0,angleDeg:!0,showWarnings:!0,Filters:{},Node:function(a){this._init(a)},Shape:function(a){this.__init(a)},Container:function(a){this.__init(a)},Stage:function(a){this.___init(a)},BaseLayer:function(a){this.___init(a)},Layer:function(a){this.____init(a)},FastLayer:function(a){this.____init(a)},Group:function(a){this.___init(a)},isDragging:function(){var a=Kinetic.DD;return a?a.isDragging:!1},isDragReady:function(){var a=Kinetic.DD;return a?!!a.node:!1},_addId:function(a,b){void 0!==b&&(this.ids[b]=a)},_removeId:function(a){void 0!==a&&delete this.ids[a]},_addName:function(a,b){if(void 0!==b)for(var c=b.split(/\\s/g),d=0;d<c.length;d++){var e=c[d];e&&(void 0===this.names[e]&&(this.names[e]=[]),this.names[e].push(a))}},_removeName:function(a,b){if(void 0!==a){var c=this.names[a];if(void 0!==c){for(var d=0;d<c.length;d++){var e=c[d];e._id===b&&c.splice(d,1)}0===c.length&&delete this.names[a]}}},getAngle:function(a){return this.angleDeg?a*b:a},_parseUA:function(a){var b=a.toLowerCase(),c=/(chrome)[ \\/]([\\w.]+)/.exec(b)||/(webkit)[ \\/]([\\w.]+)/.exec(b)||/(opera)(?:.*version|)[ \\/]([\\w.]+)/.exec(b)||/(msie) ([\\w.]+)/.exec(b)||b.indexOf(\"compatible\")<0&&/(mozilla)(?:.*? rv:([\\w.]+)|)/.exec(b)||[],d=!!a.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i),e=!!a.match(/IEMobile/i);return{browser:c[1]||\"\",version:c[2]||\"0\",mobile:d,ieMobile:e}},UA:void 0},Kinetic.UA=Kinetic._parseUA(a.navigator&&a.navigator.userAgent||\"\")}(this),function(a,b){if(\"object\"==typeof exports){var c=b();if(global.window===global)Kinetic.document=global.document,Kinetic.window=global;else{var d=require(\"canvas\"),e=require(\"jsdom\").jsdom;Kinetic.document=e(\"<!DOCTYPE html><html><head></head><body></body></html>\"),Kinetic.window=Kinetic.document.createWindow(),Kinetic.window.Image=d.Image,Kinetic._nodeCanvas=d}return Kinetic.root=a,void(module.exports=c)}\"function\"==typeof define&&define.amd&&define(b),Kinetic.document=document,Kinetic.window=window,Kinetic.root=a}(this,function(){return Kinetic}),function(){Kinetic.Collection=function(){var a=[].slice.call(arguments),b=a.length,c=0;for(this.length=b;b>c;c++)this[c]=a[c];return this},Kinetic.Collection.prototype=[],Kinetic.Collection.prototype.each=function(a){for(var b=0;b<this.length;b++)a(this[b],b)},Kinetic.Collection.prototype.toArray=function(){var a,b=[],c=this.length;for(a=0;c>a;a++)b.push(this[a]);return b},Kinetic.Collection.toCollection=function(a){var b,c=new Kinetic.Collection,d=a.length;for(b=0;d>b;b++)c.push(a[b]);return c},Kinetic.Collection._mapMethod=function(a){Kinetic.Collection.prototype[a]=function(){var b,c=this.length,d=[].slice.call(arguments);for(b=0;c>b;b++)this[b][a].apply(this[b],d);return this}},Kinetic.Collection.mapMethods=function(a){var b=a.prototype;for(var c in b)Kinetic.Collection._mapMethod(c)},Kinetic.Transform=function(a){this.m=a&&a.slice()||[1,0,0,1,0,0]},Kinetic.Transform.prototype={copy:function(){return new Kinetic.Transform(this.m)},point:function(a){var b=this.m;return{x:b[0]*a.x+b[2]*a.y+b[4],y:b[1]*a.x+b[3]*a.y+b[5]}},translate:function(a,b){return this.m[4]+=this.m[0]*a+this.m[2]*b,this.m[5]+=this.m[1]*a+this.m[3]*b,this},scale:function(a,b){return this.m[0]*=a,this.m[1]*=a,this.m[2]*=b,this.m[3]*=b,this},rotate:function(a){var b=Math.cos(a),c=Math.sin(a),d=this.m[0]*b+this.m[2]*c,e=this.m[1]*b+this.m[3]*c,f=this.m[0]*-c+this.m[2]*b,g=this.m[1]*-c+this.m[3]*b;return this.m[0]=d,this.m[1]=e,this.m[2]=f,this.m[3]=g,this},getTranslation:function(){return{x:this.m[4],y:this.m[5]}},skew:function(a,b){var c=this.m[0]+this.m[2]*b,d=this.m[1]+this.m[3]*b,e=this.m[2]+this.m[0]*a,f=this.m[3]+this.m[1]*a;return this.m[0]=c,this.m[1]=d,this.m[2]=e,this.m[3]=f,this},multiply:function(a){var b=this.m[0]*a.m[0]+this.m[2]*a.m[1],c=this.m[1]*a.m[0]+this.m[3]*a.m[1],d=this.m[0]*a.m[2]+this.m[2]*a.m[3],e=this.m[1]*a.m[2]+this.m[3]*a.m[3],f=this.m[0]*a.m[4]+this.m[2]*a.m[5]+this.m[4],g=this.m[1]*a.m[4]+this.m[3]*a.m[5]+this.m[5];return this.m[0]=b,this.m[1]=c,this.m[2]=d,this.m[3]=e,this.m[4]=f,this.m[5]=g,this},invert:function(){var a=1/(this.m[0]*this.m[3]-this.m[1]*this.m[2]),b=this.m[3]*a,c=-this.m[1]*a,d=-this.m[2]*a,e=this.m[0]*a,f=a*(this.m[2]*this.m[5]-this.m[3]*this.m[4]),g=a*(this.m[1]*this.m[4]-this.m[0]*this.m[5]);return this.m[0]=b,this.m[1]=c,this.m[2]=d,this.m[3]=e,this.m[4]=f,this.m[5]=g,this},getMatrix:function(){return this.m},setAbsolutePosition:function(a,b){var c=this.m[0],d=this.m[1],e=this.m[2],f=this.m[3],g=this.m[4],h=this.m[5],i=(c*(b-h)-d*(a-g))/(c*f-d*e),j=(a-g-e*i)/c;return this.translate(j,i)}};var a=\"2d\",b=\"[object Array]\",c=\"[object Number]\",d=\"[object String]\",e=Math.PI/180,f=180/Math.PI,g=\"#\",h=\"\",i=\"0\",j=\"Kinetic warning: \",k=\"Kinetic error: \",l=\"rgb(\",m={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},n=/rgb\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)/;Kinetic.Util={_isElement:function(a){return!(!a||1!=a.nodeType)},_isFunction:function(a){return!!(a&&a.constructor&&a.call&&a.apply)},_isObject:function(a){return!!a&&a.constructor==Object},_isArray:function(a){return Object.prototype.toString.call(a)==b},_isNumber:function(a){return Object.prototype.toString.call(a)==c},_isString:function(a){return Object.prototype.toString.call(a)==d},_throttle:function(a,b,c){var d,e,f,g=null,h=0,i=c||{},j=function(){h=i.leading===!1?0:(new Date).getTime(),g=null,f=a.apply(d,e),d=e=null};return function(){var c=(new Date).getTime();h||i.leading!==!1||(h=c);var k=b-(c-h);return d=this,e=arguments,0>=k?(clearTimeout(g),g=null,h=c,f=a.apply(d,e),d=e=null):g||i.trailing===!1||(g=setTimeout(j,k)),f}},_hasMethods:function(a){var b,c=[];for(b in a)this._isFunction(a[b])&&c.push(b);return c.length>0},createCanvasElement:function(){var a=Kinetic.document.createElement(\"canvas\");try{a.style=a.style||{}}catch(b){}return a},isBrowser:function(){return\"object\"!=typeof exports},_isInDocument:function(a){for(;a=a.parentNode;)if(a==Kinetic.document)return!0;return!1},_simplifyArray:function(a){var b,c,d=[],e=a.length,f=Kinetic.Util;for(b=0;e>b;b++)c=a[b],f._isNumber(c)?c=Math.round(1e3*c)/1e3:f._isString(c)||(c=c.toString()),d.push(c);return d},_getImage:function(b,c){var d,e;if(b)if(this._isElement(b))c(b);else if(this._isString(b))d=new Kinetic.window.Image,d.onload=function(){c(d)},d.src=b;else if(b.data){e=Kinetic.Util.createCanvasElement(),e.width=b.width,e.height=b.height;var f=e.getContext(a);f.putImageData(b,0,0),this._getImage(e.toDataURL(),c)}else c(null);else c(null)},_getRGBAString:function(a){var b=a.red||0,c=a.green||0,d=a.blue||0,e=a.alpha||1;return[\"rgba(\",b,\",\",c,\",\",d,\",\",e,\")\"].join(h)},_rgbToHex:function(a,b,c){return((1<<24)+(a<<16)+(b<<8)+c).toString(16).slice(1)},_hexToRgb:function(a){a=a.replace(g,h);var b=parseInt(a,16);return{r:b>>16&255,g:b>>8&255,b:255&b}},getRandomColor:function(){for(var a=(16777215*Math.random()<<0).toString(16);a.length<6;)a=i+a;return g+a},get:function(a,b){return void 0===a?b:a},getRGB:function(a){var b;return a in m?(b=m[a],{r:b[0],g:b[1],b:b[2]}):a[0]===g?this._hexToRgb(a.substring(1)):a.substr(0,4)===l?(b=n.exec(a.replace(/ /g,\"\")),{r:parseInt(b[1],10),g:parseInt(b[2],10),b:parseInt(b[3],10)}):{r:0,g:0,b:0}},_merge:function(a,b){var c=this._clone(b);for(var d in a)c[d]=this._isObject(a[d])?this._merge(a[d],c[d]):a[d];return c},cloneObject:function(a){var b={};for(var c in a)b[c]=this._isObject(a[c])?this.cloneObject(a[c]):this._isArray(a[c])?this.cloneArray(a[c]):a[c];return b},cloneArray:function(a){return a.slice(0)},_degToRad:function(a){return a*e},_radToDeg:function(a){return a*f},_capitalize:function(a){return a.charAt(0).toUpperCase()+a.slice(1)},error:function(a){throw new Error(k+a)},warn:function(a){Kinetic.root.console&&console.warn&&Kinetic.showWarnings&&console.warn(j+a)},extend:function(a,b){function c(){this.constructor=a}c.prototype=b.prototype;var d=a.prototype;a.prototype=new c;for(var e in d)d.hasOwnProperty(e)&&(a.prototype[e]=d[e]);a.__super__=b.prototype},addMethods:function(a,b){var c;for(c in b)a.prototype[c]=b[c]},_getControlPoints:function(a,b,c,d,e,f,g){var h=Math.sqrt(Math.pow(c-a,2)+Math.pow(d-b,2)),i=Math.sqrt(Math.pow(e-c,2)+Math.pow(f-d,2)),j=g*h/(h+i),k=g*i/(h+i),l=c-j*(e-a),m=d-j*(f-b),n=c+k*(e-a),o=d+k*(f-b);return[l,m,n,o]},_expandPoints:function(a,b){var c,d,e=a.length,f=[];for(c=2;e-2>c;c+=2)d=Kinetic.Util._getControlPoints(a[c-2],a[c-1],a[c],a[c+1],a[c+2],a[c+3],b),f.push(d[0]),f.push(d[1]),f.push(a[c]),f.push(a[c+1]),f.push(d[2]),f.push(d[3]);return f},_removeLastLetter:function(a){return a.substring(0,a.length-1)}}}(),function(){var a=Kinetic.Util.createCanvasElement(),b=a.getContext(\"2d\"),c=Kinetic.UA.mobile?function(){var a=window.devicePixelRatio||1,c=b.webkitBackingStorePixelRatio||b.mozBackingStorePixelRatio||b.msBackingStorePixelRatio||b.oBackingStorePixelRatio||b.backingStorePixelRatio||1;return a/c}():1;Kinetic.Canvas=function(a){this.init(a)},Kinetic.Canvas.prototype={init:function(a){var b=a||{},d=b.pixelRatio||Kinetic.pixelRatio||c;this.pixelRatio=d,this._canvas=Kinetic.Util.createCanvasElement(),this._canvas.style.padding=0,this._canvas.style.margin=0,this._canvas.style.border=0,this._canvas.style.background=\"transparent\",this._canvas.style.position=\"absolute\",this._canvas.style.top=0,this._canvas.style.left=0},getContext:function(){return this.context},getPixelRatio:function(){return this.pixelRatio},setPixelRatio:function(a){this.pixelRatio=a,this.setSize(this.getWidth(),this.getHeight())},setWidth:function(a){this.width=this._canvas.width=a*this.pixelRatio,this._canvas.style.width=a+\"px\"},setHeight:function(a){this.height=this._canvas.height=a*this.pixelRatio,this._canvas.style.height=a+\"px\"},getWidth:function(){return this.width},getHeight:function(){return this.height},setSize:function(a,b){this.setWidth(a),this.setHeight(b)},toDataURL:function(a,b){try{return this._canvas.toDataURL(a,b)}catch(c){try{return this._canvas.toDataURL()}catch(d){return Kinetic.Util.warn(\"Unable to get data URL. \"+d.message),\"\"}}}},Kinetic.SceneCanvas=function(a){var b=a||{},c=b.width||0,d=b.height||0;Kinetic.Canvas.call(this,b),this.context=new Kinetic.SceneContext(this),this.setSize(c,d)},Kinetic.SceneCanvas.prototype={setWidth:function(a){var b=this.pixelRatio,c=this.getContext()._context;Kinetic.Canvas.prototype.setWidth.call(this,a),c.scale(b,b)},setHeight:function(a){var b=this.pixelRatio,c=this.getContext()._context;Kinetic.Canvas.prototype.setHeight.call(this,a),c.scale(b,b)}},Kinetic.Util.extend(Kinetic.SceneCanvas,Kinetic.Canvas),Kinetic.HitCanvas=function(a){var b=a||{},c=b.width||0,d=b.height||0;Kinetic.Canvas.call(this,b),this.context=new Kinetic.HitContext(this),this.setSize(c,d),this.hitCanvas=!0},Kinetic.Util.extend(Kinetic.HitCanvas,Kinetic.Canvas)}(),function(){var a=\",\",b=\"(\",c=\")\",d=\"([\",e=\"])\",f=\";\",g=\"()\",h=\"=\",i=[\"arc\",\"arcTo\",\"beginPath\",\"bezierCurveTo\",\"clearRect\",\"clip\",\"closePath\",\"createLinearGradient\",\"createPattern\",\"createRadialGradient\",\"drawImage\",\"fill\",\"fillText\",\"getImageData\",\"createImageData\",\"lineTo\",\"moveTo\",\"putImageData\",\"quadraticCurveTo\",\"rect\",\"restore\",\"rotate\",\"save\",\"scale\",\"setLineDash\",\"setTransform\",\"stroke\",\"strokeText\",\"transform\",\"translate\"];Kinetic.Context=function(a){this.init(a)},Kinetic.Context.prototype={init:function(a){this.canvas=a,this._context=a._canvas.getContext(\"2d\"),Kinetic.enableTrace&&(this.traceArr=[],this._enableTrace())},fillShape:function(a){a.getFillEnabled()&&this._fill(a)},strokeShape:function(a){a.getStrokeEnabled()&&this._stroke(a)},fillStrokeShape:function(a){var b=a.getFillEnabled();b&&this._fill(a),a.getStrokeEnabled()&&this._stroke(a)},getTrace:function(i){var j,k,l,m,n=this.traceArr,o=n.length,p=\"\";for(j=0;o>j;j++)k=n[j],l=k.method,l?(m=k.args,p+=l,p+=i?g:Kinetic.Util._isArray(m[0])?d+m.join(a)+e:b+m.join(a)+c):(p+=k.property,i||(p+=h+k.val)),p+=f;return p},clearTrace:function(){this.traceArr=[]},_trace:function(a){var b,c=this.traceArr;c.push(a),b=c.length,b>=Kinetic.traceArrMax&&c.shift()},reset:function(){var a=this.getCanvas().getPixelRatio();this.setTransform(1*a,0,0,1*a,0,0)},getCanvas:function(){return this.canvas},clear:function(a){var b=this.getCanvas();a?this.clearRect(a.x||0,a.y||0,a.width||0,a.height||0):this.clearRect(0,0,b.getWidth(),b.getHeight())},_applyLineCap:function(a){var b=a.getLineCap();b&&this.setAttr(\"lineCap\",b)},_applyOpacity:function(a){var b=a.getAbsoluteOpacity();1!==b&&this.setAttr(\"globalAlpha\",b)},_applyLineJoin:function(a){var b=a.getLineJoin();b&&this.setAttr(\"lineJoin\",b)},setAttr:function(a,b){this._context[a]=b},arc:function(){var a=arguments;this._context.arc(a[0],a[1],a[2],a[3],a[4],a[5])},beginPath:function(){this._context.beginPath()},bezierCurveTo:function(){var a=arguments;this._context.bezierCurveTo(a[0],a[1],a[2],a[3],a[4],a[5])},clearRect:function(){var a=arguments;this._context.clearRect(a[0],a[1],a[2],a[3])},clip:function(){this._context.clip()},closePath:function(){this._context.closePath()},createImageData:function(){var a=arguments;return 2===a.length?this._context.createImageData(a[0],a[1]):1===a.length?this._context.createImageData(a[0]):void 0},createLinearGradient:function(){var a=arguments;return this._context.createLinearGradient(a[0],a[1],a[2],a[3])},createPattern:function(){var a=arguments;return this._context.createPattern(a[0],a[1])},createRadialGradient:function(){var a=arguments;return this._context.createRadialGradient(a[0],a[1],a[2],a[3],a[4],a[5])},drawImage:function(){var a=arguments,b=this._context;3===a.length?b.drawImage(a[0],a[1],a[2]):5===a.length?b.drawImage(a[0],a[1],a[2],a[3],a[4]):9===a.length&&b.drawImage(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8])},fill:function(){this._context.fill()},fillText:function(){var a=arguments;this._context.fillText(a[0],a[1],a[2])},getImageData:function(){var a=arguments;return this._context.getImageData(a[0],a[1],a[2],a[3])},lineTo:function(){var a=arguments;this._context.lineTo(a[0],a[1])},moveTo:function(){var a=arguments;this._context.moveTo(a[0],a[1])},rect:function(){var a=arguments;this._context.rect(a[0],a[1],a[2],a[3])},putImageData:function(){var a=arguments;this._context.putImageData(a[0],a[1],a[2])},quadraticCurveTo:function(){var a=arguments;this._context.quadraticCurveTo(a[0],a[1],a[2],a[3])},restore:function(){this._context.restore()},rotate:function(){var a=arguments;this._context.rotate(a[0])},save:function(){this._context.save()},scale:function(){var a=arguments;this._context.scale(a[0],a[1])},setLineDash:function(){var a=arguments,b=this._context;this._context.setLineDash?b.setLineDash(a[0]):\"mozDash\"in b?b.mozDash=a[0]:\"webkitLineDash\"in b&&(b.webkitLineDash=a[0])},setTransform:function(){var a=arguments;this._context.setTransform(a[0],a[1],a[2],a[3],a[4],a[5])},stroke:function(){this._context.stroke()},strokeText:function(){var a=arguments;this._context.strokeText(a[0],a[1],a[2])},transform:function(){var a=arguments;this._context.transform(a[0],a[1],a[2],a[3],a[4],a[5])},translate:function(){var a=arguments;this._context.translate(a[0],a[1])},_enableTrace:function(){var a,b,c=this,d=i.length,e=Kinetic.Util._simplifyArray,f=this.setAttr,g=function(a){var d,f=c[a];c[a]=function(){return b=e(Array.prototype.slice.call(arguments,0)),d=f.apply(c,arguments),c._trace({method:a,args:b}),d}};for(a=0;d>a;a++)g(i[a]);c.setAttr=function(){f.apply(c,arguments),c._trace({property:arguments[0],val:arguments[1]})}}},Kinetic.SceneContext=function(a){Kinetic.Context.call(this,a)},Kinetic.SceneContext.prototype={_fillColor:function(a){var b=a.fill()||Kinetic.Util._getRGBAString({red:a.fillRed(),green:a.fillGreen(),blue:a.fillBlue(),alpha:a.fillAlpha()});this.setAttr(\"fillStyle\",b),a._fillFunc(this)},_fillPattern:function(a){var b=a.getFillPatternImage(),c=a.getFillPatternX(),d=a.getFillPatternY(),e=a.getFillPatternScale(),f=Kinetic.getAngle(a.getFillPatternRotation()),g=a.getFillPatternOffset(),h=a.getFillPatternRepeat();(c||d)&&this.translate(c||0,d||0),f&&this.rotate(f),e&&this.scale(e.x,e.y),g&&this.translate(-1*g.x,-1*g.y),this.setAttr(\"fillStyle\",this.createPattern(b,h||\"repeat\")),this.fill()},_fillLinearGradient:function(a){var b=a.getFillLinearGradientStartPoint(),c=a.getFillLinearGradientEndPoint(),d=a.getFillLinearGradientColorStops(),e=this.createLinearGradient(b.x,b.y,c.x,c.y);if(d){for(var f=0;f<d.length;f+=2)e.addColorStop(d[f],d[f+1]);this.setAttr(\"fillStyle\",e),this.fill()}},_fillRadialGradient:function(a){for(var b=a.getFillRadialGradientStartPoint(),c=a.getFillRadialGradientEndPoint(),d=a.getFillRadialGradientStartRadius(),e=a.getFillRadialGradientEndRadius(),f=a.getFillRadialGradientColorStops(),g=this.createRadialGradient(b.x,b.y,d,c.x,c.y,e),h=0;h<f.length;h+=2)g.addColorStop(f[h],f[h+1]);this.setAttr(\"fillStyle\",g),this.fill()},_fill:function(a){var b=a.fill()||a.fillRed()||a.fillGreen()||a.fillBlue(),c=a.getFillPatternImage(),d=a.getFillLinearGradientColorStops(),e=a.getFillRadialGradientColorStops(),f=a.getFillPriority();b&&\"color\"===f?this._fillColor(a):c&&\"pattern\"===f?this._fillPattern(a):d&&\"linear-gradient\"===f?this._fillLinearGradient(a):e&&\"radial-gradient\"===f?this._fillRadialGradient(a):b?this._fillColor(a):c?this._fillPattern(a):d?this._fillLinearGradient(a):e&&this._fillRadialGradient(a)},_stroke:function(a){var b=a.dash(),c=a.getStrokeScaleEnabled();a.hasStroke()&&(c||(this.save(),this.setTransform(1,0,0,1,0,0)),this._applyLineCap(a),b&&a.dashEnabled()&&this.setLineDash(b),this.setAttr(\"lineWidth\",a.strokeWidth()),this.setAttr(\"strokeStyle\",a.stroke()||Kinetic.Util._getRGBAString({red:a.strokeRed(),green:a.strokeGreen(),blue:a.strokeBlue(),alpha:a.strokeAlpha()})),a._strokeFunc(this),c||this.restore())},_applyShadow:function(a){var b=Kinetic.Util,c=a.getAbsoluteOpacity(),d=b.get(a.getShadowColor(),\"black\"),e=b.get(a.getShadowBlur(),5),f=b.get(a.getShadowOpacity(),1),g=b.get(a.getShadowOffset(),{x:0,y:0});f&&this.setAttr(\"globalAlpha\",f*c),this.setAttr(\"shadowColor\",d),this.setAttr(\"shadowBlur\",e),this.setAttr(\"shadowOffsetX\",g.x),this.setAttr(\"shadowOffsetY\",g.y)}},Kinetic.Util.extend(Kinetic.SceneContext,Kinetic.Context),Kinetic.HitContext=function(a){Kinetic.Context.call(this,a)},Kinetic.HitContext.prototype={_fill:function(a){this.save(),this.setAttr(\"fillStyle\",a.colorKey),a._fillFuncHit(this),this.restore()},_stroke:function(a){a.hasStroke()&&(this._applyLineCap(a),this.setAttr(\"lineWidth\",a.strokeWidth()),this.setAttr(\"strokeStyle\",a.colorKey),a._strokeFuncHit(this))}},Kinetic.Util.extend(Kinetic.HitContext,Kinetic.Context)}(),function(){var a=\"get\",b=\"set\";Kinetic.Factory={addGetterSetter:function(a,b,c,d,e){this.addGetter(a,b,c),this.addSetter(a,b,d,e),this.addOverloadedGetterSetter(a,b)},addGetter:function(b,c,d){var e=a+Kinetic.Util._capitalize(c);b.prototype[e]=function(){var a=this.attrs[c];return void 0===a?d:a}},addSetter:function(a,c,d,e){var f=b+Kinetic.Util._capitalize(c);a.prototype[f]=function(a){return d&&(a=d.call(this,a)),this._setAttr(c,a),e&&e.call(this),this}},addComponentsGetterSetter:function(c,d,e,f,g){var h,i,j=e.length,k=Kinetic.Util._capitalize,l=a+k(d),m=b+k(d);c.prototype[l]=function(){var a={};for(h=0;j>h;h++)i=e[h],a[i]=this.getAttr(d+k(i));return a},c.prototype[m]=function(a){var b,c=this.attrs[d];f&&(a=f.call(this,a));for(b in a)this._setAttr(d+k(b),a[b]);return this._fireChangeEvent(d,c,a),g&&g.call(this),this},this.addOverloadedGetterSetter(c,d)},addOverloadedGetterSetter:function(c,d){var e=Kinetic.Util._capitalize(d),f=b+e,g=a+e;c.prototype[d]=function(){return arguments.length?(this[f](arguments[0]),this):this[g]()}},backCompat:function(a,b){var c;for(c in b)a.prototype[c]=a.prototype[b[c]]},afterSetFilter:function(){this._filterUpToDate=!1}},Kinetic.Validators={RGBComponent:function(a){return a>255?255:0>a?0:Math.round(a)},alphaComponent:function(a){return a>1?1:1e-4>a?1e-4:a}}}(),function(){var a=\"absoluteOpacity\",b=\"absoluteTransform\",c=\"Change\",d=\"children\",e=\".\",f=\"\",g=\"get\",h=\"id\",i=\"kinetic\",j=\"listening\",k=\"mouseenter\",l=\"mouseleave\",m=\"name\",n=\"set\",o=\"Shape\",p=\" \",q=\"stage\",r=\"transform\",s=\"Stage\",t=\"visible\",u=[\"id\"],v=[\"xChange.kinetic\",\"yChange.kinetic\",\"scaleXChange.kinetic\",\"scaleYChange.kinetic\",\"skewXChange.kinetic\",\"skewYChange.kinetic\",\"rotationChange.kinetic\",\"offsetXChange.kinetic\",\"offsetYChange.kinetic\",\"transformsEnabledChange.kinetic\"].join(p);Kinetic.Util.addMethods(Kinetic.Node,{_init:function(c){var d=this;this._id=Kinetic.idCounter++,this.eventListeners={},this.attrs={},this._cache={},this._filterUpToDate=!1,this.setAttrs(c),this.on(v,function(){this._clearCache(r),d._clearSelfAndDescendantCache(b)}),this.on(\"visibleChange.kinetic\",function(){d._clearSelfAndDescendantCache(t)}),this.on(\"listeningChange.kinetic\",function(){d._clearSelfAndDescendantCache(j)}),this.on(\"opacityChange.kinetic\",function(){d._clearSelfAndDescendantCache(a)})},_clearCache:function(a){a?delete this._cache[a]:this._cache={}},_getCache:function(a,b){var c=this._cache[a];return void 0===c&&(this._cache[a]=b.call(this)),this._cache[a]},_clearSelfAndDescendantCache:function(a){this._clearCache(a),this.children&&this.getChildren().each(function(b){b._clearSelfAndDescendantCache(a)})},clearCache:function(){return delete this._cache.canvas,this._filterUpToDate=!1,this},cache:function(a){var b=a||{},c=b.x||0,d=b.y||0,e=b.width||this.width(),f=b.height||this.height(),g=b.drawBorder||!1;if(0===e||0===f)return void Kinetic.Util.warn(\"Width or height of caching configuration equals 0. Cache is ignored.\");var h=new Kinetic.SceneCanvas({pixelRatio:1,width:e,height:f}),i=new Kinetic.SceneCanvas({pixelRatio:1,width:e,height:f}),j=new Kinetic.HitCanvas({width:e,height:f}),k=h.getContext(),l=j.getContext();return j.isCache=!0,this.clearCache(),k.save(),l.save(),g&&(k.save(),k.beginPath(),k.rect(0,0,e,f),k.closePath(),k.setAttr(\"strokeStyle\",\"red\"),k.setAttr(\"lineWidth\",5),k.stroke(),k.restore()),k.translate(-1*c,-1*d),l.translate(-1*c,-1*d),\"Shape\"===this.nodeType&&(k.translate(-1*this.x(),-1*this.y()),l.translate(-1*this.x(),-1*this.y())),this.drawScene(h,this),this.drawHit(j,this),k.restore(),l.restore(),this._cache.canvas={scene:h,filter:i,hit:j},this},_drawCachedSceneCanvas:function(a){a.save(),this.getLayer()._applyTransform(this,a),a._applyOpacity(this),a.drawImage(this._getCachedSceneCanvas()._canvas,0,0),a.restore()},_getCachedSceneCanvas:function(){var a,b,c,d,e=this.filters(),f=this._cache.canvas,g=f.scene,h=f.filter,i=h.getContext();if(e){if(!this._filterUpToDate){try{for(a=e.length,i.clear(),i.drawImage(g._canvas,0,0),b=i.getImageData(0,0,h.getWidth(),h.getHeight()),c=0;a>c;c++)d=e[c],d.call(this,b),i.putImageData(b,0,0)}catch(j){Kinetic.Util.warn(\"Unable to apply filter. \"+j.message)}this._filterUpToDate=!0}return h}return g},_drawCachedHitCanvas:function(a){var b=this._cache.canvas,c=b.hit;a.save(),this.getLayer()._applyTransform(this,a),a.drawImage(c._canvas,0,0),a.restore()},on:function(a,b){var c,d,g,h,i,j=a.split(p),k=j.length;for(c=0;k>c;c++)d=j[c],g=d.split(e),h=g[0],i=g[1]||f,this.eventListeners[h]||(this.eventListeners[h]=[]),this.eventListeners[h].push({name:i,handler:b});return this},off:function(a){var b,c,d,f,g,h,i=(a||\"\").split(p),j=i.length;if(!a)for(c in this.eventListeners)this._off(c);for(b=0;j>b;b++)if(d=i[b],f=d.split(e),g=f[0],h=f[1],g)this.eventListeners[g]&&this._off(g,h);else for(c in this.eventListeners)this._off(c,h);return this},dispatchEvent:function(a){var b={target:this,type:a.type,evt:a};this.fire(a.type,b)},addEventListener:function(a,b){this.on(a,function(a){b.call(this,a.evt)})},removeEventListener:function(a){this.off(a)},remove:function(){var c=this.getParent();return c&&c.children&&(c.children.splice(this.index,1),c._setChildrenIndices(),delete this.parent),this._clearSelfAndDescendantCache(q),this._clearSelfAndDescendantCache(b),this._clearSelfAndDescendantCache(t),this._clearSelfAndDescendantCache(j),this._clearSelfAndDescendantCache(a),this},destroy:function(){Kinetic._removeId(this.getId()),Kinetic._removeName(this.getName(),this._id),this.remove()},getAttr:function(a){var b=g+Kinetic.Util._capitalize(a);return Kinetic.Util._isFunction(this[b])?this[b]():this.attrs[a]},getAncestors:function(){for(var a=this.getParent(),b=new Kinetic.Collection;a;)b.push(a),a=a.getParent();return b},getAttrs:function(){return this.attrs||{}},setAttrs:function(a){var b,c;if(a)for(b in a)b===d||a[b]instanceof Kinetic.Node||(c=n+Kinetic.Util._capitalize(b),Kinetic.Util._isFunction(this[c])?this[c](a[b]):this._setAttr(b,a[b]));return this},isListening:function(){return this._getCache(j,this._isListening)},_isListening:function(){var a=this.getListening(),b=this.getParent();return\"inherit\"===a?b?b.isListening():!0:a},isVisible:function(){return this._getCache(t,this._isVisible)},_isVisible:function(){var a=this.getVisible(),b=this.getParent();return\"inherit\"===a?b?b.isVisible():!0:a},shouldDrawHit:function(a){var b=this.getLayer();return a&&a.isCache||b&&b.hitGraphEnabled()&&this.isListening()&&this.isVisible()},show:function(){return this.setVisible(!0),this},hide:function(){return this.setVisible(!1),this},getZIndex:function(){return this.index||0},getAbsoluteZIndex:function(){function a(i){for(b=[],c=i.length,d=0;c>d;d++)e=i[d],h++,e.nodeType!==o&&(b=b.concat(e.getChildren().toArray())),e._id===g._id&&(d=c);b.length>0&&b[0].getDepth()<=f&&a(b)}var b,c,d,e,f=this.getDepth(),g=this,h=0;return g.nodeType!==s&&a(g.getStage().getChildren()),h},getDepth:function(){for(var a=0,b=this.parent;b;)a++,b=b.parent;return a},setPosition:function(a){return this.setX(a.x),this.setY(a.y),this},getPosition:function(){return{x:this.getX(),y:this.getY()}},getAbsolutePosition:function(){var a=this.getAbsoluteTransform().getMatrix(),b=new Kinetic.Transform,c=this.offset();return b.m=a.slice(),b.translate(c.x,c.y),b.getTranslation()},setAbsolutePosition:function(a){var b,c=this._clearTransform();return this.attrs.x=c.x,this.attrs.y=c.y,delete c.x,delete c.y,b=this.getAbsoluteTransform(),b.invert(),b.translate(a.x,a.y),a={x:this.attrs.x+b.getTranslation().x,y:this.attrs.y+b.getTranslation().y},this.setPosition({x:a.x,y:a.y}),this._setTransform(c),this},_setTransform:function(a){var c;for(c in a)this.attrs[c]=a[c];this._clearCache(r),this._clearSelfAndDescendantCache(b)},_clearTransform:function(){var a={x:this.getX(),y:this.getY(),rotation:this.getRotation(),scaleX:this.getScaleX(),scaleY:this.getScaleY(),offsetX:this.getOffsetX(),offsetY:this.getOffsetY(),skewX:this.getSkewX(),skewY:this.getSkewY()};return this.attrs.x=0,this.attrs.y=0,this.attrs.rotation=0,this.attrs.scaleX=1,this.attrs.scaleY=1,this.attrs.offsetX=0,this.attrs.offsetY=0,this.attrs.skewX=0,this.attrs.skewY=0,this._clearCache(r),this._clearSelfAndDescendantCache(b),a},move:function(a){var b=a.x,c=a.y,d=this.getX(),e=this.getY();return void 0!==b&&(d+=b),void 0!==c&&(e+=c),this.setPosition({x:d,y:e}),this},_eachAncestorReverse:function(a,b){var c,d,e=[],f=this.getParent();if(b&&b._id===this._id)return a(this),!0;for(e.unshift(this);f&&(!b||f._id!==b._id);)e.unshift(f),f=f.parent;for(c=e.length,d=0;c>d;d++)a(e[d])},rotate:function(a){return this.setRotation(this.getRotation()+a),this},moveToTop:function(){if(!this.parent)return void Kinetic.Util.warn(\"Node has no parent. moveToTop function is ignored.\");var a=this.index;return this.parent.children.splice(a,1),this.parent.children.push(this),this.parent._setChildrenIndices(),!0},moveUp:function(){if(!this.parent)return void Kinetic.Util.warn(\"Node has no parent. moveUp function is ignored.\");var a=this.index,b=this.parent.getChildren().length;return b-1>a?(this.parent.children.splice(a,1),this.parent.children.splice(a+1,0,this),this.parent._setChildrenIndices(),!0):!1},moveDown:function(){if(!this.parent)return void Kinetic.Util.warn(\"Node has no parent. moveDown function is ignored.\");var a=this.index;return a>0?(this.parent.children.splice(a,1),this.parent.children.splice(a-1,0,this),this.parent._setChildrenIndices(),!0):!1},moveToBottom:function(){if(!this.parent)return void Kinetic.Util.warn(\"Node has no parent. moveToBottom function is ignored.\");var a=this.index;return a>0?(this.parent.children.splice(a,1),this.parent.children.unshift(this),this.parent._setChildrenIndices(),!0):!1},setZIndex:function(a){if(!this.parent)return void Kinetic.Util.warn(\"Node has no parent. zIndex parameter is ignored.\");var b=this.index;return this.parent.children.splice(b,1),this.parent.children.splice(a,0,this),this.parent._setChildrenIndices(),this},getAbsoluteOpacity:function(){return this._getCache(a,this._getAbsoluteOpacity)},_getAbsoluteOpacity:function(){var a=this.getOpacity();return this.getParent()&&(a*=this.getParent().getAbsoluteOpacity()),a},moveTo:function(a){return this.getParent()!==a&&(this.remove(),a.add(this)),this},toObject:function(){var a,b,c,d,e=Kinetic.Util,f={},g=this.getAttrs();f.attrs={};for(a in g)b=g[a],e._isFunction(b)||e._isElement(b)||e._isObject(b)&&e._hasMethods(b)||(c=this[a],delete g[a],d=c?c.call(this):null,g[a]=b,d!==b&&(f.attrs[a]=b));return f.className=this.getClassName(),f},toJSON:function(){return JSON.stringify(this.toObject())},getParent:function(){return this.parent},getLayer:function(){var a=this.getParent();return a?a.getLayer():null},getStage:function(){return this._getCache(q,this._getStage)},_getStage:function(){var a=this.getParent();return a?a.getStage():void 0},fire:function(a,b,c){return c?this._fireAndBubble(a,b||{}):this._fire(a,b||{}),this},getAbsoluteTransform:function(a){return a?this._getAbsoluteTransform(a):this._getCache(b,this._getAbsoluteTransform)},_getAbsoluteTransform:function(a){var b,c,d=new Kinetic.Transform;return this._eachAncestorReverse(function(a){b=a.transformsEnabled(),c=a.getTransform(),\"all\"===b?d.multiply(c):\"position\"===b&&d.translate(a.x(),a.y())},a),d},getTransform:function(){return this._getCache(r,this._getTransform)},_getTransform:function(){var a=new Kinetic.Transform,b=this.getX(),c=this.getY(),d=Kinetic.getAngle(this.getRotation()),e=this.getScaleX(),f=this.getScaleY(),g=this.getSkewX(),h=this.getSkewY(),i=this.getOffsetX(),j=this.getOffsetY();return(0!==b||0!==c)&&a.translate(b,c),0!==d&&a.rotate(d),(0!==g||0!==h)&&a.skew(g,h),(1!==e||1!==f)&&a.scale(e,f),(0!==i||0!==j)&&a.translate(-1*i,-1*j),a},clone:function(a){var b,c,d,e,f,g=this.getClassName(),h=Kinetic.Util.cloneObject(this.attrs);for(var j in u){var k=u[j];delete h[k]}for(b in a)h[b]=a[b];var l=new Kinetic[g](h);for(b in this.eventListeners)for(c=this.eventListeners[b],d=c.length,e=0;d>e;e++)f=c[e],f.name.indexOf(i)<0&&(l.eventListeners[b]||(l.eventListeners[b]=[]),l.eventListeners[b].push(f));return l},toDataURL:function(a){a=a||{};var b=a.mimeType||null,c=a.quality||null,d=this.getStage(),e=a.x||0,f=a.y||0,g=new Kinetic.SceneCanvas({width:a.width||this.getWidth()||(d?d.getWidth():0),height:a.height||this.getHeight()||(d?d.getHeight():0),pixelRatio:1}),h=g.getContext();return h.save(),(e||f)&&h.translate(-1*e,-1*f),this.drawScene(g),h.restore(),g.toDataURL(b,c)},toImage:function(a){Kinetic.Util._getImage(this.toDataURL(a),function(b){a.callback(b)})},setSize:function(a){return this.setWidth(a.width),this.setHeight(a.height),this},getSize:function(){return{width:this.getWidth(),height:this.getHeight()}},getWidth:function(){return this.attrs.width||0},getHeight:function(){return this.attrs.height||0},getClassName:function(){return this.className||this.nodeType},getType:function(){return this.nodeType},getDragDistance:function(){return void 0!==this.attrs.dragDistance?this.attrs.dragDistance:this.parent?this.parent.getDragDistance():Kinetic.dragDistance\n},_get:function(a){return this.className===a||this.nodeType===a?[this]:[]},_off:function(a,b){var c,d,e=this.eventListeners[a];for(c=0;c<e.length;c++)if(d=e[c].name,!(\"kinetic\"===d&&\"kinetic\"!==b||b&&d!==b)){if(e.splice(c,1),0===e.length){delete this.eventListeners[a];break}c--}},_fireChangeEvent:function(a,b,d){this._fire(a+c,{oldVal:b,newVal:d})},setId:function(a){var b=this.getId();return Kinetic._removeId(b),Kinetic._addId(this,a),this._setAttr(h,a),this},setName:function(a){var b=this.getName();return Kinetic._removeName(b,this._id),Kinetic._addName(this,a),this._setAttr(m,a),this},setAttr:function(a,b){var c=n+Kinetic.Util._capitalize(a),d=this[c];return Kinetic.Util._isFunction(d)?d.call(this,b):this._setAttr(a,b),this},_setAttr:function(a,b){var c;void 0!==b&&(c=this.attrs[a],this.attrs[a]=b,this._fireChangeEvent(a,c,b))},_setComponentAttr:function(a,b,c){var d;void 0!==c&&(d=this.attrs[a],d||(this.attrs[a]=this.getAttr(a)),this.attrs[a][b]=c,this._fireChangeEvent(a,d,c))},_fireAndBubble:function(a,b,c){var d=!0;if(b&&this.nodeType===o&&(b.target=this),a===k&&c&&(this._id===c._id||this.isAncestorOf&&this.isAncestorOf(c))?d=!1:a===l&&c&&(this._id===c._id||this.isAncestorOf&&this.isAncestorOf(c))&&(d=!1),d){this._fire(a,b);var e=(a===k||a===l)&&(c&&c.isAncestorOf&&c.isAncestorOf(this)||!(!c||!c.isAncestorOf));b&&!b.cancelBubble&&this.parent&&this.parent.isListening()&&!e&&(c&&c.parent?this._fireAndBubble.call(this.parent,a,b,c.parent):this._fireAndBubble.call(this.parent,a,b))}},_fire:function(a,b){var c,d=this.eventListeners[a];if(b.type=a,d)for(c=0;c<d.length;c++)d[c].handler.call(this,b)},draw:function(){return this.drawScene(),this.drawHit(),this}}),Kinetic.Node.create=function(a,b){return this._createNode(JSON.parse(a),b)},Kinetic.Node._createNode=function(a,b){var c,d,e,f=Kinetic.Node.prototype.getClassName.call(a),g=a.children;if(b&&(a.attrs.container=b),c=new Kinetic[f](a.attrs),g)for(d=g.length,e=0;d>e;e++)c.add(this._createNode(g[e]));return c},Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"position\"),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"x\",0),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"y\",0),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"opacity\",1),Kinetic.Factory.addGetter(Kinetic.Node,\"name\"),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"name\"),Kinetic.Factory.addGetter(Kinetic.Node,\"id\"),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"id\"),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"rotation\",0),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Node,\"scale\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"scaleX\",1),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"scaleY\",1),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Node,\"skew\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"skewX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"skewY\",0),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Node,\"offset\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"offsetX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"offsetY\",0),Kinetic.Factory.addSetter(Kinetic.Node,\"dragDistance\"),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"dragDistance\"),Kinetic.Factory.addSetter(Kinetic.Node,\"width\",0),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"width\"),Kinetic.Factory.addSetter(Kinetic.Node,\"height\",0),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"height\"),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"listening\",\"inherit\"),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"filters\",void 0,function(a){return this._filterUpToDate=!1,a}),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"visible\",\"inherit\"),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"transformsEnabled\",\"all\"),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"size\"),Kinetic.Factory.backCompat(Kinetic.Node,{rotateDeg:\"rotate\",setRotationDeg:\"setRotation\",getRotationDeg:\"getRotation\"}),Kinetic.Collection.mapMethods(Kinetic.Node)}(),function(){Kinetic.Filters.Grayscale=function(a){var b,c,d=a.data,e=d.length;for(b=0;e>b;b+=4)c=.34*d[b]+.5*d[b+1]+.16*d[b+2],d[b]=c,d[b+1]=c,d[b+2]=c}}(),function(){Kinetic.Filters.Brighten=function(a){var b,c=255*this.brightness(),d=a.data,e=d.length;for(b=0;e>b;b+=4)d[b]+=c,d[b+1]+=c,d[b+2]+=c},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"brightness\",0,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.Invert=function(a){var b,c=a.data,d=c.length;for(b=0;d>b;b+=4)c[b]=255-c[b],c[b+1]=255-c[b+1],c[b+2]=255-c[b+2]}}(),function(){function a(){this.r=0,this.g=0,this.b=0,this.a=0,this.next=null}function b(b,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D=b.data,E=b.width,F=b.height,G=e+e+1,H=E-1,I=F-1,J=e+1,K=J*(J+1)/2,L=new a,M=null,N=L,O=null,P=null,Q=c[e],R=d[e];for(h=1;G>h;h++)N=N.next=new a,h==J&&(M=N);for(N.next=L,l=k=0,g=0;F>g;g++){for(u=v=w=x=m=n=o=p=0,q=J*(y=D[k]),r=J*(z=D[k+1]),s=J*(A=D[k+2]),t=J*(B=D[k+3]),m+=K*y,n+=K*z,o+=K*A,p+=K*B,N=L,h=0;J>h;h++)N.r=y,N.g=z,N.b=A,N.a=B,N=N.next;for(h=1;J>h;h++)i=k+((h>H?H:h)<<2),m+=(N.r=y=D[i])*(C=J-h),n+=(N.g=z=D[i+1])*C,o+=(N.b=A=D[i+2])*C,p+=(N.a=B=D[i+3])*C,u+=y,v+=z,w+=A,x+=B,N=N.next;for(O=L,P=M,f=0;E>f;f++)D[k+3]=B=p*Q>>R,0!==B?(B=255/B,D[k]=(m*Q>>R)*B,D[k+1]=(n*Q>>R)*B,D[k+2]=(o*Q>>R)*B):D[k]=D[k+1]=D[k+2]=0,m-=q,n-=r,o-=s,p-=t,q-=O.r,r-=O.g,s-=O.b,t-=O.a,i=l+((i=f+e+1)<H?i:H)<<2,u+=O.r=D[i],v+=O.g=D[i+1],w+=O.b=D[i+2],x+=O.a=D[i+3],m+=u,n+=v,o+=w,p+=x,O=O.next,q+=y=P.r,r+=z=P.g,s+=A=P.b,t+=B=P.a,u-=y,v-=z,w-=A,x-=B,P=P.next,k+=4;l+=E}for(f=0;E>f;f++){for(v=w=x=u=n=o=p=m=0,k=f<<2,q=J*(y=D[k]),r=J*(z=D[k+1]),s=J*(A=D[k+2]),t=J*(B=D[k+3]),m+=K*y,n+=K*z,o+=K*A,p+=K*B,N=L,h=0;J>h;h++)N.r=y,N.g=z,N.b=A,N.a=B,N=N.next;for(j=E,h=1;e>=h;h++)k=j+f<<2,m+=(N.r=y=D[k])*(C=J-h),n+=(N.g=z=D[k+1])*C,o+=(N.b=A=D[k+2])*C,p+=(N.a=B=D[k+3])*C,u+=y,v+=z,w+=A,x+=B,N=N.next,I>h&&(j+=E);for(k=f,O=L,P=M,g=0;F>g;g++)i=k<<2,D[i+3]=B=p*Q>>R,B>0?(B=255/B,D[i]=(m*Q>>R)*B,D[i+1]=(n*Q>>R)*B,D[i+2]=(o*Q>>R)*B):D[i]=D[i+1]=D[i+2]=0,m-=q,n-=r,o-=s,p-=t,q-=O.r,r-=O.g,s-=O.b,t-=O.a,i=f+((i=g+J)<I?i:I)*E<<2,m+=u+=O.r=D[i],n+=v+=O.g=D[i+1],o+=w+=O.b=D[i+2],p+=x+=O.a=D[i+3],O=O.next,q+=y=P.r,r+=z=P.g,s+=A=P.b,t+=B=P.a,u-=y,v-=z,w-=A,x-=B,P=P.next,k+=E}}var c=[512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259],d=[9,11,12,13,13,14,14,15,15,15,15,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24];Kinetic.Filters.Blur=function(a){var c=Math.round(this.blurRadius());c>0&&b(a,c)},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"blurRadius\",0,null,Kinetic.Factory.afterSetFilter)}(),function(){function a(a,b,c){var d=4*(c*a.width+b),e=[];return e.push(a.data[d++],a.data[d++],a.data[d++],a.data[d++]),e}function b(a,b){return Math.sqrt(Math.pow(a[0]-b[0],2)+Math.pow(a[1]-b[1],2)+Math.pow(a[2]-b[2],2))}function c(a){for(var b=[0,0,0],c=0;c<a.length;c++)b[0]+=a[c][0],b[1]+=a[c][1],b[2]+=a[c][2];return b[0]/=a.length,b[1]/=a.length,b[2]/=a.length,b}function d(d,e){var f=a(d,0,0),g=a(d,d.width-1,0),h=a(d,0,d.height-1),i=a(d,d.width-1,d.height-1),j=e||10;if(b(f,g)<j&&b(g,i)<j&&b(i,h)<j&&b(h,f)<j){for(var k=c([g,f,i,h]),l=[],m=0;m<d.width*d.height;m++){var n=b(k,[d.data[4*m],d.data[4*m+1],d.data[4*m+2]]);l[m]=j>n?0:255}return l}}function e(a,b){for(var c=0;c<a.width*a.height;c++)a.data[4*c+3]=b[c]}function f(a,b,c){for(var d=[1,1,1,1,0,1,1,1,1],e=Math.round(Math.sqrt(d.length)),f=Math.floor(e/2),g=[],h=0;c>h;h++)for(var i=0;b>i;i++){for(var j=h*b+i,k=0,l=0;e>l;l++)for(var m=0;e>m;m++){var n=h+l-f,o=i+m-f;if(n>=0&&c>n&&o>=0&&b>o){var p=n*b+o,q=d[l*e+m];k+=a[p]*q}}g[j]=2040===k?255:0}return g}function g(a,b,c){for(var d=[1,1,1,1,1,1,1,1,1],e=Math.round(Math.sqrt(d.length)),f=Math.floor(e/2),g=[],h=0;c>h;h++)for(var i=0;b>i;i++){for(var j=h*b+i,k=0,l=0;e>l;l++)for(var m=0;e>m;m++){var n=h+l-f,o=i+m-f;if(n>=0&&c>n&&o>=0&&b>o){var p=n*b+o,q=d[l*e+m];k+=a[p]*q}}g[j]=k>=1020?255:0}return g}function h(a,b,c){for(var d=[1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9],e=Math.round(Math.sqrt(d.length)),f=Math.floor(e/2),g=[],h=0;c>h;h++)for(var i=0;b>i;i++){for(var j=h*b+i,k=0,l=0;e>l;l++)for(var m=0;e>m;m++){var n=h+l-f,o=i+m-f;if(n>=0&&c>n&&o>=0&&b>o){var p=n*b+o,q=d[l*e+m];k+=a[p]*q}}g[j]=k}return g}Kinetic.Filters.Mask=function(a){var b=this.threshold(),c=d(a,b);return c&&(c=f(c,a.width,a.height),c=g(c,a.width,a.height),c=h(c,a.width,a.height),e(a,c)),a},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"threshold\",0,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.RGB=function(a){var b,c,d=a.data,e=d.length,f=this.red(),g=this.green(),h=this.blue();for(b=0;e>b;b+=4)c=(.34*d[b]+.5*d[b+1]+.16*d[b+2])/255,d[b]=c*f,d[b+1]=c*g,d[b+2]=c*h,d[b+3]=d[b+3]},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"red\",0,function(a){return this._filterUpToDate=!1,a>255?255:0>a?0:Math.round(a)}),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"green\",0,function(a){return this._filterUpToDate=!1,a>255?255:0>a?0:Math.round(a)}),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"blue\",0,Kinetic.Validators.RGBComponent,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.HSV=function(a){var b,c,d,e,f,g=a.data,h=g.length,i=Math.pow(2,this.value()),j=Math.pow(2,this.saturation()),k=Math.abs(this.hue()+360)%360,l=i*j*Math.cos(k*Math.PI/180),m=i*j*Math.sin(k*Math.PI/180),n=.299*i+.701*l+.167*m,o=.587*i-.587*l+.33*m,p=.114*i-.114*l-.497*m,q=.299*i-.299*l-.328*m,r=.587*i+.413*l+.035*m,s=.114*i-.114*l+.293*m,t=.299*i-.3*l+1.25*m,u=.587*i-.586*l-1.05*m,v=.114*i+.886*l-.2*m;for(b=0;h>b;b+=4)c=g[b+0],d=g[b+1],e=g[b+2],f=g[b+3],g[b+0]=n*c+o*d+p*e,g[b+1]=q*c+r*d+s*e,g[b+2]=t*c+u*d+v*e,g[b+3]=f},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"hue\",0,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"saturation\",0,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"value\",0,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Factory.addGetterSetter(Kinetic.Node,\"hue\",0,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"saturation\",0,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"luminance\",0,null,Kinetic.Factory.afterSetFilter),Kinetic.Filters.HSL=function(a){var b,c,d,e,f,g=a.data,h=g.length,i=1,j=Math.pow(2,this.saturation()),k=Math.abs(this.hue()+360)%360,l=127*this.luminance(),m=i*j*Math.cos(k*Math.PI/180),n=i*j*Math.sin(k*Math.PI/180),o=.299*i+.701*m+.167*n,p=.587*i-.587*m+.33*n,q=.114*i-.114*m-.497*n,r=.299*i-.299*m-.328*n,s=.587*i+.413*m+.035*n,t=.114*i-.114*m+.293*n,u=.299*i-.3*m+1.25*n,v=.587*i-.586*m-1.05*n,w=.114*i+.886*m-.2*n;for(b=0;h>b;b+=4)c=g[b+0],d=g[b+1],e=g[b+2],f=g[b+3],g[b+0]=o*c+p*d+q*e+l,g[b+1]=r*c+s*d+t*e+l,g[b+2]=u*c+v*d+w*e+l,g[b+3]=f}}(),function(){Kinetic.Filters.Emboss=function(a){var b=10*this.embossStrength(),c=255*this.embossWhiteLevel(),d=this.embossDirection(),e=this.embossBlend(),f=0,g=0,h=a.data,i=a.width,j=a.height,k=4*i,l=j;switch(d){case\"top-left\":f=-1,g=-1;break;case\"top\":f=-1,g=0;break;case\"top-right\":f=-1,g=1;break;case\"right\":f=0,g=1;break;case\"bottom-right\":f=1,g=1;break;case\"bottom\":f=1,g=0;break;case\"bottom-left\":f=1,g=-1;break;case\"left\":f=0,g=-1}do{var m=(l-1)*k,n=f;1>l+n&&(n=0),l+n>j&&(n=0);var o=(l-1+n)*i*4,p=i;do{var q=m+4*(p-1),r=g;1>p+r&&(r=0),p+r>i&&(r=0);var s=o+4*(p-1+r),t=h[q]-h[s],u=h[q+1]-h[s+1],v=h[q+2]-h[s+2],w=t,x=w>0?w:-w,y=u>0?u:-u,z=v>0?v:-v;if(y>x&&(w=u),z>x&&(w=v),w*=b,e){var A=h[q]+w,B=h[q+1]+w,C=h[q+2]+w;h[q]=A>255?255:0>A?0:A,h[q+1]=B>255?255:0>B?0:B,h[q+2]=C>255?255:0>C?0:C}else{var D=c-w;0>D?D=0:D>255&&(D=255),h[q]=h[q+1]=h[q+2]=D}}while(--p)}while(--l)},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"embossStrength\",.5,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"embossWhiteLevel\",.5,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"embossDirection\",\"top-left\",null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"embossBlend\",!1,null,Kinetic.Factory.afterSetFilter)}(),function(){function a(a,b,c,d,e){var f,g=c-b,h=e-d;return 0===g?d+h/2:0===h?d:(f=(a-b)/g,f=h*f+d)}Kinetic.Filters.Enhance=function(b){var c,d,e,f,g=b.data,h=g.length,i=g[0],j=i,k=g[1],l=k,m=g[2],n=m,o=this.enhance();if(0!==o){for(f=0;h>f;f+=4)c=g[f+0],i>c?i=c:c>j&&(j=c),d=g[f+1],k>d?k=d:d>l&&(l=d),e=g[f+2],m>e?m=e:e>n&&(n=e);j===i&&(j=255,i=0),l===k&&(l=255,k=0),n===m&&(n=255,m=0);var p,q,r,s,t,u,v,w,x;for(o>0?(q=j+o*(255-j),r=i-o*(i-0),t=l+o*(255-l),u=k-o*(k-0),w=n+o*(255-n),x=m-o*(m-0)):(p=.5*(j+i),q=j+o*(j-p),r=i+o*(i-p),s=.5*(l+k),t=l+o*(l-s),u=k+o*(k-s),v=.5*(n+m),w=n+o*(n-v),x=m+o*(m-v)),f=0;h>f;f+=4)g[f+0]=a(g[f+0],i,j,r,q),g[f+1]=a(g[f+1],k,l,u,t),g[f+2]=a(g[f+2],m,n,x,w)}},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"enhance\",0,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.Posterize=function(a){var b,c=Math.round(254*this.levels())+1,d=a.data,e=d.length,f=255/c;for(b=0;e>b;b+=1)d[b]=Math.floor(d[b]/f)*f},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"levels\",.5,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.Noise=function(a){var b,c=255*this.noise(),d=a.data,e=d.length,f=c/2;for(b=0;e>b;b+=4)d[b+0]+=f-2*f*Math.random(),d[b+1]+=f-2*f*Math.random(),d[b+2]+=f-2*f*Math.random()},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"noise\",.2,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.Pixelate=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p=Math.ceil(this.pixelSize()),q=a.width,r=a.height,s=Math.ceil(q/p),t=Math.ceil(r/p);for(a=a.data,m=0;s>m;m+=1)for(n=0;t>n;n+=1){for(e=0,f=0,g=0,h=0,i=m*p,j=i+p,k=n*p,l=k+p,o=0,b=i;j>b;b+=1)if(!(b>=q))for(c=k;l>c;c+=1)c>=r||(d=4*(q*c+b),e+=a[d+0],f+=a[d+1],g+=a[d+2],h+=a[d+3],o+=1);for(e/=o,f/=o,g/=o,b=i;j>b;b+=1)if(!(b>=q))for(c=k;l>c;c+=1)c>=r||(d=4*(q*c+b),a[d+0]=e,a[d+1]=f,a[d+2]=g,a[d+3]=h)}},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"pixelSize\",8,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.Threshold=function(a){var b,c=255*this.threshold(),d=a.data,e=d.length;for(b=0;e>b;b+=1)d[b]=d[b]<c?0:255},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"threshold\",.5,null,Kinetic.Factory.afterSetFilter)}(),function(){Kinetic.Filters.Sepia=function(a){var b,c,d,e,f,g,h,i,j,k=a.data,l=a.width,m=a.height,n=4*l;do{b=(m-1)*n,c=l;do d=b+4*(c-1),e=k[d],f=k[d+1],g=k[d+2],h=.393*e+.769*f+.189*g,i=.349*e+.686*f+.168*g,j=.272*e+.534*f+.131*g,k[d]=h>255?255:h,k[d+1]=i>255?255:i,k[d+2]=j>255?255:j,k[d+3]=k[d+3];while(--c)}while(--m)}}(),function(){Kinetic.Filters.Solarize=function(a){var b=a.data,c=a.width,d=a.height,e=4*c,f=d;do{var g=(f-1)*e,h=c;do{var i=g+4*(h-1),j=b[i],k=b[i+1],l=b[i+2];j>127&&(j=255-j),k>127&&(k=255-k),l>127&&(l=255-l),b[i]=j,b[i+1]=k,b[i+2]=l}while(--h)}while(--f)}}(),function(){var a=function(a,b,c){var d,e,f,g,h=a.data,i=b.data,j=a.width,k=a.height,l=c.polarCenterX||j/2,m=c.polarCenterY||k/2,n=0,o=0,p=0,q=0,r=Math.sqrt(l*l+m*m);e=j-l,f=k-m,g=Math.sqrt(e*e+f*f),r=g>r?g:r;var s,t,u,v,w=k,x=j,y=360/x*Math.PI/180;for(t=0;x>t;t+=1)for(u=Math.sin(t*y),v=Math.cos(t*y),s=0;w>s;s+=1)e=Math.floor(l+r*s/w*v),f=Math.floor(m+r*s/w*u),d=4*(f*j+e),n=h[d+0],o=h[d+1],p=h[d+2],q=h[d+3],d=4*(t+s*j),i[d+0]=n,i[d+1]=o,i[d+2]=p,i[d+3]=q},b=function(a,b,c){var d,e,f,g,h,i,j=a.data,k=b.data,l=a.width,m=a.height,n=c.polarCenterX||l/2,o=c.polarCenterY||m/2,p=0,q=0,r=0,s=0,t=Math.sqrt(n*n+o*o);e=l-n,f=m-o,i=Math.sqrt(e*e+f*f),t=i>t?i:t;var u,v,w,x,y=m,z=l,A=c.polarRotation||0;for(e=0;l>e;e+=1)for(f=0;m>f;f+=1)g=e-n,h=f-o,u=Math.sqrt(g*g+h*h)*y/t,v=(180*Math.atan2(h,g)/Math.PI+360+A)%360,v=v*z/360,w=Math.floor(v),x=Math.floor(u),d=4*(x*l+w),p=j[d+0],q=j[d+1],r=j[d+2],s=j[d+3],d=4*(f*l+e),k[d+0]=p,k[d+1]=q,k[d+2]=r,k[d+3]=s},c=Kinetic.Util.createCanvasElement();Kinetic.Filters.Kaleidoscope=function(d){var e,f,g,h,i,j,k,l,m,n,o=d.width,p=d.height,q=Math.round(this.kaleidoscopePower()),r=Math.round(this.kaleidoscopeAngle()),s=Math.floor(o*(r%360)/360);if(!(1>q)){c.width=o,c.height=p;var t=c.getContext(\"2d\").getImageData(0,0,o,p);a(d,t,{polarCenterX:o/2,polarCenterY:p/2});for(var u=o/Math.pow(2,q);8>=u;)u=2*u,q-=1;u=Math.ceil(u);var v=u,w=0,x=v,y=1;for(s+u>o&&(w=v,x=0,y=-1),f=0;p>f;f+=1)for(e=w;e!==x;e+=y)g=Math.round(e+s)%o,m=4*(o*f+g),i=t.data[m+0],j=t.data[m+1],k=t.data[m+2],l=t.data[m+3],n=4*(o*f+e),t.data[n+0]=i,t.data[n+1]=j,t.data[n+2]=k,t.data[n+3]=l;for(f=0;p>f;f+=1)for(v=Math.floor(u),h=0;q>h;h+=1){for(e=0;v+1>e;e+=1)m=4*(o*f+e),i=t.data[m+0],j=t.data[m+1],k=t.data[m+2],l=t.data[m+3],n=4*(o*f+2*v-e-1),t.data[n+0]=i,t.data[n+1]=j,t.data[n+2]=k,t.data[n+3]=l;v*=2}b(t,d,{polarRotation:0})}},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"kaleidoscopePower\",2,null,Kinetic.Factory.afterSetFilter),Kinetic.Factory.addGetterSetter(Kinetic.Node,\"kaleidoscopeAngle\",0,null,Kinetic.Factory.afterSetFilter)}(),function(){function a(a){setTimeout(a,1e3/60)}function b(){return e.apply(Kinetic.root,arguments)}var c=500,d=function(){return Kinetic.root.performance&&Kinetic.root.performance.now?function(){return Kinetic.root.performance.now()}:function(){return(new Date).getTime()}}(),e=function(){return Kinetic.root.requestAnimationFrame||Kinetic.root.webkitRequestAnimationFrame||Kinetic.root.mozRequestAnimationFrame||Kinetic.root.oRequestAnimationFrame||Kinetic.root.msRequestAnimationFrame||a}();Kinetic.Animation=function(a,b){var c=Kinetic.Animation;this.func=a,this.setLayers(b),this.id=c.animIdCounter++,this.frame={time:0,timeDiff:0,lastTime:d()}},Kinetic.Animation.prototype={setLayers:function(a){var b=[];b=a?a.length>0?a:[a]:[],this.layers=b},getLayers:function(){return this.layers},addLayer:function(a){var b,c,d=this.layers;if(d){for(b=d.length,c=0;b>c;c++)if(d[c]._id===a._id)return!1}else this.layers=[];return this.layers.push(a),!0},isRunning:function(){var a,b=Kinetic.Animation,c=b.animations,d=c.length;for(a=0;d>a;a++)if(c[a].id===this.id)return!0;return!1},start:function(){var a=Kinetic.Animation;this.stop(),this.frame.timeDiff=0,this.frame.lastTime=d(),a._addAnimation(this)},stop:function(){Kinetic.Animation._removeAnimation(this)},_updateFrameObject:function(a){this.frame.timeDiff=a-this.frame.lastTime,this.frame.lastTime=a,this.frame.time+=this.frame.timeDiff,this.frame.frameRate=1e3/this.frame.timeDiff}},Kinetic.Animation.animations=[],Kinetic.Animation.animIdCounter=0,Kinetic.Animation.animRunning=!1,Kinetic.Animation._addAnimation=function(a){this.animations.push(a),this._handleAnimation()},Kinetic.Animation._removeAnimation=function(a){var b,c=a.id,d=this.animations,e=d.length;for(b=0;e>b;b++)if(d[b].id===c){this.animations.splice(b,1);break}},Kinetic.Animation._runFrames=function(){var a,b,c,e,f,g,h,i,j,k={},l=this.animations;for(e=0;e<l.length;e++)if(a=l[e],b=a.layers,c=a.func,a._updateFrameObject(d()),g=b.length,j=c?c.call(a,a.frame)!==!1:!0)for(f=0;g>f;f++)h=b[f],void 0!==h._id&&(k[h._id]=h);for(i in k)k[i].draw()},Kinetic.Animation._animationLoop=function(){var a=Kinetic.Animation;a.animations.length?(b(a._animationLoop),a._runFrames()):a.animRunning=!1},Kinetic.Animation._handleAnimation=function(){var a=this;this.animRunning||(this.animRunning=!0,a._animationLoop())};var f=Kinetic.Node.prototype.moveTo;Kinetic.Node.prototype.moveTo=function(a){f.call(this,a)},Kinetic.BaseLayer.prototype.batchDraw=function(){var a=this,b=Kinetic.Animation;this.batchAnim||(this.batchAnim=new b(function(){a.lastBatchDrawTime&&d()-a.lastBatchDrawTime>c&&a.batchAnim.stop()},this)),this.lastBatchDrawTime=d(),this.batchAnim.isRunning()||(this.draw(),this.batchAnim.start())},Kinetic.Stage.prototype.batchDraw=function(){this.getChildren().each(function(a){a.batchDraw()})}}(this),function(){var a={node:1,duration:1,easing:1,onFinish:1,yoyo:1},b=1,c=2,d=3,e=0;Kinetic.Tween=function(b){var c,d,g=this,h=b.node,i=h._id,j=b.easing||Kinetic.Easings.Linear,k=!!b.yoyo;c=\"undefined\"==typeof b.duration?1:0===b.duration?.001:b.duration,this.node=h,this._id=e++,this.anim=new Kinetic.Animation(function(){g.tween.onEnterFrame()},h.getLayer()||(h instanceof Kinetic.Stage?h.getLayers():null)),this.tween=new f(d,function(a){g._tweenFunc(a)},j,0,1,1e3*c,k),this._addListeners(),Kinetic.Tween.attrs[i]||(Kinetic.Tween.attrs[i]={}),Kinetic.Tween.attrs[i][this._id]||(Kinetic.Tween.attrs[i][this._id]={}),Kinetic.Tween.tweens[i]||(Kinetic.Tween.tweens[i]={});for(d in b)void 0===a[d]&&this._addAttr(d,b[d]);this.reset(),this.onFinish=b.onFinish,this.onReset=b.onReset},Kinetic.Tween.attrs={},Kinetic.Tween.tweens={},Kinetic.Tween.prototype={_addAttr:function(a,b){var c,d,e,f,g,h=this.node,i=h._id;if(e=Kinetic.Tween.tweens[i][a],e&&delete Kinetic.Tween.attrs[i][e][a],c=h.getAttr(a),Kinetic.Util._isArray(b))for(d=[],g=b.length,f=0;g>f;f++)d.push(b[f]-c[f]);else d=b-c;Kinetic.Tween.attrs[i][this._id][a]={start:c,diff:d},Kinetic.Tween.tweens[i][a]=this._id},_tweenFunc:function(a){var b,c,d,e,f,g,h,i=this.node,j=Kinetic.Tween.attrs[i._id][this._id];for(b in j){if(c=j[b],d=c.start,e=c.diff,Kinetic.Util._isArray(d))for(f=[],h=d.length,g=0;h>g;g++)f.push(d[g]+e[g]*a);else f=d+e*a;i.setAttr(b,f)}},_addListeners:function(){var a=this;this.tween.onPlay=function(){a.anim.start()},this.tween.onReverse=function(){a.anim.start()},this.tween.onPause=function(){a.anim.stop()},this.tween.onFinish=function(){a.onFinish&&a.onFinish()},this.tween.onReset=function(){a.onReset&&a.onReset()}},play:function(){return this.tween.play(),this},reverse:function(){return this.tween.reverse(),this},reset:function(){return this.tween.reset(),this},seek:function(a){return this.tween.seek(1e3*a),this},pause:function(){return this.tween.pause(),this},finish:function(){return this.tween.finish(),this},destroy:function(){var a,b=this.node._id,c=this._id,d=Kinetic.Tween.tweens[b];this.pause();for(a in d)delete Kinetic.Tween.tweens[b][a];delete Kinetic.Tween.attrs[b][c]}};var f=function(a,b,c,d,e,f,g){this.prop=a,this.propFunc=b,this.begin=d,this._pos=d,this.duration=f,this._change=0,this.prevPos=0,this.yoyo=g,this._time=0,this._position=0,this._startTime=0,this._finish=0,this.func=c,this._change=e-this.begin,this.pause()};f.prototype={fire:function(a){var b=this[a];b&&b()},setTime:function(a){a>this.duration?this.yoyo?(this._time=this.duration,this.reverse()):this.finish():0>a?this.yoyo?(this._time=0,this.play()):this.reset():(this._time=a,this.update())},getTime:function(){return this._time},setPosition:function(a){this.prevPos=this._pos,this.propFunc(a),this._pos=a},getPosition:function(a){return void 0===a&&(a=this._time),this.func(a,this.begin,this._change,this.duration)},play:function(){this.state=c,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire(\"onPlay\")},reverse:function(){this.state=d,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire(\"onReverse\")},seek:function(a){this.pause(),this._time=a,this.update(),this.fire(\"onSeek\")},reset:function(){this.pause(),this._time=0,this.update(),this.fire(\"onReset\")},finish:function(){this.pause(),this._time=this.duration,this.update(),this.fire(\"onFinish\")},update:function(){this.setPosition(this.getPosition(this._time))},onEnterFrame:function(){var a=this.getTimer()-this._startTime;this.state===c?this.setTime(a):this.state===d&&this.setTime(this.duration-a)},pause:function(){this.state=b,this.fire(\"onPause\")},getTimer:function(){return(new Date).getTime()}},Kinetic.Easings={BackEaseIn:function(a,b,c,d){var e=1.70158;return c*(a/=d)*a*((e+1)*a-e)+b},BackEaseOut:function(a,b,c,d){var e=1.70158;return c*((a=a/d-1)*a*((e+1)*a+e)+1)+b},BackEaseInOut:function(a,b,c,d){var e=1.70158;return(a/=d/2)<1?c/2*a*a*(((e*=1.525)+1)*a-e)+b:c/2*((a-=2)*a*(((e*=1.525)+1)*a+e)+2)+b},ElasticEaseIn:function(a,b,c,d,e,f){var g=0;return 0===a?b:1==(a/=d)?b+c:(f||(f=.3*d),!e||e<Math.abs(c)?(e=c,g=f/4):g=f/(2*Math.PI)*Math.asin(c/e),-(e*Math.pow(2,10*(a-=1))*Math.sin(2*(a*d-g)*Math.PI/f))+b)},ElasticEaseOut:function(a,b,c,d,e,f){var g=0;return 0===a?b:1==(a/=d)?b+c:(f||(f=.3*d),!e||e<Math.abs(c)?(e=c,g=f/4):g=f/(2*Math.PI)*Math.asin(c/e),e*Math.pow(2,-10*a)*Math.sin(2*(a*d-g)*Math.PI/f)+c+b)},ElasticEaseInOut:function(a,b,c,d,e,f){var g=0;return 0===a?b:2==(a/=d/2)?b+c:(f||(f=.3*d*1.5),!e||e<Math.abs(c)?(e=c,g=f/4):g=f/(2*Math.PI)*Math.asin(c/e),1>a?-.5*e*Math.pow(2,10*(a-=1))*Math.sin(2*(a*d-g)*Math.PI/f)+b:e*Math.pow(2,-10*(a-=1))*Math.sin(2*(a*d-g)*Math.PI/f)*.5+c+b)},BounceEaseOut:function(a,b,c,d){return(a/=d)<1/2.75?7.5625*c*a*a+b:2/2.75>a?c*(7.5625*(a-=1.5/2.75)*a+.75)+b:2.5/2.75>a?c*(7.5625*(a-=2.25/2.75)*a+.9375)+b:c*(7.5625*(a-=2.625/2.75)*a+.984375)+b},BounceEaseIn:function(a,b,c,d){return c-Kinetic.Easings.BounceEaseOut(d-a,0,c,d)+b},BounceEaseInOut:function(a,b,c,d){return d/2>a?.5*Kinetic.Easings.BounceEaseIn(2*a,0,c,d)+b:.5*Kinetic.Easings.BounceEaseOut(2*a-d,0,c,d)+.5*c+b},EaseIn:function(a,b,c,d){return c*(a/=d)*a+b},EaseOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},EaseInOut:function(a,b,c,d){return(a/=d/2)<1?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},StrongEaseIn:function(a,b,c,d){return c*(a/=d)*a*a*a*a+b},StrongEaseOut:function(a,b,c,d){return c*((a=a/d-1)*a*a*a*a+1)+b},StrongEaseInOut:function(a,b,c,d){return(a/=d/2)<1?c/2*a*a*a*a*a+b:c/2*((a-=2)*a*a*a*a+2)+b},Linear:function(a,b,c,d){return c*a/d+b}}}(),function(){Kinetic.DD={anim:new Kinetic.Animation(function(){var a=this.dirty;return this.dirty=!1,a}),isDragging:!1,justDragged:!1,offset:{x:0,y:0},node:null,_drag:function(a){var b=Kinetic.DD,c=b.node;if(c){if(!b.isDragging){var d=c.getStage().getPointerPosition(),e=c.dragDistance(),f=Math.max(Math.abs(d.x-b.startPointerPos.x),Math.abs(d.y-b.startPointerPos.y));if(e>f)return}c._setDragPosition(a),b.isDragging||(b.isDragging=!0,c.fire(\"dragstart\",{type:\"dragstart\",target:c,evt:a},!0)),c.fire(\"dragmove\",{type:\"dragmove\",target:c,evt:a},!0)}},_endDragBefore:function(a){var b,c,d=Kinetic.DD,e=d.node;e&&(b=e.nodeType,c=e.getLayer(),d.anim.stop(),d.isDragging&&(d.isDragging=!1,d.justDragged=!0,Kinetic.listenClickTap=!1,a&&(a.dragEndNode=e)),delete d.node,(c||e).draw())},_endDragAfter:function(a){a=a||{};var b=a.dragEndNode;a&&b&&b.fire(\"dragend\",{type:\"dragend\",target:b,evt:a},!0)}},Kinetic.Node.prototype.startDrag=function(){var a=Kinetic.DD,b=this.getStage(),c=this.getLayer(),d=b.getPointerPosition(),e=this.getAbsolutePosition();d&&(a.node&&a.node.stopDrag(),a.node=this,a.startPointerPos=d,a.offset.x=d.x-e.x,a.offset.y=d.y-e.y,a.anim.setLayers(c||this.getLayers()),a.anim.start(),this._setDragPosition())},Kinetic.Node.prototype._setDragPosition=function(a){var b=Kinetic.DD,c=this.getStage().getPointerPosition(),d=this.getDragBoundFunc();if(c){var e={x:c.x-b.offset.x,y:c.y-b.offset.y};void 0!==d&&(e=d.call(this,e,a)),this.setAbsolutePosition(e),this._lastPos&&this._lastPos.x===e.x&&this._lastPos.y===e.y||(b.anim.dirty=!0),this._lastPos=e}},Kinetic.Node.prototype.stopDrag=function(){var a=Kinetic.DD,b={};a._endDragBefore(b),a._endDragAfter(b)},Kinetic.Node.prototype.setDraggable=function(a){this._setAttr(\"draggable\",a),this._dragChange()};var a=Kinetic.Node.prototype.destroy;Kinetic.Node.prototype.destroy=function(){var b=Kinetic.DD;b.node&&b.node._id===this._id&&this.stopDrag(),a.call(this)},Kinetic.Node.prototype.isDragging=function(){var a=Kinetic.DD;return!(!a.node||a.node._id!==this._id||!a.isDragging)},Kinetic.Node.prototype._listenDrag=function(){var a=this;this._dragCleanup(),\"Stage\"===this.getClassName()?this.on(\"contentMousedown.kinetic contentTouchstart.kinetic\",function(b){Kinetic.DD.node||a.startDrag(b)}):this.on(\"mousedown.kinetic touchstart.kinetic\",function(b){1!==b.evt.button&&2!==b.evt.button&&(Kinetic.DD.node||a.startDrag(b))})},Kinetic.Node.prototype._dragChange=function(){if(this.attrs.draggable)this._listenDrag();else{this._dragCleanup();var a=this.getStage(),b=Kinetic.DD;a&&b.node&&b.node._id===this._id&&b.node.stopDrag()}},Kinetic.Node.prototype._dragCleanup=function(){\"Stage\"===this.getClassName()?(this.off(\"contentMousedown.kinetic\"),this.off(\"contentTouchstart.kinetic\")):(this.off(\"mousedown.kinetic\"),this.off(\"touchstart.kinetic\"))},Kinetic.Factory.addGetterSetter(Kinetic.Node,\"dragBoundFunc\"),Kinetic.Factory.addGetter(Kinetic.Node,\"draggable\",!1),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node,\"draggable\");var b=Kinetic.document.documentElement;b.addEventListener(\"mouseup\",Kinetic.DD._endDragBefore,!0),b.addEventListener(\"touchend\",Kinetic.DD._endDragBefore,!0),b.addEventListener(\"mouseup\",Kinetic.DD._endDragAfter,!1),b.addEventListener(\"touchend\",Kinetic.DD._endDragAfter,!1)}(),function(){Kinetic.Util.addMethods(Kinetic.Container,{__init:function(a){this.children=new Kinetic.Collection,Kinetic.Node.call(this,a)},getChildren:function(a){if(a){var b=new Kinetic.Collection;return this.children.each(function(c){a(c)&&b.push(c)}),b}return this.children},hasChildren:function(){return this.getChildren().length>0},removeChildren:function(){for(var a,b=Kinetic.Collection.toCollection(this.children),c=0;c<b.length;c++)a=b[c],delete a.parent,a.index=0,a.hasChildren()&&a.removeChildren(),a.remove();return b=null,this.children=new Kinetic.Collection,this},destroyChildren:function(){for(var a,b=Kinetic.Collection.toCollection(this.children),c=0;c<b.length;c++)a=b[c],delete a.parent,a.index=0,a.destroy();return b=null,this.children=new Kinetic.Collection,this},add:function(a){if(arguments.length>1){for(var b=0;b<arguments.length;b++)this.add(arguments[b]);return this}if(a.getParent())return a.moveTo(this),this;var c=this.children;return this._validateAdd(a),a.index=c.length,a.parent=this,c.push(a),this._fire(\"add\",{child:a}),a.isDragging()&&Kinetic.DD.anim.setLayers(a.getLayer()),this},destroy:function(){this.hasChildren()&&this.destroyChildren(),Kinetic.Node.prototype.destroy.call(this)},find:function(a){var b,c,d,e,f,g,h,i=[],j=a.replace(/ /g,\"\").split(\",\"),k=j.length;for(b=0;k>b;b++)if(d=j[b],\"#\"===d.charAt(0))f=this._getNodeById(d.slice(1)),f&&i.push(f);else if(\".\"===d.charAt(0))e=this._getNodesByName(d.slice(1)),i=i.concat(e);else for(g=this.getChildren(),h=g.length,c=0;h>c;c++)i=i.concat(g[c]._get(d));return Kinetic.Collection.toCollection(i)},_getNodeById:function(a){var b=Kinetic.ids[a];return void 0!==b&&this.isAncestorOf(b)?b:null},_getNodesByName:function(a){var b=Kinetic.names[a]||[];return this._getDescendants(b)},_get:function(a){for(var b=Kinetic.Node.prototype._get.call(this,a),c=this.getChildren(),d=c.length,e=0;d>e;e++)b=b.concat(c[e]._get(a));return b},toObject:function(){var a=Kinetic.Node.prototype.toObject.call(this);\n    a.children=[];for(var b=this.getChildren(),c=b.length,d=0;c>d;d++){var e=b[d];a.children.push(e.toObject())}return a},_getDescendants:function(a){for(var b=[],c=a.length,d=0;c>d;d++){var e=a[d];this.isAncestorOf(e)&&b.push(e)}return b},isAncestorOf:function(a){for(var b=a.getParent();b;){if(b._id===this._id)return!0;b=b.getParent()}return!1},clone:function(a){var b=Kinetic.Node.prototype.clone.call(this,a);return this.getChildren().each(function(a){b.add(a.clone())}),b},getAllIntersections:function(a){var b=[];return this.find(\"Shape\").each(function(c){c.isVisible()&&c.intersects(a)&&b.push(c)}),b},_setChildrenIndices:function(){this.children.each(function(a,b){a.index=b})},drawScene:function(a,b){var c=this.getLayer(),d=a||c&&c.getCanvas(),e=d&&d.getContext(),f=this._cache.canvas,g=f&&f.scene;return this.isVisible()&&(g?this._drawCachedSceneCanvas(e):this._drawChildren(d,\"drawScene\",b)),this},drawHit:function(a,b){var c=this.getLayer(),d=a||c&&c.hitCanvas,e=d&&d.getContext(),f=this._cache.canvas,g=f&&f.hit;return this.shouldDrawHit(d)&&(c&&c.clearHitCache(),g?this._drawCachedHitCanvas(e):this._drawChildren(d,\"drawHit\",b)),this},_drawChildren:function(a,b,c){var d,e,f=this.getLayer(),g=a&&a.getContext(),h=this.getClipWidth(),i=this.getClipHeight(),j=h&&i;j&&f&&(d=this.getClipX(),e=this.getClipY(),g.save(),f._applyTransform(this,g),g.beginPath(),g.rect(d,e,h,i),g.clip(),g.reset()),this.children.each(function(d){d[b](a,c)}),j&&g.restore()},shouldDrawHit:function(a){var b=this.getLayer(),c=Kinetic.DD,d=c&&Kinetic.isDragging()&&-1!==Kinetic.DD.anim.getLayers().indexOf(b);return a&&a.isCache||b&&b.hitGraphEnabled()&&this.isVisible()&&!d}}),Kinetic.Util.extend(Kinetic.Container,Kinetic.Node),Kinetic.Container.prototype.get=Kinetic.Container.prototype.find,Kinetic.Factory.addComponentsGetterSetter(Kinetic.Container,\"clip\",[\"x\",\"y\",\"width\",\"height\"]),Kinetic.Factory.addGetterSetter(Kinetic.Container,\"clipX\"),Kinetic.Factory.addGetterSetter(Kinetic.Container,\"clipY\"),Kinetic.Factory.addGetterSetter(Kinetic.Container,\"clipWidth\"),Kinetic.Factory.addGetterSetter(Kinetic.Container,\"clipHeight\"),Kinetic.Collection.mapMethods(Kinetic.Container)}(),function(){function a(a){a.fill()}function b(a){a.stroke()}function c(a){a.fill()}function d(a){a.stroke()}function e(){this._clearCache(f)}var f=\"hasShadow\";Kinetic.Util.addMethods(Kinetic.Shape,{__init:function(f){this.nodeType=\"Shape\",this._fillFunc=a,this._strokeFunc=b,this._fillFuncHit=c,this._strokeFuncHit=d;for(var g,h=Kinetic.shapes;;)if(g=Kinetic.Util.getRandomColor(),g&&!(g in h))break;this.colorKey=g,h[g]=this,Kinetic.Node.call(this,f),this.on(\"shadowColorChange.kinetic shadowBlurChange.kinetic shadowOffsetChange.kinetic shadowOpacityChange.kinetic shadowEnabledChange.kinetic\",e)},hasChildren:function(){return!1},getChildren:function(){return[]},getContext:function(){return this.getLayer().getContext()},getCanvas:function(){return this.getLayer().getCanvas()},hasShadow:function(){return this._getCache(f,this._hasShadow)},_hasShadow:function(){return this.getShadowEnabled()&&0!==this.getShadowOpacity()&&!!(this.getShadowColor()||this.getShadowBlur()||this.getShadowOffsetX()||this.getShadowOffsetY())},hasFill:function(){return!!(this.getFill()||this.getFillPatternImage()||this.getFillLinearGradientColorStops()||this.getFillRadialGradientColorStops())},hasStroke:function(){return!!(this.stroke()||this.strokeRed()||this.strokeGreen()||this.strokeBlue())},intersects:function(a){var b,c=this.getStage(),d=c.bufferHitCanvas;return d.getContext().clear(),this.drawScene(d),b=d.context.getImageData(Math.round(a.x),Math.round(a.y),1,1).data,b[3]>0},destroy:function(){Kinetic.Node.prototype.destroy.call(this),delete Kinetic.shapes[this.colorKey]},_useBufferCanvas:function(){return(this.hasShadow()||1!==this.getAbsoluteOpacity())&&this.hasFill()&&this.hasStroke()&&this.getStage()},drawScene:function(a,b){var c,d,e,f=this.getLayer(),g=a||f.getCanvas(),h=g.getContext(),i=this._cache.canvas,j=this.sceneFunc(),k=this.hasShadow();if(this.isVisible())if(i)this._drawCachedSceneCanvas(h);else if(j){if(h.save(),this._useBufferCanvas()){if(c=this.getStage(),d=c.bufferCanvas,e=d.getContext(),e.clear(),e.save(),e._applyLineJoin(this),f)f._applyTransform(this,e,b);else{var l=this.getAbsoluteTransform(b).getMatrix();h.transform(l[0],l[1],l[2],l[3],l[4],l[5])}j.call(this,e),e.restore(),k&&!g.hitCanvas&&(h.save(),h._applyShadow(this),h.drawImage(d._canvas,0,0),h.restore()),h._applyOpacity(this),h.drawImage(d._canvas,0,0)}else{if(h._applyLineJoin(this),f)f._applyTransform(this,h,b);else{var m=this.getAbsoluteTransform(b).getMatrix();h.transform(m[0],m[1],m[2],m[3],m[4],m[5])}k&&!g.hitCanvas&&(h.save(),h._applyShadow(this),j.call(this,h),h.restore()),h._applyOpacity(this),j.call(this,h)}h.restore()}return this},drawHit:function(a,b){var c=this.getLayer(),d=a||c.hitCanvas,e=d.getContext(),f=this.hitFunc()||this.sceneFunc(),g=this._cache.canvas,h=g&&g.hit;if(this.shouldDrawHit(d))if(c&&c.clearHitCache(),h)this._drawCachedHitCanvas(e);else if(f){if(e.save(),e._applyLineJoin(this),c)c._applyTransform(this,e,b);else{var i=this.getAbsoluteTransform(b).getMatrix();e.transform(i[0],i[1],i[2],i[3],i[4],i[5])}f.call(this,e),e.restore()}return this},drawHitFromCache:function(a){var b,c,d,e,f,g,h,i,j=a||0,k=this._cache.canvas,l=this._getCachedSceneCanvas(),m=l.getContext(),n=k.hit,o=n.getContext(),p=l.getWidth(),q=l.getHeight();o.clear();try{for(b=m.getImageData(0,0,p,q),c=b.data,d=o.getImageData(0,0,p,q),e=d.data,f=c.length,g=Kinetic.Util._hexToRgb(this.colorKey),h=0;f>h;h+=4)i=c[h+3],i>j&&(e[h]=g.r,e[h+1]=g.g,e[h+2]=g.b,e[h+3]=255);o.putImageData(d,0,0)}catch(r){Kinetic.Util.warn(\"Unable to draw hit graph from cached scene canvas. \"+r.message)}return this}}),Kinetic.Util.extend(Kinetic.Shape,Kinetic.Node),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"stroke\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeRed\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeGreen\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeBlue\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeAlpha\",1,Kinetic.Validators.alphaComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeWidth\",2),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"lineJoin\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"lineCap\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"sceneFunc\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"hitFunc\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"dash\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowColor\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowRed\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowGreen\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowBlue\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowAlpha\",1,Kinetic.Validators.alphaComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowBlur\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowOpacity\"),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"shadowOffset\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowOffsetX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowOffsetY\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternImage\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fill\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRed\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillGreen\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillBlue\",0,Kinetic.Validators.RGBComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillAlpha\",1,Kinetic.Validators.alphaComponent),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternY\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillLinearGradientColorStops\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientStartRadius\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientEndRadius\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientColorStops\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternRepeat\",\"repeat\"),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillEnabled\",!0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeEnabled\",!0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"shadowEnabled\",!0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"dashEnabled\",!0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"strokeScaleEnabled\",!0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPriority\",\"color\"),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"fillPatternOffset\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternOffsetX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternOffsetY\",0),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"fillPatternScale\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternScaleX\",1),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternScaleY\",1),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"fillLinearGradientStartPoint\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillLinearGradientStartPointX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillLinearGradientStartPointY\",0),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"fillLinearGradientEndPoint\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillLinearGradientEndPointX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillLinearGradientEndPointY\",0),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"fillRadialGradientStartPoint\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientStartPointX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientStartPointY\",0),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Shape,\"fillRadialGradientEndPoint\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientEndPointX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillRadialGradientEndPointY\",0),Kinetic.Factory.addGetterSetter(Kinetic.Shape,\"fillPatternRotation\",0),Kinetic.Factory.backCompat(Kinetic.Shape,{dashArray:\"dash\",getDashArray:\"getDash\",setDashArray:\"getDash\",drawFunc:\"sceneFunc\",getDrawFunc:\"getSceneFunc\",setDrawFunc:\"setSceneFunc\",drawHitFunc:\"hitFunc\",getDrawHitFunc:\"getHitFunc\",setDrawHitFunc:\"setHitFunc\"}),Kinetic.Collection.mapMethods(Kinetic.Shape)}(),function(){function a(a,b){a.content.addEventListener(b,function(c){a[L+b](c)},!1)}var b=\"Stage\",c=\"string\",d=\"px\",e=\"mouseout\",f=\"mouseleave\",g=\"mouseover\",h=\"mouseenter\",i=\"mousemove\",j=\"mousedown\",k=\"mouseup\",l=\"click\",m=\"dblclick\",n=\"touchstart\",o=\"touchend\",p=\"tap\",q=\"dbltap\",r=\"touchmove\",s=\"DOMMouseScroll\",t=\"mousewheel\",u=\"wheel\",v=\"contentMouseout\",w=\"contentMouseover\",x=\"contentMousemove\",y=\"contentMousedown\",z=\"contentMouseup\",A=\"contentClick\",B=\"contentDblclick\",C=\"contentTouchstart\",D=\"contentTouchend\",E=\"contentDbltap\",F=\"contentTouchmove\",G=\"div\",H=\"relative\",I=\"inline-block\",J=\"kineticjs-content\",K=\" \",L=\"_\",M=\"container\",N=\"\",O=[j,i,k,e,n,r,o,g,s,t,u],P=O.length;Kinetic.Util.addMethods(Kinetic.Stage,{___init:function(a){this.nodeType=b,Kinetic.Container.call(this,a),this._id=Kinetic.idCounter++,this._buildDOM(),this._bindContentEvents(),this._enableNestedTransforms=!1,Kinetic.stages.push(this)},_validateAdd:function(a){\"Layer\"!==a.getType()&&Kinetic.Util.error(\"You may only add layers to the stage.\")},setContainer:function(a){if(typeof a===c){var b=a;if(a=Kinetic.document.getElementById(a),!a)throw\"Can not find container in document with id \"+b}return this._setAttr(M,a),this},shouldDrawHit:function(){return!0},draw:function(){return Kinetic.Node.prototype.draw.call(this),this},setHeight:function(a){return Kinetic.Node.prototype.setHeight.call(this,a),this._resizeDOM(),this},setWidth:function(a){return Kinetic.Node.prototype.setWidth.call(this,a),this._resizeDOM(),this},clear:function(){var a,b=this.children,c=b.length;for(a=0;c>a;a++)b[a].clear();return this},clone:function(a){return a||(a={}),a.container=Kinetic.document.createElement(G),Kinetic.Container.prototype.clone.call(this,a)},destroy:function(){var a=this.content;Kinetic.Container.prototype.destroy.call(this),a&&Kinetic.Util._isInDocument(a)&&this.getContainer().removeChild(a);var b=Kinetic.stages.indexOf(this);b>-1&&Kinetic.stages.splice(b,1)},getPointerPosition:function(){return this.pointerPos},getStage:function(){return this},getContent:function(){return this.content},toDataURL:function(a){function b(e){var f=i[e],j=f.toDataURL(),k=new Kinetic.window.Image;k.onload=function(){h.drawImage(k,0,0),e<i.length-1?b(e+1):a.callback(g.toDataURL(c,d))},k.src=j}a=a||{};var c=a.mimeType||null,d=a.quality||null,e=a.x||0,f=a.y||0,g=new Kinetic.SceneCanvas({width:a.width||this.getWidth(),height:a.height||this.getHeight(),pixelRatio:1}),h=g.getContext()._context,i=this.children;(e||f)&&h.translate(-1*e,-1*f),b(0)},toImage:function(a){var b=a.callback;a.callback=function(a){Kinetic.Util._getImage(a,function(a){b(a)})},this.toDataURL(a)},getIntersection:function(a){var b,c,d=this.getChildren(),e=d.length,f=e-1;for(b=f;b>=0;b--)if(c=d[b].getIntersection(a))return c;return null},_resizeDOM:function(){if(this.content){var a,b,c=this.getWidth(),e=this.getHeight(),f=this.getChildren(),g=f.length;for(this.content.style.width=c+d,this.content.style.height=e+d,this.bufferCanvas.setSize(c,e),this.bufferHitCanvas.setSize(c,e),a=0;g>a;a++)b=f[a],b.setSize(c,e),b.draw()}},add:function(a){if(!(arguments.length>1))return Kinetic.Container.prototype.add.call(this,a),a._setCanvasSize(this.width(),this.height()),a.draw(),this.content.appendChild(a.canvas._canvas),this;for(var b=0;b<arguments.length;b++)this.add(arguments[b])},getParent:function(){return null},getLayer:function(){return null},getLayers:function(){return this.getChildren()},_bindContentEvents:function(){for(var b=0;P>b;b++)a(this,O[b])},_mouseover:function(a){Kinetic.UA.mobile||(this._setPointerPosition(a),this._fire(w,{evt:a}))},_mouseout:function(a){if(!Kinetic.UA.mobile){this._setPointerPosition(a);var b=this.targetShape;b&&!Kinetic.isDragging()&&(b._fireAndBubble(e,{evt:a}),b._fireAndBubble(f,{evt:a}),this.targetShape=null),this.pointerPos=void 0,this._fire(v,{evt:a})}},_mousemove:function(a){if(Kinetic.UA.ieMobile)return this._touchmove(a);if((\"undefined\"==typeof a.webkitMovementX&&\"undefined\"==typeof a.webkitMovementY||0!==a.webkitMovementY||0!==a.webkitMovementX)&&!Kinetic.UA.mobile){this._setPointerPosition(a);var b,c=Kinetic.DD;Kinetic.isDragging()||(b=this.getIntersection(this.getPointerPosition()),b&&b.isListening()?Kinetic.isDragging()||this.targetShape&&this.targetShape._id===b._id?b._fireAndBubble(i,{evt:a}):(this.targetShape&&(this.targetShape._fireAndBubble(e,{evt:a},b),this.targetShape._fireAndBubble(f,{evt:a},b)),b._fireAndBubble(g,{evt:a},this.targetShape),b._fireAndBubble(h,{evt:a},this.targetShape),this.targetShape=b):this.targetShape&&!Kinetic.isDragging()&&(this.targetShape._fireAndBubble(e,{evt:a}),this.targetShape._fireAndBubble(f,{evt:a}),this.targetShape=null),this._fire(x,{evt:a})),c&&c._drag(a),a.preventDefault&&a.preventDefault()}},_mousedown:function(a){if(Kinetic.UA.ieMobile)return this._touchstart(a);if(!Kinetic.UA.mobile){this._setPointerPosition(a);var b=this.getIntersection(this.getPointerPosition());Kinetic.listenClickTap=!0,b&&b.isListening()&&(this.clickStartShape=b,b._fireAndBubble(j,{evt:a})),this._fire(y,{evt:a})}a.preventDefault&&a.preventDefault()},_mouseup:function(a){if(Kinetic.UA.ieMobile)return this._touchend(a);if(!Kinetic.UA.mobile){this._setPointerPosition(a);var b=this.getIntersection(this.getPointerPosition()),c=this.clickStartShape,d=!1,e=Kinetic.DD;Kinetic.inDblClickWindow?(d=!0,Kinetic.inDblClickWindow=!1):e&&e.justDragged?e&&(e.justDragged=!1):Kinetic.inDblClickWindow=!0,setTimeout(function(){Kinetic.inDblClickWindow=!1},Kinetic.dblClickWindow),b&&b.isListening()&&(b._fireAndBubble(k,{evt:a}),Kinetic.listenClickTap&&c&&c._id===b._id&&(b._fireAndBubble(l,{evt:a}),d&&b._fireAndBubble(m,{evt:a}))),this._fire(z,{evt:a}),Kinetic.listenClickTap&&(this._fire(A,{evt:a}),d&&this._fire(B,{evt:a})),Kinetic.listenClickTap=!1}a.preventDefault&&a.preventDefault()},_touchstart:function(a){this._setPointerPosition(a);var b=this.getIntersection(this.getPointerPosition());Kinetic.listenClickTap=!0,b&&b.isListening()&&(this.tapStartShape=b,b._fireAndBubble(n,{evt:a}),b.isListening()&&a.preventDefault&&a.preventDefault()),this._fire(C,{evt:a})},_touchend:function(a){this._setPointerPosition(a);var b=this.getIntersection(this.getPointerPosition()),c=!1;Kinetic.inDblClickWindow?(c=!0,Kinetic.inDblClickWindow=!1):Kinetic.inDblClickWindow=!0,setTimeout(function(){Kinetic.inDblClickWindow=!1},Kinetic.dblClickWindow),b&&b.isListening()&&(b._fireAndBubble(o,{evt:a}),Kinetic.listenClickTap&&b._id===this.tapStartShape._id&&(b._fireAndBubble(p,{evt:a}),c&&b._fireAndBubble(q,{evt:a})),b.isListening()&&a.preventDefault&&a.preventDefault()),Kinetic.listenClickTap&&(this._fire(D,{evt:a}),c&&this._fire(E,{evt:a})),Kinetic.listenClickTap=!1},_touchmove:function(a){this._setPointerPosition(a);var b,c=Kinetic.DD;Kinetic.isDragging()||(b=this.getIntersection(this.getPointerPosition()),b&&b.isListening()&&(b._fireAndBubble(r,{evt:a}),b.isListening()&&a.preventDefault&&a.preventDefault()),this._fire(F,{evt:a})),c&&(c._drag(a),Kinetic.isDragging()&&a.preventDefault())},_DOMMouseScroll:function(a){this._mousewheel(a)},_mousewheel:function(a){this._setPointerPosition(a);var b=this.getIntersection(this.getPointerPosition());b&&b.isListening()&&b._fireAndBubble(t,{evt:a})},_wheel:function(a){this._mousewheel(a)},_setPointerPosition:function(a){var b,c=this._getContentPosition(),d=a.offsetX,e=a.clientX,f=null,g=null;a=a?a:window.event,void 0!==a.touches?a.touches.length>0&&(b=a.touches[0],f=b.clientX-c.left,g=b.clientY-c.top):void 0!==d?(f=d,g=a.offsetY):\"mozilla\"===Kinetic.UA.browser?(f=a.layerX,g=a.layerY):void 0!==e&&c&&(f=e-c.left,g=a.clientY-c.top),null!==f&&null!==g&&(this.pointerPos={x:f,y:g})},_getContentPosition:function(){var a=this.content.getBoundingClientRect?this.content.getBoundingClientRect():{top:0,left:0};return{top:a.top,left:a.left}},_buildDOM:function(){var a=this.getContainer();if(!a){if(Kinetic.Util.isBrowser())throw\"Stage has no container. A container is required.\";a=Kinetic.document.createElement(G)}a.innerHTML=N,this.content=Kinetic.document.createElement(G),this.content.style.position=H,this.content.style.display=I,this.content.className=J,this.content.setAttribute(\"role\",\"presentation\"),a.appendChild(this.content),this.bufferCanvas=new Kinetic.SceneCanvas({pixelRatio:1}),this.bufferHitCanvas=new Kinetic.HitCanvas,this._resizeDOM()},_onContent:function(a,b){var c,d,e=a.split(K),f=e.length;for(c=0;f>c;c++)d=e[c],this.content.addEventListener(d,b,!1)},cache:function(){Kinetic.Util.warn(\"Cache function is not allowed for stage. You may use cache only for layers, groups and shapes.\")},clearCache:function(){}}),Kinetic.Util.extend(Kinetic.Stage,Kinetic.Container),Kinetic.Factory.addGetter(Kinetic.Stage,\"container\"),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Stage,\"container\")}(),function(){Kinetic.Util.addMethods(Kinetic.BaseLayer,{___init:function(a){this.nodeType=\"Layer\",Kinetic.Container.call(this,a)},createPNGStream:function(){return this.canvas._canvas.createPNGStream()},getCanvas:function(){return this.canvas},getHitCanvas:function(){return this.hitCanvas},getContext:function(){return this.getCanvas().getContext()},clear:function(a){return this.getContext().clear(a),this.getHitCanvas().getContext().clear(a),this},clearHitCache:function(){this._hitImageData=void 0},setZIndex:function(a){Kinetic.Node.prototype.setZIndex.call(this,a);var b=this.getStage();return b&&(b.content.removeChild(this.getCanvas()._canvas),a<b.getChildren().length-1?b.content.insertBefore(this.getCanvas()._canvas,b.getChildren()[a+1].getCanvas()._canvas):b.content.appendChild(this.getCanvas()._canvas)),this},moveToTop:function(){Kinetic.Node.prototype.moveToTop.call(this);var a=this.getStage();a&&(a.content.removeChild(this.getCanvas()._canvas),a.content.appendChild(this.getCanvas()._canvas))},moveUp:function(){if(Kinetic.Node.prototype.moveUp.call(this)){var a=this.getStage();a&&(a.content.removeChild(this.getCanvas()._canvas),this.index<a.getChildren().length-1?a.content.insertBefore(this.getCanvas()._canvas,a.getChildren()[this.index+1].getCanvas()._canvas):a.content.appendChild(this.getCanvas()._canvas))}},moveDown:function(){if(Kinetic.Node.prototype.moveDown.call(this)){var a=this.getStage();if(a){var b=a.getChildren();a.content.removeChild(this.getCanvas()._canvas),a.content.insertBefore(this.getCanvas()._canvas,b[this.index+1].getCanvas()._canvas)}}},moveToBottom:function(){if(Kinetic.Node.prototype.moveToBottom.call(this)){var a=this.getStage();if(a){var b=a.getChildren();a.content.removeChild(this.getCanvas()._canvas),a.content.insertBefore(this.getCanvas()._canvas,b[1].getCanvas()._canvas)}}},getLayer:function(){return this},remove:function(){var a=this.getCanvas()._canvas;return Kinetic.Node.prototype.remove.call(this),a&&a.parentNode&&Kinetic.Util._isInDocument(a)&&a.parentNode.removeChild(a),this},getStage:function(){return this.parent},setSize:function(a,b){this.canvas.setSize(a,b)},getWidth:function(){return this.parent?this.parent.getWidth():void 0},setWidth:function(){Kinetic.Util.warn('Can not change width of layer. Use \"stage.width(value)\" function instead.')},getHeight:function(){return this.parent?this.parent.getHeight():void 0},setHeight:function(){Kinetic.Util.warn('Can not change height of layer. Use \"stage.height(value)\" function instead.')}}),Kinetic.Util.extend(Kinetic.BaseLayer,Kinetic.Container),Kinetic.Factory.addGetterSetter(Kinetic.BaseLayer,\"clearBeforeDraw\",!0),Kinetic.Collection.mapMethods(Kinetic.BaseLayer)}(),function(){var a=\"#\",b=\"beforeDraw\",c=\"draw\",d=[{x:0,y:0},{x:-1,y:0},{x:-1,y:-1},{x:0,y:-1},{x:1,y:-1},{x:1,y:0},{x:1,y:1},{x:0,y:1},{x:-1,y:1}],e=d.length;Kinetic.Util.addMethods(Kinetic.Layer,{____init:function(a){this.nodeType=\"Layer\",this.canvas=new Kinetic.SceneCanvas,this.hitCanvas=new Kinetic.HitCanvas,Kinetic.BaseLayer.call(this,a)},_setCanvasSize:function(a,b){this.canvas.setSize(a,b),this.hitCanvas.setSize(a,b)},_validateAdd:function(a){var b=a.getType();\"Group\"!==b&&\"Shape\"!==b&&Kinetic.Util.error(\"You may only add groups and shapes to a layer.\")},getIntersection:function(a){var b,c,f,g;if(!this.hitGraphEnabled()||!this.isVisible())return null;for(var h=1,i=!1;;){for(c=0;e>c;c++){if(f=d[c],b=this._getIntersection({x:a.x+f.x*h,y:a.y+f.y*h}),g=b.shape)return g;b.antialiased&&(i=!0)}if(!i)return;h+=1}},_getImageData:function(a,b){var c=this.hitCanvas.width||1,d=this.hitCanvas.height||1,e=Math.round(b)*c+Math.round(a);return this._hitImageData||(this._hitImageData=this.hitCanvas.context.getImageData(0,0,c,d)),[this._hitImageData.data[4*e+0],this._hitImageData.data[4*e+1],this._hitImageData.data[4*e+2],this._hitImageData.data[4*e+3]]},_getIntersection:function(b){var c,d,e=this.hitCanvas.context.getImageData(b.x,b.y,1,1).data,f=e[3];return 255===f?(c=Kinetic.Util._rgbToHex(e[0],e[1],e[2]),d=Kinetic.shapes[a+c],{shape:d}):f>0?{antialiased:!0}:{}},drawScene:function(a,d){var e=this.getLayer(),f=a||e&&e.getCanvas();return this._fire(b,{node:this}),this.getClearBeforeDraw()&&f.getContext().clear(),Kinetic.Container.prototype.drawScene.call(this,f,d),this._fire(c,{node:this}),this},_applyTransform:function(a,b,c){var d=a.getAbsoluteTransform(c).getMatrix();b.transform(d[0],d[1],d[2],d[3],d[4],d[5])},drawHit:function(a,b){var c=this.getLayer(),d=a||c&&c.hitCanvas;return c&&c.getClearBeforeDraw()&&c.getHitCanvas().getContext().clear(),Kinetic.Container.prototype.drawHit.call(this,d,b),this.imageData=null,this},clear:function(a){return this.getContext().clear(a),this.getHitCanvas().getContext().clear(a),this.imageData=null,this},setVisible:function(a){return Kinetic.Node.prototype.setVisible.call(this,a),a?(this.getCanvas()._canvas.style.display=\"block\",this.hitCanvas._canvas.style.display=\"block\"):(this.getCanvas()._canvas.style.display=\"none\",this.hitCanvas._canvas.style.display=\"none\"),this},enableHitGraph:function(){return this.setHitGraphEnabled(!0),this},disableHitGraph:function(){return this.setHitGraphEnabled(!1),this},setSize:function(a,b){Kinetic.BaseLayer.prototype.setSize.call(this,a,b),this.hitCanvas.setSize(a,b)}}),Kinetic.Util.extend(Kinetic.Layer,Kinetic.BaseLayer),Kinetic.Factory.addGetterSetter(Kinetic.Layer,\"hitGraphEnabled\",!0),Kinetic.Collection.mapMethods(Kinetic.Layer)}(),function(){Kinetic.Util.addMethods(Kinetic.FastLayer,{____init:function(a){this.nodeType=\"Layer\",this.canvas=new Kinetic.SceneCanvas,Kinetic.BaseLayer.call(this,a)},_validateAdd:function(a){var b=a.getType();\"Shape\"!==b&&Kinetic.Util.error(\"You may only add shapes to a fast layer.\")},_setCanvasSize:function(a,b){this.canvas.setSize(a,b)},hitGraphEnabled:function(){return!1},getIntersection:function(){return null},drawScene:function(a){var b=this.getLayer(),c=a||b&&b.getCanvas();return this.getClearBeforeDraw()&&c.getContext().clear(),Kinetic.Container.prototype.drawScene.call(this,c),this},_applyTransform:function(a,b,c){if(!c||c._id!==this._id){var d=a.getTransform().getMatrix();b.transform(d[0],d[1],d[2],d[3],d[4],d[5])}},draw:function(){return this.drawScene(),this},clear:function(a){return this.getContext().clear(a),this},setVisible:function(a){return Kinetic.Node.prototype.setVisible.call(this,a),this.getCanvas()._canvas.style.display=a?\"block\":\"none\",this}}),Kinetic.Util.extend(Kinetic.FastLayer,Kinetic.BaseLayer),Kinetic.Collection.mapMethods(Kinetic.FastLayer)}(),function(){Kinetic.Util.addMethods(Kinetic.Group,{___init:function(a){this.nodeType=\"Group\",Kinetic.Container.call(this,a)},_validateAdd:function(a){var b=a.getType();\"Group\"!==b&&\"Shape\"!==b&&Kinetic.Util.error(\"You may only add groups and shapes to groups.\")}}),Kinetic.Util.extend(Kinetic.Group,Kinetic.Container),Kinetic.Collection.mapMethods(Kinetic.Group)}(),function(){Kinetic.Rect=function(a){this.___init(a)},Kinetic.Rect.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Rect\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b=this.getCornerRadius(),c=this.getWidth(),d=this.getHeight();a.beginPath(),b?(a.moveTo(b,0),a.lineTo(c-b,0),a.arc(c-b,b,b,3*Math.PI/2,0,!1),a.lineTo(c,d-b),a.arc(c-b,d-b,b,0,Math.PI/2,!1),a.lineTo(b,d),a.arc(b,d-b,b,Math.PI/2,Math.PI,!1),a.lineTo(0,b),a.arc(b,b,b,Math.PI,3*Math.PI/2,!1)):a.rect(0,0,c,d),a.closePath(),a.fillStrokeShape(this)}},Kinetic.Util.extend(Kinetic.Rect,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Rect,\"cornerRadius\",0),Kinetic.Collection.mapMethods(Kinetic.Rect)}(),function(){var a=2*Math.PI-1e-4,b=\"Circle\";Kinetic.Circle=function(a){this.___init(a)},Kinetic.Circle.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=b,this.sceneFunc(this._sceneFunc)},_sceneFunc:function(b){b.beginPath(),b.arc(0,0,this.getRadius(),0,a,!1),b.closePath(),b.fillStrokeShape(this)},getWidth:function(){return 2*this.getRadius()},getHeight:function(){return 2*this.getRadius()},setWidth:function(a){Kinetic.Node.prototype.setWidth.call(this,a),this.radius()!==a/2&&this.setRadius(a/2)},setHeight:function(a){Kinetic.Node.prototype.setHeight.call(this,a),this.radius()!==a/2&&this.setRadius(a/2)},setRadius:function(a){this._setAttr(\"radius\",a),this.setWidth(2*a),this.setHeight(2*a)}},Kinetic.Util.extend(Kinetic.Circle,Kinetic.Shape),Kinetic.Factory.addGetter(Kinetic.Circle,\"radius\",0),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Circle,\"radius\"),Kinetic.Collection.mapMethods(Kinetic.Circle)}(),function(){var a=2*Math.PI-1e-4,b=\"Ellipse\";Kinetic.Ellipse=function(a){this.___init(a)},Kinetic.Ellipse.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=b,this.sceneFunc(this._sceneFunc)},_sceneFunc:function(b){var c=this.getRadiusX(),d=this.getRadiusY();b.beginPath(),b.save(),c!==d&&b.scale(1,d/c),b.arc(0,0,c,0,a,!1),b.restore(),b.closePath(),b.fillStrokeShape(this)},getWidth:function(){return 2*this.getRadiusX()},getHeight:function(){return 2*this.getRadiusY()},setWidth:function(a){Kinetic.Node.prototype.setWidth.call(this,a),this.setRadius({x:a/2})},setHeight:function(a){Kinetic.Node.prototype.setHeight.call(this,a),this.setRadius({y:a/2})}},Kinetic.Util.extend(Kinetic.Ellipse,Kinetic.Shape),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Ellipse,\"radius\",[\"x\",\"y\"]),Kinetic.Factory.addGetterSetter(Kinetic.Ellipse,\"radiusX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Ellipse,\"radiusY\",0),Kinetic.Collection.mapMethods(Kinetic.Ellipse)}(),function(){var a=2*Math.PI-1e-4;Kinetic.Ring=function(a){this.___init(a)},Kinetic.Ring.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Ring\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(b){b.beginPath(),b.arc(0,0,this.getInnerRadius(),0,a,!1),b.moveTo(this.getOuterRadius(),0),b.arc(0,0,this.getOuterRadius(),a,0,!0),b.closePath(),b.fillStrokeShape(this)},getWidth:function(){return 2*this.getOuterRadius()},getHeight:function(){return 2*this.getOuterRadius()},setWidth:function(a){Kinetic.Node.prototype.setWidth.call(this,a),this.outerRadius()!==a/2&&this.setOuterRadius(a/2)},setHeight:function(a){Kinetic.Node.prototype.setHeight.call(this,a),this.outerRadius()!==a/2&&this.setOuterRadius(a/2)},setOuterRadius:function(a){this._setAttr(\"outerRadius\",a),this.setWidth(2*a),this.setHeight(2*a)}},Kinetic.Util.extend(Kinetic.Ring,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Ring,\"innerRadius\",0),Kinetic.Factory.addGetter(Kinetic.Ring,\"outerRadius\",0),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Ring,\"outerRadius\"),Kinetic.Collection.mapMethods(Kinetic.Ring)}(),function(){Kinetic.Wedge=function(a){this.___init(a)},Kinetic.Wedge.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Wedge\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){a.beginPath(),a.arc(0,0,this.getRadius(),0,Kinetic.getAngle(this.getAngle()),this.getClockwise()),a.lineTo(0,0),a.closePath(),a.fillStrokeShape(this)}},Kinetic.Util.extend(Kinetic.Wedge,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Wedge,\"radius\",0),Kinetic.Factory.addGetterSetter(Kinetic.Wedge,\"angle\",0),Kinetic.Factory.addGetterSetter(Kinetic.Wedge,\"clockwise\",!1),Kinetic.Factory.backCompat(Kinetic.Wedge,{angleDeg:\"angle\",getAngleDeg:\"getAngle\",setAngleDeg:\"setAngle\"}),Kinetic.Collection.mapMethods(Kinetic.Wedge)}(),function(){Kinetic.Arc=function(a){this.___init(a)},Kinetic.Arc.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Arc\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b=Kinetic.getAngle(this.angle()),c=this.clockwise();a.beginPath(),a.arc(0,0,this.getOuterRadius(),0,b,c),a.arc(0,0,this.getInnerRadius(),b,0,!c),a.closePath(),a.fillStrokeShape(this)}},Kinetic.Util.extend(Kinetic.Arc,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Arc,\"innerRadius\",0),Kinetic.Factory.addGetterSetter(Kinetic.Arc,\"outerRadius\",0),Kinetic.Factory.addGetterSetter(Kinetic.Arc,\"angle\",0),Kinetic.Factory.addGetterSetter(Kinetic.Arc,\"clockwise\",!1),Kinetic.Collection.mapMethods(Kinetic.Arc)}(),function(){var a=\"Image\";Kinetic.Image=function(a){this.___init(a)},Kinetic.Image.prototype={___init:function(b){Kinetic.Shape.call(this,b),this.className=a,this.sceneFunc(this._sceneFunc),this.hitFunc(this._hitFunc)},_useBufferCanvas:function(){return(this.hasShadow()||1!==this.getAbsoluteOpacity())&&this.hasStroke()&&this.getStage()},_sceneFunc:function(a){var b,c,d,e=this.getWidth(),f=this.getHeight(),g=this.getImage();g&&(b=this.getCropWidth(),c=this.getCropHeight(),d=b&&c?[g,this.getCropX(),this.getCropY(),b,c,0,0,e,f]:[g,0,0,e,f]),(this.hasFill()||this.hasStroke()||this.hasShadow())&&(a.beginPath(),a.rect(0,0,e,f),a.closePath(),a.fillStrokeShape(this)),g&&a.drawImage.apply(a,d)\n},_hitFunc:function(a){var b=this.getWidth(),c=this.getHeight();a.beginPath(),a.rect(0,0,b,c),a.closePath(),a.fillStrokeShape(this)},getWidth:function(){var a=this.getImage();return this.attrs.width||(a?a.width:0)},getHeight:function(){var a=this.getImage();return this.attrs.height||(a?a.height:0)}},Kinetic.Util.extend(Kinetic.Image,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Image,\"image\"),Kinetic.Factory.addComponentsGetterSetter(Kinetic.Image,\"crop\",[\"x\",\"y\",\"width\",\"height\"]),Kinetic.Factory.addGetterSetter(Kinetic.Image,\"cropX\",0),Kinetic.Factory.addGetterSetter(Kinetic.Image,\"cropY\",0),Kinetic.Factory.addGetterSetter(Kinetic.Image,\"cropWidth\",0),Kinetic.Factory.addGetterSetter(Kinetic.Image,\"cropHeight\",0),Kinetic.Collection.mapMethods(Kinetic.Image)}(),function(){function a(a){a.fillText(this.partialText,0,0)}function b(a){a.strokeText(this.partialText,0,0)}var c=\"auto\",d=\"center\",e=\"Change.kinetic\",f=\"2d\",g=\"-\",h=\"\",i=\"left\",j=\"text\",k=\"Text\",l=\"middle\",m=\"normal\",n=\"px \",o=\" \",p=\"right\",q=\"word\",r=\"char\",s=\"none\",t=[\"fontFamily\",\"fontSize\",\"fontStyle\",\"fontVariant\",\"padding\",\"align\",\"lineHeight\",\"text\",\"width\",\"height\",\"wrap\"],u=t.length,v=Kinetic.Util.createCanvasElement().getContext(f);Kinetic.Text=function(a){this.___init(a)},Kinetic.Text.prototype={___init:function(d){d=d||{},d.fill=d.fill||\"black\",void 0===d.width&&(d.width=c),void 0===d.height&&(d.height=c),Kinetic.Shape.call(this,d),this._fillFunc=a,this._strokeFunc=b,this.className=k;for(var f=0;u>f;f++)this.on(t[f]+e,this._setTextData);this._setTextData(),this.sceneFunc(this._sceneFunc),this.hitFunc(this._hitFunc)},_sceneFunc:function(a){var b,c=this.getPadding(),e=this.getTextHeight(),f=this.getLineHeight()*e,g=this.textArr,h=g.length,j=this.getWidth();for(a.setAttr(\"font\",this._getContextFont()),a.setAttr(\"textBaseline\",l),a.setAttr(\"textAlign\",i),a.save(),a.translate(c,0),a.translate(0,c+e/2),b=0;h>b;b++){var k=g[b],m=k.text,n=k.width;a.save(),this.getAlign()===p?a.translate(j-n-2*c,0):this.getAlign()===d&&a.translate((j-n-2*c)/2,0),this.partialText=m,a.fillStrokeShape(this),a.restore(),a.translate(0,f)}a.restore()},_hitFunc:function(a){var b=this.getWidth(),c=this.getHeight();a.beginPath(),a.rect(0,0,b,c),a.closePath(),a.fillStrokeShape(this)},setText:function(a){var b=Kinetic.Util._isString(a)?a:a.toString();return this._setAttr(j,b),this},getWidth:function(){return this.attrs.width===c?this.getTextWidth()+2*this.getPadding():this.attrs.width},getHeight:function(){return this.attrs.height===c?this.getTextHeight()*this.textArr.length*this.getLineHeight()+2*this.getPadding():this.attrs.height},getTextWidth:function(){return this.textWidth},getTextHeight:function(){return this.textHeight},_getTextSize:function(a){var b,c=v,d=this.getFontSize();return c.save(),c.font=this._getContextFont(),b=c.measureText(a),c.restore(),{width:b.width,height:parseInt(d,10)}},_getContextFont:function(){return this.getFontStyle()+o+this.getFontVariant()+o+this.getFontSize()+n+this.getFontFamily()},_addTextLine:function(a,b){return this.textArr.push({text:a,width:b})},_getTextWidth:function(a){return v.measureText(a).width},_setTextData:function(){var a=this.getText().split(\"\\n\"),b=+this.getFontSize(),d=0,e=this.getLineHeight()*b,f=this.attrs.width,h=this.attrs.height,i=f!==c,j=h!==c,k=this.getPadding(),l=f-2*k,m=h-2*k,n=0,p=this.getWrap(),q=p!==s,t=p!==r&&q;this.textArr=[],v.save(),v.font=this._getContextFont();for(var u=0,w=a.length;w>u;++u){var x=a[u],y=this._getTextWidth(x);if(i&&y>l)for(;x.length>0;){for(var z=0,A=x.length,B=\"\",C=0;A>z;){var D=z+A>>>1,E=x.slice(0,D+1),F=this._getTextWidth(E);l>=F?(z=D+1,B=E,C=F):A=D}if(!B)break;if(t){var G=Math.max(B.lastIndexOf(o),B.lastIndexOf(g))+1;G>0&&(z=G,B=B.slice(0,z),C=this._getTextWidth(B))}if(this._addTextLine(B,C),d=Math.max(d,C),n+=e,!q||j&&n+e>m)break;if(x=x.slice(z),x.length>0&&(y=this._getTextWidth(x),l>=y)){this._addTextLine(x,y),n+=e,d=Math.max(d,y);break}}else this._addTextLine(x,y),n+=e,d=Math.max(d,y);if(j&&n+e>m)break}v.restore(),this.textHeight=b,this.textWidth=d}},Kinetic.Util.extend(Kinetic.Text,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"fontFamily\",\"Arial\"),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"fontSize\",12),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"fontStyle\",m),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"fontVariant\",m),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"padding\",0),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"align\",i),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"lineHeight\",1),Kinetic.Factory.addGetterSetter(Kinetic.Text,\"wrap\",q),Kinetic.Factory.addGetter(Kinetic.Text,\"text\",h),Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Text,\"text\"),Kinetic.Collection.mapMethods(Kinetic.Text)}(),function(){Kinetic.Line=function(a){this.___init(a)},Kinetic.Line.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Line\",this.on(\"pointsChange.kinetic tensionChange.kinetic closedChange.kinetic\",function(){this._clearCache(\"tensionPoints\")}),this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b,c,d,e=this.getPoints(),f=e.length,g=this.getTension(),h=this.getClosed();if(f){if(a.beginPath(),a.moveTo(e[0],e[1]),0!==g&&f>4){for(b=this.getTensionPoints(),c=b.length,d=h?0:4,h||a.quadraticCurveTo(b[0],b[1],b[2],b[3]);c-2>d;)a.bezierCurveTo(b[d++],b[d++],b[d++],b[d++],b[d++],b[d++]);h||a.quadraticCurveTo(b[c-2],b[c-1],e[f-2],e[f-1])}else for(d=2;f>d;d+=2)a.lineTo(e[d],e[d+1]);h?(a.closePath(),a.fillStrokeShape(this)):a.strokeShape(this)}},getTensionPoints:function(){return this._getCache(\"tensionPoints\",this._getTensionPoints)},_getTensionPoints:function(){return this.getClosed()?this._getTensionPointsClosed():Kinetic.Util._expandPoints(this.getPoints(),this.getTension())},_getTensionPointsClosed:function(){var a=this.getPoints(),b=a.length,c=this.getTension(),d=Kinetic.Util,e=d._getControlPoints(a[b-2],a[b-1],a[0],a[1],a[2],a[3],c),f=d._getControlPoints(a[b-4],a[b-3],a[b-2],a[b-1],a[0],a[1],c),g=Kinetic.Util._expandPoints(a,c),h=[e[2],e[3]].concat(g).concat([f[0],f[1],a[b-2],a[b-1],f[2],f[3],e[0],e[1],a[0],a[1]]);return h}},Kinetic.Util.extend(Kinetic.Line,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Line,\"closed\",!1),Kinetic.Factory.addGetterSetter(Kinetic.Line,\"tension\",0),Kinetic.Factory.addGetterSetter(Kinetic.Line,\"points\",[]),Kinetic.Collection.mapMethods(Kinetic.Line)}(),function(){Kinetic.Sprite=function(a){this.___init(a)},Kinetic.Sprite.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Sprite\",this._updated=!0;var b=this;this.anim=new Kinetic.Animation(function(){var a=b._updated;return b._updated=!1,a}),this.on(\"animationChange.kinetic\",function(){this.frameIndex(0)}),this.on(\"frameIndexChange.kinetic\",function(){this._updated=!0}),this.on(\"frameRateChange.kinetic\",function(){this.anim.isRunning()&&(clearInterval(this.interval),this._setInterval())}),this.sceneFunc(this._sceneFunc),this.hitFunc(this._hitFunc)},_sceneFunc:function(a){var b=this.getAnimation(),c=this.frameIndex(),d=4*c,e=this.getAnimations()[b],f=this.frameOffsets(),g=e[d+0],h=e[d+1],i=e[d+2],j=e[d+3],k=this.getImage();if(k)if(f){var l=f[b],m=2*c;a.drawImage(k,g,h,i,j,l[m+0],l[m+1],i,j)}else a.drawImage(k,g,h,i,j,0,0,i,j)},_hitFunc:function(a){var b=this.getAnimation(),c=this.frameIndex(),d=4*c,e=this.getAnimations()[b],f=this.frameOffsets(),g=e[d+2],h=e[d+3];if(a.beginPath(),f){var i=f[b],j=2*c;a.rect(i[j+0],i[j+1],g,h)}else a.rect(0,0,g,h);a.closePath(),a.fillShape(this)},_useBufferCanvas:function(){return(this.hasShadow()||1!==this.getAbsoluteOpacity())&&this.hasStroke()},_setInterval:function(){var a=this;this.interval=setInterval(function(){a._updateIndex()},1e3/this.getFrameRate())},start:function(){var a=this.getLayer();this.anim.setLayers(a),this._setInterval(),this.anim.start()},stop:function(){this.anim.stop(),clearInterval(this.interval)},isRunning:function(){return this.anim.isRunning()},_updateIndex:function(){var a=this.frameIndex(),b=this.getAnimation(),c=this.getAnimations(),d=c[b],e=d.length/4;this.frameIndex(e-1>a?a+1:0)}},Kinetic.Util.extend(Kinetic.Sprite,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Sprite,\"animation\"),Kinetic.Factory.addGetterSetter(Kinetic.Sprite,\"animations\"),Kinetic.Factory.addGetterSetter(Kinetic.Sprite,\"frameOffsets\"),Kinetic.Factory.addGetterSetter(Kinetic.Sprite,\"image\"),Kinetic.Factory.addGetterSetter(Kinetic.Sprite,\"frameIndex\",0),Kinetic.Factory.addGetterSetter(Kinetic.Sprite,\"frameRate\",17),Kinetic.Factory.backCompat(Kinetic.Sprite,{index:\"frameIndex\",getIndex:\"getFrameIndex\",setIndex:\"setFrameIndex\"}),Kinetic.Collection.mapMethods(Kinetic.Sprite)}(),function(){Kinetic.Path=function(a){this.___init(a)},Kinetic.Path.prototype={___init:function(a){this.dataArray=[];var b=this;Kinetic.Shape.call(this,a),this.className=\"Path\",this.dataArray=Kinetic.Path.parsePathData(this.getData()),this.on(\"dataChange.kinetic\",function(){b.dataArray=Kinetic.Path.parsePathData(this.getData())}),this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b=this.dataArray,c=!1;a.beginPath();for(var d=0;d<b.length;d++){var e=b[d].command,f=b[d].points;switch(e){case\"L\":a.lineTo(f[0],f[1]);break;case\"M\":a.moveTo(f[0],f[1]);break;case\"C\":a.bezierCurveTo(f[0],f[1],f[2],f[3],f[4],f[5]);break;case\"Q\":a.quadraticCurveTo(f[0],f[1],f[2],f[3]);break;case\"A\":var g=f[0],h=f[1],i=f[2],j=f[3],k=f[4],l=f[5],m=f[6],n=f[7],o=i>j?i:j,p=i>j?1:i/j,q=i>j?j/i:1;a.translate(g,h),a.rotate(m),a.scale(p,q),a.arc(0,0,o,k,k+l,1-n),a.scale(1/p,1/q),a.rotate(-m),a.translate(-g,-h);break;case\"z\":a.closePath(),c=!0}}c?a.fillStrokeShape(this):a.strokeShape(this)}},Kinetic.Util.extend(Kinetic.Path,Kinetic.Shape),Kinetic.Path.getLineLength=function(a,b,c,d){return Math.sqrt((c-a)*(c-a)+(d-b)*(d-b))},Kinetic.Path.getPointOnLine=function(a,b,c,d,e,f,g){void 0===f&&(f=b),void 0===g&&(g=c);var h=(e-c)/(d-b+1e-8),i=Math.sqrt(a*a/(1+h*h));b>d&&(i*=-1);var j,k=h*i;if(d===b)j={x:f,y:g+k};else if((g-c)/(f-b+1e-8)===h)j={x:f+i,y:g+k};else{var l,m,n=this.getLineLength(b,c,d,e);if(1e-8>n)return void 0;var o=(f-b)*(d-b)+(g-c)*(e-c);o/=n*n,l=b+o*(d-b),m=c+o*(e-c);var p=this.getLineLength(f,g,l,m),q=Math.sqrt(a*a-p*p);i=Math.sqrt(q*q/(1+h*h)),b>d&&(i*=-1),k=h*i,j={x:l+i,y:m+k}}return j},Kinetic.Path.getPointOnCubicBezier=function(a,b,c,d,e,f,g,h,i){function j(a){return a*a*a}function k(a){return 3*a*a*(1-a)}function l(a){return 3*a*(1-a)*(1-a)}function m(a){return(1-a)*(1-a)*(1-a)}var n=h*j(a)+f*k(a)+d*l(a)+b*m(a),o=i*j(a)+g*k(a)+e*l(a)+c*m(a);return{x:n,y:o}},Kinetic.Path.getPointOnQuadraticBezier=function(a,b,c,d,e,f,g){function h(a){return a*a}function i(a){return 2*a*(1-a)}function j(a){return(1-a)*(1-a)}var k=f*h(a)+d*i(a)+b*j(a),l=g*h(a)+e*i(a)+c*j(a);return{x:k,y:l}},Kinetic.Path.getPointOnEllipticalArc=function(a,b,c,d,e,f){var g=Math.cos(f),h=Math.sin(f),i={x:c*Math.cos(e),y:d*Math.sin(e)};return{x:a+(i.x*g-i.y*h),y:b+(i.x*h+i.y*g)}},Kinetic.Path.parsePathData=function(a){if(!a)return[];var b=a,c=[\"m\",\"M\",\"l\",\"L\",\"v\",\"V\",\"h\",\"H\",\"z\",\"Z\",\"c\",\"C\",\"q\",\"Q\",\"t\",\"T\",\"s\",\"S\",\"a\",\"A\"];b=b.replace(new RegExp(\" \",\"g\"),\",\");for(var d=0;d<c.length;d++)b=b.replace(new RegExp(c[d],\"g\"),\"|\"+c[d]);var e=b.split(\"|\"),f=[],g=0,h=0;for(d=1;d<e.length;d++){var i=e[d],j=i.charAt(0);i=i.slice(1),i=i.replace(new RegExp(\",-\",\"g\"),\"-\"),i=i.replace(new RegExp(\"-\",\"g\"),\",-\"),i=i.replace(new RegExp(\"e,-\",\"g\"),\"e-\");var k=i.split(\",\");k.length>0&&\"\"===k[0]&&k.shift();for(var l=0;l<k.length;l++)k[l]=parseFloat(k[l]);for(;k.length>0&&!isNaN(k[0]);){var m,n,o,p,q,r,s,t,u,v,w=null,x=[],y=g,z=h;switch(j){case\"l\":g+=k.shift(),h+=k.shift(),w=\"L\",x.push(g,h);break;case\"L\":g=k.shift(),h=k.shift(),x.push(g,h);break;case\"m\":var A=k.shift(),B=k.shift();if(g+=A,h+=B,w=\"M\",f.length>2&&\"z\"===f[f.length-1].command)for(var C=f.length-2;C>=0;C--)if(\"M\"===f[C].command){g=f[C].points[0]+A,h=f[C].points[1]+B;break}x.push(g,h),j=\"l\";break;case\"M\":g=k.shift(),h=k.shift(),w=\"M\",x.push(g,h),j=\"L\";break;case\"h\":g+=k.shift(),w=\"L\",x.push(g,h);break;case\"H\":g=k.shift(),w=\"L\",x.push(g,h);break;case\"v\":h+=k.shift(),w=\"L\",x.push(g,h);break;case\"V\":h=k.shift(),w=\"L\",x.push(g,h);break;case\"C\":x.push(k.shift(),k.shift(),k.shift(),k.shift()),g=k.shift(),h=k.shift(),x.push(g,h);break;case\"c\":x.push(g+k.shift(),h+k.shift(),g+k.shift(),h+k.shift()),g+=k.shift(),h+=k.shift(),w=\"C\",x.push(g,h);break;case\"S\":n=g,o=h,m=f[f.length-1],\"C\"===m.command&&(n=g+(g-m.points[2]),o=h+(h-m.points[3])),x.push(n,o,k.shift(),k.shift()),g=k.shift(),h=k.shift(),w=\"C\",x.push(g,h);break;case\"s\":n=g,o=h,m=f[f.length-1],\"C\"===m.command&&(n=g+(g-m.points[2]),o=h+(h-m.points[3])),x.push(n,o,g+k.shift(),h+k.shift()),g+=k.shift(),h+=k.shift(),w=\"C\",x.push(g,h);break;case\"Q\":x.push(k.shift(),k.shift()),g=k.shift(),h=k.shift(),x.push(g,h);break;case\"q\":x.push(g+k.shift(),h+k.shift()),g+=k.shift(),h+=k.shift(),w=\"Q\",x.push(g,h);break;case\"T\":n=g,o=h,m=f[f.length-1],\"Q\"===m.command&&(n=g+(g-m.points[0]),o=h+(h-m.points[1])),g=k.shift(),h=k.shift(),w=\"Q\",x.push(n,o,g,h);break;case\"t\":n=g,o=h,m=f[f.length-1],\"Q\"===m.command&&(n=g+(g-m.points[0]),o=h+(h-m.points[1])),g+=k.shift(),h+=k.shift(),w=\"Q\",x.push(n,o,g,h);break;case\"A\":p=k.shift(),q=k.shift(),r=k.shift(),s=k.shift(),t=k.shift(),u=g,v=h,g=k.shift(),h=k.shift(),w=\"A\",x=this.convertEndpointToCenterParameterization(u,v,g,h,s,t,p,q,r);break;case\"a\":p=k.shift(),q=k.shift(),r=k.shift(),s=k.shift(),t=k.shift(),u=g,v=h,g+=k.shift(),h+=k.shift(),w=\"A\",x=this.convertEndpointToCenterParameterization(u,v,g,h,s,t,p,q,r)}f.push({command:w||j,points:x,start:{x:y,y:z},pathLength:this.calcLength(y,z,w||j,x)})}(\"z\"===j||\"Z\"===j)&&f.push({command:\"z\",points:[],start:void 0,pathLength:0})}return f},Kinetic.Path.calcLength=function(a,b,c,d){var e,f,g,h,i=Kinetic.Path;switch(c){case\"L\":return i.getLineLength(a,b,d[0],d[1]);case\"C\":for(e=0,f=i.getPointOnCubicBezier(0,a,b,d[0],d[1],d[2],d[3],d[4],d[5]),h=.01;1>=h;h+=.01)g=i.getPointOnCubicBezier(h,a,b,d[0],d[1],d[2],d[3],d[4],d[5]),e+=i.getLineLength(f.x,f.y,g.x,g.y),f=g;return e;case\"Q\":for(e=0,f=i.getPointOnQuadraticBezier(0,a,b,d[0],d[1],d[2],d[3]),h=.01;1>=h;h+=.01)g=i.getPointOnQuadraticBezier(h,a,b,d[0],d[1],d[2],d[3]),e+=i.getLineLength(f.x,f.y,g.x,g.y),f=g;return e;case\"A\":e=0;var j=d[4],k=d[5],l=d[4]+k,m=Math.PI/180;if(Math.abs(j-l)<m&&(m=Math.abs(j-l)),f=i.getPointOnEllipticalArc(d[0],d[1],d[2],d[3],j,0),0>k)for(h=j-m;h>l;h-=m)g=i.getPointOnEllipticalArc(d[0],d[1],d[2],d[3],h,0),e+=i.getLineLength(f.x,f.y,g.x,g.y),f=g;else for(h=j+m;l>h;h+=m)g=i.getPointOnEllipticalArc(d[0],d[1],d[2],d[3],h,0),e+=i.getLineLength(f.x,f.y,g.x,g.y),f=g;return g=i.getPointOnEllipticalArc(d[0],d[1],d[2],d[3],l,0),e+=i.getLineLength(f.x,f.y,g.x,g.y)}return 0},Kinetic.Path.convertEndpointToCenterParameterization=function(a,b,c,d,e,f,g,h,i){var j=i*(Math.PI/180),k=Math.cos(j)*(a-c)/2+Math.sin(j)*(b-d)/2,l=-1*Math.sin(j)*(a-c)/2+Math.cos(j)*(b-d)/2,m=k*k/(g*g)+l*l/(h*h);m>1&&(g*=Math.sqrt(m),h*=Math.sqrt(m));var n=Math.sqrt((g*g*h*h-g*g*l*l-h*h*k*k)/(g*g*l*l+h*h*k*k));e===f&&(n*=-1),isNaN(n)&&(n=0);var o=n*g*l/h,p=n*-h*k/g,q=(a+c)/2+Math.cos(j)*o-Math.sin(j)*p,r=(b+d)/2+Math.sin(j)*o+Math.cos(j)*p,s=function(a){return Math.sqrt(a[0]*a[0]+a[1]*a[1])},t=function(a,b){return(a[0]*b[0]+a[1]*b[1])/(s(a)*s(b))},u=function(a,b){return(a[0]*b[1]<a[1]*b[0]?-1:1)*Math.acos(t(a,b))},v=u([1,0],[(k-o)/g,(l-p)/h]),w=[(k-o)/g,(l-p)/h],x=[(-1*k-o)/g,(-1*l-p)/h],y=u(w,x);return t(w,x)<=-1&&(y=Math.PI),t(w,x)>=1&&(y=0),0===f&&y>0&&(y-=2*Math.PI),1===f&&0>y&&(y+=2*Math.PI),[q,r,g,h,v,y,j,f]},Kinetic.Factory.addGetterSetter(Kinetic.Path,\"data\"),Kinetic.Collection.mapMethods(Kinetic.Path)}(),function(){function a(a){a.fillText(this.partialText,0,0)}function b(a){a.strokeText(this.partialText,0,0)}var c=\"\",d=\"normal\";Kinetic.TextPath=function(a){this.___init(a)},Kinetic.TextPath.prototype={___init:function(c){var d=this;this.dummyCanvas=Kinetic.Util.createCanvasElement(),this.dataArray=[],Kinetic.Shape.call(this,c),this._fillFunc=a,this._strokeFunc=b,this._fillFuncHit=a,this._strokeFuncHit=b,this.className=\"TextPath\",this.dataArray=Kinetic.Path.parsePathData(this.attrs.data),this.on(\"dataChange.kinetic\",function(){d.dataArray=Kinetic.Path.parsePathData(this.attrs.data)}),this.on(\"textChange.kinetic textStroke.kinetic textStrokeWidth.kinetic\",d._setTextData),d._setTextData(),this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){a.setAttr(\"font\",this._getContextFont()),a.setAttr(\"textBaseline\",\"middle\"),a.setAttr(\"textAlign\",\"left\"),a.save();for(var b=this.glyphInfo,c=0;c<b.length;c++){a.save();var d=b[c].p0;a.translate(d.x,d.y),a.rotate(b[c].rotation),this.partialText=b[c].text,a.fillStrokeShape(this),a.restore()}a.restore()},getTextWidth:function(){return this.textWidth},getTextHeight:function(){return this.textHeight},setText:function(a){Kinetic.Text.prototype.setText.call(this,a)},_getTextSize:function(a){var b=this.dummyCanvas,c=b.getContext(\"2d\");c.save(),c.font=this._getContextFont();var d=c.measureText(a);return c.restore(),{width:d.width,height:parseInt(this.attrs.fontSize,10)}},_setTextData:function(){var a=this,b=this._getTextSize(this.attrs.text);this.textWidth=b.width,this.textHeight=b.height,this.glyphInfo=[];for(var c,d,e,f=this.attrs.text.split(\"\"),g=-1,h=0,i=function(){h=0;for(var b=a.dataArray,d=g+1;d<b.length;d++){if(b[d].pathLength>0)return g=d,b[d];\"M\"==b[d].command&&(c={x:b[d].points[0],y:b[d].points[1]})}return{}},j=function(b){var f=a._getTextSize(b).width,g=0,j=0;for(d=void 0;Math.abs(f-g)/f>.01&&25>j;){j++;for(var k=g;void 0===e;)e=i(),e&&k+e.pathLength<f&&(k+=e.pathLength,e=void 0);if(e==={}||void 0===c)return void 0;var l=!1;switch(e.command){case\"L\":Kinetic.Path.getLineLength(c.x,c.y,e.points[0],e.points[1])>f?d=Kinetic.Path.getPointOnLine(f,c.x,c.y,e.points[0],e.points[1],c.x,c.y):e=void 0;break;case\"A\":var m=e.points[4],n=e.points[5],o=e.points[4]+n;0===h?h=m+1e-8:f>g?h+=Math.PI/180*n/Math.abs(n):h-=Math.PI/360*n/Math.abs(n),(0>n&&o>h||n>=0&&h>o)&&(h=o,l=!0),d=Kinetic.Path.getPointOnEllipticalArc(e.points[0],e.points[1],e.points[2],e.points[3],h,e.points[6]);break;case\"C\":0===h?h=f>e.pathLength?1e-8:f/e.pathLength:f>g?h+=(f-g)/e.pathLength:h-=(g-f)/e.pathLength,h>1&&(h=1,l=!0),d=Kinetic.Path.getPointOnCubicBezier(h,e.start.x,e.start.y,e.points[0],e.points[1],e.points[2],e.points[3],e.points[4],e.points[5]);break;case\"Q\":0===h?h=f/e.pathLength:f>g?h+=(f-g)/e.pathLength:h-=(g-f)/e.pathLength,h>1&&(h=1,l=!0),d=Kinetic.Path.getPointOnQuadraticBezier(h,e.start.x,e.start.y,e.points[0],e.points[1],e.points[2],e.points[3])}void 0!==d&&(g=Kinetic.Path.getLineLength(c.x,c.y,d.x,d.y)),l&&(l=!1,e=void 0)}},k=0;k<f.length&&(j(f[k]),void 0!==c&&void 0!==d);k++){var l=Kinetic.Path.getLineLength(c.x,c.y,d.x,d.y),m=0,n=Kinetic.Path.getPointOnLine(m+l/2,c.x,c.y,d.x,d.y),o=Math.atan2(d.y-c.y,d.x-c.x);this.glyphInfo.push({transposeX:n.x,transposeY:n.y,text:f[k],rotation:o,p0:c,p1:d}),c=d}}},Kinetic.TextPath.prototype._getContextFont=Kinetic.Text.prototype._getContextFont,Kinetic.Util.extend(Kinetic.TextPath,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.TextPath,\"fontFamily\",\"Arial\"),Kinetic.Factory.addGetterSetter(Kinetic.TextPath,\"fontSize\",12),Kinetic.Factory.addGetterSetter(Kinetic.TextPath,\"fontStyle\",d),Kinetic.Factory.addGetterSetter(Kinetic.TextPath,\"fontVariant\",d),Kinetic.Factory.addGetter(Kinetic.TextPath,\"text\",c),Kinetic.Collection.mapMethods(Kinetic.TextPath)}(),function(){Kinetic.RegularPolygon=function(a){this.___init(a)},Kinetic.RegularPolygon.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"RegularPolygon\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b,c,d,e=this.attrs.sides,f=this.attrs.radius;for(a.beginPath(),a.moveTo(0,0-f),b=1;e>b;b++)c=f*Math.sin(2*b*Math.PI/e),d=-1*f*Math.cos(2*b*Math.PI/e),a.lineTo(c,d);a.closePath(),a.fillStrokeShape(this)}},Kinetic.Util.extend(Kinetic.RegularPolygon,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.RegularPolygon,\"radius\",0),Kinetic.Factory.addGetterSetter(Kinetic.RegularPolygon,\"sides\",0),Kinetic.Collection.mapMethods(Kinetic.RegularPolygon)}(),function(){Kinetic.Star=function(a){this.___init(a)},Kinetic.Star.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Star\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b=this.innerRadius(),c=this.outerRadius(),d=this.numPoints();a.beginPath(),a.moveTo(0,0-c);for(var e=1;2*d>e;e++){var f=e%2===0?c:b,g=f*Math.sin(e*Math.PI/d),h=-1*f*Math.cos(e*Math.PI/d);a.lineTo(g,h)}a.closePath(),a.fillStrokeShape(this)}},Kinetic.Util.extend(Kinetic.Star,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Star,\"numPoints\",5),Kinetic.Factory.addGetterSetter(Kinetic.Star,\"innerRadius\",0),Kinetic.Factory.addGetterSetter(Kinetic.Star,\"outerRadius\",0),Kinetic.Collection.mapMethods(Kinetic.Star)}(),function(){var a=[\"fontFamily\",\"fontSize\",\"fontStyle\",\"padding\",\"lineHeight\",\"text\"],b=\"Change.kinetic\",c=\"none\",d=\"up\",e=\"right\",f=\"down\",g=\"left\",h=\"Label\",i=a.length;Kinetic.Label=function(a){this.____init(a)},Kinetic.Label.prototype={____init:function(a){var b=this;Kinetic.Group.call(this,a),this.className=h,this.on(\"add.kinetic\",function(a){b._addListeners(a.child),b._sync()})},getText:function(){return this.find(\"Text\")[0]},getTag:function(){return this.find(\"Tag\")[0]},_addListeners:function(c){var d,e=this,f=function(){e._sync()};for(d=0;i>d;d++)c.on(a[d]+b,f)},getWidth:function(){return this.getText().getWidth()},getHeight:function(){return this.getText().getHeight()},_sync:function(){var a,b,c,h,i,j,k,l=this.getText(),m=this.getTag();if(l&&m){switch(a=l.getWidth(),b=l.getHeight(),c=m.getPointerDirection(),h=m.getPointerWidth(),k=m.getPointerHeight(),i=0,j=0,c){case d:i=a/2,j=-1*k;break;case e:i=a+h,j=b/2;break;case f:i=a/2,j=b+k;break;case g:i=-1*h,j=b/2}m.setAttrs({x:-1*i,y:-1*j,width:a,height:b}),l.setAttrs({x:-1*i,y:-1*j})}}},Kinetic.Util.extend(Kinetic.Label,Kinetic.Group),Kinetic.Collection.mapMethods(Kinetic.Label),Kinetic.Tag=function(a){this.___init(a)},Kinetic.Tag.prototype={___init:function(a){Kinetic.Shape.call(this,a),this.className=\"Tag\",this.sceneFunc(this._sceneFunc)},_sceneFunc:function(a){var b=this.getWidth(),c=this.getHeight(),h=this.getPointerDirection(),i=this.getPointerWidth(),j=this.getPointerHeight(),k=this.getCornerRadius();a.beginPath(),a.moveTo(0,0),h===d&&(a.lineTo((b-i)/2,0),a.lineTo(b/2,-1*j),a.lineTo((b+i)/2,0)),k?(a.lineTo(b-k,0),a.arc(b-k,k,k,3*Math.PI/2,0,!1)):a.lineTo(b,0),h===e&&(a.lineTo(b,(c-j)/2),a.lineTo(b+i,c/2),a.lineTo(b,(c+j)/2)),k?(a.lineTo(b,c-k),a.arc(b-k,c-k,k,0,Math.PI/2,!1)):a.lineTo(b,c),h===f&&(a.lineTo((b+i)/2,c),a.lineTo(b/2,c+j),a.lineTo((b-i)/2,c)),k?(a.lineTo(k,c),a.arc(k,c-k,k,Math.PI/2,Math.PI,!1)):a.lineTo(0,c),h===g&&(a.lineTo(0,(c+j)/2),a.lineTo(-1*i,c/2),a.lineTo(0,(c-j)/2)),k&&(a.lineTo(0,k),a.arc(k,k,k,Math.PI,3*Math.PI/2,!1)),a.closePath(),a.fillStrokeShape(this)}},Kinetic.Util.extend(Kinetic.Tag,Kinetic.Shape),Kinetic.Factory.addGetterSetter(Kinetic.Tag,\"pointerDirection\",c),Kinetic.Factory.addGetterSetter(Kinetic.Tag,\"pointerWidth\",0),Kinetic.Factory.addGetterSetter(Kinetic.Tag,\"pointerHeight\",0),Kinetic.Factory.addGetterSetter(Kinetic.Tag,\"cornerRadius\",0),Kinetic.Collection.mapMethods(Kinetic.Tag)}(),function(){Kinetic.Arrow=function(a){this.____init(a)},Kinetic.Arrow.prototype={____init:function(a){Kinetic.Line.call(this,a),this.className=\"Arrow\"},_sceneFunc:function(a){var b=2*Math.PI,c=this.points(),d=c.length,e=c[d-2]-c[d-4],f=c[d-1]-c[d-3],g=(Math.atan2(f,e)+b)%b,h=this.pointerLength(),i=this.pointerWidth();a.save(),a.beginPath(),a.translate(c[d-2],c[d-1]),a.rotate(g),a.moveTo(0,0),a.lineTo(-h,i/2),a.lineTo(-h,-i/2),a.closePath(),a.restore(),this.pointerAtBeginning()&&(a.save(),a.translate(c[0],c[1]),e=c[2]-c[0],f=c[3]-c[1],a.rotate((Math.atan2(-f,-e)+b)%b),a.moveTo(0,0),a.lineTo(-10,6),a.lineTo(-10,-6),a.closePath(),a.restore()),a.fillStrokeShape(this),Kinetic.Line.prototype._sceneFunc.apply(this,arguments)}},Kinetic.Util.extend(Kinetic.Arrow,Kinetic.Line),Kinetic.Factory.addGetterSetter(Kinetic.Arrow,\"pointerLength\",10),Kinetic.Factory.addGetterSetter(Kinetic.Arrow,\"pointerWidth\",10),Kinetic.Factory.addGetterSetter(Kinetic.Arrow,\"pointerAtBeginning\",!1),Kinetic.Collection.mapMethods(Kinetic.Arrow)}();;/**\n * Copyright (c) 2007-2014 Ariel Flesler - aflesler<a>gmail<d>com | http://flesler.blogspot.com\n * Licensed under MIT\n * @author Ariel Flesler\n * @version 1.4.14\n */\n;(function(k){'use strict';k(['jquery'],function($){var j=$.scrollTo=function(a,b,c){return $(window).scrollTo(a,b,c)};j.defaults={axis:'xy',duration:0,limit:!0};j.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(f,g,h){if(typeof g=='object'){h=g;g=0}if(typeof h=='function')h={onAfter:h};if(f=='max')f=9e9;h=$.extend({},j.defaults,h);g=g||h.duration;h.queue=h.queue&&h.axis.length>1;if(h.queue)g/=2;h.offset=both(h.offset);h.over=both(h.over);return this._scrollable().each(function(){if(f==null)return;var d=this,$elem=$(d),targ=f,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\\d+(\\.\\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=win?$(targ):$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}var e=$.isFunction(h.offset)&&h.offset(d,targ)||h.offset;$.each(h.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=j.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(h.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=e[pos]||0;if(h.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*h.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(h.limit&&/^\\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&h.queue){if(old!=attr[key])animate(h.onAfterFirst);delete attr[key]}});animate(h.onAfter);function animate(a){$elem.animate(attr,g,h.easing,a&&function(){a.call(this,targ,h)})}}).end()};j.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}return j})}(typeof define==='function'&&define.amd?define:function(a,b){if(typeof module!=='undefined'&&module.exports){module.exports=b(require('jquery'))}else{b(jQuery)}}));"
  },
  {
    "path": "src/libs/fabric.require1-4-12.js",
    "content": "/* build: `node build.js modules=ALL exclude=gestures,cufon,json minifier=uglifyjs` */\n/*! Fabric.js Copyright 2008-2014, Printio (Juriy Zaytsev, Maxim Chernyak) */\n\nvar fabric = fabric || { version: \"1.4.12\" };\nif (typeof exports !== 'undefined') {\n    exports.fabric = fabric;\n}\n\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n    fabric.document = document;\n    fabric.window = window;\n}\n\n/**\n * True when in environment that supports touch events\n * @type boolean\n */\nfabric.isTouchSupported = \"ontouchstart\" in fabric.document.documentElement;\n\n/**\n * True when in environment that's probably Node.js\n * @type boolean\n */\nfabric.isLikelyNode = typeof Buffer !== 'undefined' &&\n    typeof window === 'undefined';\n\n\n/**\n * Attributes parsed from all SVG elements\n * @type array\n */\nfabric.SHARED_ATTRIBUTES = [\n    \"display\",\n    \"transform\",\n    \"fill\", \"fill-opacity\", \"fill-rule\",\n    \"opacity\",\n    \"stroke\", \"stroke-dasharray\", \"stroke-linecap\",\n    \"stroke-linejoin\", \"stroke-miterlimit\",\n    \"stroke-opacity\", \"stroke-width\"\n];\n\n/**\n * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion.\n */\nfabric.DPI = 96;\n\n\n(function() {\n\n    /**\n     * @private\n     * @param {String} eventName\n     * @param {Function} handler\n     */\n    function _removeEventListener(eventName, handler) {\n        if (!this.__eventListeners[eventName]) {\n            return;\n        }\n\n        if (handler) {\n            fabric.util.removeFromArray(this.__eventListeners[eventName], handler);\n        }\n        else {\n            this.__eventListeners[eventName].length = 0;\n        }\n    }\n\n    /**\n     * Observes specified event\n     * @deprecated `observe` deprecated since 0.8.34 (use `on` instead)\n     * @memberOf fabric.Observable\n     * @alias on\n     * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n     * @param {Function} handler Function that receives a notification when an event of the specified type occurs\n     * @return {Self} thisArg\n     * @chainable\n     */\n    function observe(eventName, handler) {\n        if (!this.__eventListeners) {\n            this.__eventListeners = { };\n        }\n        // one object with key/value pairs was passed\n        if (arguments.length === 1) {\n            for (var prop in eventName) {\n                this.on(prop, eventName[prop]);\n            }\n        }\n        else {\n            if (!this.__eventListeners[eventName]) {\n                this.__eventListeners[eventName] = [ ];\n            }\n            this.__eventListeners[eventName].push(handler);\n        }\n        return this;\n    }\n\n    /**\n     * Stops event observing for a particular event handler. Calling this method\n     * without arguments removes all handlers for all events\n     * @deprecated `stopObserving` deprecated since 0.8.34 (use `off` instead)\n     * @memberOf fabric.Observable\n     * @alias off\n     * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n     * @param {Function} handler Function to be deleted from EventListeners\n     * @return {Self} thisArg\n     * @chainable\n     */\n    function stopObserving(eventName, handler) {\n        if (!this.__eventListeners) {\n            return;\n        }\n\n        // remove all key/value pairs (event name -> event handler)\n        if (arguments.length === 0) {\n            this.__eventListeners = { };\n        }\n        // one object with key/value pairs was passed\n        else if (arguments.length === 1 && typeof arguments[0] === 'object') {\n            for (var prop in eventName) {\n                _removeEventListener.call(this, prop, eventName[prop]);\n            }\n        }\n        else {\n            _removeEventListener.call(this, eventName, handler);\n        }\n        return this;\n    }\n\n    /**\n     * Fires event with an optional options object\n     * @deprecated `fire` deprecated since 1.0.7 (use `trigger` instead)\n     * @memberOf fabric.Observable\n     * @alias trigger\n     * @param {String} eventName Event name to fire\n     * @param {Object} [options] Options object\n     * @return {Self} thisArg\n     * @chainable\n     */\n    function fire(eventName, options) {\n        if (!this.__eventListeners) {\n            return;\n        }\n\n        var listenersForEvent = this.__eventListeners[eventName];\n        if (!listenersForEvent) {\n            return;\n        }\n\n        for (var i = 0, len = listenersForEvent.length; i < len; i++) {\n            // avoiding try/catch for perf. reasons\n            listenersForEvent[i].call(this, options || { });\n        }\n        return this;\n    }\n\n    /**\n     * @namespace fabric.Observable\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#events}\n     * @see {@link http://fabricjs.com/events/|Events demo}\n     */\n    fabric.Observable = {\n        observe: observe,\n        stopObserving: stopObserving,\n        fire: fire,\n\n        on: observe,\n        off: stopObserving,\n        trigger: fire\n    };\n})();\n\n\n/**\n * @namespace fabric.Collection\n */\nfabric.Collection = {\n\n    /**\n     * Adds objects to collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n     * Objects should be instances of (or inherit from) fabric.Object\n     * @param {...fabric.Object} object Zero or more fabric instances\n     * @return {Self} thisArg\n     */\n    add: function () {\n        this._objects.push.apply(this._objects, arguments);\n        for (var i = 0, length = arguments.length; i < length; i++) {\n            this._onObjectAdded(arguments[i]);\n        }\n        this.renderOnAddRemove && this.renderAll();\n        return this;\n    },\n\n    /**\n     * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)\n     * An object should be an instance of (or inherit from) fabric.Object\n     * @param {Object} object Object to insert\n     * @param {Number} index Index to insert object at\n     * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs\n     * @return {Self} thisArg\n     * @chainable\n     */\n    insertAt: function (object, index, nonSplicing) {\n        var objects = this.getObjects();\n        if (nonSplicing) {\n            objects[index] = object;\n        }\n        else {\n            objects.splice(index, 0, object);\n        }\n        this._onObjectAdded(object);\n        this.renderOnAddRemove && this.renderAll();\n        return this;\n    },\n\n    /**\n     * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n     * @param {...fabric.Object} object Zero or more fabric instances\n     * @return {Self} thisArg\n     * @chainable\n     */\n    remove: function() {\n        var objects = this.getObjects(),\n            index;\n\n        for (var i = 0, length = arguments.length; i < length; i++) {\n            index = objects.indexOf(arguments[i]);\n\n            // only call onObjectRemoved if an object was actually removed\n            if (index !== -1) {\n                objects.splice(index, 1);\n                this._onObjectRemoved(arguments[i]);\n            }\n        }\n\n        this.renderOnAddRemove && this.renderAll();\n        return this;\n    },\n\n    /**\n     * Executes given function for each object in this group\n     * @param {Function} callback\n     *                   Callback invoked with current object as first argument,\n     *                   index - as second and an array of all objects - as third.\n     *                   Iteration happens in reverse order (for performance reasons).\n     *                   Callback is invoked in a context of Global Object (e.g. `window`)\n     *                   when no `context` argument is given\n     *\n     * @param {Object} context Context (aka thisObject)\n     * @return {Self} thisArg\n     */\n    forEachObject: function(callback, context) {\n        var objects = this.getObjects(),\n            i = objects.length;\n        while (i--) {\n            callback.call(context, objects[i], i, objects);\n        }\n        return this;\n    },\n\n    /**\n     * Returns an array of children objects of this instance\n     * Type parameter introduced in 1.3.10\n     * @param {String} [type] When specified, only objects of this type are returned\n     * @return {Array}\n     */\n    getObjects: function(type) {\n        if (typeof type === 'undefined') {\n            return this._objects;\n        }\n        return this._objects.filter(function(o) {\n            return o.type === type;\n        });\n    },\n\n    /**\n     * Returns object at specified index\n     * @param {Number} index\n     * @return {Self} thisArg\n     */\n    item: function (index) {\n        return this.getObjects()[index];\n    },\n\n    /**\n     * Returns true if collection contains no objects\n     * @return {Boolean} true if collection is empty\n     */\n    isEmpty: function () {\n        return this.getObjects().length === 0;\n    },\n\n    /**\n     * Returns a size of a collection (i.e: length of an array containing its objects)\n     * @return {Number} Collection size\n     */\n    size: function() {\n        return this.getObjects().length;\n    },\n\n    /**\n     * Returns true if collection contains an object\n     * @param {Object} object Object to check against\n     * @return {Boolean} `true` if collection contains an object\n     */\n    contains: function(object) {\n        return this.getObjects().indexOf(object) > -1;\n    },\n\n    /**\n     * Returns number representation of a collection complexity\n     * @return {Number} complexity\n     */\n    complexity: function () {\n        return this.getObjects().reduce(function (memo, current) {\n            memo += current.complexity ? current.complexity() : 0;\n            return memo;\n        }, 0);\n    }\n};\n\n\n(function(global) {\n\n    var sqrt = Math.sqrt,\n        atan2 = Math.atan2,\n        PiBy180 = Math.PI / 180;\n\n    /**\n     * @namespace fabric.util\n     */\n    fabric.util = {\n\n        /**\n         * Removes value from an array.\n         * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf`\n         * @static\n         * @memberOf fabric.util\n         * @param {Array} array\n         * @param {Any} value\n         * @return {Array} original array\n         */\n        removeFromArray: function(array, value) {\n            var idx = array.indexOf(value);\n            if (idx !== -1) {\n                array.splice(idx, 1);\n            }\n            return array;\n        },\n\n        /**\n         * Returns random number between 2 specified ones.\n         * @static\n         * @memberOf fabric.util\n         * @param {Number} min lower limit\n         * @param {Number} max upper limit\n         * @return {Number} random value (between min and max)\n         */\n        getRandomInt: function(min, max) {\n            return Math.floor(Math.random() * (max - min + 1)) + min;\n        },\n\n        /**\n         * Transforms degrees to radians.\n         * @static\n         * @memberOf fabric.util\n         * @param {Number} degrees value in degrees\n         * @return {Number} value in radians\n         */\n        degreesToRadians: function(degrees) {\n            return degrees * PiBy180;\n        },\n\n        /**\n         * Transforms radians to degrees.\n         * @static\n         * @memberOf fabric.util\n         * @param {Number} radians value in radians\n         * @return {Number} value in degrees\n         */\n        radiansToDegrees: function(radians) {\n            return radians / PiBy180;\n        },\n\n        /**\n         * Rotates `point` around `origin` with `radians`\n         * @static\n         * @memberOf fabric.util\n         * @param {fabric.Point} point The point to rotate\n         * @param {fabric.Point} origin The origin of the rotation\n         * @param {Number} radians The radians of the angle for the rotation\n         * @return {fabric.Point} The new rotated point\n         */\n        rotatePoint: function(point, origin, radians) {\n            var sin = Math.sin(radians),\n                cos = Math.cos(radians);\n\n            point.subtractEquals(origin);\n\n            var rx = point.x * cos - point.y * sin,\n                ry = point.x * sin + point.y * cos;\n\n            return new fabric.Point(rx, ry).addEquals(origin);\n        },\n\n        /**\n         * Apply transform t to point p\n         * @static\n         * @memberOf fabric.util\n         * @param  {fabric.Point} p The point to transform\n         * @param  {Array} t The transform\n         * @param  {Boolean} [ignoreOffset] Indicates that the offset should not be applied\n         * @return {fabric.Point} The transformed point\n         */\n        transformPoint: function(p, t, ignoreOffset) {\n            if (ignoreOffset) {\n                return new fabric.Point(\n                        t[0] * p.x + t[1] * p.y,\n                        t[2] * p.x + t[3] * p.y\n                );\n            }\n            return new fabric.Point(\n                    t[0] * p.x + t[1] * p.y + t[4],\n                    t[2] * p.x + t[3] * p.y + t[5]\n            );\n        },\n\n        /**\n         * Invert transformation t\n         * @static\n         * @memberOf fabric.util\n         * @param {Array} t The transform\n         * @return {Array} The inverted transform\n         */\n        invertTransform: function(t) {\n            var r = t.slice(),\n                a = 1 / (t[0] * t[3] - t[1] * t[2]);\n            r = [a * t[3], -a * t[1], -a * t[2], a * t[0], 0, 0];\n            var o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r);\n            r[4] = -o.x;\n            r[5] = -o.y;\n            return r;\n        },\n\n        /**\n         * A wrapper around Number#toFixed, which contrary to native method returns number, not string.\n         * @static\n         * @memberOf fabric.util\n         * @param {Number|String} number number to operate on\n         * @param {Number} fractionDigits number of fraction digits to \"leave\"\n         * @return {Number}\n         */\n        toFixed: function(number, fractionDigits) {\n            return parseFloat(Number(number).toFixed(fractionDigits));\n        },\n\n        /**\n         * Converts from attribute value to pixel value if applicable.\n         * Returns converted pixels or original value not converted.\n         * @param {Number|String} value number to operate on\n         * @return {Number|String}\n         */\n        parseUnit: function(value) {\n            var unit = /\\D{0,2}$/.exec(value),\n                number = parseFloat(value);\n\n            switch (unit[0]) {\n                case 'mm':\n                    return number * fabric.DPI / 25.4;\n\n                case 'cm':\n                    return number * fabric.DPI / 2.54;\n\n                case 'in':\n                    return number * fabric.DPI;\n\n                case 'pt':\n                    return number * fabric.DPI / 72; // or * 4 / 3\n\n                case 'pc':\n                    return number * fabric.DPI / 72 * 12; // or * 16\n\n                default:\n                    return number;\n            }\n        },\n\n        /**\n         * Function which always returns `false`.\n         * @static\n         * @memberOf fabric.util\n         * @return {Boolean}\n         */\n        falseFunction: function() {\n            return false;\n        },\n\n        /**\n         * Returns klass \"Class\" object of given namespace\n         * @memberOf fabric.util\n         * @param {String} type Type of object (eg. 'circle')\n         * @param {String} namespace Namespace to get klass \"Class\" object from\n         * @return {Object} klass \"Class\"\n         */\n        getKlass: function(type, namespace) {\n            // capitalize first letter only\n            type = fabric.util.string.camelize(type.charAt(0).toUpperCase() + type.slice(1));\n            return fabric.util.resolveNamespace(namespace)[type];\n        },\n\n        /**\n         * Returns object of given namespace\n         * @memberOf fabric.util\n         * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric'\n         * @return {Object} Object for given namespace (default fabric)\n         */\n        resolveNamespace: function(namespace) {\n            if (!namespace) {\n                return fabric;\n            }\n\n            var parts = namespace.split('.'),\n                len = parts.length,\n                obj = global || fabric.window;\n\n            for (var i = 0; i < len; ++i) {\n                obj = obj[parts[i]];\n            }\n\n            return obj;\n        },\n\n        /**\n         * Loads image element from given url and passes it to a callback\n         * @memberOf fabric.util\n         * @param {String} url URL representing an image\n         * @param {Function} callback Callback; invoked with loaded image\n         * @param {Any} [context] Context to invoke callback in\n         * @param {Object} [crossOrigin] crossOrigin value to set image element to\n         */\n        loadImage: function(url, callback, context, crossOrigin) {\n            if (!url) {\n                callback && callback.call(context, url);\n                return;\n            }\n\n            var img = fabric.util.createImage();\n\n            /** @ignore */\n            img.onload = function () {\n                callback && callback.call(context, img);\n                img = img.onload = img.onerror = null;\n            };\n\n            /** @ignore */\n            img.onerror = function() {\n                fabric.log('Error loading ' + img.src);\n                callback && callback.call(context, null, true);\n                img = img.onload = img.onerror = null;\n            };\n\n            // data-urls appear to be buggy with crossOrigin\n            // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767\n            // see https://code.google.com/p/chromium/issues/detail?id=315152\n            //     https://bugzilla.mozilla.org/show_bug.cgi?id=935069\n            if (url.indexOf('data') !== 0 && typeof crossOrigin !== 'undefined') {\n                img.crossOrigin = crossOrigin;\n            }\n\n            img.src = url;\n        },\n\n        /**\n         * Creates corresponding fabric instances from their object representations\n         * @static\n         * @memberOf fabric.util\n         * @param {Array} objects Objects to enliven\n         * @param {Function} callback Callback to invoke when all objects are created\n         * @param {String} namespace Namespace to get klass \"Class\" object from\n         * @param {Function} reviver Method for further parsing of object elements,\n         * called after each fabric object created.\n         */\n        enlivenObjects: function(objects, callback, namespace, reviver) {\n            objects = objects || [ ];\n\n            function onLoaded() {\n                if (++numLoadedObjects === numTotalObjects) {\n                    callback && callback(enlivenedObjects);\n                }\n            }\n\n            var enlivenedObjects = [ ],\n                numLoadedObjects = 0,\n                numTotalObjects = objects.length;\n\n            if (!numTotalObjects) {\n                callback && callback(enlivenedObjects);\n                return;\n            }\n\n            objects.forEach(function (o, index) {\n                // if sparse array\n                if (!o || !o.type) {\n                    onLoaded();\n                    return;\n                }\n                var klass = fabric.util.getKlass(o.type, namespace);\n                if (klass.async) {\n                    klass.fromObject(o, function (obj, error) {\n                        if (!error) {\n                            enlivenedObjects[index] = obj;\n                            reviver && reviver(o, enlivenedObjects[index]);\n                        }\n                        onLoaded();\n                    });\n                }\n                else {\n                    enlivenedObjects[index] = klass.fromObject(o);\n                    reviver && reviver(o, enlivenedObjects[index]);\n                    onLoaded();\n                }\n            });\n        },\n\n        /**\n         * Groups SVG elements (usually those retrieved from SVG document)\n         * @static\n         * @memberOf fabric.util\n         * @param {Array} elements SVG elements to group\n         * @param {Object} [options] Options object\n         * @return {fabric.Object|fabric.PathGroup}\n         */\n        groupSVGElements: function(elements, options, path) {\n            var object;\n\n            object = new fabric.PathGroup(elements, options);\n\n            if (typeof path !== 'undefined') {\n                object.setSourcePath(path);\n            }\n            return object;\n        },\n\n        /**\n         * Populates an object with properties of another object\n         * @static\n         * @memberOf fabric.util\n         * @param {Object} source Source object\n         * @param {Object} destination Destination object\n         * @return {Array} properties Propertie names to include\n         */\n        populateWithProperties: function(source, destination, properties) {\n            if (properties && Object.prototype.toString.call(properties) === '[object Array]') {\n                for (var i = 0, len = properties.length; i < len; i++) {\n                    if (properties[i] in source) {\n                        destination[properties[i]] = source[properties[i]];\n                    }\n                }\n            }\n        },\n\n        /**\n         * Draws a dashed line between two points\n         *\n         * This method is used to draw dashed line around selection area.\n         * See <a href=\"http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas\">dotted stroke in canvas</a>\n         *\n         * @param {CanvasRenderingContext2D} ctx context\n         * @param {Number} x  start x coordinate\n         * @param {Number} y start y coordinate\n         * @param {Number} x2 end x coordinate\n         * @param {Number} y2 end y coordinate\n         * @param {Array} da dash array pattern\n         */\n        drawDashedLine: function(ctx, x, y, x2, y2, da) {\n            var dx = x2 - x,\n                dy = y2 - y,\n                len = sqrt(dx * dx + dy * dy),\n                rot = atan2(dy, dx),\n                dc = da.length,\n                di = 0,\n                draw = true;\n\n            ctx.save();\n            ctx.translate(x, y);\n            ctx.moveTo(0, 0);\n            ctx.rotate(rot);\n\n            x = 0;\n            while (len > x) {\n                x += da[di++ % dc];\n                if (x > len) {\n                    x = len;\n                }\n                ctx[draw ? 'lineTo' : 'moveTo'](x, 0);\n                draw = !draw;\n            }\n\n            ctx.restore();\n        },\n\n        /**\n         * Creates canvas element and initializes it via excanvas if necessary\n         * @static\n         * @memberOf fabric.util\n         * @param {CanvasElement} [canvasEl] optional canvas element to initialize;\n         * when not given, element is created implicitly\n         * @return {CanvasElement} initialized canvas element\n         */\n        createCanvasElement: function(canvasEl) {\n            canvasEl || (canvasEl = fabric.document.createElement('canvas'));\n            //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n            if (!canvasEl.getContext && typeof G_vmlCanvasManager !== 'undefined') {\n                G_vmlCanvasManager.initElement(canvasEl);\n            }\n            //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n            return canvasEl;\n        },\n\n        /**\n         * Creates image element (works on client and node)\n         * @static\n         * @memberOf fabric.util\n         * @return {HTMLImageElement} HTML image element\n         */\n        createImage: function() {\n            return fabric.isLikelyNode\n                ? new (require('canvas').Image)()\n                : fabric.document.createElement('img');\n        },\n\n        /**\n         * Creates accessors (getXXX, setXXX) for a \"class\", based on \"stateProperties\" array\n         * @static\n         * @memberOf fabric.util\n         * @param {Object} klass \"Class\" to create accessors for\n         */\n        createAccessors: function(klass) {\n            var proto = klass.prototype;\n\n            for (var i = proto.stateProperties.length; i--; ) {\n\n                var propName = proto.stateProperties[i],\n                    capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1),\n                    setterName = 'set' + capitalizedPropName,\n                    getterName = 'get' + capitalizedPropName;\n\n                // using `new Function` for better introspection\n                if (!proto[getterName]) {\n                    proto[getterName] = (function(property) {\n                        return new Function('return this.get(\"' + property + '\")');\n                    })(propName);\n                }\n                if (!proto[setterName]) {\n                    proto[setterName] = (function(property) {\n                        return new Function('value', 'return this.set(\"' + property + '\", value)');\n                    })(propName);\n                }\n            }\n        },\n\n        /**\n         * @static\n         * @memberOf fabric.util\n         * @param {fabric.Object} receiver Object implementing `clipTo` method\n         * @param {CanvasRenderingContext2D} ctx Context to clip\n         */\n        clipContext: function(receiver, ctx) {\n            ctx.save();\n            ctx.beginPath();\n            receiver.clipTo(ctx);\n            ctx.clip();\n        },\n\n        /**\n         * Multiply matrix A by matrix B to nest transformations\n         * @static\n         * @memberOf fabric.util\n         * @param  {Array} matrixA First transformMatrix\n         * @param  {Array} matrixB Second transformMatrix\n         * @return {Array} The product of the two transform matrices\n         */\n        multiplyTransformMatrices: function(matrixA, matrixB) {\n            // Matrix multiply matrixA * matrixB\n            var a = [\n                    [matrixA[0], matrixA[2], matrixA[4]],\n                    [matrixA[1], matrixA[3], matrixA[5]],\n                    [0,          0,          1         ]\n                ],\n\n                b = [\n                    [matrixB[0], matrixB[2], matrixB[4]],\n                    [matrixB[1], matrixB[3], matrixB[5]],\n                    [0,          0,          1         ]\n                ],\n\n                result = [];\n\n            for (var r = 0; r < 3; r++) {\n                result[r] = [];\n                for (var c = 0; c < 3; c++) {\n                    var sum = 0;\n                    for (var k = 0; k < 3; k++) {\n                        sum += a[r][k] * b[k][c];\n                    }\n\n                    result[r][c] = sum;\n                }\n            }\n\n            return [\n                result[0][0],\n                result[1][0],\n                result[0][1],\n                result[1][1],\n                result[0][2],\n                result[1][2]\n            ];\n        },\n\n        /**\n         * Returns string representation of function body\n         * @param {Function} fn Function to get body of\n         * @return {String} Function body\n         */\n        getFunctionBody: function(fn) {\n            return (String(fn).match(/function[^{]*\\{([\\s\\S]*)\\}/) || {})[1];\n        },\n\n        /**\n         * Returns true if context has transparent pixel\n         * at specified location (taking tolerance into account)\n         * @param {CanvasRenderingContext2D} ctx context\n         * @param {Number} x x coordinate\n         * @param {Number} y y coordinate\n         * @param {Number} tolerance Tolerance\n         */\n        isTransparent: function(ctx, x, y, tolerance) {\n\n            // If tolerance is > 0 adjust start coords to take into account.\n            // If moves off Canvas fix to 0\n            if (tolerance > 0) {\n                if (x > tolerance) {\n                    x -= tolerance;\n                }\n                else {\n                    x = 0;\n                }\n                if (y > tolerance) {\n                    y -= tolerance;\n                }\n                else {\n                    y = 0;\n                }\n            }\n\n            var _isTransparent = true,\n                imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1);\n\n            // Split image data - for tolerance > 1, pixelDataSize = 4;\n            for (var i = 3, l = imageData.data.length; i < l; i += 4) {\n                var temp = imageData.data[i];\n                _isTransparent = temp <= 0;\n                if (_isTransparent === false) {\n                    break; // Stop if colour found\n                }\n            }\n\n            imageData = null;\n\n            return _isTransparent;\n        }\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n    var arcToSegmentsCache = { },\n        segmentToBezierCache = { },\n        boundsOfCurveCache = { },\n        _join = Array.prototype.join;\n\n    /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp\n     * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here\n     * http://mozilla.org/MPL/2.0/\n     */\n    function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {\n        var argsString = _join.call(arguments);\n        if (arcToSegmentsCache[argsString]) {\n            return arcToSegmentsCache[argsString];\n        }\n\n        var PI = Math.PI, th = rotateX * PI / 180,\n            sinTh = Math.sin(th),\n            cosTh = Math.cos(th),\n            fromX = 0, fromY = 0;\n\n        rx = Math.abs(rx);\n        ry = Math.abs(ry);\n\n        var px = -cosTh * toX * 0.5 - sinTh * toY * 0.5,\n            py = -cosTh * toY * 0.5 + sinTh * toX * 0.5,\n            rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px,\n            pl = rx2 * ry2 - rx2 * py2 - ry2 * px2,\n            root = 0;\n\n        if (pl < 0) {\n            var s = Math.sqrt(1 - pl/(rx2 * ry2));\n            rx *= s;\n            ry *= s;\n        }\n        else {\n            root = (large === sweep ? -1.0 : 1.0) *\n                Math.sqrt( pl /(rx2 * py2 + ry2 * px2));\n        }\n\n        var cx = root * rx * py / ry,\n            cy = -root * ry * px / rx,\n            cx1 = cosTh * cx - sinTh * cy + toX * 0.5,\n            cy1 = sinTh * cx + cosTh * cy + toY * 0.5,\n            mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry),\n            dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px - cx) / rx, (-py - cy) / ry);\n\n        if (sweep === 0 && dtheta > 0) {\n            dtheta -= 2 * PI;\n        }\n        else if (sweep === 1 && dtheta < 0) {\n            dtheta += 2 * PI;\n        }\n\n        // Convert into cubic bezier segments <= 90deg\n        var segments = Math.ceil(Math.abs(dtheta / PI * 2)),\n            result = [], mDelta = dtheta / segments,\n            mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2),\n            th3 = mTheta + mDelta;\n\n        for (var i = 0; i < segments; i++) {\n            result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY);\n            fromX = result[i][4];\n            fromY = result[i][5];\n            mTheta = th3;\n            th3 += mDelta;\n        }\n        arcToSegmentsCache[argsString] = result;\n        return result;\n    }\n\n    function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {\n        var argsString2 = _join.call(arguments);\n        if (segmentToBezierCache[argsString2]) {\n            return segmentToBezierCache[argsString2];\n        }\n\n        var costh2 = Math.cos(th2),\n            sinth2 = Math.sin(th2),\n            costh3 = Math.cos(th3),\n            sinth3 = Math.sin(th3),\n            toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,\n            toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,\n            cp1X = fromX + mT * ( - cosTh * rx * sinth2 - sinTh * ry * costh2),\n            cp1Y = fromY + mT * ( - sinTh * rx * sinth2 + cosTh * ry * costh2),\n            cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),\n            cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);\n\n        segmentToBezierCache[argsString2] = [\n            cp1X, cp1Y,\n            cp2X, cp2Y,\n            toX, toY\n        ];\n        return segmentToBezierCache[argsString2];\n    }\n\n    /*\n     * Private\n     */\n    function calcVectorAngle(ux, uy, vx, vy) {\n        var ta = Math.atan2(uy, ux),\n            tb = Math.atan2(vy, vx);\n        if (tb >= ta) {\n            return tb - ta;\n        }\n        else {\n            return 2 * Math.PI - (ta - tb);\n        }\n    }\n\n    /**\n     * Draws arc\n     * @param {CanvasRenderingContext2D} ctx\n     * @param {Number} fx\n     * @param {Number} fy\n     * @param {Array} coords\n     */\n    fabric.util.drawArc = function(ctx, fx, fy, coords) {\n        var rx = coords[0],\n            ry = coords[1],\n            rot = coords[2],\n            large = coords[3],\n            sweep = coords[4],\n            tx = coords[5],\n            ty = coords[6],\n            segs = [[ ], [ ], [ ], [ ]],\n            segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);\n\n        for (var i = 0, len = segsNorm.length; i < len; i++) {\n            segs[i][0] = segsNorm[i][0] + fx;\n            segs[i][1] = segsNorm[i][1] + fy;\n            segs[i][2] = segsNorm[i][2] + fx;\n            segs[i][3] = segsNorm[i][3] + fy;\n            segs[i][4] = segsNorm[i][4] + fx;\n            segs[i][5] = segsNorm[i][5] + fy;\n            ctx.bezierCurveTo.apply(ctx, segs[i]);\n        }\n    };\n\n    /**\n     * Calculate bounding box of a elliptic-arc\n     * @param {Number} fx start point of arc\n     * @param {Number} fy\n     * @param {Number} rx horizontal radius\n     * @param {Number} ry vertical radius\n     * @param {Number} rot angle of horizontal axe\n     * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points\n     * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction\n     * @param {Number} tx end point of arc\n     * @param {Number} ty\n     */\n    fabric.util.getBoundsOfArc = function(fx, fy, rx, ry, rot, large, sweep, tx, ty) {\n\n        var fromX = 0, fromY = 0, bound = [ ], bounds = [ ],\n            segs = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);\n\n        for (var i = 0, len = segs.length; i < len; i++) {\n            bound = getBoundsOfCurve(fromX, fromY, segs[i][0], segs[i][1], segs[i][2], segs[i][3], segs[i][4], segs[i][5]);\n            bound[0].x += fx;\n            bound[0].y += fy;\n            bound[1].x += fx;\n            bound[1].y += fy;\n            bounds.push(bound[0]);\n            bounds.push(bound[1]);\n            fromX = segs[i][4];\n            fromY = segs[i][5];\n        }\n        return bounds;\n    };\n\n    /**\n     * Calculate bounding box of a beziercurve\n     * @param {Number} x0 starting point\n     * @param {Number} y0\n     * @param {Number} x1 first control point\n     * @param {Number} y1\n     * @param {Number} x2 secondo control point\n     * @param {Number} y2\n     * @param {Number} x3 end of beizer\n     * @param {Number} y3\n     */\n        // taken from http://jsbin.com/ivomiq/56/edit  no credits available for that.\n    function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {\n        var argsString = _join.call(arguments);\n        if (boundsOfCurveCache[argsString]) {\n            return boundsOfCurveCache[argsString];\n        }\n\n        var sqrt = Math.sqrt,\n            min = Math.min, max = Math.max,\n            abs = Math.abs, tvalues = [ ],\n            bounds = [[ ], [ ]],\n            a, b, c, t, t1, t2, b2ac, sqrtb2ac;\n\n        b = 6 * x0 - 12 * x1 + 6 * x2;\n        a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;\n        c = 3 * x1 - 3 * x0;\n\n        for (var i = 0; i < 2; ++i) {\n            if (i > 0) {\n                b = 6 * y0 - 12 * y1 + 6 * y2;\n                a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;\n                c = 3 * y1 - 3 * y0;\n            }\n\n            if (abs(a) < 1e-12) {\n                if (abs(b) < 1e-12) {\n                    continue;\n                }\n                t = -c / b;\n                if (0 < t && t < 1) {\n                    tvalues.push(t);\n                }\n                continue;\n            }\n            b2ac = b * b - 4 * c * a;\n            if (b2ac < 0) {\n                continue;\n            }\n            sqrtb2ac = sqrt(b2ac);\n            t1 = (-b + sqrtb2ac) / (2 * a);\n            if (0 < t1 && t1 < 1) {\n                tvalues.push(t1);\n            }\n            t2 = (-b - sqrtb2ac) / (2 * a);\n            if (0 < t2 && t2 < 1) {\n                tvalues.push(t2);\n            }\n        }\n\n        var x, y, j = tvalues.length, jlen = j, mt;\n        while (j--) {\n            t = tvalues[j];\n            mt = 1 - t;\n            x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);\n            bounds[0][j] = x;\n\n            y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);\n            bounds[1][j] = y;\n        }\n\n        bounds[0][jlen] = x0;\n        bounds[1][jlen] = y0;\n        bounds[0][jlen + 1] = x3;\n        bounds[1][jlen + 1] = y3;\n        var result = [\n            {\n                x: min.apply(null, bounds[0]),\n                y: min.apply(null, bounds[1])\n            },\n            {\n                x: max.apply(null, bounds[0]),\n                y: max.apply(null, bounds[1])\n            }\n        ];\n        boundsOfCurveCache[argsString] = result;\n        return result;\n    }\n\n    fabric.util.getBoundsOfCurve = getBoundsOfCurve;\n\n})();\n\n\n(function() {\n\n    var slice = Array.prototype.slice;\n\n    /* _ES5_COMPAT_START_ */\n\n    if (!Array.prototype.indexOf) {\n        /**\n         * Finds index of an element in an array\n         * @param {Any} searchElement\n         * @param {Number} [fromIndex]\n         * @return {Number}\n         */\n        Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {\n            if (this === void 0 || this === null) {\n                throw new TypeError();\n            }\n            var t = Object(this), len = t.length >>> 0;\n            if (len === 0) {\n                return -1;\n            }\n            var n = 0;\n            if (arguments.length > 0) {\n                n = Number(arguments[1]);\n                if (n !== n) { // shortcut for verifying if it's NaN\n                    n = 0;\n                }\n                else if (n !== 0 && n !== Number.POSITIVE_INFINITY && n !== Number.NEGATIVE_INFINITY) {\n                    n = (n > 0 || -1) * Math.floor(Math.abs(n));\n                }\n            }\n            if (n >= len) {\n                return -1;\n            }\n            var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);\n            for (; k < len; k++) {\n                if (k in t && t[k] === searchElement) {\n                    return k;\n                }\n            }\n            return -1;\n        };\n    }\n\n    if (!Array.prototype.forEach) {\n        /**\n         * Iterates an array, invoking callback for each element\n         * @param {Function} fn Callback to invoke for each element\n         * @param {Object} [context] Context to invoke callback in\n         * @return {Array}\n         */\n        Array.prototype.forEach = function(fn, context) {\n            for (var i = 0, len = this.length >>> 0; i < len; i++) {\n                if (i in this) {\n                    fn.call(context, this[i], i, this);\n                }\n            }\n        };\n    }\n\n    if (!Array.prototype.map) {\n        /**\n         * Returns a result of iterating over an array, invoking callback for each element\n         * @param {Function} fn Callback to invoke for each element\n         * @param {Object} [context] Context to invoke callback in\n         * @return {Array}\n         */\n        Array.prototype.map = function(fn, context) {\n            var result = [ ];\n            for (var i = 0, len = this.length >>> 0; i < len; i++) {\n                if (i in this) {\n                    result[i] = fn.call(context, this[i], i, this);\n                }\n            }\n            return result;\n        };\n    }\n\n    if (!Array.prototype.every) {\n        /**\n         * Returns true if a callback returns truthy value for all elements in an array\n         * @param {Function} fn Callback to invoke for each element\n         * @param {Object} [context] Context to invoke callback in\n         * @return {Boolean}\n         */\n        Array.prototype.every = function(fn, context) {\n            for (var i = 0, len = this.length >>> 0; i < len; i++) {\n                if (i in this && !fn.call(context, this[i], i, this)) {\n                    return false;\n                }\n            }\n            return true;\n        };\n    }\n\n    if (!Array.prototype.some) {\n        /**\n         * Returns true if a callback returns truthy value for at least one element in an array\n         * @param {Function} fn Callback to invoke for each element\n         * @param {Object} [context] Context to invoke callback in\n         * @return {Boolean}\n         */\n        Array.prototype.some = function(fn, context) {\n            for (var i = 0, len = this.length >>> 0; i < len; i++) {\n                if (i in this && fn.call(context, this[i], i, this)) {\n                    return true;\n                }\n            }\n            return false;\n        };\n    }\n\n    if (!Array.prototype.filter) {\n        /**\n         * Returns the result of iterating over elements in an array\n         * @param {Function} fn Callback to invoke for each element\n         * @param {Object} [context] Context to invoke callback in\n         * @return {Array}\n         */\n        Array.prototype.filter = function(fn, context) {\n            var result = [ ], val;\n            for (var i = 0, len = this.length >>> 0; i < len; i++) {\n                if (i in this) {\n                    val = this[i]; // in case fn mutates this\n                    if (fn.call(context, val, i, this)) {\n                        result.push(val);\n                    }\n                }\n            }\n            return result;\n        };\n    }\n\n    if (!Array.prototype.reduce) {\n        /**\n         * Returns \"folded\" (reduced) result of iterating over elements in an array\n         * @param {Function} fn Callback to invoke for each element\n         * @param {Object} [initial] Object to use as the first argument to the first call of the callback\n         * @return {Any}\n         */\n        Array.prototype.reduce = function(fn /*, initial*/) {\n            var len = this.length >>> 0,\n                i = 0,\n                rv;\n\n            if (arguments.length > 1) {\n                rv = arguments[1];\n            }\n            else {\n                do {\n                    if (i in this) {\n                        rv = this[i++];\n                        break;\n                    }\n                    // if array contains no values, no initial value to return\n                    if (++i >= len) {\n                        throw new TypeError();\n                    }\n                }\n                while (true);\n            }\n            for (; i < len; i++) {\n                if (i in this) {\n                    rv = fn.call(null, rv, this[i], i, this);\n                }\n            }\n            return rv;\n        };\n    }\n\n    /* _ES5_COMPAT_END_ */\n\n    /**\n     * Invokes method on all items in a given array\n     * @memberOf fabric.util.array\n     * @param {Array} array Array to iterate over\n     * @param {String} method Name of a method to invoke\n     * @return {Array}\n     */\n    function invoke(array, method) {\n        var args = slice.call(arguments, 2), result = [ ];\n        for (var i = 0, len = array.length; i < len; i++) {\n            result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]);\n        }\n        return result;\n    }\n\n    /**\n     * Finds maximum value in array (not necessarily \"first\" one)\n     * @memberOf fabric.util.array\n     * @param {Array} array Array to iterate over\n     * @param {String} byProperty\n     * @return {Any}\n     */\n    function max(array, byProperty) {\n        return find(array, byProperty, function(value1, value2) {\n            return value1 >= value2;\n        });\n    }\n\n    /**\n     * Finds minimum value in array (not necessarily \"first\" one)\n     * @memberOf fabric.util.array\n     * @param {Array} array Array to iterate over\n     * @param {String} byProperty\n     * @return {Any}\n     */\n    function min(array, byProperty) {\n        return find(array, byProperty, function(value1, value2) {\n            return value1 < value2;\n        });\n    }\n\n    /**\n     * @private\n     */\n    function find(array, byProperty, condition) {\n        if (!array || array.length === 0) {\n            return;\n        }\n\n        var i = array.length - 1,\n            result = byProperty ? array[i][byProperty] : array[i];\n        if (byProperty) {\n            while (i--) {\n                if (condition(array[i][byProperty], result)) {\n                    result = array[i][byProperty];\n                }\n            }\n        }\n        else {\n            while (i--) {\n                if (condition(array[i], result)) {\n                    result = array[i];\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @namespace fabric.util.array\n     */\n    fabric.util.array = {\n        invoke: invoke,\n        min: min,\n        max: max\n    };\n\n})();\n\n\n(function() {\n\n    /**\n     * Copies all enumerable properties of one object to another\n     * @memberOf fabric.util.object\n     * @param {Object} destination Where to copy to\n     * @param {Object} source Where to copy from\n     * @return {Object}\n     */\n    function extend(destination, source) {\n        // JScript DontEnum bug is not taken care of\n        for (var property in source) {\n            destination[property] = source[property];\n        }\n        return destination;\n    }\n\n    /**\n     * Creates an empty object and copies all enumerable properties of another object to it\n     * @memberOf fabric.util.object\n     * @param {Object} object Object to clone\n     * @return {Object}\n     */\n    function clone(object) {\n        return extend({ }, object);\n    }\n\n    /** @namespace fabric.util.object */\n    fabric.util.object = {\n        extend: extend,\n        clone: clone\n    };\n\n})();\n\n\n(function() {\n\n    /* _ES5_COMPAT_START_ */\n    if (!String.prototype.trim) {\n        /**\n         * Trims a string (removing whitespace from the beginning and the end)\n         * @function external:String#trim\n         * @see <a href=\"https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim\">String#trim on MDN</a>\n         */\n        String.prototype.trim = function () {\n            // this trim is not fully ES3 or ES5 compliant, but it should cover most cases for now\n            return this.replace(/^[\\s\\xA0]+/, '').replace(/[\\s\\xA0]+$/, '');\n        };\n    }\n    /* _ES5_COMPAT_END_ */\n\n    /**\n     * Camelizes a string\n     * @memberOf fabric.util.string\n     * @param {String} string String to camelize\n     * @return {String} Camelized version of a string\n     */\n    function camelize(string) {\n        return string.replace(/-+(.)?/g, function(match, character) {\n            return character ? character.toUpperCase() : '';\n        });\n    }\n\n    /**\n     * Capitalizes a string\n     * @memberOf fabric.util.string\n     * @param {String} string String to capitalize\n     * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized\n     * and other letters stay untouched, if false first letter is capitalized\n     * and other letters are converted to lowercase.\n     * @return {String} Capitalized version of a string\n     */\n    function capitalize(string, firstLetterOnly) {\n        return string.charAt(0).toUpperCase() +\n            (firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase());\n    }\n\n    /**\n     * Escapes XML in a string\n     * @memberOf fabric.util.string\n     * @param {String} string String to escape\n     * @return {String} Escaped version of a string\n     */\n    function escapeXml(string) {\n        return string.replace(/&/g, '&amp;')\n            .replace(/\"/g, '&quot;')\n            .replace(/'/g, '&apos;')\n            .replace(/</g, '&lt;')\n            .replace(/>/g, '&gt;');\n    }\n\n    /**\n     * String utilities\n     * @namespace fabric.util.string\n     */\n    fabric.util.string = {\n        camelize: camelize,\n        capitalize: capitalize,\n        escapeXml: escapeXml\n    };\n}());\n\n\n/* _ES5_COMPAT_START_ */\n(function() {\n\n    var slice = Array.prototype.slice,\n        apply = Function.prototype.apply,\n        Dummy = function() { };\n\n    if (!Function.prototype.bind) {\n        /**\n         * Cross-browser approximation of ES5 Function.prototype.bind (not fully spec conforming)\n         * @see <a href=\"https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind\">Function#bind on MDN</a>\n         * @param {Object} thisArg Object to bind function to\n         * @param {Any[]} [...] Values to pass to a bound function\n         * @return {Function}\n         */\n        Function.prototype.bind = function(thisArg) {\n            var _this = this, args = slice.call(arguments, 1), bound;\n            if (args.length) {\n                bound = function() {\n                    return apply.call(_this, this instanceof Dummy ? this : thisArg, args.concat(slice.call(arguments)));\n                };\n            }\n            else {\n                /** @ignore */\n                bound = function() {\n                    return apply.call(_this, this instanceof Dummy ? this : thisArg, arguments);\n                };\n            }\n            Dummy.prototype = this.prototype;\n            bound.prototype = new Dummy();\n\n            return bound;\n        };\n    }\n\n})();\n/* _ES5_COMPAT_END_ */\n\n\n(function() {\n\n    var slice = Array.prototype.slice, emptyFunction = function() { },\n\n        IS_DONTENUM_BUGGY = (function() {\n            for (var p in { toString: 1 }) {\n                if (p === 'toString') {\n                    return false;\n                }\n            }\n            return true;\n        })(),\n\n        /** @ignore */\n        addMethods = function(klass, source, parent) {\n            for (var property in source) {\n\n                if (property in klass.prototype &&\n                    typeof klass.prototype[property] === 'function' &&\n                    (source[property] + '').indexOf('callSuper') > -1) {\n\n                    klass.prototype[property] = (function(property) {\n                        return function() {\n\n                            var superclass = this.constructor.superclass;\n                            this.constructor.superclass = parent;\n                            var returnValue = source[property].apply(this, arguments);\n                            this.constructor.superclass = superclass;\n\n                            if (property !== 'initialize') {\n                                return returnValue;\n                            }\n                        };\n                    })(property);\n                }\n                else {\n                    klass.prototype[property] = source[property];\n                }\n\n                if (IS_DONTENUM_BUGGY) {\n                    if (source.toString !== Object.prototype.toString) {\n                        klass.prototype.toString = source.toString;\n                    }\n                    if (source.valueOf !== Object.prototype.valueOf) {\n                        klass.prototype.valueOf = source.valueOf;\n                    }\n                }\n            }\n        };\n\n    function Subclass() { }\n\n    function callSuper(methodName) {\n        var fn = this.constructor.superclass.prototype[methodName];\n        return (arguments.length > 1)\n            ? fn.apply(this, slice.call(arguments, 1))\n            : fn.call(this);\n    }\n\n    /**\n     * Helper for creation of \"classes\".\n     * @memberOf fabric.util\n     * @param {Function} [parent] optional \"Class\" to inherit from\n     * @param {Object} [properties] Properties shared by all instances of this class\n     *                  (be careful modifying objects defined here as this would affect all instances)\n     */\n    function createClass() {\n        var parent = null,\n            properties = slice.call(arguments, 0);\n\n        if (typeof properties[0] === 'function') {\n            parent = properties.shift();\n        }\n        function klass() {\n            this.initialize.apply(this, arguments);\n        }\n\n        klass.superclass = parent;\n        klass.subclasses = [ ];\n\n        if (parent) {\n            Subclass.prototype = parent.prototype;\n            klass.prototype = new Subclass();\n            parent.subclasses.push(klass);\n        }\n        for (var i = 0, length = properties.length; i < length; i++) {\n            addMethods(klass, properties[i], parent);\n        }\n        if (!klass.prototype.initialize) {\n            klass.prototype.initialize = emptyFunction;\n        }\n        klass.prototype.constructor = klass;\n        klass.prototype.callSuper = callSuper;\n        return klass;\n    }\n\n    fabric.util.createClass = createClass;\n})();\n\n\n(function () {\n\n    var unknown = 'unknown';\n\n    /* EVENT HANDLING */\n\n    function areHostMethods(object) {\n        var methodNames = Array.prototype.slice.call(arguments, 1),\n            t, i, len = methodNames.length;\n        for (i = 0; i < len; i++) {\n            t = typeof object[methodNames[i]];\n            if (!(/^(?:function|object|unknown)$/).test(t)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /** @ignore */\n    var getElement,\n        setElement,\n        getUniqueId = (function () {\n            var uid = 0;\n            return function (element) {\n                return element.__uniqueID || (element.__uniqueID = 'uniqueID__' + uid++);\n            };\n        })();\n\n    (function () {\n        var elements = { };\n        /** @ignore */\n        getElement = function (uid) {\n            return elements[uid];\n        };\n        /** @ignore */\n        setElement = function (uid, element) {\n            elements[uid] = element;\n        };\n    })();\n\n    function createListener(uid, handler) {\n        return {\n            handler: handler,\n            wrappedHandler: createWrappedHandler(uid, handler)\n        };\n    }\n\n    function createWrappedHandler(uid, handler) {\n        return function (e) {\n            handler.call(getElement(uid), e || fabric.window.event);\n        };\n    }\n\n    function createDispatcher(uid, eventName) {\n        return function (e) {\n            if (handlers[uid] && handlers[uid][eventName]) {\n                var handlersForEvent = handlers[uid][eventName];\n                for (var i = 0, len = handlersForEvent.length; i < len; i++) {\n                    handlersForEvent[i].call(this, e || fabric.window.event);\n                }\n            }\n        };\n    }\n\n    var shouldUseAddListenerRemoveListener = (\n            areHostMethods(fabric.document.documentElement, 'addEventListener', 'removeEventListener') &&\n            areHostMethods(fabric.window, 'addEventListener', 'removeEventListener')),\n\n        shouldUseAttachEventDetachEvent = (\n            areHostMethods(fabric.document.documentElement, 'attachEvent', 'detachEvent') &&\n            areHostMethods(fabric.window, 'attachEvent', 'detachEvent')),\n\n    // IE branch\n        listeners = { },\n\n    // DOM L0 branch\n        handlers = { },\n\n        addListener, removeListener;\n\n    if (shouldUseAddListenerRemoveListener) {\n        /** @ignore */\n        addListener = function (element, eventName, handler) {\n            element.addEventListener(eventName, handler, false);\n        };\n        /** @ignore */\n        removeListener = function (element, eventName, handler) {\n            element.removeEventListener(eventName, handler, false);\n        };\n    }\n\n    else if (shouldUseAttachEventDetachEvent) {\n        /** @ignore */\n        addListener = function (element, eventName, handler) {\n            var uid = getUniqueId(element);\n            setElement(uid, element);\n            if (!listeners[uid]) {\n                listeners[uid] = { };\n            }\n            if (!listeners[uid][eventName]) {\n                listeners[uid][eventName] = [ ];\n\n            }\n            var listener = createListener(uid, handler);\n            listeners[uid][eventName].push(listener);\n            element.attachEvent('on' + eventName, listener.wrappedHandler);\n        };\n        /** @ignore */\n        removeListener = function (element, eventName, handler) {\n            var uid = getUniqueId(element), listener;\n            if (listeners[uid] && listeners[uid][eventName]) {\n                for (var i = 0, len = listeners[uid][eventName].length; i < len; i++) {\n                    listener = listeners[uid][eventName][i];\n                    if (listener && listener.handler === handler) {\n                        element.detachEvent('on' + eventName, listener.wrappedHandler);\n                        listeners[uid][eventName][i] = null;\n                    }\n                }\n            }\n        };\n    }\n    else {\n        /** @ignore */\n        addListener = function (element, eventName, handler) {\n            var uid = getUniqueId(element);\n            if (!handlers[uid]) {\n                handlers[uid] = { };\n            }\n            if (!handlers[uid][eventName]) {\n                handlers[uid][eventName] = [ ];\n                var existingHandler = element['on' + eventName];\n                if (existingHandler) {\n                    handlers[uid][eventName].push(existingHandler);\n                }\n                element['on' + eventName] = createDispatcher(uid, eventName);\n            }\n            handlers[uid][eventName].push(handler);\n        };\n        /** @ignore */\n        removeListener = function (element, eventName, handler) {\n            var uid = getUniqueId(element);\n            if (handlers[uid] && handlers[uid][eventName]) {\n                var handlersForEvent = handlers[uid][eventName];\n                for (var i = 0, len = handlersForEvent.length; i < len; i++) {\n                    if (handlersForEvent[i] === handler) {\n                        handlersForEvent.splice(i, 1);\n                    }\n                }\n            }\n        };\n    }\n\n    /**\n     * Adds an event listener to an element\n     * @function\n     * @memberOf fabric.util\n     * @param {HTMLElement} element\n     * @param {String} eventName\n     * @param {Function} handler\n     */\n    fabric.util.addListener = addListener;\n\n    /**\n     * Removes an event listener from an element\n     * @function\n     * @memberOf fabric.util\n     * @param {HTMLElement} element\n     * @param {String} eventName\n     * @param {Function} handler\n     */\n    fabric.util.removeListener = removeListener;\n\n    /**\n     * Cross-browser wrapper for getting event's coordinates\n     * @memberOf fabric.util\n     * @param {Event} event Event object\n     * @param {HTMLCanvasElement} upperCanvasEl &lt;canvas> element on which object selection is drawn\n     */\n    function getPointer(event, upperCanvasEl) {\n        event || (event = fabric.window.event);\n\n        var element = event.target ||\n                (typeof event.srcElement !== unknown ? event.srcElement : null),\n\n            scroll = fabric.util.getScrollLeftTop(element, upperCanvasEl);\n\n        return {\n            x: pointerX(event) + scroll.left,\n            y: pointerY(event) + scroll.top\n        };\n    }\n\n    var pointerX = function(event) {\n            // looks like in IE (<9) clientX at certain point (apparently when mouseup fires on VML element)\n            // is represented as COM object, with all the consequences, like \"unknown\" type and error on [[Get]]\n            // need to investigate later\n            return (typeof event.clientX !== unknown ? event.clientX : 0);\n        },\n\n        pointerY = function(event) {\n            return (typeof event.clientY !== unknown ? event.clientY : 0);\n        };\n\n    function _getPointer(event, pageProp, clientProp) {\n        var touchProp = event.type === 'touchend' ? 'changedTouches' : 'touches';\n\n        return (event[touchProp] && event[touchProp][0]\n            ? (event[touchProp][0][pageProp] - (event[touchProp][0][pageProp] - event[touchProp][0][clientProp]))\n            || event[clientProp]\n            : event[clientProp]);\n    }\n\n    if (fabric.isTouchSupported) {\n        pointerX = function(event) {\n            return _getPointer(event, 'pageX', 'clientX');\n        };\n        pointerY = function(event) {\n            return _getPointer(event, 'pageY', 'clientY');\n        };\n    }\n\n    fabric.util.getPointer = getPointer;\n\n    fabric.util.object.extend(fabric.util, fabric.Observable);\n\n})();\n\n\n(function () {\n\n    /**\n     * Cross-browser wrapper for setting element's style\n     * @memberOf fabric.util\n     * @param {HTMLElement} element\n     * @param {Object} styles\n     * @return {HTMLElement} Element that was passed as a first argument\n     */\n    function setStyle(element, styles) {\n        var elementStyle = element.style;\n        if (!elementStyle) {\n            return element;\n        }\n        if (typeof styles === 'string') {\n            element.style.cssText += ';' + styles;\n            return styles.indexOf('opacity') > -1\n                ? setOpacity(element, styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1])\n                : element;\n        }\n        for (var property in styles) {\n            if (property === 'opacity') {\n                setOpacity(element, styles[property]);\n            }\n            else {\n                var normalizedProperty = (property === 'float' || property === 'cssFloat')\n                    ? (typeof elementStyle.styleFloat === 'undefined' ? 'cssFloat' : 'styleFloat')\n                    : property;\n                elementStyle[normalizedProperty] = styles[property];\n            }\n        }\n        return element;\n    }\n\n    var parseEl = fabric.document.createElement('div'),\n        supportsOpacity = typeof parseEl.style.opacity === 'string',\n        supportsFilters = typeof parseEl.style.filter === 'string',\n        reOpacity = /alpha\\s*\\(\\s*opacity\\s*=\\s*([^\\)]+)\\)/,\n\n        /** @ignore */\n        setOpacity = function (element) { return element; };\n\n    if (supportsOpacity) {\n        /** @ignore */\n        setOpacity = function(element, value) {\n            element.style.opacity = value;\n            return element;\n        };\n    }\n    else if (supportsFilters) {\n        /** @ignore */\n        setOpacity = function(element, value) {\n            var es = element.style;\n            if (element.currentStyle && !element.currentStyle.hasLayout) {\n                es.zoom = 1;\n            }\n            if (reOpacity.test(es.filter)) {\n                value = value >= 0.9999 ? '' : ('alpha(opacity=' + (value * 100) + ')');\n                es.filter = es.filter.replace(reOpacity, value);\n            }\n            else {\n                es.filter += ' alpha(opacity=' + (value * 100) + ')';\n            }\n            return element;\n        };\n    }\n\n    fabric.util.setStyle = setStyle;\n\n})();\n\n\n(function() {\n\n    var _slice = Array.prototype.slice;\n\n    /**\n     * Takes id and returns an element with that id (if one exists in a document)\n     * @memberOf fabric.util\n     * @param {String|HTMLElement} id\n     * @return {HTMLElement|null}\n     */\n    function getById(id) {\n        return typeof id === 'string' ? fabric.document.getElementById(id) : id;\n    }\n\n    var sliceCanConvertNodelists,\n        /**\n         * Converts an array-like object (e.g. arguments or NodeList) to an array\n         * @memberOf fabric.util\n         * @param {Object} arrayLike\n         * @return {Array}\n         */\n        toArray = function(arrayLike) {\n            return _slice.call(arrayLike, 0);\n        };\n\n    try {\n        sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array;\n    }\n    catch (err) { }\n\n    if (!sliceCanConvertNodelists) {\n        toArray = function(arrayLike) {\n            var arr = new Array(arrayLike.length), i = arrayLike.length;\n            while (i--) {\n                arr[i] = arrayLike[i];\n            }\n            return arr;\n        };\n    }\n\n    /**\n     * Creates specified element with specified attributes\n     * @memberOf fabric.util\n     * @param {String} tagName Type of an element to create\n     * @param {Object} [attributes] Attributes to set on an element\n     * @return {HTMLElement} Newly created element\n     */\n    function makeElement(tagName, attributes) {\n        var el = fabric.document.createElement(tagName);\n        for (var prop in attributes) {\n            if (prop === 'class') {\n                el.className = attributes[prop];\n            }\n            else if (prop === 'for') {\n                el.htmlFor = attributes[prop];\n            }\n            else {\n                el.setAttribute(prop, attributes[prop]);\n            }\n        }\n        return el;\n    }\n\n    /**\n     * Adds class to an element\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to add class to\n     * @param {String} className Class to add to an element\n     */\n    function addClass(element, className) {\n        if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) {\n            element.className += (element.className ? ' ' : '') + className;\n        }\n    }\n\n    /**\n     * Wraps element with another element\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to wrap\n     * @param {HTMLElement|String} wrapper Element to wrap with\n     * @param {Object} [attributes] Attributes to set on a wrapper\n     * @return {HTMLElement} wrapper\n     */\n    function wrapElement(element, wrapper, attributes) {\n        if (typeof wrapper === 'string') {\n            wrapper = makeElement(wrapper, attributes);\n        }\n        if (element.parentNode) {\n            element.parentNode.replaceChild(wrapper, element);\n        }\n        wrapper.appendChild(element);\n        return wrapper;\n    }\n\n    /**\n     * Returns element scroll offsets\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to operate on\n     * @param {HTMLElement} upperCanvasEl Upper canvas element\n     * @return {Object} Object with left/top values\n     */\n    function getScrollLeftTop(element, upperCanvasEl) {\n\n        var firstFixedAncestor,\n            origElement,\n            left = 0,\n            top = 0,\n            docElement = fabric.document.documentElement,\n            body = fabric.document.body || {\n                scrollLeft: 0, scrollTop: 0\n            };\n\n        origElement = element;\n\n        while (element && element.parentNode && !firstFixedAncestor) {\n\n            element = element.parentNode;\n\n            if (element.nodeType === 1 &&\n                fabric.util.getElementStyle(element, 'position') === 'fixed') {\n                firstFixedAncestor = element;\n            }\n\n            if (element.nodeType === 1 &&\n                origElement !== upperCanvasEl &&\n                fabric.util.getElementStyle(element, 'position') === 'absolute') {\n                left = 0;\n                top = 0;\n            }\n            else if (element === fabric.document) {\n                left = body.scrollLeft || docElement.scrollLeft || 0;\n                top = body.scrollTop ||  docElement.scrollTop || 0;\n            }\n            else {\n                left += element.scrollLeft || 0;\n                top += element.scrollTop || 0;\n            }\n        }\n\n        return { left: left, top: top };\n    }\n\n    /**\n     * Returns offset for a given element\n     * @function\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to get offset for\n     * @return {Object} Object with \"left\" and \"top\" properties\n     */\n    function getElementOffset(element) {\n        var docElem,\n            doc = element && element.ownerDocument,\n            box = { left: 0, top: 0 },\n            offset = { left: 0, top: 0 },\n            scrollLeftTop,\n            offsetAttributes = {\n                borderLeftWidth: 'left',\n                borderTopWidth:  'top',\n                paddingLeft:     'left',\n                paddingTop:      'top'\n            };\n\n        if (!doc) {\n            return { left: 0, top: 0 };\n        }\n\n        for (var attr in offsetAttributes) {\n            offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0;\n        }\n\n        docElem = doc.documentElement;\n        if ( typeof element.getBoundingClientRect !== 'undefined' ) {\n            box = element.getBoundingClientRect();\n        }\n\n        scrollLeftTop = fabric.util.getScrollLeftTop(element, null);\n\n        return {\n            left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left,\n            top: box.top + scrollLeftTop.top - (docElem.clientTop || 0)  + offset.top\n        };\n    }\n\n    /**\n     * Returns style attribute value of a given element\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to get style attribute for\n     * @param {String} attr Style attribute to get for element\n     * @return {String} Style attribute value of the given element.\n     */\n    var getElementStyle;\n    if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) {\n        getElementStyle = function(element, attr) {\n            var style = fabric.document.defaultView.getComputedStyle(element, null);\n            return style ? style[attr] : undefined;\n        };\n    }\n    else {\n        getElementStyle = function(element, attr) {\n            var value = element.style[attr];\n            if (!value && element.currentStyle) {\n                value = element.currentStyle[attr];\n            }\n            return value;\n        };\n    }\n\n    (function () {\n        var style = fabric.document.documentElement.style,\n            selectProp = 'userSelect' in style\n                ? 'userSelect'\n                : 'MozUserSelect' in style\n                ? 'MozUserSelect'\n                : 'WebkitUserSelect' in style\n                ? 'WebkitUserSelect'\n                : 'KhtmlUserSelect' in style\n                ? 'KhtmlUserSelect'\n                : '';\n\n        /**\n         * Makes element unselectable\n         * @memberOf fabric.util\n         * @param {HTMLElement} element Element to make unselectable\n         * @return {HTMLElement} Element that was passed in\n         */\n        function makeElementUnselectable(element) {\n            if (typeof element.onselectstart !== 'undefined') {\n                element.onselectstart = fabric.util.falseFunction;\n            }\n            if (selectProp) {\n                element.style[selectProp] = 'none';\n            }\n            else if (typeof element.unselectable === 'string') {\n                element.unselectable = 'on';\n            }\n            return element;\n        }\n\n        /**\n         * Makes element selectable\n         * @memberOf fabric.util\n         * @param {HTMLElement} element Element to make selectable\n         * @return {HTMLElement} Element that was passed in\n         */\n        function makeElementSelectable(element) {\n            if (typeof element.onselectstart !== 'undefined') {\n                element.onselectstart = null;\n            }\n            if (selectProp) {\n                element.style[selectProp] = '';\n            }\n            else if (typeof element.unselectable === 'string') {\n                element.unselectable = '';\n            }\n            return element;\n        }\n\n        fabric.util.makeElementUnselectable = makeElementUnselectable;\n        fabric.util.makeElementSelectable = makeElementSelectable;\n    })();\n\n    (function() {\n\n        /**\n         * Inserts a script element with a given url into a document; invokes callback, when that script is finished loading\n         * @memberOf fabric.util\n         * @param {String} url URL of a script to load\n         * @param {Function} callback Callback to execute when script is finished loading\n         */\n        function getScript(url, callback) {\n            var headEl = fabric.document.getElementsByTagName('head')[0],\n                scriptEl = fabric.document.createElement('script'),\n                loading = true;\n\n            /** @ignore */\n            scriptEl.onload = /** @ignore */ scriptEl.onreadystatechange = function(e) {\n                if (loading) {\n                    if (typeof this.readyState === 'string' &&\n                        this.readyState !== 'loaded' &&\n                        this.readyState !== 'complete') {\n                        return;\n                    }\n                    loading = false;\n                    callback(e || fabric.window.event);\n                    scriptEl = scriptEl.onload = scriptEl.onreadystatechange = null;\n                }\n            };\n            scriptEl.src = url;\n            headEl.appendChild(scriptEl);\n            // causes issue in Opera\n            // headEl.removeChild(scriptEl);\n        }\n\n        fabric.util.getScript = getScript;\n    })();\n\n    fabric.util.getById = getById;\n    fabric.util.toArray = toArray;\n    fabric.util.makeElement = makeElement;\n    fabric.util.addClass = addClass;\n    fabric.util.wrapElement = wrapElement;\n    fabric.util.getScrollLeftTop = getScrollLeftTop;\n    fabric.util.getElementOffset = getElementOffset;\n    fabric.util.getElementStyle = getElementStyle;\n\n})();\n\n\n(function() {\n\n    function addParamToUrl(url, param) {\n        return url + (/\\?/.test(url) ? '&' : '?') + param;\n    }\n\n    var makeXHR = (function() {\n        var factories = [\n            function() { return new ActiveXObject('Microsoft.XMLHTTP'); },\n            function() { return new ActiveXObject('Msxml2.XMLHTTP'); },\n            function() { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); },\n            function() { return new XMLHttpRequest(); }\n        ];\n        for (var i = factories.length; i--; ) {\n            try {\n                var req = factories[i]();\n                if (req) {\n                    return factories[i];\n                }\n            }\n            catch (err) { }\n        }\n    })();\n\n    function emptyFn() { }\n\n    /**\n     * Cross-browser abstraction for sending XMLHttpRequest\n     * @memberOf fabric.util\n     * @param {String} url URL to send XMLHttpRequest to\n     * @param {Object} [options] Options object\n     * @param {String} [options.method=\"GET\"]\n     * @param {Function} options.onComplete Callback to invoke when request is completed\n     * @return {XMLHttpRequest} request\n     */\n    function request(url, options) {\n\n        options || (options = { });\n\n        var method = options.method ? options.method.toUpperCase() : 'GET',\n            onComplete = options.onComplete || function() { },\n            xhr = makeXHR(),\n            body;\n\n        /** @ignore */\n        xhr.onreadystatechange = function() {\n            if (xhr.readyState === 4) {\n                onComplete(xhr);\n                xhr.onreadystatechange = emptyFn;\n            }\n        };\n\n        if (method === 'GET') {\n            body = null;\n            if (typeof options.parameters === 'string') {\n                url = addParamToUrl(url, options.parameters);\n            }\n        }\n\n        xhr.open(method, url, true);\n\n        if (method === 'POST' || method === 'PUT') {\n            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n        }\n\n        xhr.send(body);\n        return xhr;\n    }\n\n    fabric.util.request = request;\n})();\n\n\n/**\n * Wrapper around `console.log` (when available)\n * @param {Any} [values] Values to log\n */\nfabric.log = function() { };\n\n/**\n * Wrapper around `console.warn` (when available)\n * @param {Any} [values] Values to log as a warning\n */\nfabric.warn = function() { };\n\nif (typeof console !== 'undefined') {\n    ['log', 'warn'].forEach(function(methodName) {\n        if (typeof console[methodName] !== 'undefined' && console[methodName].apply) {\n            fabric[methodName] = function() {\n                return console[methodName].apply(console, arguments);\n            };\n        }\n    });\n}\n\n\n(function() {\n\n    /**\n     * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.\n     * @memberOf fabric.util\n     * @param {Object} [options] Animation options\n     * @param {Function} [options.onChange] Callback; invoked on every value change\n     * @param {Function} [options.onComplete] Callback; invoked when value change is completed\n     * @param {Number} [options.startValue=0] Starting value\n     * @param {Number} [options.endValue=100] Ending value\n     * @param {Number} [options.byValue=100] Value to modify the property by\n     * @param {Function} [options.easing] Easing function\n     * @param {Number} [options.duration=500] Duration of change (in ms)\n     */\n    function animate(options) {\n\n        requestAnimFrame(function(timestamp) {\n            options || (options = { });\n\n            var start = timestamp || +new Date(),\n                duration = options.duration || 500,\n                finish = start + duration, time,\n                onChange = options.onChange || function() { },\n                abort = options.abort || function() { return false; },\n                easing = options.easing || function(t, b, c, d) {return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;},\n                startValue = 'startValue' in options ? options.startValue : 0,\n                endValue = 'endValue' in options ? options.endValue : 100,\n                byValue = options.byValue || endValue - startValue;\n\n            options.onStart && options.onStart();\n\n            (function tick(ticktime) {\n                time = ticktime || +new Date();\n                var currentTime = time > finish ? duration : (time - start);\n                if (abort()) {\n                    options.onComplete && options.onComplete();\n                    return;\n                }\n                onChange(easing(currentTime, startValue, byValue, duration));\n                if (time > finish) {\n                    options.onComplete && options.onComplete();\n                    return;\n                }\n                requestAnimFrame(tick);\n            })(start);\n        });\n\n    }\n\n    var _requestAnimFrame = fabric.window.requestAnimationFrame       ||\n        fabric.window.webkitRequestAnimationFrame ||\n        fabric.window.mozRequestAnimationFrame    ||\n        fabric.window.oRequestAnimationFrame      ||\n        fabric.window.msRequestAnimationFrame     ||\n        function(callback) {\n            fabric.window.setTimeout(callback, 1000 / 60);\n        };\n    /**\n     * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n     * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method\n     * @memberOf fabric.util\n     * @param {Function} callback Callback to invoke\n     * @param {DOMElement} element optional Element to associate with animation\n     */\n    function requestAnimFrame() {\n        return _requestAnimFrame.apply(fabric.window, arguments);\n    }\n\n    fabric.util.animate = animate;\n    fabric.util.requestAnimFrame = requestAnimFrame;\n\n})();\n\n\n(function() {\n\n    function normalize(a, c, p, s) {\n        if (a < Math.abs(c)) {\n            a = c;\n            s = p / 4;\n        }\n        else {\n            s = p / (2 * Math.PI) * Math.asin(c / a);\n        }\n        return { a: a, c: c, p: p, s: s };\n    }\n\n    function elastic(opts, t, d) {\n        return opts.a *\n            Math.pow(2, 10 * (t -= 1)) *\n            Math.sin( (t * d - opts.s) * (2 * Math.PI) / opts.p );\n    }\n\n    /**\n     * Cubic easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutCubic(t, b, c, d) {\n        return c * ((t = t / d - 1) * t * t + 1) + b;\n    }\n\n    /**\n     * Cubic easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutCubic(t, b, c, d) {\n        t /= d/2;\n        if (t < 1) {\n            return c / 2 * t * t * t + b;\n        }\n        return c / 2 * ((t -= 2) * t * t + 2) + b;\n    }\n\n    /**\n     * Quartic easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInQuart(t, b, c, d) {\n        return c * (t /= d) * t * t * t + b;\n    }\n\n    /**\n     * Quartic easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutQuart(t, b, c, d) {\n        return -c * ((t = t / d - 1) * t * t * t - 1) + b;\n    }\n\n    /**\n     * Quartic easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutQuart(t, b, c, d) {\n        t /= d / 2;\n        if (t < 1) {\n            return c / 2 * t * t * t * t + b;\n        }\n        return -c / 2 * ((t -= 2) * t * t * t - 2) + b;\n    }\n\n    /**\n     * Quintic easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInQuint(t, b, c, d) {\n        return c * (t /= d) * t * t * t * t + b;\n    }\n\n    /**\n     * Quintic easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutQuint(t, b, c, d) {\n        return c * ((t = t / d - 1) * t * t * t * t + 1) + b;\n    }\n\n    /**\n     * Quintic easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutQuint(t, b, c, d) {\n        t /= d / 2;\n        if (t < 1) {\n            return c / 2 * t * t * t * t * t + b;\n        }\n        return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;\n    }\n\n    /**\n     * Sinusoidal easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInSine(t, b, c, d) {\n        return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;\n    }\n\n    /**\n     * Sinusoidal easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutSine(t, b, c, d) {\n        return c * Math.sin(t / d * (Math.PI / 2)) + b;\n    }\n\n    /**\n     * Sinusoidal easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutSine(t, b, c, d) {\n        return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n    }\n\n    /**\n     * Exponential easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInExpo(t, b, c, d) {\n        return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n    }\n\n    /**\n     * Exponential easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutExpo(t, b, c, d) {\n        return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n    }\n\n    /**\n     * Exponential easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutExpo(t, b, c, d) {\n        if (t === 0) {\n            return b;\n        }\n        if (t === d) {\n            return b + c;\n        }\n        t /= d / 2;\n        if (t < 1) {\n            return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n        }\n        return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n    }\n\n    /**\n     * Circular easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInCirc(t, b, c, d) {\n        return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;\n    }\n\n    /**\n     * Circular easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutCirc(t, b, c, d) {\n        return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;\n    }\n\n    /**\n     * Circular easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutCirc(t, b, c, d) {\n        t /= d / 2;\n        if (t < 1) {\n            return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;\n        }\n        return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;\n    }\n\n    /**\n     * Elastic easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInElastic(t, b, c, d) {\n        var s = 1.70158, p = 0, a = c;\n        if (t === 0) {\n            return b;\n        }\n        t /= d;\n        if (t === 1) {\n            return b + c;\n        }\n        if (!p) {\n            p = d * 0.3;\n        }\n        var opts = normalize(a, c, p, s);\n        return -elastic(opts, t, d) + b;\n    }\n\n    /**\n     * Elastic easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutElastic(t, b, c, d) {\n        var s = 1.70158, p = 0, a = c;\n        if (t === 0) {\n            return b;\n        }\n        t /= d;\n        if (t === 1) {\n            return b + c;\n        }\n        if (!p) {\n            p = d * 0.3;\n        }\n        var opts = normalize(a, c, p, s);\n        return opts.a * Math.pow(2, -10 * t) * Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) + opts.c + b;\n    }\n\n    /**\n     * Elastic easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutElastic(t, b, c, d) {\n        var s = 1.70158, p = 0, a = c;\n        if (t === 0) {\n            return b;\n        }\n        t /= d / 2;\n        if (t === 2) {\n            return b + c;\n        }\n        if (!p) {\n            p = d * (0.3 * 1.5);\n        }\n        var opts = normalize(a, c, p, s);\n        if (t < 1) {\n            return -0.5 * elastic(opts, t, d) + b;\n        }\n        return opts.a * Math.pow(2, -10 * (t -= 1)) *\n            Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) * 0.5 + opts.c + b;\n    }\n\n    /**\n     * Backwards easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInBack(t, b, c, d, s) {\n        if (s === undefined) {\n            s = 1.70158;\n        }\n        return c * (t /= d) * t * ((s + 1) * t - s) + b;\n    }\n\n    /**\n     * Backwards easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutBack(t, b, c, d, s) {\n        if (s === undefined) {\n            s = 1.70158;\n        }\n        return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;\n    }\n\n    /**\n     * Backwards easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutBack(t, b, c, d, s) {\n        if (s === undefined) {\n            s = 1.70158;\n        }\n        t /= d / 2;\n        if (t < 1) {\n            return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;\n        }\n        return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;\n    }\n\n    /**\n     * Bouncing easing in\n     * @memberOf fabric.util.ease\n     */\n    function easeInBounce(t, b, c, d) {\n        return c - easeOutBounce (d - t, 0, c, d) + b;\n    }\n\n    /**\n     * Bouncing easing out\n     * @memberOf fabric.util.ease\n     */\n    function easeOutBounce(t, b, c, d) {\n        if ((t /= d) < (1 / 2.75)) {\n            return c * (7.5625 * t * t) + b;\n        }\n        else if (t < (2/2.75)) {\n            return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;\n        }\n        else if (t < (2.5/2.75)) {\n            return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;\n        }\n        else {\n            return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;\n        }\n    }\n\n    /**\n     * Bouncing easing in and out\n     * @memberOf fabric.util.ease\n     */\n    function easeInOutBounce(t, b, c, d) {\n        if (t < d / 2) {\n            return easeInBounce (t * 2, 0, c, d) * 0.5 + b;\n        }\n        return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;\n    }\n\n    /**\n     * Easing functions\n     * See <a href=\"http://gizma.com/easing/\">Easing Equations by Robert Penner</a>\n     * @namespace fabric.util.ease\n     */\n    fabric.util.ease = {\n\n        /**\n         * Quadratic easing in\n         * @memberOf fabric.util.ease\n         */\n        easeInQuad: function(t, b, c, d) {\n            return c * (t /= d) * t + b;\n        },\n\n        /**\n         * Quadratic easing out\n         * @memberOf fabric.util.ease\n         */\n        easeOutQuad: function(t, b, c, d) {\n            return -c * (t /= d) * (t - 2) + b;\n        },\n\n        /**\n         * Quadratic easing in and out\n         * @memberOf fabric.util.ease\n         */\n        easeInOutQuad: function(t, b, c, d) {\n            t /= (d / 2);\n            if (t < 1) {\n                return c / 2 * t * t + b;\n            }\n            return -c / 2 * ((--t) * (t - 2) - 1) + b;\n        },\n\n        /**\n         * Cubic easing in\n         * @memberOf fabric.util.ease\n         */\n        easeInCubic: function(t, b, c, d) {\n            return c * (t /= d) * t * t + b;\n        },\n\n        easeOutCubic: easeOutCubic,\n        easeInOutCubic: easeInOutCubic,\n        easeInQuart: easeInQuart,\n        easeOutQuart: easeOutQuart,\n        easeInOutQuart: easeInOutQuart,\n        easeInQuint: easeInQuint,\n        easeOutQuint: easeOutQuint,\n        easeInOutQuint: easeInOutQuint,\n        easeInSine: easeInSine,\n        easeOutSine: easeOutSine,\n        easeInOutSine: easeInOutSine,\n        easeInExpo: easeInExpo,\n        easeOutExpo: easeOutExpo,\n        easeInOutExpo: easeInOutExpo,\n        easeInCirc: easeInCirc,\n        easeOutCirc: easeOutCirc,\n        easeInOutCirc: easeInOutCirc,\n        easeInElastic: easeInElastic,\n        easeOutElastic: easeOutElastic,\n        easeInOutElastic: easeInOutElastic,\n        easeInBack: easeInBack,\n        easeOutBack: easeOutBack,\n        easeInOutBack: easeInOutBack,\n        easeInBounce: easeInBounce,\n        easeOutBounce: easeOutBounce,\n        easeInOutBounce: easeInOutBounce\n    };\n\n}());\n\n\n(function(global) {\n\n    'use strict';\n\n    /**\n     * @name fabric\n     * @namespace\n     */\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        capitalize = fabric.util.string.capitalize,\n        clone = fabric.util.object.clone,\n        toFixed = fabric.util.toFixed,\n        parseUnit = fabric.util.parseUnit,\n        multiplyTransformMatrices = fabric.util.multiplyTransformMatrices,\n\n        attributesMap = {\n            cx:                   'left',\n            x:                    'left',\n            r:                    'radius',\n            cy:                   'top',\n            y:                    'top',\n            display:              'visible',\n            visibility:           'visible',\n            transform:            'transformMatrix',\n            'fill-opacity':       'fillOpacity',\n            'fill-rule':          'fillRule',\n            'font-family':        'fontFamily',\n            'font-size':          'fontSize',\n            'font-style':         'fontStyle',\n            'font-weight':        'fontWeight',\n            'stroke-dasharray':   'strokeDashArray',\n            'stroke-linecap':     'strokeLineCap',\n            'stroke-linejoin':    'strokeLineJoin',\n            'stroke-miterlimit':  'strokeMiterLimit',\n            'stroke-opacity':     'strokeOpacity',\n            'stroke-width':       'strokeWidth',\n            'text-decoration':    'textDecoration',\n            'text-anchor':        'originX'\n        },\n\n        colorAttributes = {\n            stroke: 'strokeOpacity',\n            fill:   'fillOpacity'\n        };\n\n    fabric.cssRules = { };\n    fabric.gradientDefs = { };\n\n    function normalizeAttr(attr) {\n        // transform attribute names\n        if (attr in attributesMap) {\n            return attributesMap[attr];\n        }\n        return attr;\n    }\n\n    function normalizeValue(attr, value, parentAttributes) {\n        var isArray = Object.prototype.toString.call(value) === '[object Array]',\n            parsed;\n\n        if ((attr === 'fill' || attr === 'stroke') && value === 'none') {\n            value = '';\n        }\n        else if (attr === 'strokeDashArray') {\n            value = value.replace(/,/g, ' ').split(/\\s+/).map(function(n) {\n                return parseFloat(n);\n            });\n        }\n        else if (attr === 'transformMatrix') {\n            if (parentAttributes && parentAttributes.transformMatrix) {\n                value = multiplyTransformMatrices(\n                    parentAttributes.transformMatrix, fabric.parseTransformAttribute(value));\n            }\n            else {\n                value = fabric.parseTransformAttribute(value);\n            }\n        }\n        else if (attr === 'visible') {\n            value = (value === 'none' || value === 'hidden') ? false : true;\n            // display=none on parent element always takes precedence over child element\n            if (parentAttributes && parentAttributes.visible === false) {\n                value = false;\n            }\n        }\n        else if (attr === 'originX' /* text-anchor */) {\n            value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';\n        }\n        else {\n            parsed = isArray ? value.map(parseUnit) : parseUnit(value);\n        }\n\n        return (!isArray && isNaN(parsed) ? value : parsed);\n    }\n\n    /**\n     * @private\n     * @param {Object} attributes Array of attributes to parse\n     */\n    function _setStrokeFillOpacity(attributes) {\n        for (var attr in colorAttributes) {\n\n            if (!attributes[attr] || typeof attributes[colorAttributes[attr]] === 'undefined') {\n                continue;\n            }\n\n            if (attributes[attr].indexOf('url(') === 0) {\n                continue;\n            }\n\n            var color = new fabric.Color(attributes[attr]);\n            attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();\n        }\n        return attributes;\n    }\n\n    /**\n     * Parses \"transform\" attribute, returning an array of values\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {String} attributeValue String containing attribute value\n     * @return {Array} Array of 6 elements representing transformation matrix\n     */\n    fabric.parseTransformAttribute = (function() {\n        function rotateMatrix(matrix, args) {\n            var angle = args[0];\n\n            matrix[0] = Math.cos(angle);\n            matrix[1] = Math.sin(angle);\n            matrix[2] = -Math.sin(angle);\n            matrix[3] = Math.cos(angle);\n        }\n\n        function scaleMatrix(matrix, args) {\n            var multiplierX = args[0],\n                multiplierY = (args.length === 2) ? args[1] : args[0];\n\n            matrix[0] = multiplierX;\n            matrix[3] = multiplierY;\n        }\n\n        function skewXMatrix(matrix, args) {\n            matrix[2] = Math.tan(fabric.util.degreesToRadians(args[0]));\n        }\n\n        function skewYMatrix(matrix, args) {\n            matrix[1] = Math.tan(fabric.util.degreesToRadians(args[0]));\n        }\n\n        function translateMatrix(matrix, args) {\n            matrix[4] = args[0];\n            if (args.length === 2) {\n                matrix[5] = args[1];\n            }\n        }\n\n        // identity matrix\n        var iMatrix = [\n                1, // a\n                0, // b\n                0, // c\n                1, // d\n                0, // e\n                0  // f\n            ],\n\n        // == begin transform regexp\n            number = '(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)',\n\n            commaWsp = '(?:\\\\s+,?\\\\s*|,\\\\s*)',\n\n            skewX = '(?:(skewX)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n            skewY = '(?:(skewY)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n            rotate = '(?:(rotate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                commaWsp + '(' + number + ')' +\n                commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n            scale = '(?:(scale)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n            translate = '(?:(translate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n            matrix = '(?:(matrix)\\\\s*\\\\(\\\\s*' +\n                '(' + number + ')' + commaWsp +\n                '(' + number + ')' + commaWsp +\n                '(' + number + ')' + commaWsp +\n                '(' + number + ')' + commaWsp +\n                '(' + number + ')' + commaWsp +\n                '(' + number + ')' +\n                '\\\\s*\\\\))',\n\n            transform = '(?:' +\n                matrix + '|' +\n                translate + '|' +\n                scale + '|' +\n                rotate + '|' +\n                skewX + '|' +\n                skewY +\n                ')',\n\n            transforms = '(?:' + transform + '(?:' + commaWsp + transform + ')*' + ')',\n\n            transformList = '^\\\\s*(?:' + transforms + '?)\\\\s*$',\n\n        // http://www.w3.org/TR/SVG/coords.html#TransformAttribute\n            reTransformList = new RegExp(transformList),\n        // == end transform regexp\n\n            reTransform = new RegExp(transform, 'g');\n\n        return function(attributeValue) {\n\n            // start with identity matrix\n            var matrix = iMatrix.concat(),\n                matrices = [ ];\n\n            // return if no argument was given or\n            // an argument does not match transform attribute regexp\n            if (!attributeValue || (attributeValue && !reTransformList.test(attributeValue))) {\n                return matrix;\n            }\n\n            attributeValue.replace(reTransform, function(match) {\n\n                var m = new RegExp(transform).exec(match).filter(function (match) {\n                        return (match !== '' && match != null);\n                    }),\n                    operation = m[1],\n                    args = m.slice(2).map(parseFloat);\n\n                switch (operation) {\n                    case 'translate':\n                        translateMatrix(matrix, args);\n                        break;\n                    case 'rotate':\n                        args[0] = fabric.util.degreesToRadians(args[0]);\n                        rotateMatrix(matrix, args);\n                        break;\n                    case 'scale':\n                        scaleMatrix(matrix, args);\n                        break;\n                    case 'skewX':\n                        skewXMatrix(matrix, args);\n                        break;\n                    case 'skewY':\n                        skewYMatrix(matrix, args);\n                        break;\n                    case 'matrix':\n                        matrix = args;\n                        break;\n                }\n\n                // snapshot current matrix into matrices array\n                matrices.push(matrix.concat());\n                // reset\n                matrix = iMatrix.concat();\n            });\n\n            var combinedMatrix = matrices[0];\n            while (matrices.length > 1) {\n                matrices.shift();\n                combinedMatrix = fabric.util.multiplyTransformMatrices(combinedMatrix, matrices[0]);\n            }\n            return combinedMatrix;\n        };\n    })();\n\n    function parseFontDeclaration(value, oStyle) {\n\n        // TODO: support non-px font size\n        var match = value.match(/(normal|italic)?\\s*(normal|small-caps)?\\s*(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\s*(\\d+)px(?:\\/(normal|[\\d\\.]+))?\\s+(.*)/);\n\n        if (!match) {\n            return;\n        }\n\n        var fontStyle = match[1],\n        // font variant is not used\n        // fontVariant = match[2],\n            fontWeight = match[3],\n            fontSize = match[4],\n            lineHeight = match[5],\n            fontFamily = match[6];\n\n        if (fontStyle) {\n            oStyle.fontStyle = fontStyle;\n        }\n        if (fontWeight) {\n            oStyle.fontWeight = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);\n        }\n        if (fontSize) {\n            oStyle.fontSize = parseFloat(fontSize);\n        }\n        if (fontFamily) {\n            oStyle.fontFamily = fontFamily;\n        }\n        if (lineHeight) {\n            oStyle.lineHeight = lineHeight === 'normal' ? 1 : lineHeight;\n        }\n    }\n\n    /**\n     * @private\n     */\n    function parseStyleString(style, oStyle) {\n        var attr, value;\n        style.replace(/;$/, '').split(';').forEach(function (chunk) {\n            var pair = chunk.split(':');\n\n            attr = normalizeAttr(pair[0].trim().toLowerCase());\n            value = normalizeValue(attr, pair[1].trim());\n\n            if (attr === 'font') {\n                parseFontDeclaration(value, oStyle);\n            }\n            else {\n                oStyle[attr] = value;\n            }\n        });\n    }\n\n    /**\n     * @private\n     */\n    function parseStyleObject(style, oStyle) {\n        var attr, value;\n        for (var prop in style) {\n            if (typeof style[prop] === 'undefined') {\n                continue;\n            }\n\n            attr = normalizeAttr(prop.toLowerCase());\n            value = normalizeValue(attr, style[prop]);\n\n            if (attr === 'font') {\n                parseFontDeclaration(value, oStyle);\n            }\n            else {\n                oStyle[attr] = value;\n            }\n        }\n    }\n\n    /**\n     * @private\n     */\n    function getGlobalStylesForElement(element, svgUid) {\n        var styles = { };\n        for (var rule in fabric.cssRules[svgUid]) {\n            if (elementMatchesRule(element, rule.split(' '))) {\n                for (var property in fabric.cssRules[svgUid][rule]) {\n                    styles[property] = fabric.cssRules[svgUid][rule][property];\n                }\n            }\n        }\n        return styles;\n    }\n\n    /**\n     * @private\n     */\n    function elementMatchesRule(element, selectors) {\n        var firstMatching, parentMatching = true;\n        //start from rightmost selector.\n        firstMatching = selectorMatches(element, selectors.pop());\n        if (firstMatching && selectors.length) {\n            parentMatching = doesSomeParentMatch(element, selectors);\n        }\n        return firstMatching && parentMatching && (selectors.length === 0);\n    }\n\n    function doesSomeParentMatch(element, selectors) {\n        var selector, parentMatching = true;\n        while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) {\n            if (parentMatching) {\n                selector = selectors.pop();\n            }\n            element = element.parentNode;\n            parentMatching = selectorMatches(element, selector);\n        }\n        return selectors.length === 0;\n    }\n    /**\n     * @private\n     */\n    function selectorMatches(element, selector) {\n        var nodeName = element.nodeName,\n            classNames = element.getAttribute('class'),\n            id = element.getAttribute('id'), matcher;\n        // i check if a selector matches slicing away part from it.\n        // if i get empty string i should match\n        matcher = new RegExp('^' + nodeName, 'i');\n        selector = selector.replace(matcher, '');\n        if (id && selector.length) {\n            matcher = new RegExp('#' + id + '(?![a-zA-Z\\\\-]+)', 'i');\n            selector = selector.replace(matcher, '');\n        }\n        if (classNames && selector.length) {\n            classNames = classNames.split(' ');\n            for (var i = classNames.length; i--;) {\n                matcher = new RegExp('\\\\.' + classNames[i] + '(?![a-zA-Z\\\\-]+)', 'i');\n                selector = selector.replace(matcher, '');\n            }\n        }\n        return selector.length === 0;\n    }\n\n    /**\n     * @private\n     */\n    function parseUseDirectives(doc) {\n        var nodelist = doc.getElementsByTagName('use');\n        while (nodelist.length) {\n            var el = nodelist[0],\n                xlink = el.getAttribute('xlink:href').substr(1),\n                x = el.getAttribute('x') || 0,\n                y = el.getAttribute('y') || 0,\n                el2 = doc.getElementById(xlink).cloneNode(true),\n                currentTrans = (el.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')',\n                parentNode;\n\n            for (var j = 0, attrs = el.attributes, l = attrs.length; j < l; j++) {\n                var attr = attrs.item(j);\n                if (attr.nodeName === 'x' || attr.nodeName === 'y' || attr.nodeName === 'xlink:href') {\n                    continue;\n                }\n\n                if (attr.nodeName === 'transform') {\n                    currentTrans = currentTrans + ' ' + attr.nodeValue;\n                }\n                else {\n                    el2.setAttribute(attr.nodeName, attr.nodeValue);\n                }\n            }\n\n            el2.setAttribute('transform', currentTrans);\n            el2.removeAttribute('id');\n            parentNode = el.parentNode;\n            parentNode.replaceChild(el2, el);\n        }\n    }\n\n    /**\n     * Add a <g> element that envelop all SCG elements and makes the viewbox transformMatrix descend on all elements\n     */\n    function addSvgTransform(doc, matrix) {\n        matrix[3] = matrix[0] = (matrix[0] > matrix[3] ? matrix[3] : matrix[0]);\n        if (!(matrix[0] !== 1 || matrix[3] !== 1 || matrix[4] !== 0 || matrix[5] !== 0)) {\n            return;\n        }\n        // default is to preserve aspect ratio\n        // preserveAspectRatio attribute to be implemented\n        var el = doc.ownerDocument.createElement('g');\n        while (doc.firstChild != null) {\n            el.appendChild(doc.firstChild);\n        }\n        el.setAttribute('transform',\n                'matrix(' + matrix[0] + ' ' +\n                matrix[1] + ' ' +\n                matrix[2] + ' ' +\n                matrix[3] + ' ' +\n                matrix[4] + ' ' +\n                matrix[5] + ')');\n\n        doc.appendChild(el);\n    }\n\n    /**\n     * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {SVGDocument} doc SVG document to parse\n     * @param {Function} callback Callback to call when parsing is finished; It's being passed an array of elements (parsed from a document).\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    fabric.parseSVGDocument = (function() {\n\n        var reAllowedSVGTagNames = /^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/,\n\n        // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute\n        // \\d doesn't quite cut it (as we need to match an actual float number)\n\n        // matches, e.g.: +14.56e-12, etc.\n            reNum = '(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)',\n\n            reViewBoxAttrValue = new RegExp(\n                    '^' +\n                    '\\\\s*(' + reNum + '+)\\\\s*,?' +\n                    '\\\\s*(' + reNum + '+)\\\\s*,?' +\n                    '\\\\s*(' + reNum + '+)\\\\s*,?' +\n                    '\\\\s*(' + reNum + '+)\\\\s*' +\n                    '$'\n            );\n\n        function hasAncestorWithNodeName(element, nodeName) {\n            while (element && (element = element.parentNode)) {\n                if (nodeName.test(element.nodeName)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        return function(doc, callback, reviver) {\n            if (!doc) {\n                return;\n            }\n            var startTime = new Date(),\n                svgUid =  fabric.Object.__uid++;\n\n            parseUseDirectives(doc);\n            /* http://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute\n             *  as per spec, width and height attributes are to be considered\n             *  100% if no value is specified.\n             */\n            var viewBoxAttr = doc.getAttribute('viewBox'),\n                widthAttr = parseUnit(doc.getAttribute('width') || '100%'),\n                heightAttr = parseUnit(doc.getAttribute('height') || '100%'),\n                viewBoxWidth,\n                viewBoxHeight;\n\n            if (viewBoxAttr && (viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))) {\n                var minX = parseFloat(viewBoxAttr[1]),\n                    minY = parseFloat(viewBoxAttr[2]),\n                    scaleX = 1, scaleY = 1;\n                viewBoxWidth = parseFloat(viewBoxAttr[3]);\n                viewBoxHeight = parseFloat(viewBoxAttr[4]);\n                if (widthAttr && widthAttr !== viewBoxWidth ) {\n                    scaleX = widthAttr / viewBoxWidth;\n                }\n                if (heightAttr && heightAttr !== viewBoxHeight) {\n                    scaleY = heightAttr / viewBoxHeight;\n                }\n                addSvgTransform(doc, [scaleX, 0, 0, scaleY, scaleX * -minX, scaleY * -minY]);\n            }\n\n            var descendants = fabric.util.toArray(doc.getElementsByTagName('*'));\n\n            if (descendants.length === 0 && fabric.isLikelyNode) {\n                // we're likely in node, where \"o3-xml\" library fails to gEBTN(\"*\")\n                // https://github.com/ajaxorg/node-o3-xml/issues/21\n                descendants = doc.selectNodes('//*[name(.)!=\"svg\"]');\n                var arr = [ ];\n                for (var i = 0, len = descendants.length; i < len; i++) {\n                    arr[i] = descendants[i];\n                }\n                descendants = arr;\n            }\n\n            var elements = descendants.filter(function(el) {\n                return reAllowedSVGTagNames.test(el.tagName) &&\n                    !hasAncestorWithNodeName(el, /^(?:pattern|defs)$/); // http://www.w3.org/TR/SVG/struct.html#DefsElement\n            });\n\n            if (!elements || (elements && !elements.length)) {\n                callback && callback([], {});\n                return;\n            }\n\n            var options = {\n                width: widthAttr ? widthAttr : viewBoxWidth,\n                height: heightAttr ? heightAttr : viewBoxHeight,\n                widthAttr: widthAttr,\n                heightAttr: heightAttr,\n                svgUid: svgUid\n            };\n\n            fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc);\n            fabric.cssRules[svgUid] = fabric.getCSSRules(doc);\n            // Precedence of rules:   style > class > attribute\n\n            fabric.parseElements(elements, function(instances) {\n                fabric.documentParsingTime = new Date() - startTime;\n                if (callback) {\n                    callback(instances, options);\n                }\n            }, clone(options), reviver);\n        };\n    })();\n\n    /**\n     * Used for caching SVG documents (loaded via `fabric.Canvas#loadSVGFromURL`)\n     * @namespace\n     */\n    var svgCache = {\n\n        /**\n         * @param {String} name\n         * @param {Function} callback\n         */\n        has: function (name, callback) {\n            callback(false);\n        },\n\n        get: function () {\n            /* NOOP */\n        },\n\n        set: function () {\n            /* NOOP */\n        }\n    };\n\n    /**\n     * @private\n     */\n    function _enlivenCachedObject(cachedObject) {\n\n        var objects = cachedObject.objects,\n            options = cachedObject.options;\n\n        objects = objects.map(function (o) {\n            return fabric[capitalize(o.type)].fromObject(o);\n        });\n\n        return ({ objects: objects, options: options });\n    }\n\n    /**\n     * @private\n     */\n    function _createSVGPattern(markup, canvas, property) {\n        if (canvas[property] && canvas[property].toSVG) {\n            markup.push(\n                '<pattern x=\"0\" y=\"0\" id=\"', property, 'Pattern\" ',\n                'width=\"', canvas[property].source.width,\n                '\" height=\"', canvas[property].source.height,\n                '\" patternUnits=\"userSpaceOnUse\">',\n                '<image x=\"0\" y=\"0\" ',\n                'width=\"', canvas[property].source.width,\n                '\" height=\"', canvas[property].source.height,\n                '\" xlink:href=\"', canvas[property].source.src,\n                '\"></image></pattern>'\n            );\n        }\n    }\n\n    extend(fabric, {\n\n        /**\n         * Parses an SVG document, returning all of the gradient declarations found in it\n         * @static\n         * @function\n         * @memberOf fabric\n         * @param {SVGDocument} doc SVG document to parse\n         * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element\n         */\n        getGradientDefs: function(doc) {\n            var linearGradientEls = doc.getElementsByTagName('linearGradient'),\n                radialGradientEls = doc.getElementsByTagName('radialGradient'),\n                el, i, j = 0, id, xlink, elList = [ ],\n                gradientDefs = { }, idsToXlinkMap = { };\n\n            elList.length = linearGradientEls.length + radialGradientEls.length;\n            i = linearGradientEls.length;\n            while (i--) {\n                elList[j++] = linearGradientEls[i];\n            }\n            i = radialGradientEls.length;\n            while (i--) {\n                elList[j++] = radialGradientEls[i];\n            }\n\n            while (j--) {\n                el = elList[j];\n                xlink = el.getAttribute('xlink:href');\n                id = el.getAttribute('id');\n                if (xlink) {\n                    idsToXlinkMap[id] = xlink.substr(1);\n                }\n                gradientDefs[id] = el;\n            }\n\n            for (id in idsToXlinkMap) {\n                var el2 = gradientDefs[idsToXlinkMap[id]].cloneNode(true);\n                el = gradientDefs[id];\n                while (el2.firstChild) {\n                    el.appendChild(el2.firstChild);\n                }\n            }\n            return gradientDefs;\n        },\n\n        /**\n         * Returns an object of attributes' name/value, given element and an array of attribute names;\n         * Parses parent \"g\" nodes recursively upwards.\n         * @static\n         * @memberOf fabric\n         * @param {DOMElement} element Element to parse\n         * @param {Array} attributes Array of attributes to parse\n         * @return {Object} object containing parsed attributes' names/values\n         */\n        parseAttributes: function(element, attributes, svgUid) {\n\n            if (!element) {\n                return;\n            }\n\n            var value,\n                parentAttributes = { };\n\n            if (typeof svgUid === 'undefined') {\n                svgUid = element.getAttribute('svgUid');\n            }\n            // if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards\n            if (element.parentNode && /^symbol|[g|a]$/i.test(element.parentNode.nodeName)) {\n                parentAttributes = fabric.parseAttributes(element.parentNode, attributes, svgUid);\n            }\n\n            var ownAttributes = attributes.reduce(function(memo, attr) {\n                value = element.getAttribute(attr);\n                if (value) {\n                    attr = normalizeAttr(attr);\n                    value = normalizeValue(attr, value, parentAttributes);\n\n                    memo[attr] = value;\n                }\n                return memo;\n            }, { });\n\n            // add values parsed from style, which take precedence over attributes\n            // (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)\n            ownAttributes = extend(ownAttributes,\n                extend(getGlobalStylesForElement(element, svgUid), fabric.parseStyleAttribute(element)));\n\n            return _setStrokeFillOpacity(extend(parentAttributes, ownAttributes));\n        },\n\n        /**\n         * Transforms an array of svg elements to corresponding fabric.* instances\n         * @static\n         * @memberOf fabric\n         * @param {Array} elements Array of elements to parse\n         * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements)\n         * @param {Object} [options] Options object\n         * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n         */\n        parseElements: function(elements, callback, options, reviver) {\n            new fabric.ElementsParser(elements, callback, options, reviver).parse();\n        },\n\n        /**\n         * Parses \"style\" attribute, retuning an object with values\n         * @static\n         * @memberOf fabric\n         * @param {SVGElement} element Element to parse\n         * @return {Object} Objects with values parsed from style attribute of an element\n         */\n        parseStyleAttribute: function(element) {\n            var oStyle = { },\n                style = element.getAttribute('style');\n\n            if (!style) {\n                return oStyle;\n            }\n\n            if (typeof style === 'string') {\n                parseStyleString(style, oStyle);\n            }\n            else {\n                parseStyleObject(style, oStyle);\n            }\n\n            return oStyle;\n        },\n\n        /**\n         * Parses \"points\" attribute, returning an array of values\n         * @static\n         * @memberOf fabric\n         * @param {String} points points attribute string\n         * @return {Array} array of points\n         */\n        parsePointsAttribute: function(points) {\n\n            // points attribute is required and must not be empty\n            if (!points) {\n                return null;\n            }\n\n            // replace commas with whitespace and remove bookending whitespace\n            points = points.replace(/,/g, ' ').trim();\n\n            points = points.split(/\\s+/);\n            var parsedPoints = [ ], i, len;\n\n            i = 0;\n            len = points.length;\n            for (; i < len; i+=2) {\n                parsedPoints.push({\n                    x: parseFloat(points[i]),\n                    y: parseFloat(points[i + 1])\n                });\n            }\n\n            // odd number of points is an error\n            // if (parsedPoints.length % 2 !== 0) {\n            // return null;\n            // }\n\n            return parsedPoints;\n        },\n\n        /**\n         * Returns CSS rules for a given SVG document\n         * @static\n         * @function\n         * @memberOf fabric\n         * @param {SVGDocument} doc SVG document to parse\n         * @return {Object} CSS rules of this document\n         */\n        getCSSRules: function(doc) {\n            var styles = doc.getElementsByTagName('style'),\n                allRules = { }, rules;\n\n            // very crude parsing of style contents\n            for (var i = 0, len = styles.length; i < len; i++) {\n                var styleContents = styles[i].textContent;\n\n                // remove comments\n                styleContents = styleContents.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n                if (styleContents.trim() === '') {\n                    continue;\n                }\n                rules = styleContents.match(/[^{]*\\{[\\s\\S]*?\\}/g);\n                rules = rules.map(function(rule) { return rule.trim(); });\n\n                rules.forEach(function(rule) {\n\n                    var match = rule.match(/([\\s\\S]*?)\\s*\\{([^}]*)\\}/),\n                        ruleObj = { }, declaration = match[2].trim(),\n                        propertyValuePairs = declaration.replace(/;$/, '').split(/\\s*;\\s*/);\n\n                    for (var i = 0, len = propertyValuePairs.length; i < len; i++) {\n                        var pair = propertyValuePairs[i].split(/\\s*:\\s*/),\n                            property = normalizeAttr(pair[0]),\n                            value = normalizeValue(property, pair[1], pair[0]);\n                        ruleObj[property] = value;\n                    }\n                    rule = match[1];\n                    rule.split(',').forEach(function(_rule) {\n                        allRules[_rule.trim()] = fabric.util.object.clone(ruleObj);\n                    });\n                });\n            }\n            return allRules;\n        },\n\n        /**\n         * Takes url corresponding to an SVG document, and parses it into a set of fabric objects. Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy)\n         * @memberof fabric\n         * @param {String} url\n         * @param {Function} callback\n         * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n         */\n        loadSVGFromURL: function(url, callback, reviver) {\n\n            url = url.replace(/^\\n\\s*/, '').trim();\n            svgCache.has(url, function (hasUrl) {\n                if (hasUrl) {\n                    svgCache.get(url, function (value) {\n                        var enlivedRecord = _enlivenCachedObject(value);\n                        callback(enlivedRecord.objects, enlivedRecord.options);\n                    });\n                }\n                else {\n                    new fabric.util.request(url, {\n                        method: 'get',\n                        onComplete: onComplete\n                    });\n                }\n            });\n\n            function onComplete(r) {\n\n                var xml = r.responseXML;\n                if (xml && !xml.documentElement && fabric.window.ActiveXObject && r.responseText) {\n                    xml = new ActiveXObject('Microsoft.XMLDOM');\n                    xml.async = 'false';\n                    //IE chokes on DOCTYPE\n                    xml.loadXML(r.responseText.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i, ''));\n                }\n                if (!xml || !xml.documentElement) {\n                    return;\n                }\n\n                fabric.parseSVGDocument(xml.documentElement, function (results, options) {\n                    svgCache.set(url, {\n                        objects: fabric.util.array.invoke(results, 'toObject'),\n                        options: options\n                    });\n                    callback(results, options);\n                }, reviver);\n            }\n        },\n\n        /**\n         * Takes string corresponding to an SVG document, and parses it into a set of fabric objects\n         * @memberof fabric\n         * @param {String} string\n         * @param {Function} callback\n         * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n         */\n        loadSVGFromString: function(string, callback, reviver) {\n            string = string.trim();\n            var doc;\n            if (typeof DOMParser !== 'undefined') {\n                var parser = new DOMParser();\n                if (parser && parser.parseFromString) {\n                    doc = parser.parseFromString(string, 'text/xml');\n                }\n            }\n            else if (fabric.window.ActiveXObject) {\n                doc = new ActiveXObject('Microsoft.XMLDOM');\n                doc.async = 'false';\n                // IE chokes on DOCTYPE\n                doc.loadXML(string.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i, ''));\n            }\n\n            fabric.parseSVGDocument(doc.documentElement, function (results, options) {\n                callback(results, options);\n            }, reviver);\n        },\n\n        /**\n         * Creates markup containing SVG font faces\n         * @param {Array} objects Array of fabric objects\n         * @return {String}\n         */\n        createSVGFontFacesMarkup: function(objects) {\n            var markup = '';\n\n            for (var i = 0, len = objects.length; i < len; i++) {\n                if (objects[i].type !== 'text' || !objects[i].path) {\n                    continue;\n                }\n\n                markup += [\n                    //jscs:disable validateIndentation\n                    '@font-face {',\n                    'font-family: ', objects[i].fontFamily, '; ',\n                    'src: url(\\'', objects[i].path, '\\')',\n                    '}'\n                    //jscs:enable validateIndentation\n                ].join('');\n            }\n\n            if (markup) {\n                markup = [\n                    //jscs:disable validateIndentation\n                    '<style type=\"text/css\">',\n                    '<![CDATA[',\n                    markup,\n                    ']]>',\n                    '</style>'\n                    //jscs:enable validateIndentation\n                ].join('');\n            }\n\n            return markup;\n        },\n\n        /**\n         * Creates markup containing SVG referenced elements like patterns, gradients etc.\n         * @param {fabric.Canvas} canvas instance of fabric.Canvas\n         * @return {String}\n         */\n        createSVGRefElementsMarkup: function(canvas) {\n            var markup = [ ];\n\n            _createSVGPattern(markup, canvas, 'backgroundColor');\n            _createSVGPattern(markup, canvas, 'overlayColor');\n\n            return markup.join('');\n        }\n    });\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.ElementsParser = function(elements, callback, options, reviver) {\n    this.elements = elements;\n    this.callback = callback;\n    this.options = options;\n    this.reviver = reviver;\n    this.svgUid = (options && options.svgUid) || 0;\n};\n\nfabric.ElementsParser.prototype.parse = function() {\n    this.instances = new Array(this.elements.length);\n    this.numElements = this.elements.length;\n\n    this.createObjects();\n};\n\nfabric.ElementsParser.prototype.createObjects = function() {\n    for (var i = 0, len = this.elements.length; i < len; i++) {\n        this.elements[i].setAttribute('svgUid', this.svgUid);\n        (function(_this, i) {\n            setTimeout(function() {\n                _this.createObject(_this.elements[i], i);\n            }, 0);\n        })(this, i);\n    }\n};\n\nfabric.ElementsParser.prototype.createObject = function(el, index) {\n    var klass = fabric[fabric.util.string.capitalize(el.tagName)];\n    if (klass && klass.fromElement) {\n        try {\n            this._createObject(klass, el, index);\n        }\n        catch (err) {\n            fabric.log(err);\n        }\n    }\n    else {\n        this.checkIfDone();\n    }\n};\n\nfabric.ElementsParser.prototype._createObject = function(klass, el, index) {\n    if (klass.async) {\n        klass.fromElement(el, this.createCallback(index, el), this.options);\n    }\n    else {\n        var obj = klass.fromElement(el, this.options);\n        this.resolveGradient(obj, 'fill');\n        this.resolveGradient(obj, 'stroke');\n        this.reviver && this.reviver(el, obj);\n        this.instances[index] = obj;\n        this.checkIfDone();\n    }\n};\n\nfabric.ElementsParser.prototype.createCallback = function(index, el) {\n    var _this = this;\n    return function(obj) {\n        _this.resolveGradient(obj, 'fill');\n        _this.resolveGradient(obj, 'stroke');\n        _this.reviver && _this.reviver(el, obj);\n        _this.instances[index] = obj;\n        _this.checkIfDone();\n    };\n};\n\nfabric.ElementsParser.prototype.resolveGradient = function(obj, property) {\n\n    var instanceFillValue = obj.get(property);\n    if (!(/^url\\(/).test(instanceFillValue)) {\n        return;\n    }\n    var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);\n    if (fabric.gradientDefs[this.svgUid][gradientId]) {\n        obj.set(property,\n            fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][gradientId], obj));\n    }\n};\n\nfabric.ElementsParser.prototype.checkIfDone = function() {\n    if (--this.numElements === 0) {\n        this.instances = this.instances.filter(function(el) {\n            return el != null;\n        });\n        this.callback(this.instances);\n    }\n};\n\n\n(function(global) {\n\n    'use strict';\n\n    /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n\n    var fabric = global.fabric || (global.fabric = { });\n\n    if (fabric.Point) {\n        fabric.warn('fabric.Point is already defined');\n        return;\n    }\n\n    fabric.Point = Point;\n\n    /**\n     * Point class\n     * @class fabric.Point\n     * @memberOf fabric\n     * @constructor\n     * @param {Number} x\n     * @param {Number} y\n     * @return {fabric.Point} thisArg\n     */\n    function Point(x, y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    Point.prototype = /** @lends fabric.Point.prototype */ {\n\n        constructor: Point,\n\n        /**\n         * Adds another point to this one and returns another one\n         * @param {fabric.Point} that\n         * @return {fabric.Point} new Point instance with added values\n         */\n        add: function (that) {\n            return new Point(this.x + that.x, this.y + that.y);\n        },\n\n        /**\n         * Adds another point to this one\n         * @param {fabric.Point} that\n         * @return {fabric.Point} thisArg\n         */\n        addEquals: function (that) {\n            this.x += that.x;\n            this.y += that.y;\n            return this;\n        },\n\n        /**\n         * Adds value to this point and returns a new one\n         * @param {Number} scalar\n         * @return {fabric.Point} new Point with added value\n         */\n        scalarAdd: function (scalar) {\n            return new Point(this.x + scalar, this.y + scalar);\n        },\n\n        /**\n         * Adds value to this point\n         * @param {Number} scalar\n         * @return {fabric.Point} thisArg\n         */\n        scalarAddEquals: function (scalar) {\n            this.x += scalar;\n            this.y += scalar;\n            return this;\n        },\n\n        /**\n         * Subtracts another point from this point and returns a new one\n         * @param {fabric.Point} that\n         * @return {fabric.Point} new Point object with subtracted values\n         */\n        subtract: function (that) {\n            return new Point(this.x - that.x, this.y - that.y);\n        },\n\n        /**\n         * Subtracts another point from this point\n         * @param {fabric.Point} that\n         * @return {fabric.Point} thisArg\n         */\n        subtractEquals: function (that) {\n            this.x -= that.x;\n            this.y -= that.y;\n            return this;\n        },\n\n        /**\n         * Subtracts value from this point and returns a new one\n         * @param {Number} scalar\n         * @return {fabric.Point}\n         */\n        scalarSubtract: function (scalar) {\n            return new Point(this.x - scalar, this.y - scalar);\n        },\n\n        /**\n         * Subtracts value from this point\n         * @param {Number} scalar\n         * @return {fabric.Point} thisArg\n         */\n        scalarSubtractEquals: function (scalar) {\n            this.x -= scalar;\n            this.y -= scalar;\n            return this;\n        },\n\n        /**\n         * Miltiplies this point by a value and returns a new one\n         * @param {Number} scalar\n         * @return {fabric.Point}\n         */\n        multiply: function (scalar) {\n            return new Point(this.x * scalar, this.y * scalar);\n        },\n\n        /**\n         * Miltiplies this point by a value\n         * @param {Number} scalar\n         * @return {fabric.Point} thisArg\n         */\n        multiplyEquals: function (scalar) {\n            this.x *= scalar;\n            this.y *= scalar;\n            return this;\n        },\n\n        /**\n         * Divides this point by a value and returns a new one\n         * @param {Number} scalar\n         * @return {fabric.Point}\n         */\n        divide: function (scalar) {\n            return new Point(this.x / scalar, this.y / scalar);\n        },\n\n        /**\n         * Divides this point by a value\n         * @param {Number} scalar\n         * @return {fabric.Point} thisArg\n         */\n        divideEquals: function (scalar) {\n            this.x /= scalar;\n            this.y /= scalar;\n            return this;\n        },\n\n        /**\n         * Returns true if this point is equal to another one\n         * @param {fabric.Point} that\n         * @return {Boolean}\n         */\n        eq: function (that) {\n            return (this.x === that.x && this.y === that.y);\n        },\n\n        /**\n         * Returns true if this point is less than another one\n         * @param {fabric.Point} that\n         * @return {Boolean}\n         */\n        lt: function (that) {\n            return (this.x < that.x && this.y < that.y);\n        },\n\n        /**\n         * Returns true if this point is less than or equal to another one\n         * @param {fabric.Point} that\n         * @return {Boolean}\n         */\n        lte: function (that) {\n            return (this.x <= that.x && this.y <= that.y);\n        },\n\n        /**\n\n         * Returns true if this point is greater another one\n         * @param {fabric.Point} that\n         * @return {Boolean}\n         */\n        gt: function (that) {\n            return (this.x > that.x && this.y > that.y);\n        },\n\n        /**\n         * Returns true if this point is greater than or equal to another one\n         * @param {fabric.Point} that\n         * @return {Boolean}\n         */\n        gte: function (that) {\n            return (this.x >= that.x && this.y >= that.y);\n        },\n\n        /**\n         * Returns new point which is the result of linear interpolation with this one and another one\n         * @param {fabric.Point} that\n         * @param {Number} t\n         * @return {fabric.Point}\n         */\n        lerp: function (that, t) {\n            return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t);\n        },\n\n        /**\n         * Returns distance from this point and another one\n         * @param {fabric.Point} that\n         * @return {Number}\n         */\n        distanceFrom: function (that) {\n            var dx = this.x - that.x,\n                dy = this.y - that.y;\n            return Math.sqrt(dx * dx + dy * dy);\n        },\n\n        /**\n         * Returns the point between this point and another one\n         * @param {fabric.Point} that\n         * @return {fabric.Point}\n         */\n        midPointFrom: function (that) {\n            return new Point(this.x + (that.x - this.x)/2, this.y + (that.y - this.y)/2);\n        },\n\n        /**\n         * Returns a new point which is the min of this and another one\n         * @param {fabric.Point} that\n         * @return {fabric.Point}\n         */\n        min: function (that) {\n            return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y));\n        },\n\n        /**\n         * Returns a new point which is the max of this and another one\n         * @param {fabric.Point} that\n         * @return {fabric.Point}\n         */\n        max: function (that) {\n            return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y));\n        },\n\n        /**\n         * Returns string representation of this point\n         * @return {String}\n         */\n        toString: function () {\n            return this.x + ',' + this.y;\n        },\n\n        /**\n         * Sets x/y of this point\n         * @param {Number} x\n         * @return {Number} y\n         */\n        setXY: function (x, y) {\n            this.x = x;\n            this.y = y;\n        },\n\n        /**\n         * Sets x/y of this point from another point\n         * @param {fabric.Point} that\n         */\n        setFromPoint: function (that) {\n            this.x = that.x;\n            this.y = that.y;\n        },\n\n        /**\n         * Swaps x/y of this point and another point\n         * @param {fabric.Point} that\n         */\n        swap: function (that) {\n            var x = this.x,\n                y = this.y;\n            this.x = that.x;\n            this.y = that.y;\n            that.x = x;\n            that.y = y;\n        }\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n    var fabric = global.fabric || (global.fabric = { });\n\n    if (fabric.Intersection) {\n        fabric.warn('fabric.Intersection is already defined');\n        return;\n    }\n\n    /**\n     * Intersection class\n     * @class fabric.Intersection\n     * @memberOf fabric\n     * @constructor\n     */\n    function Intersection(status) {\n        this.status = status;\n        this.points = [];\n    }\n\n    fabric.Intersection = Intersection;\n\n    fabric.Intersection.prototype = /** @lends fabric.Intersection.prototype */ {\n\n        /**\n         * Appends a point to intersection\n         * @param {fabric.Point} point\n         */\n        appendPoint: function (point) {\n            this.points.push(point);\n        },\n\n        /**\n         * Appends points to intersection\n         * @param {Array} points\n         */\n        appendPoints: function (points) {\n            this.points = this.points.concat(points);\n        }\n    };\n\n    /**\n     * Checks if one line intersects another\n     * @static\n     * @param {fabric.Point} a1\n     * @param {fabric.Point} a2\n     * @param {fabric.Point} b1\n     * @param {fabric.Point} b2\n     * @return {fabric.Intersection}\n     */\n    fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) {\n        var result,\n            uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),\n            ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),\n            uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);\n        if (uB !== 0) {\n            var ua = uaT / uB,\n                ub = ubT / uB;\n            if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n                result = new Intersection('Intersection');\n                result.points.push(new fabric.Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)));\n            }\n            else {\n                result = new Intersection();\n            }\n        }\n        else {\n            if (uaT === 0 || ubT === 0) {\n                result = new Intersection('Coincident');\n            }\n            else {\n                result = new Intersection('Parallel');\n            }\n        }\n        return result;\n    };\n\n    /**\n     * Checks if line intersects polygon\n     * @static\n     * @param {fabric.Point} a1\n     * @param {fabric.Point} a2\n     * @param {Array} points\n     * @return {fabric.Intersection}\n     */\n    fabric.Intersection.intersectLinePolygon = function(a1, a2, points) {\n        var result = new Intersection(),\n            length = points.length;\n\n        for (var i = 0; i < length; i++) {\n            var b1 = points[i],\n                b2 = points[(i + 1) % length],\n                inter = Intersection.intersectLineLine(a1, a2, b1, b2);\n\n            result.appendPoints(inter.points);\n        }\n        if (result.points.length > 0) {\n            result.status = 'Intersection';\n        }\n        return result;\n    };\n\n    /**\n     * Checks if polygon intersects another polygon\n     * @static\n     * @param {Array} points1\n     * @param {Array} points2\n     * @return {fabric.Intersection}\n     */\n    fabric.Intersection.intersectPolygonPolygon = function (points1, points2) {\n        var result = new Intersection(),\n            length = points1.length;\n\n        for (var i = 0; i < length; i++) {\n            var a1 = points1[i],\n                a2 = points1[(i + 1) % length],\n                inter = Intersection.intersectLinePolygon(a1, a2, points2);\n\n            result.appendPoints(inter.points);\n        }\n        if (result.points.length > 0) {\n            result.status = 'Intersection';\n        }\n        return result;\n    };\n\n    /**\n     * Checks if polygon intersects rectangle\n     * @static\n     * @param {Array} points\n     * @param {Number} r1\n     * @param {Number} r2\n     * @return {fabric.Intersection}\n     */\n    fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) {\n        var min = r1.min(r2),\n            max = r1.max(r2),\n            topRight = new fabric.Point(max.x, min.y),\n            bottomLeft = new fabric.Point(min.x, max.y),\n            inter1 = Intersection.intersectLinePolygon(min, topRight, points),\n            inter2 = Intersection.intersectLinePolygon(topRight, max, points),\n            inter3 = Intersection.intersectLinePolygon(max, bottomLeft, points),\n            inter4 = Intersection.intersectLinePolygon(bottomLeft, min, points),\n            result = new Intersection();\n\n        result.appendPoints(inter1.points);\n        result.appendPoints(inter2.points);\n        result.appendPoints(inter3.points);\n        result.appendPoints(inter4.points);\n\n        if (result.points.length > 0) {\n            result.status = 'Intersection';\n        }\n        return result;\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { });\n\n    if (fabric.Color) {\n        fabric.warn('fabric.Color is already defined.');\n        return;\n    }\n\n    /**\n     * Color class\n     * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations;\n     * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects.\n     *\n     * @class fabric.Color\n     * @param {String} color optional in hex or rgb(a) format\n     * @return {fabric.Color} thisArg\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors}\n     */\n    function Color(color) {\n        if (!color) {\n            this.setSource([0, 0, 0, 1]);\n        }\n        else {\n            this._tryParsingColor(color);\n        }\n    }\n\n    fabric.Color = Color;\n\n    fabric.Color.prototype = /** @lends fabric.Color.prototype */ {\n\n        /**\n         * @private\n         * @param {String|Array} color Color value to parse\n         */\n        _tryParsingColor: function(color) {\n            var source;\n\n            if (color in Color.colorNameMap) {\n                color = Color.colorNameMap[color];\n            }\n\n            if (color === 'transparent') {\n                this.setSource([255, 255, 255, 0]);\n                return;\n            }\n\n            source = Color.sourceFromHex(color);\n\n            if (!source) {\n                source = Color.sourceFromRgb(color);\n            }\n            if (!source) {\n                source = Color.sourceFromHsl(color);\n            }\n            if (source) {\n                this.setSource(source);\n            }\n        },\n\n        /**\n         * Adapted from <a href=\"https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html\">https://github.com/mjijackson</a>\n         * @private\n         * @param {Number} r Red color value\n         * @param {Number} g Green color value\n         * @param {Number} b Blue color value\n         * @return {Array} Hsl color\n         */\n        _rgbToHsl: function(r, g, b) {\n            r /= 255, g /= 255, b /= 255;\n\n            var h, s, l,\n                max = fabric.util.array.max([r, g, b]),\n                min = fabric.util.array.min([r, g, b]);\n\n            l = (max + min) / 2;\n\n            if (max === min) {\n                h = s = 0; // achromatic\n            }\n            else {\n                var d = max - min;\n                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n                switch (max) {\n                    case r:\n                        h = (g - b) / d + (g < b ? 6 : 0);\n                        break;\n                    case g:\n                        h = (b - r) / d + 2;\n                        break;\n                    case b:\n                        h = (r - g) / d + 4;\n                        break;\n                }\n                h /= 6;\n            }\n\n            return [\n                Math.round(h * 360),\n                Math.round(s * 100),\n                Math.round(l * 100)\n            ];\n        },\n\n        /**\n         * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n         * @return {Array}\n         */\n        getSource: function() {\n            return this._source;\n        },\n\n        /**\n         * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n         * @param {Array} source\n         */\n        setSource: function(source) {\n            this._source = source;\n        },\n\n        /**\n         * Returns color represenation in RGB format\n         * @return {String} ex: rgb(0-255,0-255,0-255)\n         */\n        toRgb: function() {\n            var source = this.getSource();\n            return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')';\n        },\n\n        /**\n         * Returns color represenation in RGBA format\n         * @return {String} ex: rgba(0-255,0-255,0-255,0-1)\n         */\n        toRgba: function() {\n            var source = this.getSource();\n            return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';\n        },\n\n        /**\n         * Returns color represenation in HSL format\n         * @return {String} ex: hsl(0-360,0%-100%,0%-100%)\n         */\n        toHsl: function() {\n            var source = this.getSource(),\n                hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n            return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';\n        },\n\n        /**\n         * Returns color represenation in HSLA format\n         * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)\n         */\n        toHsla: function() {\n            var source = this.getSource(),\n                hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n            return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';\n        },\n\n        /**\n         * Returns color represenation in HEX format\n         * @return {String} ex: FF5555\n         */\n        toHex: function() {\n            var source = this.getSource(), r, g, b;\n\n            r = source[0].toString(16);\n            r = (r.length === 1) ? ('0' + r) : r;\n\n            g = source[1].toString(16);\n            g = (g.length === 1) ? ('0' + g) : g;\n\n            b = source[2].toString(16);\n            b = (b.length === 1) ? ('0' + b) : b;\n\n            return r.toUpperCase() + g.toUpperCase() + b.toUpperCase();\n        },\n\n        /**\n         * Gets value of alpha channel for this color\n         * @return {Number} 0-1\n         */\n        getAlpha: function() {\n            return this.getSource()[3];\n        },\n\n        /**\n         * Sets value of alpha channel for this color\n         * @param {Number} alpha Alpha value 0-1\n         * @return {fabric.Color} thisArg\n         */\n        setAlpha: function(alpha) {\n            var source = this.getSource();\n            source[3] = alpha;\n            this.setSource(source);\n            return this;\n        },\n\n        /**\n         * Transforms color to its grayscale representation\n         * @return {fabric.Color} thisArg\n         */\n        toGrayscale: function() {\n            var source = this.getSource(),\n                average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10),\n                currentAlpha = source[3];\n            this.setSource([average, average, average, currentAlpha]);\n            return this;\n        },\n\n        /**\n         * Transforms color to its black and white representation\n         * @param {Number} threshold\n         * @return {fabric.Color} thisArg\n         */\n        toBlackWhite: function(threshold) {\n            var source = this.getSource(),\n                average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0),\n                currentAlpha = source[3];\n\n            threshold = threshold || 127;\n\n            average = (Number(average) < Number(threshold)) ? 0 : 255;\n            this.setSource([average, average, average, currentAlpha]);\n            return this;\n        },\n\n        /**\n         * Overlays color with another color\n         * @param {String|fabric.Color} otherColor\n         * @return {fabric.Color} thisArg\n         */\n        overlayWith: function(otherColor) {\n            if (!(otherColor instanceof Color)) {\n                otherColor = new Color(otherColor);\n            }\n\n            var result = [],\n                alpha = this.getAlpha(),\n                otherAlpha = 0.5,\n                source = this.getSource(),\n                otherSource = otherColor.getSource();\n\n            for (var i = 0; i < 3; i++) {\n                result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha)));\n            }\n\n            result[3] = alpha;\n            this.setSource(result);\n            return this;\n        }\n    };\n\n    /**\n     * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5))\n     * @static\n     * @field\n     * @memberOf fabric.Color\n     */\n    fabric.Color.reRGBa = /^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/;\n\n    /**\n     * Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 ))\n     * @static\n     * @field\n     * @memberOf fabric.Color\n     */\n    fabric.Color.reHSLa = /^hsla?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}\\%)\\s*,\\s*(\\d{1,3}\\%)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/;\n\n    /**\n     * Regex matching color in HEX format (ex: #FF5555, 010155, aff)\n     * @static\n     * @field\n     * @memberOf fabric.Color\n     */\n    fabric.Color.reHex = /^#?([0-9a-f]{6}|[0-9a-f]{3})$/i;\n\n    /**\n     * Map of the 17 basic color names with HEX code\n     * @static\n     * @field\n     * @memberOf fabric.Color\n     * @see: http://www.w3.org/TR/CSS2/syndata.html#color-units\n     */\n    fabric.Color.colorNameMap = {\n        aqua:    '#00FFFF',\n        black:   '#000000',\n        blue:    '#0000FF',\n        fuchsia: '#FF00FF',\n        gray:    '#808080',\n        green:   '#008000',\n        lime:    '#00FF00',\n        maroon:  '#800000',\n        navy:    '#000080',\n        olive:   '#808000',\n        orange:  '#FFA500',\n        purple:  '#800080',\n        red:     '#FF0000',\n        silver:  '#C0C0C0',\n        teal:    '#008080',\n        white:   '#FFFFFF',\n        yellow:  '#FFFF00'\n    };\n\n    /**\n     * @private\n     * @param {Number} p\n     * @param {Number} q\n     * @param {Number} t\n     * @return {Number}\n     */\n    function hue2rgb(p, q, t) {\n        if (t < 0) {\n            t += 1;\n        }\n        if (t > 1) {\n            t -= 1;\n        }\n        if (t < 1/6) {\n            return p + (q - p) * 6 * t;\n        }\n        if (t < 1/2) {\n            return q;\n        }\n        if (t < 2/3) {\n            return p + (q - p) * (2/3 - t) * 6;\n        }\n        return p;\n    }\n\n    /**\n     * Returns new color object, when given a color in RGB format\n     * @memberOf fabric.Color\n     * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n     * @return {fabric.Color}\n     */\n    fabric.Color.fromRgb = function(color) {\n        return Color.fromSource(Color.sourceFromRgb(color));\n    };\n\n    /**\n     * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format\n     * @memberOf fabric.Color\n     * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)\n     * @return {Array} source\n     */\n    fabric.Color.sourceFromRgb = function(color) {\n        var match = color.match(Color.reRGBa);\n        if (match) {\n            var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),\n                g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),\n                b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);\n\n            return [\n                parseInt(r, 10),\n                parseInt(g, 10),\n                parseInt(b, 10),\n                match[4] ? parseFloat(match[4]) : 1\n            ];\n        }\n    };\n\n    /**\n     * Returns new color object, when given a color in RGBA format\n     * @static\n     * @function\n     * @memberOf fabric.Color\n     * @param {String} color\n     * @return {fabric.Color}\n     */\n    fabric.Color.fromRgba = Color.fromRgb;\n\n    /**\n     * Returns new color object, when given a color in HSL format\n     * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n     * @memberOf fabric.Color\n     * @return {fabric.Color}\n     */\n    fabric.Color.fromHsl = function(color) {\n        return Color.fromSource(Color.sourceFromHsl(color));\n    };\n\n    /**\n     * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.\n     * Adapted from <a href=\"https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html\">https://github.com/mjijackson</a>\n     * @memberOf fabric.Color\n     * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)\n     * @return {Array} source\n     * @see http://http://www.w3.org/TR/css3-color/#hsl-color\n     */\n    fabric.Color.sourceFromHsl = function(color) {\n        var match = color.match(Color.reHSLa);\n        if (!match) {\n            return;\n        }\n\n        var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,\n            s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),\n            l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),\n            r, g, b;\n\n        if (s === 0) {\n            r = g = b = l;\n        }\n        else {\n            var q = l <= 0.5 ? l * (s + 1) : l + s - l * s,\n                p = l * 2 - q;\n\n            r = hue2rgb(p, q, h + 1/3);\n            g = hue2rgb(p, q, h);\n            b = hue2rgb(p, q, h - 1/3);\n        }\n\n        return [\n            Math.round(r * 255),\n            Math.round(g * 255),\n            Math.round(b * 255),\n            match[4] ? parseFloat(match[4]) : 1\n        ];\n    };\n\n    /**\n     * Returns new color object, when given a color in HSLA format\n     * @static\n     * @function\n     * @memberOf fabric.Color\n     * @param {String} color\n     * @return {fabric.Color}\n     */\n    fabric.Color.fromHsla = Color.fromHsl;\n\n    /**\n     * Returns new color object, when given a color in HEX format\n     * @static\n     * @memberOf fabric.Color\n     * @param {String} color Color value ex: FF5555\n     * @return {fabric.Color}\n     */\n    fabric.Color.fromHex = function(color) {\n        return Color.fromSource(Color.sourceFromHex(color));\n    };\n\n    /**\n     * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HEX format\n     * @static\n     * @memberOf fabric.Color\n     * @param {String} color ex: FF5555\n     * @return {Array} source\n     */\n    fabric.Color.sourceFromHex = function(color) {\n        if (color.match(Color.reHex)) {\n            var value = color.slice(color.indexOf('#') + 1),\n                isShortNotation = (value.length === 3),\n                r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2),\n                g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4),\n                b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6);\n\n            return [\n                parseInt(r, 16),\n                parseInt(g, 16),\n                parseInt(b, 16),\n                1\n            ];\n        }\n    };\n\n    /**\n     * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])\n     * @static\n     * @memberOf fabric.Color\n     * @param {Array} source\n     * @return {fabric.Color}\n     */\n    fabric.Color.fromSource = function(source) {\n        var oColor = new Color();\n        oColor.setSource(source);\n        return oColor;\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n    /* _FROM_SVG_START_ */\n    function getColorStop(el) {\n        var style = el.getAttribute('style'),\n            offset = el.getAttribute('offset'),\n            color, colorAlpha, opacity;\n\n        // convert percents to absolute values\n        offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);\n        offset = offset < 0 ? 0 : offset > 1 ? 1 : offset;\n        if (style) {\n            var keyValuePairs = style.split(/\\s*;\\s*/);\n\n            if (keyValuePairs[keyValuePairs.length - 1] === '') {\n                keyValuePairs.pop();\n            }\n\n            for (var i = keyValuePairs.length; i--; ) {\n\n                var split = keyValuePairs[i].split(/\\s*:\\s*/),\n                    key = split[0].trim(),\n                    value = split[1].trim();\n\n                if (key === 'stop-color') {\n                    color = value;\n                }\n                else if (key === 'stop-opacity') {\n                    opacity = value;\n                }\n            }\n        }\n\n        if (!color) {\n            color = el.getAttribute('stop-color') || 'rgb(0,0,0)';\n        }\n        if (!opacity) {\n            opacity = el.getAttribute('stop-opacity');\n        }\n\n        color = new fabric.Color(color);\n        colorAlpha = color.getAlpha();\n        opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);\n        opacity *= colorAlpha;\n\n        return {\n            offset: offset,\n            color: color.toRgb(),\n            opacity: opacity\n        };\n    }\n\n    function getLinearCoords(el) {\n        return {\n            x1: el.getAttribute('x1') || 0,\n            y1: el.getAttribute('y1') || 0,\n            x2: el.getAttribute('x2') || '100%',\n            y2: el.getAttribute('y2') || 0\n        };\n    }\n\n    function getRadialCoords(el) {\n        return {\n            x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',\n            y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',\n            r1: 0,\n            x2: el.getAttribute('cx') || '50%',\n            y2: el.getAttribute('cy') || '50%',\n            r2: el.getAttribute('r') || '50%'\n        };\n    }\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Gradient class\n     * @class fabric.Gradient\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#gradients}\n     * @see {@link fabric.Gradient#initialize} for constructor definition\n     */\n    fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {\n\n        /**\n         * Horizontal offset for aligning gradients coming from SVG when outside pathgroups\n         * @type Number\n         * @default 0\n         */\n        offsetX: 0,\n\n        /**\n         * Vertical offset for aligning gradients coming from SVG when outside pathgroups\n         * @type Number\n         * @default 0\n         */\n        offsetY: 0,\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops\n         * @return {fabric.Gradient} thisArg\n         */\n        initialize: function(options) {\n            options || (options = { });\n\n            var coords = { };\n\n            this.id = fabric.Object.__uid++;\n            this.type = options.type || 'linear';\n\n            coords = {\n                x1: options.coords.x1 || 0,\n                y1: options.coords.y1 || 0,\n                x2: options.coords.x2 || 0,\n                y2: options.coords.y2 || 0\n            };\n\n            if (this.type === 'radial') {\n                coords.r1 = options.coords.r1 || 0;\n                coords.r2 = options.coords.r2 || 0;\n            }\n            this.coords = coords;\n            this.colorStops = options.colorStops.slice();\n            if (options.gradientTransform) {\n                this.gradientTransform = options.gradientTransform;\n            }\n            this.offsetX = options.offsetX || this.offsetX;\n            this.offsetY = options.offsetY || this.offsetY;\n        },\n\n        /**\n         * Adds another colorStop\n         * @param {Object} colorStop Object with offset and color\n         * @return {fabric.Gradient} thisArg\n         */\n        addColorStop: function(colorStop) {\n            for (var position in colorStop) {\n                var color = new fabric.Color(colorStop[position]);\n                this.colorStops.push({\n                    offset: position,\n                    color: color.toRgb(),\n                    opacity: color.getAlpha()\n                });\n            }\n            return this;\n        },\n\n        /**\n         * Returns object representation of a gradient\n         * @return {Object}\n         */\n        toObject: function() {\n            return {\n                type: this.type,\n                coords: this.coords,\n                colorStops: this.colorStops,\n                offsetX: this.offsetX,\n                offsetY: this.offsetY\n            };\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of an gradient\n         * @param {Object} object Object to create a gradient for\n         * @param {Boolean} normalize Whether coords should be normalized\n         * @return {String} SVG representation of an gradient (linear/radial)\n         */\n        toSVG: function(object) {\n            var coords = fabric.util.object.clone(this.coords),\n                markup, commonAttributes;\n\n            // colorStops must be sorted ascending\n            this.colorStops.sort(function(a, b) {\n                return a.offset - b.offset;\n            });\n\n            if (!(object.group && object.group.type === 'path-group')) {\n                for (var prop in coords) {\n                    if (prop === 'x1' || prop === 'x2' || prop === 'r2') {\n                        coords[prop] += this.offsetX - object.width / 2;\n                    }\n                    else if (prop === 'y1' || prop === 'y2') {\n                        coords[prop] += this.offsetY - object.height / 2;\n                    }\n                }\n            }\n\n            commonAttributes = 'id=\"SVGID_' + this.id +\n                '\" gradientUnits=\"userSpaceOnUse\"';\n            if (this.gradientTransform) {\n                commonAttributes += ' gradientTransform=\"matrix(' + this.gradientTransform.join(' ') + ')\" ';\n            }\n            if (this.type === 'linear') {\n                markup = [\n                    //jscs:disable validateIndentation\n                    '<linearGradient ',\n                    commonAttributes,\n                    ' x1=\"', coords.x1,\n                    '\" y1=\"', coords.y1,\n                    '\" x2=\"', coords.x2,\n                    '\" y2=\"', coords.y2,\n                    '\">\\n'\n                    //jscs:enable validateIndentation\n                ];\n            }\n            else if (this.type === 'radial') {\n                markup = [\n                    //jscs:disable validateIndentation\n                    '<radialGradient ',\n                    commonAttributes,\n                    ' cx=\"', coords.x2,\n                    '\" cy=\"', coords.y2,\n                    '\" r=\"', coords.r2,\n                    '\" fx=\"', coords.x1,\n                    '\" fy=\"', coords.y1,\n                    '\">\\n'\n                    //jscs:enable validateIndentation\n                ];\n            }\n\n            for (var i = 0; i < this.colorStops.length; i++) {\n                markup.push(\n                    //jscs:disable validateIndentation\n                    '<stop ',\n                    'offset=\"', (this.colorStops[i].offset * 100) + '%',\n                    '\" style=\"stop-color:', this.colorStops[i].color,\n                    (this.colorStops[i].opacity != null ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),\n                    '\"/>\\n'\n                    //jscs:enable validateIndentation\n                );\n            }\n\n            markup.push((this.type === 'linear' ? '</linearGradient>\\n' : '</radialGradient>\\n'));\n\n            return markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns an instance of CanvasGradient\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @return {CanvasGradient}\n         */\n        toLive: function(ctx, object) {\n            var gradient, coords = fabric.util.object.clone(this.coords);\n\n            if (!this.type) {\n                return;\n            }\n\n            if (object.group && object.group.type === 'path-group') {\n                for (var prop in coords) {\n                    if (prop === 'x1' || prop === 'x2') {\n                        coords[prop] += -this.offsetX + object.width / 2;\n                    }\n                    else if (prop === 'y1' || prop === 'y2') {\n                        coords[prop] += -this.offsetY + object.height / 2;\n                    }\n                }\n            }\n\n            if (this.type === 'linear') {\n                gradient = ctx.createLinearGradient(\n                    coords.x1, coords.y1, coords.x2, coords.y2);\n            }\n            else if (this.type === 'radial') {\n                gradient = ctx.createRadialGradient(\n                    coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2);\n            }\n\n            for (var i = 0, len = this.colorStops.length; i < len; i++) {\n                var color = this.colorStops[i].color,\n                    opacity = this.colorStops[i].opacity,\n                    offset = this.colorStops[i].offset;\n\n                if (typeof opacity !== 'undefined') {\n                    color = new fabric.Color(color).setAlpha(opacity).toRgba();\n                }\n                gradient.addColorStop(parseFloat(offset), color);\n            }\n\n            return gradient;\n        }\n    });\n\n    fabric.util.object.extend(fabric.Gradient, {\n\n        /* _FROM_SVG_START_ */\n        /**\n         * Returns {@link fabric.Gradient} instance from an SVG element\n         * @static\n         * @memberof fabric.Gradient\n         * @param {SVGGradientElement} el SVG gradient element\n         * @param {fabric.Object} instance\n         * @return {fabric.Gradient} Gradient instance\n         * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement\n         * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement\n         */\n        fromElement: function(el, instance) {\n\n            /**\n             *  @example:\n             *\n             *  <linearGradient id=\"linearGrad1\">\n             *    <stop offset=\"0%\" stop-color=\"white\"/>\n             *    <stop offset=\"100%\" stop-color=\"black\"/>\n             *  </linearGradient>\n             *\n             *  OR\n             *\n             *  <linearGradient id=\"linearGrad2\">\n             *    <stop offset=\"0\" style=\"stop-color:rgb(255,255,255)\"/>\n             *    <stop offset=\"1\" style=\"stop-color:rgb(0,0,0)\"/>\n             *  </linearGradient>\n             *\n             *  OR\n             *\n             *  <radialGradient id=\"radialGrad1\">\n             *    <stop offset=\"0%\" stop-color=\"white\" stop-opacity=\"1\" />\n             *    <stop offset=\"50%\" stop-color=\"black\" stop-opacity=\"0.5\" />\n             *    <stop offset=\"100%\" stop-color=\"white\" stop-opacity=\"1\" />\n             *  </radialGradient>\n             *\n             *  OR\n             *\n             *  <radialGradient id=\"radialGrad2\">\n             *    <stop offset=\"0\" stop-color=\"rgb(255,255,255)\" />\n             *    <stop offset=\"0.5\" stop-color=\"rgb(0,0,0)\" />\n             *    <stop offset=\"1\" stop-color=\"rgb(255,255,255)\" />\n             *  </radialGradient>\n             *\n             */\n\n            var colorStopEls = el.getElementsByTagName('stop'),\n                type = (el.nodeName === 'linearGradient' ? 'linear' : 'radial'),\n                gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',\n                gradientTransform = el.getAttribute('gradientTransform'),\n                colorStops = [],\n                coords = { }, ellipseMatrix;\n\n            if (type === 'linear') {\n                coords = getLinearCoords(el);\n            }\n            else if (type === 'radial') {\n                coords = getRadialCoords(el);\n            }\n\n            for (var i = colorStopEls.length; i--; ) {\n                colorStops.push(getColorStop(colorStopEls[i]));\n            }\n\n            ellipseMatrix = _convertPercentUnitsToValues(instance, coords, gradientUnits);\n\n            var gradient = new fabric.Gradient({\n                type: type,\n                coords: coords,\n                colorStops: colorStops,\n                offsetX: -instance.left,\n                offsetY: -instance.top\n            });\n\n            if (gradientTransform || ellipseMatrix !== '') {\n                gradient.gradientTransform = fabric.parseTransformAttribute((gradientTransform || '') + ellipseMatrix);\n            }\n            return gradient;\n        },\n        /* _FROM_SVG_END_ */\n\n        /**\n         * Returns {@link fabric.Gradient} instance from its object representation\n         * @static\n         * @memberof fabric.Gradient\n         * @param {Object} obj\n         * @param {Object} [options] Options object\n         */\n        forObject: function(obj, options) {\n            options || (options = { });\n            _convertPercentUnitsToValues(obj, options.coords, 'userSpaceOnUse');\n            return new fabric.Gradient(options);\n        }\n    });\n\n    /**\n     * @private\n     */\n    function _convertPercentUnitsToValues(object, options, gradientUnits) {\n        var propValue, addFactor = 0, multFactor = 1, ellipseMatrix = '';\n        for (var prop in options) {\n            propValue = parseFloat(options[prop], 10);\n            if (typeof options[prop] === 'string' && /^\\d+%$/.test(options[prop])) {\n                multFactor = 0.01;\n            }\n            else {\n                multFactor = 1;\n            }\n            if (prop === 'x1' || prop === 'x2' || prop === 'r2') {\n                multFactor *= gradientUnits === 'objectBoundingBox' ? object.width : 1;\n                addFactor = gradientUnits === 'objectBoundingBox' ? object.left || 0 : 0;\n            }\n            else if (prop === 'y1' || prop === 'y2') {\n                multFactor *= gradientUnits === 'objectBoundingBox' ? object.height : 1;\n                addFactor = gradientUnits === 'objectBoundingBox' ? object.top || 0 : 0;\n            }\n            options[prop] = propValue * multFactor + addFactor;\n        }\n        if (object.type === 'ellipse' &&\n            options.r2 !== null &&\n            gradientUnits === 'objectBoundingBox' &&\n            object.rx !== object.ry) {\n\n            var scaleFactor = object.ry/object.rx;\n            ellipseMatrix = ' scale(1, ' + scaleFactor + ')';\n            if (options.y1) {\n                options.y1 /= scaleFactor;\n            }\n            if (options.y2) {\n                options.y2 /= scaleFactor;\n            }\n        }\n        return ellipseMatrix;\n    }\n})();\n\n\n/**\n * Pattern class\n * @class fabric.Pattern\n * @see {@link http://fabricjs.com/patterns/|Pattern demo}\n * @see {@link http://fabricjs.com/dynamic-patterns/|DynamicPattern demo}\n * @see {@link fabric.Pattern#initialize} for constructor definition\n */\nfabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ {\n\n    /**\n     * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n     * @type String\n     * @default\n     */\n    repeat: 'repeat',\n\n    /**\n     * Pattern horizontal offset from object's left/top corner\n     * @type Number\n     * @default\n     */\n    offsetX: 0,\n\n    /**\n     * Pattern vertical offset from object's left/top corner\n     * @type Number\n     * @default\n     */\n    offsetY: 0,\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {fabric.Pattern} thisArg\n     */\n    initialize: function(options) {\n        options || (options = { });\n\n        this.id = fabric.Object.__uid++;\n\n        if (options.source) {\n            if (typeof options.source === 'string') {\n                // function string\n                if (typeof fabric.util.getFunctionBody(options.source) !== 'undefined') {\n                    this.source = new Function(fabric.util.getFunctionBody(options.source));\n                }\n                else {\n                    // img src string\n                    var _this = this;\n                    this.source = fabric.util.createImage();\n                    fabric.util.loadImage(options.source, function(img) {\n                        _this.source = img;\n                    });\n                }\n            }\n            else {\n                // img element\n                this.source = options.source;\n            }\n        }\n        if (options.repeat) {\n            this.repeat = options.repeat;\n        }\n        if (options.offsetX) {\n            this.offsetX = options.offsetX;\n        }\n        if (options.offsetY) {\n            this.offsetY = options.offsetY;\n        }\n    },\n\n    /**\n     * Returns object representation of a pattern\n     * @return {Object} Object representation of a pattern instance\n     */\n    toObject: function() {\n\n        var source;\n\n        // callback\n        if (typeof this.source === 'function') {\n            source = String(this.source);\n        }\n        // <img> element\n        else if (typeof this.source.src === 'string') {\n            source = this.source.src;\n        }\n\n        return {\n            source: source,\n            repeat: this.repeat,\n            offsetX: this.offsetX,\n            offsetY: this.offsetY\n        };\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of a pattern\n     * @param {fabric.Object} object\n     * @return {String} SVG representation of a pattern\n     */\n    toSVG: function(object) {\n        var patternSource = typeof this.source === 'function' ? this.source() : this.source,\n            patternWidth = patternSource.width / object.getWidth(),\n            patternHeight = patternSource.height / object.getHeight(),\n            patternImgSrc = '';\n\n        if (patternSource.src) {\n            patternImgSrc = patternSource.src;\n        }\n        else if (patternSource.toDataURL) {\n            patternImgSrc = patternSource.toDataURL();\n        }\n\n        return '<pattern id=\"SVGID_' + this.id +\n            '\" x=\"' + this.offsetX +\n            '\" y=\"' + this.offsetY +\n            '\" width=\"' + patternWidth +\n            '\" height=\"' + patternHeight + '\">' +\n            '<image x=\"0\" y=\"0\"' +\n            ' width=\"' + patternSource.width +\n            '\" height=\"' + patternSource.height +\n            '\" xlink:href=\"' + patternImgSrc +\n            '\"></image>' +\n            '</pattern>';\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns an instance of CanvasPattern\n     * @param {CanvasRenderingContext2D} ctx Context to create pattern\n     * @return {CanvasPattern}\n     */\n    toLive: function(ctx) {\n        var source = typeof this.source === 'function'\n            ? this.source()\n            : this.source;\n\n        // if the image failed to load, return, and allow rest to continue loading\n        if (!source) {\n            return '';\n        }\n\n        // if an image\n        if (typeof source.src !== 'undefined') {\n            if (!source.complete) {\n                return '';\n            }\n            if (source.naturalWidth === 0 || source.naturalHeight === 0) {\n                return '';\n            }\n        }\n        return ctx.createPattern(source, this.repeat);\n    }\n});\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { });\n\n    if (fabric.Shadow) {\n        fabric.warn('fabric.Shadow is already defined.');\n        return;\n    }\n\n    /**\n     * Shadow class\n     * @class fabric.Shadow\n     * @see {@link http://fabricjs.com/shadows/|Shadow demo}\n     * @see {@link fabric.Shadow#initialize} for constructor definition\n     */\n    fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {\n\n        /**\n         * Shadow color\n         * @type String\n         * @default\n         */\n        color: 'rgb(0,0,0)',\n\n        /**\n         * Shadow blur\n         * @type Number\n         */\n        blur: 0,\n\n        /**\n         * Shadow horizontal offset\n         * @type Number\n         * @default\n         */\n        offsetX: 0,\n\n        /**\n         * Shadow vertical offset\n         * @type Number\n         * @default\n         */\n        offsetY: 0,\n\n        /**\n         * Whether the shadow should affect stroke operations\n         * @type Boolean\n         * @default\n         */\n        affectStroke: false,\n\n        /**\n         * Indicates whether toObject should include default values\n         * @type Boolean\n         * @default\n         */\n        includeDefaultValues: true,\n\n        /**\n         * Constructor\n         * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetX properties or string (e.g. \"rgba(0,0,0,0.2) 2px 2px 10px, \"2px 2px 10px rgba(0,0,0,0.2)\")\n         * @return {fabric.Shadow} thisArg\n         */\n        initialize: function(options) {\n\n            if (typeof options === 'string') {\n                options = this._parseShadow(options);\n            }\n\n            for (var prop in options) {\n                this[prop] = options[prop];\n            }\n\n            this.id = fabric.Object.__uid++;\n        },\n\n        /**\n         * @private\n         * @param {String} shadow Shadow value to parse\n         * @return {Object} Shadow object with color, offsetX, offsetY and blur\n         */\n        _parseShadow: function(shadow) {\n            var shadowStr = shadow.trim(),\n                offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [ ],\n                color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)';\n\n            return {\n                color: color.trim(),\n                offsetX: parseInt(offsetsAndBlur[1], 10) || 0,\n                offsetY: parseInt(offsetsAndBlur[2], 10) || 0,\n                blur: parseInt(offsetsAndBlur[3], 10) || 0\n            };\n        },\n\n        /**\n         * Returns a string representation of an instance\n         * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow\n         * @return {String} Returns CSS3 text-shadow declaration\n         */\n        toString: function() {\n            return [this.offsetX, this.offsetY, this.blur, this.color].join('px ');\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of a shadow\n         * @param {fabric.Object} object\n         * @return {String} SVG representation of a shadow\n         */\n        toSVG: function(object) {\n            var mode = 'SourceAlpha';\n\n            if (object && (object.fill === this.color || object.stroke === this.color)) {\n                mode = 'SourceGraphic';\n            }\n\n            return (\n                '<filter id=\"SVGID_' + this.id + '\" y=\"-40%\" height=\"180%\">' +\n                '<feGaussianBlur in=\"' + mode + '\" stdDeviation=\"' +\n                (this.blur ? this.blur / 3 : 0) +\n                '\"></feGaussianBlur>' +\n                '<feOffset dx=\"' + this.offsetX + '\" dy=\"' + this.offsetY + '\"></feOffset>' +\n                '<feMerge>' +\n                '<feMergeNode></feMergeNode>' +\n                '<feMergeNode in=\"SourceGraphic\"></feMergeNode>' +\n                '</feMerge>' +\n                '</filter>');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns object representation of a shadow\n         * @return {Object} Object representation of a shadow instance\n         */\n        toObject: function() {\n            if (this.includeDefaultValues) {\n                return {\n                    color: this.color,\n                    blur: this.blur,\n                    offsetX: this.offsetX,\n                    offsetY: this.offsetY\n                };\n            }\n            var obj = { }, proto = fabric.Shadow.prototype;\n            if (this.color !== proto.color) {\n                obj.color = this.color;\n            }\n            if (this.blur !== proto.blur) {\n                obj.blur = this.blur;\n            }\n            if (this.offsetX !== proto.offsetX) {\n                obj.offsetX = this.offsetX;\n            }\n            if (this.offsetY !== proto.offsetY) {\n                obj.offsetY = this.offsetY;\n            }\n            return obj;\n        }\n    });\n\n    /**\n     * Regex matching shadow offsetX, offsetY and blur (ex: \"2px 2px 10px rgba(0,0,0,0.2)\", \"rgb(0,255,0) 2px 2px\")\n     * @static\n     * @field\n     * @memberOf fabric.Shadow\n     */\n    fabric.Shadow.reOffsetsAndBlur = /(?:\\s|^)(-?\\d+(?:px)?(?:\\s?|$))?(-?\\d+(?:px)?(?:\\s?|$))?(\\d+(?:px)?)?(?:\\s?|$)(?:$|\\s)/;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function () {\n\n    'use strict';\n\n    if (fabric.StaticCanvas) {\n        fabric.warn('fabric.StaticCanvas is already defined.');\n        return;\n    }\n\n    // aliases for faster resolution\n    var extend = fabric.util.object.extend,\n        getElementOffset = fabric.util.getElementOffset,\n        removeFromArray = fabric.util.removeFromArray,\n\n        CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element');\n\n    /**\n     * Static canvas class\n     * @class fabric.StaticCanvas\n     * @mixes fabric.Collection\n     * @mixes fabric.Observable\n     * @see {@link http://fabricjs.com/static_canvas/|StaticCanvas demo}\n     * @see {@link fabric.StaticCanvas#initialize} for constructor definition\n     * @fires before:render\n     * @fires after:render\n     * @fires canvas:cleared\n     * @fires object:added\n     * @fires object:removed\n     */\n    fabric.StaticCanvas = fabric.util.createClass(/** @lends fabric.StaticCanvas.prototype */ {\n\n        /**\n         * Constructor\n         * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n         * @param {Object} [options] Options object\n         * @return {Object} thisArg\n         */\n        initialize: function(el, options) {\n            options || (options = { });\n\n            this._initStatic(el, options);\n            fabric.StaticCanvas.activeInstance = this;\n        },\n\n        /**\n         * Background color of canvas instance.\n         * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}.\n         * @type {(String|fabric.Pattern)}\n         * @default\n         */\n        backgroundColor: '',\n\n        /**\n         * Background image of canvas instance.\n         * Should be set via {@link fabric.StaticCanvas#setBackgroundImage}.\n         * <b>Backwards incompatibility note:</b> The \"backgroundImageOpacity\"\n         * and \"backgroundImageStretch\" properties are deprecated since 1.3.9.\n         * Use {@link fabric.Image#opacity}, {@link fabric.Image#width} and {@link fabric.Image#height}.\n         * @type fabric.Image\n         * @default\n         */\n        backgroundImage: null,\n\n        /**\n         * Overlay color of canvas instance.\n         * Should be set via {@link fabric.StaticCanvas#setOverlayColor}\n         * @since 1.3.9\n         * @type {(String|fabric.Pattern)}\n         * @default\n         */\n        overlayColor: '',\n\n        /**\n         * Overlay image of canvas instance.\n         * Should be set via {@link fabric.StaticCanvas#setOverlayImage}.\n         * <b>Backwards incompatibility note:</b> The \"overlayImageLeft\"\n         * and \"overlayImageTop\" properties are deprecated since 1.3.9.\n         * Use {@link fabric.Image#left} and {@link fabric.Image#top}.\n         * @type fabric.Image\n         * @default\n         */\n        overlayImage: null,\n\n        /**\n         * Indicates whether toObject/toDatalessObject should include default values\n         * @type Boolean\n         * @default\n         */\n        includeDefaultValues: true,\n\n        /**\n         * Indicates whether objects' state should be saved\n         * @type Boolean\n         * @default\n         */\n        stateful: true,\n\n        /**\n         * Indicates whether {@link fabric.Collection.add}, {@link fabric.Collection.insertAt} and {@link fabric.Collection.remove} should also re-render canvas.\n         * Disabling this option could give a great performance boost when adding/removing a lot of objects to/from canvas at once\n         * (followed by a manual rendering after addition/deletion)\n         * @type Boolean\n         * @default\n         */\n        renderOnAddRemove: true,\n\n        /**\n         * Function that determines clipping of entire canvas area\n         * Being passed context as first argument. See clipping canvas area in {@link https://github.com/kangax/fabric.js/wiki/FAQ}\n         * @type Function\n         * @default\n         */\n        clipTo: null,\n\n        /**\n         * Indicates whether object controls (borders/controls) are rendered above overlay image\n         * @type Boolean\n         * @default\n         */\n        controlsAboveOverlay: false,\n\n        /**\n         * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas\n         * @type Boolean\n         * @default\n         */\n        allowTouchScrolling: false,\n\n        /**\n         * Indicates whether this canvas will use image smoothing, this is on by default in browsers\n         * @type Boolean\n         * @default\n         */\n        imageSmoothingEnabled: true,\n\n        /**\n         * Indicates whether objects should remain in current stack position when selected. When false objects are brought to top and rendered as part of the selection group\n         * @type Boolean\n         * @default\n         */\n        preserveObjectStacking: false,\n\n        /**\n         * The transformation (in the format of Canvas transform) which focuses the viewport\n         * @type Array\n         * @default\n         */\n        viewportTransform: [1, 0, 0, 1, 0, 0],\n\n        /**\n         * Callback; invoked right before object is about to be scaled/rotated\n         */\n        onBeforeScaleRotate: function () {\n            /* NOOP */\n        },\n\n        /**\n         * @private\n         * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n         * @param {Object} [options] Options object\n         */\n        _initStatic: function(el, options) {\n            this._objects = [];\n\n            this._createLowerCanvas(el);\n            this._initOptions(options);\n            this._setImageSmoothing();\n\n            if (options.overlayImage) {\n                this.setOverlayImage(options.overlayImage, this.renderAll.bind(this));\n            }\n            if (options.backgroundImage) {\n                this.setBackgroundImage(options.backgroundImage, this.renderAll.bind(this));\n            }\n            if (options.backgroundColor) {\n                this.setBackgroundColor(options.backgroundColor, this.renderAll.bind(this));\n            }\n            if (options.overlayColor) {\n                this.setOverlayColor(options.overlayColor, this.renderAll.bind(this));\n            }\n            this.calcOffset();\n        },\n\n        /**\n         * Calculates canvas element offset relative to the document\n         * This method is also attached as \"resize\" event handler of window\n         * @return {fabric.Canvas} instance\n         * @chainable\n         */\n        calcOffset: function () {\n            this._offset = getElementOffset(this.lowerCanvasEl);\n            return this;\n        },\n\n        /**\n         * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas\n         * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to\n         * @param {Function} callback callback to invoke when image is loaded and set as an overlay\n         * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}.\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo}\n         * @example <caption>Normal overlayImage with left/top = 0</caption>\n         * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   // Needed to position overlayImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n         * @example <caption>overlayImage with different properties</caption>\n         * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n         * @example <caption>Stretched overlayImage #1 - width/height correspond to canvas width/height</caption>\n         * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img) {\n     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n     *    canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));\n     * });\n         * @example <caption>Stretched overlayImage #2 - width/height correspond to canvas width/height</caption>\n         * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   width: canvas.width,\n     *   height: canvas.height,\n     *   // Needed to position overlayImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n         */\n        setOverlayImage: function (image, callback, options) {\n            return this.__setBgOverlayImage('overlayImage', image, callback, options);\n        },\n\n        /**\n         * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas\n         * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to\n         * @param {Function} callback Callback to invoke when image is loaded and set as background\n         * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}.\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/YH9yD/|jsFiddle demo}\n         * @example <caption>Normal backgroundImage with left/top = 0</caption>\n         * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   // Needed to position backgroundImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n         * @example <caption>backgroundImage with different properties</caption>\n         * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n         * @example <caption>Stretched backgroundImage #1 - width/height correspond to canvas width/height</caption>\n         * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img) {\n     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n     *    canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));\n     * });\n         * @example <caption>Stretched backgroundImage #2 - width/height correspond to canvas width/height</caption>\n         * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   width: canvas.width,\n     *   height: canvas.height,\n     *   // Needed to position backgroundImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n         */\n        setBackgroundImage: function (image, callback, options) {\n            return this.__setBgOverlayImage('backgroundImage', image, callback, options);\n        },\n\n        /**\n         * Sets {@link fabric.StaticCanvas#overlayColor|background color} for this canvas\n         * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set background color to\n         * @param {Function} callback Callback to invoke when background color is set\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo}\n         * @example <caption>Normal overlayColor - color value</caption>\n         * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n         * @example <caption>fabric.Pattern used as overlayColor</caption>\n         * canvas.setOverlayColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'\n     * }, canvas.renderAll.bind(canvas));\n         * @example <caption>fabric.Pattern used as overlayColor with repeat and offset</caption>\n         * canvas.setOverlayColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',\n     *   repeat: 'repeat',\n     *   offsetX: 200,\n     *   offsetY: 100\n     * }, canvas.renderAll.bind(canvas));\n         */\n        setOverlayColor: function(overlayColor, callback) {\n            return this.__setBgOverlayColor('overlayColor', overlayColor, callback);\n        },\n\n        /**\n         * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas\n         * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to\n         * @param {Function} callback Callback to invoke when background color is set\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo}\n         * @example <caption>Normal backgroundColor - color value</caption>\n         * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n         * @example <caption>fabric.Pattern used as backgroundColor</caption>\n         * canvas.setBackgroundColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'\n     * }, canvas.renderAll.bind(canvas));\n         * @example <caption>fabric.Pattern used as backgroundColor with repeat and offset</caption>\n         * canvas.setBackgroundColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',\n     *   repeat: 'repeat',\n     *   offsetX: 200,\n     *   offsetY: 100\n     * }, canvas.renderAll.bind(canvas));\n         */\n        setBackgroundColor: function(backgroundColor, callback) {\n            return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback);\n        },\n\n        /**\n         * @private\n         * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-imagesmoothingenabled|WhatWG Canvas Standard}\n         */\n        _setImageSmoothing: function() {\n            var ctx = this.getContext();\n\n            ctx.imageSmoothingEnabled       = this.imageSmoothingEnabled;\n            ctx.imageSmoothingEnabled       = this.imageSmoothingEnabled;\n            ctx.mozImageSmoothingEnabled    = this.imageSmoothingEnabled;\n            ctx.msImageSmoothingEnabled     = this.imageSmoothingEnabled;\n            ctx.oImageSmoothingEnabled      = this.imageSmoothingEnabled;\n        },\n\n        /**\n         * @private\n         * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage}\n         * or {@link fabric.StaticCanvas#overlayImage|overlayImage})\n         * @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to\n         * @param {Function} callback Callback to invoke when image is loaded and set as background or overlay\n         * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}.\n         */\n        __setBgOverlayImage: function(property, image, callback, options) {\n            if (typeof image === 'string') {\n                fabric.util.loadImage(image, function(img) {\n                    this[property] = new fabric.Image(img, options);\n                    callback && callback();\n                }, this);\n            }\n            else {\n                this[property] = image;\n                callback && callback();\n            }\n\n            return this;\n        },\n\n        /**\n         * @private\n         * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor}\n         * or {@link fabric.StaticCanvas#overlayColor|overlayColor})\n         * @param {(Object|String|null)} color Object with pattern information, color value or null\n         * @param {Function} [callback] Callback is invoked when color is set\n         */\n        __setBgOverlayColor: function(property, color, callback) {\n            if (color && color.source) {\n                var _this = this;\n                fabric.util.loadImage(color.source, function(img) {\n                    _this[property] = new fabric.Pattern({\n                        source: img,\n                        repeat: color.repeat,\n                        offsetX: color.offsetX,\n                        offsetY: color.offsetY\n                    });\n                    callback && callback();\n                });\n            }\n            else {\n                this[property] = color;\n                callback && callback();\n            }\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _createCanvasElement: function() {\n            var element = fabric.document.createElement('canvas');\n            if (!element.style) {\n                element.style = { };\n            }\n            if (!element) {\n                throw CANVAS_INIT_ERROR;\n            }\n            this._initCanvasElement(element);\n            return element;\n        },\n\n        /**\n         * @private\n         * @param {HTMLElement} element\n         */\n        _initCanvasElement: function(element) {\n            fabric.util.createCanvasElement(element);\n\n            if (typeof element.getContext === 'undefined') {\n                throw CANVAS_INIT_ERROR;\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Options object\n         */\n        _initOptions: function (options) {\n            for (var prop in options) {\n                this[prop] = options[prop];\n            }\n\n            this.width = this.width || parseInt(this.lowerCanvasEl.width, 10) || 0;\n            this.height = this.height || parseInt(this.lowerCanvasEl.height, 10) || 0;\n\n            if (!this.lowerCanvasEl.style) {\n                return;\n            }\n\n            this.lowerCanvasEl.width = this.width;\n            this.lowerCanvasEl.height = this.height;\n\n            this.lowerCanvasEl.style.width = this.width + 'px';\n            this.lowerCanvasEl.style.height = this.height + 'px';\n\n            this.viewportTransform = this.viewportTransform.slice();\n        },\n\n        /**\n         * Creates a bottom canvas\n         * @private\n         * @param {HTMLElement} [canvasEl]\n         */\n        _createLowerCanvas: function (canvasEl) {\n            this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement();\n            this._initCanvasElement(this.lowerCanvasEl);\n\n            fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas');\n\n            if (this.interactive) {\n                this._applyCanvasStyle(this.lowerCanvasEl);\n            }\n\n            this.contextContainer = this.lowerCanvasEl.getContext('2d');\n        },\n\n        /**\n         * Returns canvas width (in px)\n         * @return {Number}\n         */\n        getWidth: function () {\n            return this.width;\n        },\n\n        /**\n         * Returns canvas height (in px)\n         * @return {Number}\n         */\n        getHeight: function () {\n            return this.height;\n        },\n\n        /**\n         * Sets width of this canvas instance\n         * @param {Number|String} value                         Value to set width to\n         * @param {Object}        [options]                     Options object\n         * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n         * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        setWidth: function (value, options) {\n            return this.setDimensions({ width: value }, options);\n        },\n\n        /**\n         * Sets height of this canvas instance\n         * @param {Number|String} value                         Value to set height to\n         * @param {Object}        [options]                     Options object\n         * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n         * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        setHeight: function (value, options) {\n            return this.setDimensions({ height: value }, options);\n        },\n\n        /**\n         * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em)\n         * @param {Object}        dimensions                    Object with width/height properties\n         * @param {Number|String} [dimensions.width]            Width of canvas element\n         * @param {Number|String} [dimensions.height]           Height of canvas element\n         * @param {Object}        [options]                     Options object\n         * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n         * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        setDimensions: function (dimensions, options) {\n            var cssValue;\n\n            options = options || {};\n\n            for (var prop in dimensions) {\n                cssValue = dimensions[prop];\n\n                if (!options.cssOnly) {\n                    this._setBackstoreDimension(prop, dimensions[prop]);\n                    cssValue += 'px';\n                }\n\n                if (!options.backstoreOnly) {\n                    this._setCssDimension(prop, cssValue);\n                }\n            }\n\n            if (!options.cssOnly) {\n                this.renderAll();\n            }\n\n            this.calcOffset();\n\n            return this;\n        },\n\n        /**\n         * Helper for setting width/height\n         * @private\n         * @param {String} prop property (width|height)\n         * @param {Number} value value to set property to\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        _setBackstoreDimension: function (prop, value) {\n            this.lowerCanvasEl[prop] = value;\n\n            if (this.upperCanvasEl) {\n                this.upperCanvasEl[prop] = value;\n            }\n\n            if (this.cacheCanvasEl) {\n                this.cacheCanvasEl[prop] = value;\n            }\n\n            this[prop] = value;\n\n            return this;\n        },\n\n        /**\n         * Helper for setting css width/height\n         * @private\n         * @param {String} prop property (width|height)\n         * @param {String} value value to set property to\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        _setCssDimension: function (prop, value) {\n            this.lowerCanvasEl.style[prop] = value;\n\n            if (this.upperCanvasEl) {\n                this.upperCanvasEl.style[prop] = value;\n            }\n\n            if (this.wrapperEl) {\n                this.wrapperEl.style[prop] = value;\n            }\n\n            return this;\n        },\n\n        /**\n         * Returns canvas zoom level\n         * @return {Number}\n         */\n        getZoom: function () {\n            return Math.sqrt(this.viewportTransform[0] * this.viewportTransform[3]);\n        },\n\n        /**\n         * Sets viewport transform of this canvas instance\n         * @param {Array} vpt the transform in the form of context.transform\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        setViewportTransform: function (vpt) {\n            this.viewportTransform = vpt;\n            this.renderAll();\n            for (var i = 0, len = this._objects.length; i < len; i++) {\n                this._objects[i].setCoords();\n            }\n            return this;\n        },\n\n        /**\n         * Sets zoom level of this canvas instance, zoom centered around point\n         * @param {fabric.Point} point to zoom with respect to\n         * @param {Number} value to set zoom to, less than 1 zooms out\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        zoomToPoint: function (point, value) {\n            // TODO: just change the scale, preserve other transformations\n            var before = point;\n            point = fabric.util.transformPoint(point, fabric.util.invertTransform(this.viewportTransform));\n            this.viewportTransform[0] = value;\n            this.viewportTransform[3] = value;\n            var after = fabric.util.transformPoint(point, this.viewportTransform);\n            this.viewportTransform[4] += before.x - after.x;\n            this.viewportTransform[5] += before.y - after.y;\n            this.renderAll();\n            for (var i = 0, len = this._objects.length; i < len; i++) {\n                this._objects[i].setCoords();\n            }\n            return this;\n        },\n\n        /**\n         * Sets zoom level of this canvas instance\n         * @param {Number} value to set zoom to, less than 1 zooms out\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        setZoom: function (value) {\n            this.zoomToPoint(new fabric.Point(0, 0), value);\n            return this;\n        },\n\n        /**\n         * Pan viewport so as to place point at top left corner of canvas\n         * @param {fabric.Point} point to move to\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        absolutePan: function (point) {\n            this.viewportTransform[4] = -point.x;\n            this.viewportTransform[5] = -point.y;\n            this.renderAll();\n            for (var i = 0, len = this._objects.length; i < len; i++) {\n                this._objects[i].setCoords();\n            }\n            return this;\n        },\n\n        /**\n         * Pans viewpoint relatively\n         * @param {fabric.Point} point (position vector) to move by\n         * @return {fabric.Canvas} instance\n         * @chainable true\n         */\n        relativePan: function (point) {\n            return this.absolutePan(new fabric.Point(\n                    -point.x - this.viewportTransform[4],\n                    -point.y - this.viewportTransform[5]\n            ));\n        },\n\n        /**\n         * Returns &lt;canvas> element corresponding to this instance\n         * @return {HTMLCanvasElement}\n         */\n        getElement: function () {\n            return this.lowerCanvasEl;\n        },\n\n        /**\n         * Returns currently selected object, if any\n         * @return {fabric.Object}\n         */\n        getActiveObject: function() {\n            return null;\n        },\n\n        /**\n         * Returns currently selected group of object, if any\n         * @return {fabric.Group}\n         */\n        getActiveGroup: function() {\n            return null;\n        },\n\n        /**\n         * Given a context, renders an object on that context\n         * @param {CanvasRenderingContext2D} ctx Context to render object on\n         * @param {fabric.Object} object Object to render\n         * @private\n         */\n        _draw: function (ctx, object) {\n            if (!object) {\n                return;\n            }\n\n            ctx.save();\n            var v = this.viewportTransform;\n            ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n            if (this._shouldRenderObject(object)) {\n                object.render(ctx);\n            }\n            ctx.restore();\n            if (!this.controlsAboveOverlay) {\n                object._renderControls(ctx);\n            }\n        },\n\n        _shouldRenderObject: function(object) {\n            if (!object) {\n                return false;\n            }\n            return (object !== this.getActiveGroup() || !this.preserveObjectStacking);\n        },\n\n        /**\n         * @private\n         * @param {fabric.Object} obj Object that was added\n         */\n        _onObjectAdded: function(obj) {\n            this.stateful && obj.setupState();\n            obj.canvas = this;\n            obj.setCoords();\n            this.fire('object:added', { target: obj });\n            obj.fire('added');\n        },\n\n        /**\n         * @private\n         * @param {fabric.Object} obj Object that was removed\n         */\n        _onObjectRemoved: function(obj) {\n            // removing active object should fire \"selection:cleared\" events\n            if (this.getActiveObject() === obj) {\n                this.fire('before:selection:cleared', { target: obj });\n                this._discardActiveObject();\n                this.fire('selection:cleared');\n            }\n\n            this.fire('object:removed', { target: obj });\n            obj.fire('removed');\n        },\n\n        /**\n         * Clears specified context of canvas element\n         * @param {CanvasRenderingContext2D} ctx Context to clear\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        clearContext: function(ctx) {\n            ctx.clearRect(0, 0, this.width, this.height);\n            return this;\n        },\n\n        /**\n         * Returns context of canvas where objects are drawn\n         * @return {CanvasRenderingContext2D}\n         */\n        getContext: function () {\n            return this.contextContainer;\n        },\n\n        /**\n         * Clears all contexts (background, main, top) of an instance\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        clear: function () {\n            this._objects.length = 0;\n            if (this.discardActiveGroup) {\n                this.discardActiveGroup();\n            }\n            if (this.discardActiveObject) {\n                this.discardActiveObject();\n            }\n            this.clearContext(this.contextContainer);\n            if (this.contextTop) {\n                this.clearContext(this.contextTop);\n            }\n            this.fire('canvas:cleared');\n            this.renderAll();\n            return this;\n        },\n\n        /**\n         * Renders both the top canvas and the secondary container canvas.\n         * @param {Boolean} [allOnTop] Whether we want to force all images to be rendered on the top canvas\n         * @return {fabric.Canvas} instance\n         * @chainable\n         */\n        renderAll: function (allOnTop) {\n            var canvasToDrawOn = this[(allOnTop === true && this.interactive) ? 'contextTop' : 'contextContainer'],\n                activeGroup = this.getActiveGroup();\n\n            if (this.contextTop && this.selection && !this._groupSelector) {\n                this.clearContext(this.contextTop);\n            }\n\n            if (!allOnTop) {\n                this.clearContext(canvasToDrawOn);\n            }\n\n            this.fire('before:render');\n\n            if (this.clipTo) {\n                fabric.util.clipContext(this, canvasToDrawOn);\n            }\n\n            this._renderBackground(canvasToDrawOn);\n            this._renderObjects(canvasToDrawOn, activeGroup);\n            this._renderActiveGroup(canvasToDrawOn, activeGroup);\n\n            if (this.clipTo) {\n                canvasToDrawOn.restore();\n            }\n\n            this._renderOverlay(canvasToDrawOn);\n\n            if (this.controlsAboveOverlay && this.interactive) {\n                this.drawControls(canvasToDrawOn);\n            }\n\n            this.fire('after:render');\n\n            return this;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {fabric.Group} activeGroup\n         */\n        _renderObjects: function(ctx, activeGroup) {\n            var i, length;\n\n            // fast path\n            if (!activeGroup || this.preserveObjectStacking) {\n                for (i = 0, length = this._objects.length; i < length; ++i) {\n                    this._draw(ctx, this._objects[i]);\n                }\n            }\n            else {\n                for (i = 0, length = this._objects.length; i < length; ++i) {\n                    if (this._objects[i] && !activeGroup.contains(this._objects[i])) {\n                        this._draw(ctx, this._objects[i]);\n                    }\n                }\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {fabric.Group} activeGroup\n         */\n        _renderActiveGroup: function(ctx, activeGroup) {\n\n            // delegate rendering to group selection (if one exists)\n            if (activeGroup) {\n\n                //Store objects in group preserving order, then replace\n                var sortedObjects = [];\n                this.forEachObject(function (object) {\n                    if (activeGroup.contains(object)) {\n                        sortedObjects.push(object);\n                    }\n                });\n                activeGroup._set('objects', sortedObjects);\n                this._draw(ctx, activeGroup);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderBackground: function(ctx) {\n            if (this.backgroundColor) {\n                ctx.fillStyle = this.backgroundColor.toLive\n                    ? this.backgroundColor.toLive(ctx)\n                    : this.backgroundColor;\n\n                ctx.fillRect(\n                        this.backgroundColor.offsetX || 0,\n                        this.backgroundColor.offsetY || 0,\n                    this.width,\n                    this.height);\n            }\n            if (this.backgroundImage) {\n                this._draw(ctx, this.backgroundImage);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderOverlay: function(ctx) {\n            if (this.overlayColor) {\n                ctx.fillStyle = this.overlayColor.toLive\n                    ? this.overlayColor.toLive(ctx)\n                    : this.overlayColor;\n\n                ctx.fillRect(\n                        this.overlayColor.offsetX || 0,\n                        this.overlayColor.offsetY || 0,\n                    this.width,\n                    this.height);\n            }\n            if (this.overlayImage) {\n                this._draw(ctx, this.overlayImage);\n            }\n        },\n\n        /**\n         * Method to render only the top canvas.\n         * Also used to render the group selection box.\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        renderTop: function () {\n            var ctx = this.contextTop || this.contextContainer;\n            this.clearContext(ctx);\n\n            // we render the top context - last object\n            if (this.selection && this._groupSelector) {\n                this._drawSelection();\n            }\n\n            // delegate rendering to group selection if one exists\n            // used for drawing selection borders/controls\n            var activeGroup = this.getActiveGroup();\n            if (activeGroup) {\n                activeGroup.render(ctx);\n            }\n\n            this._renderOverlay(ctx);\n\n            this.fire('after:render');\n\n            return this;\n        },\n\n        /**\n         * Returns coordinates of a center of canvas.\n         * Returned value is an object with top and left properties\n         * @return {Object} object with \"top\" and \"left\" number values\n         */\n        getCenter: function () {\n            return {\n                top: this.getHeight() / 2,\n                left: this.getWidth() / 2\n            };\n        },\n\n        /**\n         * Centers object horizontally.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @param {fabric.Object} object Object to center horizontally\n         * @return {fabric.Canvas} thisArg\n         */\n        centerObjectH: function (object) {\n            this._centerObject(object, new fabric.Point(this.getCenter().left, object.getCenterPoint().y));\n            this.renderAll();\n            return this;\n        },\n\n        /**\n         * Centers object vertically.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @param {fabric.Object} object Object to center vertically\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        centerObjectV: function (object) {\n            this._centerObject(object, new fabric.Point(object.getCenterPoint().x, this.getCenter().top));\n            this.renderAll();\n            return this;\n        },\n\n        /**\n         * Centers object vertically and horizontally.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @param {fabric.Object} object Object to center vertically and horizontally\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        centerObject: function(object) {\n            var center = this.getCenter();\n\n            this._centerObject(object, new fabric.Point(center.left, center.top));\n            this.renderAll();\n            return this;\n        },\n\n        /**\n         * @private\n         * @param {fabric.Object} object Object to center\n         * @param {fabric.Point} center Center point\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        _centerObject: function(object, center) {\n            object.setPositionByOrigin(center, 'center', 'center');\n            return this;\n        },\n\n        /**\n         * Returs dataless JSON representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {String} json string\n         */\n        toDatalessJSON: function (propertiesToInclude) {\n            return this.toDatalessObject(propertiesToInclude);\n        },\n\n        /**\n         * Returns object representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function (propertiesToInclude) {\n            return this._toObjectMethod('toObject', propertiesToInclude);\n        },\n\n        /**\n         * Returns dataless object representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toDatalessObject: function (propertiesToInclude) {\n            return this._toObjectMethod('toDatalessObject', propertiesToInclude);\n        },\n\n        /**\n         * @private\n         */\n        _toObjectMethod: function (methodName, propertiesToInclude) {\n\n            var activeGroup = this.getActiveGroup();\n            if (activeGroup) {\n                this.discardActiveGroup();\n            }\n\n            var data = {\n                objects: this._toObjects(methodName, propertiesToInclude)\n            };\n\n            extend(data, this.__serializeBgOverlay());\n\n            fabric.util.populateWithProperties(this, data, propertiesToInclude);\n\n            if (activeGroup) {\n                this.setActiveGroup(new fabric.Group(activeGroup.getObjects(), {\n                    originX: 'center',\n                    originY: 'center'\n                }));\n                activeGroup.forEachObject(function(o) {\n                    o.set('active', true);\n                });\n\n                if (this._currentTransform) {\n                    this._currentTransform.target = this.getActiveGroup();\n                }\n            }\n\n            return data;\n        },\n\n        /**\n         * @private\n         */\n        _toObjects: function(methodName, propertiesToInclude) {\n            return this.getObjects().map(function(instance) {\n                return this._toObject(instance, methodName, propertiesToInclude);\n            }, this);\n        },\n\n        /**\n         * @private\n         */\n        _toObject: function(instance, methodName, propertiesToInclude) {\n            var originalValue;\n\n            if (!this.includeDefaultValues) {\n                originalValue = instance.includeDefaultValues;\n                instance.includeDefaultValues = false;\n            }\n            var object = instance[methodName](propertiesToInclude);\n            if (!this.includeDefaultValues) {\n                instance.includeDefaultValues = originalValue;\n            }\n            return object;\n        },\n\n        /**\n         * @private\n         */\n        __serializeBgOverlay: function() {\n            var data = {\n                background: (this.backgroundColor && this.backgroundColor.toObject)\n                    ? this.backgroundColor.toObject()\n                    : this.backgroundColor\n            };\n\n            if (this.overlayColor) {\n                data.overlay = this.overlayColor.toObject\n                    ? this.overlayColor.toObject()\n                    : this.overlayColor;\n            }\n            if (this.backgroundImage) {\n                data.backgroundImage = this.backgroundImage.toObject();\n            }\n            if (this.overlayImage) {\n                data.overlayImage = this.overlayImage.toObject();\n            }\n\n            return data;\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true,\n         * a zoomed canvas will then produce zoomed SVG output.\n         * @type Boolean\n         * @default\n         */\n        svgViewportTransformation: true,\n\n        /**\n         * Returns SVG representation of canvas\n         * @function\n         * @param {Object} [options] Options object for SVG output\n         * @param {Boolean} [options.suppressPreamble=false] If true xml tag is not included\n         * @param {Object} [options.viewBox] SVG viewbox object\n         * @param {Number} [options.viewBox.x] x-cooridnate of viewbox\n         * @param {Number} [options.viewBox.y] y-coordinate of viewbox\n         * @param {Number} [options.viewBox.width] Width of viewbox\n         * @param {Number} [options.viewBox.height] Height of viewbox\n         * @param {String} [options.encoding=UTF-8] Encoding of SVG output\n         * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.\n         * @return {String} SVG string\n         * @tutorial {@link http://fabricjs.com/fabric-intro-part-3/#serialization}\n         * @see {@link http://jsfiddle.net/fabricjs/jQ3ZZ/|jsFiddle demo}\n         * @example <caption>Normal SVG output</caption>\n         * var svg = canvas.toSVG();\n         * @example <caption>SVG output without preamble (without &lt;?xml ../>)</caption>\n         * var svg = canvas.toSVG({suppressPreamble: true});\n         * @example <caption>SVG output with viewBox attribute</caption>\n         * var svg = canvas.toSVG({\n     *   viewBox: {\n     *     x: 100,\n     *     y: 100,\n     *     width: 200,\n     *     height: 300\n     *   }\n     * });\n         * @example <caption>SVG output with different encoding (default: UTF-8)</caption>\n         * var svg = canvas.toSVG({encoding: 'ISO-8859-1'});\n         * @example <caption>Modify SVG output with reviver function</caption>\n         * var svg = canvas.toSVG(null, function(svg) {\n     *   return svg.replace('stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; ', '');\n     * });\n         */\n        toSVG: function(options, reviver) {\n            options || (options = { });\n\n            var markup = [];\n\n            this._setSVGPreamble(markup, options);\n            this._setSVGHeader(markup, options);\n\n            this._setSVGBgOverlayColor(markup, 'backgroundColor');\n            this._setSVGBgOverlayImage(markup, 'backgroundImage');\n\n            this._setSVGObjects(markup, reviver);\n\n            this._setSVGBgOverlayColor(markup, 'overlayColor');\n            this._setSVGBgOverlayImage(markup, 'overlayImage');\n\n            markup.push('</svg>');\n\n            return markup.join('');\n        },\n\n        /**\n         * @private\n         */\n        _setSVGPreamble: function(markup, options) {\n            if (!options.suppressPreamble) {\n                markup.push(\n                    '<?xml version=\"1.0\" encoding=\"', (options.encoding || 'UTF-8'), '\" standalone=\"no\" ?>',\n                    '<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ',\n                    '\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\\n'\n                );\n            }\n        },\n\n        /**\n         * @private\n         */\n        _setSVGHeader: function(markup, options) {\n            var width, height, vpt;\n\n            if (options.viewBox) {\n                width = options.viewBox.width;\n                height = options.viewBox.height;\n            }\n            else {\n                width = this.width;\n                height = this.height;\n                if (!this.svgViewportTransformation) {\n                    vpt = this.viewportTransform;\n                    width /= vpt[0];\n                    height /= vpt[3];\n                }\n            }\n\n            markup.push(\n                '<svg ',\n                'xmlns=\"http://www.w3.org/2000/svg\" ',\n                'xmlns:xlink=\"http://www.w3.org/1999/xlink\" ',\n                'version=\"1.1\" ',\n                'width=\"', width, '\" ',\n                'height=\"', height, '\" ',\n                (this.backgroundColor && !this.backgroundColor.toLive\n                    ? 'style=\"background-color: ' + this.backgroundColor + '\" '\n                    : null),\n                (options.viewBox\n                    ? 'viewBox=\"' +\n                    options.viewBox.x + ' ' +\n                    options.viewBox.y + ' ' +\n                    options.viewBox.width + ' ' +\n                    options.viewBox.height + '\" '\n                    : null),\n                'xml:space=\"preserve\">',\n                '<desc>Created with Fabric.js ', fabric.version, '</desc>',\n                '<defs>',\n                fabric.createSVGFontFacesMarkup(this.getObjects()),\n                fabric.createSVGRefElementsMarkup(this),\n                '</defs>'\n            );\n        },\n\n        /**\n         * @private\n         */\n        _setSVGObjects: function(markup, reviver) {\n            var activeGroup = this.getActiveGroup();\n            if (activeGroup) {\n                this.discardActiveGroup();\n            }\n            for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) {\n                markup.push(objects[i].toSVG(reviver));\n            }\n            if (activeGroup) {\n                this.setActiveGroup(new fabric.Group(activeGroup.getObjects()));\n                activeGroup.forEachObject(function(o) {\n                    o.set('active', true);\n                });\n            }\n        },\n\n        /**\n         * @private\n         */\n        _setSVGBgOverlayImage: function(markup, property) {\n            if (this[property] && this[property].toSVG) {\n                markup.push(this[property].toSVG());\n            }\n        },\n\n        /**\n         * @private\n         */\n        _setSVGBgOverlayColor: function(markup, property) {\n            if (this[property] && this[property].source) {\n                markup.push(\n                    '<rect x=\"', this[property].offsetX, '\" y=\"', this[property].offsetY, '\" ',\n                    'width=\"',\n                    (this[property].repeat === 'repeat-y' || this[property].repeat === 'no-repeat'\n                        ? this[property].source.width\n                        : this.width),\n                    '\" height=\"',\n                    (this[property].repeat === 'repeat-x' || this[property].repeat === 'no-repeat'\n                        ? this[property].source.height\n                        : this.height),\n                        '\" fill=\"url(#' + property + 'Pattern)\"',\n                    '></rect>'\n                );\n            }\n            else if (this[property] && property === 'overlayColor') {\n                markup.push(\n                    '<rect x=\"0\" y=\"0\" ',\n                    'width=\"', this.width,\n                    '\" height=\"', this.height,\n                    '\" fill=\"', this[property], '\"',\n                    '></rect>'\n                );\n            }\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Moves an object to the bottom of the stack of drawn objects\n         * @param {fabric.Object} object Object to send to back\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        sendToBack: function (object) {\n            removeFromArray(this._objects, object);\n            this._objects.unshift(object);\n            return this.renderAll && this.renderAll();\n        },\n\n        /**\n         * Moves an object to the top of the stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        bringToFront: function (object) {\n            removeFromArray(this._objects, object);\n            this._objects.push(object);\n            return this.renderAll && this.renderAll();\n        },\n\n        /**\n         * Moves an object down in stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        sendBackwards: function (object, intersecting) {\n            var idx = this._objects.indexOf(object);\n\n            // if object is not on the bottom of stack\n            if (idx !== 0) {\n                var newIdx = this._findNewLowerIndex(object, idx, intersecting);\n\n                removeFromArray(this._objects, object);\n                this._objects.splice(newIdx, 0, object);\n                this.renderAll && this.renderAll();\n            }\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _findNewLowerIndex: function(object, idx, intersecting) {\n            var newIdx;\n\n            if (intersecting) {\n                newIdx = idx;\n\n                // traverse down the stack looking for the nearest intersecting object\n                for (var i = idx - 1; i >= 0; --i) {\n\n                    var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n                        object.isContainedWithinObject(this._objects[i]) ||\n                        this._objects[i].isContainedWithinObject(object);\n\n                    if (isIntersecting) {\n                        newIdx = i;\n                        break;\n                    }\n                }\n            }\n            else {\n                newIdx = idx - 1;\n            }\n\n            return newIdx;\n        },\n\n        /**\n         * Moves an object up in stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        bringForward: function (object, intersecting) {\n            var idx = this._objects.indexOf(object);\n\n            // if object is not on top of stack (last item in an array)\n            if (idx !== this._objects.length - 1) {\n                var newIdx = this._findNewUpperIndex(object, idx, intersecting);\n\n                removeFromArray(this._objects, object);\n                this._objects.splice(newIdx, 0, object);\n                this.renderAll && this.renderAll();\n            }\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _findNewUpperIndex: function(object, idx, intersecting) {\n            var newIdx;\n\n            if (intersecting) {\n                newIdx = idx;\n\n                // traverse up the stack looking for the nearest intersecting object\n                for (var i = idx + 1; i < this._objects.length; ++i) {\n\n                    var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n                        object.isContainedWithinObject(this._objects[i]) ||\n                        this._objects[i].isContainedWithinObject(object);\n\n                    if (isIntersecting) {\n                        newIdx = i;\n                        break;\n                    }\n                }\n            }\n            else {\n                newIdx = idx + 1;\n            }\n\n            return newIdx;\n        },\n\n        /**\n         * Moves an object to specified level in stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @param {Number} index Position to move to\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        moveTo: function (object, index) {\n            removeFromArray(this._objects, object);\n            this._objects.splice(index, 0, object);\n            return this.renderAll && this.renderAll();\n        },\n\n        /**\n         * Clears a canvas element and removes all event listeners\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        dispose: function () {\n            this.clear();\n            this.interactive && this.removeListeners();\n            return this;\n        },\n\n        /**\n         * Returns a string representation of an instance\n         * @return {String} string representation of an instance\n         */\n        toString: function () {\n            return '#<fabric.Canvas (' + this.complexity() + '): ' +\n                '{ objects: ' + this.getObjects().length + ' }>';\n        }\n    });\n\n    extend(fabric.StaticCanvas.prototype, fabric.Observable);\n    extend(fabric.StaticCanvas.prototype, fabric.Collection);\n    extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);\n\n    extend(fabric.StaticCanvas, /** @lends fabric.StaticCanvas */ {\n\n        /**\n         * @static\n         * @type String\n         * @default\n         */\n        EMPTY_JSON: '{\"objects\": [], \"background\": \"white\"}',\n\n        /**\n         * Provides a way to check support of some of the canvas methods\n         * (either those of HTMLCanvasElement itself, or rendering context)\n         *\n         * @param {String} methodName Method to check support for;\n         *                            Could be one of \"getImageData\", \"toDataURL\", \"toDataURLWithQuality\" or \"setLineDash\"\n         * @return {Boolean | null} `true` if method is supported (or at least exists),\n         *                          `null` if canvas element or context can not be initialized\n         */\n        supports: function (methodName) {\n            var el = fabric.util.createCanvasElement();\n\n            if (!el || !el.getContext) {\n                return null;\n            }\n\n            var ctx = el.getContext('2d');\n            if (!ctx) {\n                return null;\n            }\n\n            switch (methodName) {\n\n                case 'getImageData':\n                    return typeof ctx.getImageData !== 'undefined';\n\n                case 'setLineDash':\n                    return typeof ctx.setLineDash !== 'undefined';\n\n                case 'toDataURL':\n                    return typeof el.toDataURL !== 'undefined';\n\n                case 'toDataURLWithQuality':\n                    try {\n                        el.toDataURL('image/jpeg', 0);\n                        return true;\n                    }\n                    catch (e) { }\n                    return false;\n\n                default:\n                    return null;\n            }\n        }\n    });\n\n    /**\n     * Returns JSON representation of canvas\n     * @function\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {String} JSON string\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3/#serialization}\n     * @see {@link http://jsfiddle.net/fabricjs/pec86/|jsFiddle demo}\n     * @example <caption>JSON without additional properties</caption>\n     * var json = canvas.toJSON();\n     * @example <caption>JSON with additional properties included</caption>\n     * var json = canvas.toJSON(['lockMovementX', 'lockMovementY', 'lockRotation', 'lockScalingX', 'lockScalingY', 'lockUniScaling']);\n     * @example <caption>JSON without default values</caption>\n     * canvas.includeDefaultValues = false;\n     * var json = canvas.toJSON();\n     */\n    fabric.StaticCanvas.prototype.toJSON = fabric.StaticCanvas.prototype.toObject;\n\n})();\n\n\n/**\n * BaseBrush class\n * @class fabric.BaseBrush\n * @see {@link http://fabricjs.com/freedrawing/|Freedrawing demo}\n */\nfabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ {\n\n    /**\n     * Color of a brush\n     * @type String\n     * @default\n     */\n    color:            'rgb(0, 0, 0)',\n\n    /**\n     * Width of a brush\n     * @type Number\n     * @default\n     */\n    width:            1,\n\n    /**\n     * Shadow object representing shadow of this shape.\n     * <b>Backwards incompatibility note:</b> This property replaces \"shadowColor\" (String), \"shadowOffsetX\" (Number),\n     * \"shadowOffsetY\" (Number) and \"shadowBlur\" (Number) since v1.2.12\n     * @type fabric.Shadow\n     * @default\n     */\n    shadow:          null,\n\n    /**\n     * Line endings style of a brush (one of \"butt\", \"round\", \"square\")\n     * @type String\n     * @default\n     */\n    strokeLineCap:    'round',\n\n    /**\n     * Corner style of a brush (one of \"bevil\", \"round\", \"miter\")\n     * @type String\n     * @default\n     */\n    strokeLineJoin:   'round',\n\n    /**\n     * Sets shadow of an object\n     * @param {Object|String} [options] Options object or string (e.g. \"2px 2px 10px rgba(0,0,0,0.2)\")\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setShadow: function(options) {\n        this.shadow = new fabric.Shadow(options);\n        return this;\n    },\n\n    /**\n     * Sets brush styles\n     * @private\n     */\n    _setBrushStyles: function() {\n        var ctx = this.canvas.contextTop;\n\n        ctx.strokeStyle = this.color;\n        ctx.lineWidth = this.width;\n        ctx.lineCap = this.strokeLineCap;\n        ctx.lineJoin = this.strokeLineJoin;\n    },\n\n    /**\n     * Sets brush shadow styles\n     * @private\n     */\n    _setShadow: function() {\n        if (!this.shadow) {\n            return;\n        }\n\n        var ctx = this.canvas.contextTop;\n\n        ctx.shadowColor = this.shadow.color;\n        ctx.shadowBlur = this.shadow.blur;\n        ctx.shadowOffsetX = this.shadow.offsetX;\n        ctx.shadowOffsetY = this.shadow.offsetY;\n    },\n\n    /**\n     * Removes brush shadow styles\n     * @private\n     */\n    _resetShadow: function() {\n        var ctx = this.canvas.contextTop;\n\n        ctx.shadowColor = '';\n        ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n    }\n});\n\n\n(function() {\n\n    /**\n     * PencilBrush class\n     * @class fabric.PencilBrush\n     * @extends fabric.BaseBrush\n     */\n    fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ {\n\n        /**\n         * Constructor\n         * @param {fabric.Canvas} canvas\n         * @return {fabric.PencilBrush} Instance of a pencil brush\n         */\n        initialize: function(canvas) {\n            this.canvas = canvas;\n            this._points = [ ];\n        },\n\n        /**\n         * Inovoked on mouse down\n         * @param {Object} pointer\n         */\n        onMouseDown: function(pointer) {\n            this._prepareForDrawing(pointer);\n            // capture coordinates immediately\n            // this allows to draw dots (when movement never occurs)\n            this._captureDrawingPath(pointer);\n            this._render();\n        },\n\n        /**\n         * Inovoked on mouse move\n         * @param {Object} pointer\n         */\n        onMouseMove: function(pointer) {\n            this._captureDrawingPath(pointer);\n            // redraw curve\n            // clear top canvas\n            this.canvas.clearContext(this.canvas.contextTop);\n            this._render();\n        },\n\n        /**\n         * Invoked on mouse up\n         */\n        onMouseUp: function() {\n            this._finalizeAndAddPath();\n        },\n\n        /**\n         * @private\n         * @param {Object} pointer Actual mouse position related to the canvas.\n         */\n        _prepareForDrawing: function(pointer) {\n\n            var p = new fabric.Point(pointer.x, pointer.y);\n\n            this._reset();\n            this._addPoint(p);\n\n            this.canvas.contextTop.moveTo(p.x, p.y);\n        },\n\n        /**\n         * @private\n         * @param {fabric.Point} point Point to be added to points array\n         */\n        _addPoint: function(point) {\n            this._points.push(point);\n        },\n\n        /**\n         * Clear points array and set contextTop canvas style.\n         * @private\n         */\n        _reset: function() {\n            this._points.length = 0;\n\n            this._setBrushStyles();\n            this._setShadow();\n        },\n\n        /**\n         * @private\n         * @param {Object} pointer Actual mouse position related to the canvas.\n         */\n        _captureDrawingPath: function(pointer) {\n            var pointerPoint = new fabric.Point(pointer.x, pointer.y);\n            this._addPoint(pointerPoint);\n        },\n\n        /**\n         * Draw a smooth path on the topCanvas using quadraticCurveTo\n         * @private\n         */\n        _render: function() {\n            var ctx  = this.canvas.contextTop,\n                v = this.canvas.viewportTransform,\n                p1 = this._points[0],\n                p2 = this._points[1];\n\n            ctx.save();\n            ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n            ctx.beginPath();\n\n            //if we only have 2 points in the path and they are the same\n            //it means that the user only clicked the canvas without moving the mouse\n            //then we should be drawing a dot. A path isn't drawn between two identical dots\n            //that's why we set them apart a bit\n            if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) {\n                p1.x -= 0.5;\n                p2.x += 0.5;\n            }\n            ctx.moveTo(p1.x, p1.y);\n\n            for (var i = 1, len = this._points.length; i < len; i++) {\n                // we pick the point between pi + 1 & pi + 2 as the\n                // end point and p1 as our control point.\n                var midPoint = p1.midPointFrom(p2);\n                ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);\n\n                p1 = this._points[i];\n                p2 = this._points[i + 1];\n            }\n            // Draw last line as a straight line while\n            // we wait for the next point to be able to calculate\n            // the bezier control point\n            ctx.lineTo(p1.x, p1.y);\n            ctx.stroke();\n            ctx.restore();\n        },\n\n        /**\n         * Converts points to SVG path\n         * @param {Array} points Array of points\n         * @param {Number} minX\n         * @param {Number} minY\n         * @return {String} SVG path\n         */\n        convertPointsToSVGPath: function(points) {\n            var path = [],\n                p1 = new fabric.Point(points[0].x, points[0].y),\n                p2 = new fabric.Point(points[1].x, points[1].y);\n\n            path.push('M ', points[0].x, ' ', points[0].y, ' ');\n            for (var i = 1, len = points.length; i < len; i++) {\n                var midPoint = p1.midPointFrom(p2);\n                // p1 is our bezier control point\n                // midpoint is our endpoint\n                // start point is p(i-1) value.\n                path.push('Q ', p1.x, ' ', p1.y, ' ', midPoint.x, ' ', midPoint.y, ' ');\n                p1 = new fabric.Point(points[i].x, points[i].y);\n                if ((i + 1) < points.length) {\n                    p2 = new fabric.Point(points[i + 1].x, points[i + 1].y);\n                }\n            }\n            path.push('L ', p1.x, ' ', p1.y, ' ');\n            return path;\n        },\n\n        /**\n         * Creates fabric.Path object to add on canvas\n         * @param {String} pathData Path data\n         * @return {fabric.Path} Path to add on canvas\n         */\n        createPath: function(pathData) {\n            var path = new fabric.Path(pathData);\n            path.fill = null;\n            path.stroke = this.color;\n            path.strokeWidth = this.width;\n            path.strokeLineCap = this.strokeLineCap;\n            path.strokeLineJoin = this.strokeLineJoin;\n\n            if (this.shadow) {\n                this.shadow.affectStroke = true;\n                path.setShadow(this.shadow);\n            }\n\n            return path;\n        },\n\n        /**\n         * On mouseup after drawing the path on contextTop canvas\n         * we use the points captured to create an new fabric path object\n         * and add it to the fabric canvas.\n         */\n        _finalizeAndAddPath: function() {\n            var ctx = this.canvas.contextTop;\n            ctx.closePath();\n\n            var pathData = this.convertPointsToSVGPath(this._points).join('');\n            if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {\n                // do not create 0 width/height paths, as they are\n                // rendered inconsistently across browsers\n                // Firefox 4, for example, renders a dot,\n                // whereas Chrome 10 renders nothing\n                this.canvas.renderAll();\n                return;\n            }\n\n            var path = this.createPath(pathData);\n\n            this.canvas.add(path);\n            path.setCoords();\n\n            this.canvas.clearContext(this.canvas.contextTop);\n            this._resetShadow();\n            this.canvas.renderAll();\n\n            // fire event 'path' created\n            this.canvas.fire('path:created', { path: path });\n        }\n    });\n})();\n\n\n/**\n * CircleBrush class\n * @class fabric.CircleBrush\n */\nfabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.CircleBrush.prototype */ {\n\n    /**\n     * Width of a brush\n     * @type Number\n     * @default\n     */\n    width: 10,\n\n    /**\n     * Constructor\n     * @param {fabric.Canvas} canvas\n     * @return {fabric.CircleBrush} Instance of a circle brush\n     */\n    initialize: function(canvas) {\n        this.canvas = canvas;\n        this.points = [ ];\n    },\n    /**\n     * Invoked inside on mouse down and mouse move\n     * @param {Object} pointer\n     */\n    drawDot: function(pointer) {\n        var point = this.addPoint(pointer),\n            ctx = this.canvas.contextTop,\n            v = this.canvas.viewportTransform;\n        ctx.save();\n        ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n\n        ctx.fillStyle = point.fill;\n        ctx.beginPath();\n        ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);\n        ctx.closePath();\n        ctx.fill();\n\n        ctx.restore();\n    },\n\n    /**\n     * Invoked on mouse down\n     */\n    onMouseDown: function(pointer) {\n        this.points.length = 0;\n        this.canvas.clearContext(this.canvas.contextTop);\n        this._setShadow();\n        this.drawDot(pointer);\n    },\n\n    /**\n     * Invoked on mouse move\n     * @param {Object} pointer\n     */\n    onMouseMove: function(pointer) {\n        this.drawDot(pointer);\n    },\n\n    /**\n     * Invoked on mouse up\n     */\n    onMouseUp: function() {\n        var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n        this.canvas.renderOnAddRemove = false;\n\n        var circles = [ ];\n\n        for (var i = 0, len = this.points.length; i < len; i++) {\n            var point = this.points[i],\n                circle = new fabric.Circle({\n                    radius: point.radius,\n                    left: point.x,\n                    top: point.y,\n                    originX: 'center',\n                    originY: 'center',\n                    fill: point.fill\n                });\n\n            this.shadow && circle.setShadow(this.shadow);\n\n            circles.push(circle);\n        }\n        var group = new fabric.Group(circles, { originX: 'center', originY: 'center' });\n        group.canvas = this.canvas;\n\n        this.canvas.add(group);\n        this.canvas.fire('path:created', { path: group });\n\n        this.canvas.clearContext(this.canvas.contextTop);\n        this._resetShadow();\n        this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n        this.canvas.renderAll();\n    },\n\n    /**\n     * @param {Object} pointer\n     * @return {fabric.Point} Just added pointer point\n     */\n    addPoint: function(pointer) {\n        var pointerPoint = new fabric.Point(pointer.x, pointer.y),\n\n            circleRadius = fabric.util.getRandomInt(\n                Math.max(0, this.width - 20), this.width + 20) / 2,\n\n            circleColor = new fabric.Color(this.color)\n                .setAlpha(fabric.util.getRandomInt(0, 100) / 100)\n                .toRgba();\n\n        pointerPoint.radius = circleRadius;\n        pointerPoint.fill = circleColor;\n\n        this.points.push(pointerPoint);\n\n        return pointerPoint;\n    }\n});\n\n\n/**\n * SprayBrush class\n * @class fabric.SprayBrush\n */\nfabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ {\n\n    /**\n     * Width of a spray\n     * @type Number\n     * @default\n     */\n    width:              10,\n\n    /**\n     * Density of a spray (number of dots per chunk)\n     * @type Number\n     * @default\n     */\n    density:            20,\n\n    /**\n     * Width of spray dots\n     * @type Number\n     * @default\n     */\n    dotWidth:           1,\n\n    /**\n     * Width variance of spray dots\n     * @type Number\n     * @default\n     */\n    dotWidthVariance:   1,\n\n    /**\n     * Whether opacity of a dot should be random\n     * @type Boolean\n     * @default\n     */\n    randomOpacity:        false,\n\n    /**\n     * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n     * @type Boolean\n     * @default\n     */\n    optimizeOverlapping:  true,\n\n    /**\n     * Constructor\n     * @param {fabric.Canvas} canvas\n     * @return {fabric.SprayBrush} Instance of a spray brush\n     */\n    initialize: function(canvas) {\n        this.canvas = canvas;\n        this.sprayChunks = [ ];\n    },\n\n    /**\n     * Invoked on mouse down\n     * @param {Object} pointer\n     */\n    onMouseDown: function(pointer) {\n        this.sprayChunks.length = 0;\n        this.canvas.clearContext(this.canvas.contextTop);\n        this._setShadow();\n\n        this.addSprayChunk(pointer);\n        this.render();\n    },\n\n    /**\n     * Invoked on mouse move\n     * @param {Object} pointer\n     */\n    onMouseMove: function(pointer) {\n        this.addSprayChunk(pointer);\n        this.render();\n    },\n\n    /**\n     * Invoked on mouse up\n     */\n    onMouseUp: function() {\n        var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n        this.canvas.renderOnAddRemove = false;\n\n        var rects = [ ];\n\n        for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {\n            var sprayChunk = this.sprayChunks[i];\n\n            for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {\n\n                var rect = new fabric.Rect({\n                    width: sprayChunk[j].width,\n                    height: sprayChunk[j].width,\n                    left: sprayChunk[j].x + 1,\n                    top: sprayChunk[j].y + 1,\n                    originX: 'center',\n                    originY: 'center',\n                    fill: this.color\n                });\n\n                this.shadow && rect.setShadow(this.shadow);\n                rects.push(rect);\n            }\n        }\n\n        if (this.optimizeOverlapping) {\n            rects = this._getOptimizedRects(rects);\n        }\n\n        var group = new fabric.Group(rects, { originX: 'center', originY: 'center' });\n        group.canvas = this.canvas;\n\n        this.canvas.add(group);\n        this.canvas.fire('path:created', { path: group });\n\n        this.canvas.clearContext(this.canvas.contextTop);\n        this._resetShadow();\n        this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n        this.canvas.renderAll();\n    },\n\n    /**\n     * @private\n     * @param {Array} rects\n     */\n    _getOptimizedRects: function(rects) {\n\n        // avoid creating duplicate rects at the same coordinates\n        var uniqueRects = { }, key;\n\n        for (var i = 0, len = rects.length; i < len; i++) {\n            key = rects[i].left + '' + rects[i].top;\n            if (!uniqueRects[key]) {\n                uniqueRects[key] = rects[i];\n            }\n        }\n        var uniqueRectsArray = [ ];\n        for (key in uniqueRects) {\n            uniqueRectsArray.push(uniqueRects[key]);\n        }\n\n        return uniqueRectsArray;\n    },\n\n    /**\n     * Renders brush\n     */\n    render: function() {\n        var ctx = this.canvas.contextTop;\n        ctx.fillStyle = this.color;\n\n        var v = this.canvas.viewportTransform;\n        ctx.save();\n        ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n\n        for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) {\n            var point = this.sprayChunkPoints[i];\n            if (typeof point.opacity !== 'undefined') {\n                ctx.globalAlpha = point.opacity;\n            }\n            ctx.fillRect(point.x, point.y, point.width, point.width);\n        }\n        ctx.restore();\n    },\n\n    /**\n     * @param {Object} pointer\n     */\n    addSprayChunk: function(pointer) {\n        this.sprayChunkPoints = [ ];\n\n        var x, y, width, radius = this.width / 2;\n\n        for (var i = 0; i < this.density; i++) {\n\n            x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);\n            y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);\n\n            if (this.dotWidthVariance) {\n                width = fabric.util.getRandomInt(\n                    // bottom clamp width to 1\n                    Math.max(1, this.dotWidth - this.dotWidthVariance),\n                        this.dotWidth + this.dotWidthVariance);\n            }\n            else {\n                width = this.dotWidth;\n            }\n\n            var point = new fabric.Point(x, y);\n            point.width = width;\n\n            if (this.randomOpacity) {\n                point.opacity = fabric.util.getRandomInt(0, 100) / 100;\n            }\n\n            this.sprayChunkPoints.push(point);\n        }\n\n        this.sprayChunks.push(this.sprayChunkPoints);\n    }\n});\n\n\n/**\n * PatternBrush class\n * @class fabric.PatternBrush\n * @extends fabric.BaseBrush\n */\nfabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fabric.PatternBrush.prototype */ {\n\n    getPatternSrc: function() {\n\n        var dotWidth = 20,\n            dotDistance = 5,\n            patternCanvas = fabric.document.createElement('canvas'),\n            patternCtx = patternCanvas.getContext('2d');\n\n        patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;\n\n        patternCtx.fillStyle = this.color;\n        patternCtx.beginPath();\n        patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);\n        patternCtx.closePath();\n        patternCtx.fill();\n\n        return patternCanvas;\n    },\n\n    getPatternSrcFunction: function() {\n        return String(this.getPatternSrc).replace('this.color', '\"' + this.color + '\"');\n    },\n\n    /**\n     * Creates \"pattern\" instance property\n     */\n    getPattern: function() {\n        return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat');\n    },\n\n    /**\n     * Sets brush styles\n     */\n    _setBrushStyles: function() {\n        this.callSuper('_setBrushStyles');\n        this.canvas.contextTop.strokeStyle = this.getPattern();\n    },\n\n    /**\n     * Creates path\n     */\n    createPath: function(pathData) {\n        var path = this.callSuper('createPath', pathData);\n        path.stroke = new fabric.Pattern({\n            source: this.source || this.getPatternSrcFunction()\n        });\n        return path;\n    }\n});\n\n\n(function() {\n\n    var getPointer = fabric.util.getPointer,\n        degreesToRadians = fabric.util.degreesToRadians,\n        radiansToDegrees = fabric.util.radiansToDegrees,\n        atan2 = Math.atan2,\n        abs = Math.abs,\n\n        STROKE_OFFSET = 0.5;\n\n    /**\n     * Canvas class\n     * @class fabric.Canvas\n     * @extends fabric.StaticCanvas\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-1/#canvas}\n     * @see {@link fabric.Canvas#initialize} for constructor definition\n     *\n     * @fires object:modified\n     * @fires object:rotating\n     * @fires object:scaling\n     * @fires object:moving\n     * @fires object:selected\n     *\n     * @fires before:selection:cleared\n     * @fires selection:cleared\n     * @fires selection:created\n     *\n     * @fires path:created\n     * @fires mouse:down\n     * @fires mouse:move\n     * @fires mouse:up\n     * @fires mouse:over\n     * @fires mouse:out\n     *\n     */\n    fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {\n\n        /**\n         * Constructor\n         * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n         * @param {Object} [options] Options object\n         * @return {Object} thisArg\n         */\n        initialize: function(el, options) {\n            options || (options = { });\n\n            this._initStatic(el, options);\n            this._initInteractive();\n            this._createCacheCanvas();\n\n            fabric.Canvas.activeInstance = this;\n        },\n\n        /**\n         * When true, objects can be transformed by one side (unproportionally)\n         * @type Boolean\n         * @default\n         */\n        uniScaleTransform:      false,\n\n        /**\n         * When true, objects use center point as the origin of scale transformation.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         * @since 1.3.4\n         * @type Boolean\n         * @default\n         */\n        centeredScaling:        false,\n\n        /**\n         * When true, objects use center point as the origin of rotate transformation.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         * @since 1.3.4\n         * @type Boolean\n         * @default\n         */\n        centeredRotation:       false,\n\n        /**\n         * Indicates that canvas is interactive. This property should not be changed.\n         * @type Boolean\n         * @default\n         */\n        interactive:            true,\n\n        /**\n         * Indicates whether group selection should be enabled\n         * @type Boolean\n         * @default\n         */\n        selection:              true,\n\n        /**\n         * Color of selection\n         * @type String\n         * @default\n         */\n        selectionColor:         'rgba(100, 100, 255, 0.3)', // blue\n\n        /**\n         * Default dash array pattern\n         * If not empty the selection border is dashed\n         * @type Array\n         */\n        selectionDashArray:     [ ],\n\n        /**\n         * Color of the border of selection (usually slightly darker than color of selection itself)\n         * @type String\n         * @default\n         */\n        selectionBorderColor:   'rgba(255, 255, 255, 0.3)',\n\n        /**\n         * Width of a line used in object/group selection\n         * @type Number\n         * @default\n         */\n        selectionLineWidth:     1,\n\n        /**\n         * Default cursor value used when hovering over an object on canvas\n         * @type String\n         * @default\n         */\n        hoverCursor:            'move',\n\n        /**\n         * Default cursor value used when moving an object on canvas\n         * @type String\n         * @default\n         */\n        moveCursor:             'move',\n\n        /**\n         * Default cursor value used for the entire canvas\n         * @type String\n         * @default\n         */\n        defaultCursor:          'default',\n\n        /**\n         * Cursor value used during free drawing\n         * @type String\n         * @default\n         */\n        freeDrawingCursor:      'crosshair',\n\n        /**\n         * Cursor value used for rotation point\n         * @type String\n         * @default\n         */\n        rotationCursor:         'crosshair',\n\n        /**\n         * Default element class that's given to wrapper (div) element of canvas\n         * @type String\n         * @default\n         */\n        containerClass:         'canvas-container',\n\n        /**\n         * When true, object detection happens on per-pixel basis rather than on per-bounding-box\n         * @type Boolean\n         * @default\n         */\n        perPixelTargetFind:     false,\n\n        /**\n         * Number of pixels around target pixel to tolerate (consider active) during object detection\n         * @type Number\n         * @default\n         */\n        targetFindTolerance:    0,\n\n        /**\n         * When true, target detection is skipped when hovering over canvas. This can be used to improve performance.\n         * @type Boolean\n         * @default\n         */\n        skipTargetFind:         false,\n\n        /**\n         * @private\n         */\n        _initInteractive: function() {\n            this._currentTransform = null;\n            this._groupSelector = null;\n            this._initWrapperElement();\n            this._createUpperCanvas();\n            this._initEventListeners();\n\n            this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this);\n\n            this.calcOffset();\n        },\n\n        /**\n         * Resets the current transform to its original values and chooses the type of resizing based on the event\n         * @private\n         * @param {Event} e Event object fired on mousemove\n         */\n        _resetCurrentTransform: function(e) {\n            var t = this._currentTransform;\n\n            t.target.set({\n                scaleX: t.original.scaleX,\n                scaleY: t.original.scaleY,\n                left: t.original.left,\n                top: t.original.top\n            });\n\n            if (this._shouldCenterTransform(e, t.target)) {\n                if (t.action === 'rotate') {\n                    this._setOriginToCenter(t.target);\n                }\n                else {\n                    if (t.originX !== 'center') {\n                        if (t.originX === 'right') {\n                            t.mouseXSign = -1;\n                        }\n                        else {\n                            t.mouseXSign = 1;\n                        }\n                    }\n                    if (t.originY !== 'center') {\n                        if (t.originY === 'bottom') {\n                            t.mouseYSign = -1;\n                        }\n                        else {\n                            t.mouseYSign = 1;\n                        }\n                    }\n\n                    t.originX = 'center';\n                    t.originY = 'center';\n                }\n            }\n            else {\n                t.originX = t.original.originX;\n                t.originY = t.original.originY;\n            }\n        },\n\n        /**\n         * Checks if point is contained within an area of given object\n         * @param {Event} e Event object\n         * @param {fabric.Object} target Object to test against\n         * @return {Boolean} true if point is contained within an area of given object\n         */\n        containsPoint: function (e, target) {\n            var pointer = this.getPointer(e, true),\n                xy = this._normalizePointer(target, pointer);\n\n            // http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html\n            // http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html\n            return (target.containsPoint(xy) || target._findTargetCorner(pointer));\n        },\n\n        /**\n         * @private\n         */\n        _normalizePointer: function (object, pointer) {\n            var activeGroup = this.getActiveGroup(),\n                x = pointer.x,\n                y = pointer.y,\n                isObjectInGroup = (\n                    activeGroup &&\n                    object.type !== 'group' &&\n                    activeGroup.contains(object)),\n                lt;\n\n            if (isObjectInGroup) {\n                lt = new fabric.Point(activeGroup.left, activeGroup.top);\n                lt = fabric.util.transformPoint(lt, this.viewportTransform, true);\n                x -= lt.x;\n                y -= lt.y;\n            }\n            return { x: x, y: y };\n        },\n\n        /**\n         * Returns true if object is transparent at a certain location\n         * @param {fabric.Object} target Object to check\n         * @param {Number} x Left coordinate\n         * @param {Number} y Top coordinate\n         * @return {Boolean}\n         */\n        isTargetTransparent: function (target, x, y) {\n            var hasBorders = target.hasBorders,\n                transparentCorners = target.transparentCorners;\n\n            target.hasBorders = target.transparentCorners = false;\n\n            this._draw(this.contextCache, target);\n\n            target.hasBorders = hasBorders;\n            target.transparentCorners = transparentCorners;\n\n            var isTransparent = fabric.util.isTransparent(\n                this.contextCache, x, y, this.targetFindTolerance);\n\n            this.clearContext(this.contextCache);\n\n            return isTransparent;\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object\n         * @param {fabric.Object} target\n         */\n        _shouldClearSelection: function (e, target) {\n            var activeGroup = this.getActiveGroup(),\n                activeObject = this.getActiveObject();\n\n            return (\n                !target\n                ||\n                (target &&\n                    activeGroup &&\n                    !activeGroup.contains(target) &&\n                    activeGroup !== target &&\n                    !e.shiftKey)\n                ||\n                (target && !target.evented)\n                ||\n                (target &&\n                    !target.selectable &&\n                    activeObject &&\n                    activeObject !== target)\n                );\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object\n         * @param {fabric.Object} target\n         */\n        _shouldCenterTransform: function (e, target) {\n            if (!target) {\n                return;\n            }\n\n            var t = this._currentTransform,\n                centerTransform;\n\n            if (t.action === 'scale' || t.action === 'scaleX' || t.action === 'scaleY') {\n                centerTransform = this.centeredScaling || target.centeredScaling;\n            }\n            else if (t.action === 'rotate') {\n                centerTransform = this.centeredRotation || target.centeredRotation;\n            }\n\n            return centerTransform ? !e.altKey : e.altKey;\n        },\n\n        /**\n         * @private\n         */\n        _getOriginFromCorner: function(target, corner) {\n            var origin = {\n                x: target.originX,\n                y: target.originY\n            };\n\n            if (corner === 'ml' || corner === 'tl' || corner === 'bl') {\n                origin.x = 'right';\n            }\n            else if (corner === 'mr' || corner === 'tr' || corner === 'br') {\n                origin.x = 'left';\n            }\n\n            if (corner === 'tl' || corner === 'mt' || corner === 'tr') {\n                origin.y = 'bottom';\n            }\n            else if (corner === 'bl' || corner === 'mb' || corner === 'br') {\n                origin.y = 'top';\n            }\n\n            return origin;\n        },\n\n        /**\n         * @private\n         */\n        _getActionFromCorner: function(target, corner) {\n            var action = 'drag';\n            if (corner) {\n                action = (corner === 'ml' || corner === 'mr')\n                    ? 'scaleX'\n                    : (corner === 'mt' || corner === 'mb')\n                    ? 'scaleY'\n                    : corner === 'mtr'\n                    ? 'rotate'\n                    : 'scale';\n            }\n            return action;\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object\n         * @param {fabric.Object} target\n         */\n        _setupCurrentTransform: function (e, target) {\n            if (!target) {\n                return;\n            }\n\n            var pointer = this.getPointer(e),\n                corner = target._findTargetCorner(this.getPointer(e, true)),\n                action = this._getActionFromCorner(target, corner),\n                origin = this._getOriginFromCorner(target, corner);\n\n            this._currentTransform = {\n                target: target,\n                action: action,\n                scaleX: target.scaleX,\n                scaleY: target.scaleY,\n                offsetX: pointer.x - target.left,\n                offsetY: pointer.y - target.top,\n                originX: origin.x,\n                originY: origin.y,\n                ex: pointer.x,\n                ey: pointer.y,\n                left: target.left,\n                top: target.top,\n                theta: degreesToRadians(target.angle),\n                width: target.width * target.scaleX,\n                mouseXSign: 1,\n                mouseYSign: 1\n            };\n\n            this._currentTransform.original = {\n                left: target.left,\n                top: target.top,\n                scaleX: target.scaleX,\n                scaleY: target.scaleY,\n                originX: origin.x,\n                originY: origin.y\n            };\n\n            this._resetCurrentTransform(e);\n        },\n\n        /**\n         * Translates object by \"setting\" its left/top\n         * @private\n         * @param {Number} x pointer's x coordinate\n         * @param {Number} y pointer's y coordinate\n         */\n        _translateObject: function (x, y) {\n            var target = this._currentTransform.target;\n\n            if (!target.get('lockMovementX')) {\n                target.set('left', x - this._currentTransform.offsetX);\n            }\n            if (!target.get('lockMovementY')) {\n                target.set('top', y - this._currentTransform.offsetY);\n            }\n        },\n\n        /**\n         * Scales object by invoking its scaleX/scaleY methods\n         * @private\n         * @param {Number} x pointer's x coordinate\n         * @param {Number} y pointer's y coordinate\n         * @param {String} by Either 'x' or 'y' - specifies dimension constraint by which to scale an object.\n         *                    When not provided, an object is scaled by both dimensions equally\n         */\n        _scaleObject: function (x, y, by) {\n            var t = this._currentTransform,\n                target = t.target,\n                lockScalingX = target.get('lockScalingX'),\n                lockScalingY = target.get('lockScalingY'),\n                lockScalingFlip = target.get('lockScalingFlip');\n\n            if (lockScalingX && lockScalingY) {\n                return;\n            }\n\n            // Get the constraint point\n            var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),\n                localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY);\n\n            this._setLocalMouse(localMouse, t);\n\n            // Actually scale the object\n            this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip);\n\n            // Make sure the constraints apply\n            target.setPositionByOrigin(constraintPosition, t.originX, t.originY);\n        },\n\n        /**\n         * @private\n         */\n        _setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip) {\n            var target = transform.target, forbidScalingX = false, forbidScalingY = false;\n\n            transform.newScaleX = localMouse.x / (target.width + target.strokeWidth);\n            transform.newScaleY = localMouse.y / (target.height + target.strokeWidth);\n\n            if (lockScalingFlip && transform.newScaleX <= 0 && transform.newScaleX < target.scaleX) {\n                forbidScalingX = true;\n            }\n\n            if (lockScalingFlip && transform.newScaleY <= 0 && transform.newScaleY < target.scaleY) {\n                forbidScalingY = true;\n            }\n\n            if (by === 'equally' && !lockScalingX && !lockScalingY) {\n                forbidScalingX || forbidScalingY || this._scaleObjectEqually(localMouse, target, transform);\n            }\n            else if (!by) {\n                forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);\n                forbidScalingY || lockScalingY || target.set('scaleY', transform.newScaleY);\n            }\n            else if (by === 'x' && !target.get('lockUniScaling')) {\n                forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);\n            }\n            else if (by === 'y' && !target.get('lockUniScaling')) {\n                forbidScalingY || lockScalingY || target.set('scaleY', transform.newScaleY);\n            }\n\n            forbidScalingX || forbidScalingY || this._flipObject(transform, by);\n\n        },\n\n        /**\n         * @private\n         */\n        _scaleObjectEqually: function(localMouse, target, transform) {\n\n            var dist = localMouse.y + localMouse.x,\n                lastDist = (target.height + (target.strokeWidth)) * transform.original.scaleY +\n                    (target.width + (target.strokeWidth)) * transform.original.scaleX;\n\n            // We use transform.scaleX/Y instead of target.scaleX/Y\n            // because the object may have a min scale and we'll loose the proportions\n            transform.newScaleX = transform.original.scaleX * dist / lastDist;\n            transform.newScaleY = transform.original.scaleY * dist / lastDist;\n\n            target.set('scaleX', transform.newScaleX);\n            target.set('scaleY', transform.newScaleY);\n        },\n\n        /**\n         * @private\n         */\n        _flipObject: function(transform, by) {\n            if (transform.newScaleX < 0 && by !== 'y') {\n                if (transform.originX === 'left') {\n                    transform.originX = 'right';\n                }\n                else if (transform.originX === 'right') {\n                    transform.originX = 'left';\n                }\n            }\n\n            if (transform.newScaleY < 0 && by !== 'x') {\n                if (transform.originY === 'top') {\n                    transform.originY = 'bottom';\n                }\n                else if (transform.originY === 'bottom') {\n                    transform.originY = 'top';\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _setLocalMouse: function(localMouse, t) {\n            var target = t.target;\n\n            if (t.originX === 'right') {\n                localMouse.x *= -1;\n            }\n            else if (t.originX === 'center') {\n                localMouse.x *= t.mouseXSign * 2;\n\n                if (localMouse.x < 0) {\n                    t.mouseXSign = -t.mouseXSign;\n                }\n            }\n\n            if (t.originY === 'bottom') {\n                localMouse.y *= -1;\n            }\n            else if (t.originY === 'center') {\n                localMouse.y *= t.mouseYSign * 2;\n\n                if (localMouse.y < 0) {\n                    t.mouseYSign = -t.mouseYSign;\n                }\n            }\n\n            // adjust the mouse coordinates when dealing with padding\n            if (abs(localMouse.x) > target.padding) {\n                if (localMouse.x < 0) {\n                    localMouse.x += target.padding;\n                }\n                else {\n                    localMouse.x -= target.padding;\n                }\n            }\n            else { // mouse is within the padding, set to 0\n                localMouse.x = 0;\n            }\n\n            if (abs(localMouse.y) > target.padding) {\n                if (localMouse.y < 0) {\n                    localMouse.y += target.padding;\n                }\n                else {\n                    localMouse.y -= target.padding;\n                }\n            }\n            else {\n                localMouse.y = 0;\n            }\n        },\n\n        /**\n         * Rotates object by invoking its rotate method\n         * @private\n         * @param {Number} x pointer's x coordinate\n         * @param {Number} y pointer's y coordinate\n         */\n        _rotateObject: function (x, y) {\n\n            var t = this._currentTransform;\n\n            if (t.target.get('lockRotation')) {\n                return;\n            }\n\n            var lastAngle = atan2(t.ey - t.top, t.ex - t.left),\n                curAngle = atan2(y - t.top, x - t.left),\n                angle = radiansToDegrees(curAngle - lastAngle + t.theta);\n\n            // normalize angle to positive value\n            if (angle < 0) {\n                angle = 360 + angle;\n            }\n\n            t.target.angle = angle;\n        },\n\n        /**\n         * Set the cursor type of the canvas element\n         * @param {String} value Cursor type of the canvas element.\n         * @see http://www.w3.org/TR/css3-ui/#cursor\n         */\n        setCursor: function (value) {\n            this.upperCanvasEl.style.cursor = value;\n        },\n\n        /**\n         * @private\n         */\n        _resetObjectTransform: function (target) {\n            target.scaleX = 1;\n            target.scaleY = 1;\n            target.setAngle(0);\n        },\n\n        /**\n         * @private\n         */\n        _drawSelection: function () {\n            var ctx = this.contextTop,\n                groupSelector = this._groupSelector,\n                left = groupSelector.left,\n                top = groupSelector.top,\n                aleft = abs(left),\n                atop = abs(top);\n\n            ctx.fillStyle = this.selectionColor;\n\n            ctx.fillRect(\n                    groupSelector.ex - ((left > 0) ? 0 : -left),\n                    groupSelector.ey - ((top > 0) ? 0 : -top),\n                aleft,\n                atop\n            );\n\n            ctx.lineWidth = this.selectionLineWidth;\n            ctx.strokeStyle = this.selectionBorderColor;\n\n            // selection border\n            if (this.selectionDashArray.length > 1) {\n\n                var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0: aleft),\n                    py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0: atop);\n\n                ctx.beginPath();\n\n                fabric.util.drawDashedLine(ctx, px, py, px + aleft, py, this.selectionDashArray);\n                fabric.util.drawDashedLine(ctx, px, py + atop - 1, px + aleft, py + atop - 1, this.selectionDashArray);\n                fabric.util.drawDashedLine(ctx, px, py, px, py + atop, this.selectionDashArray);\n                fabric.util.drawDashedLine(ctx, px + aleft - 1, py, px + aleft - 1, py + atop, this.selectionDashArray);\n\n                ctx.closePath();\n                ctx.stroke();\n            }\n            else {\n                ctx.strokeRect(\n                        groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),\n                        groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop),\n                    aleft,\n                    atop\n                );\n            }\n        },\n\n        /**\n         * @private\n         */\n        _isLastRenderedObject: function(e) {\n            return (\n                this.controlsAboveOverlay &&\n                this.lastRenderedObjectWithControlsAboveOverlay &&\n                this.lastRenderedObjectWithControlsAboveOverlay.visible &&\n                this.containsPoint(e, this.lastRenderedObjectWithControlsAboveOverlay) &&\n                this.lastRenderedObjectWithControlsAboveOverlay._findTargetCorner(this.getPointer(e, true)));\n        },\n\n        /**\n         * Method that determines what object we are clicking on\n         * @param {Event} e mouse event\n         * @param {Boolean} skipGroup when true, group is skipped and only objects are traversed through\n         */\n        findTarget: function (e, skipGroup) {\n            if (this.skipTargetFind) {\n                return;\n            }\n\n            if (this._isLastRenderedObject(e)) {\n                return this.lastRenderedObjectWithControlsAboveOverlay;\n            }\n\n            // first check current group (if one exists)\n            var activeGroup = this.getActiveGroup();\n            if (activeGroup && !skipGroup && this.containsPoint(e, activeGroup)) {\n                return activeGroup;\n            }\n\n            var target = this._searchPossibleTargets(e);\n            this._fireOverOutEvents(target);\n\n            return target;\n        },\n\n        /**\n         * @private\n         */\n        _fireOverOutEvents: function(target) {\n            if (target) {\n                if (this._hoveredTarget !== target) {\n                    this.fire('mouse:over', { target: target });\n                    target.fire('mouseover');\n                    if (this._hoveredTarget) {\n                        this.fire('mouse:out', { target: this._hoveredTarget });\n                        //TODO: Sean fixed bug 5-19-2014\n                        if (!this._hoveredTarget.fire)\n                            return;\n                        this._hoveredTarget.fire('mouseout');\n                    }\n                    this._hoveredTarget = target;\n                }\n            }\n            else if (this._hoveredTarget) {\n                this.fire('mouse:out', { target: this._hoveredTarget });\n                //TODO: Sean fixed bug 6-4-2014\n                if (!this._hoveredTarget.fire)\n                    return;\n                this._hoveredTarget.fire('mouseout');\n                this._hoveredTarget = null;\n            }\n        },\n\n        /**\n         * @private\n         */\n        _checkTarget: function(e, obj, pointer) {\n            if (obj &&\n                obj.visible &&\n                obj.evented &&\n                this.containsPoint(e, obj)){\n                if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) {\n                    var isTransparent = this.isTargetTransparent(obj, pointer.x, pointer.y);\n                    if (!isTransparent) {\n                        return true;\n                    }\n                }\n                else {\n                    return true;\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _searchPossibleTargets: function(e) {\n\n            // Cache all targets where their bounding box contains point.\n            var target,\n                pointer = this.getPointer(e, true),\n                i = this._objects.length;\n\n            while (i--) {\n                if (this._checkTarget(e, this._objects[i], pointer)){\n                    this.relatedTarget = this._objects[i];\n                    target = this._objects[i];\n                    break;\n                }\n            }\n\n            return target;\n        },\n\n        /**\n         * Returns pointer coordinates relative to canvas.\n         * @param {Event} e\n         * @return {Object} object with \"x\" and \"y\" number values\n         */\n        getPointer: function (e, ignoreZoom, upperCanvasEl) {\n            if (!upperCanvasEl) {\n                upperCanvasEl = this.upperCanvasEl;\n            }\n            var pointer = getPointer(e, upperCanvasEl),\n                bounds = upperCanvasEl.getBoundingClientRect(),\n                boundsWidth = bounds.width || 0,\n                boundsHeight = bounds.height || 0,\n                cssScale;\n\n            if (!boundsWidth || !boundsHeight ) {\n                if ('top' in bounds && 'bottom' in bounds) {\n                    boundsHeight = Math.abs( bounds.top - bounds.bottom );\n                }\n                if ('right' in bounds && 'left' in bounds) {\n                    boundsWidth = Math.abs( bounds.right - bounds.left );\n                }\n            }\n\n            this.calcOffset();\n\n            pointer.x = pointer.x - this._offset.left;\n            pointer.y = pointer.y - this._offset.top;\n            if (!ignoreZoom) {\n                pointer = fabric.util.transformPoint(\n                    pointer,\n                    fabric.util.invertTransform(this.viewportTransform)\n                );\n            }\n\n            if (boundsWidth === 0 || boundsHeight === 0) {\n                // If bounds are not available (i.e. not visible), do not apply scale.\n                cssScale = { width: 1, height: 1 };\n            }\n            else {\n                cssScale = {\n                    width: upperCanvasEl.width / boundsWidth,\n                    height: upperCanvasEl.height / boundsHeight\n                };\n            }\n\n            return {\n                x: pointer.x * cssScale.width,\n                y: pointer.y * cssScale.height\n            };\n        },\n\n        /**\n         * @private\n         * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized\n         */\n        _createUpperCanvas: function () {\n            var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\\s*lower-canvas\\s*/, '');\n\n            this.upperCanvasEl = this._createCanvasElement();\n            fabric.util.addClass(this.upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);\n\n            this.wrapperEl.appendChild(this.upperCanvasEl);\n\n            this._copyCanvasStyle(this.lowerCanvasEl, this.upperCanvasEl);\n            this._applyCanvasStyle(this.upperCanvasEl);\n            this.contextTop = this.upperCanvasEl.getContext('2d');\n        },\n\n        /**\n         * @private\n         */\n        _createCacheCanvas: function () {\n            this.cacheCanvasEl = this._createCanvasElement();\n            this.cacheCanvasEl.setAttribute('width', this.width);\n            this.cacheCanvasEl.setAttribute('height', this.height);\n            this.contextCache = this.cacheCanvasEl.getContext('2d');\n        },\n\n        /**\n         * @private\n         */\n        _initWrapperElement: function () {\n            this.wrapperEl = fabric.util.wrapElement(this.lowerCanvasEl, 'div', {\n                'class': this.containerClass\n            });\n            fabric.util.setStyle(this.wrapperEl, {\n                width: this.getWidth() + 'px',\n                height: this.getHeight() + 'px',\n                position: 'relative'\n            });\n            fabric.util.makeElementUnselectable(this.wrapperEl);\n        },\n\n        /**\n         * @private\n         * @param {HTMLElement} element canvas element to apply styles on\n         */\n        _applyCanvasStyle: function (element) {\n            var width = this.getWidth() || element.width,\n                height = this.getHeight() || element.height;\n\n            fabric.util.setStyle(element, {\n                position: 'absolute',\n                width: width + 'px',\n                height: height + 'px',\n                left: 0,\n                top: 0\n            });\n            element.width = width;\n            element.height = height;\n            fabric.util.makeElementUnselectable(element);\n        },\n\n        /**\n         * Copys the the entire inline style from one element (fromEl) to another (toEl)\n         * @private\n         * @param {Element} fromEl Element style is copied from\n         * @param {Element} toEl Element copied style is applied to\n         */\n        _copyCanvasStyle: function (fromEl, toEl) {\n            toEl.style.cssText = fromEl.style.cssText;\n        },\n\n        /**\n         * Returns context of canvas where object selection is drawn\n         * @return {CanvasRenderingContext2D}\n         */\n        getSelectionContext: function() {\n            return this.contextTop;\n        },\n\n        /**\n         * Returns &lt;canvas> element on which object selection is drawn\n         * @return {HTMLCanvasElement}\n         */\n        getSelectionElement: function () {\n            return this.upperCanvasEl;\n        },\n\n        /**\n         * @private\n         * @param {Object} object\n         */\n        _setActiveObject: function(object) {\n            if (this._activeObject) {\n                this._activeObject.set('active', false);\n            }\n            this._activeObject = object;\n            object.set('active', true);\n        },\n\n        /**\n         * Sets given object as the only active object on canvas\n         * @param {fabric.Object} object Object to set as an active one\n         * @param {Event} [e] Event (passed along when firing \"object:selected\")\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        setActiveObject: function (object, e) {\n            this._setActiveObject(object);\n            this.renderAll();\n            this.fire('object:selected', { target: object, e: e });\n            object.fire('selected', { e: e });\n            return this;\n        },\n\n        /**\n         * Returns currently active object\n         * @return {fabric.Object} active object\n         */\n        getActiveObject: function () {\n            return this._activeObject;\n        },\n\n        /**\n         * @private\n         */\n        _discardActiveObject: function() {\n            if (this._activeObject) {\n                this._activeObject.set('active', false);\n            }\n            this._activeObject = null;\n        },\n\n        /**\n         * Discards currently active object\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        discardActiveObject: function (e) {\n            this._discardActiveObject();\n            this.renderAll();\n            this.fire('selection:cleared', { e: e });\n            return this;\n        },\n\n        /**\n         * @private\n         * @param {fabric.Group} group\n         */\n        _setActiveGroup: function(group) {\n            this._activeGroup = group;\n            if (group) {\n                group.set('active', true);\n            }\n        },\n\n        /**\n         * Sets active group to a speicified one\n         * @param {fabric.Group} group Group to set as a current one\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        setActiveGroup: function (group, e) {\n            this._setActiveGroup(group);\n            if (group) {\n                this.fire('object:selected', { target: group, e: e });\n                group.fire('selected', { e: e });\n            }\n            return this;\n        },\n\n        /**\n         * Returns currently active group\n         * @return {fabric.Group} Current group\n         */\n        getActiveGroup: function () {\n            return this._activeGroup;\n        },\n\n        /**\n         * @private\n         */\n        _discardActiveGroup: function() {\n            var g = this.getActiveGroup();\n            if (g) {\n                g.destroy();\n            }\n            this.setActiveGroup(null);\n        },\n\n        /**\n         * Discards currently active group\n         * @return {fabric.Canvas} thisArg\n         */\n        discardActiveGroup: function (e) {\n            this._discardActiveGroup();\n            this.fire('selection:cleared', { e: e });\n            return this;\n        },\n\n        /**\n         * Deactivates all objects on canvas, removing any active group or object\n         * @return {fabric.Canvas} thisArg\n         */\n        deactivateAll: function () {\n            var allObjects = this.getObjects(),\n                i = 0,\n                len = allObjects.length;\n            for ( ; i < len; i++) {\n                allObjects[i].set('active', false);\n            }\n            this._discardActiveGroup();\n            this._discardActiveObject();\n            return this;\n        },\n\n        /**\n         * Deactivates all objects and dispatches appropriate events\n         * @return {fabric.Canvas} thisArg\n         */\n        deactivateAllWithDispatch: function (e) {\n            var activeObject = this.getActiveGroup() || this.getActiveObject();\n            if (activeObject) {\n                this.fire('before:selection:cleared', { target: activeObject, e: e });\n            }\n            this.deactivateAll();\n            if (activeObject) {\n                this.fire('selection:cleared', { e: e });\n            }\n            return this;\n        },\n\n        /**\n         * Draws objects' controls (borders/controls)\n         * @param {CanvasRenderingContext2D} ctx Context to render controls on\n         */\n        drawControls: function(ctx) {\n            var activeGroup = this.getActiveGroup();\n            if (activeGroup) {\n                this._drawGroupControls(ctx, activeGroup);\n            }\n            else {\n                this._drawObjectsControls(ctx);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _drawGroupControls: function(ctx, activeGroup) {\n            activeGroup._renderControls(ctx);\n        },\n\n        /**\n         * @private\n         */\n        _drawObjectsControls: function(ctx) {\n            for (var i = 0, len = this._objects.length; i < len; ++i) {\n                if (!this._objects[i] || !this._objects[i].active) {\n                    continue;\n                }\n                this._objects[i]._renderControls(ctx);\n                this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];\n            }\n        }\n    });\n\n    // copying static properties manually to work around Opera's bug,\n    // where \"prototype\" property is enumerable and overrides existing prototype\n    for (var prop in fabric.StaticCanvas) {\n        if (prop !== 'prototype') {\n            fabric.Canvas[prop] = fabric.StaticCanvas[prop];\n        }\n    }\n\n    if (fabric.isTouchSupported) {\n        /** @ignore */\n        fabric.Canvas.prototype._setCursorFromEvent = function() { };\n    }\n\n    /**\n     * @class fabric.Element\n     * @alias fabric.Canvas\n     * @deprecated Use {@link fabric.Canvas} instead.\n     * @constructor\n     */\n    fabric.Element = fabric.Canvas;\n})()\n;\n\n\n(function() {\n\n    var cursorOffset = {\n            mt: 0, // n\n            tr: 1, // ne\n            mr: 2, // e\n            br: 3, // se\n            mb: 4, // s\n            bl: 5, // sw\n            ml: 6, // w\n            tl: 7 // nw\n        },\n        addListener = fabric.util.addListener,\n        removeListener = fabric.util.removeListener;\n\n    fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n        /**\n         * Map of cursor style values for each of the object controls\n         * @private\n         */\n        cursorMap: [\n            'n-resize',\n            'ne-resize',\n            'e-resize',\n            'se-resize',\n            's-resize',\n            'sw-resize',\n            'w-resize',\n            'nw-resize'\n        ],\n\n        /**\n         * Adds mouse listeners to canvas\n         * @private\n         */\n        _initEventListeners: function () {\n\n            this._bindEvents();\n\n            addListener(fabric.window, 'resize', this._onResize);\n\n            // mouse events\n            addListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);\n            addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n            addListener(this.upperCanvasEl, 'mousewheel', this._onMouseWheel);\n\n            // touch events\n            addListener(this.upperCanvasEl, 'touchstart', this._onMouseDown);\n            addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);\n\n            if (typeof Event !== 'undefined' && 'add' in Event) {\n                Event.add(this.upperCanvasEl, 'gesture', this._onGesture);\n                Event.add(this.upperCanvasEl, 'drag', this._onDrag);\n                Event.add(this.upperCanvasEl, 'orientation', this._onOrientationChange);\n                Event.add(this.upperCanvasEl, 'shake', this._onShake);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _bindEvents: function() {\n            this._onMouseDown = this._onMouseDown.bind(this);\n            this._onMouseMove = this._onMouseMove.bind(this);\n            this._onMouseUp = this._onMouseUp.bind(this);\n            this._onResize = this._onResize.bind(this);\n            this._onGesture = this._onGesture.bind(this);\n            this._onDrag = this._onDrag.bind(this);\n            this._onShake = this._onShake.bind(this);\n            this._onOrientationChange = this._onOrientationChange.bind(this);\n            this._onMouseWheel = this._onMouseWheel.bind(this);\n        },\n\n        /**\n         * Removes all event listeners\n         */\n        removeListeners: function() {\n            removeListener(fabric.window, 'resize', this._onResize);\n\n            removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);\n            removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n            removeListener(this.upperCanvasEl, 'mousewheel', this._onMouseWheel);\n\n            removeListener(this.upperCanvasEl, 'touchstart', this._onMouseDown);\n            removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);\n\n            if (typeof Event !== 'undefined' && 'remove' in Event) {\n                Event.remove(this.upperCanvasEl, 'gesture', this._onGesture);\n                Event.remove(this.upperCanvasEl, 'drag', this._onDrag);\n                Event.remove(this.upperCanvasEl, 'orientation', this._onOrientationChange);\n                Event.remove(this.upperCanvasEl, 'shake', this._onShake);\n            }\n        },\n\n        /**\n         * @private\n         * @param {Event} [e] Event object fired on Event.js gesture\n         * @param {Event} [self] Inner Event object\n         */\n        _onGesture: function(e, self) {\n            this.__onTransformGesture && this.__onTransformGesture(e, self);\n        },\n\n        /**\n         * @private\n         * @param {Event} [e] Event object fired on Event.js drag\n         * @param {Event} [self] Inner Event object\n         */\n        _onDrag: function(e, self) {\n            this.__onDrag && this.__onDrag(e, self);\n        },\n\n        /**\n         * @private\n         * @param {Event} [e] Event object fired on Event.js wheel event\n         * @param {Event} [self] Inner Event object\n         */\n        _onMouseWheel: function(e, self) {\n            this.__onMouseWheel && this.__onMouseWheel(e, self);\n        },\n\n        /**\n         * @private\n         * @param {Event} [e] Event object fired on Event.js orientation change\n         * @param {Event} [self] Inner Event object\n         */\n        _onOrientationChange: function(e, self) {\n            this.__onOrientationChange && this.__onOrientationChange(e, self);\n        },\n\n        /**\n         * @private\n         * @param {Event} [e] Event object fired on Event.js shake\n         * @param {Event} [self] Inner Event object\n         */\n        _onShake: function(e, self) {\n            this.__onShake && this.__onShake(e, self);\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object fired on mousedown\n         */\n        _onMouseDown: function (e) {\n            this.__onMouseDown(e);\n\n            addListener(fabric.document, 'touchend', this._onMouseUp);\n            addListener(fabric.document, 'touchmove', this._onMouseMove);\n\n            removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n            removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);\n\n            if (e.type === 'touchstart') {\n                // Unbind mousedown to prevent double triggers from touch devices\n                removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);\n            }\n            else {\n                addListener(fabric.document, 'mouseup', this._onMouseUp);\n                addListener(fabric.document, 'mousemove', this._onMouseMove);\n            }\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object fired on mouseup\n         */\n        _onMouseUp: function (e) {\n            this.__onMouseUp(e);\n\n            removeListener(fabric.document, 'mouseup', this._onMouseUp);\n            removeListener(fabric.document, 'touchend', this._onMouseUp);\n\n            removeListener(fabric.document, 'mousemove', this._onMouseMove);\n            removeListener(fabric.document, 'touchmove', this._onMouseMove);\n\n            addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n            addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);\n\n            if (e.type === 'touchend') {\n                // Wait 400ms before rebinding mousedown to prevent double triggers\n                // from touch devices\n                var _this = this;\n                setTimeout(function() {\n                    addListener(_this.upperCanvasEl, 'mousedown', _this._onMouseDown);\n                }, 400);\n            }\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object fired on mousemove\n         */\n        _onMouseMove: function (e) {\n            !this.allowTouchScrolling && e.preventDefault && e.preventDefault();\n            this.__onMouseMove(e);\n        },\n\n        /**\n         * @private\n         */\n        _onResize: function () {\n            this.calcOffset();\n        },\n\n        /**\n         * Decides whether the canvas should be redrawn in mouseup and mousedown events.\n         * @private\n         * @param {Object} target\n         * @param {Object} pointer\n         */\n        _shouldRender: function(target, pointer) {\n            var activeObject = this.getActiveGroup() || this.getActiveObject();\n\n            return !!(\n                (target && (\n                    target.isMoving ||\n                    target !== activeObject))\n                ||\n                (!target && !!activeObject)\n                ||\n                (!target && !activeObject && !this._groupSelector)\n                ||\n                (pointer &&\n                    this._previousPointer &&\n                    this.selection && (\n                    pointer.x !== this._previousPointer.x ||\n                    pointer.y !== this._previousPointer.y))\n                );\n        },\n\n        /**\n         * Method that defines the actions when mouse is released on canvas.\n         * The method resets the currentTransform parameters, store the image corner\n         * position in the image object and render the canvas on top.\n         * @private\n         * @param {Event} e Event object fired on mouseup\n         */\n        __onMouseUp: function (e) {\n            var target;\n\n            if (this.isDrawingMode && this._isCurrentlyDrawing) {\n                this._onMouseUpInDrawingMode(e);\n                return;\n            }\n\n            if (this._currentTransform) {\n                this._finalizeCurrentTransform();\n                target = this._currentTransform.target;\n            }\n            else {\n                target = this.findTarget(e, true);\n            }\n\n            var shouldRender = this._shouldRender(target, this.getPointer(e));\n\n            this._maybeGroupObjects(e);\n\n            if (target) {\n                target.isMoving = false;\n            }\n\n            shouldRender && this.renderAll();\n\n            this._handleCursorAndEvent(e, target);\n        },\n\n        _handleCursorAndEvent: function(e, target) {\n            this._setCursorFromEvent(e, target);\n\n            // TODO: why are we doing this?\n            var _this = this;\n            setTimeout(function () {\n                _this._setCursorFromEvent(e, target);\n            }, 50);\n\n            this.fire('mouse:up', { target: target, e: e });\n            target && target.fire('mouseup', { e: e });\n        },\n\n        /**\n         * @private\n         */\n        _finalizeCurrentTransform: function() {\n\n            var transform = this._currentTransform,\n                target = transform.target;\n\n            if (target._scaling) {\n                target._scaling = false;\n            }\n\n            target.setCoords();\n\n            // only fire :modified event if target coordinates were changed during mousedown-mouseup\n            if (this.stateful && target.hasStateChanged()) {\n                this.fire('object:modified', { target: target });\n                target.fire('modified');\n            }\n\n            this._restoreOriginXY(target);\n        },\n\n        /**\n         * @private\n         * @param {Object} target Object to restore\n         */\n        _restoreOriginXY: function(target) {\n            if (this._previousOriginX && this._previousOriginY) {\n\n                var originPoint = target.translateToOriginPoint(\n                    target.getCenterPoint(),\n                    this._previousOriginX,\n                    this._previousOriginY);\n\n                target.originX = this._previousOriginX;\n                target.originY = this._previousOriginY;\n\n                target.left = originPoint.x;\n                target.top = originPoint.y;\n\n                this._previousOriginX = null;\n                this._previousOriginY = null;\n            }\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object fired on mousedown\n         */\n        _onMouseDownInDrawingMode: function(e) {\n            this._isCurrentlyDrawing = true;\n            this.discardActiveObject(e).renderAll();\n            if (this.clipTo) {\n                fabric.util.clipContext(this, this.contextTop);\n            }\n            var ivt = fabric.util.invertTransform(this.viewportTransform),\n                pointer = fabric.util.transformPoint(this.getPointer(e, true), ivt);\n            this.freeDrawingBrush.onMouseDown(pointer);\n            this.fire('mouse:down', { e: e });\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object fired on mousemove\n         */\n        _onMouseMoveInDrawingMode: function(e) {\n            if (this._isCurrentlyDrawing) {\n                var ivt = fabric.util.invertTransform(this.viewportTransform),\n                    pointer = fabric.util.transformPoint(this.getPointer(e, true), ivt);\n                this.freeDrawingBrush.onMouseMove(pointer);\n            }\n            this.setCursor(this.freeDrawingCursor);\n            this.fire('mouse:move', { e: e });\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object fired on mouseup\n         */\n        _onMouseUpInDrawingMode: function(e) {\n            this._isCurrentlyDrawing = false;\n            if (this.clipTo) {\n                this.contextTop.restore();\n            }\n            this.freeDrawingBrush.onMouseUp();\n            this.fire('mouse:up', { e: e });\n        },\n\n        /**\n         * Method that defines the actions when mouse is clic ked on canvas.\n         * The method inits the currentTransform parameters and renders all the\n         * canvas so the current image can be placed on the top canvas and the rest\n         * in on the container one.\n         * @private\n         * @param {Event} e Event object fired on mousedown\n         */\n        __onMouseDown: function (e) {\n\n            // accept only left clicks\n            var isLeftClick  = 'which' in e ? e.which === 1 : e.button === 1;\n            if (!isLeftClick && !fabric.isTouchSupported) {\n                return;\n            }\n\n            if (this.isDrawingMode) {\n                this._onMouseDownInDrawingMode(e);\n                return;\n            }\n\n            // ignore if some object is being transformed at this moment\n            if (this._currentTransform) {\n                return;\n            }\n\n            var target = this.findTarget(e),\n                pointer = this.getPointer(e, true);\n\n            // save pointer for check in __onMouseUp event\n            this._previousPointer = pointer;\n\n            var shouldRender = this._shouldRender(target, pointer),\n                shouldGroup = this._shouldGroup(e, target);\n\n            if (this._shouldClearSelection(e, target)) {\n                this._clearSelection(e, target, pointer);\n            }\n            else if (shouldGroup) {\n                this._handleGrouping(e, target);\n                target = this.getActiveGroup();\n            }\n\n            if (target && target.selectable && !shouldGroup) {\n                this._beforeTransform(e, target);\n                this._setupCurrentTransform(e, target);\n            }\n            // we must renderAll so that active image is placed on the top canvas\n            shouldRender && this.renderAll();\n\n            this.fire('mouse:down', { target: target, e: e });\n            target && target.fire('mousedown', { e: e });\n        },\n\n        /**\n         * @private\n         */\n        _beforeTransform: function(e, target) {\n            var corner;\n\n            this.stateful && target.saveState();\n\n            // determine if it's a drag or rotate case\n            if ((corner = target._findTargetCorner(this.getPointer(e)))) {\n                this.onBeforeScaleRotate(target);\n            }\n\n            if (target !== this.getActiveGroup() && target !== this.getActiveObject()) {\n                this.deactivateAll();\n                this.setActiveObject(target, e);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _clearSelection: function(e, target, pointer) {\n            this.deactivateAllWithDispatch(e);\n\n            if (target && target.selectable) {\n                this.setActiveObject(target, e);\n            }\n            else if (this.selection) {\n                this._groupSelector = {\n                    ex: pointer.x,\n                    ey: pointer.y,\n                    top: 0,\n                    left: 0\n                };\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} target Object for that origin is set to center\n         */\n        _setOriginToCenter: function(target) {\n            this._previousOriginX = this._currentTransform.target.originX;\n            this._previousOriginY = this._currentTransform.target.originY;\n\n            var center = target.getCenterPoint();\n\n            target.originX = 'center';\n            target.originY = 'center';\n\n            target.left = center.x;\n            target.top = center.y;\n\n            this._currentTransform.left = target.left;\n            this._currentTransform.top = target.top;\n        },\n\n        /**\n         * @private\n         * @param {Object} target Object for that center is set to origin\n         */\n        _setCenterToOrigin: function(target) {\n            var originPoint = target.translateToOriginPoint(\n                target.getCenterPoint(),\n                this._previousOriginX,\n                this._previousOriginY);\n\n            target.originX = this._previousOriginX;\n            target.originY = this._previousOriginY;\n\n            target.left = originPoint.x;\n            target.top = originPoint.y;\n\n            this._previousOriginX = null;\n            this._previousOriginY = null;\n        },\n\n        /**\n         * Method that defines the actions when mouse is hovering the canvas.\n         * The currentTransform parameter will definde whether the user is rotating/scaling/translating\n         * an image or neither of them (only hovering). A group selection is also possible and would cancel\n         * all any other type of action.\n         * In case of an image transformation only the top canvas will be rendered.\n         * @private\n         * @param {Event} e Event object fired on mousemove\n         */\n        __onMouseMove: function (e) {\n\n            var target, pointer;\n\n            if (this.isDrawingMode) {\n                this._onMouseMoveInDrawingMode(e);\n                return;\n            }\n\n            var groupSelector = this._groupSelector;\n\n            // We initially clicked in an empty area, so we draw a box for multiple selection\n            if (groupSelector) {\n                pointer = this.getPointer(e, true);\n\n                groupSelector.left = pointer.x - groupSelector.ex;\n                groupSelector.top = pointer.y - groupSelector.ey;\n\n                this.renderTop();\n            }\n            else if (!this._currentTransform) {\n\n                target = this.findTarget(e);\n\n                if (!target || target && !target.selectable) {\n                    this.setCursor(this.defaultCursor);\n                }\n                else {\n                    this._setCursorFromEvent(e, target);\n                }\n            }\n            else {\n                this._transformObject(e);\n            }\n\n            this.fire('mouse:move', { target: target, e: e });\n            target && target.fire('mousemove', { e: e });\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event fired on mousemove\n         */\n        _transformObject: function(e) {\n            var pointer = this.getPointer(e),\n                transform = this._currentTransform;\n\n            transform.reset = false,\n                transform.target.isMoving = true;\n\n            this._beforeScaleTransform(e, transform);\n            this._performTransformAction(e, transform, pointer);\n\n            this.renderAll();\n        },\n\n        /**\n         * @private\n         */\n        _performTransformAction: function(e, transform, pointer) {\n            var x = pointer.x,\n                y = pointer.y,\n                target = transform.target,\n                action = transform.action;\n\n            if (action === 'rotate') {\n                this._rotateObject(x, y);\n                this._fire('rotating', target, e);\n            }\n            else if (action === 'scale') {\n                this._onScale(e, transform, x, y);\n                this._fire('scaling', target, e);\n            }\n            else if (action === 'scaleX') {\n                this._scaleObject(x, y, 'x');\n                this._fire('scaling', target, e);\n            }\n            else if (action === 'scaleY') {\n                this._scaleObject(x, y, 'y');\n                this._fire('scaling', target, e);\n            }\n            else {\n                this._translateObject(x, y);\n                this._fire('moving', target, e);\n                this.setCursor(this.moveCursor);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _fire: function(eventName, target, e) {\n            this.fire('object:' + eventName, { target: target, e: e });\n            target.fire(eventName, { e: e });\n        },\n\n        /**\n         * @private\n         */\n        _beforeScaleTransform: function(e, transform) {\n            if (transform.action === 'scale' || transform.action === 'scaleX' || transform.action === 'scaleY') {\n                var centerTransform = this._shouldCenterTransform(e, transform.target);\n\n                // Switch from a normal resize to center-based\n                if ((centerTransform && (transform.originX !== 'center' || transform.originY !== 'center')) ||\n                    // Switch from center-based resize to normal one\n                    (!centerTransform && transform.originX === 'center' && transform.originY === 'center')\n                    ) {\n                    this._resetCurrentTransform(e);\n                    transform.reset = true;\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _onScale: function(e, transform, x, y) {\n            // rotate object only if shift key is not pressed\n            // and if it is not a group we are transforming\n            if ((e.shiftKey || this.uniScaleTransform) && !transform.target.get('lockUniScaling')) {\n                transform.currentAction = 'scale';\n                this._scaleObject(x, y);\n            }\n            else {\n                // Switch from a normal resize to proportional\n                if (!transform.reset && transform.currentAction === 'scale') {\n                    this._resetCurrentTransform(e, transform.target);\n                }\n\n                transform.currentAction = 'scaleEqually';\n                this._scaleObject(x, y, 'equally');\n            }\n        },\n\n        /**\n         * Sets the cursor depending on where the canvas is being hovered.\n         * Note: very buggy in Opera\n         * @param {Event} e Event object\n         * @param {Object} target Object that the mouse is hovering, if so.\n         */\n        _setCursorFromEvent: function (e, target) {\n            if (!target || !target.selectable) {\n                this.setCursor(this.defaultCursor);\n                return false;\n            }\n            else {\n                var activeGroup = this.getActiveGroup(),\n                // only show proper corner when group selection is not active\n                    corner = target._findTargetCorner\n                        && (!activeGroup || !activeGroup.contains(target))\n                        && target._findTargetCorner(this.getPointer(e, true));\n\n                if (!corner) {\n                    this.setCursor(target.hoverCursor || this.hoverCursor);\n                }\n                else {\n                    this._setCornerCursor(corner, target);\n                }\n            }\n            return true;\n        },\n\n        /**\n         * @private\n         */\n        _setCornerCursor: function(corner, target) {\n            if (corner in cursorOffset) {\n                this.setCursor(this._getRotatedCornerCursor(corner, target));\n            }\n            else if (corner === 'mtr' && target.hasRotatingPoint) {\n                this.setCursor(this.rotationCursor);\n            }\n            else {\n                this.setCursor(this.defaultCursor);\n                return false;\n            }\n        },\n\n        /**\n         * @private\n         */\n        _getRotatedCornerCursor: function(corner, target) {\n            var n = Math.round((target.getAngle() % 360) / 45);\n\n            if (n < 0) {\n                n += 8; // full circle ahead\n            }\n            n += cursorOffset[corner];\n            // normalize n to be from 0 to 7\n            n %= 8;\n\n            return this.cursorMap[n];\n        }\n    });\n})();\n\n\n(function() {\n\n    var min = Math.min,\n        max = Math.max;\n\n    fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n        /**\n         * @private\n         * @param {Event} e Event object\n         * @param {fabric.Object} target\n         * @return {Boolean}\n         */\n        _shouldGroup: function(e, target) {\n            var activeObject = this.getActiveObject();\n            return e.shiftKey &&\n                (this.getActiveGroup() || (activeObject && activeObject !== target))\n                && this.selection;\n        },\n\n        /**\n         * @private\n         * @param {Event} e Event object\n         * @param {fabric.Object} target\n         */\n        _handleGrouping: function (e, target) {\n\n            if (target === this.getActiveGroup()) {\n\n                // if it's a group, find target again, this time skipping group\n                target = this.findTarget(e, true);\n\n                // if even object is not found, bail out\n                if (!target || target.isType('group')) {\n                    return;\n                }\n            }\n            if (this.getActiveGroup()) {\n                this._updateActiveGroup(target, e);\n            }\n            else {\n                this._createActiveGroup(target, e);\n            }\n\n            if (this._activeGroup) {\n                this._activeGroup.saveCoords();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _updateActiveGroup: function(target, e) {\n            var activeGroup = this.getActiveGroup();\n\n            if (activeGroup.contains(target)) {\n\n                activeGroup.removeWithUpdate(target);\n                this._resetObjectTransform(activeGroup);\n                target.set('active', false);\n\n                if (activeGroup.size() === 1) {\n                    // remove group alltogether if after removal it only contains 1 object\n                    this.discardActiveGroup(e);\n                    // activate last remaining object\n                    this.setActiveObject(activeGroup.item(0));\n                    return;\n                }\n            }\n            else {\n                activeGroup.addWithUpdate(target);\n                this._resetObjectTransform(activeGroup);\n            }\n            this.fire('selection:created', { target: activeGroup, e: e });\n            activeGroup.set('active', true);\n        },\n\n        /**\n         * @private\n         */\n        _createActiveGroup: function(target, e) {\n\n            if (this._activeObject && target !== this._activeObject) {\n\n                var group = this._createGroup(target);\n                group.addWithUpdate();\n\n                this.setActiveGroup(group);\n                this._activeObject = null;\n\n                this.fire('selection:created', { target: group, e: e });\n            }\n\n            target.set('active', true);\n        },\n\n        /**\n         * @private\n         * @param {Object} target\n         */\n        _createGroup: function(target) {\n\n            var objects = this.getObjects(),\n                isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),\n                groupObjects = isActiveLower\n                    ? [ this._activeObject, target ]\n                    : [ target, this._activeObject ];\n\n            return new fabric.Group(groupObjects, {\n                originX: 'center',\n                originY: 'center',\n                canvas: this\n            });\n        },\n\n        /**\n         * @private\n         * @param {Event} e mouse event\n         */\n        _groupSelectedObjects: function (e) {\n\n            var group = this._collectObjects();\n\n            // do not create group for 1 element only\n            if (group.length === 1) {\n                this.setActiveObject(group[0], e);\n            }\n            else if (group.length > 1) {\n                group = new fabric.Group(group.reverse(), {\n                    originX: 'center',\n                    originY: 'center',\n                    canvas: this\n                });\n                group.addWithUpdate();\n                this.setActiveGroup(group, e);\n                group.saveCoords();\n                this.fire('selection:created', { target: group });\n                this.renderAll();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _collectObjects: function() {\n            var group = [ ],\n                currentObject,\n                x1 = this._groupSelector.ex,\n                y1 = this._groupSelector.ey,\n                x2 = x1 + this._groupSelector.left,\n                y2 = y1 + this._groupSelector.top,\n                selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),\n                selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),\n                isClick = x1 === x2 && y1 === y2;\n\n            for (var i = this._objects.length; i--; ) {\n                currentObject = this._objects[i];\n\n                if (!currentObject || !currentObject.selectable || !currentObject.visible) {\n                    continue;\n                }\n\n                if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) ||\n                    currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) ||\n                    currentObject.containsPoint(selectionX1Y1) ||\n                    currentObject.containsPoint(selectionX2Y2)\n                    ) {\n                    currentObject.set('active', true);\n                    group.push(currentObject);\n\n                    // only add one object if it's a click\n                    if (isClick) {\n                        break;\n                    }\n                }\n            }\n\n            return group;\n        },\n\n        /**\n         * @private\n         */\n        _maybeGroupObjects: function(e) {\n            if (this.selection && this._groupSelector) {\n                this._groupSelectedObjects(e);\n            }\n\n            var activeGroup = this.getActiveGroup();\n            if (activeGroup) {\n                activeGroup.setObjectsCoords().setCoords();\n                activeGroup.isMoving = false;\n                this.setCursor(this.defaultCursor);\n            }\n\n            // clear selection and current transformation\n            this._groupSelector = null;\n            this._currentTransform = null;\n        }\n    });\n\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately\n     * @param {Object} [options] Options object\n     * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n     * @param {Number} [options.multiplier=1] Multiplier to scale by\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n     * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}\n     * @example <caption>Generate jpeg dataURL with lower quality</caption>\n     * var dataURL = canvas.toDataURL({\n   *   format: 'jpeg',\n   *   quality: 0.8\n   * });\n     * @example <caption>Generate cropped png dataURL (clipping of canvas)</caption>\n     * var dataURL = canvas.toDataURL({\n   *   format: 'png',\n   *   left: 100,\n   *   top: 100,\n   *   width: 200,\n   *   height: 200\n   * });\n     * @example <caption>Generate double scaled png dataURL</caption>\n     * var dataURL = canvas.toDataURL({\n   *   format: 'png',\n   *   multiplier: 2\n   * });\n     */\n    toDataURL: function (options) {\n        options || (options = { });\n\n        var format = options.format || 'png',\n            quality = options.quality || 1,\n            multiplier = options.multiplier || 1,\n            cropping = {\n                left: options.left,\n                top: options.top,\n                width: options.width,\n                height: options.height\n            };\n\n        if (multiplier !== 1) {\n            return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier);\n        }\n        else {\n            return this.__toDataURL(format, quality, cropping);\n        }\n    },\n\n    /**\n     * @private\n     */\n    __toDataURL: function(format, quality, cropping) {\n\n        this.renderAll(true);\n\n        var canvasEl = this.upperCanvasEl || this.lowerCanvasEl,\n            croppedCanvasEl = this.__getCroppedCanvas(canvasEl, cropping);\n\n        // to avoid common confusion https://github.com/kangax/fabric.js/issues/806\n        if (format === 'jpg') {\n            format = 'jpeg';\n        }\n\n        var data = (fabric.StaticCanvas.supports('toDataURLWithQuality'))\n            ? (croppedCanvasEl || canvasEl).toDataURL('image/' + format, quality)\n            : (croppedCanvasEl || canvasEl).toDataURL('image/' + format);\n\n        this.contextTop && this.clearContext(this.contextTop);\n        this.renderAll();\n\n        if (croppedCanvasEl) {\n            croppedCanvasEl = null;\n        }\n\n        return data;\n    },\n\n    /**\n     * @private\n     */\n    __getCroppedCanvas: function(canvasEl, cropping) {\n\n        var croppedCanvasEl,\n            croppedCtx,\n            shouldCrop = 'left' in cropping ||\n                'top' in cropping ||\n                'width' in cropping ||\n                'height' in cropping;\n\n        if (shouldCrop) {\n\n            croppedCanvasEl = fabric.util.createCanvasElement();\n            croppedCtx = croppedCanvasEl.getContext('2d');\n\n            croppedCanvasEl.width = cropping.width || this.width;\n            croppedCanvasEl.height = cropping.height || this.height;\n\n            croppedCtx.drawImage(canvasEl, -cropping.left || 0, -cropping.top || 0);\n        }\n\n        return croppedCanvasEl;\n    },\n\n    /**\n     * @private\n     */\n    __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) {\n\n        var origWidth = this.getWidth(),\n            origHeight = this.getHeight(),\n            scaledWidth = origWidth * multiplier,\n            scaledHeight = origHeight * multiplier,\n            activeObject = this.getActiveObject(),\n            activeGroup = this.getActiveGroup(),\n\n            ctx = this.contextTop || this.contextContainer;\n\n        if (multiplier > 1) {\n            this.setWidth(scaledWidth).setHeight(scaledHeight);\n        }\n        ctx.scale(multiplier, multiplier);\n\n        if (cropping.left) {\n            cropping.left *= multiplier;\n        }\n        if (cropping.top) {\n            cropping.top *= multiplier;\n        }\n        if (cropping.width) {\n            cropping.width *= multiplier;\n        }\n        else if (multiplier < 1) {\n            cropping.width = scaledWidth;\n        }\n        if (cropping.height) {\n            cropping.height *= multiplier;\n        }\n        else if (multiplier < 1) {\n            cropping.height = scaledHeight;\n        }\n\n        if (activeGroup) {\n            // not removing group due to complications with restoring it with correct state afterwords\n            this._tempRemoveBordersControlsFromGroup(activeGroup);\n        }\n        else if (activeObject && this.deactivateAll) {\n            this.deactivateAll();\n        }\n\n        this.renderAll(true);\n\n        var data = this.__toDataURL(format, quality, cropping);\n\n        // restoring width, height for `renderAll` to draw\n        // background properly (while context is scaled)\n        this.width = origWidth;\n        this.height = origHeight;\n\n        ctx.scale(1 / multiplier,  1 / multiplier);\n        this.setWidth(origWidth).setHeight(origHeight);\n\n        if (activeGroup) {\n            this._restoreBordersControlsOnGroup(activeGroup);\n        }\n        else if (activeObject && this.setActiveObject) {\n            this.setActiveObject(activeObject);\n        }\n\n        this.contextTop && this.clearContext(this.contextTop);\n        this.renderAll();\n\n        return data;\n    },\n\n    /**\n     * Exports canvas element to a dataurl image (allowing to change image size via multiplier).\n     * @deprecated since 1.0.13\n     * @param {String} format (png|jpeg)\n     * @param {Number} multiplier\n     * @param {Number} quality (0..1)\n     * @return {String}\n     */\n    toDataURLWithMultiplier: function (format, multiplier, quality) {\n        return this.toDataURL({\n            format: format,\n            multiplier: multiplier,\n            quality: quality\n        });\n    },\n\n    /**\n     * @private\n     */\n    _tempRemoveBordersControlsFromGroup: function(group) {\n        group.origHasControls = group.hasControls;\n        group.origBorderColor = group.borderColor;\n\n        group.hasControls = true;\n        group.borderColor = 'rgba(0,0,0,0)';\n\n        group.forEachObject(function(o) {\n            o.origBorderColor = o.borderColor;\n            o.borderColor = 'rgba(0,0,0,0)';\n        });\n    },\n\n    /**\n     * @private\n     */\n    _restoreBordersControlsOnGroup: function(group) {\n        group.hideControls = group.origHideControls;\n        group.borderColor = group.origBorderColor;\n\n        group.forEachObject(function(o) {\n            o.borderColor = o.origBorderColor;\n            delete o.origBorderColor;\n        });\n    }\n});\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Populates canvas with data from the specified dataless JSON.\n     * JSON format must conform to the one of {@link fabric.Canvas#toDatalessJSON}\n     * @deprecated since 1.2.2\n     * @param {String|Object} json JSON string or object\n     * @param {Function} callback Callback, invoked when json is parsed\n     *                            and corresponding objects (e.g: {@link fabric.Image})\n     *                            are initialized\n     * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n     * @return {fabric.Canvas} instance\n     * @chainable\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3/#deserialization}\n     */\n    loadFromDatalessJSON: function (json, callback, reviver) {\n        return this.loadFromJSON(json, callback, reviver);\n    },\n\n    /**\n     * Populates canvas with data from the specified JSON.\n     * JSON format must conform to the one of {@link fabric.Canvas#toJSON}\n     * @param {String|Object} json JSON string or object\n     * @param {Function} callback Callback, invoked when json is parsed\n     *                            and corresponding objects (e.g: {@link fabric.Image})\n     *                            are initialized\n     * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n     * @return {fabric.Canvas} instance\n     * @chainable\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3/#deserialization}\n     * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo}\n     * @example <caption>loadFromJSON</caption>\n     * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));\n     * @example <caption>loadFromJSON with reviver</caption>\n     * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) {\n   *   // `o` = json object\n   *   // `object` = fabric.Object instance\n   *   // ... do some stuff ...\n   * });\n     */\n    loadFromJSON: function (json, callback, reviver) {\n        if (!json) {\n            return;\n        }\n\n        // serialize if it wasn't already\n        var serialized = (typeof json === 'string')\n            ? JSON.parse(json)\n            : json;\n\n        this.clear();\n\n        var _this = this;\n        this._enlivenObjects(serialized.objects, function () {\n            _this._setBgOverlay(serialized, callback);\n        }, reviver);\n\n        return this;\n    },\n\n    /**\n     * @private\n     * @param {Object} serialized Object with background and overlay information\n     * @param {Function} callback Invoked after all background and overlay images/patterns loaded\n     */\n    _setBgOverlay: function(serialized, callback) {\n        var _this = this,\n            loaded = {\n                backgroundColor: false,\n                overlayColor: false,\n                backgroundImage: false,\n                overlayImage: false\n            };\n\n        if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) {\n            callback && callback();\n            return;\n        }\n\n        var cbIfLoaded = function () {\n            if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) {\n                _this.renderAll();\n                callback && callback();\n            }\n        };\n\n        this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded);\n        this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded);\n        this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded);\n        this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded);\n\n        cbIfLoaded();\n    },\n\n    /**\n     * @private\n     * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor)\n     * @param {(Object|String)} value Value to set\n     * @param {Object} loaded Set loaded property to true if property is set\n     * @param {Object} callback Callback function to invoke after property is set\n     */\n    __setBgOverlay: function(property, value, loaded, callback) {\n        var _this = this;\n\n        if (!value) {\n            loaded[property] = true;\n            return;\n        }\n\n        if (property === 'backgroundImage' || property === 'overlayImage') {\n            fabric.Image.fromObject(value, function(img) {\n                _this[property] = img;\n                loaded[property] = true;\n                callback && callback();\n            });\n        }\n        else {\n            this['set' + fabric.util.string.capitalize(property, true)](value, function() {\n                loaded[property] = true;\n                callback && callback();\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {Array} objects\n     * @param {Function} callback\n     * @param {Function} [reviver]\n     */\n    _enlivenObjects: function (objects, callback, reviver) {\n        var _this = this;\n\n        if (!objects || objects.length === 0) {\n            callback && callback();\n            return;\n        }\n\n        var renderOnAddRemove = this.renderOnAddRemove;\n        this.renderOnAddRemove = false;\n\n        fabric.util.enlivenObjects(objects, function(enlivenedObjects) {\n            enlivenedObjects.forEach(function(obj, index) {\n                _this.insertAt(obj, index, true);\n            });\n\n            _this.renderOnAddRemove = renderOnAddRemove;\n            callback && callback();\n        }, null, reviver);\n    },\n\n    /**\n     * @private\n     * @param {String} format\n     * @param {Function} callback\n     */\n    _toDataURL: function (format, callback) {\n        this.clone(function (clone) {\n            callback(clone.toDataURL(format));\n        });\n    },\n\n    /**\n     * @private\n     * @param {String} format\n     * @param {Number} multiplier\n     * @param {Function} callback\n     */\n    _toDataURLWithMultiplier: function (format, multiplier, callback) {\n        this.clone(function (clone) {\n            callback(clone.toDataURLWithMultiplier(format, multiplier));\n        });\n    },\n\n    /**\n     * Clones canvas instance\n     * @param {Object} [callback] Receives cloned instance as a first argument\n     * @param {Array} [properties] Array of properties to include in the cloned canvas and children\n     */\n    clone: function (callback, properties) {\n        var data = JSON.stringify(this.toJSON(properties));\n        this.cloneWithoutData(function(clone) {\n            clone.loadFromJSON(data, function() {\n                callback && callback(clone);\n            });\n        });\n    },\n\n    /**\n     * Clones canvas instance without cloning existing data.\n     * This essentially copies canvas dimensions, clipping properties, etc.\n     * but leaves data empty (so that you can populate it with your own)\n     * @param {Object} [callback] Receives cloned instance as a first argument\n     */\n    cloneWithoutData: function(callback) {\n        var el = fabric.document.createElement('canvas');\n\n        el.width = this.getWidth();\n        el.height = this.getHeight();\n\n        var clone = new fabric.Canvas(el);\n        clone.clipTo = this.clipTo;\n        if (this.backgroundImage) {\n            clone.setBackgroundImage(this.backgroundImage.src, function() {\n                clone.renderAll();\n                callback && callback(clone);\n            });\n            clone.backgroundImageOpacity = this.backgroundImageOpacity;\n            clone.backgroundImageStretch = this.backgroundImageStretch;\n        }\n        else {\n            callback && callback(clone);\n        }\n    }\n});\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        toFixed = fabric.util.toFixed,\n        capitalize = fabric.util.string.capitalize,\n        degreesToRadians = fabric.util.degreesToRadians,\n        supportsLineDash = fabric.StaticCanvas.supports('setLineDash');\n\n    if (fabric.Object) {\n        return;\n    }\n\n    /**\n     * Root object class from which all 2d shape classes inherit from\n     * @class fabric.Object\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-1/#objects}\n     * @see {@link fabric.Object#initialize} for constructor definition\n     *\n     * @fires added\n     * @fires removed\n     *\n     * @fires selected\n     * @fires modified\n     * @fires rotating\n     * @fires scaling\n     * @fires moving\n     *\n     * @fires mousedown\n     * @fires mouseup\n     */\n    fabric.Object = fabric.util.createClass(/** @lends fabric.Object.prototype */ {\n\n        /**\n         * Retrieves object's {@link fabric.Object#clipTo|clipping function}\n         * @method getClipTo\n         * @memberOf fabric.Object.prototype\n         * @return {Function}\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#clipTo|clipping function}\n         * @method setClipTo\n         * @memberOf fabric.Object.prototype\n         * @param {Function} clipTo Clipping function\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#transformMatrix|transformMatrix}\n         * @method getTransformMatrix\n         * @memberOf fabric.Object.prototype\n         * @return {Array} transformMatrix\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#transformMatrix|transformMatrix}\n         * @method setTransformMatrix\n         * @memberOf fabric.Object.prototype\n         * @param {Array} transformMatrix\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#visible|visible} state\n         * @method getVisible\n         * @memberOf fabric.Object.prototype\n         * @return {Boolean} True if visible\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#visible|visible} state\n         * @method setVisible\n         * @memberOf fabric.Object.prototype\n         * @param {Boolean} value visible value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#shadow|shadow}\n         * @method getShadow\n         * @memberOf fabric.Object.prototype\n         * @return {Object} Shadow instance\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#stroke|stroke}\n         * @method getStroke\n         * @memberOf fabric.Object.prototype\n         * @return {String} stroke value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#stroke|stroke}\n         * @method setStroke\n         * @memberOf fabric.Object.prototype\n         * @param {String} value stroke value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#strokeWidth|strokeWidth}\n         * @method getStrokeWidth\n         * @memberOf fabric.Object.prototype\n         * @return {Number} strokeWidth value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#strokeWidth|strokeWidth}\n         * @method setStrokeWidth\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value strokeWidth value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#originX|originX}\n         * @method getOriginX\n         * @memberOf fabric.Object.prototype\n         * @return {String} originX value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#originX|originX}\n         * @method setOriginX\n         * @memberOf fabric.Object.prototype\n         * @param {String} value originX value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#originY|originY}\n         * @method getOriginY\n         * @memberOf fabric.Object.prototype\n         * @return {String} originY value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#originY|originY}\n         * @method setOriginY\n         * @memberOf fabric.Object.prototype\n         * @param {String} value originY value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#fill|fill}\n         * @method getFill\n         * @memberOf fabric.Object.prototype\n         * @return {String} Fill value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#fill|fill}\n         * @method setFill\n         * @memberOf fabric.Object.prototype\n         * @param {String} value Fill value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#opacity|opacity}\n         * @method getOpacity\n         * @memberOf fabric.Object.prototype\n         * @return {Number} Opacity value (0-1)\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#opacity|opacity}\n         * @method setOpacity\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value Opacity value (0-1)\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#angle|angle} (in degrees)\n         * @method getAngle\n         * @memberOf fabric.Object.prototype\n         * @return {Number}\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#angle|angle}\n         * @method setAngle\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value Angle value (in degrees)\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#top|top position}\n         * @method getTop\n         * @memberOf fabric.Object.prototype\n         * @return {Number} Top value (in pixels)\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#top|top position}\n         * @method setTop\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value Top value (in pixels)\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#left|left position}\n         * @method getLeft\n         * @memberOf fabric.Object.prototype\n         * @return {Number} Left value (in pixels)\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#left|left position}\n         * @method setLeft\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value Left value (in pixels)\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#scaleX|scaleX} value\n         * @method getScaleX\n         * @memberOf fabric.Object.prototype\n         * @return {Number} scaleX value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#scaleX|scaleX} value\n         * @method setScaleX\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value scaleX value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#scaleY|scaleY} value\n         * @method getScaleY\n         * @memberOf fabric.Object.prototype\n         * @return {Number} scaleY value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#scaleY|scaleY} value\n         * @method setScaleY\n         * @memberOf fabric.Object.prototype\n         * @param {Number} value scaleY value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#flipX|flipX} value\n         * @method getFlipX\n         * @memberOf fabric.Object.prototype\n         * @return {Boolean} flipX value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#flipX|flipX} value\n         * @method setFlipX\n         * @memberOf fabric.Object.prototype\n         * @param {Boolean} value flipX value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's {@link fabric.Object#flipY|flipY} value\n         * @method getFlipY\n         * @memberOf fabric.Object.prototype\n         * @return {Boolean} flipY value\n         */\n\n        /**\n         * Sets object's {@link fabric.Object#flipY|flipY} value\n         * @method setFlipY\n         * @memberOf fabric.Object.prototype\n         * @param {Boolean} value flipY value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n\n        /**\n         * Type of an object (rect, circle, path, etc.)\n         * @type String\n         * @default\n         */\n        type:                     'object',\n\n        /**\n         * Horizontal origin of transformation of an object (one of \"left\", \"right\", \"center\")\n         * @type String\n         * @default\n         */\n        originX:                  'left',\n\n        /**\n         * Vertical origin of transformation of an object (one of \"top\", \"bottom\", \"center\")\n         * @type String\n         * @default\n         */\n        originY:                  'top',\n\n        /**\n         * Top position of an object. Note that by default it's relative to object center. You can change this by setting originY={top/center/bottom}\n         * @type Number\n         * @default\n         */\n        top:                      0,\n\n        /**\n         * Left position of an object. Note that by default it's relative to object center. You can change this by setting originX={left/center/right}\n         * @type Number\n         * @default\n         */\n        left:                     0,\n\n        /**\n         * Object width\n         * @type Number\n         * @default\n         */\n        width:                    0,\n\n        /**\n         * Object height\n         * @type Number\n         * @default\n         */\n        height:                   0,\n\n        /**\n         * Object scale factor (horizontal)\n         * @type Number\n         * @default\n         */\n        scaleX:                   1,\n\n        /**\n         * Object scale factor (vertical)\n         * @type Number\n         * @default\n         */\n        scaleY:                   1,\n\n        /**\n         * When true, an object is rendered as flipped horizontally\n         * @type Boolean\n         * @default\n         */\n        flipX:                    false,\n\n        /**\n         * When true, an object is rendered as flipped vertically\n         * @type Boolean\n         * @default\n         */\n        flipY:                    false,\n\n        /**\n         * Opacity of an object\n         * @type Number\n         * @default\n         */\n        opacity:                  1,\n\n        /**\n         * Angle of rotation of an object (in degrees)\n         * @type Number\n         * @default\n         */\n        angle:                    0,\n\n        /**\n         * Size of object's controlling corners (in pixels)\n         * @type Number\n         * @default\n         */\n        cornerSize:               12,\n\n        /**\n         * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)\n         * @type Boolean\n         * @default\n         */\n        transparentCorners:       true,\n\n        /**\n         * Default cursor value used when hovering over this object on canvas\n         * @type String\n         * @default\n         */\n        hoverCursor:              null,\n\n        /**\n         * Padding between object and its controlling borders (in pixels)\n         * @type Number\n         * @default\n         */\n        padding:                  0,\n\n        /**\n         * Color of controlling borders of an object (when it's active)\n         * @type String\n         * @default\n         */\n        borderColor:              'rgba(102,153,255,0.75)',\n\n        /**\n         * Color of controlling corners of an object (when it's active)\n         * @type String\n         * @default\n         */\n        cornerColor:              'rgba(102,153,255,0.5)',\n\n        /**\n         * When true, this object will use center point as the origin of transformation\n         * when being scaled via the controls.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         * @since 1.3.4\n         * @type Boolean\n         * @default\n         */\n        centeredScaling:          false,\n\n        /**\n         * When true, this object will use center point as the origin of transformation\n         * when being rotated via the controls.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         * @since 1.3.4\n         * @type Boolean\n         * @default\n         */\n        centeredRotation:         true,\n\n        /**\n         * Color of object's fill\n         * @type String\n         * @default\n         */\n        fill:                     'rgb(0,0,0)',\n\n        /**\n         * Fill rule used to fill an object\n         * accepted values are nonzero, evenodd\n         * <b>Backwards incompatibility note:</b> This property was used for setting globalCompositeOperation until v1.4.12 (use `fabric.Object#globalCompositeOperation` instead)\n         * @type String\n         * @default\n         */\n        fillRule:                 'nonzero',\n\n        /**\n         * Composite rule used for canvas globalCompositeOperation\n         * @type String\n         * @default\n         */\n        globalCompositeOperation: 'source-over',\n\n        /**\n         * Background color of an object. Only works with text objects at the moment.\n         * @type String\n         * @default\n         */\n        backgroundColor:          '',\n\n        /**\n         * When defined, an object is rendered via stroke and this property specifies its color\n         * @type String\n         * @default\n         */\n        stroke:                   null,\n\n        /**\n         * Width of a stroke used to render this object\n         * @type Number\n         * @default\n         */\n        strokeWidth:              1,\n\n        /**\n         * Array specifying dash pattern of an object's stroke (stroke must be defined)\n         * @type Array\n         */\n        strokeDashArray:          null,\n\n        /**\n         * Line endings style of an object's stroke (one of \"butt\", \"round\", \"square\")\n         * @type String\n         * @default\n         */\n        strokeLineCap:            'butt',\n\n        /**\n         * Corner style of an object's stroke (one of \"bevil\", \"round\", \"miter\")\n         * @type String\n         * @default\n         */\n        strokeLineJoin:           'miter',\n\n        /**\n         * Maximum miter length (used for strokeLineJoin = \"miter\") of an object's stroke\n         * @type Number\n         * @default\n         */\n        strokeMiterLimit:         10,\n\n        /**\n         * Shadow object representing shadow of this shape\n         * @type fabric.Shadow\n         * @default\n         */\n        shadow:                   null,\n\n        /**\n         * Opacity of object's controlling borders when object is active and moving\n         * @type Number\n         * @default\n         */\n        borderOpacityWhenMoving:  0.4,\n\n        /**\n         * Scale factor of object's controlling borders\n         * @type Number\n         * @default\n         */\n        borderScaleFactor:        1,\n\n        /**\n         * Transform matrix (similar to SVG's transform matrix)\n         * @type Array\n         */\n        transformMatrix:          null,\n\n        /**\n         * Minimum allowed scale value of an object\n         * @type Number\n         * @default\n         */\n        minScaleLimit:            0.01,\n\n        /**\n         * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).\n         * But events still fire on it.\n         * @type Boolean\n         * @default\n         */\n        selectable:               true,\n\n        /**\n         * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4\n         * @type Boolean\n         * @default\n         */\n        evented:                  true,\n\n        /**\n         * When set to `false`, an object is not rendered on canvas\n         * @type Boolean\n         * @default\n         */\n        visible:                  true,\n\n        /**\n         * When set to `false`, object's controls are not displayed and can not be used to manipulate object\n         * @type Boolean\n         * @default\n         */\n        hasControls:              true,\n\n        /**\n         * When set to `false`, object's controlling borders are not rendered\n         * @type Boolean\n         * @default\n         */\n        hasBorders:               true,\n\n        /**\n         * When set to `false`, object's controlling rotating point will not be visible or selectable\n         * @type Boolean\n         * @default\n         */\n        hasRotatingPoint:         true,\n\n        /**\n         * Offset for object's controlling rotating point (when enabled via `hasRotatingPoint`)\n         * @type Number\n         * @default\n         */\n        rotatingPointOffset:      40,\n\n        /**\n         * When set to `true`, objects are \"found\" on canvas on per-pixel basis rather than according to bounding box\n         * @type Boolean\n         * @default\n         */\n        perPixelTargetFind:       false,\n\n        /**\n         * When `false`, default object's values are not included in its serialization\n         * @type Boolean\n         * @default\n         */\n        includeDefaultValues:     true,\n\n        /**\n         * Function that determines clipping of an object (context is passed as a first argument)\n         * Note that context origin is at the object's center point (not left/top corner)\n         * @type Function\n         */\n        clipTo:                   null,\n\n        /**\n         * When `true`, object horizontal movement is locked\n         * @type Boolean\n         * @default\n         */\n        lockMovementX:            false,\n\n        /**\n         * When `true`, object vertical movement is locked\n         * @type Boolean\n         * @default\n         */\n        lockMovementY:            false,\n\n        /**\n         * When `true`, object rotation is locked\n         * @type Boolean\n         * @default\n         */\n        lockRotation:             false,\n\n        /**\n         * When `true`, object horizontal scaling is locked\n         * @type Boolean\n         * @default\n         */\n        lockScalingX:             false,\n\n        /**\n         * When `true`, object vertical scaling is locked\n         * @type Boolean\n         * @default\n         */\n        lockScalingY:             false,\n\n        /**\n         * When `true`, object non-uniform scaling is locked\n         * @type Boolean\n         * @default\n         */\n        lockUniScaling:           false,\n\n        /**\n         * When `true`, object cannot be flipped by scaling into negative values\n         * @type Boolean\n         * @default\n         */\n\n        lockScalingFlip:          false,\n        /**\n         * List of properties to consider when checking if state\n         * of an object is changed (fabric.Object#hasStateChanged)\n         * as well as for history (undo/redo) purposes\n         * @type Array\n         */\n        stateProperties:  (\n            'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +\n            'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' +\n            'angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor'\n            ).split(' '),\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         */\n        initialize: function(options) {\n            if (options) {\n                this.setOptions(options);\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Options object\n         */\n        _initGradient: function(options) {\n            if (options.fill && options.fill.colorStops && !(options.fill instanceof fabric.Gradient)) {\n                this.set('fill', new fabric.Gradient(options.fill));\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Options object\n         */\n        _initPattern: function(options) {\n            if (options.fill && options.fill.source && !(options.fill instanceof fabric.Pattern)) {\n                this.set('fill', new fabric.Pattern(options.fill));\n            }\n            if (options.stroke && options.stroke.source && !(options.stroke instanceof fabric.Pattern)) {\n                this.set('stroke', new fabric.Pattern(options.stroke));\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Options object\n         */\n        _initClipping: function(options) {\n            if (!options.clipTo || typeof options.clipTo !== 'string') {\n                return;\n            }\n\n            var functionBody = fabric.util.getFunctionBody(options.clipTo);\n            if (typeof functionBody !== 'undefined') {\n                this.clipTo = new Function('ctx', functionBody);\n            }\n        },\n\n        /**\n         * Sets object's properties from options\n         * @param {Object} [options] Options object\n         */\n        setOptions: function(options) {\n            for (var prop in options) {\n                this.set(prop, options[prop]);\n            }\n            this._initGradient(options);\n            this._initPattern(options);\n            this._initClipping(options);\n        },\n\n        /**\n         * Transforms context when rendering an object\n         * @param {CanvasRenderingContext2D} ctx Context\n         * @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node\n         */\n        transform: function(ctx, fromLeft) {\n            if (this.group) {\n                this.group.transform(ctx, fromLeft);\n            }\n            var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();\n            ctx.translate(center.x, center.y);\n            ctx.rotate(degreesToRadians(this.angle));\n            ctx.scale(\n                    this.scaleX * (this.flipX ? -1 : 1),\n                    this.scaleY * (this.flipY ? -1 : 1)\n            );\n        },\n\n        /**\n         * Returns an object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n\n                object = {\n                    type:                     this.type,\n                    originX:                  this.originX,\n                    originY:                  this.originY,\n                    left:                     toFixed(this.left, NUM_FRACTION_DIGITS),\n                    top:                      toFixed(this.top, NUM_FRACTION_DIGITS),\n                    width:                    toFixed(this.width, NUM_FRACTION_DIGITS),\n                    height:                   toFixed(this.height, NUM_FRACTION_DIGITS),\n                    fill:                     (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,\n                    stroke:                   (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,\n                    strokeWidth:              toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),\n                    strokeDashArray:          this.strokeDashArray,\n                    strokeLineCap:            this.strokeLineCap,\n                    strokeLineJoin:           this.strokeLineJoin,\n                    strokeMiterLimit:         toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),\n                    scaleX:                   toFixed(this.scaleX, NUM_FRACTION_DIGITS),\n                    scaleY:                   toFixed(this.scaleY, NUM_FRACTION_DIGITS),\n                    angle:                    toFixed(this.getAngle(), NUM_FRACTION_DIGITS),\n                    flipX:                    this.flipX,\n                    flipY:                    this.flipY,\n                    opacity:                  toFixed(this.opacity, NUM_FRACTION_DIGITS),\n                    shadow:                   (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow,\n                    visible:                  this.visible,\n                    clipTo:                   this.clipTo && String(this.clipTo),\n                    backgroundColor:          this.backgroundColor,\n                    fillRule:                 this.fillRule,\n                    globalCompositeOperation: this.globalCompositeOperation\n                };\n\n            if (!this.includeDefaultValues) {\n                object = this._removeDefaultValues(object);\n            }\n\n            fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n            return object;\n        },\n\n        /**\n         * Returns (dataless) object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toDatalessObject: function(propertiesToInclude) {\n            // will be overwritten by subclasses\n            return this.toObject(propertiesToInclude);\n        },\n\n        /**\n         * @private\n         * @param {Object} object\n         */\n        _removeDefaultValues: function(object) {\n            var prototype = fabric.util.getKlass(object.type).prototype,\n                stateProperties = prototype.stateProperties;\n\n            stateProperties.forEach(function(prop) {\n                if (object[prop] === prototype[prop]) {\n                    delete object[prop];\n                }\n            });\n\n            return object;\n        },\n\n        /**\n         * Returns a string representation of an instance\n         * @return {String}\n         */\n        toString: function() {\n            return '#<fabric.' + capitalize(this.type) + '>';\n        },\n\n        /**\n         * Basic getter\n         * @param {String} property Property name\n         * @return {Any} value of a property\n         */\n        get: function(property) {\n            return this[property];\n        },\n\n        /**\n         * @private\n         */\n        _setObject: function(obj) {\n            for (var prop in obj) {\n                this._set(prop, obj[prop]);\n            }\n        },\n\n        /**\n         * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.\n         * @param {String|Object} key Property name or object (if object, iterate over the object properties)\n         * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        set: function(key, value) {\n            if (typeof key === 'object') {\n                this._setObject(key);\n            }\n            else {\n                if (typeof value === 'function' && key !== 'clipTo') {\n                    this._set(key, value(this.get(key)));\n                }\n                else {\n                    this._set(key, value);\n                }\n            }\n            return this;\n        },\n\n        /**\n         * @private\n         * @param {String} key\n         * @param {Any} value\n         * @return {fabric.Object} thisArg\n         */\n        _set: function(key, value) {\n            var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY');\n\n            if (shouldConstrainValue) {\n                value = this._constrainScale(value);\n            }\n            if (key === 'scaleX' && value < 0) {\n                this.flipX = !this.flipX;\n                value *= -1;\n            }\n            else if (key === 'scaleY' && value < 0) {\n                this.flipY = !this.flipY;\n                value *= -1;\n            }\n            else if (key === 'width' || key === 'height') {\n                this.minScaleLimit = toFixed(Math.min(0.1, 1/Math.max(this.width, this.height)), 2);\n            }\n            else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) {\n                value = new fabric.Shadow(value);\n            }\n\n            this[key] = value;\n\n            return this;\n        },\n\n        /**\n         * Toggles specified property from `true` to `false` or from `false` to `true`\n         * @param {String} property Property to toggle\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        toggle: function(property) {\n            var value = this.get(property);\n            if (typeof value === 'boolean') {\n                this.set(property, !value);\n            }\n            return this;\n        },\n\n        /**\n         * Sets sourcePath of an object\n         * @param {String} value Value to set sourcePath to\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        setSourcePath: function(value) {\n            this.sourcePath = value;\n            return this;\n        },\n\n        /**\n         * Retrieves viewportTransform from Object's canvas if possible\n         * @method getViewportTransform\n         * @memberOf fabric.Object.prototype\n         * @return {Boolean} flipY value // TODO\n         */\n        getViewportTransform: function() {\n            if (this.canvas && this.canvas.viewportTransform) {\n                return this.canvas.viewportTransform;\n            }\n            return [1, 0, 0, 1, 0, 0];\n        },\n\n        /**\n         * Renders an object on a specified context\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        render: function(ctx, noTransform) {\n            // do not render if width/height are zeros or object is not visible\n            if (this.width === 0 || this.height === 0 || !this.visible) {\n                return;\n            }\n\n            ctx.save();\n\n            //setup fill rule for current object\n            this._setupCompositeOperation(ctx);\n            if (!noTransform) {\n                this.transform(ctx);\n            }\n            this._setStrokeStyles(ctx);\n            this._setFillStyles(ctx);\n            if (this.group && this.group.type === 'path-group') {\n                ctx.translate(-this.group.width/2, -this.group.height/2);\n            }\n            if (this.transformMatrix) {\n                ctx.transform.apply(ctx, this.transformMatrix);\n            }\n            this._setOpacity(ctx);\n            this._setShadow(ctx);\n            this.clipTo && fabric.util.clipContext(this, ctx);\n            this._render(ctx, noTransform);\n            this.clipTo && ctx.restore();\n            this._removeShadow(ctx);\n            this._restoreCompositeOperation(ctx);\n\n            ctx.restore();\n        },\n\n        /* @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _setOpacity: function(ctx) {\n            if (this.group) {\n                this.group._setOpacity(ctx);\n            }\n            ctx.globalAlpha *= this.opacity;\n        },\n\n        _setStrokeStyles: function(ctx) {\n            if (this.stroke) {\n                ctx.lineWidth = this.strokeWidth;\n                ctx.lineCap = this.strokeLineCap;\n                ctx.lineJoin = this.strokeLineJoin;\n                ctx.miterLimit = this.strokeMiterLimit;\n                ctx.strokeStyle = this.stroke.toLive\n                    ? this.stroke.toLive(ctx, this)\n                    : this.stroke;\n            }\n        },\n\n        _setFillStyles: function(ctx) {\n            if (this.fill) {\n                ctx.fillStyle = this.fill.toLive\n                    ? this.fill.toLive(ctx, this)\n                    : this.fill;\n            }\n        },\n\n        /**\n         * Renders controls and borders for the object\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        _renderControls: function(ctx, noTransform) {\n            var vpt = this.getViewportTransform();\n\n            ctx.save();\n            if (this.active && !noTransform) {\n                var center;\n                if (this.group) {\n                    center = fabric.util.transformPoint(this.group.getCenterPoint(), vpt);\n                    ctx.translate(center.x, center.y);\n                    ctx.rotate(degreesToRadians(this.group.angle));\n                }\n                center = fabric.util.transformPoint(this.getCenterPoint(), vpt, null != this.group);\n                if (this.group) {\n                    center.x *= this.group.scaleX;\n                    center.y *= this.group.scaleY;\n                }\n                ctx.translate(center.x, center.y);\n                ctx.rotate(degreesToRadians(this.angle));\n                this.drawBorders(ctx);\n                this.drawControls(ctx);\n            }\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _setShadow: function(ctx) {\n            if (!this.shadow) {\n                return;\n            }\n\n            ctx.shadowColor = this.shadow.color;\n            ctx.shadowBlur = this.shadow.blur;\n            ctx.shadowOffsetX = this.shadow.offsetX;\n            ctx.shadowOffsetY = this.shadow.offsetY;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _removeShadow: function(ctx) {\n            if (!this.shadow) {\n                return;\n            }\n\n            ctx.shadowColor = '';\n            ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderFill: function(ctx) {\n            if (!this.fill) {\n                return;\n            }\n\n            ctx.save();\n            if (this.fill.gradientTransform) {\n                var g = this.fill.gradientTransform;\n                ctx.transform.apply(ctx, g);\n            }\n            if (this.fill.toLive) {\n                ctx.translate(\n                        -this.width / 2 + this.fill.offsetX || 0,\n                        -this.height / 2 + this.fill.offsetY || 0);\n            }\n            if (this.fillRule === 'evenodd') {\n                ctx.fill('evenodd');\n            }\n            else {\n                ctx.fill();\n            }\n            ctx.restore();\n            if (this.shadow && !this.shadow.affectStroke) {\n                this._removeShadow(ctx);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderStroke: function(ctx) {\n            if (!this.stroke || this.strokeWidth === 0) {\n                return;\n            }\n\n            ctx.save();\n            if (this.strokeDashArray) {\n                // Spec requires the concatenation of two copies the dash list when the number of elements is odd\n                if (1 & this.strokeDashArray.length) {\n                    this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);\n                }\n                if (supportsLineDash) {\n                    ctx.setLineDash(this.strokeDashArray);\n                    this._stroke && this._stroke(ctx);\n                }\n                else {\n                    this._renderDashedStroke && this._renderDashedStroke(ctx);\n                }\n                ctx.stroke();\n            }\n            else {\n                if (this.stroke.gradientTransform) {\n                    var g = this.stroke.gradientTransform;\n                    ctx.transform.apply(ctx, g);\n                }\n                this._stroke ? this._stroke(ctx) : ctx.stroke();\n            }\n            this._removeShadow(ctx);\n            ctx.restore();\n        },\n\n        /**\n         * Clones an instance\n         * @param {Function} callback Callback is invoked with a clone as a first argument\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {fabric.Object} clone of an instance\n         */\n        clone: function(callback, propertiesToInclude) {\n            if (this.constructor.fromObject) {\n                return this.constructor.fromObject(this.toObject(propertiesToInclude), callback);\n            }\n            return new fabric.Object(this.toObject(propertiesToInclude));\n        },\n\n        /**\n         * Creates an instance of fabric.Image out of an object\n         * @param {Function} callback callback, invoked with an instance as a first argument\n         * @return {fabric.Object} thisArg\n         */\n        cloneAsImage: function(callback) {\n            var dataUrl = this.toDataURL();\n            fabric.util.loadImage(dataUrl, function(img) {\n                if (callback) {\n                    callback(new fabric.Image(img));\n                }\n            });\n            return this;\n        },\n\n        /**\n         * Converts an object into a data-url-like string\n         * @param {Object} options Options object\n         * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n         * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n         * @param {Number} [options.multiplier=1] Multiplier to scale by\n         * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n         * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n         * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n         * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n         * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n         */\n        toDataURL: function(options) {\n            options || (options = { });\n\n            var el = fabric.util.createCanvasElement(),\n                boundingRect = this.getBoundingRect();\n\n            el.width = boundingRect.width;\n            el.height = boundingRect.height;\n\n            fabric.util.wrapElement(el, 'div');\n            var canvas = new fabric.Canvas(el);\n\n            // to avoid common confusion https://github.com/kangax/fabric.js/issues/806\n            if (options.format === 'jpg') {\n                options.format = 'jpeg';\n            }\n\n            if (options.format === 'jpeg') {\n                canvas.backgroundColor = '#fff';\n            }\n\n            var origParams = {\n                active: this.get('active'),\n                left: this.getLeft(),\n                top: this.getTop()\n            };\n\n            this.set('active', false);\n            this.setPositionByOrigin(new fabric.Point(el.width / 2, el.height / 2), 'center', 'center');\n\n            var originalCanvas = this.canvas;\n            canvas.add(this);\n            var data = canvas.toDataURL(options);\n\n            this.set(origParams).setCoords();\n            this.canvas = originalCanvas;\n\n            canvas.dispose();\n            canvas = null;\n\n            return data;\n        },\n\n        /**\n         * Returns true if specified type is identical to the type of an instance\n         * @param {String} type Type to check against\n         * @return {Boolean}\n         */\n        isType: function(type) {\n            return this.type === type;\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return 0;\n        },\n\n        /**\n         * Returns a JSON representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} JSON\n         */\n        toJSON: function(propertiesToInclude) {\n            // delegate, not alias\n            return this.toObject(propertiesToInclude);\n        },\n\n        /**\n         * Sets gradient (fill or stroke) of an object\n         * <b>Backwards incompatibility note:</b> This method was named \"setGradientFill\" until v1.1.0\n         * @param {String} property Property name 'stroke' or 'fill'\n         * @param {Object} [options] Options object\n         * @param {String} [options.type] Type of gradient 'radial' or 'linear'\n         * @param {Number} [options.x1=0] x-coordinate of start point\n         * @param {Number} [options.y1=0] y-coordinate of start point\n         * @param {Number} [options.x2=0] x-coordinate of end point\n         * @param {Number} [options.y2=0] y-coordinate of end point\n         * @param {Number} [options.r1=0] Radius of start point (only for radial gradients)\n         * @param {Number} [options.r2=0] Radius of end point (only for radial gradients)\n         * @param {Object} [options.colorStops] Color stops object eg. {0: 'ff0000', 1: '000000'}\n         * @return {fabric.Object} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo}\n         * @example <caption>Set linear gradient</caption>\n         * object.setGradient('fill', {\n     *   type: 'linear',\n     *   x1: -object.width / 2,\n     *   y1: 0,\n     *   x2: object.width / 2,\n     *   y2: 0,\n     *   colorStops: {\n     *     0: 'red',\n     *     0.5: '#005555',\n     *     1: 'rgba(0,0,255,0.5)'\n     *   }\n     * });\n         * canvas.renderAll();\n         * @example <caption>Set radial gradient</caption>\n         * object.setGradient('fill', {\n     *   type: 'radial',\n     *   x1: 0,\n     *   y1: 0,\n     *   x2: 0,\n     *   y2: 0,\n     *   r1: object.width / 2,\n     *   r2: 10,\n     *   colorStops: {\n     *     0: 'red',\n     *     0.5: '#005555',\n     *     1: 'rgba(0,0,255,0.5)'\n     *   }\n     * });\n         * canvas.renderAll();\n         */\n        setGradient: function(property, options) {\n            options || (options = { });\n\n            var gradient = { colorStops: [] };\n\n            gradient.type = options.type || (options.r1 || options.r2 ? 'radial' : 'linear');\n            gradient.coords = {\n                x1: options.x1,\n                y1: options.y1,\n                x2: options.x2,\n                y2: options.y2\n            };\n\n            if (options.r1 || options.r2) {\n                gradient.coords.r1 = options.r1;\n                gradient.coords.r2 = options.r2;\n            }\n\n            for (var position in options.colorStops) {\n                var color = new fabric.Color(options.colorStops[position]);\n                gradient.colorStops.push({\n                    offset: position,\n                    color: color.toRgb(),\n                    opacity: color.getAlpha()\n                });\n            }\n\n            return this.set(property, fabric.Gradient.forObject(this, gradient));\n        },\n\n        /**\n         * Sets pattern fill of an object\n         * @param {Object} options Options object\n         * @param {(String|HTMLImageElement)} options.source Pattern source\n         * @param {String} [options.repeat=repeat] Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n         * @param {Number} [options.offsetX=0] Pattern horizontal offset from object's left/top corner\n         * @param {Number} [options.offsetY=0] Pattern vertical offset from object's left/top corner\n         * @return {fabric.Object} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/QT3pa/|jsFiddle demo}\n         * @example <caption>Set pattern</caption>\n         * fabric.util.loadImage('http://fabricjs.com/assets/escheresque_ste.png', function(img) {\n     *   object.setPatternFill({\n     *     source: img,\n     *     repeat: 'repeat'\n     *   });\n     *   canvas.renderAll();\n     * });\n         */\n        setPatternFill: function(options) {\n            return this.set('fill', new fabric.Pattern(options));\n        },\n\n        /**\n         * Sets {@link fabric.Object#shadow|shadow} of an object\n         * @param {Object|String} [options] Options object or string (e.g. \"2px 2px 10px rgba(0,0,0,0.2)\")\n         * @param {String} [options.color=rgb(0,0,0)] Shadow color\n         * @param {Number} [options.blur=0] Shadow blur\n         * @param {Number} [options.offsetX=0] Shadow horizontal offset\n         * @param {Number} [options.offsetY=0] Shadow vertical offset\n         * @return {fabric.Object} thisArg\n         * @chainable\n         * @see {@link http://jsfiddle.net/fabricjs/7gvJG/|jsFiddle demo}\n         * @example <caption>Set shadow with string notation</caption>\n         * object.setShadow('2px 2px 10px rgba(0,0,0,0.2)');\n         * canvas.renderAll();\n         * @example <caption>Set shadow with object notation</caption>\n         * object.setShadow({\n     *   color: 'red',\n     *   blur: 10,\n     *   offsetX: 20,\n     *   offsetY: 20\n     * });\n         * canvas.renderAll();\n         */\n        setShadow: function(options) {\n            return this.set('shadow', options ? new fabric.Shadow(options) : null);\n        },\n\n        /**\n         * Sets \"color\" of an instance (alias of `set('fill', &hellip;)`)\n         * @param {String} color Color value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        setColor: function(color) {\n            this.set('fill', color);\n            return this;\n        },\n\n        /**\n         * Sets \"angle\" of an instance\n         * @param {Number} angle Angle value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        setAngle: function(angle) {\n            var shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation;\n\n            if (shouldCenterOrigin) {\n                this._setOriginToCenter();\n            }\n\n            this.set('angle', angle);\n\n            if (shouldCenterOrigin) {\n                this._resetOrigin();\n            }\n\n            return this;\n        },\n\n        /**\n         * Centers object horizontally on canvas to which it was added last.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        centerH: function () {\n            this.canvas.centerObjectH(this);\n            return this;\n        },\n\n        /**\n         * Centers object vertically on canvas to which it was added last.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        centerV: function () {\n            this.canvas.centerObjectV(this);\n            return this;\n        },\n\n        /**\n         * Centers object vertically and horizontally on canvas to which is was added last\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        center: function () {\n            this.canvas.centerObject(this);\n            return this;\n        },\n\n        /**\n         * Removes object from canvas to which it was added last\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        remove: function() {\n            this.canvas.remove(this);\n            return this;\n        },\n\n        /**\n         * Returns coordinates of a pointer relative to an object\n         * @param {Event} e Event to operate upon\n         * @param {Object} [pointer] Pointer to operate upon (instead of event)\n         * @return {Object} Coordinates of a pointer (x, y)\n         */\n        getLocalPointer: function(e, pointer) {\n            pointer = pointer || this.canvas.getPointer(e);\n            var objectLeftTop = this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top');\n            return {\n                x: pointer.x - objectLeftTop.x,\n                y: pointer.y - objectLeftTop.y\n            };\n        },\n\n        /**\n         * Sets canvas globalCompositeOperation for specific object\n         * custom composition operation for the particular object can be specifed using globalCompositeOperation property\n         * @param {CanvasRenderingContext2D} ctx Rendering canvas context\n         */\n        _setupCompositeOperation: function (ctx) {\n            if (this.globalCompositeOperation) {\n                this._prevGlobalCompositeOperation = ctx.globalCompositeOperation;\n                ctx.globalCompositeOperation = this.globalCompositeOperation;\n            }\n        },\n\n        /**\n         * Restores previously saved canvas globalCompositeOperation after obeject rendering\n         * @param {CanvasRenderingContext2D} ctx Rendering canvas context\n         */\n        _restoreCompositeOperation: function (ctx) {\n            if (this.globalCompositeOperation && this._prevGlobalCompositeOperation) {\n                ctx.globalCompositeOperation = this._prevGlobalCompositeOperation;\n            }\n        }\n    });\n\n    fabric.util.createAccessors(fabric.Object);\n\n    /**\n     * Alias for {@link fabric.Object.prototype.setAngle}\n     * @alias rotate -> setAngle\n     * @memberof fabric.Object\n     */\n    fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle;\n\n    extend(fabric.Object.prototype, fabric.Observable);\n\n    /**\n     * Defines the number of fraction digits to use when serializing object values.\n     * You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.\n     * @static\n     * @memberof fabric.Object\n     * @constant\n     * @type Number\n     */\n    fabric.Object.NUM_FRACTION_DIGITS = 2;\n\n    /**\n     * Unique id used internally when creating SVG elements\n     * @static\n     * @memberof fabric.Object\n     * @type Number\n     */\n    fabric.Object.__uid = 0;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n    var degreesToRadians = fabric.util.degreesToRadians;\n\n    fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n        /**\n         * Translates the coordinates from origin to center coordinates (based on the object's dimensions)\n         * @param {fabric.Point} point The point which corresponds to the originX and originY params\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         * @return {fabric.Point}\n         */\n        translateToCenterPoint: function(point, originX, originY) {\n            var cx = point.x,\n                cy = point.y,\n                strokeWidth = this.stroke ? this.strokeWidth : 0;\n\n            if (originX === 'left') {\n                cx = point.x + (this.getWidth() + strokeWidth * this.scaleX) / 2;\n            }\n            else if (originX === 'right') {\n                cx = point.x - (this.getWidth() + strokeWidth * this.scaleX) / 2;\n            }\n\n            if (originY === 'top') {\n                cy = point.y + (this.getHeight() + strokeWidth * this.scaleY) / 2;\n            }\n            else if (originY === 'bottom') {\n                cy = point.y - (this.getHeight() + strokeWidth * this.scaleY) / 2;\n            }\n\n            // Apply the reverse rotation to the point (it's already scaled properly)\n            return fabric.util.rotatePoint(new fabric.Point(cx, cy), point, degreesToRadians(this.angle));\n        },\n\n        /**\n         * Translates the coordinates from center to origin coordinates (based on the object's dimensions)\n         * @param {fabric.Point} center The point which corresponds to center of the object\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         * @return {fabric.Point}\n         */\n        translateToOriginPoint: function(center, originX, originY) {\n            var x = center.x,\n                y = center.y,\n                strokeWidth = this.stroke ? this.strokeWidth : 0;\n\n            // Get the point coordinates\n            if (originX === 'left') {\n                x = center.x - (this.getWidth() + strokeWidth * this.scaleX) / 2;\n            }\n            else if (originX === 'right') {\n                x = center.x + (this.getWidth() + strokeWidth * this.scaleX) / 2;\n            }\n            if (originY === 'top') {\n                y = center.y - (this.getHeight() + strokeWidth * this.scaleY) / 2;\n            }\n            else if (originY === 'bottom') {\n                y = center.y + (this.getHeight() + strokeWidth * this.scaleY) / 2;\n            }\n\n            // Apply the rotation to the point (it's already scaled properly)\n            return fabric.util.rotatePoint(new fabric.Point(x, y), center, degreesToRadians(this.angle));\n        },\n\n        /**\n         * Returns the real center coordinates of the object\n         * @return {fabric.Point}\n         */\n        getCenterPoint: function() {\n            var leftTop = new fabric.Point(this.left, this.top);\n            return this.translateToCenterPoint(leftTop, this.originX, this.originY);\n        },\n\n        /**\n         * Returns the coordinates of the object based on center coordinates\n         * @param {fabric.Point} point The point which corresponds to the originX and originY params\n         * @return {fabric.Point}\n         */\n        // getOriginPoint: function(center) {\n        //   return this.translateToOriginPoint(center, this.originX, this.originY);\n        // },\n\n        /**\n         * Returns the coordinates of the object as if it has a different origin\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         * @return {fabric.Point}\n         */\n        getPointByOrigin: function(originX, originY) {\n            var center = this.getCenterPoint();\n            return this.translateToOriginPoint(center, originX, originY);\n        },\n\n        /**\n         * Returns the point in local coordinates\n         * @param {fabric.Point} point The point relative to the global coordinate system\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         * @return {fabric.Point}\n         */\n        toLocalPoint: function(point, originX, originY) {\n            var center = this.getCenterPoint(),\n                strokeWidth = this.stroke ? this.strokeWidth : 0,\n                x, y;\n\n            if (originX && originY) {\n                if (originX === 'left') {\n                    x = center.x - (this.getWidth() + strokeWidth * this.scaleX) / 2;\n                }\n                else if (originX === 'right') {\n                    x = center.x + (this.getWidth() + strokeWidth * this.scaleX) / 2;\n                }\n                else {\n                    x = center.x;\n                }\n\n                if (originY === 'top') {\n                    y = center.y - (this.getHeight() + strokeWidth * this.scaleY) / 2;\n                }\n                else if (originY === 'bottom') {\n                    y = center.y + (this.getHeight() + strokeWidth * this.scaleY) / 2;\n                }\n                else {\n                    y = center.y;\n                }\n            }\n            else {\n                x = this.left;\n                y = this.top;\n            }\n\n            return fabric.util.rotatePoint(new fabric.Point(point.x, point.y), center, -degreesToRadians(this.angle))\n                .subtractEquals(new fabric.Point(x, y));\n        },\n\n        /**\n         * Returns the point in global coordinates\n         * @param {fabric.Point} The point relative to the local coordinate system\n         * @return {fabric.Point}\n         */\n        // toGlobalPoint: function(point) {\n        //   return fabric.util.rotatePoint(point, this.getCenterPoint(), degreesToRadians(this.angle)).addEquals(new fabric.Point(this.left, this.top));\n        // },\n\n        /**\n         * Sets the position of the object taking into consideration the object's origin\n         * @param {fabric.Point} pos The new position of the object\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         * @return {void}\n         */\n        setPositionByOrigin: function(pos, originX, originY) {\n            var center = this.translateToCenterPoint(pos, originX, originY),\n                position = this.translateToOriginPoint(center, this.originX, this.originY);\n\n            this.set('left', position.x);\n            this.set('top', position.y);\n        },\n\n        /**\n         * @param {String} to One of 'left', 'center', 'right'\n         */\n        adjustPosition: function(to) {\n            var angle = degreesToRadians(this.angle),\n                hypotHalf = this.getWidth() / 2,\n                xHalf = Math.cos(angle) * hypotHalf,\n                yHalf = Math.sin(angle) * hypotHalf,\n                hypotFull = this.getWidth(),\n                xFull = Math.cos(angle) * hypotFull,\n                yFull = Math.sin(angle) * hypotFull;\n\n            if (this.originX === 'center' && to === 'left' ||\n                this.originX === 'right' && to === 'center') {\n                // move half left\n                this.left -= xHalf;\n                this.top -= yHalf;\n            }\n            else if (this.originX === 'left' && to === 'center' ||\n                this.originX === 'center' && to === 'right') {\n                // move half right\n                this.left += xHalf;\n                this.top += yHalf;\n            }\n            else if (this.originX === 'left' && to === 'right') {\n                // move full right\n                this.left += xFull;\n                this.top += yFull;\n            }\n            else if (this.originX === 'right' && to === 'left') {\n                // move full left\n                this.left -= xFull;\n                this.top -= yFull;\n            }\n\n            this.setCoords();\n            this.originX = to;\n        },\n\n        /**\n         * Sets the origin/position of the object to it's center point\n         * @private\n         * @return {void}\n         */\n        _setOriginToCenter: function() {\n            this._originalOriginX = this.originX;\n            this._originalOriginY = this.originY;\n\n            var center = this.getCenterPoint();\n\n            this.originX = 'center';\n            this.originY = 'center';\n\n            this.left = center.x;\n            this.top = center.y;\n        },\n\n        /**\n         * Resets the origin/position of the object to it's original origin\n         * @private\n         * @return {void}\n         */\n        _resetOrigin: function() {\n            var originPoint = this.translateToOriginPoint(\n                this.getCenterPoint(),\n                this._originalOriginX,\n                this._originalOriginY);\n\n            this.originX = this._originalOriginX;\n            this.originY = this._originalOriginY;\n\n            this.left = originPoint.x;\n            this.top = originPoint.y;\n\n            this._originalOriginX = null;\n            this._originalOriginY = null;\n        },\n\n        /**\n         * @private\n         */\n        _getLeftTopCoords: function() {\n            return this.translateToOriginPoint(this.getCenterPoint(), 'left', 'center');\n        }\n    });\n\n})();\n\n\n(function() {\n\n    var degreesToRadians = fabric.util.degreesToRadians;\n\n    fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n        /**\n         * Object containing coordinates of object's controls\n         * @type Object\n         * @default\n         */\n        oCoords: null,\n\n        /**\n         * Checks if object intersects with an area formed by 2 points\n         * @param {Object} pointTL top-left point of area\n         * @param {Object} pointBR bottom-right point of area\n         * @return {Boolean} true if object intersects with an area formed by 2 points\n         */\n        intersectsWithRect: function(pointTL, pointBR) {\n            var oCoords = this.oCoords,\n                tl = new fabric.Point(oCoords.tl.x, oCoords.tl.y),\n                tr = new fabric.Point(oCoords.tr.x, oCoords.tr.y),\n                bl = new fabric.Point(oCoords.bl.x, oCoords.bl.y),\n                br = new fabric.Point(oCoords.br.x, oCoords.br.y),\n                intersection = fabric.Intersection.intersectPolygonRectangle(\n                    [tl, tr, br, bl],\n                    pointTL,\n                    pointBR\n                );\n            return intersection.status === 'Intersection';\n        },\n\n        /**\n         * Checks if object intersects with another object\n         * @param {Object} other Object to test\n         * @return {Boolean} true if object intersects with another object\n         */\n        intersectsWithObject: function(other) {\n            // extracts coords\n            function getCoords(oCoords) {\n                return {\n                    tl: new fabric.Point(oCoords.tl.x, oCoords.tl.y),\n                    tr: new fabric.Point(oCoords.tr.x, oCoords.tr.y),\n                    bl: new fabric.Point(oCoords.bl.x, oCoords.bl.y),\n                    br: new fabric.Point(oCoords.br.x, oCoords.br.y)\n                };\n            }\n            var thisCoords = getCoords(this.oCoords),\n                otherCoords = getCoords(other.oCoords),\n                intersection = fabric.Intersection.intersectPolygonPolygon(\n                    [thisCoords.tl, thisCoords.tr, thisCoords.br, thisCoords.bl],\n                    [otherCoords.tl, otherCoords.tr, otherCoords.br, otherCoords.bl]\n                );\n\n            return intersection.status === 'Intersection';\n        },\n\n        /**\n         * Checks if object is fully contained within area of another object\n         * @param {Object} other Object to test\n         * @return {Boolean} true if object is fully contained within area of another object\n         */\n        isContainedWithinObject: function(other) {\n            var boundingRect = other.getBoundingRect(),\n                point1 = new fabric.Point(boundingRect.left, boundingRect.top),\n                point2 = new fabric.Point(boundingRect.left + boundingRect.width, boundingRect.top + boundingRect.height);\n\n            return this.isContainedWithinRect(point1, point2);\n        },\n\n        /**\n         * Checks if object is fully contained within area formed by 2 points\n         * @param {Object} pointTL top-left point of area\n         * @param {Object} pointBR bottom-right point of area\n         * @return {Boolean} true if object is fully contained within area formed by 2 points\n         */\n        isContainedWithinRect: function(pointTL, pointBR) {\n            var boundingRect = this.getBoundingRect();\n\n            return (\n                boundingRect.left >= pointTL.x &&\n                boundingRect.left + boundingRect.width <= pointBR.x &&\n                boundingRect.top >= pointTL.y &&\n                boundingRect.top + boundingRect.height <= pointBR.y\n                );\n        },\n\n        /**\n         * Checks if point is inside the object\n         * @param {fabric.Point} point Point to check against\n         * @return {Boolean} true if point is inside the object\n         */\n        containsPoint: function(point) {\n            var lines = this._getImageLines(this.oCoords),\n                xPoints = this._findCrossPoints(point, lines);\n\n            // if xPoints is odd then point is inside the object\n            return (xPoints !== 0 && xPoints % 2 === 1);\n        },\n\n        /**\n         * Method that returns an object with the object edges in it, given the coordinates of the corners\n         * @private\n         * @param {Object} oCoords Coordinates of the object corners\n         */\n        _getImageLines: function(oCoords) {\n            return {\n                topline: {\n                    o: oCoords.tl,\n                    d: oCoords.tr\n                },\n                rightline: {\n                    o: oCoords.tr,\n                    d: oCoords.br\n                },\n                bottomline: {\n                    o: oCoords.br,\n                    d: oCoords.bl\n                },\n                leftline: {\n                    o: oCoords.bl,\n                    d: oCoords.tl\n                }\n            };\n        },\n\n        /**\n         * Helper method to determine how many cross points are between the 4 object edges\n         * and the horizontal line determined by a point on canvas\n         * @private\n         * @param {fabric.Point} point Point to check\n         * @param {Object} oCoords Coordinates of the object being evaluated\n         */\n        _findCrossPoints: function(point, oCoords) {\n            var b1, b2, a1, a2, xi, yi,\n                xcount = 0,\n                iLine;\n\n            for (var lineKey in oCoords) {\n                iLine = oCoords[lineKey];\n                // optimisation 1: line below point. no cross\n                if ((iLine.o.y < point.y) && (iLine.d.y < point.y)) {\n                    continue;\n                }\n                // optimisation 2: line above point. no cross\n                if ((iLine.o.y >= point.y) && (iLine.d.y >= point.y)) {\n                    continue;\n                }\n                // optimisation 3: vertical line case\n                if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) {\n                    xi = iLine.o.x;\n                    yi = point.y;\n                }\n                // calculate the intersection point\n                else {\n                    b1 = 0;\n                    b2 = (iLine.d.y - iLine.o.y) / (iLine.d.x - iLine.o.x);\n                    a1 = point.y - b1 * point.x;\n                    a2 = iLine.o.y - b2 * iLine.o.x;\n\n                    xi = - (a1 - a2) / (b1 - b2);\n                    yi = a1 + b1 * xi;\n                }\n                // dont count xi < point.x cases\n                if (xi >= point.x) {\n                    xcount += 1;\n                }\n                // optimisation 4: specific for square images\n                if (xcount === 2) {\n                    break;\n                }\n            }\n            return xcount;\n        },\n\n        /**\n         * Returns width of an object's bounding rectangle\n         * @deprecated since 1.0.4\n         * @return {Number} width value\n         */\n        getBoundingRectWidth: function() {\n            return this.getBoundingRect().width;\n        },\n\n        /**\n         * Returns height of an object's bounding rectangle\n         * @deprecated since 1.0.4\n         * @return {Number} height value\n         */\n        getBoundingRectHeight: function() {\n            return this.getBoundingRect().height;\n        },\n\n        /**\n         * Returns coordinates of object's bounding rectangle (left, top, width, height)\n         * @return {Object} Object with left, top, width, height properties\n         */\n        getBoundingRect: function() {\n            this.oCoords || this.setCoords();\n\n            var xCoords = [this.oCoords.tl.x, this.oCoords.tr.x, this.oCoords.br.x, this.oCoords.bl.x],\n                minX = fabric.util.array.min(xCoords),\n                maxX = fabric.util.array.max(xCoords),\n                width = Math.abs(minX - maxX),\n\n                yCoords = [this.oCoords.tl.y, this.oCoords.tr.y, this.oCoords.br.y, this.oCoords.bl.y],\n                minY = fabric.util.array.min(yCoords),\n                maxY = fabric.util.array.max(yCoords),\n                height = Math.abs(minY - maxY);\n\n            return {\n                left: minX,\n                top: minY,\n                width: width,\n                height: height\n            };\n        },\n\n        /**\n         * Returns width of an object\n         * @return {Number} width value\n         */\n        getWidth: function() {\n            return this.width * this.scaleX;\n        },\n\n        /**\n         * Returns height of an object\n         * @return {Number} height value\n         */\n        getHeight: function() {\n            return this.height * this.scaleY;\n        },\n\n        /**\n         * Makes sure the scale is valid and modifies it if necessary\n         * @private\n         * @param {Number} value\n         * @return {Number}\n         */\n        _constrainScale: function(value) {\n            if (Math.abs(value) < this.minScaleLimit) {\n                if (value < 0) {\n                    return -this.minScaleLimit;\n                }\n                else {\n                    return this.minScaleLimit;\n                }\n            }\n            return value;\n        },\n\n        /**\n         * Scales an object (equally by x and y)\n         * @param {Number} value Scale factor\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        scale: function(value) {\n            value = this._constrainScale(value);\n\n            if (value < 0) {\n                this.flipX = !this.flipX;\n                this.flipY = !this.flipY;\n                value *= -1;\n            }\n\n            this.scaleX = value;\n            this.scaleY = value;\n            this.setCoords();\n            return this;\n        },\n\n        /**\n         * Scales an object to a given width, with respect to bounding box (scaling by x/y equally)\n         * @param {Number} value New width value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        scaleToWidth: function(value) {\n            // adjust to bounding rect factor so that rotated shapes would fit as well\n            var boundingRectFactor = this.getBoundingRectWidth() / this.getWidth();\n            return this.scale(value / this.width / boundingRectFactor);\n        },\n\n        /**\n         * Scales an object to a given height, with respect to bounding box (scaling by x/y equally)\n         * @param {Number} value New height value\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        scaleToHeight: function(value) {\n            // adjust to bounding rect factor so that rotated shapes would fit as well\n            var boundingRectFactor = this.getBoundingRectHeight() / this.getHeight();\n            return this.scale(value / this.height / boundingRectFactor);\n        },\n\n        /**\n         * Sets corner position coordinates based on current angle, width and height\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        setCoords: function() {\n            var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,\n                theta = degreesToRadians(this.angle),\n                vpt = this.getViewportTransform(),\n                f = function (p) {\n                    return fabric.util.transformPoint(p, vpt);\n                },\n                w = this.width,\n                h = this.height,\n                capped = this.strokeLineCap === 'round' || this.strokeLineCap === 'square',\n                vLine = this.type === 'line' && this.width === 1,\n                hLine = this.type === 'line' && this.height === 1,\n                strokeW = (capped && hLine) || this.type !== 'line',\n                strokeH = (capped && vLine) || this.type !== 'line';\n\n            if (vLine) {\n                w = strokeWidth;\n            }\n            else if (hLine) {\n                h = strokeWidth;\n            }\n            if (strokeW) {\n                w += strokeWidth;\n            }\n            if (strokeH) {\n                h += strokeWidth;\n            }\n            this.currentWidth = w * this.scaleX;\n            this.currentHeight = h * this.scaleY;\n\n            // If width is negative, make postive. Fixes path selection issue\n            if (this.currentWidth < 0) {\n                this.currentWidth = Math.abs(this.currentWidth);\n            }\n\n            var _hypotenuse = Math.sqrt(\n                        Math.pow(this.currentWidth / 2, 2) +\n                        Math.pow(this.currentHeight / 2, 2)),\n\n                _angle = Math.atan(\n                    isFinite(this.currentHeight / this.currentWidth)\n                        ? this.currentHeight / this.currentWidth\n                        : 0),\n\n            // offset added for rotate and scale actions\n                offsetX = Math.cos(_angle + theta) * _hypotenuse,\n                offsetY = Math.sin(_angle + theta) * _hypotenuse,\n                sinTh = Math.sin(theta),\n                cosTh = Math.cos(theta),\n                coords = this.getCenterPoint(),\n                wh = new fabric.Point(this.currentWidth, this.currentHeight),\n                _tl =   new fabric.Point(coords.x - offsetX, coords.y - offsetY),\n                _tr =   new fabric.Point(_tl.x + (wh.x * cosTh),   _tl.y + (wh.x * sinTh)),\n                _bl =   new fabric.Point(_tl.x - (wh.y * sinTh),   _tl.y + (wh.y * cosTh)),\n                _mt =   new fabric.Point(_tl.x + (wh.x/2 * cosTh), _tl.y + (wh.x/2 * sinTh)),\n                tl  = f(_tl),\n                tr  = f(_tr),\n                br  = f(new fabric.Point(_tr.x - (wh.y * sinTh),   _tr.y + (wh.y * cosTh))),\n                bl  = f(_bl),\n                ml  = f(new fabric.Point(_tl.x - (wh.y/2 * sinTh), _tl.y + (wh.y/2 * cosTh))),\n                mt  = f(_mt),\n                mr  = f(new fabric.Point(_tr.x - (wh.y/2 * sinTh), _tr.y + (wh.y/2 * cosTh))),\n                mb  = f(new fabric.Point(_bl.x + (wh.x/2 * cosTh), _bl.y + (wh.x/2 * sinTh))),\n                mtr = f(new fabric.Point(_mt.x, _mt.y)),\n\n            // padding\n                padX = Math.cos(_angle + theta) * this.padding * Math.sqrt(2),\n                padY = Math.sin(_angle + theta) * this.padding * Math.sqrt(2);\n\n            tl = tl.add(new fabric.Point(-padX, -padY));\n            tr = tr.add(new fabric.Point(padY, -padX));\n            br = br.add(new fabric.Point(padX, padY));\n            bl = bl.add(new fabric.Point(-padY, padX));\n            ml = ml.add(new fabric.Point((-padX - padY) / 2, (-padY + padX) / 2));\n            mt = mt.add(new fabric.Point((padY - padX) / 2, -(padY + padX) / 2));\n            mr = mr.add(new fabric.Point((padY + padX) / 2, (padY - padX) / 2));\n            mb = mb.add(new fabric.Point((padX - padY) / 2, (padX + padY) / 2));\n            mtr = mtr.add(new fabric.Point((padY - padX) / 2, -(padY + padX) / 2));\n\n            // debugging\n\n            // setTimeout(function() {\n            //   canvas.contextTop.fillStyle = 'green';\n            //   canvas.contextTop.fillRect(mb.x, mb.y, 3, 3);\n            //   canvas.contextTop.fillRect(bl.x, bl.y, 3, 3);\n            //   canvas.contextTop.fillRect(br.x, br.y, 3, 3);\n            //   canvas.contextTop.fillRect(tl.x, tl.y, 3, 3);\n            //   canvas.contextTop.fillRect(tr.x, tr.y, 3, 3);\n            //   canvas.contextTop.fillRect(ml.x, ml.y, 3, 3);\n            //   canvas.contextTop.fillRect(mr.x, mr.y, 3, 3);\n            //   canvas.contextTop.fillRect(mt.x, mt.y, 3, 3);\n            // }, 50);\n\n            this.oCoords = {\n                // corners\n                tl: tl, tr: tr, br: br, bl: bl,\n                // middle\n                ml: ml, mt: mt, mr: mr, mb: mb,\n                // rotating point\n                mtr: mtr\n            };\n\n            // set coordinates of the draggable boxes in the corners used to scale/rotate the image\n            this._setCornerCoords && this._setCornerCoords();\n\n            return this;\n        }\n    });\n})();\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Moves an object to the bottom of the stack of drawn objects\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    sendToBack: function() {\n        if (this.group) {\n            fabric.StaticCanvas.prototype.sendToBack.call(this.group, this);\n        }\n        else {\n            this.canvas.sendToBack(this);\n        }\n        return this;\n    },\n\n    /**\n     * Moves an object to the top of the stack of drawn objects\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    bringToFront: function() {\n        if (this.group) {\n            fabric.StaticCanvas.prototype.bringToFront.call(this.group, this);\n        }\n        else {\n            this.canvas.bringToFront(this);\n        }\n        return this;\n    },\n\n    /**\n     * Moves an object down in stack of drawn objects\n     * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    sendBackwards: function(intersecting) {\n        if (this.group) {\n            fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting);\n        }\n        else {\n            this.canvas.sendBackwards(this, intersecting);\n        }\n        return this;\n    },\n\n    /**\n     * Moves an object up in stack of drawn objects\n     * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    bringForward: function(intersecting) {\n        if (this.group) {\n            fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting);\n        }\n        else {\n            this.canvas.bringForward(this, intersecting);\n        }\n        return this;\n    },\n\n    /**\n     * Moves an object to specified level in stack of drawn objects\n     * @param {Number} index New position of object\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    moveTo: function(index) {\n        if (this.group) {\n            fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index);\n        }\n        else {\n            this.canvas.moveTo(this, index);\n        }\n        return this;\n    }\n});\n\n\n/* _TO_SVG_START_ */\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Returns styles-string for svg-export\n     * @return {String}\n     */\n    getSvgStyles: function() {\n\n        var fill = this.fill\n                ? (this.fill.toLive ? 'url(#SVGID_' + this.fill.id + ')' : this.fill)\n                : 'none',\n            fillRule = this.fillRule,\n            stroke = this.stroke\n                ? (this.stroke.toLive ? 'url(#SVGID_' + this.stroke.id + ')' : this.stroke)\n                : 'none',\n\n            strokeWidth = this.strokeWidth ? this.strokeWidth : '0',\n            strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : '',\n            strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',\n            strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',\n            strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',\n            opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',\n\n            visibility = this.visible ? '' : ' visibility: hidden;',\n            filter = this.shadow && this.type !== 'text' ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';\n\n        return [\n            'stroke: ', stroke, '; ',\n            'stroke-width: ', strokeWidth, '; ',\n            'stroke-dasharray: ', strokeDashArray, '; ',\n            'stroke-linecap: ', strokeLineCap, '; ',\n            'stroke-linejoin: ', strokeLineJoin, '; ',\n            'stroke-miterlimit: ', strokeMiterLimit, '; ',\n            'fill: ', fill, '; ',\n            'fill-rule: ', fillRule, '; ',\n            'opacity: ', opacity, ';',\n            filter,\n            visibility\n        ].join('');\n    },\n\n    /**\n     * Returns transform-string for svg-export\n     * @return {String}\n     */\n    getSvgTransform: function() {\n        if (this.group && this.group.type === 'path-group') {\n            return '';\n        }\n        var toFixed = fabric.util.toFixed,\n            angle = this.getAngle(),\n            vpt = !this.canvas || this.canvas.svgViewportTransformation ? this.getViewportTransform() : [1, 0, 0, 1, 0, 0],\n            center = fabric.util.transformPoint(this.getCenterPoint(), vpt),\n\n            NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n\n            translatePart = this.type === 'path-group' ? '' : 'translate(' +\n                toFixed(center.x, NUM_FRACTION_DIGITS) +\n                ' ' +\n                toFixed(center.y, NUM_FRACTION_DIGITS) +\n                ')',\n\n            anglePart = angle !== 0\n                ? (' rotate(' + toFixed(angle, NUM_FRACTION_DIGITS) + ')')\n                : '',\n\n            scalePart = (this.scaleX === 1 && this.scaleY === 1 && vpt[0] === 1 && vpt[3] === 1)\n                ? '' :\n                (' scale(' +\n                    toFixed(this.scaleX * vpt[0], NUM_FRACTION_DIGITS) +\n                    ' ' +\n                    toFixed(this.scaleY * vpt[3], NUM_FRACTION_DIGITS) +\n                    ')'),\n\n            addTranslateX = this.type === 'path-group' ? this.width * vpt[0] : 0,\n\n            flipXPart = this.flipX ? ' matrix(-1 0 0 1 ' + addTranslateX + ' 0) ' : '',\n\n            addTranslateY = this.type === 'path-group' ? this.height * vpt[3] : 0,\n\n            flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : '';\n\n        return [\n            translatePart, anglePart, scalePart, flipXPart, flipYPart\n        ].join('');\n    },\n\n    /**\n     * Returns transform-string for svg-export from the transform matrix of single elements\n     * @return {String}\n     */\n    getSvgTransformMatrix: function() {\n        return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ')' : '';\n    },\n\n    /**\n     * @private\n     */\n    _createBaseSVGMarkup: function() {\n        var markup = [ ];\n\n        if (this.fill && this.fill.toLive) {\n            markup.push(this.fill.toSVG(this, false));\n        }\n        if (this.stroke && this.stroke.toLive) {\n            markup.push(this.stroke.toSVG(this, false));\n        }\n        if (this.shadow) {\n            markup.push(this.shadow.toSVG(this));\n        }\n        return markup;\n    }\n});\n/* _TO_SVG_END_ */\n\n\n/*\n Depends on `stateProperties`\n */\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Returns true if object state (one of its state properties) was changed\n     * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called\n     */\n    hasStateChanged: function() {\n        return this.stateProperties.some(function(prop) {\n            return this.get(prop) !== this.originalState[prop];\n        }, this);\n    },\n\n    /**\n     * Saves state of an object\n     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n     * @return {fabric.Object} thisArg\n     */\n    saveState: function(options) {\n        this.stateProperties.forEach(function(prop) {\n            this.originalState[prop] = this.get(prop);\n        }, this);\n\n        if (options && options.stateProperties) {\n            options.stateProperties.forEach(function(prop) {\n                this.originalState[prop] = this.get(prop);\n            }, this);\n        }\n\n        return this;\n    },\n\n    /**\n     * Setups state of an object\n     * @return {fabric.Object} thisArg\n     */\n    setupState: function() {\n        this.originalState = { };\n        this.saveState();\n\n        return this;\n    }\n});\n\n\n(function() {\n\n    var degreesToRadians = fabric.util.degreesToRadians,\n    //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n        isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; };\n    //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n    fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n        /**\n         * The object interactivity controls.\n         * @private\n         */\n        _controlsVisibility: null,\n\n        /**\n         * Determines which corner has been clicked\n         * @private\n         * @param {Object} pointer The pointer indicating the mouse position\n         * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found\n         */\n        _findTargetCorner: function(pointer) {\n            if (!this.hasControls || !this.active) {\n                return false;\n            }\n\n            var ex = pointer.x,\n                ey = pointer.y,\n                xPoints,\n                lines;\n\n            for (var i in this.oCoords) {\n\n                if (!this.isControlVisible(i)) {\n                    continue;\n                }\n\n                if (i === 'mtr' && !this.hasRotatingPoint) {\n                    continue;\n                }\n\n                if (this.get('lockUniScaling') &&\n                    (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {\n                    continue;\n                }\n\n                lines = this._getImageLines(this.oCoords[i].corner);\n\n                // debugging\n\n                // canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);\n                // canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);\n\n                // canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);\n                // canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);\n\n                // canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);\n                // canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);\n\n                // canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);\n                // canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);\n\n                xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);\n                if (xPoints !== 0 && xPoints % 2 === 1) {\n                    this.__corner = i;\n                    return i;\n                }\n            }\n            return false;\n        },\n\n        /**\n         * Sets the coordinates of the draggable boxes in the corners of\n         * the image used to scale/rotate it.\n         * @private\n         */\n        _setCornerCoords: function() {\n            var coords = this.oCoords,\n                theta = degreesToRadians(this.angle),\n                newTheta = degreesToRadians(45 - this.angle),\n                cornerHypotenuse = Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2,\n                cosHalfOffset = cornerHypotenuse * Math.cos(newTheta),\n                sinHalfOffset = cornerHypotenuse * Math.sin(newTheta),\n                sinTh = Math.sin(theta),\n                cosTh = Math.cos(theta);\n\n            coords.tl.corner = {\n                tl: {\n                    x: coords.tl.x - sinHalfOffset,\n                    y: coords.tl.y - cosHalfOffset\n                },\n                tr: {\n                    x: coords.tl.x + cosHalfOffset,\n                    y: coords.tl.y - sinHalfOffset\n                },\n                bl: {\n                    x: coords.tl.x - cosHalfOffset,\n                    y: coords.tl.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.tl.x + sinHalfOffset,\n                    y: coords.tl.y + cosHalfOffset\n                }\n            };\n\n            coords.tr.corner = {\n                tl: {\n                    x: coords.tr.x - sinHalfOffset,\n                    y: coords.tr.y - cosHalfOffset\n                },\n                tr: {\n                    x: coords.tr.x + cosHalfOffset,\n                    y: coords.tr.y - sinHalfOffset\n                },\n                br: {\n                    x: coords.tr.x + sinHalfOffset,\n                    y: coords.tr.y + cosHalfOffset\n                },\n                bl: {\n                    x: coords.tr.x - cosHalfOffset,\n                    y: coords.tr.y + sinHalfOffset\n                }\n            };\n\n            coords.bl.corner = {\n                tl: {\n                    x: coords.bl.x - sinHalfOffset,\n                    y: coords.bl.y - cosHalfOffset\n                },\n                bl: {\n                    x: coords.bl.x - cosHalfOffset,\n                    y: coords.bl.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.bl.x + sinHalfOffset,\n                    y: coords.bl.y + cosHalfOffset\n                },\n                tr: {\n                    x: coords.bl.x + cosHalfOffset,\n                    y: coords.bl.y - sinHalfOffset\n                }\n            };\n\n            coords.br.corner = {\n                tr: {\n                    x: coords.br.x + cosHalfOffset,\n                    y: coords.br.y - sinHalfOffset\n                },\n                bl: {\n                    x: coords.br.x - cosHalfOffset,\n                    y: coords.br.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.br.x + sinHalfOffset,\n                    y: coords.br.y + cosHalfOffset\n                },\n                tl: {\n                    x: coords.br.x - sinHalfOffset,\n                    y: coords.br.y - cosHalfOffset\n                }\n            };\n\n            coords.ml.corner = {\n                tl: {\n                    x: coords.ml.x - sinHalfOffset,\n                    y: coords.ml.y - cosHalfOffset\n                },\n                tr: {\n                    x: coords.ml.x + cosHalfOffset,\n                    y: coords.ml.y - sinHalfOffset\n                },\n                bl: {\n                    x: coords.ml.x - cosHalfOffset,\n                    y: coords.ml.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.ml.x + sinHalfOffset,\n                    y: coords.ml.y + cosHalfOffset\n                }\n            };\n\n            coords.mt.corner = {\n                tl: {\n                    x: coords.mt.x - sinHalfOffset,\n                    y: coords.mt.y - cosHalfOffset\n                },\n                tr: {\n                    x: coords.mt.x + cosHalfOffset,\n                    y: coords.mt.y - sinHalfOffset\n                },\n                bl: {\n                    x: coords.mt.x - cosHalfOffset,\n                    y: coords.mt.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.mt.x + sinHalfOffset,\n                    y: coords.mt.y + cosHalfOffset\n                }\n            };\n\n            coords.mr.corner = {\n                tl: {\n                    x: coords.mr.x - sinHalfOffset,\n                    y: coords.mr.y - cosHalfOffset\n                },\n                tr: {\n                    x: coords.mr.x + cosHalfOffset,\n                    y: coords.mr.y - sinHalfOffset\n                },\n                bl: {\n                    x: coords.mr.x - cosHalfOffset,\n                    y: coords.mr.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.mr.x + sinHalfOffset,\n                    y: coords.mr.y + cosHalfOffset\n                }\n            };\n\n            coords.mb.corner = {\n                tl: {\n                    x: coords.mb.x - sinHalfOffset,\n                    y: coords.mb.y - cosHalfOffset\n                },\n                tr: {\n                    x: coords.mb.x + cosHalfOffset,\n                    y: coords.mb.y - sinHalfOffset\n                },\n                bl: {\n                    x: coords.mb.x - cosHalfOffset,\n                    y: coords.mb.y + sinHalfOffset\n                },\n                br: {\n                    x: coords.mb.x + sinHalfOffset,\n                    y: coords.mb.y + cosHalfOffset\n                }\n            };\n\n            coords.mtr.corner = {\n                tl: {\n                    x: coords.mtr.x - sinHalfOffset + (sinTh * this.rotatingPointOffset),\n                    y: coords.mtr.y - cosHalfOffset - (cosTh * this.rotatingPointOffset)\n                },\n                tr: {\n                    x: coords.mtr.x + cosHalfOffset + (sinTh * this.rotatingPointOffset),\n                    y: coords.mtr.y - sinHalfOffset - (cosTh * this.rotatingPointOffset)\n                },\n                bl: {\n                    x: coords.mtr.x - cosHalfOffset + (sinTh * this.rotatingPointOffset),\n                    y: coords.mtr.y + sinHalfOffset - (cosTh * this.rotatingPointOffset)\n                },\n                br: {\n                    x: coords.mtr.x + sinHalfOffset + (sinTh * this.rotatingPointOffset),\n                    y: coords.mtr.y + cosHalfOffset - (cosTh * this.rotatingPointOffset)\n                }\n            };\n        },\n        /**\n         * Draws borders of an object's bounding box.\n         * Requires public properties: width, height\n         * Requires public options: padding, borderColor\n         * @param {CanvasRenderingContext2D} ctx Context to draw on\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        drawBorders: function(ctx) {\n            if (!this.hasBorders) {\n                return this;\n            }\n\n            var padding = this.padding,\n                padding2 = padding * 2,\n                vpt = this.getViewportTransform();\n\n            ctx.save();\n\n            ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n            ctx.strokeStyle = this.borderColor;\n\n            var scaleX = 1 / this._constrainScale(this.scaleX),\n                scaleY = 1 / this._constrainScale(this.scaleY);\n\n            ctx.lineWidth = 1 / this.borderScaleFactor;\n\n            var w = this.getWidth(),\n                h = this.getHeight(),\n                strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,\n                capped = this.strokeLineCap === 'round' || this.strokeLineCap === 'square',\n                vLine = this.type === 'line' && this.width === 1,\n                hLine = this.type === 'line' && this.height === 1,\n                strokeW = (capped && hLine) || this.type !== 'line',\n                strokeH = (capped && vLine) || this.type !== 'line';\n            if (vLine) {\n                w = strokeWidth / scaleX;\n            }\n            else if (hLine) {\n                h = strokeWidth / scaleY;\n            }\n            if (strokeW) {\n                w += strokeWidth / scaleX;\n            }\n            if (strokeH) {\n                h += strokeWidth / scaleY;\n            }\n            var wh = fabric.util.transformPoint(new fabric.Point(w, h), vpt, true),\n                width = wh.x,\n                height = wh.y;\n            if (this.group) {\n                width = width * this.group.scaleX;\n                height = height * this.group.scaleY;\n            }\n\n            ctx.strokeRect(\n                    ~~(-(width / 2) - padding) - 0.5, // offset needed to make lines look sharper\n                    ~~(-(height / 2) - padding) - 0.5,\n                    ~~(width + padding2) + 1, // double offset needed to make lines look sharper\n                    ~~(height + padding2) + 1\n            );\n\n            if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) {\n\n                var rotateHeight = ( -height - (padding * 2)) / 2;\n\n                ctx.beginPath();\n                ctx.moveTo(0, rotateHeight);\n                ctx.lineTo(0, rotateHeight - this.rotatingPointOffset);\n                ctx.closePath();\n                ctx.stroke();\n            }\n\n            ctx.restore();\n            return this;\n        },\n\n        /**\n         * Draws corners of an object's bounding box.\n         * Requires public properties: width, height\n         * Requires public options: cornerSize, padding\n         * @param {CanvasRenderingContext2D} ctx Context to draw on\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        drawControls: function(ctx) {\n            if (!this.hasControls) {\n                return this;\n            }\n\n            var size = this.cornerSize,\n                size2 = size / 2,\n                vpt = this.getViewportTransform(),\n                strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,\n                w = this.width,\n                h = this.height,\n                capped = this.strokeLineCap === 'round' || this.strokeLineCap === 'square',\n                vLine = this.type === 'line' && this.width === 1,\n                hLine = this.type === 'line' && this.height === 1,\n                strokeW = (capped && hLine) || this.type !== 'line',\n                strokeH = (capped && vLine) || this.type !== 'line';\n\n            if (vLine) {\n                w = strokeWidth;\n            }\n            else if (hLine) {\n                h = strokeWidth;\n            }\n            if (strokeW) {\n                w += strokeWidth;\n            }\n            if (strokeH) {\n                h += strokeWidth;\n            }\n            w *= this.scaleX;\n            h *= this.scaleY;\n\n            var wh = fabric.util.transformPoint(new fabric.Point(w, h), vpt, true),\n                width = wh.x,\n                height = wh.y,\n                left = -(width / 2),\n                top = -(height / 2),\n                padding = this.padding,\n                scaleOffset = size2,\n                scaleOffsetSize = size2 - size,\n                methodName = this.transparentCorners ? 'strokeRect' : 'fillRect';\n\n            ctx.save();\n\n            ctx.lineWidth = 1;\n\n            ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n            ctx.strokeStyle = ctx.fillStyle = this.cornerColor;\n\n            // top-left\n            this._drawControl('tl', ctx, methodName,\n                    left - scaleOffset - padding,\n                    top - scaleOffset - padding);\n\n            // top-right\n            this._drawControl('tr', ctx, methodName,\n                    left + width - scaleOffset + padding,\n                    top - scaleOffset - padding);\n\n            // bottom-left\n            this._drawControl('bl', ctx, methodName,\n                    left - scaleOffset - padding,\n                    top + height + scaleOffsetSize + padding);\n\n            // bottom-right\n            this._drawControl('br', ctx, methodName,\n                    left + width + scaleOffsetSize + padding,\n                    top + height + scaleOffsetSize + padding);\n\n            if (!this.get('lockUniScaling')) {\n\n                // middle-top\n                this._drawControl('mt', ctx, methodName,\n                        left + width/2 - scaleOffset,\n                        top - scaleOffset - padding);\n\n                // middle-bottom\n                this._drawControl('mb', ctx, methodName,\n                        left + width/2 - scaleOffset,\n                        top + height + scaleOffsetSize + padding);\n\n                // middle-right\n                this._drawControl('mr', ctx, methodName,\n                        left + width + scaleOffsetSize + padding,\n                        top + height/2 - scaleOffset);\n\n                // middle-left\n                this._drawControl('ml', ctx, methodName,\n                        left - scaleOffset - padding,\n                        top + height/2 - scaleOffset);\n            }\n\n            // middle-top-rotate\n            if (this.hasRotatingPoint) {\n                this._drawControl('mtr', ctx, methodName,\n                        left + width/2 - scaleOffset,\n                        top - this.rotatingPointOffset - this.cornerSize/2 - padding);\n            }\n\n            ctx.restore();\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _drawControl: function(control, ctx, methodName, left, top) {\n            var size = this.cornerSize;\n\n            if (this.isControlVisible(control)) {\n                isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);\n                ctx[methodName](left, top, size, size);\n            }\n        },\n\n        /**\n         * Returns true if the specified control is visible, false otherwise.\n         * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n         * @returns {Boolean} true if the specified control is visible, false otherwise\n         */\n        isControlVisible: function(controlName) {\n            return this._getControlsVisibility()[controlName];\n        },\n\n        /**\n         * Sets the visibility of the specified control.\n         * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n         * @param {Boolean} visible true to set the specified control visible, false otherwise\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        setControlVisible: function(controlName, visible) {\n            this._getControlsVisibility()[controlName] = visible;\n            return this;\n        },\n\n        /**\n         * Sets the visibility state of object controls.\n         * @param {Object} [options] Options object\n         * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it\n         * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it\n         * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it\n         * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it\n         * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it\n         * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it\n         * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it\n         * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it\n         * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it\n         * @return {fabric.Object} thisArg\n         * @chainable\n         */\n        setControlsVisibility: function(options) {\n            options || (options = { });\n\n            for (var p in options) {\n                this.setControlVisible(p, options[p]);\n            }\n            return this;\n        },\n\n        /**\n         * Returns the instance of the control visibility set for this object.\n         * @private\n         * @returns {Object}\n         */\n        _getControlsVisibility: function() {\n            if (!this._controlsVisibility) {\n                this._controlsVisibility = {\n                    tl: true,\n                    tr: true,\n                    br: true,\n                    bl: true,\n                    ml: true,\n                    mt: true,\n                    mr: true,\n                    mb: true,\n                    mtr: true\n                };\n            }\n            return this._controlsVisibility;\n        }\n    });\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Animation duration (in ms) for fx* methods\n     * @type Number\n     * @default\n     */\n    FX_DURATION: 500,\n\n    /**\n     * Centers object horizontally with animation.\n     * @param {fabric.Object} object Object to center\n     * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n     * @param {Function} [callbacks.onComplete] Invoked on completion\n     * @param {Function} [callbacks.onChange] Invoked on every step of animation\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    fxCenterObjectH: function (object, callbacks) {\n        callbacks = callbacks || { };\n\n        var empty = function() { },\n            onComplete = callbacks.onComplete || empty,\n            onChange = callbacks.onChange || empty,\n            _this = this;\n\n        fabric.util.animate({\n            startValue: object.get('left'),\n            endValue: this.getCenter().left,\n            duration: this.FX_DURATION,\n            onChange: function(value) {\n                object.set('left', value);\n                _this.renderAll();\n                onChange();\n            },\n            onComplete: function() {\n                object.setCoords();\n                onComplete();\n            }\n        });\n\n        return this;\n    },\n\n    /**\n     * Centers object vertically with animation.\n     * @param {fabric.Object} object Object to center\n     * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n     * @param {Function} [callbacks.onComplete] Invoked on completion\n     * @param {Function} [callbacks.onChange] Invoked on every step of animation\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    fxCenterObjectV: function (object, callbacks) {\n        callbacks = callbacks || { };\n\n        var empty = function() { },\n            onComplete = callbacks.onComplete || empty,\n            onChange = callbacks.onChange || empty,\n            _this = this;\n\n        fabric.util.animate({\n            startValue: object.get('top'),\n            endValue: this.getCenter().top,\n            duration: this.FX_DURATION,\n            onChange: function(value) {\n                object.set('top', value);\n                _this.renderAll();\n                onChange();\n            },\n            onComplete: function() {\n                object.setCoords();\n                onComplete();\n            }\n        });\n\n        return this;\n    },\n\n    /**\n     * Same as `fabric.Canvas#remove` but animated\n     * @param {fabric.Object} object Object to remove\n     * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n     * @param {Function} [callbacks.onComplete] Invoked on completion\n     * @param {Function} [callbacks.onChange] Invoked on every step of animation\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    fxRemove: function (object, callbacks) {\n        callbacks = callbacks || { };\n\n        var empty = function() { },\n            onComplete = callbacks.onComplete || empty,\n            onChange = callbacks.onChange || empty,\n            _this = this;\n\n        fabric.util.animate({\n            startValue: object.get('opacity'),\n            endValue: 0,\n            duration: this.FX_DURATION,\n            onStart: function() {\n                object.set('active', false);\n            },\n            onChange: function(value) {\n                object.set('opacity', value);\n                _this.renderAll();\n                onChange();\n            },\n            onComplete: function () {\n                _this.remove(object);\n                onComplete();\n            }\n        });\n\n        return this;\n    }\n});\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n    /**\n     * Animates object's properties\n     * @param {String|Object} property Property to animate (if string) or properties to animate (if object)\n     * @param {Number|Object} value Value to animate property to (if string was given first) or options object\n     * @return {fabric.Object} thisArg\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#animation}\n     * @chainable\n     *\n     * As object — multiple properties\n     *\n     * object.animate({ left: ..., top: ... });\n     * object.animate({ left: ..., top: ... }, { duration: ... });\n     *\n     * As string — one property\n     *\n     * object.animate('left', ...);\n     * object.animate('left', { duration: ... });\n     *\n     */\n    animate: function() {\n        if (arguments[0] && typeof arguments[0] === 'object') {\n            var propsToAnimate = [ ], prop, skipCallbacks;\n            for (prop in arguments[0]) {\n                propsToAnimate.push(prop);\n            }\n            for (var i = 0, len = propsToAnimate.length; i < len; i++) {\n                prop = propsToAnimate[i];\n                skipCallbacks = i !== len - 1;\n                this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks);\n            }\n        }\n        else {\n            this._animate.apply(this, arguments);\n        }\n        return this;\n    },\n\n    /**\n     * @private\n     * @param {String} property Property to animate\n     * @param {String} to Value to animate to\n     * @param {Object} [options] Options object\n     * @param {Boolean} [skipCallbacks] When true, callbacks like onchange and oncomplete are not invoked\n     */\n    _animate: function(property, to, options, skipCallbacks) {\n        var _this = this, propPair;\n\n        to = to.toString();\n\n        if (!options) {\n            options = { };\n        }\n        else {\n            options = fabric.util.object.clone(options);\n        }\n\n        if (~property.indexOf('.')) {\n            propPair = property.split('.');\n        }\n\n        var currentValue = propPair\n            ? this.get(propPair[0])[propPair[1]]\n            : this.get(property);\n\n        if (!('from' in options)) {\n            options.from = currentValue;\n        }\n\n        if (~to.indexOf('=')) {\n            to = currentValue + parseFloat(to.replace('=', ''));\n        }\n        else {\n            to = parseFloat(to);\n        }\n\n        fabric.util.animate({\n            startValue: options.from,\n            endValue: to,\n            byValue: options.by,\n            easing: options.easing,\n            duration: options.duration,\n            abort: options.abort && function() {\n                return options.abort.call(_this);\n            },\n            onChange: function(value) {\n                if (propPair) {\n                    _this[propPair[0]][propPair[1]] = value;\n                }\n                else {\n                    _this.set(property, value);\n                }\n                if (skipCallbacks) {\n                    return;\n                }\n                options.onChange && options.onChange();\n            },\n            onComplete: function() {\n                if (skipCallbacks) {\n                    return;\n                }\n\n                _this.setCoords();\n                options.onComplete && options.onComplete();\n            }\n        });\n    }\n});\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 },\n        supportsLineDash = fabric.StaticCanvas.supports('setLineDash');\n\n    if (fabric.Line) {\n        fabric.warn('fabric.Line is already defined');\n        return;\n    }\n\n    /**\n     * Line class\n     * @class fabric.Line\n     * @extends fabric.Object\n     * @see {@link fabric.Line#initialize} for constructor definition\n     */\n    fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'line',\n\n        /**\n         * x value or first line edge\n         * @type Number\n         * @default\n         */\n        x1: 0,\n\n        /**\n         * y value or first line edge\n         * @type Number\n         * @default\n         */\n        y1: 0,\n\n        /**\n         * x value or second line edge\n         * @type Number\n         * @default\n         */\n        x2: 0,\n\n        /**\n         * y value or second line edge\n         * @type Number\n         * @default\n         */\n        y2: 0,\n\n        /**\n         * Constructor\n         * @param {Array} [points] Array of points\n         * @param {Object} [options] Options object\n         * @return {fabric.Line} thisArg\n         */\n        initialize: function(points, options) {\n            options = options || { };\n\n            if (!points) {\n                points = [0, 0, 0, 0];\n            }\n\n            this.callSuper('initialize', options);\n\n            this.set('x1', points[0]);\n            this.set('y1', points[1]);\n            this.set('x2', points[2]);\n            this.set('y2', points[3]);\n\n            this._setWidthHeight(options);\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Options\n         */\n        _setWidthHeight: function(options) {\n            options || (options = { });\n\n            this.width = Math.abs(this.x2 - this.x1) || 1;\n            this.height = Math.abs(this.y2 - this.y1) || 1;\n\n            this.left = 'left' in options\n                ? options.left\n                : this._getLeftToOriginX();\n\n            this.top = 'top' in options\n                ? options.top\n                : this._getTopToOriginY();\n        },\n\n        /**\n         * @private\n         * @param {String} key\n         * @param {Any} value\n         */\n        _set: function(key, value) {\n            this.callSuper('_set', key, value);\n            if (typeof coordProps[key] !== 'undefined') {\n                this._setWidthHeight();\n            }\n            return this;\n        },\n\n        /**\n         * @private\n         * @return {Number} leftToOriginX Distance from left edge of canvas to originX of Line.\n         */\n        _getLeftToOriginX: makeEdgeToOriginGetter(\n            { // property names\n                origin: 'originX',\n                axis1: 'x1',\n                axis2: 'x2',\n                dimension: 'width'\n            },\n            { // possible values of origin\n                nearest: 'left',\n                center: 'center',\n                farthest: 'right'\n            }\n        ),\n\n        /**\n         * @private\n         * @return {Number} topToOriginY Distance from top edge of canvas to originY of Line.\n         */\n        _getTopToOriginY: makeEdgeToOriginGetter(\n            { // property names\n                origin: 'originY',\n                axis1: 'y1',\n                axis2: 'y2',\n                dimension: 'height'\n            },\n            { // possible values of origin\n                nearest: 'top',\n                center: 'center',\n                farthest: 'bottom'\n            }\n        ),\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx, noTransform) {\n            ctx.beginPath();\n\n            if (noTransform) {\n                //  Line coords are distances from left-top of canvas to origin of line.\n                //\n                //  To render line in a path-group, we need to translate them to\n                //  distances from center of path-group to center of line.\n                var cp = this.getCenterPoint();\n                ctx.translate(\n                    cp.x,\n                    cp.y\n                );\n            }\n\n            if (!this.strokeDashArray || this.strokeDashArray && supportsLineDash) {\n\n                // move from center (of virtual box) to its left/top corner\n                // we can't assume x1, y1 is top left and x2, y2 is bottom right\n                var xMult = this.x1 <= this.x2 ? -1 : 1,\n                    yMult = this.y1 <= this.y2 ? -1 : 1;\n\n                ctx.moveTo(\n                        this.width === 1 ? 0 : (xMult * this.width / 2),\n                        this.height === 1 ? 0 : (yMult * this.height / 2));\n\n                ctx.lineTo(\n                        this.width === 1 ? 0 : (xMult * -1 * this.width / 2),\n                        this.height === 1 ? 0 : (yMult * -1 * this.height / 2));\n            }\n\n            ctx.lineWidth = this.strokeWidth;\n\n            // TODO: test this\n            // make sure setting \"fill\" changes color of a line\n            // (by copying fillStyle to strokeStyle, since line is stroked, not filled)\n            var origStrokeStyle = ctx.strokeStyle;\n            ctx.strokeStyle = this.stroke || ctx.fillStyle;\n            this.stroke && this._renderStroke(ctx);\n            ctx.strokeStyle = origStrokeStyle;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderDashedStroke: function(ctx) {\n            var\n                xMult = this.x1 <= this.x2 ? -1 : 1,\n                yMult = this.y1 <= this.y2 ? -1 : 1,\n                x = this.width === 1 ? 0 : xMult * this.width / 2,\n                y = this.height === 1 ? 0 : yMult * this.height / 2;\n\n            ctx.beginPath();\n            fabric.util.drawDashedLine(ctx, x, y, -x, -y, this.strokeDashArray);\n            ctx.closePath();\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @methd toObject\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return extend(this.callSuper('toObject', propertiesToInclude), this.calcLinePoints());\n        },\n\n        /**\n         * @private\n         * Recalculate line points from width and height.\n         */\n        calcLinePoints: function() {\n            var xMult = this.x1 <= this.x2 ? -1 : 1,\n                yMult = this.y1 <= this.y2 ? -1 : 1,\n                x1 = (xMult * this.width / 2),\n                y1 = (yMult * this.height / 2),\n                x2 = (xMult * -1 * this.width / 2),\n                y2 = (yMult * -1 * this.height / 2);\n\n            return {\n                x1: x1,\n                x2: x2,\n                y1: y1,\n                y2: y2\n            };\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = this._createBaseSVGMarkup(),\n                p = { x1: this.x1, x2: this.x2, y1: this.y1, y2: this.y2 };\n\n            if (!(this.group && this.group.type === 'path-group')) {\n                p = this.calcLinePoints();\n            }\n            markup.push(\n                '<line ',\n                'x1=\"', p.x1,\n                '\" y1=\"', p.y1,\n                '\" x2=\"', p.x2,\n                '\" y2=\"', p.y2,\n                '\" style=\"', this.getSvgStyles(),\n                '\" transform=\"', this.getSvgTransform(),\n                this.getSvgTransformMatrix(),\n                '\"/>\\n'\n            );\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement})\n     * @static\n     * @memberOf fabric.Line\n     * @see http://www.w3.org/TR/SVG/shapes.html#LineElement\n     */\n    fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));\n\n    /**\n     * Returns fabric.Line instance from an SVG element\n     * @static\n     * @memberOf fabric.Line\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @return {fabric.Line} instance of fabric.Line\n     */\n    fabric.Line.fromElement = function(element, options) {\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES),\n            points = [\n                    parsedAttributes.x1 || 0,\n                    parsedAttributes.y1 || 0,\n                    parsedAttributes.x2 || 0,\n                    parsedAttributes.y2 || 0\n            ];\n        return new fabric.Line(points, extend(parsedAttributes, options));\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns fabric.Line instance from an object representation\n     * @static\n     * @memberOf fabric.Line\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Line} instance of fabric.Line\n     */\n    fabric.Line.fromObject = function(object) {\n        var points = [object.x1, object.y1, object.x2, object.y2];\n        return new fabric.Line(points, object);\n    };\n\n    /**\n     * Produces a function that calculates distance from canvas edge to Line origin.\n     */\n    function makeEdgeToOriginGetter(propertyNames, originValues) {\n        var origin = propertyNames.origin,\n            axis1 = propertyNames.axis1,\n            axis2 = propertyNames.axis2,\n            dimension = propertyNames.dimension,\n            nearest = originValues.nearest,\n            center = originValues.center,\n            farthest = originValues.farthest;\n\n        return function() {\n            switch (this.get(origin)) {\n                case nearest:\n                    return Math.min(this.get(axis1), this.get(axis2));\n                case center:\n                    return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension));\n                case farthest:\n                    return Math.max(this.get(axis1), this.get(axis2));\n            }\n        };\n\n    }\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        pi = Math.PI,\n        extend = fabric.util.object.extend;\n\n    if (fabric.Circle) {\n        fabric.warn('fabric.Circle is already defined.');\n        return;\n    }\n\n    /**\n     * Circle class\n     * @class fabric.Circle\n     * @extends fabric.Object\n     * @see {@link fabric.Circle#initialize} for constructor definition\n     */\n    fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'circle',\n\n        /**\n         * Radius of this circle\n         * @type Number\n         * @default\n         */\n        radius: 0,\n\n        /**\n         * Start angle of the circle, moving clockwise\n         * @type Number\n         * @default 0\n         */\n        startAngle: 0,\n\n        /**\n         * End angle of the circle\n         * @type Number\n         * @default 2Pi\n         */\n        endAngle: pi * 2,\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         * @return {fabric.Circle} thisArg\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.callSuper('initialize', options);\n            this.set('radius', options.radius || 0);\n            this.startAngle = options.startAngle || this.startAngle;\n            this.endAngle = options.endAngle || this.endAngle;\n        },\n\n        /**\n         * @private\n         * @param {String} key\n         * @param {Any} value\n         * @return {fabric.Circle} thisArg\n         */\n        _set: function(key, value) {\n            this.callSuper('_set', key, value);\n\n            if (key === 'radius') {\n                this.setRadius(value);\n            }\n\n            return this;\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return extend(this.callSuper('toObject', propertiesToInclude), {\n                radius: this.get('radius'),\n                startAngle: this.startAngle,\n                endAngle: this.endAngle\n            });\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = this._createBaseSVGMarkup(), x = 0, y = 0,\n                angle = (this.endAngle - this.startAngle) % ( 2 * pi);\n\n            if (angle === 0) {\n                if (this.group && this.group.type === 'path-group') {\n                    x = this.left + this.radius;\n                    y = this.top + this.radius;\n                }\n                markup.push(\n                    '<circle ',\n                        'cx=\"' + x + '\" cy=\"' + y + '\" ',\n                    'r=\"', this.radius,\n                    '\" style=\"', this.getSvgStyles(),\n                    '\" transform=\"', this.getSvgTransform(),\n                    ' ', this.getSvgTransformMatrix(),\n                    '\"/>\\n'\n                );\n            }\n            else {\n                var startX = Math.cos(this.startAngle) * this.radius,\n                    startY = Math.sin(this.startAngle) * this.radius,\n                    endX = Math.cos(this.endAngle) * this.radius,\n                    endY = Math.sin(this.endAngle) * this.radius,\n                    largeFlag = angle > pi ? '1' : '0';\n\n                markup.push(\n                        '<path d=\"M ' + startX + ' ' + startY,\n                        ' A ' + this.radius + ' ' + this.radius,\n                    ' 0 ', + largeFlag + ' 1', ' ' + endX + ' ' + endY,\n                    '\" style=\"', this.getSvgStyles(),\n                    '\" transform=\"', this.getSvgTransform(),\n                    ' ', this.getSvgTransformMatrix(),\n                    '\"/>\\n'\n                );\n            }\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx context to render on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        _render: function(ctx, noTransform) {\n            ctx.beginPath();\n            ctx.arc(noTransform ? this.left + this.radius : 0,\n                noTransform ? this.top + this.radius : 0,\n                this.radius,\n                this.startAngle,\n                this.endAngle, false);\n            this._renderFill(ctx);\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * Returns horizontal radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRadiusX: function() {\n            return this.get('radius') * this.get('scaleX');\n        },\n\n        /**\n         * Returns vertical radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRadiusY: function() {\n            return this.get('radius') * this.get('scaleY');\n        },\n\n        /**\n         * Sets radius of an object (and updates width accordingly)\n         * @return {Number}\n         */\n        setRadius: function(value) {\n            this.radius = value;\n            this.set('width', value * 2).set('height', value * 2);\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})\n     * @static\n     * @memberOf fabric.Circle\n     * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement\n     */\n    fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));\n\n    /**\n     * Returns {@link fabric.Circle} instance from an SVG element\n     * @static\n     * @memberOf fabric.Circle\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @throws {Error} If value of `r` attribute is missing or invalid\n     * @return {fabric.Circle} Instance of fabric.Circle\n     */\n    fabric.Circle.fromElement = function(element, options) {\n        options || (options = { });\n\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);\n\n        if (!isValidRadius(parsedAttributes)) {\n            throw new Error('value of `r` attribute is required and can not be negative');\n        }\n\n        parsedAttributes.left = parsedAttributes.left || 0;\n        parsedAttributes.top = parsedAttributes.top || 0;\n\n        var obj = new fabric.Circle(extend(parsedAttributes, options));\n\n        obj.left -= obj.radius;\n        obj.top -= obj.radius;\n        return obj;\n    };\n\n    /**\n     * @private\n     */\n    function isValidRadius(attributes) {\n        return (('radius' in attributes) && (attributes.radius > 0));\n    }\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns {@link fabric.Circle} instance from an object representation\n     * @static\n     * @memberOf fabric.Circle\n     * @param {Object} object Object to create an instance from\n     * @return {Object} Instance of fabric.Circle\n     */\n    fabric.Circle.fromObject = function(object) {\n        return new fabric.Circle(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { });\n\n    if (fabric.Triangle) {\n        fabric.warn('fabric.Triangle is already defined');\n        return;\n    }\n\n    /**\n     * Triangle class\n     * @class fabric.Triangle\n     * @extends fabric.Object\n     * @return {fabric.Triangle} thisArg\n     * @see {@link fabric.Triangle#initialize} for constructor definition\n     */\n    fabric.Triangle = fabric.util.createClass(fabric.Object, /** @lends fabric.Triangle.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'triangle',\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         * @return {Object} thisArg\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.callSuper('initialize', options);\n\n            this.set('width', options.width || 100)\n                .set('height', options.height || 100);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx) {\n            var widthBy2 = this.width / 2,\n                heightBy2 = this.height / 2;\n\n            ctx.beginPath();\n            ctx.moveTo(-widthBy2, heightBy2);\n            ctx.lineTo(0, -heightBy2);\n            ctx.lineTo(widthBy2, heightBy2);\n            ctx.closePath();\n\n            this._renderFill(ctx);\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderDashedStroke: function(ctx) {\n            var widthBy2 = this.width / 2,\n                heightBy2 = this.height / 2;\n\n            ctx.beginPath();\n            fabric.util.drawDashedLine(ctx, -widthBy2, heightBy2, 0, -heightBy2, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, 0, -heightBy2, widthBy2, heightBy2, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, widthBy2, heightBy2, -widthBy2, heightBy2, this.strokeDashArray);\n            ctx.closePath();\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = this._createBaseSVGMarkup(),\n                widthBy2 = this.width / 2,\n                heightBy2 = this.height / 2,\n                points = [\n                        -widthBy2 + ' ' + heightBy2,\n                        '0 ' + -heightBy2,\n                        widthBy2 + ' ' + heightBy2\n                ]\n                    .join(',');\n\n            markup.push(\n                '<polygon ',\n                'points=\"', points,\n                '\" style=\"', this.getSvgStyles(),\n                '\" transform=\"', this.getSvgTransform(),\n                '\"/>'\n            );\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /**\n     * Returns fabric.Triangle instance from an object representation\n     * @static\n     * @memberOf fabric.Triangle\n     * @param {Object} object Object to create an instance from\n     * @return {Object} instance of Canvas.Triangle\n     */\n    fabric.Triangle.fromObject = function(object) {\n        return new fabric.Triangle(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        piBy2   = Math.PI * 2,\n        extend = fabric.util.object.extend;\n\n    if (fabric.Ellipse) {\n        fabric.warn('fabric.Ellipse is already defined.');\n        return;\n    }\n\n    /**\n     * Ellipse class\n     * @class fabric.Ellipse\n     * @extends fabric.Object\n     * @return {fabric.Ellipse} thisArg\n     * @see {@link fabric.Ellipse#initialize} for constructor definition\n     */\n    fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @lends fabric.Ellipse.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'ellipse',\n\n        /**\n         * Horizontal radius\n         * @type Number\n         * @default\n         */\n        rx:   0,\n\n        /**\n         * Vertical radius\n         * @type Number\n         * @default\n         */\n        ry:   0,\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         * @return {fabric.Ellipse} thisArg\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.callSuper('initialize', options);\n\n            this.set('rx', options.rx || 0);\n            this.set('ry', options.ry || 0);\n        },\n\n        /**\n         * @private\n         * @param {String} key\n         * @param {Any} value\n         * @return {fabric.Ellipse} thisArg\n         */\n        _set: function(key, value) {\n            this.callSuper('_set', key, value);\n            switch (key) {\n\n                case 'rx':\n                    this.rx = value;\n                    this.set('width', value * 2);\n                    break;\n\n                case 'ry':\n                    this.ry = value;\n                    this.set('height', value * 2);\n                    break;\n\n            }\n            return this;\n        },\n\n        /**\n         * Returns horizontal radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRx: function() {\n            return this.get('rx') * this.get('scaleX');\n        },\n\n        /**\n         * Returns Vertical radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRy: function() {\n            return this.get('ry') * this.get('scaleY');\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return extend(this.callSuper('toObject', propertiesToInclude), {\n                rx: this.get('rx'),\n                ry: this.get('ry')\n            });\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = this._createBaseSVGMarkup(), x = 0, y = 0;\n            if (this.group && this.group.type === 'path-group') {\n                x = this.left + this.rx;\n                y = this.top + this.ry;\n            }\n            markup.push(\n                '<ellipse ',\n                'cx=\"', x, '\" cy=\"', y, '\" ',\n                'rx=\"', this.rx,\n                '\" ry=\"', this.ry,\n                '\" style=\"', this.getSvgStyles(),\n                '\" transform=\"', this.getSvgTransform(),\n                this.getSvgTransformMatrix(),\n                '\"/>\\n'\n            );\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx context to render on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        _render: function(ctx, noTransform) {\n            ctx.beginPath();\n            ctx.save();\n            ctx.transform(1, 0, 0, this.ry/this.rx, 0, 0);\n            ctx.arc(\n                noTransform ? this.left + this.rx : 0,\n                noTransform ? (this.top + this.ry) * this.rx/this.ry : 0,\n                this.rx,\n                0,\n                piBy2,\n                false);\n            ctx.restore();\n            this._renderFill(ctx);\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement})\n     * @static\n     * @memberOf fabric.Ellipse\n     * @see http://www.w3.org/TR/SVG/shapes.html#EllipseElement\n     */\n    fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy rx ry'.split(' '));\n\n    /**\n     * Returns {@link fabric.Ellipse} instance from an SVG element\n     * @static\n     * @memberOf fabric.Ellipse\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @return {fabric.Ellipse}\n     */\n    fabric.Ellipse.fromElement = function(element, options) {\n        options || (options = { });\n\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);\n\n        parsedAttributes.left = parsedAttributes.left || 0;\n        parsedAttributes.top = parsedAttributes.top || 0;\n\n        var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));\n\n        ellipse.top -= ellipse.ry;\n        ellipse.left -= ellipse.rx;\n        return ellipse;\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns {@link fabric.Ellipse} instance from an object representation\n     * @static\n     * @memberOf fabric.Ellipse\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Ellipse}\n     */\n    fabric.Ellipse.fromObject = function(object) {\n        return new fabric.Ellipse(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    if (fabric.Rect) {\n        console.warn('fabric.Rect is already defined');\n        return;\n    }\n\n    var stateProperties = fabric.Object.prototype.stateProperties.concat();\n    stateProperties.push('rx', 'ry', 'x', 'y');\n\n    /**\n     * Rectangle class\n     * @class fabric.Rect\n     * @extends fabric.Object\n     * @return {fabric.Rect} thisArg\n     * @see {@link fabric.Rect#initialize} for constructor definition\n     */\n    fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {\n\n        /**\n         * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})\n         * as well as for history (undo/redo) purposes\n         * @type Array\n         */\n        stateProperties: stateProperties,\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'rect',\n\n        /**\n         * Horizontal border radius\n         * @type Number\n         * @default\n         */\n        rx:   0,\n\n        /**\n         * Vertical border radius\n         * @type Number\n         * @default\n         */\n        ry:   0,\n\n        /**\n         * Used to specify dash pattern for stroke on this object\n         * @type Array\n         */\n        strokeDashArray: null,\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         * @return {Object} thisArg\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.callSuper('initialize', options);\n            this._initRxRy();\n\n        },\n\n        /**\n         * Initializes rx/ry attributes\n         * @private\n         */\n        _initRxRy: function() {\n            if (this.rx && !this.ry) {\n                this.ry = this.rx;\n            }\n            else if (this.ry && !this.rx) {\n                this.rx = this.ry;\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx, noTransform) {\n\n            // optimize 1x1 case (used in spray brush)\n            if (this.width === 1 && this.height === 1) {\n                ctx.fillRect(0, 0, 1, 1);\n                return;\n            }\n\n            var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0,\n                ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,\n                w = this.width,\n                h = this.height,\n                x = noTransform ? this.left : -this.width / 2,\n                y = noTransform ? this.top : -this.height / 2,\n                isRounded = rx !== 0 || ry !== 0,\n                k = 1 - 0.5522847498 /* \"magic number\" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */;\n\n            ctx.beginPath();\n\n            ctx.moveTo(x + rx, y);\n\n            ctx.lineTo(x + w - rx, y);\n            isRounded && ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry);\n\n            ctx.lineTo(x + w, y + h - ry);\n            isRounded && ctx.bezierCurveTo(x + w, y + h - k * ry, x + w - k * rx, y + h, x + w - rx, y + h);\n\n            ctx.lineTo(x + rx, y + h);\n            isRounded && ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry);\n\n            ctx.lineTo(x, y + ry);\n            isRounded && ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y);\n\n            ctx.closePath();\n\n            this._renderFill(ctx);\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderDashedStroke: function(ctx) {\n            var x = -this.width / 2,\n                y = -this.height / 2,\n                w = this.width,\n                h = this.height;\n\n            ctx.beginPath();\n            fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);\n            ctx.closePath();\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            var object = extend(this.callSuper('toObject', propertiesToInclude), {\n                rx: this.get('rx') || 0,\n                ry: this.get('ry') || 0\n            });\n            if (!this.includeDefaultValues) {\n                this._removeDefaultValues(object);\n            }\n            return object;\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = this._createBaseSVGMarkup(), x = this.left, y = this.top;\n            if (!(this.group && this.group.type === 'path-group')) {\n                x = -this.width / 2;\n                y = -this.height / 2;\n            }\n            markup.push(\n                '<rect ',\n                'x=\"', x, '\" y=\"', y,\n                '\" rx=\"', this.get('rx'), '\" ry=\"', this.get('ry'),\n                '\" width=\"', this.width, '\" height=\"', this.height,\n                '\" style=\"', this.getSvgStyles(),\n                '\" transform=\"', this.getSvgTransform(),\n                this.getSvgTransformMatrix(),\n                '\"/>\\n');\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)\n     * @static\n     * @memberOf fabric.Rect\n     * @see: http://www.w3.org/TR/SVG/shapes.html#RectElement\n     */\n    fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));\n\n    /**\n     * Returns {@link fabric.Rect} instance from an SVG element\n     * @static\n     * @memberOf fabric.Rect\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @return {fabric.Rect} Instance of fabric.Rect\n     */\n    fabric.Rect.fromElement = function(element, options) {\n        if (!element) {\n            return null;\n        }\n        options = options || { };\n\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);\n\n        parsedAttributes.left = parsedAttributes.left || 0;\n        parsedAttributes.top  = parsedAttributes.top  || 0;\n\n        return new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns {@link fabric.Rect} instance from an object representation\n     * @static\n     * @memberOf fabric.Rect\n     * @param {Object} object Object to create an instance from\n     * @return {Object} instance of fabric.Rect\n     */\n    fabric.Rect.fromObject = function(object) {\n        return new fabric.Rect(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { });\n\n    if (fabric.Polyline) {\n        fabric.warn('fabric.Polyline is already defined');\n        return;\n    }\n\n    /**\n     * Polyline class\n     * @class fabric.Polyline\n     * @extends fabric.Object\n     * @see {@link fabric.Polyline#initialize} for constructor definition\n     */\n    fabric.Polyline = fabric.util.createClass(fabric.Object, /** @lends fabric.Polyline.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'polyline',\n\n        /**\n         * Points array\n         * @type Array\n         * @default\n         */\n        points: null,\n\n        /**\n         * Minimum X from points values, necessary to offset points\n         * @type Number\n         * @default\n         */\n        minX: 0,\n\n        /**\n         * Minimum Y from points values, necessary to offset points\n         * @type Number\n         * @default\n         */\n        minY: 0,\n\n        /**\n         * Constructor\n         * @param {Array} points Array of points (where each point is an object with x and y)\n         * @param {Object} [options] Options object\n         * @param {Boolean} [skipOffset] Whether points offsetting should be skipped\n         * @return {fabric.Polyline} thisArg\n         * @example\n         * var poly = new fabric.Polyline([\n         *     { x: 10, y: 10 },\n         *     { x: 50, y: 30 },\n         *     { x: 40, y: 70 },\n         *     { x: 60, y: 50 },\n         *     { x: 100, y: 150 },\n         *     { x: 40, y: 100 }\n         *   ], {\n     *   stroke: 'red',\n     *   left: 100,\n     *   top: 100\n     * });\n         */\n        initialize: function(points, options) {\n            return fabric.Polygon.prototype.initialize.call(this, points, options);\n        },\n\n        /**\n         * @private\n         */\n        _calcDimensions: function() {\n            return fabric.Polygon.prototype._calcDimensions.call(this);\n        },\n\n        /**\n         * @private\n         */\n        _applyPointOffset: function() {\n            return fabric.Polygon.prototype._applyPointOffset.call(this);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return fabric.Polygon.prototype.toObject.call(this, propertiesToInclude);\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            return fabric.Polygon.prototype.toSVG.call(this, reviver);\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx) {\n            fabric.Polygon.prototype.commonRender.call(this, ctx);\n            this._renderFill(ctx);\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderDashedStroke: function(ctx) {\n            var p1, p2;\n\n            ctx.beginPath();\n            for (var i = 0, len = this.points.length; i < len; i++) {\n                p1 = this.points[i];\n                p2 = this.points[i + 1] || p1;\n                fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray);\n            }\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return this.get('points').length;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement})\n     * @static\n     * @memberOf fabric.Polyline\n     * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement\n     */\n    fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n    /**\n     * Returns fabric.Polyline instance from an SVG element\n     * @static\n     * @memberOf fabric.Polyline\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @return {fabric.Polyline} Instance of fabric.Polyline\n     */\n    fabric.Polyline.fromElement = function(element, options) {\n        if (!element) {\n            return null;\n        }\n        options || (options = { });\n\n        var points = fabric.parsePointsAttribute(element.getAttribute('points')),\n            parsedAttributes = fabric.parseAttributes(element, fabric.Polyline.ATTRIBUTE_NAMES);\n\n        if (points === null) {\n            return null;\n        }\n\n        return new fabric.Polyline(points, fabric.util.object.extend(parsedAttributes, options));\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns fabric.Polyline instance from an object representation\n     * @static\n     * @memberOf fabric.Polyline\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Polyline} Instance of fabric.Polyline\n     */\n    fabric.Polyline.fromObject = function(object) {\n        var points = object.points;\n        return new fabric.Polyline(points, object, true);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        min = fabric.util.array.min,\n        max = fabric.util.array.max,\n        toFixed = fabric.util.toFixed;\n\n    if (fabric.Polygon) {\n        fabric.warn('fabric.Polygon is already defined');\n        return;\n    }\n\n    /**\n     * Polygon class\n     * @class fabric.Polygon\n     * @extends fabric.Object\n     * @see {@link fabric.Polygon#initialize} for constructor definition\n     */\n    fabric.Polygon = fabric.util.createClass(fabric.Object, /** @lends fabric.Polygon.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'polygon',\n\n        /**\n         * Points array\n         * @type Array\n         * @default\n         */\n        points: null,\n\n        /**\n         * Minimum X from points values, necessary to offset points\n         * @type Number\n         * @default\n         */\n        minX: 0,\n\n        /**\n         * Minimum Y from points values, necessary to offset points\n         * @type Number\n         * @default\n         */\n        minY: 0,\n\n        /**\n         * Constructor\n         * @param {Array} points Array of points\n         * @param {Object} [options] Options object\n         * @return {fabric.Polygon} thisArg\n         */\n        initialize: function(points, options) {\n            options = options || { };\n            this.points = points;\n            this.callSuper('initialize', options);\n            this._calcDimensions();\n            if (!('top' in options)) {\n                this.top = this.minY;\n            }\n            if (!('left' in options)) {\n                this.left = this.minX;\n            }\n        },\n\n        /**\n         * @private\n         */\n        _calcDimensions: function() {\n\n            var points = this.points,\n                minX = min(points, 'x'),\n                minY = min(points, 'y'),\n                maxX = max(points, 'x'),\n                maxY = max(points, 'y');\n\n            this.width = (maxX - minX) || 1;\n            this.height = (maxY - minY) || 1;\n\n            this.minX = minX,\n                this.minY = minY;\n        },\n\n        /**\n         * @private\n         */\n        _applyPointOffset: function() {\n            // change points to offset polygon into a bounding box\n            // executed one time\n            this.points.forEach(function(p) {\n                p.x -= (this.minX + this.width / 2);\n                p.y -= (this.minY + this.height / 2);\n            }, this);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return extend(this.callSuper('toObject', propertiesToInclude), {\n                points: this.points.concat()\n            });\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var points = [],\n                markup = this._createBaseSVGMarkup();\n\n            for (var i = 0, len = this.points.length; i < len; i++) {\n                points.push(toFixed(this.points[i].x, 2), ',', toFixed(this.points[i].y, 2), ' ');\n            }\n\n            markup.push(\n                '<', this.type, ' ',\n                'points=\"', points.join(''),\n                '\" style=\"', this.getSvgStyles(),\n                '\" transform=\"', this.getSvgTransform(),\n                ' ', this.getSvgTransformMatrix(),\n                '\"/>\\n'\n            );\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx) {\n            this.commonRender(ctx);\n            this._renderFill(ctx);\n            if (this.stroke || this.strokeDashArray) {\n                ctx.closePath();\n                this._renderStroke(ctx);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        commonRender: function(ctx) {\n            var point;\n            ctx.beginPath();\n\n            if (this._applyPointOffset) {\n                if (!(this.group && this.group.type === 'path-group')) {\n                    this._applyPointOffset();\n                }\n                this._applyPointOffset = null;\n            }\n\n            ctx.moveTo(this.points[0].x, this.points[0].y);\n            for (var i = 0, len = this.points.length; i < len; i++) {\n                point = this.points[i];\n                ctx.lineTo(point.x, point.y);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderDashedStroke: function(ctx) {\n            fabric.Polyline.prototype._renderDashedStroke.call(this, ctx);\n            ctx.closePath();\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return this.points.length;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)\n     * @static\n     * @memberOf fabric.Polygon\n     * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement\n     */\n    fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n    /**\n     * Returns {@link fabric.Polygon} instance from an SVG element\n     * @static\n     * @memberOf fabric.Polygon\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @return {fabric.Polygon} Instance of fabric.Polygon\n     */\n    fabric.Polygon.fromElement = function(element, options) {\n        if (!element) {\n            return null;\n        }\n\n        options || (options = { });\n\n        var points = fabric.parsePointsAttribute(element.getAttribute('points')),\n            parsedAttributes = fabric.parseAttributes(element, fabric.Polygon.ATTRIBUTE_NAMES);\n\n        if (points === null) {\n            return null;\n        }\n\n        return new fabric.Polygon(points, extend(parsedAttributes, options));\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns fabric.Polygon instance from an object representation\n     * @static\n     * @memberOf fabric.Polygon\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Polygon} Instance of fabric.Polygon\n     */\n    fabric.Polygon.fromObject = function(object) {\n        return new fabric.Polygon(object.points, object, true);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        min = fabric.util.array.min,\n        max = fabric.util.array.max,\n        extend = fabric.util.object.extend,\n        _toString = Object.prototype.toString,\n        drawArc = fabric.util.drawArc,\n        commandLengths = {\n            m: 2,\n            l: 2,\n            h: 1,\n            v: 1,\n            c: 6,\n            s: 4,\n            q: 4,\n            t: 2,\n            a: 7\n        },\n        repeatedCommands = {\n            m: 'l',\n            M: 'L'\n        };\n\n    if (fabric.Path) {\n        fabric.warn('fabric.Path is already defined');\n        return;\n    }\n\n    /**\n     * Path class\n     * @class fabric.Path\n     * @extends fabric.Object\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-1/#path_and_pathgroup}\n     * @see {@link fabric.Path#initialize} for constructor definition\n     */\n    fabric.Path = fabric.util.createClass(fabric.Object, /** @lends fabric.Path.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'path',\n\n        /**\n         * Array of path points\n         * @type Array\n         * @default\n         */\n        path: null,\n\n        /**\n         * Minimum X from points values, necessary to offset points\n         * @type Number\n         * @default\n         */\n        minX: 0,\n\n        /**\n         * Minimum Y from points values, necessary to offset points\n         * @type Number\n         * @default\n         */\n        minY: 0,\n\n        /**\n         * Constructor\n         * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n         * @param {Object} [options] Options object\n         * @return {fabric.Path} thisArg\n         */\n        initialize: function(path, options) {\n            options = options || { };\n\n            this.setOptions(options);\n\n            if (!path) {\n                throw new Error('`path` argument is required');\n            }\n\n            var fromArray = _toString.call(path) === '[object Array]';\n\n            this.path = fromArray\n                ? path\n                // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)\n                : path.match && path.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);\n\n            if (!this.path) {\n                return;\n            }\n\n            if (!fromArray) {\n                this.path = this._parsePath();\n            }\n\n            var calcDim = this._parseDimensions();\n            this.minX = calcDim.left;\n            this.minY = calcDim.top;\n            this.width = calcDim.width;\n            this.height = calcDim.height;\n            this.top = this.top || this.minY;\n            this.left = this.left || this.minX;\n            this.pathOffset = this.pathOffset || {\n                x: this.minX + this.width / 2,\n                y: this.minY + this.height / 2\n            };\n\n            if (options.sourcePath) {\n                this.setSourcePath(options.sourcePath);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx context to render path on\n         */\n        _render: function(ctx) {\n            var current, // current instruction\n                previous = null,\n                subpathStartX = 0,\n                subpathStartY = 0,\n                x = 0, // current x\n                y = 0, // current y\n                controlX = 0, // current control point x\n                controlY = 0, // current control point y\n                tempX,\n                tempY,\n                tempControlX,\n                tempControlY,\n                l = -this.pathOffset.x,\n                t = -this.pathOffset.y;\n\n            if (this.group && this.group.type === 'path-group') {\n                l = 0;\n                t = 0;\n            }\n\n            ctx.beginPath();\n\n            for (var i = 0, len = this.path.length; i < len; ++i) {\n\n                current = this.path[i];\n\n                switch (current[0]) { // first letter\n\n                    case 'l': // lineto, relative\n                        x += current[1];\n                        y += current[2];\n                        ctx.lineTo(x + l, y + t);\n                        break;\n\n                    case 'L': // lineto, absolute\n                        x = current[1];\n                        y = current[2];\n                        ctx.lineTo(x + l, y + t);\n                        break;\n\n                    case 'h': // horizontal lineto, relative\n                        x += current[1];\n                        ctx.lineTo(x + l, y + t);\n                        break;\n\n                    case 'H': // horizontal lineto, absolute\n                        x = current[1];\n                        ctx.lineTo(x + l, y + t);\n                        break;\n\n                    case 'v': // vertical lineto, relative\n                        y += current[1];\n                        ctx.lineTo(x + l, y + t);\n                        break;\n\n                    case 'V': // verical lineto, absolute\n                        y = current[1];\n                        ctx.lineTo(x + l, y + t);\n                        break;\n\n                    case 'm': // moveTo, relative\n                        x += current[1];\n                        y += current[2];\n                        subpathStartX = x;\n                        subpathStartY = y;\n                        ctx.moveTo(x + l, y + t);\n                        break;\n\n                    case 'M': // moveTo, absolute\n                        x = current[1];\n                        y = current[2];\n                        subpathStartX = x;\n                        subpathStartY = y;\n                        ctx.moveTo(x + l, y + t);\n                        break;\n\n                    case 'c': // bezierCurveTo, relative\n                        tempX = x + current[5];\n                        tempY = y + current[6];\n                        controlX = x + current[3];\n                        controlY = y + current[4];\n                        ctx.bezierCurveTo(\n                                x + current[1] + l, // x1\n                                y + current[2] + t, // y1\n                                controlX + l, // x2\n                                controlY + t, // y2\n                                tempX + l,\n                                tempY + t\n                        );\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'C': // bezierCurveTo, absolute\n                        x = current[5];\n                        y = current[6];\n                        controlX = current[3];\n                        controlY = current[4];\n                        ctx.bezierCurveTo(\n                                current[1] + l,\n                                current[2] + t,\n                                controlX + l,\n                                controlY + t,\n                                x + l,\n                                y + t\n                        );\n                        break;\n\n                    case 's': // shorthand cubic bezierCurveTo, relative\n\n                        // transform to absolute x,y\n                        tempX = x + current[3];\n                        tempY = y + current[4];\n\n                        // calculate reflection of previous control points\n                        controlX = controlX ? (2 * x - controlX) : x;\n                        controlY = controlY ? (2 * y - controlY) : y;\n\n                        ctx.bezierCurveTo(\n                                controlX + l,\n                                controlY + t,\n                                x + current[1] + l,\n                                y + current[2] + t,\n                                tempX + l,\n                                tempY + t\n                        );\n                        // set control point to 2nd one of this command\n                        // \"... the first control point is assumed to be\n                        // the reflection of the second control point on\n                        // the previous command relative to the current point.\"\n                        controlX = x + current[1];\n                        controlY = y + current[2];\n\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'S': // shorthand cubic bezierCurveTo, absolute\n                        tempX = current[3];\n                        tempY = current[4];\n                        // calculate reflection of previous control points\n                        controlX = 2 * x - controlX;\n                        controlY = 2 * y - controlY;\n                        ctx.bezierCurveTo(\n                                controlX + l,\n                                controlY + t,\n                                current[1] + l,\n                                current[2] + t,\n                                tempX + l,\n                                tempY + t\n                        );\n                        x = tempX;\n                        y = tempY;\n\n                        // set control point to 2nd one of this command\n                        // \"... the first control point is assumed to be\n                        // the reflection of the second control point on\n                        // the previous command relative to the current point.\"\n                        controlX = current[1];\n                        controlY = current[2];\n\n                        break;\n\n                    case 'q': // quadraticCurveTo, relative\n                        // transform to absolute x,y\n                        tempX = x + current[3];\n                        tempY = y + current[4];\n\n                        controlX = x + current[1];\n                        controlY = y + current[2];\n\n                        ctx.quadraticCurveTo(\n                                controlX + l,\n                                controlY + t,\n                                tempX + l,\n                                tempY + t\n                        );\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'Q': // quadraticCurveTo, absolute\n                        tempX = current[3];\n                        tempY = current[4];\n\n                        ctx.quadraticCurveTo(\n                                current[1] + l,\n                                current[2] + t,\n                                tempX + l,\n                                tempY + t\n                        );\n                        x = tempX;\n                        y = tempY;\n                        controlX = current[1];\n                        controlY = current[2];\n                        break;\n\n                    case 't': // shorthand quadraticCurveTo, relative\n\n                        // transform to absolute x,y\n                        tempX = x + current[1];\n                        tempY = y + current[2];\n\n                        if (previous[0].match(/[QqTt]/) === null) {\n                            // If there is no previous command or if the previous command was not a Q, q, T or t,\n                            // assume the control point is coincident with the current point\n                            controlX = x;\n                            controlY = y;\n                        }\n                        else if (previous[0] === 't') {\n                            // calculate reflection of previous control points for t\n                            controlX = 2 * x - tempControlX;\n                            controlY = 2 * y - tempControlY;\n                        }\n                        else if (previous[0] === 'q') {\n                            // calculate reflection of previous control points for q\n                            controlX = 2 * x - controlX;\n                            controlY = 2 * y - controlY;\n                        }\n\n                        tempControlX = controlX;\n                        tempControlY = controlY;\n\n                        ctx.quadraticCurveTo(\n                                controlX + l,\n                                controlY + t,\n                                tempX + l,\n                                tempY + t\n                        );\n                        x = tempX;\n                        y = tempY;\n                        controlX = x + current[1];\n                        controlY = y + current[2];\n                        break;\n\n                    case 'T':\n                        tempX = current[1];\n                        tempY = current[2];\n\n                        // calculate reflection of previous control points\n                        controlX = 2 * x - controlX;\n                        controlY = 2 * y - controlY;\n                        ctx.quadraticCurveTo(\n                                controlX + l,\n                                controlY + t,\n                                tempX + l,\n                                tempY + t\n                        );\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'a':\n                        // TODO: optimize this\n                        drawArc(ctx, x + l, y + t, [\n                            current[1],\n                            current[2],\n                            current[3],\n                            current[4],\n                            current[5],\n                                current[6] + x + l,\n                                current[7] + y + t\n                        ]);\n                        x += current[6];\n                        y += current[7];\n                        break;\n\n                    case 'A':\n                        // TODO: optimize this\n                        drawArc(ctx, x + l, y + t, [\n                            current[1],\n                            current[2],\n                            current[3],\n                            current[4],\n                            current[5],\n                                current[6] + l,\n                                current[7] + t\n                        ]);\n                        x = current[6];\n                        y = current[7];\n                        break;\n\n                    case 'z':\n                    case 'Z':\n                        x = subpathStartX;\n                        y = subpathStartY;\n                        ctx.closePath();\n                        break;\n                }\n                previous = current;\n            }\n            this._renderFill(ctx);\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * Renders path on a specified context\n         * @param {CanvasRenderingContext2D} ctx context to render path on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        render: function(ctx, noTransform) {\n            // do not render if width/height are zeros or object is not visible\n            if (!this.visible) {\n                return;\n            }\n\n            ctx.save();\n\n            this._setupCompositeOperation(ctx);\n            if (!noTransform) {\n                this.transform(ctx);\n            }\n            this._setStrokeStyles(ctx);\n            this._setFillStyles(ctx);\n            if (this.group && this.group.type === 'path-group') {\n                ctx.translate(-this.group.width / 2, -this.group.height / 2);\n            }\n            if (this.transformMatrix) {\n                ctx.transform.apply(ctx, this.transformMatrix);\n            }\n            this._setOpacity(ctx);\n            this._setShadow(ctx);\n            this.clipTo && fabric.util.clipContext(this, ctx);\n            this._render(ctx, noTransform);\n            this.clipTo && ctx.restore();\n            this._removeShadow(ctx);\n            this._restoreCompositeOperation(ctx);\n\n            ctx.restore();\n        },\n\n        /**\n         * Returns string representation of an instance\n         * @return {String} string representation of an instance\n         */\n        toString: function() {\n            return '#<fabric.Path (' + this.complexity() +\n                '): { \"top\": ' + this.top + ', \"left\": ' + this.left + ' }>';\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            var o = extend(this.callSuper('toObject', propertiesToInclude), {\n                path: this.path.map(function(item) { return item.slice() }),\n                pathOffset: this.pathOffset\n            });\n            if (this.sourcePath) {\n                o.sourcePath = this.sourcePath;\n            }\n            if (this.transformMatrix) {\n                o.transformMatrix = this.transformMatrix;\n            }\n            return o;\n        },\n\n        /**\n         * Returns dataless object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toDatalessObject: function(propertiesToInclude) {\n            var o = this.toObject(propertiesToInclude);\n            if (this.sourcePath) {\n                o.path = this.sourcePath;\n            }\n            delete o.sourcePath;\n            return o;\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var chunks = [],\n                markup = this._createBaseSVGMarkup(), addTransform = '';\n\n            for (var i = 0, len = this.path.length; i < len; i++) {\n                chunks.push(this.path[i].join(' '));\n            }\n            var path = chunks.join(' ');\n            if (!(this.group && this.group.type === 'path-group')) {\n                addTransform = 'translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ')';\n            }\n            markup.push(\n                //jscs:disable validateIndentation\n                '<path ',\n                'd=\"', path,\n                '\" style=\"', this.getSvgStyles(),\n                '\" transform=\"', this.getSvgTransform(), addTransform,\n                this.getSvgTransformMatrix(), '\" stroke-linecap=\"round\" ',\n                '/>\\n'\n                //jscs:enable validateIndentation\n            );\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns number representation of an instance complexity\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return this.path.length;\n        },\n\n        /**\n         * @private\n         */\n        _parsePath: function() {\n            var result = [ ],\n                coords = [ ],\n                currentPath,\n                parsed,\n                re = /([-+]?((\\d+\\.\\d+)|((\\d+)|(\\.\\d+)))(?:e[-+]?\\d+)?)/ig,\n                match,\n                coordsStr;\n\n            for (var i = 0, coordsParsed, len = this.path.length; i < len; i++) {\n                currentPath = this.path[i];\n\n                coordsStr = currentPath.slice(1).trim();\n                coords.length = 0;\n\n                while ((match = re.exec(coordsStr))) {\n                    coords.push(match[0]);\n                }\n\n                coordsParsed = [ currentPath.charAt(0) ];\n\n                for (var j = 0, jlen = coords.length; j < jlen; j++) {\n                    parsed = parseFloat(coords[j]);\n                    if (!isNaN(parsed)) {\n                        coordsParsed.push(parsed);\n                    }\n                }\n\n                var command = coordsParsed[0],\n                    commandLength = commandLengths[command.toLowerCase()],\n                    repeatedCommand = repeatedCommands[command] || command;\n\n                if (coordsParsed.length - 1 > commandLength) {\n                    for (var k = 1, klen = coordsParsed.length; k < klen; k += commandLength) {\n                        result.push([ command ].concat(coordsParsed.slice(k, k + commandLength)));\n                        command = repeatedCommand;\n                    }\n                }\n                else {\n                    result.push(coordsParsed);\n                }\n            }\n\n            return result;\n        },\n\n        /**\n         * @private\n         */\n        _parseDimensions: function() {\n\n            var aX = [],\n                aY = [],\n                current, // current instruction\n                previous = null,\n                subpathStartX = 0,\n                subpathStartY = 0,\n                x = 0, // current x\n                y = 0, // current y\n                controlX = 0, // current control point x\n                controlY = 0, // current control point y\n                tempX,\n                tempY,\n                tempControlX,\n                tempControlY,\n                bounds;\n\n            for (var i = 0, len = this.path.length; i < len; ++i) {\n\n                current = this.path[i];\n\n                switch (current[0]) { // first letter\n\n                    case 'l': // lineto, relative\n                        x += current[1];\n                        y += current[2];\n                        bounds = [ ];\n                        break;\n\n                    case 'L': // lineto, absolute\n                        x = current[1];\n                        y = current[2];\n                        bounds = [ ];\n                        break;\n\n                    case 'h': // horizontal lineto, relative\n                        x += current[1];\n                        bounds = [ ];\n                        break;\n\n                    case 'H': // horizontal lineto, absolute\n                        x = current[1];\n                        bounds = [ ];\n                        break;\n\n                    case 'v': // vertical lineto, relative\n                        y += current[1];\n                        bounds = [ ];\n                        break;\n\n                    case 'V': // verical lineto, absolute\n                        y = current[1];\n                        bounds = [ ];\n                        break;\n\n                    case 'm': // moveTo, relative\n                        x += current[1];\n                        y += current[2];\n                        subpathStartX = x;\n                        subpathStartY = y;\n                        bounds = [ ];\n                        break;\n\n                    case 'M': // moveTo, absolute\n                        x = current[1];\n                        y = current[2];\n                        subpathStartX = x;\n                        subpathStartY = y;\n                        bounds = [ ];\n                        break;\n\n                    case 'c': // bezierCurveTo, relative\n                        tempX = x + current[5];\n                        tempY = y + current[6];\n                        controlX = x + current[3];\n                        controlY = y + current[4];\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                                x + current[1], // x1\n                                y + current[2], // y1\n                            controlX, // x2\n                            controlY, // y2\n                            tempX,\n                            tempY\n                        );\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'C': // bezierCurveTo, absolute\n                        x = current[5];\n                        y = current[6];\n                        controlX = current[3];\n                        controlY = current[4];\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            current[1],\n                            current[2],\n                            controlX,\n                            controlY,\n                            x,\n                            y\n                        );\n                        break;\n\n                    case 's': // shorthand cubic bezierCurveTo, relative\n\n                        // transform to absolute x,y\n                        tempX = x + current[3];\n                        tempY = y + current[4];\n\n                        // calculate reflection of previous control points\n                        controlX = controlX ? (2 * x - controlX) : x;\n                        controlY = controlY ? (2 * y - controlY) : y;\n\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            controlX,\n                            controlY,\n                                x + current[1],\n                                y + current[2],\n                            tempX,\n                            tempY\n                        );\n                        // set control point to 2nd one of this command\n                        // \"... the first control point is assumed to be\n                        // the reflection of the second control point on\n                        // the previous command relative to the current point.\"\n                        controlX = x + current[1];\n                        controlY = y + current[2];\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'S': // shorthand cubic bezierCurveTo, absolute\n                        tempX = current[3];\n                        tempY = current[4];\n                        // calculate reflection of previous control points\n                        controlX = 2 * x - controlX;\n                        controlY = 2 * y - controlY;\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            controlX,\n                            controlY,\n                            current[1],\n                            current[2],\n                            tempX,\n                            tempY\n                        );\n                        x = tempX;\n                        y = tempY;\n                        // set control point to 2nd one of this command\n                        // \"... the first control point is assumed to be\n                        // the reflection of the second control point on\n                        // the previous command relative to the current point.\"\n                        controlX = current[1];\n                        controlY = current[2];\n                        break;\n\n                    case 'q': // quadraticCurveTo, relative\n                        // transform to absolute x,y\n                        tempX = x + current[3];\n                        tempY = y + current[4];\n                        controlX = x + current[1];\n                        controlY = y + current[2];\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            controlX,\n                            controlY,\n                            controlX,\n                            controlY,\n                            tempX,\n                            tempY\n                        );\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'Q': // quadraticCurveTo, absolute\n                        controlX = current[1];\n                        controlY = current[2];\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            controlX,\n                            controlY,\n                            controlX,\n                            controlY,\n                            current[3],\n                            current[4]\n                        );\n                        x = current[3];\n                        y = current[4];\n                        break;\n\n                    case 't': // shorthand quadraticCurveTo, relative\n                        // transform to absolute x,y\n                        tempX = x + current[1];\n                        tempY = y + current[2];\n                        if (previous[0].match(/[QqTt]/) === null) {\n                            // If there is no previous command or if the previous command was not a Q, q, T or t,\n                            // assume the control point is coincident with the current point\n                            controlX = x;\n                            controlY = y;\n                        }\n                        else if (previous[0] === 't') {\n                            // calculate reflection of previous control points for t\n                            controlX = 2 * x - tempControlX;\n                            controlY = 2 * y - tempControlY;\n                        }\n                        else if (previous[0] === 'q') {\n                            // calculate reflection of previous control points for q\n                            controlX = 2 * x - controlX;\n                            controlY = 2 * y - controlY;\n                        }\n\n                        tempControlX = controlX;\n                        tempControlY = controlY;\n\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            controlX,\n                            controlY,\n                            controlX,\n                            controlY,\n                            tempX,\n                            tempY\n                        );\n                        x = tempX;\n                        y = tempY;\n                        controlX = x + current[1];\n                        controlY = y + current[2];\n                        break;\n\n                    case 'T':\n                        tempX = current[1];\n                        tempY = current[2];\n                        // calculate reflection of previous control points\n                        controlX = 2 * x - controlX;\n                        controlY = 2 * y - controlY;\n                        bounds = fabric.util.getBoundsOfCurve(x, y,\n                            controlX,\n                            controlY,\n                            controlX,\n                            controlY,\n                            tempX,\n                            tempY\n                        );\n                        x = tempX;\n                        y = tempY;\n                        break;\n\n                    case 'a':\n                        // TODO: optimize this\n                        bounds = fabric.util.getBoundsOfArc(x, y,\n                            current[1],\n                            current[2],\n                            current[3],\n                            current[4],\n                            current[5],\n                                current[6] + x,\n                                current[7] + y\n                        );\n                        x += current[6];\n                        y += current[7];\n                        break;\n\n                    case 'A':\n                        // TODO: optimize this\n                        bounds = fabric.util.getBoundsOfArc(x, y,\n                            current[1],\n                            current[2],\n                            current[3],\n                            current[4],\n                            current[5],\n                            current[6],\n                            current[7]\n                        );\n                        x = current[6];\n                        y = current[7];\n                        break;\n\n                    case 'z':\n                    case 'Z':\n                        x = subpathStartX;\n                        y = subpathStartY;\n                        break;\n                }\n                previous = current;\n                bounds.forEach(function (point) {\n                    aX.push(point.x);\n                    aY.push(point.y);\n                });\n                aX.push(x);\n                aY.push(y);\n            }\n\n            var minX = min(aX),\n                minY = min(aY),\n                maxX = max(aX),\n                maxY = max(aY),\n                deltaX = maxX - minX,\n                deltaY = maxY - minY,\n\n                o = {\n                    left: minX,\n                    top: minY,\n                    width: deltaX,\n                    height: deltaY\n                };\n\n            return o;\n        }\n    });\n\n    /**\n     * Creates an instance of fabric.Path from an object\n     * @static\n     * @memberOf fabric.Path\n     * @param {Object} object\n     * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n     */\n    fabric.Path.fromObject = function(object, callback) {\n        if (typeof object.path === 'string') {\n            fabric.loadSVGFromURL(object.path, function (elements) {\n                var path = elements[0],\n                    pathUrl = object.path;\n\n                delete object.path;\n\n                fabric.util.object.extend(path, object);\n                path.setSourcePath(pathUrl);\n\n                callback(path);\n            });\n        }\n        else {\n            callback(new fabric.Path(object.path, object));\n        }\n    };\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`)\n     * @static\n     * @memberOf fabric.Path\n     * @see http://www.w3.org/TR/SVG/paths.html#PathElement\n     */\n    fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(['d']);\n\n    /**\n     * Creates an instance of fabric.Path from an SVG <path> element\n     * @static\n     * @memberOf fabric.Path\n     * @param {SVGElement} element to parse\n     * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n     * @param {Object} [options] Options object\n     */\n    fabric.Path.fromElement = function(element, callback, options) {\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES);\n        callback && callback(new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options)));\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Indicates that instances of this type are async\n     * @static\n     * @memberOf fabric.Path\n     * @type Boolean\n     * @default\n     */\n    fabric.Path.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        invoke = fabric.util.array.invoke,\n        parentToObject = fabric.Object.prototype.toObject;\n\n    if (fabric.PathGroup) {\n        fabric.warn('fabric.PathGroup is already defined');\n        return;\n    }\n\n    /**\n     * Path group class\n     * @class fabric.PathGroup\n     * @extends fabric.Path\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-1/#path_and_pathgroup}\n     * @see {@link fabric.PathGroup#initialize} for constructor definition\n     */\n    fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @lends fabric.PathGroup.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'path-group',\n\n        /**\n         * Fill value\n         * @type String\n         * @default\n         */\n        fill: '',\n\n        /**\n         * Constructor\n         * @param {Array} paths\n         * @param {Object} [options] Options object\n         * @return {fabric.PathGroup} thisArg\n         */\n        initialize: function(paths, options) {\n\n            options = options || { };\n            this.paths = paths || [ ];\n\n            for (var i = this.paths.length; i--; ) {\n                this.paths[i].group = this;\n            }\n\n            this.setOptions(options);\n\n            if (options.widthAttr) {\n                this.scaleX = options.widthAttr / options.width;\n            }\n            if (options.heightAttr) {\n                this.scaleY = options.heightAttr / options.height;\n            }\n\n            this.setCoords();\n\n            if (options.sourcePath) {\n                this.setSourcePath(options.sourcePath);\n            }\n        },\n\n        /**\n         * Renders this group on a specified context\n         * @param {CanvasRenderingContext2D} ctx Context to render this instance on\n         */\n        render: function(ctx) {\n            // do not render if object is not visible\n            if (!this.visible) {\n                return;\n            }\n\n            ctx.save();\n\n            var m = this.transformMatrix;\n\n            if (m) {\n                ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n            }\n            this.transform(ctx);\n\n            this._setShadow(ctx);\n            this.clipTo && fabric.util.clipContext(this, ctx);\n            for (var i = 0, l = this.paths.length; i < l; ++i) {\n                this.paths[i].render(ctx, true);\n            }\n            this.clipTo && ctx.restore();\n            this._removeShadow(ctx);\n            ctx.restore();\n        },\n\n        /**\n         * Sets certain property to a certain value\n         * @param {String} prop\n         * @param {Any} value\n         * @return {fabric.PathGroup} thisArg\n         */\n        _set: function(prop, value) {\n\n            if (prop === 'fill' && value && this.isSameColor()) {\n                var i = this.paths.length;\n                while (i--) {\n                    this.paths[i]._set(prop, value);\n                }\n            }\n\n            return this.callSuper('_set', prop, value);\n        },\n\n        /**\n         * Returns object representation of this path group\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            var o = extend(parentToObject.call(this, propertiesToInclude), {\n                paths: invoke(this.getObjects(), 'toObject', propertiesToInclude)\n            });\n            if (this.sourcePath) {\n                o.sourcePath = this.sourcePath;\n            }\n            return o;\n        },\n\n        /**\n         * Returns dataless object representation of this path group\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} dataless object representation of an instance\n         */\n        toDatalessObject: function(propertiesToInclude) {\n            var o = this.toObject(propertiesToInclude);\n            if (this.sourcePath) {\n                o.paths = this.sourcePath;\n            }\n            return o;\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var objects = this.getObjects(),\n                translatePart = 'translate(' + this.left + ' ' + this.top + ')',\n                markup = [\n                    //jscs:disable validateIndentation\n                    '<g ',\n                    'style=\"', this.getSvgStyles(), '\" ',\n                    'transform=\"', translatePart, this.getSvgTransform(), '\" ',\n                    '>\\n'\n                    //jscs:enable validateIndentation\n                ];\n\n            for (var i = 0, len = objects.length; i < len; i++) {\n                markup.push(objects[i].toSVG(reviver));\n            }\n            markup.push('</g>\\n');\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns a string representation of this path group\n         * @return {String} string representation of an object\n         */\n        toString: function() {\n            return '#<fabric.PathGroup (' + this.complexity() +\n                '): { top: ' + this.top + ', left: ' + this.left + ' }>';\n        },\n\n        /**\n         * Returns true if all paths in this group are of same color\n         * @return {Boolean} true if all paths are of the same color (`fill`)\n         */\n        isSameColor: function() {\n            var firstPathFill = (this.getObjects()[0].get('fill') || '').toLowerCase();\n            return this.getObjects().every(function(path) {\n                return (path.get('fill') || '').toLowerCase() === firstPathFill;\n            });\n        },\n\n        /**\n         * Returns number representation of object's complexity\n         * @return {Number} complexity\n         */\n        complexity: function() {\n            return this.paths.reduce(function(total, path) {\n                return total + ((path && path.complexity) ? path.complexity() : 0);\n            }, 0);\n        },\n\n        /**\n         * Returns all paths in this path group\n         * @return {Array} array of path objects included in this path group\n         */\n        getObjects: function() {\n            return this.paths;\n        }\n    });\n\n    /**\n     * Creates fabric.PathGroup instance from an object representation\n     * @static\n     * @memberOf fabric.PathGroup\n     * @param {Object} object Object to create an instance from\n     * @param {Function} callback Callback to invoke when an fabric.PathGroup instance is created\n     */\n    fabric.PathGroup.fromObject = function(object, callback) {\n        if (typeof object.paths === 'string') {\n            fabric.loadSVGFromURL(object.paths, function (elements) {\n\n                var pathUrl = object.paths;\n                delete object.paths;\n\n                var pathGroup = fabric.util.groupSVGElements(elements, object, pathUrl);\n\n                callback(pathGroup);\n            });\n        }\n        else {\n            fabric.util.enlivenObjects(object.paths, function(enlivenedObjects) {\n                delete object.paths;\n                callback(new fabric.PathGroup(enlivenedObjects, object));\n            });\n        }\n    };\n\n    /**\n     * Indicates that instances of this type are async\n     * @static\n     * @memberOf fabric.PathGroup\n     * @type Boolean\n     * @default\n     */\n    fabric.PathGroup.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        min = fabric.util.array.min,\n        max = fabric.util.array.max,\n        invoke = fabric.util.array.invoke;\n\n    if (fabric.Group) {\n        return;\n    }\n\n    // lock-related properties, for use in fabric.Group#get\n    // to enable locking behavior on group\n    // when one of its objects has lock-related properties set\n    var _lockProperties = {\n        lockMovementX:  true,\n        lockMovementY:  true,\n        lockRotation:   true,\n        lockScalingX:   true,\n        lockScalingY:   true,\n        lockUniScaling: true\n    };\n\n    /**\n     * Group class\n     * @class fabric.Group\n     * @extends fabric.Object\n     * @mixes fabric.Collection\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3/#groups}\n     * @see {@link fabric.Group#initialize} for constructor definition\n     */\n    fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, /** @lends fabric.Group.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'group',\n\n        /**\n         * Constructor\n         * @param {Object} objects Group objects\n         * @param {Object} [options] Options object\n         * @return {Object} thisArg\n         */\n        initialize: function(objects, options) {\n            options = options || { };\n\n            this._objects = objects || [];\n            for (var i = this._objects.length; i--; ) {\n                this._objects[i].group = this;\n            }\n\n            this.originalState = { };\n            this.callSuper('initialize');\n\n            this._calcBounds();\n            this._updateObjectsCoords();\n\n            if (options) {\n                extend(this, options);\n            }\n\n            this.setCoords();\n            this.saveCoords();\n        },\n\n        /**\n         * @private\n         */\n        _updateObjectsCoords: function() {\n            this.forEachObject(this._updateObjectCoords, this);\n        },\n\n        /**\n         * @private\n         */\n        _updateObjectCoords: function(object) {\n            var objectLeft = object.getLeft(),\n                objectTop = object.getTop();\n\n            object.set({\n                originalLeft: objectLeft,\n                originalTop: objectTop,\n                left: objectLeft - this.left,\n                top: objectTop - this.top\n            });\n\n            object.setCoords();\n\n            // do not display corners of objects enclosed in a group\n            object.__origHasControls = object.hasControls;\n            object.hasControls = false;\n        },\n\n        /**\n         * Returns string represenation of a group\n         * @return {String}\n         */\n        toString: function() {\n            return '#<fabric.Group: (' + this.complexity() + ')>';\n        },\n\n        /**\n         * Adds an object to a group; Then recalculates group's dimension, position.\n         * @param {Object} object\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        addWithUpdate: function(object) {\n            this._restoreObjectsState();\n            if (object) {\n                this._objects.push(object);\n                object.group = this;\n            }\n            // since _restoreObjectsState set objects inactive\n            this.forEachObject(this._setObjectActive, this);\n            this._calcBounds();\n            this._updateObjectsCoords();\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _setObjectActive: function(object) {\n            object.set('active', true);\n            object.group = this;\n        },\n\n        /**\n         * Removes an object from a group; Then recalculates group's dimension, position.\n         * @param {Object} object\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        removeWithUpdate: function(object) {\n            this._moveFlippedObject(object);\n            this._restoreObjectsState();\n\n            // since _restoreObjectsState set objects inactive\n            this.forEachObject(this._setObjectActive, this);\n\n            this.remove(object);\n            this._calcBounds();\n            this._updateObjectsCoords();\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _onObjectAdded: function(object) {\n            object.group = this;\n        },\n\n        /**\n         * @private\n         */\n        _onObjectRemoved: function(object) {\n            delete object.group;\n            object.set('active', false);\n        },\n\n        /**\n         * Properties that are delegated to group objects when reading/writing\n         * @param {Object} delegatedProperties\n         */\n        delegatedProperties: {\n            fill:             true,\n            opacity:          true,\n            fontFamily:       true,\n            fontWeight:       true,\n            fontSize:         true,\n            fontStyle:        true,\n            lineHeight:       true,\n            textDecoration:   true,\n            textAlign:        true,\n            backgroundColor:  true\n        },\n\n        /**\n         * @private\n         */\n        _set: function(key, value) {\n            if (key in this.delegatedProperties) {\n                var i = this._objects.length;\n                this[key] = value;\n                while (i--) {\n                    this._objects[i].set(key, value);\n                }\n            }\n            else {\n                this[key] = value;\n            }\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return extend(this.callSuper('toObject', propertiesToInclude), {\n                objects: invoke(this._objects, 'toObject', propertiesToInclude)\n            });\n        },\n\n        /**\n         * Renders instance on a given context\n         * @param {CanvasRenderingContext2D} ctx context to render instance on\n         */\n        render: function(ctx) {\n            // do not render if object is not visible\n            if (!this.visible) {\n                return;\n            }\n\n            ctx.save();\n            this.clipTo && fabric.util.clipContext(this, ctx);\n\n            // the array is now sorted in order of highest first, so start from end\n            for (var i = 0, len = this._objects.length; i < len; i++) {\n                this._renderObject(this._objects[i], ctx);\n            }\n\n            this.clipTo && ctx.restore();\n\n            ctx.restore();\n        },\n\n        /**\n         * Renders controls and borders for the object\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        _renderControls: function(ctx, noTransform) {\n            this.callSuper('_renderControls', ctx, noTransform);\n            for (var i = 0, len = this._objects.length; i < len; i++) {\n                this._objects[i]._renderControls(ctx);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _renderObject: function(object, ctx) {\n            var originalHasRotatingPoint = object.hasRotatingPoint;\n\n            // do not render if object is not visible\n            if (!object.visible) {\n                return;\n            }\n\n            object.hasRotatingPoint = false;\n\n            object.render(ctx);\n\n            object.hasRotatingPoint = originalHasRotatingPoint;\n        },\n\n        /**\n         * Retores original state of each of group objects (original state is that which was before group was created).\n         * @private\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        _restoreObjectsState: function() {\n            this._objects.forEach(this._restoreObjectState, this);\n            return this;\n        },\n\n        /**\n         * Moves a flipped object to the position where it's displayed\n         * @private\n         * @param {fabric.Object} object\n         * @return {fabric.Group} thisArg\n         */\n        _moveFlippedObject: function(object) {\n            var oldOriginX = object.get('originX'),\n                oldOriginY = object.get('originY'),\n                center = object.getCenterPoint();\n\n            object.set({\n                originX: 'center',\n                originY: 'center',\n                left: center.x,\n                top: center.y\n            });\n\n            this._toggleFlipping(object);\n\n            var newOrigin = object.getPointByOrigin(oldOriginX, oldOriginY);\n\n            object.set({\n                originX: oldOriginX,\n                originY: oldOriginY,\n                left: newOrigin.x,\n                top: newOrigin.y\n            });\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _toggleFlipping: function(object) {\n            if (this.flipX) {\n                object.toggle('flipX');\n                object.set('left', -object.get('left'));\n                object.setAngle(-object.getAngle());\n            }\n            if (this.flipY) {\n                object.toggle('flipY');\n                object.set('top', -object.get('top'));\n                object.setAngle(-object.getAngle());\n            }\n        },\n\n        /**\n         * Restores original state of a specified object in group\n         * @private\n         * @param {fabric.Object} object\n         * @return {fabric.Group} thisArg\n         */\n        _restoreObjectState: function(object) {\n            this._setObjectPosition(object);\n\n            object.setCoords();\n            object.hasControls = object.__origHasControls;\n            delete object.__origHasControls;\n            object.set('active', false);\n            object.setCoords();\n            delete object.group;\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _setObjectPosition: function(object) {\n            var groupLeft = this.getLeft(),\n                groupTop = this.getTop(),\n                rotated = this._getRotatedLeftTop(object);\n\n            object.set({\n                angle: object.getAngle() + this.getAngle(),\n                left: groupLeft + rotated.left,\n                top: groupTop + rotated.top,\n                scaleX: object.get('scaleX') * this.get('scaleX'),\n                scaleY: object.get('scaleY') * this.get('scaleY')\n            });\n        },\n\n        /**\n         * @private\n         */\n        _getRotatedLeftTop: function(object) {\n            var groupAngle = this.getAngle() * (Math.PI / 180);\n            return {\n                left: (-Math.sin(groupAngle) * object.getTop() * this.get('scaleY') +\n                    Math.cos(groupAngle) * object.getLeft() * this.get('scaleX')),\n\n                top:  (Math.cos(groupAngle) * object.getTop() * this.get('scaleY') +\n                    Math.sin(groupAngle) * object.getLeft() * this.get('scaleX'))\n            };\n        },\n\n        /**\n         * Destroys a group (restoring state of its objects)\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        destroy: function() {\n            this._objects.forEach(this._moveFlippedObject, this);\n            return this._restoreObjectsState();\n        },\n\n        /**\n         * Saves coordinates of this instance (to be used together with `hasMoved`)\n         * @saveCoords\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        saveCoords: function() {\n            this._originalLeft = this.get('left');\n            this._originalTop = this.get('top');\n            return this;\n        },\n\n        /**\n         * Checks whether this group was moved (since `saveCoords` was called last)\n         * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called)\n         */\n        hasMoved: function() {\n            return this._originalLeft !== this.get('left') ||\n                this._originalTop !== this.get('top');\n        },\n\n        /**\n         * Sets coordinates of all group objects\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        setObjectsCoords: function() {\n            this.forEachObject(function(object) {\n                object.setCoords();\n            });\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _calcBounds: function(onlyWidthHeight) {\n            var aX = [],\n                aY = [],\n                o;\n\n            for (var i = 0, len = this._objects.length; i < len; ++i) {\n                o = this._objects[i];\n                o.setCoords();\n                for (var prop in o.oCoords) {\n                    aX.push(o.oCoords[prop].x);\n                    aY.push(o.oCoords[prop].y);\n                }\n            }\n\n            this.set(this._getBounds(aX, aY, onlyWidthHeight));\n        },\n\n        /**\n         * @private\n         */\n        _getBounds: function(aX, aY, onlyWidthHeight) {\n            var ivt = fabric.util.invertTransform(this.getViewportTransform()),\n                minXY = fabric.util.transformPoint(new fabric.Point(min(aX), min(aY)), ivt),\n                maxXY = fabric.util.transformPoint(new fabric.Point(max(aX), max(aY)), ivt),\n                obj = {\n                    width: (maxXY.x - minXY.x) || 0,\n                    height: (maxXY.y - minXY.y) || 0\n                };\n\n            if (!onlyWidthHeight) {\n                obj.left = (minXY.x + maxXY.x) / 2 || 0;\n                obj.top = (minXY.y + maxXY.y) / 2 || 0;\n            }\n            return obj;\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = [\n                //jscs:disable validateIndentation\n                '<g ',\n                'transform=\"', this.getSvgTransform(),\n                '\">\\n'\n                //jscs:enable validateIndentation\n            ];\n\n            for (var i = 0, len = this._objects.length; i < len; i++) {\n                markup.push(this._objects[i].toSVG(reviver));\n            }\n\n            markup.push('</g>\\n');\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns requested property\n         * @param {String} prop Property to get\n         * @return {Any}\n         */\n        get: function(prop) {\n            if (prop in _lockProperties) {\n                if (this[prop]) {\n                    return this[prop];\n                }\n                else {\n                    for (var i = 0, len = this._objects.length; i < len; i++) {\n                        if (this._objects[i][prop]) {\n                            return true;\n                        }\n                    }\n                    return false;\n                }\n            }\n            else {\n                if (prop in this.delegatedProperties) {\n                    return this._objects[0] && this._objects[0].get(prop);\n                }\n                return this[prop];\n            }\n        }\n    });\n\n    /**\n     * Returns {@link fabric.Group} instance from an object representation\n     * @static\n     * @memberOf fabric.Group\n     * @param {Object} object Object to create a group from\n     * @param {Function} [callback] Callback to invoke when an group instance is created\n     * @return {fabric.Group} An instance of fabric.Group\n     */\n    fabric.Group.fromObject = function(object, callback) {\n        fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) {\n            delete object.objects;\n            callback && callback(new fabric.Group(enlivenedObjects, object));\n        });\n    };\n\n    /**\n     * Indicates that instances of this type are async\n     * @static\n     * @memberOf fabric.Group\n     * @type Boolean\n     * @default\n     */\n    fabric.Group.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var extend = fabric.util.object.extend;\n\n    if (!global.fabric) {\n        global.fabric = { };\n    }\n\n    if (global.fabric.Image) {\n        fabric.warn('fabric.Image is already defined.');\n        return;\n    }\n\n    /**\n     * Image class\n     * @class fabric.Image\n     * @extends fabric.Object\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-1/#images}\n     * @see {@link fabric.Image#initialize} for constructor definition\n     */\n    fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'image',\n\n        /**\n         * crossOrigin value (one of \"\", \"anonymous\", \"allow-credentials\")\n         * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes\n         * @type String\n         * @default\n         */\n        crossOrigin: '',\n\n        /**\n         * Constructor\n         * @param {HTMLImageElement | String} element Image element\n         * @param {Object} [options] Options object\n         * @return {fabric.Image} thisArg\n         */\n        initialize: function(element, options) {\n            options || (options = { });\n\n            this.filters = [ ];\n\n            this.callSuper('initialize', options);\n\n            this._initElement(element, options);\n            this._initConfig(options);\n\n            if (options.filters) {\n                this.filters = options.filters;\n                this.applyFilters();\n            }\n        },\n\n        /**\n         * Returns image element which this instance if based on\n         * @return {HTMLImageElement} Image element\n         */\n        getElement: function() {\n            return this._element;\n        },\n\n        /**\n         * Sets image element for this instance to a specified one.\n         * If filters defined they are applied to new image.\n         * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area.\n         * @param {HTMLImageElement} element\n         * @param {Function} [callback] Callback is invoked when all filters have been applied and new image is generated\n         * @return {fabric.Image} thisArg\n         * @chainable\n         */\n        setElement: function(element, callback) {\n            this._element = element;\n            this._originalElement = element;\n            this._initConfig();\n\n            if (this.filters.length !== 0) {\n                this.applyFilters(callback);\n            }\n\n            return this;\n        },\n\n        /**\n         * Sets crossOrigin value (on an instance and corresponding image element)\n         * @return {fabric.Image} thisArg\n         * @chainable\n         */\n        setCrossOrigin: function(value) {\n            this.crossOrigin = value;\n            this._element.crossOrigin = value;\n\n            return this;\n        },\n\n        /**\n         * Returns original size of an image\n         * @return {Object} Object with \"width\" and \"height\" properties\n         */\n        getOriginalSize: function() {\n            var element = this.getElement();\n            return {\n                width: element.width,\n                height: element.height\n            };\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _stroke: function(ctx) {\n            ctx.save();\n            this._setStrokeStyles(ctx);\n            ctx.beginPath();\n            ctx.strokeRect(-this.width / 2, -this.height / 2, this.width, this.height);\n            ctx.closePath();\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderDashedStroke: function(ctx) {\n            var x = -this.width / 2,\n                y = -this.height / 2,\n                w = this.width,\n                h = this.height;\n\n            ctx.save();\n            this._setStrokeStyles(ctx);\n\n            ctx.beginPath();\n            fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);\n            fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);\n            ctx.closePath();\n            ctx.restore();\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return extend(this.callSuper('toObject', propertiesToInclude), {\n                src: this._originalElement.src || this._originalElement._src,\n                filters: this.filters.map(function(filterObj) {\n                    return filterObj && filterObj.toObject();\n                }),\n                crossOrigin: this.crossOrigin\n            });\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = [], x = -this.width / 2, y = -this.height / 2;\n            if (this.group && this.group.type === 'path-group') {\n                x = this.left;\n                y = this.top;\n            }\n            markup.push(\n                '<g transform=\"', this.getSvgTransform(), this.getSvgTransformMatrix(), '\">\\n',\n                '<image xlink:href=\"', this.getSvgSrc(),\n                '\" x=\"', x, '\" y=\"', y,\n                '\" style=\"', this.getSvgStyles(),\n                // we're essentially moving origin of transformation from top/left corner to the center of the shape\n                // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left\n                // so that object's center aligns with container's left/top\n                '\" width=\"', this.width,\n                '\" height=\"', this.height,\n                '\" preserveAspectRatio=\"none\"',\n                '></image>\\n'\n            );\n\n            if (this.stroke || this.strokeDashArray) {\n                var origFill = this.fill;\n                this.fill = null;\n                markup.push(\n                    '<rect ',\n                    'x=\"', x, '\" y=\"', y,\n                    '\" width=\"', this.width, '\" height=\"', this.height,\n                    '\" style=\"', this.getSvgStyles(),\n                    '\"/>\\n'\n                );\n                this.fill = origFill;\n            }\n\n            markup.push('</g>\\n');\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Returns source of an image\n         * @return {String} Source of an image\n         */\n        getSrc: function() {\n            if (this.getElement()) {\n                return this.getElement().src || this.getElement()._src;\n            }\n        },\n\n        /**\n         * Returns string representation of an instance\n         * @return {String} String representation of an instance\n         */\n        toString: function() {\n            return '#<fabric.Image: { src: \"' + this.getSrc() + '\" }>';\n        },\n\n        /**\n         * Returns a clone of an instance\n         * @param {Function} callback Callback is invoked with a clone as a first argument\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        clone: function(callback, propertiesToInclude) {\n            this.constructor.fromObject(this.toObject(propertiesToInclude), callback);\n        },\n\n        /**\n         * Applies filters assigned to this image (from \"filters\" array)\n         * @mthod applyFilters\n         * @param {Function} callback Callback is invoked when all filters have been applied and new image is generated\n         * @return {fabric.Image} thisArg\n         * @chainable\n         */\n        applyFilters: function(callback) {\n\n            if (!this._originalElement) {\n                return;\n            }\n\n            if (this.filters.length === 0) {\n                this._element = this._originalElement;\n                callback && callback();\n                return;\n            }\n\n            var imgEl = this._originalElement,\n                canvasEl = fabric.util.createCanvasElement(),\n                replacement = fabric.util.createImage(),\n                _this = this;\n\n            canvasEl.width = imgEl.width;\n            canvasEl.height = imgEl.height;\n\n            canvasEl.getContext('2d').drawImage(imgEl, 0, 0, imgEl.width, imgEl.height);\n\n            this.filters.forEach(function(filter) {\n                filter && filter.applyTo(canvasEl);\n            });\n\n            /** @ignore */\n\n            replacement.width = imgEl.width;\n            replacement.height = imgEl.height;\n\n            if (fabric.isLikelyNode) {\n                replacement.src = canvasEl.toBuffer(undefined, fabric.Image.pngCompression);\n\n                // onload doesn't fire in some node versions, so we invoke callback manually\n                _this._element = replacement;\n                callback && callback();\n            }\n            else {\n                replacement.onload = function() {\n                    _this._element = replacement;\n                    callback && callback();\n                    replacement.onload = canvasEl = imgEl = null;\n                };\n                replacement.src = canvasEl.toDataURL('image/png');\n            }\n\n            return this;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx, noTransform) {\n            this._element &&\n            ctx.drawImage(\n                this._element,\n                noTransform ? this.left : -this.width/2,\n                noTransform ? this.top : -this.height/2,\n                this.width,\n                this.height\n            );\n            this._renderStroke(ctx);\n        },\n\n        /**\n         * @private\n         */\n        _resetWidthHeight: function() {\n            var element = this.getElement();\n\n            this.set('width', element.width);\n            this.set('height', element.height);\n        },\n\n        /**\n         * The Image class's initialization method. This method is automatically\n         * called by the constructor.\n         * @private\n         * @param {HTMLImageElement|String} element The element representing the image\n         */\n        _initElement: function(element) {\n            this.setElement(fabric.util.getById(element));\n            fabric.util.addClass(this.getElement(), fabric.Image.CSS_CANVAS);\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Options object\n         */\n        _initConfig: function(options) {\n            options || (options = { });\n            this.setOptions(options);\n            this._setWidthHeight(options);\n            if (this._element && this.crossOrigin) {\n                this._element.crossOrigin = this.crossOrigin;\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} object Object with filters property\n         * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created\n         */\n        _initFilters: function(object, callback) {\n            if (object.filters && object.filters.length) {\n                fabric.util.enlivenObjects(object.filters, function(enlivenedObjects) {\n                    callback && callback(enlivenedObjects);\n                }, 'fabric.Image.filters');\n            }\n            else {\n                callback && callback();\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} [options] Object with width/height properties\n         */\n        _setWidthHeight: function(options) {\n            this.width = 'width' in options\n                ? options.width\n                : (this.getElement()\n                ? this.getElement().width || 0\n                : 0);\n\n            this.height = 'height' in options\n                ? options.height\n                : (this.getElement()\n                ? this.getElement().height || 0\n                : 0);\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /**\n     * Default CSS class name for canvas\n     * @static\n     * @type String\n     * @default\n     */\n    fabric.Image.CSS_CANVAS = 'canvas-img';\n\n    /**\n     * Alias for getSrc\n     * @static\n     */\n    fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;\n\n    /**\n     * Creates an instance of fabric.Image from its object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @param {Function} [callback] Callback to invoke when an image instance is created\n     */\n    fabric.Image.fromObject = function(object, callback) {\n        fabric.util.loadImage(object.src, function(img) {\n            fabric.Image.prototype._initFilters.call(object, object, function(filters) {\n                object.filters = filters || [ ];\n                var instance = new fabric.Image(img, object);\n                callback && callback(instance);\n            });\n        }, null, object.crossOrigin);\n    };\n\n    /**\n     * Creates an instance of fabric.Image from an URL string\n     * @static\n     * @param {String} url URL to create an image from\n     * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument)\n     * @param {Object} [imgOptions] Options object\n     */\n    fabric.Image.fromURL = function(url, callback, imgOptions) {\n        fabric.util.loadImage(url, function(img) {\n            callback(new fabric.Image(img, imgOptions));\n        }, null, imgOptions && imgOptions.crossOrigin);\n    };\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement})\n     * @static\n     * @see {@link http://www.w3.org/TR/SVG/struct.html#ImageElement}\n     */\n    fabric.Image.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y width height xlink:href'.split(' '));\n\n    /**\n     * Returns {@link fabric.Image} instance from an SVG element\n     * @static\n     * @param {SVGElement} element Element to parse\n     * @param {Function} callback Callback to execute when fabric.Image object is created\n     * @param {Object} [options] Options object\n     * @return {fabric.Image} Instance of fabric.Image\n     */\n    fabric.Image.fromElement = function(element, callback, options) {\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES);\n\n        fabric.Image.fromURL(parsedAttributes['xlink:href'], callback,\n            extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Indicates that instances of this type are async\n     * @static\n     * @type Boolean\n     * @default\n     */\n    fabric.Image.async = true;\n\n    /**\n     * Indicates compression level used when generating PNG under Node (in applyFilters). Any of 0-9\n     * @static\n     * @type Number\n     * @default\n     */\n    fabric.Image.pngCompression = 1;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * @private\n     * @return {Number} angle value\n     */\n    _getAngleValueForStraighten: function() {\n        var angle = this.getAngle() % 360;\n        if (angle > 0) {\n            return Math.round((angle - 1) / 90) * 90;\n        }\n        return Math.round(angle / 90) * 90;\n    },\n\n    /**\n     * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    straighten: function() {\n        this.setAngle(this._getAngleValueForStraighten());\n        return this;\n    },\n\n    /**\n     * Same as {@link fabric.Object.prototype.straighten} but with animation\n     * @param {Object} callbacks Object with callback functions\n     * @param {Function} [callbacks.onComplete] Invoked on completion\n     * @param {Function} [callbacks.onChange] Invoked on every step of animation\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    fxStraighten: function(callbacks) {\n        callbacks = callbacks || { };\n\n        var empty = function() { },\n            onComplete = callbacks.onComplete || empty,\n            onChange = callbacks.onChange || empty,\n            _this = this;\n\n        fabric.util.animate({\n            startValue: this.get('angle'),\n            endValue: this._getAngleValueForStraighten(),\n            duration: this.FX_DURATION,\n            onChange: function(value) {\n                _this.setAngle(value);\n                onChange();\n            },\n            onComplete: function() {\n                _this.setCoords();\n                onComplete();\n            },\n            onStart: function() {\n                _this.set('active', false);\n            }\n        });\n\n        return this;\n    }\n});\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Straightens object, then rerenders canvas\n     * @param {fabric.Object} object Object to straighten\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    straightenObject: function (object) {\n        object.straighten();\n        this.renderAll();\n        return this;\n    },\n\n    /**\n     * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated\n     * @param {fabric.Object} object Object to straighten\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    fxStraightenObject: function (object) {\n        object.fxStraighten({\n            onChange: this.renderAll.bind(this)\n        });\n        return this;\n    }\n});\n\n\n/**\n * @namespace fabric.Image.filters\n * @memberOf fabric.Image\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#image_filters}\n * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n */\nfabric.Image.filters = fabric.Image.filters || { };\n\n/**\n * Root filter class from which all filter classes inherit from\n * @class fabric.Image.filters.BaseFilter\n * @memberOf fabric.Image.filters\n */\nfabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Image.filters.BaseFilter.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'BaseFilter',\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n        return { type: this.type };\n    },\n\n    /**\n     * Returns a JSON representation of an instance\n     * @return {Object} JSON\n     */\n    toJSON: function() {\n        // delegate, not alias\n        return this.toObject();\n    }\n});\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Brightness filter class\n     * @class fabric.Image.filters.Brightness\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.Brightness#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Brightness({\n   *   brightness: 200\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Brightness = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Brightness',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Brightness.prototype\n         * @param {Object} [options] Options object\n         * @param {Number} [options.brightness=0] Value to brighten the image up (0..255)\n         */\n        initialize: function(options) {\n            options = options || { };\n            this.brightness = options.brightness || 0;\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                brightness = this.brightness;\n\n            for (var i = 0, len = data.length; i < len; i += 4) {\n                data[i] += brightness;\n                data[i + 1] += brightness;\n                data[i + 2] += brightness;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                brightness: this.brightness\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness\n     */\n    fabric.Image.filters.Brightness.fromObject = function(object) {\n        return new fabric.Image.filters.Brightness(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Adapted from <a href=\"http://www.html5rocks.com/en/tutorials/canvas/imagefilters/\">html5rocks article</a>\n     * @class fabric.Image.filters.Convolute\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.Convolute#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example <caption>Sharpen filter</caption>\n     * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 0, -1,  0,\n   *            -1,  5, -1,\n   *             0, -1,  0 ]\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     * @example <caption>Blur filter</caption>\n     * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 1/9, 1/9, 1/9,\n   *             1/9, 1/9, 1/9,\n   *             1/9, 1/9, 1/9 ]\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     * @example <caption>Emboss filter</caption>\n     * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 1,   1,  1,\n   *             1, 0.7, -1,\n   *            -1,  -1, -1 ]\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     * @example <caption>Emboss filter with opaqueness</caption>\n     * var filter = new fabric.Image.filters.Convolute({\n   *   opaque: true,\n   *   matrix: [ 1,   1,  1,\n   *             1, 0.7, -1,\n   *            -1,  -1, -1 ]\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Convolute = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Convolute',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Convolute.prototype\n         * @param {Object} [options] Options object\n         * @param {Boolean} [options.opaque=false] Opaque value (true/false)\n         * @param {Array} [options.matrix] Filter matrix\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.opaque = options.opaque;\n            this.matrix = options.matrix || [\n                0, 0, 0,\n                0, 1, 0,\n                0, 0, 0\n            ];\n\n            var canvasEl = fabric.util.createCanvasElement();\n            this.tmpCtx = canvasEl.getContext('2d');\n        },\n\n        /**\n         * @private\n         */\n        _createImageData: function(w, h) {\n            return this.tmpCtx.createImageData(w, h);\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n\n            var weights = this.matrix,\n                context = canvasEl.getContext('2d'),\n                pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n\n                side = Math.round(Math.sqrt(weights.length)),\n                halfSide = Math.floor(side/2),\n                src = pixels.data,\n                sw = pixels.width,\n                sh = pixels.height,\n\n            // pad output by the convolution matrix\n                w = sw,\n                h = sh,\n                output = this._createImageData(w, h),\n\n                dst = output.data,\n\n            // go through the destination image pixels\n                alphaFac = this.opaque ? 1 : 0;\n\n            for (var y = 0; y < h; y++) {\n                for (var x = 0; x < w; x++) {\n                    var sy = y,\n                        sx = x,\n                        dstOff = (y * w + x) * 4,\n                    // calculate the weighed sum of the source image pixels that\n                    // fall under the convolution matrix\n                        r = 0, g = 0, b = 0, a = 0;\n\n                    for (var cy = 0; cy < side; cy++) {\n                        for (var cx = 0; cx < side; cx++) {\n\n                            var scy = sy + cy - halfSide,\n                                scx = sx + cx - halfSide;\n\n                            /* jshint maxdepth:5 */\n                            if (scy < 0 || scy > sh || scx < 0 || scx > sw) {\n                                continue;\n                            }\n\n                            var srcOff = (scy * sw + scx) * 4,\n                                wt = weights[cy * side + cx];\n\n                            r += src[srcOff] * wt;\n                            g += src[srcOff + 1] * wt;\n                            b += src[srcOff + 2] * wt;\n                            a += src[srcOff + 3] * wt;\n                        }\n                    }\n                    dst[dstOff] = r;\n                    dst[dstOff + 1] = g;\n                    dst[dstOff + 2] = b;\n                    dst[dstOff + 3] = a + alphaFac * (255 - a);\n                }\n            }\n\n            context.putImageData(output, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                opaque: this.opaque,\n                matrix: this.matrix\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute\n     */\n    fabric.Image.filters.Convolute.fromObject = function(object) {\n        return new fabric.Image.filters.Convolute(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * GradientTransparency filter class\n     * @class fabric.Image.filters.GradientTransparency\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.GradientTransparency#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.GradientTransparency({\n   *   threshold: 200\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.GradientTransparency = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.GradientTransparency.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'GradientTransparency',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.GradientTransparency.prototype\n         * @param {Object} [options] Options object\n         * @param {Number} [options.threshold=100] Threshold value\n         */\n        initialize: function(options) {\n            options = options || { };\n            this.threshold = options.threshold || 100;\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                threshold = this.threshold,\n                total = data.length;\n\n            for (var i = 0, len = data.length; i < len; i += 4) {\n                data[i + 3] = threshold + 255 * (total - i) / total;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                threshold: this.threshold\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.GradientTransparency} Instance of fabric.Image.filters.GradientTransparency\n     */\n    fabric.Image.filters.GradientTransparency.fromObject = function(object) {\n        return new fabric.Image.filters.GradientTransparency(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { });\n\n    /**\n     * Grayscale image filter class\n     * @class fabric.Image.filters.Grayscale\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Grayscale();\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Grayscale = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Grayscale',\n\n        /**\n         * Applies filter to canvas element\n         * @memberOf fabric.Image.filters.Grayscale.prototype\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                len = imageData.width * imageData.height * 4,\n                index = 0,\n                average;\n\n            while (index < len) {\n                average = (data[index] + data[index + 1] + data[index + 2]) / 3;\n                data[index]     = average;\n                data[index + 1] = average;\n                data[index + 2] = average;\n                index += 4;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale\n     */\n    fabric.Image.filters.Grayscale.fromObject = function() {\n        return new fabric.Image.filters.Grayscale();\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { });\n\n    /**\n     * Invert filter class\n     * @class fabric.Image.filters.Invert\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Invert();\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Invert = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Invert',\n\n        /**\n         * Applies filter to canvas element\n         * @memberOf fabric.Image.filters.Invert.prototype\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                iLen = data.length, i;\n\n            for (i = 0; i < iLen; i+=4) {\n                data[i] = 255 - data[i];\n                data[i + 1] = 255 - data[i + 1];\n                data[i + 2] = 255 - data[i + 2];\n            }\n\n            context.putImageData(imageData, 0, 0);\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert\n     */\n    fabric.Image.filters.Invert.fromObject = function() {\n        return new fabric.Image.filters.Invert();\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Mask filter class\n     * See http://resources.aleph-1.com/mask/\n     * @class fabric.Image.filters.Mask\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.Mask#initialize} for constructor definition\n     */\n    fabric.Image.filters.Mask = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Mask.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Mask',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Mask.prototype\n         * @param {Object} [options] Options object\n         * @param {fabric.Image} [options.mask] Mask image object\n         * @param {Number} [options.channel=0] Rgb channel (0, 1, 2 or 3)\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.mask = options.mask;\n            this.channel = [ 0, 1, 2, 3 ].indexOf(options.channel) > -1 ? options.channel : 0;\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            if (!this.mask) {\n                return;\n            }\n\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                maskEl = this.mask.getElement(),\n                maskCanvasEl = fabric.util.createCanvasElement(),\n                channel = this.channel,\n                i,\n                iLen = imageData.width * imageData.height * 4;\n\n            maskCanvasEl.width = maskEl.width;\n            maskCanvasEl.height = maskEl.height;\n\n            maskCanvasEl.getContext('2d').drawImage(maskEl, 0, 0, maskEl.width, maskEl.height);\n\n            var maskImageData = maskCanvasEl.getContext('2d').getImageData(0, 0, maskEl.width, maskEl.height),\n                maskData = maskImageData.data;\n\n            for (i = 0; i < iLen; i += 4) {\n                data[i + 3] = maskData[i + channel];\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                mask: this.mask.toObject(),\n                channel: this.channel\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @param {Function} [callback] Callback to invoke when a mask filter instance is created\n     */\n    fabric.Image.filters.Mask.fromObject = function(object, callback) {\n        fabric.util.loadImage(object.mask.src, function(img) {\n            object.mask = new fabric.Image(img, object.mask);\n            callback && callback(new fabric.Image.filters.Mask(object));\n        });\n    };\n\n    /**\n     * Indicates that instances of this type are async\n     * @static\n     * @type Boolean\n     * @default\n     */\n    fabric.Image.filters.Mask.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Noise filter class\n     * @class fabric.Image.filters.Noise\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.Noise#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Noise({\n   *   noise: 700\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Noise = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Noise',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Noise.prototype\n         * @param {Object} [options] Options object\n         * @param {Number} [options.noise=0] Noise value\n         */\n        initialize: function(options) {\n            options = options || { };\n            this.noise = options.noise || 0;\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                noise = this.noise, rand;\n\n            for (var i = 0, len = data.length; i < len; i += 4) {\n\n                rand = (0.5 - Math.random()) * noise;\n\n                data[i] += rand;\n                data[i + 1] += rand;\n                data[i + 2] += rand;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                noise: this.noise\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise\n     */\n    fabric.Image.filters.Noise.fromObject = function(object) {\n        return new fabric.Image.filters.Noise(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Pixelate filter class\n     * @class fabric.Image.filters.Pixelate\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.Pixelate#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Pixelate({\n   *   blocksize: 8\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Pixelate = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Pixelate',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Pixelate.prototype\n         * @param {Object} [options] Options object\n         * @param {Number} [options.blocksize=4] Blocksize for pixelate\n         */\n        initialize: function(options) {\n            options = options || { };\n            this.blocksize = options.blocksize || 4;\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                iLen = imageData.height,\n                jLen = imageData.width,\n                index, i, j, r, g, b, a;\n\n            for (i = 0; i < iLen; i += this.blocksize) {\n                for (j = 0; j < jLen; j += this.blocksize) {\n\n                    index = (i * 4) * jLen + (j * 4);\n\n                    r = data[index];\n                    g = data[index + 1];\n                    b = data[index + 2];\n                    a = data[index + 3];\n\n                    /*\n                     blocksize: 4\n\n                     [1,x,x,x,1]\n                     [x,x,x,x,1]\n                     [x,x,x,x,1]\n                     [x,x,x,x,1]\n                     [1,1,1,1,1]\n                     */\n\n                    for (var _i = i, _ilen = i + this.blocksize; _i < _ilen; _i++) {\n                        for (var _j = j, _jlen = j + this.blocksize; _j < _jlen; _j++) {\n                            index = (_i * 4) * jLen + (_j * 4);\n                            data[index] = r;\n                            data[index + 1] = g;\n                            data[index + 2] = b;\n                            data[index + 3] = a;\n                        }\n                    }\n                }\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                blocksize: this.blocksize\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate\n     */\n    fabric.Image.filters.Pixelate.fromObject = function(object) {\n        return new fabric.Image.filters.Pixelate(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Remove white filter class\n     * @class fabric.Image.filters.RemoveWhite\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.RemoveWhite#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.RemoveWhite({\n   *   threshold: 40,\n   *   distance: 140\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.RemoveWhite = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.RemoveWhite.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'RemoveWhite',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.RemoveWhite.prototype\n         * @param {Object} [options] Options object\n         * @param {Number} [options.threshold=30] Threshold value\n         * @param {Number} [options.distance=20] Distance value\n         */\n        initialize: function(options) {\n            options = options || { };\n            this.threshold = options.threshold || 30;\n            this.distance = options.distance || 20;\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                threshold = this.threshold,\n                distance = this.distance,\n                limit = 255 - threshold,\n                abs = Math.abs,\n                r, g, b;\n\n            for (var i = 0, len = data.length; i < len; i += 4) {\n                r = data[i];\n                g = data[i + 1];\n                b = data[i + 2];\n\n                if (r > limit &&\n                    g > limit &&\n                    b > limit &&\n                    abs(r - g) < distance &&\n                    abs(r - b) < distance &&\n                    abs(g - b) < distance\n                    ) {\n                    data[i + 3] = 1;\n                }\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                threshold: this.threshold,\n                distance: this.distance\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.RemoveWhite} Instance of fabric.Image.filters.RemoveWhite\n     */\n    fabric.Image.filters.RemoveWhite.fromObject = function(object) {\n        return new fabric.Image.filters.RemoveWhite(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { });\n\n    /**\n     * Sepia filter class\n     * @class fabric.Image.filters.Sepia\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Sepia();\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Sepia = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Sepia.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Sepia',\n\n        /**\n         * Applies filter to canvas element\n         * @memberOf fabric.Image.filters.Sepia.prototype\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                iLen = data.length, i, avg;\n\n            for (i = 0; i < iLen; i+=4) {\n                avg = 0.3  * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2];\n                data[i] = avg + 100;\n                data[i + 1] = avg + 50;\n                data[i + 2] = avg + 255;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @return {fabric.Image.filters.Sepia} Instance of fabric.Image.filters.Sepia\n     */\n    fabric.Image.filters.Sepia.fromObject = function() {\n        return new fabric.Image.filters.Sepia();\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { });\n\n    /**\n     * Sepia2 filter class\n     * @class fabric.Image.filters.Sepia2\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example\n     * var filter = new fabric.Image.filters.Sepia2();\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Sepia2 = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Sepia2.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Sepia2',\n\n        /**\n         * Applies filter to canvas element\n         * @memberOf fabric.Image.filters.Sepia.prototype\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                iLen = data.length, i, r, g, b;\n\n            for (i = 0; i < iLen; i+=4) {\n                r = data[i];\n                g = data[i + 1];\n                b = data[i + 2];\n\n                data[i] = (r * 0.393 + g * 0.769 + b * 0.189 ) / 1.351;\n                data[i + 1] = (r * 0.349 + g * 0.686 + b * 0.168 ) / 1.203;\n                data[i + 2] = (r * 0.272 + g * 0.534 + b * 0.131 ) / 2.140;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @return {fabric.Image.filters.Sepia2} Instance of fabric.Image.filters.Sepia2\n     */\n    fabric.Image.filters.Sepia2.fromObject = function() {\n        return new fabric.Image.filters.Sepia2();\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Tint filter class\n     * Adapted from <a href=\"https://github.com/mezzoblue/PaintbrushJS\">https://github.com/mezzoblue/PaintbrushJS</a>\n     * @class fabric.Image.filters.Tint\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @see {@link fabric.Image.filters.Tint#initialize} for constructor definition\n     * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}\n     * @example <caption>Tint filter with hex color and opacity</caption>\n     * var filter = new fabric.Image.filters.Tint({\n   *   color: '#3513B0',\n   *   opacity: 0.5\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     * @example <caption>Tint filter with rgba color</caption>\n     * var filter = new fabric.Image.filters.Tint({\n   *   color: 'rgba(53, 21, 176, 0.5)'\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Tint = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Tint',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Tint.prototype\n         * @param {Object} [options] Options object\n         * @param {String} [options.color=#000000] Color to tint the image with\n         * @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1)\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.color = options.color || '#000000';\n            this.opacity = typeof options.opacity !== 'undefined'\n                ? options.opacity\n                : new fabric.Color(this.color).getAlpha();\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                iLen = data.length, i,\n                tintR, tintG, tintB,\n                r, g, b, alpha1,\n                source;\n\n            source = new fabric.Color(this.color).getSource();\n\n            tintR = source[0] * this.opacity;\n            tintG = source[1] * this.opacity;\n            tintB = source[2] * this.opacity;\n\n            alpha1 = 1 - this.opacity;\n\n            for (i = 0; i < iLen; i+=4) {\n                r = data[i];\n                g = data[i + 1];\n                b = data[i + 2];\n\n                // alpha compositing\n                data[i] = tintR + r * alpha1;\n                data[i + 1] = tintG + g * alpha1;\n                data[i + 2] = tintB + b * alpha1;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                color: this.color,\n                opacity: this.opacity\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.Tint} Instance of fabric.Image.filters.Tint\n     */\n    fabric.Image.filters.Tint.fromObject = function(object) {\n        return new fabric.Image.filters.Tint(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric  = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend;\n\n    /**\n     * Multiply filter class\n     * Adapted from <a href=\"http://www.laurenscorijn.com/articles/colormath-basics\">http://www.laurenscorijn.com/articles/colormath-basics</a>\n     * @class fabric.Image.filters.Multiply\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @example <caption>Multiply filter with hex color</caption>\n     * var filter = new fabric.Image.filters.Multiply({\n   *   color: '#F0F'\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     * @example <caption>Multiply filter with rgb color</caption>\n     * var filter = new fabric.Image.filters.Multiply({\n   *   color: 'rgb(53, 21, 176)'\n   * });\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Multiply = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Multiply.prototype */ {\n\n        /**\n         * Filter type\n         * @param {String} type\n         * @default\n         */\n        type: 'Multiply',\n\n        /**\n         * Constructor\n         * @memberOf fabric.Image.filters.Multiply.prototype\n         * @param {Object} [options] Options object\n         * @param {String} [options.color=#000000] Color to multiply the image pixels with\n         */\n        initialize: function(options) {\n            options = options || { };\n\n            this.color = options.color || '#000000';\n        },\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                iLen = data.length, i,\n                source;\n\n            source = new fabric.Color(this.color).getSource();\n\n            for (i = 0; i < iLen; i+=4) {\n                data[i] *= source[0] / 255;\n                data[i + 1] *= source[1] / 255;\n                data[i + 2] *= source[2] / 255;\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return extend(this.callSuper('toObject'), {\n                color: this.color\n            });\n        }\n    });\n\n    /**\n     * Returns filter instance from an object representation\n     * @static\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Image.filters.Multiply} Instance of fabric.Image.filters.Multiply\n     */\n    fabric.Image.filters.Multiply.fromObject = function(object) {\n        return new fabric.Image.filters.Multiply(object);\n    };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n    'use strict';\n\n    var fabric = global.fabric;\n\n    /**\n     * Color Blend filter class\n     * @class fabric.Image.filter.Blend\n     * @memberOf fabric.Image.filters\n     * @extends fabric.Image.filters.BaseFilter\n     * @example\n     * var filter = new fabric.Image.filters.Blend({\n   *  color: '#000',\n   *  mode: 'multiply'\n   * });\n     *\n     * var filter = new fabric.Image.filters.Blend({\n   *  image: fabricImageObject,\n   *  mode: 'multiply',\n   *  alpha: 0.5\n   * });\n\n     * object.filters.push(filter);\n     * object.applyFilters(canvas.renderAll.bind(canvas));\n     */\n    fabric.Image.filters.Blend = fabric.util.createClass({\n        type: 'Blend',\n\n        initialize: function(options) {\n            options = options || {};\n            this.color = options.color || '#000';\n            this.image = options.image || false;\n            this.mode = options.mode || 'multiply';\n            this.alpha = options.alpha || 1;\n        },\n\n        applyTo: function(canvasEl) {\n            var context = canvasEl.getContext('2d'),\n                imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n                data = imageData.data,\n                tr, tg, tb,\n                r, g, b,\n                source,\n                isImage = false;\n\n            if (this.image) {\n                // Blend images\n                isImage = true;\n\n                var _el = fabric.util.createCanvasElement();\n                _el.width = this.image.width;\n                _el.height = this.image.height;\n\n                var tmpCanvas = new fabric.StaticCanvas(_el);\n                tmpCanvas.add(this.image);\n                var context2 =  tmpCanvas.getContext('2d');\n                source = context2.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height).data;\n            }\n            else {\n                // Blend color\n                source = new fabric.Color(this.color).getSource();\n\n                tr = source[0] * this.alpha;\n                tg = source[1] * this.alpha;\n                tb = source[2] * this.alpha;\n            }\n\n            for (var i = 0, len = data.length; i < len; i += 4) {\n\n                r = data[i];\n                g = data[i + 1];\n                b = data[i + 2];\n\n                if (isImage) {\n                    tr = source[i] * this.alpha;\n                    tg = source[i + 1] * this.alpha;\n                    tb = source[i + 2] * this.alpha;\n                }\n\n                switch (this.mode) {\n                    case 'multiply':\n                        data[i] = r * tr / 255;\n                        data[i + 1] = g * tg / 255;\n                        data[i + 2] = b * tb / 255;\n                        break;\n                    case 'screen':\n                        data[i] = 1 - (1 - r) * (1 - tr);\n                        data[i + 1] = 1 - (1 - g) * (1 - tg);\n                        data[i + 2] = 1 - (1 - b) * (1 - tb);\n                        break;\n                    case 'add':\n                        data[i] = Math.min(255, r + tr);\n                        data[i + 1] = Math.min(255, g + tg);\n                        data[i + 2] = Math.min(255, b + tb);\n                        break;\n                    case 'diff':\n                    case 'difference':\n                        data[i] = Math.abs(r - tr);\n                        data[i + 1] = Math.abs(g - tg);\n                        data[i + 2] = Math.abs(b - tb);\n                        break;\n                    case 'subtract':\n                        var _r = r - tr,\n                            _g = g - tg,\n                            _b = b - tb;\n\n                        data[i] = (_r < 0) ? 0 : _r;\n                        data[i + 1] = (_g < 0) ? 0 : _g;\n                        data[i + 2] = (_b < 0) ? 0 : _b;\n                        break;\n                    case 'darken':\n                        data[i] = Math.min(r, tr);\n                        data[i + 1] = Math.min(g, tg);\n                        data[i + 2] = Math.min(b, tb);\n                        break;\n                    case 'lighten':\n                        data[i] = Math.max(r, tr);\n                        data[i + 1] = Math.max(g, tg);\n                        data[i + 2] = Math.max(b, tb);\n                        break;\n                }\n            }\n\n            context.putImageData(imageData, 0, 0);\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function() {\n            return {\n                color: this.color,\n                image: this.image,\n                mode: this.mode,\n                alpha: this.alpha\n            };\n        }\n    });\n\n    fabric.Image.filters.Blend.fromObject = function(object) {\n        return new fabric.Image.filters.Blend(object);\n    };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n    'use strict';\n\n    var fabric = global.fabric || (global.fabric = { }),\n        extend = fabric.util.object.extend,\n        clone = fabric.util.object.clone,\n        toFixed = fabric.util.toFixed,\n        supportsLineDash = fabric.StaticCanvas.supports('setLineDash');\n\n    if (fabric.Text) {\n        fabric.warn('fabric.Text is already defined');\n        return;\n    }\n\n    var stateProperties = fabric.Object.prototype.stateProperties.concat();\n    stateProperties.push(\n        'fontFamily',\n        'fontWeight',\n        'fontSize',\n        'text',\n        'textDecoration',\n        'textAlign',\n        'fontStyle',\n        'lineHeight',\n        'textBackgroundColor',\n        'useNative',\n        'path'\n    );\n\n    /**\n     * Text class\n     * @class fabric.Text\n     * @extends fabric.Object\n     * @return {fabric.Text} thisArg\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#text}\n     * @see {@link fabric.Text#initialize} for constructor definition\n     */\n    fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {\n\n        /**\n         * Properties which when set cause object to change dimensions\n         * @type Object\n         * @private\n         */\n        _dimensionAffectingProps: {\n            fontSize: true,\n            fontWeight: true,\n            fontFamily: true,\n            textDecoration: true,\n            fontStyle: true,\n            lineHeight: true,\n            stroke: true,\n            strokeWidth: true,\n            text: true\n        },\n\n        /**\n         * @private\n         */\n        _reNewline: /\\r?\\n/,\n\n        /**\n         * Retrieves object's fontSize\n         * @method getFontSize\n         * @memberOf fabric.Text.prototype\n         * @return {String} Font size (in pixels)\n         */\n\n        /**\n         * Sets object's fontSize\n         * @method setFontSize\n         * @memberOf fabric.Text.prototype\n         * @param {Number} fontSize Font size (in pixels)\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's fontWeight\n         * @method getFontWeight\n         * @memberOf fabric.Text.prototype\n         * @return {(String|Number)} Font weight\n         */\n\n        /**\n         * Sets object's fontWeight\n         * @method setFontWeight\n         * @memberOf fabric.Text.prototype\n         * @param {(Number|String)} fontWeight Font weight\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's fontFamily\n         * @method getFontFamily\n         * @memberOf fabric.Text.prototype\n         * @return {String} Font family\n         */\n\n        /**\n         * Sets object's fontFamily\n         * @method setFontFamily\n         * @memberOf fabric.Text.prototype\n         * @param {String} fontFamily Font family\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's text\n         * @method getText\n         * @memberOf fabric.Text.prototype\n         * @return {String} text\n         */\n\n        /**\n         * Sets object's text\n         * @method setText\n         * @memberOf fabric.Text.prototype\n         * @param {String} text Text\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's textDecoration\n         * @method getTextDecoration\n         * @memberOf fabric.Text.prototype\n         * @return {String} Text decoration\n         */\n\n        /**\n         * Sets object's textDecoration\n         * @method setTextDecoration\n         * @memberOf fabric.Text.prototype\n         * @param {String} textDecoration Text decoration\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's fontStyle\n         * @method getFontStyle\n         * @memberOf fabric.Text.prototype\n         * @return {String} Font style\n         */\n\n        /**\n         * Sets object's fontStyle\n         * @method setFontStyle\n         * @memberOf fabric.Text.prototype\n         * @param {String} fontStyle Font style\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's lineHeight\n         * @method getLineHeight\n         * @memberOf fabric.Text.prototype\n         * @return {Number} Line height\n         */\n\n        /**\n         * Sets object's lineHeight\n         * @method setLineHeight\n         * @memberOf fabric.Text.prototype\n         * @param {Number} lineHeight Line height\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's textAlign\n         * @method getTextAlign\n         * @memberOf fabric.Text.prototype\n         * @return {String} Text alignment\n         */\n\n        /**\n         * Sets object's textAlign\n         * @method setTextAlign\n         * @memberOf fabric.Text.prototype\n         * @param {String} textAlign Text alignment\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Retrieves object's textBackgroundColor\n         * @method getTextBackgroundColor\n         * @memberOf fabric.Text.prototype\n         * @return {String} Text background color\n         */\n\n        /**\n         * Sets object's textBackgroundColor\n         * @method setTextBackgroundColor\n         * @memberOf fabric.Text.prototype\n         * @param {String} textBackgroundColor Text background color\n         * @return {fabric.Text}\n         * @chainable\n         */\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type:                 'text',\n\n        /**\n         * Font size (in pixels)\n         * @type Number\n         * @default\n         */\n        fontSize:             40,\n\n        /**\n         * Font weight (e.g. bold, normal, 400, 600, 800)\n         * @type {(Number|String)}\n         * @default\n         */\n        fontWeight:           'normal',\n\n        /**\n         * Font family\n         * @type String\n         * @default\n         */\n        fontFamily:           'Times New Roman',\n\n        /**\n         * Text decoration Possible values: \"\", \"underline\", \"overline\" or \"line-through\".\n         * @type String\n         * @default\n         */\n        textDecoration:       '',\n\n        /**\n         * Text alignment. Possible values: \"left\", \"center\", or \"right\".\n         * @type String\n         * @default\n         */\n        textAlign:            'left',\n\n        /**\n         * Font style . Possible values: \"\", \"normal\", \"italic\" or \"oblique\".\n         * @type String\n         * @default\n         */\n        fontStyle:            '',\n\n        /**\n         * Line height\n         * @type Number\n         * @default\n         */\n        lineHeight:           1.3,\n\n        /**\n         * Background color of text lines\n         * @type String\n         * @default\n         */\n        textBackgroundColor:  '',\n\n        /**\n         * URL of a font file, when using Cufon\n         * @type String | null\n         * @default\n         */\n        path:                 null,\n\n        /**\n         * Indicates whether canvas native text methods should be used to render text (otherwise, Cufon is used)\n         * @type Boolean\n         * @default\n         */\n        useNative:            true,\n\n        /**\n         * List of properties to consider when checking if\n         * state of an object is changed ({@link fabric.Object#hasStateChanged})\n         * as well as for history (undo/redo) purposes\n         * @type Array\n         */\n        stateProperties:      stateProperties,\n\n        /**\n         * When defined, an object is rendered via stroke and this property specifies its color.\n         * <b>Backwards incompatibility note:</b> This property was named \"strokeStyle\" until v1.1.6\n         * @type String\n         * @default\n         */\n        stroke:               null,\n\n        /**\n         * Shadow object representing shadow of this shape.\n         * <b>Backwards incompatibility note:</b> This property was named \"textShadow\" (String) until v1.2.11\n         * @type fabric.Shadow\n         * @default\n         */\n        shadow:               null,\n\n        /**\n         * Constructor\n         * @param {String} text Text string\n         * @param {Object} [options] Options object\n         * @return {fabric.Text} thisArg\n         */\n        initialize: function(text, options) {\n            options = options || { };\n\n            this.text = text;\n            this.__skipDimension = true;\n            this.setOptions(options);\n            this.__skipDimension = false;\n            this._initDimensions();\n        },\n\n        /**\n         * Renders text object on offscreen canvas, so that it would get dimensions\n         * @private\n         */\n        _initDimensions: function() {\n            if (this.__skipDimension) {\n                return;\n            }\n            var canvasEl = fabric.util.createCanvasElement();\n            this._render(canvasEl.getContext('2d'));\n        },\n\n        /**\n         * Returns string representation of an instance\n         * @return {String} String representation of text object\n         */\n        toString: function() {\n            return '#<fabric.Text (' + this.complexity() +\n                '): { \"text\": \"' + this.text + '\", \"fontFamily\": \"' + this.fontFamily + '\" }>';\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx) {\n\n            if (typeof Cufon === 'undefined' || this.useNative === true) {\n                this._renderViaNative(ctx);\n            }\n            else {\n                this._renderViaCufon(ctx);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderViaNative: function(ctx) {\n            var textLines = this.text.split(this._reNewline);\n\n            this._setTextStyles(ctx);\n\n            this.width = this._getTextWidth(ctx, textLines);\n            this.height = this._getTextHeight(ctx, textLines);\n\n            this.clipTo && fabric.util.clipContext(this, ctx);\n\n            this._renderTextBackground(ctx, textLines);\n            this._translateForTextAlign(ctx);\n            this._renderText(ctx, textLines);\n\n            if (this.textAlign !== 'left' && this.textAlign !== 'justify') {\n                ctx.restore();\n            }\n\n            this._renderTextDecoration(ctx, textLines);\n            this.clipTo && ctx.restore();\n\n            this._setBoundaries(ctx, textLines);\n            this._totalLineHeight = 0;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderText: function(ctx, textLines) {\n            ctx.save();\n            this._setShadow(ctx);\n            this._setupCompositeOperation(ctx);\n            this._renderTextFill(ctx, textLines);\n            this._renderTextStroke(ctx, textLines);\n            this._restoreCompositeOperation(ctx);\n            this._removeShadow(ctx);\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _translateForTextAlign: function(ctx) {\n            if (this.textAlign !== 'left' && this.textAlign !== 'justify') {\n                ctx.save();\n                ctx.translate(this.textAlign === 'center' ? (this.width / 2) : this.width, 0);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _setBoundaries: function(ctx, textLines) {\n            this._boundaries = [ ];\n\n            for (var i = 0, len = textLines.length; i < len; i++) {\n\n                var lineWidth = this._getLineWidth(ctx, textLines[i]),\n                    lineLeftOffset = this._getLineLeftOffset(lineWidth);\n\n                this._boundaries.push({\n                    height: this.fontSize * this.lineHeight,\n                    width: lineWidth,\n                    left: lineLeftOffset\n                });\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _setTextStyles: function(ctx) {\n            this._setFillStyles(ctx);\n            this._setStrokeStyles(ctx);\n            ctx.textBaseline = 'alphabetic';\n            if (!this.skipTextAlign) {\n                ctx.textAlign = this.textAlign;\n            }\n            ctx.font = this._getFontDeclaration();\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         * @return {Number} Height of fabric.Text object\n         */\n        _getTextHeight: function(ctx, textLines) {\n            return this.fontSize * textLines.length * this.lineHeight;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         * @return {Number} Maximum width of fabric.Text object\n         */\n        _getTextWidth: function(ctx, textLines) {\n            var maxWidth = ctx.measureText(textLines[0] || '|').width;\n\n            for (var i = 1, len = textLines.length; i < len; i++) {\n                var currentLineWidth = ctx.measureText(textLines[i]).width;\n                if (currentLineWidth > maxWidth) {\n                    maxWidth = currentLineWidth;\n                }\n            }\n            return maxWidth;\n        },\n\n        /**\n         * @private\n         * @param {String} method Method name (\"fillText\" or \"strokeText\")\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {String} chars Chars to render\n         * @param {Number} left Left position of text\n         * @param {Number} top Top position of text\n         */\n        _renderChars: function(method, ctx, chars, left, top) {\n            ctx[method](chars, left, top);\n        },\n\n        /**\n         * @private\n         * @param {String} method Method name (\"fillText\" or \"strokeText\")\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {String} line Text to render\n         * @param {Number} left Left position of text\n         * @param {Number} top Top position of text\n         * @param {Number} lineIndex Index of a line in a text\n         */\n        _renderTextLine: function(method, ctx, line, left, top, lineIndex) {\n            // lift the line by quarter of fontSize\n            top -= this.fontSize / 4;\n\n            // short-circuit\n            if (this.textAlign !== 'justify') {\n                this._renderChars(method, ctx, line, left, top, lineIndex);\n                return;\n            }\n\n            var lineWidth = ctx.measureText(line).width,\n                totalWidth = this.width;\n\n            if (totalWidth > lineWidth) {\n                // stretch the line\n                var words = line.split(/\\s+/),\n                    wordsWidth = ctx.measureText(line.replace(/\\s+/g, '')).width,\n                    widthDiff = totalWidth - wordsWidth,\n                    numSpaces = words.length - 1,\n                    spaceWidth = widthDiff / numSpaces,\n                    leftOffset = 0;\n\n                for (var i = 0, len = words.length; i < len; i++) {\n                    this._renderChars(method, ctx, words[i], left + leftOffset, top, lineIndex);\n                    leftOffset += ctx.measureText(words[i]).width + spaceWidth;\n                }\n            }\n            else {\n                this._renderChars(method, ctx, line, left, top, lineIndex);\n            }\n        },\n\n        /**\n         * @private\n         * @return {Number} Left offset\n         */\n        _getLeftOffset: function() {\n            if (fabric.isLikelyNode) {\n                return 0;\n            }\n            return -this.width / 2;\n        },\n\n        /**\n         * @private\n         * @return {Number} Top offset\n         */\n        _getTopOffset: function() {\n            return -this.height / 2;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _renderTextFill: function(ctx, textLines) {\n            if (!this.fill && !this._skipFillStrokeCheck) {\n                return;\n            }\n\n            this._boundaries = [ ];\n            var lineHeights = 0;\n\n            for (var i = 0, len = textLines.length; i < len; i++) {\n                var heightOfLine = this._getHeightOfLine(ctx, i, textLines);\n                lineHeights += heightOfLine;\n\n                this._renderTextLine(\n                    'fillText',\n                    ctx,\n                    textLines[i],\n                    this._getLeftOffset(),\n                        this._getTopOffset() + lineHeights,\n                    i\n                );\n            }\n            if (this.shadow && !this.shadow.affectStroke) {\n                this._removeShadow(ctx);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _renderTextStroke: function(ctx, textLines) {\n            if ((!this.stroke || this.strokeWidth === 0) && !this._skipFillStrokeCheck) {\n                return;\n            }\n\n            var lineHeights = 0;\n\n            ctx.save();\n            if (this.strokeDashArray) {\n                // Spec requires the concatenation of two copies the dash list when the number of elements is odd\n                if (1 & this.strokeDashArray.length) {\n                    this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);\n                }\n                supportsLineDash && ctx.setLineDash(this.strokeDashArray);\n            }\n\n            ctx.beginPath();\n            for (var i = 0, len = textLines.length; i < len; i++) {\n                var heightOfLine = this._getHeightOfLine(ctx, i, textLines);\n                lineHeights += heightOfLine;\n\n                this._renderTextLine(\n                    'strokeText',\n                    ctx,\n                    textLines[i],\n                    this._getLeftOffset(),\n                        this._getTopOffset() + lineHeights,\n                    i\n                );\n            }\n            ctx.closePath();\n            ctx.restore();\n        },\n\n        _getHeightOfLine: function() {\n            return this.fontSize * this.lineHeight;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _renderTextBackground: function(ctx, textLines) {\n            this._renderTextBoxBackground(ctx);\n            this._renderTextLinesBackground(ctx, textLines);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderTextBoxBackground: function(ctx) {\n            if (!this.backgroundColor) {\n                return;\n            }\n\n            ctx.save();\n            ctx.fillStyle = this.backgroundColor;\n\n            ctx.fillRect(\n                this._getLeftOffset(),\n                this._getTopOffset(),\n                this.width,\n                this.height\n            );\n\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _renderTextLinesBackground: function(ctx, textLines) {\n            if (!this.textBackgroundColor) {\n                return;\n            }\n\n            ctx.save();\n            ctx.fillStyle = this.textBackgroundColor;\n\n            for (var i = 0, len = textLines.length; i < len; i++) {\n\n                if (textLines[i] !== '') {\n\n                    var lineWidth = this._getLineWidth(ctx, textLines[i]),\n                        lineLeftOffset = this._getLineLeftOffset(lineWidth);\n\n                    ctx.fillRect(\n                            this._getLeftOffset() + lineLeftOffset,\n                            this._getTopOffset() + (i * this.fontSize * this.lineHeight),\n                        lineWidth,\n                            this.fontSize * this.lineHeight\n                    );\n                }\n            }\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {Number} lineWidth Width of text line\n         * @return {Number} Line left offset\n         */\n        _getLineLeftOffset: function(lineWidth) {\n            if (this.textAlign === 'center') {\n                return (this.width - lineWidth) / 2;\n            }\n            if (this.textAlign === 'right') {\n                return this.width - lineWidth;\n            }\n            return 0;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {String} line Text line\n         * @return {Number} Line width\n         */\n        _getLineWidth: function(ctx, line) {\n            return this.textAlign === 'justify'\n                ? this.width\n                : ctx.measureText(line).width;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _renderTextDecoration: function(ctx, textLines) {\n            if (!this.textDecoration) {\n                return;\n            }\n\n            // var halfOfVerticalBox = this.originY === 'top' ? 0 : this._getTextHeight(ctx, textLines) / 2;\n            var halfOfVerticalBox = this._getTextHeight(ctx, textLines) / 2,\n                _this = this;\n\n            /** @ignore */\n            function renderLinesAtOffset(offset) {\n                for (var i = 0, len = textLines.length; i < len; i++) {\n\n                    var lineWidth = _this._getLineWidth(ctx, textLines[i]),\n                        lineLeftOffset = _this._getLineLeftOffset(lineWidth);\n\n                    ctx.fillRect(\n                            _this._getLeftOffset() + lineLeftOffset,\n                        ~~((offset + (i * _this._getHeightOfLine(ctx, i, textLines))) - halfOfVerticalBox),\n                        lineWidth,\n                        1);\n                }\n            }\n\n            if (this.textDecoration.indexOf('underline') > -1) {\n                renderLinesAtOffset(this.fontSize * this.lineHeight);\n            }\n            if (this.textDecoration.indexOf('line-through') > -1) {\n                renderLinesAtOffset(this.fontSize * this.lineHeight - this.fontSize / 2);\n            }\n            if (this.textDecoration.indexOf('overline') > -1) {\n                renderLinesAtOffset(this.fontSize * this.lineHeight - this.fontSize);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _getFontDeclaration: function() {\n            return [\n                // node-canvas needs \"weight style\", while browsers need \"style weight\"\n                (fabric.isLikelyNode ? this.fontWeight : this.fontStyle),\n                (fabric.isLikelyNode ? this.fontStyle : this.fontWeight),\n                    this.fontSize + 'px',\n                (fabric.isLikelyNode ? ('\"' + this.fontFamily + '\"') : this.fontFamily)\n            ].join(' ');\n        },\n\n        /**\n         * Renders text instance on a specified context\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        render: function(ctx, noTransform) {\n            // do not render if object is not visible\n            if (!this.visible) {\n                return;\n            }\n\n            ctx.save();\n            if (!noTransform) {\n                this.transform(ctx);\n            }\n\n            var isInPathGroup = this.group && this.group.type === 'path-group';\n\n            if (isInPathGroup) {\n                ctx.translate(-this.group.width/2, -this.group.height/2);\n            }\n            if (this.transformMatrix) {\n                ctx.transform.apply(ctx, this.transformMatrix);\n            }\n            if (isInPathGroup) {\n                ctx.translate(this.left, this.top);\n            }\n            this._render(ctx);\n            ctx.restore();\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            var object = extend(this.callSuper('toObject', propertiesToInclude), {\n                text:                 this.text,\n                fontSize:             this.fontSize,\n                fontWeight:           this.fontWeight,\n                fontFamily:           this.fontFamily,\n                fontStyle:            this.fontStyle,\n                lineHeight:           this.lineHeight,\n                textDecoration:       this.textDecoration,\n                textAlign:            this.textAlign,\n                path:                 this.path,\n                textBackgroundColor:  this.textBackgroundColor,\n                useNative:            this.useNative\n            });\n            if (!this.includeDefaultValues) {\n                this._removeDefaultValues(object);\n            }\n            return object;\n        },\n\n        /* _TO_SVG_START_ */\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG: function(reviver) {\n            var markup = [ ],\n                textLines = this.text.split(this._reNewline),\n                offsets = this._getSVGLeftTopOffsets(textLines),\n                textAndBg = this._getSVGTextAndBg(offsets.lineTop, offsets.textLeft, textLines),\n                shadowSpans = this._getSVGShadows(offsets.lineTop, textLines);\n\n            // move top offset by an ascent\n            offsets.textTop += (this._fontAscent ? ((this._fontAscent / 5) * this.lineHeight) : 0);\n\n            this._wrapSVGTextAndBg(markup, textAndBg, shadowSpans, offsets);\n\n            return reviver ? reviver(markup.join('')) : markup.join('');\n        },\n\n        /**\n         * @private\n         */\n        _getSVGLeftTopOffsets: function(textLines) {\n            var lineTop = this.useNative\n                    ? this.fontSize * this.lineHeight\n                    : (-this._fontAscent - ((this._fontAscent / 5) * this.lineHeight)),\n\n                textLeft = -(this.width/2),\n                textTop = this.useNative\n                    ? this.fontSize - 1\n                    : (this.height/2) - (textLines.length * this.fontSize) - this._totalLineHeight;\n\n            return {\n                textLeft: textLeft + (this.group && this.group.type === 'path-group' ? this.left : 0),\n                textTop: textTop + (this.group && this.group.type === 'path-group' ? this.top : 0),\n                lineTop: lineTop\n            };\n        },\n\n        /**\n         * @private\n         */\n        _wrapSVGTextAndBg: function(markup, textAndBg, shadowSpans, offsets) {\n            markup.push(\n                '<g transform=\"', this.getSvgTransform(), this.getSvgTransformMatrix(), '\">\\n',\n                textAndBg.textBgRects.join(''),\n                '<text ',\n                (this.fontFamily ? 'font-family=\"' + this.fontFamily.replace(/\"/g, '\\'') + '\" ': ''),\n                (this.fontSize ? 'font-size=\"' + this.fontSize + '\" ': ''),\n                (this.fontStyle ? 'font-style=\"' + this.fontStyle + '\" ': ''),\n                (this.fontWeight ? 'font-weight=\"' + this.fontWeight + '\" ': ''),\n                (this.textDecoration ? 'text-decoration=\"' + this.textDecoration + '\" ': ''),\n                'style=\"', this.getSvgStyles(), '\" ',\n                /* svg starts from left/bottom corner so we normalize height */\n                'transform=\"translate(', toFixed(offsets.textLeft, 2), ' ', toFixed(offsets.textTop, 2), ')\">',\n                shadowSpans.join(''),\n                textAndBg.textSpans.join(''),\n                '</text>\\n',\n                '</g>\\n'\n            );\n        },\n\n        /**\n         * @private\n         * @param {Number} lineHeight\n         * @param {Array} textLines Array of all text lines\n         * @return {Array}\n         */\n        _getSVGShadows: function(lineHeight, textLines) {\n            var shadowSpans = [],\n                i, len,\n                lineTopOffsetMultiplier = 1;\n\n            if (!this.shadow || !this._boundaries) {\n                return shadowSpans;\n            }\n\n            for (i = 0, len = textLines.length; i < len; i++) {\n                if (textLines[i] !== '') {\n                    var lineLeftOffset = (this._boundaries && this._boundaries[i]) ? this._boundaries[i].left : 0;\n                    shadowSpans.push(\n                        '<tspan x=\"',\n                        toFixed((lineLeftOffset + lineTopOffsetMultiplier) + this.shadow.offsetX, 2),\n                        ((i === 0 || this.useNative) ? '\" y' : '\" dy'), '=\"',\n                        toFixed(this.useNative\n                            ? ((lineHeight * i) - this.height / 2 + this.shadow.offsetY)\n                            : (lineHeight + (i === 0 ? this.shadow.offsetY : 0)), 2),\n                        '\" ',\n                        this._getFillAttributes(this.shadow.color), '>',\n                        fabric.util.string.escapeXml(textLines[i]),\n                        '</tspan>');\n                    lineTopOffsetMultiplier = 1;\n                }\n                else {\n                    // in some environments (e.g. IE 7 & 8) empty tspans are completely ignored, using a lineTopOffsetMultiplier\n                    // prevents empty tspans\n                    lineTopOffsetMultiplier++;\n                }\n            }\n\n            return shadowSpans;\n        },\n\n        /**\n         * @private\n         * @param {Number} lineHeight\n         * @param {Number} textLeftOffset Text left offset\n         * @param {Array} textLines Array of all text lines\n         * @return {Object}\n         */\n        _getSVGTextAndBg: function(lineHeight, textLeftOffset, textLines) {\n            var textSpans = [ ],\n                textBgRects = [ ],\n                lineTopOffsetMultiplier = 1;\n\n            // bounding-box background\n            this._setSVGBg(textBgRects);\n\n            // text and text-background\n            for (var i = 0, len = textLines.length; i < len; i++) {\n                if (textLines[i] !== '') {\n                    this._setSVGTextLineText(textLines[i], i, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects);\n                    lineTopOffsetMultiplier = 1;\n                }\n                else {\n                    // in some environments (e.g. IE 7 & 8) empty tspans are completely ignored, using a lineTopOffsetMultiplier\n                    // prevents empty tspans\n                    lineTopOffsetMultiplier++;\n                }\n\n                if (!this.textBackgroundColor || !this._boundaries) {\n                    continue;\n                }\n\n                this._setSVGTextLineBg(textBgRects, i, textLeftOffset, lineHeight);\n            }\n\n            return {\n                textSpans: textSpans,\n                textBgRects: textBgRects\n            };\n        },\n\n        _setSVGTextLineText: function(textLine, i, textSpans, lineHeight, lineTopOffsetMultiplier) {\n            var lineLeftOffset = (this._boundaries && this._boundaries[i])\n                ? toFixed(this._boundaries[i].left, 2)\n                : 0;\n\n            textSpans.push(\n                '<tspan x=\"',\n                lineLeftOffset, '\" ',\n                (i === 0 || this.useNative ? 'y' : 'dy'), '=\"',\n                toFixed(this.useNative\n                    ? ((lineHeight * i) - this.height / 2)\n                    : (lineHeight * lineTopOffsetMultiplier), 2), '\" ',\n                // doing this on <tspan> elements since setting opacity\n                // on containing <text> one doesn't work in Illustrator\n                this._getFillAttributes(this.fill), '>',\n                fabric.util.string.escapeXml(textLine),\n                '</tspan>'\n            );\n        },\n\n        _setSVGTextLineBg: function(textBgRects, i, textLeftOffset, lineHeight) {\n            textBgRects.push(\n                '<rect ',\n                this._getFillAttributes(this.textBackgroundColor),\n                ' x=\"',\n                toFixed(textLeftOffset + this._boundaries[i].left, 2),\n                '\" y=\"',\n                /* an offset that seems to straighten things out */\n                toFixed((lineHeight * i) - this.height / 2, 2),\n                '\" width=\"',\n                toFixed(this._boundaries[i].width, 2),\n                '\" height=\"',\n                toFixed(this._boundaries[i].height, 2),\n                '\"></rect>\\n');\n        },\n\n        _setSVGBg: function(textBgRects) {\n            if (this.backgroundColor && this._boundaries) {\n                textBgRects.push(\n                    '<rect ',\n                    this._getFillAttributes(this.backgroundColor),\n                    ' x=\"',\n                    toFixed(-this.width / 2, 2),\n                    '\" y=\"',\n                    toFixed(-this.height / 2, 2),\n                    '\" width=\"',\n                    toFixed(this.width, 2),\n                    '\" height=\"',\n                    toFixed(this.height, 2),\n                    '\"></rect>');\n            }\n        },\n\n        /**\n         * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values\n         * we work around it by \"moving\" alpha channel into opacity attribute and setting fill's alpha to 1\n         *\n         * @private\n         * @param {Any} value\n         * @return {String}\n         */\n        _getFillAttributes: function(value) {\n            var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';\n            if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) {\n                return 'fill=\"' + value + '\"';\n            }\n            return 'opacity=\"' + fillColor.getAlpha() + '\" fill=\"' + fillColor.setAlpha(1).toRgb() + '\"';\n        },\n        /* _TO_SVG_END_ */\n\n        /**\n         * Sets specified property to a specified value\n         * @param {String} key\n         * @param {Any} value\n         * @return {fabric.Text} thisArg\n         * @chainable\n         */\n        _set: function(key, value) {\n            if (key === 'fontFamily' && this.path) {\n                this.path = this.path.replace(/(.*?)([^\\/]*)(\\.font\\.js)/, '$1' + value + '$3');\n            }\n            this.callSuper('_set', key, value);\n\n            if (key in this._dimensionAffectingProps) {\n                this._initDimensions();\n                this.setCoords();\n            }\n        },\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity: function() {\n            return 1;\n        }\n    });\n\n    /* _FROM_SVG_START_ */\n    /**\n     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement})\n     * @static\n     * @memberOf fabric.Text\n     * @see: http://www.w3.org/TR/SVG/text.html#TextElement\n     */\n    fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(\n        'x y dx dy font-family font-style font-weight font-size text-decoration text-anchor'.split(' '));\n\n    /**\n     * Default SVG font size\n     * @static\n     * @memberOf fabric.Text\n     */\n    fabric.Text.DEFAULT_SVG_FONT_SIZE = 16;\n\n    /**\n     * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)\n     * @static\n     * @memberOf fabric.Text\n     * @param {SVGElement} element Element to parse\n     * @param {Object} [options] Options object\n     * @return {fabric.Text} Instance of fabric.Text\n     */\n    fabric.Text.fromElement = function(element, options) {\n        if (!element) {\n            return null;\n        }\n\n        var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES);\n        options = fabric.util.object.extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes);\n\n        if ('dx' in parsedAttributes) {\n            options.left += parsedAttributes.dx;\n        }\n        if ('dy' in parsedAttributes) {\n            options.top += parsedAttributes.dy;\n        }\n        if (!('fontSize' in options)) {\n            options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n        }\n\n        if (!options.originX) {\n            options.originX = 'left';\n        }\n\n        var text = new fabric.Text(element.textContent, options),\n        /*\n         Adjust positioning:\n         x/y attributes in SVG correspond to the bottom-left corner of text bounding box\n         top/left properties in Fabric correspond to center point of text bounding box\n         */\n            offX = 0;\n\n        if (text.originX === 'left') {\n            offX = text.getWidth() / 2;\n        }\n        if (text.originX === 'right') {\n            offX = -text.getWidth() / 2;\n        }\n        text.set({\n            left: text.getLeft() + offX,\n            top: text.getTop() - text.getHeight() / 2\n        });\n\n        return text;\n    };\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns fabric.Text instance from an object representation\n     * @static\n     * @memberOf fabric.Text\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.Text} Instance of fabric.Text\n     */\n    fabric.Text.fromObject = function(object) {\n        return new fabric.Text(object.text, clone(object));\n    };\n\n    fabric.util.createAccessors(fabric.Text);\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n    var clone = fabric.util.object.clone;\n\n    /**\n     * IText class (introduced in <b>v1.4</b>) Events are also fired with \"text:\"\n     * prefix when observing canvas.\n     * @class fabric.IText\n     * @extends fabric.Text\n     * @mixes fabric.Observable\n     *\n     * @fires changed\n     * @fires selection:changed\n     * @fires editing:entered\n     * @fires editing:exited\n     *\n     * @return {fabric.IText} thisArg\n     * @see {@link fabric.IText#initialize} for constructor definition\n     *\n     * <p>Supported key combinations:</p>\n     * <pre>\n     *   Move cursor:                    left, right, up, down\n     *   Select character:               shift + left, shift + right\n     *   Select text vertically:         shift + up, shift + down\n     *   Move cursor by word:            alt + left, alt + right\n     *   Select words:                   shift + alt + left, shift + alt + right\n     *   Move cursor to line start/end:  cmd + left, cmd + right\n     *   Select till start/end of line:  cmd + shift + left, cmd + shift + right\n     *   Jump to start/end of text:      cmd + up, cmd + down\n     *   Select till start/end of text:  cmd + shift + up, cmd + shift + down\n     *   Delete character:               backspace\n     *   Delete word:                    alt + backspace\n     *   Delete line:                    cmd + backspace\n     *   Forward delete:                 delete\n     *   Copy text:                      ctrl/cmd + c\n     *   Paste text:                     ctrl/cmd + v\n     *   Cut text:                       ctrl/cmd + x\n     *   Select entire text:             ctrl/cmd + a\n     * </pre>\n     *\n     * <p>Supported mouse/touch combination</p>\n     * <pre>\n     *   Position cursor:                click/touch\n     *   Create selection:               click/touch & drag\n     *   Create selection:               click & shift + click\n     *   Select word:                    double click\n     *   Select line:                    triple click\n     * </pre>\n     */\n    fabric.IText = fabric.util.createClass(fabric.Text, fabric.Observable, /** @lends fabric.IText.prototype */ {\n\n        /**\n         * Type of an object\n         * @type String\n         * @default\n         */\n        type: 'i-text',\n\n        /**\n         * Index where text selection starts (or where cursor is when there is no selection)\n         * @type Nubmer\n         * @default\n         */\n        selectionStart: 0,\n\n        /**\n         * Index where text selection ends\n         * @type Nubmer\n         * @default\n         */\n        selectionEnd: 0,\n\n        /**\n         * Color of text selection\n         * @type String\n         * @default\n         */\n        selectionColor: 'rgba(17,119,255,0.3)',\n\n        /**\n         * Indicates whether text is in editing mode\n         * @type Boolean\n         * @default\n         */\n        isEditing: false,\n\n        /**\n         * Indicates whether a text can be edited\n         * @type Boolean\n         * @default\n         */\n        editable: true,\n\n        /**\n         * Border color of text object while it's in editing mode\n         * @type String\n         * @default\n         */\n        editingBorderColor: 'rgba(102,153,255,0.25)',\n\n        /**\n         * Width of cursor (in px)\n         * @type Number\n         * @default\n         */\n        cursorWidth: 2,\n\n        /**\n         * Color of default cursor (when not overwritten by character style)\n         * @type String\n         * @default\n         */\n        cursorColor: '#333',\n\n        /**\n         * Delay between cursor blink (in ms)\n         * @type Number\n         * @default\n         */\n        cursorDelay: 1000,\n\n        /**\n         * Duration of cursor fadein (in ms)\n         * @type Number\n         * @default\n         */\n        cursorDuration: 600,\n\n        /**\n         * Object containing character styles\n         * (where top-level properties corresponds to line number and 2nd-level properties -- to char number in a line)\n         * @type Object\n         * @default\n         */\n        styles: null,\n\n        /**\n         * Indicates whether internal text char widths can be cached\n         * @type Boolean\n         * @default\n         */\n        caching: true,\n\n        /**\n         * @private\n         * @type Boolean\n         * @default\n         */\n        _skipFillStrokeCheck: true,\n\n        /**\n         * @private\n         */\n        _reSpace: /\\s|\\n/,\n\n        /**\n         * @private\n         */\n        _fontSizeFraction: 4,\n\n        /**\n         * @private\n         */\n        _currentCursorOpacity: 0,\n\n        /**\n         * @private\n         */\n        _selectionDirection: null,\n\n        /**\n         * @private\n         */\n        _abortCursorAnimation: false,\n\n        /**\n         * @private\n         */\n        _charWidthsCache: { },\n\n        /**\n         * Constructor\n         * @param {String} text Text string\n         * @param {Object} [options] Options object\n         * @return {fabric.IText} thisArg\n         */\n        initialize: function(text, options) {\n            this.styles = options ? (options.styles || { }) : { };\n            this.callSuper('initialize', text, options);\n            this.initBehavior();\n\n            fabric.IText.instances.push(this);\n\n            // caching\n            this.__lineWidths = { };\n            this.__lineHeights = { };\n            this.__lineOffsets = { };\n        },\n\n        /**\n         * Returns true if object has no styling\n         */\n        isEmptyStyles: function() {\n            if (!this.styles) {\n                return true;\n            }\n            var obj = this.styles;\n\n            for (var p1 in obj) {\n                for (var p2 in obj[p1]) {\n                    /*jshint unused:false */\n                    for (var p3 in obj[p1][p2]) {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        },\n\n        /**\n         * Sets selection start (left boundary of a selection)\n         * @param {Number} index Index to set selection start to\n         */\n        setSelectionStart: function(index) {\n            if (this.selectionStart !== index) {\n                this.fire('selection:changed');\n                this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n            }\n            this.selectionStart = index;\n            this.hiddenTextarea && (this.hiddenTextarea.selectionStart = index);\n        },\n\n        /**\n         * Sets selection end (right boundary of a selection)\n         * @param {Number} index Index to set selection end to\n         */\n        setSelectionEnd: function(index) {\n            if (this.selectionEnd !== index) {\n                this.fire('selection:changed');\n                this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n            }\n            this.selectionEnd = index;\n            this.hiddenTextarea && (this.hiddenTextarea.selectionEnd = index);\n        },\n\n        /**\n         * Gets style of a current selection/cursor (at the start position)\n         * @param {Number} [startIndex] Start index to get styles at\n         * @param {Number} [endIndex] End index to get styles at\n         * @return {Object} styles Style object at a specified (or current) index\n         */\n        getSelectionStyles: function(startIndex, endIndex) {\n\n            if (arguments.length === 2) {\n                var styles = [ ];\n                for (var i = startIndex; i < endIndex; i++) {\n                    styles.push(this.getSelectionStyles(i));\n                }\n                return styles;\n            }\n\n            var loc = this.get2DCursorLocation(startIndex);\n            if (this.styles[loc.lineIndex]) {\n                return this.styles[loc.lineIndex][loc.charIndex] || { };\n            }\n\n            return { };\n        },\n\n        /**\n         * Sets style of a current selection\n         * @param {Object} [styles] Styles object\n         * @return {fabric.IText} thisArg\n         * @chainable\n         */\n        setSelectionStyles: function(styles) {\n            if (this.selectionStart === this.selectionEnd) {\n                this._extendStyles(this.selectionStart, styles);\n            }\n            else {\n                for (var i = this.selectionStart; i < this.selectionEnd; i++) {\n                    this._extendStyles(i, styles);\n                }\n            }\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _extendStyles: function(index, styles) {\n            var loc = this.get2DCursorLocation(index);\n\n            if (!this.styles[loc.lineIndex]) {\n                this.styles[loc.lineIndex] = { };\n            }\n            if (!this.styles[loc.lineIndex][loc.charIndex]) {\n                this.styles[loc.lineIndex][loc.charIndex] = { };\n            }\n\n            fabric.util.object.extend(this.styles[loc.lineIndex][loc.charIndex], styles);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _render: function(ctx) {\n            this.callSuper('_render', ctx);\n            this.ctx = ctx;\n            this.isEditing && this.renderCursorOrSelection();\n        },\n\n        /**\n         * Renders cursor or selection (depending on what exists)\n         */\n        renderCursorOrSelection: function() {\n            if (!this.active) {\n                return;\n            }\n\n            var chars = this.text.split(''),\n                boundaries;\n\n            if (this.selectionStart === this.selectionEnd) {\n                boundaries = this._getCursorBoundaries(chars, 'cursor');\n                this.renderCursor(boundaries);\n            }\n            else {\n                boundaries = this._getCursorBoundaries(chars, 'selection');\n                this.renderSelection(chars, boundaries);\n            }\n        },\n\n        /**\n         * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n         * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n         */\n        get2DCursorLocation: function(selectionStart) {\n            if (typeof selectionStart === 'undefined') {\n                selectionStart = this.selectionStart;\n            }\n            var textBeforeCursor = this.text.slice(0, selectionStart),\n                linesBeforeCursor = textBeforeCursor.split(this._reNewline);\n\n            return {\n                lineIndex: linesBeforeCursor.length - 1,\n                charIndex: linesBeforeCursor[linesBeforeCursor.length - 1].length\n            };\n        },\n\n        /**\n         * Returns complete style of char at the current cursor\n         * @param {Number} lineIndex Line index\n         * @param {Number} charIndex Char index\n         * @return {Object} Character style\n         */\n        getCurrentCharStyle: function(lineIndex, charIndex) {\n            var style = this.styles[lineIndex] && this.styles[lineIndex][charIndex === 0 ? 0 : (charIndex - 1)];\n\n            return {\n                fontSize: style && style.fontSize || this.fontSize,\n                fill: style && style.fill || this.fill,\n                textBackgroundColor: style && style.textBackgroundColor || this.textBackgroundColor,\n                textDecoration: style && style.textDecoration || this.textDecoration,\n                fontFamily: style && style.fontFamily || this.fontFamily,\n                fontWeight: style && style.fontWeight || this.fontWeight,\n                fontStyle: style && style.fontStyle || this.fontStyle,\n                stroke: style && style.stroke || this.stroke,\n                strokeWidth: style && style.strokeWidth || this.strokeWidth\n            };\n        },\n\n        /**\n         * Returns fontSize of char at the current cursor\n         * @param {Number} lineIndex Line index\n         * @param {Number} charIndex Char index\n         * @return {Number} Character font size\n         */\n        getCurrentCharFontSize: function(lineIndex, charIndex) {\n            return (\n                this.styles[lineIndex] &&\n                this.styles[lineIndex][charIndex === 0 ? 0 : (charIndex - 1)] &&\n                this.styles[lineIndex][charIndex === 0 ? 0 : (charIndex - 1)].fontSize) || this.fontSize;\n        },\n\n        /**\n         * Returns color (fill) of char at the current cursor\n         * @param {Number} lineIndex Line index\n         * @param {Number} charIndex Char index\n         * @return {String} Character color (fill)\n         */\n        getCurrentCharColor: function(lineIndex, charIndex) {\n            return (\n                this.styles[lineIndex] &&\n                this.styles[lineIndex][charIndex === 0 ? 0 : (charIndex - 1)] &&\n                this.styles[lineIndex][charIndex === 0 ? 0 : (charIndex - 1)].fill) || this.cursorColor;\n        },\n\n        /**\n         * Returns cursor boundaries (left, top, leftOffset, topOffset)\n         * @private\n         * @param {Array} chars Array of characters\n         * @param {String} typeOfBoundaries\n         */\n        _getCursorBoundaries: function(chars, typeOfBoundaries) {\n\n            var cursorLocation = this.get2DCursorLocation(),\n\n                textLines = this.text.split(this._reNewline),\n\n            // left/top are left/top of entire text box\n            // leftOffset/topOffset are offset from that left/top point of a text box\n\n                left = Math.round(this._getLeftOffset()),\n                top = this._getTopOffset(),\n\n                offsets = this._getCursorBoundariesOffsets(\n                    chars, typeOfBoundaries, cursorLocation, textLines);\n\n            return {\n                left: left,\n                top: top,\n                leftOffset: offsets.left + offsets.lineLeft,\n                topOffset: offsets.top\n            };\n        },\n\n        /**\n         * @private\n         */\n        _getCursorBoundariesOffsets: function(chars, typeOfBoundaries, cursorLocation, textLines) {\n\n            var lineLeftOffset = 0,\n\n                lineIndex = 0,\n                charIndex = 0,\n\n                leftOffset = 0,\n                topOffset = typeOfBoundaries === 'cursor'\n                    // selection starts at the very top of the line,\n                    // whereas cursor starts at the padding created by line height\n                    ? (this._getHeightOfLine(this.ctx, 0) -\n                    this.getCurrentCharFontSize(cursorLocation.lineIndex, cursorLocation.charIndex))\n                    : 0;\n\n            for (var i = 0; i < this.selectionStart; i++) {\n                if (chars[i] === '\\n') {\n                    leftOffset = 0;\n                    var index = lineIndex + (typeOfBoundaries === 'cursor' ? 1 : 0);\n                    topOffset += this._getCachedLineHeight(index);\n\n                    lineIndex++;\n                    charIndex = 0;\n                }\n                else {\n                    leftOffset += this._getWidthOfChar(this.ctx, chars[i], lineIndex, charIndex);\n                    charIndex++;\n                }\n\n                lineLeftOffset = this._getCachedLineOffset(lineIndex, textLines);\n            }\n\n            this._clearCache();\n\n            return {\n                top: topOffset,\n                left: leftOffset,\n                lineLeft: lineLeftOffset\n            };\n        },\n\n        /**\n         * @private\n         */\n        _clearCache: function() {\n            this.__lineWidths = { };\n            this.__lineHeights = { };\n            this.__lineOffsets = { };\n        },\n\n        /**\n         * @private\n         */\n        _getCachedLineHeight: function(index) {\n            return this.__lineHeights[index] ||\n                (this.__lineHeights[index] = this._getHeightOfLine(this.ctx, index));\n        },\n\n        /**\n         * @private\n         */\n        _getCachedLineWidth: function(lineIndex, textLines) {\n            return this.__lineWidths[lineIndex] ||\n                (this.__lineWidths[lineIndex] = this._getWidthOfLine(this.ctx, lineIndex, textLines));\n        },\n\n        /**\n         * @private\n         */\n        _getCachedLineOffset: function(lineIndex, textLines) {\n            var widthOfLine = this._getCachedLineWidth(lineIndex, textLines);\n\n            return this.__lineOffsets[lineIndex] ||\n                (this.__lineOffsets[lineIndex] = this._getLineLeftOffset(widthOfLine));\n        },\n\n        /**\n         * Renders cursor\n         * @param {Object} boundaries\n         */\n        renderCursor: function(boundaries) {\n            var ctx = this.ctx;\n\n            ctx.save();\n\n            var cursorLocation = this.get2DCursorLocation(),\n                lineIndex = cursorLocation.lineIndex,\n                charIndex = cursorLocation.charIndex,\n                charHeight = this.getCurrentCharFontSize(lineIndex, charIndex),\n                leftOffset = (lineIndex === 0 && charIndex === 0)\n                    ? this._getCachedLineOffset(lineIndex, this.text.split(this._reNewline))\n                    : boundaries.leftOffset;\n\n            ctx.fillStyle = this.getCurrentCharColor(lineIndex, charIndex);\n            ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity;\n\n            ctx.fillRect(\n                    boundaries.left + leftOffset,\n                    boundaries.top + boundaries.topOffset,\n                    this.cursorWidth / this.scaleX,\n                charHeight);\n\n            ctx.restore();\n        },\n\n        /**\n         * Renders text selection\n         * @param {Array} chars Array of characters\n         * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n         */\n        renderSelection: function(chars, boundaries) {\n            var ctx = this.ctx;\n\n            ctx.save();\n\n            ctx.fillStyle = this.selectionColor;\n\n            var start = this.get2DCursorLocation(this.selectionStart),\n                end = this.get2DCursorLocation(this.selectionEnd),\n                startLine = start.lineIndex,\n                endLine = end.lineIndex,\n                textLines = this.text.split(this._reNewline);\n\n            for (var i = startLine; i <= endLine; i++) {\n                var lineOffset = this._getCachedLineOffset(i, textLines) || 0,\n                    lineHeight = this._getCachedLineHeight(i),\n                    boxWidth = 0;\n\n                if (i === startLine) {\n                    for (var j = 0, len = textLines[i].length; j < len; j++) {\n                        if (j >= start.charIndex && (i !== endLine || j < end.charIndex)) {\n                            boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, j);\n                        }\n                        if (j < start.charIndex) {\n                            lineOffset += this._getWidthOfChar(ctx, textLines[i][j], i, j);\n                        }\n                    }\n                }\n                else if (i > startLine && i < endLine) {\n                    boxWidth += this._getCachedLineWidth(i, textLines) || 5;\n                }\n                else if (i === endLine) {\n                    for (var j2 = 0, j2len = end.charIndex; j2 < j2len; j2++) {\n                        boxWidth += this._getWidthOfChar(ctx, textLines[i][j2], i, j2);\n                    }\n                }\n\n                ctx.fillRect(\n                        boundaries.left + lineOffset,\n                        boundaries.top + boundaries.topOffset,\n                    boxWidth,\n                    lineHeight);\n\n                boundaries.topOffset += lineHeight;\n            }\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {String} method\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderChars: function(method, ctx, line, left, top, lineIndex) {\n\n            if (this.isEmptyStyles()) {\n                return this._renderCharsFast(method, ctx, line, left, top);\n            }\n\n            this.skipTextAlign = true;\n\n            // set proper box offset\n            left -= this.textAlign === 'center'\n                ? (this.width / 2)\n                : (this.textAlign === 'right')\n                ? this.width\n                : 0;\n\n            // set proper line offset\n            var textLines = this.text.split(this._reNewline),\n                lineWidth = this._getWidthOfLine(ctx, lineIndex, textLines),\n                lineHeight = this._getHeightOfLine(ctx, lineIndex, textLines),\n                lineLeftOffset = this._getLineLeftOffset(lineWidth),\n                chars = line.split(''),\n                prevStyle,\n                charsToRender = '';\n\n            left += lineLeftOffset || 0;\n\n            ctx.save();\n\n            for (var i = 0, len = chars.length; i <= len; i++) {\n                prevStyle = prevStyle || this.getCurrentCharStyle(lineIndex, i);\n                var thisStyle = this.getCurrentCharStyle(lineIndex, i + 1);\n\n                if (this._hasStyleChanged(prevStyle, thisStyle) || i === len) {\n                    this._renderChar(method, ctx, lineIndex, i - 1, charsToRender, left, top, lineHeight);\n                    charsToRender = '';\n                    prevStyle = thisStyle;\n                }\n                charsToRender += chars[i];\n            }\n\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         * @param {String} method\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {String} line Content of the line\n         * @param {Number} left Left coordinate\n         * @param {Number} top Top coordinate\n         */\n        _renderCharsFast: function(method, ctx, line, left, top) {\n            this.skipTextAlign = false;\n\n            if (method === 'fillText' && this.fill) {\n                this.callSuper('_renderChars', method, ctx, line, left, top);\n            }\n            if (method === 'strokeText' && this.stroke) {\n                this.callSuper('_renderChars', method, ctx, line, left, top);\n            }\n        },\n\n        /**\n         * @private\n         * @param {String} method\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Number} lineIndex\n         * @param {Number} i\n         * @param {String} _char\n         * @param {Number} left Left coordinate\n         * @param {Number} top Top coordinate\n         * @param {Number} lineHeight Height of the line\n         */\n        _renderChar: function(method, ctx, lineIndex, i, _char, left, top, lineHeight) {\n            var decl, charWidth, charHeight;\n\n            if (this.styles && this.styles[lineIndex] && (decl = this.styles[lineIndex][i])) {\n\n                var shouldStroke = decl.stroke || this.stroke,\n                    shouldFill = decl.fill || this.fill;\n\n                ctx.save();\n                charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i, decl);\n                charHeight = this._getHeightOfChar(ctx, _char, lineIndex, i);\n\n                if (shouldFill) {\n                    ctx.fillText(_char, left, top);\n                }\n                if (shouldStroke) {\n                    ctx.strokeText(_char, left, top);\n                }\n\n                this._renderCharDecoration(ctx, decl, left, top, charWidth, lineHeight, charHeight);\n                ctx.restore();\n\n                ctx.translate(charWidth, 0);\n            }\n            else {\n                if (method === 'strokeText' && this.stroke) {\n                    ctx[method](_char, left, top);\n                }\n                if (method === 'fillText' && this.fill) {\n                    ctx[method](_char, left, top);\n                }\n                charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i);\n                this._renderCharDecoration(ctx, null, left, top, charWidth, lineHeight);\n\n                ctx.translate(ctx.measureText(_char).width, 0);\n            }\n        },\n\n        /**\n         * @private\n         * @param {Object} prevStyle\n         * @param {Object} thisStyle\n         */\n        _hasStyleChanged: function(prevStyle, thisStyle) {\n            return (prevStyle.fill !== thisStyle.fill ||\n                prevStyle.fontSize !== thisStyle.fontSize ||\n                prevStyle.textBackgroundColor !== thisStyle.textBackgroundColor ||\n                prevStyle.textDecoration !== thisStyle.textDecoration ||\n                prevStyle.fontFamily !== thisStyle.fontFamily ||\n                prevStyle.fontWeight !== thisStyle.fontWeight ||\n                prevStyle.fontStyle !== thisStyle.fontStyle ||\n                prevStyle.stroke !== thisStyle.stroke ||\n                prevStyle.strokeWidth !== thisStyle.strokeWidth\n                );\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderCharDecoration: function(ctx, styleDeclaration, left, top, charWidth, lineHeight, charHeight) {\n\n            var textDecoration = styleDeclaration\n                    ? (styleDeclaration.textDecoration || this.textDecoration)\n                    : this.textDecoration,\n\n                fontSize = (styleDeclaration ? styleDeclaration.fontSize : null) || this.fontSize;\n\n            if (!textDecoration) {\n                return;\n            }\n\n            if (textDecoration.indexOf('underline') > -1) {\n                this._renderCharDecorationAtOffset(\n                    ctx,\n                    left,\n                        top + (this.fontSize / this._fontSizeFraction),\n                    charWidth,\n                    0,\n                        this.fontSize / 20\n                );\n            }\n            if (textDecoration.indexOf('line-through') > -1) {\n                this._renderCharDecorationAtOffset(\n                    ctx,\n                    left,\n                        top + (this.fontSize / this._fontSizeFraction),\n                    charWidth,\n                        charHeight / 2,\n                        fontSize / 20\n                );\n            }\n            if (textDecoration.indexOf('overline') > -1) {\n                this._renderCharDecorationAtOffset(\n                    ctx,\n                    left,\n                    top,\n                    charWidth,\n                        lineHeight - (this.fontSize / this._fontSizeFraction),\n                        this.fontSize / 20\n                );\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _renderCharDecorationAtOffset: function(ctx, left, top, charWidth, offset, thickness) {\n            ctx.fillRect(left, top - offset, charWidth, thickness);\n        },\n\n        /**\n         * @private\n         * @param {String} method\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {String} line\n         */\n        _renderTextLine: function(method, ctx, line, left, top, lineIndex) {\n            // to \"cancel\" this.fontSize subtraction in fabric.Text#_renderTextLine\n            top += this.fontSize / 4;\n            this.callSuper('_renderTextLine', method, ctx, line, left, top, lineIndex);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines\n         */\n        _renderTextDecoration: function(ctx, textLines) {\n            if (this.isEmptyStyles()) {\n                return this.callSuper('_renderTextDecoration', ctx, textLines);\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _renderTextLinesBackground: function(ctx, textLines) {\n            if (!this.textBackgroundColor && !this.styles) {\n                return;\n            }\n\n            ctx.save();\n\n            if (this.textBackgroundColor) {\n                ctx.fillStyle = this.textBackgroundColor;\n            }\n\n            var lineHeights = 0,\n                fractionOfFontSize = this.fontSize / this._fontSizeFraction;\n\n            for (var i = 0, len = textLines.length; i < len; i++) {\n\n                var heightOfLine = this._getHeightOfLine(ctx, i, textLines);\n                if (textLines[i] === '') {\n                    lineHeights += heightOfLine;\n                    continue;\n                }\n\n                var lineWidth = this._getWidthOfLine(ctx, i, textLines),\n                    lineLeftOffset = this._getLineLeftOffset(lineWidth);\n\n                if (this.textBackgroundColor) {\n                    ctx.fillStyle = this.textBackgroundColor;\n\n                    ctx.fillRect(\n                            this._getLeftOffset() + lineLeftOffset,\n                            this._getTopOffset() + lineHeights + fractionOfFontSize,\n                        lineWidth,\n                        heightOfLine\n                    );\n                }\n                if (this.styles[i]) {\n                    for (var j = 0, jlen = textLines[i].length; j < jlen; j++) {\n                        if (this.styles[i] && this.styles[i][j] && this.styles[i][j].textBackgroundColor) {\n\n                            var _char = textLines[i][j];\n\n                            ctx.fillStyle = this.styles[i][j].textBackgroundColor;\n\n                            ctx.fillRect(\n                                    this._getLeftOffset() + lineLeftOffset + this._getWidthOfCharsAt(ctx, i, j, textLines),\n                                    this._getTopOffset() + lineHeights + fractionOfFontSize,\n                                    this._getWidthOfChar(ctx, _char, i, j, textLines) + 1,\n                                heightOfLine\n                            );\n                        }\n                    }\n                }\n                lineHeights += heightOfLine;\n            }\n            ctx.restore();\n        },\n\n        /**\n         * @private\n         */\n        _getCacheProp: function(_char, styleDeclaration) {\n            return _char +\n\n                styleDeclaration.fontFamily +\n                styleDeclaration.fontSize +\n                styleDeclaration.fontWeight +\n                styleDeclaration.fontStyle +\n\n                styleDeclaration.shadow;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {String} _char\n         * @param {Number} lineIndex\n         * @param {Number} charIndex\n         * @param {Object} [decl]\n         */\n        _applyCharStylesGetWidth: function(ctx, _char, lineIndex, charIndex, decl) {\n            var styleDeclaration = decl ||\n                (this.styles[lineIndex] &&\n                    this.styles[lineIndex][charIndex]);\n\n            if (styleDeclaration) {\n                // cloning so that original style object is not polluted with following font declarations\n                styleDeclaration = clone(styleDeclaration);\n            }\n            else {\n                styleDeclaration = { };\n            }\n\n            this._applyFontStyles(styleDeclaration);\n\n            var cacheProp = this._getCacheProp(_char, styleDeclaration);\n\n            // short-circuit if no styles\n            if (this.isEmptyStyles() && this._charWidthsCache[cacheProp] && this.caching) {\n                return this._charWidthsCache[cacheProp];\n            }\n\n            if (typeof styleDeclaration.shadow === 'string') {\n                styleDeclaration.shadow = new fabric.Shadow(styleDeclaration.shadow);\n            }\n\n            var fill = styleDeclaration.fill || this.fill;\n            ctx.fillStyle = fill.toLive\n                ? fill.toLive(ctx)\n                : fill;\n\n            if (styleDeclaration.stroke) {\n                ctx.strokeStyle = (styleDeclaration.stroke && styleDeclaration.stroke.toLive)\n                    ? styleDeclaration.stroke.toLive(ctx)\n                    : styleDeclaration.stroke;\n            }\n\n            ctx.lineWidth = styleDeclaration.strokeWidth || this.strokeWidth;\n            ctx.font = this._getFontDeclaration.call(styleDeclaration);\n            this._setShadow.call(styleDeclaration, ctx);\n\n            if (!this.caching) {\n                return ctx.measureText(_char).width;\n            }\n\n            if (!this._charWidthsCache[cacheProp]) {\n                this._charWidthsCache[cacheProp] = ctx.measureText(_char).width;\n            }\n\n            return this._charWidthsCache[cacheProp];\n        },\n\n        /**\n         * @private\n         * @param {Object} styleDeclaration\n         */\n        _applyFontStyles: function(styleDeclaration) {\n            if (!styleDeclaration.fontFamily) {\n                styleDeclaration.fontFamily = this.fontFamily;\n            }\n            if (!styleDeclaration.fontSize) {\n                styleDeclaration.fontSize = this.fontSize;\n            }\n            if (!styleDeclaration.fontWeight) {\n                styleDeclaration.fontWeight = this.fontWeight;\n            }\n            if (!styleDeclaration.fontStyle) {\n                styleDeclaration.fontStyle = this.fontStyle;\n            }\n        },\n\n        /**\n         * @private\n         * @param {Number} lineIndex\n         * @param {Number} charIndex\n         */\n        _getStyleDeclaration: function(lineIndex, charIndex) {\n            return (this.styles[lineIndex] && this.styles[lineIndex][charIndex])\n                ? clone(this.styles[lineIndex][charIndex])\n                : { };\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getWidthOfChar: function(ctx, _char, lineIndex, charIndex) {\n            if (this.textAlign === 'justify' && /\\s/.test(_char)) {\n                return this._getWidthOfSpace(ctx, lineIndex);\n            }\n\n            var styleDeclaration = this._getStyleDeclaration(lineIndex, charIndex);\n            this._applyFontStyles(styleDeclaration);\n            var cacheProp = this._getCacheProp(_char, styleDeclaration);\n\n            if (this._charWidthsCache[cacheProp] && this.caching) {\n                return this._charWidthsCache[cacheProp];\n            }\n            else if (ctx) {\n                ctx.save();\n                var width = this._applyCharStylesGetWidth(ctx, _char, lineIndex, charIndex);\n                ctx.restore();\n                return width;\n            }\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getHeightOfChar: function(ctx, _char, lineIndex, charIndex) {\n            if (this.styles[lineIndex] && this.styles[lineIndex][charIndex]) {\n                return this.styles[lineIndex][charIndex].fontSize || this.fontSize;\n            }\n            return this.fontSize;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getWidthOfCharAt: function(ctx, lineIndex, charIndex, lines) {\n            lines = lines || this.text.split(this._reNewline);\n            var _char = lines[lineIndex].split('')[charIndex];\n            return this._getWidthOfChar(ctx, _char, lineIndex, charIndex);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getHeightOfCharAt: function(ctx, lineIndex, charIndex, lines) {\n            lines = lines || this.text.split(this._reNewline);\n            var _char = lines[lineIndex].split('')[charIndex];\n            return this._getHeightOfChar(ctx, _char, lineIndex, charIndex);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getWidthOfCharsAt: function(ctx, lineIndex, charIndex, lines) {\n            var width = 0;\n            for (var i = 0; i < charIndex; i++) {\n                width += this._getWidthOfCharAt(ctx, lineIndex, i, lines);\n            }\n            return width;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getWidthOfLine: function(ctx, lineIndex, textLines) {\n            // if (!this.styles[lineIndex]) {\n            //   return this.callSuper('_getLineWidth', ctx, textLines[lineIndex]);\n            // }\n            return this._getWidthOfCharsAt(ctx, lineIndex, textLines[lineIndex].length, textLines);\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Number} lineIndex\n         */\n        _getWidthOfSpace: function (ctx, lineIndex) {\n            var lines = this.text.split(this._reNewline),\n                line = lines[lineIndex],\n                words = line.split(/\\s+/),\n                wordsWidth = this._getWidthOfWords(ctx, line, lineIndex),\n                widthDiff = this.width - wordsWidth,\n                numSpaces = words.length - 1,\n                width = widthDiff / numSpaces;\n\n            return width;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Number} line\n         * @param {Number} lineIndex\n         */\n        _getWidthOfWords: function (ctx, line, lineIndex) {\n            var width = 0;\n\n            for (var charIndex = 0; charIndex < line.length; charIndex++) {\n                var _char = line[charIndex];\n\n                if (!_char.match(/\\s/)) {\n                    width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex);\n                }\n            }\n\n            return width;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getTextWidth: function(ctx, textLines) {\n\n            if (this.isEmptyStyles()) {\n                return this.callSuper('_getTextWidth', ctx, textLines);\n            }\n\n            var maxWidth = this._getWidthOfLine(ctx, 0, textLines);\n\n            for (var i = 1, len = textLines.length; i < len; i++) {\n                var currentLineWidth = this._getWidthOfLine(ctx, i, textLines);\n                if (currentLineWidth > maxWidth) {\n                    maxWidth = currentLineWidth;\n                }\n            }\n            return maxWidth;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        _getHeightOfLine: function(ctx, lineIndex, textLines) {\n\n            textLines = textLines || this.text.split(this._reNewline);\n\n            var maxHeight = this._getHeightOfChar(ctx, textLines[lineIndex][0], lineIndex, 0),\n                line = textLines[lineIndex],\n                chars = line.split('');\n\n            for (var i = 1, len = chars.length; i < len; i++) {\n                var currentCharHeight = this._getHeightOfChar(ctx, chars[i], lineIndex, i);\n                if (currentCharHeight > maxHeight) {\n                    maxHeight = currentCharHeight;\n                }\n            }\n\n            return maxHeight * this.lineHeight;\n        },\n\n        /**\n         * @private\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Array} textLines Array of all text lines\n         */\n        _getTextHeight: function(ctx, textLines) {\n            var height = 0;\n            for (var i = 0, len = textLines.length; i < len; i++) {\n                height += this._getHeightOfLine(ctx, i, textLines);\n            }\n            return height;\n        },\n\n        /**\n         * @private\n         */\n        _getTopOffset: function() {\n            var topOffset = fabric.Text.prototype._getTopOffset.call(this);\n            return topOffset - (this.fontSize / this._fontSizeFraction);\n        },\n\n        /**\n         * This method is overwritten to account for different top offset\n         * @private\n         */\n        _renderTextBoxBackground: function(ctx) {\n            if (!this.backgroundColor) {\n                return;\n            }\n\n            ctx.save();\n            ctx.fillStyle = this.backgroundColor;\n\n            ctx.fillRect(\n                this._getLeftOffset(),\n                    this._getTopOffset() + (this.fontSize / this._fontSizeFraction),\n                this.width,\n                this.height\n            );\n\n            ctx.restore();\n        },\n\n        /**\n         * Returns object representation of an instance\n         * @method toObject\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject: function(propertiesToInclude) {\n            return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {\n                styles: clone(this.styles)\n            });\n        }\n    });\n\n    /**\n     * Returns fabric.IText instance from an object representation\n     * @static\n     * @memberOf fabric.IText\n     * @param {Object} object Object to create an instance from\n     * @return {fabric.IText} instance of fabric.IText\n     */\n    fabric.IText.fromObject = function(object) {\n        return new fabric.IText(object.text, clone(object));\n    };\n\n    /**\n     * Contains all fabric.IText objects that have been created\n     * @static\n     * @memberof fabric.IText\n     * @type Array\n     */\n    fabric.IText.instances = [ ];\n\n})();\n\n\n(function() {\n\n    var clone = fabric.util.object.clone;\n\n    fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n        /**\n         * Initializes all the interactive behavior of IText\n         */\n        initBehavior: function() {\n            this.initAddedHandler();\n            this.initCursorSelectionHandlers();\n            this.initDoubleClickSimulation();\n        },\n\n        /**\n         * Initializes \"selected\" event handler\n         */\n        initSelectedHandler: function() {\n            this.on('selected', function() {\n\n                var _this = this;\n                setTimeout(function() {\n                    _this.selected = true;\n                }, 100);\n            });\n        },\n\n        /**\n         * Initializes \"added\" event handler\n         */\n        initAddedHandler: function() {\n            this.on('added', function() {\n                if (this.canvas && !this.canvas._hasITextHandlers) {\n                    this.canvas._hasITextHandlers = true;\n                    this._initCanvasHandlers();\n                }\n            });\n        },\n\n        /**\n         * @private\n         */\n        _initCanvasHandlers: function() {\n            this.canvas.on('selection:cleared', function() {\n                fabric.IText.prototype.exitEditingOnOthers.call();\n            });\n\n            this.canvas.on('mouse:up', function() {\n                fabric.IText.instances.forEach(function(obj) {\n                    obj.__isMousedown = false;\n                });\n            });\n\n            this.canvas.on('object:selected', function(options) {\n                fabric.IText.prototype.exitEditingOnOthers.call(options.target);\n            });\n        },\n\n        /**\n         * @private\n         */\n        _tick: function() {\n            if (this._abortCursorAnimation) {\n                return;\n            }\n\n            var _this = this;\n\n            this.animate('_currentCursorOpacity', 1, {\n\n                duration: this.cursorDuration,\n\n                onComplete: function() {\n                    _this._onTickComplete();\n                },\n\n                onChange: function() {\n                    _this.canvas && _this.canvas.renderAll();\n                },\n\n                abort: function() {\n                    return _this._abortCursorAnimation;\n                }\n            });\n        },\n\n        /**\n         * @private\n         */\n        _onTickComplete: function() {\n            if (this._abortCursorAnimation) {\n                return;\n            }\n\n            var _this = this;\n            if (this._cursorTimeout1) {\n                clearTimeout(this._cursorTimeout1);\n            }\n            this._cursorTimeout1 = setTimeout(function() {\n                _this.animate('_currentCursorOpacity', 0, {\n                    duration: this.cursorDuration / 2,\n                    onComplete: function() {\n                        _this._tick();\n                    },\n                    onChange: function() {\n                        _this.canvas && _this.canvas.renderAll();\n                    },\n                    abort: function() {\n                        return _this._abortCursorAnimation;\n                    }\n                });\n            }, 100);\n        },\n\n        /**\n         * Initializes delayed cursor\n         */\n        initDelayedCursor: function(restart) {\n            var _this = this,\n                delay = restart ? 0 : this.cursorDelay;\n\n            if (restart) {\n                this._abortCursorAnimation = true;\n                clearTimeout(this._cursorTimeout1);\n                this._currentCursorOpacity = 1;\n                this.canvas && this.canvas.renderAll();\n            }\n            if (this._cursorTimeout2) {\n                clearTimeout(this._cursorTimeout2);\n            }\n            this._cursorTimeout2 = setTimeout(function() {\n                _this._abortCursorAnimation = false;\n                _this._tick();\n            }, delay);\n        },\n\n        /**\n         * Aborts cursor animation and clears all timeouts\n         */\n        abortCursorAnimation: function() {\n            this._abortCursorAnimation = true;\n\n            clearTimeout(this._cursorTimeout1);\n            clearTimeout(this._cursorTimeout2);\n\n            this._currentCursorOpacity = 0;\n            this.canvas && this.canvas.renderAll();\n\n            var _this = this;\n            setTimeout(function() {\n                _this._abortCursorAnimation = false;\n            }, 10);\n        },\n\n        /**\n         * Selects entire text\n         */\n        selectAll: function() {\n            this.selectionStart = 0;\n            this.selectionEnd = this.text.length;\n            this.fire('selection:changed');\n            this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n        },\n\n        /**\n         * Returns selected text\n         * @return {String}\n         */\n        getSelectedText: function() {\n            return this.text.slice(this.selectionStart, this.selectionEnd);\n        },\n\n        /**\n         * Find new selection index representing start of current word according to current selection index\n         * @param {Number} startFrom Surrent selection index\n         * @return {Number} New selection index\n         */\n        findWordBoundaryLeft: function(startFrom) {\n            var offset = 0, index = startFrom - 1;\n\n            // remove space before cursor first\n            if (this._reSpace.test(this.text.charAt(index))) {\n                while (this._reSpace.test(this.text.charAt(index))) {\n                    offset++;\n                    index--;\n                }\n            }\n            while (/\\S/.test(this.text.charAt(index)) && index > -1) {\n                offset++;\n                index--;\n            }\n\n            return startFrom - offset;\n        },\n\n        /**\n         * Find new selection index representing end of current word according to current selection index\n         * @param {Number} startFrom Current selection index\n         * @return {Number} New selection index\n         */\n        findWordBoundaryRight: function(startFrom) {\n            var offset = 0, index = startFrom;\n\n            // remove space after cursor first\n            if (this._reSpace.test(this.text.charAt(index))) {\n                while (this._reSpace.test(this.text.charAt(index))) {\n                    offset++;\n                    index++;\n                }\n            }\n            while (/\\S/.test(this.text.charAt(index)) && index < this.text.length) {\n                offset++;\n                index++;\n            }\n\n            return startFrom + offset;\n        },\n\n        /**\n         * Find new selection index representing start of current line according to current selection index\n         * @param {Number} startFrom Current selection index\n         * @return {Number} New selection index\n         */\n        findLineBoundaryLeft: function(startFrom) {\n            var offset = 0, index = startFrom - 1;\n\n            while (!/\\n/.test(this.text.charAt(index)) && index > -1) {\n                offset++;\n                index--;\n            }\n\n            return startFrom - offset;\n        },\n\n        /**\n         * Find new selection index representing end of current line according to current selection index\n         * @param {Number} startFrom Current selection index\n         * @return {Number} New selection index\n         */\n        findLineBoundaryRight: function(startFrom) {\n            var offset = 0, index = startFrom;\n\n            while (!/\\n/.test(this.text.charAt(index)) && index < this.text.length) {\n                offset++;\n                index++;\n            }\n\n            return startFrom + offset;\n        },\n\n        /**\n         * Returns number of newlines in selected text\n         * @return {Number} Number of newlines in selected text\n         */\n        getNumNewLinesInSelectedText: function() {\n            var selectedText = this.getSelectedText(),\n                numNewLines = 0;\n\n            for (var i = 0, chars = selectedText.split(''), len = chars.length; i < len; i++) {\n                if (chars[i] === '\\n') {\n                    numNewLines++;\n                }\n            }\n            return numNewLines;\n        },\n\n        /**\n         * Finds index corresponding to beginning or end of a word\n         * @param {Number} selectionStart Index of a character\n         * @param {Number} direction: 1 or -1\n         * @return {Number} Index of the beginning or end of a word\n         */\n        searchWordBoundary: function(selectionStart, direction) {\n            var index = this._reSpace.test(this.text.charAt(selectionStart)) ? selectionStart - 1 : selectionStart,\n                _char = this.text.charAt(index),\n                reNonWord = /[ \\n\\.,;!\\?\\-]/;\n\n            while (!reNonWord.test(_char) && index > 0 && index < this.text.length) {\n                index += direction;\n                _char = this.text.charAt(index);\n            }\n            if (reNonWord.test(_char) && _char !== '\\n') {\n                index += direction === 1 ? 0 : 1;\n            }\n            return index;\n        },\n\n        /**\n         * Selects a word based on the index\n         * @param {Number} selectionStart Index of a character\n         */\n        selectWord: function(selectionStart) {\n            var newSelectionStart = this.searchWordBoundary(selectionStart, -1), /* search backwards */\n                newSelectionEnd = this.searchWordBoundary(selectionStart, 1); /* search forward */\n\n            this.setSelectionStart(newSelectionStart);\n            this.setSelectionEnd(newSelectionEnd);\n            this.initDelayedCursor(true);\n        },\n\n        /**\n         * Selects a line based on the index\n         * @param {Number} selectionStart Index of a character\n         */\n        selectLine: function(selectionStart) {\n            var newSelectionStart = this.findLineBoundaryLeft(selectionStart),\n                newSelectionEnd = this.findLineBoundaryRight(selectionStart);\n\n            this.setSelectionStart(newSelectionStart);\n            this.setSelectionEnd(newSelectionEnd);\n            this.initDelayedCursor(true);\n        },\n\n        /**\n         * Enters editing state\n         * @return {fabric.IText} thisArg\n         * @chainable\n         */\n        enterEditing: function() {\n            if (this.isEditing || !this.editable) {\n                return;\n            }\n\n            this.exitEditingOnOthers();\n\n            this.isEditing = true;\n\n            this.initHiddenTextarea();\n            this._updateTextarea();\n            this._saveEditingProps();\n            this._setEditingProps();\n\n            this._tick();\n            this.canvas && this.canvas.renderAll();\n\n            this.fire('editing:entered');\n            this.canvas && this.canvas.fire('text:editing:entered', { target: this });\n\n            return this;\n        },\n\n        exitEditingOnOthers: function() {\n            fabric.IText.instances.forEach(function(obj) {\n                obj.selected = false;\n                if (obj.isEditing) {\n                    obj.exitEditing();\n                }\n            }, this);\n        },\n\n        /**\n         * @private\n         */\n        _setEditingProps: function() {\n            this.hoverCursor = 'text';\n\n            if (this.canvas) {\n                this.canvas.defaultCursor = this.canvas.moveCursor = 'text';\n            }\n\n            this.borderColor = this.editingBorderColor;\n\n            this.hasControls = this.selectable = false;\n            this.lockMovementX = this.lockMovementY = true;\n        },\n\n        /**\n         * @private\n         */\n        _updateTextarea: function() {\n            if (!this.hiddenTextarea) {\n                return;\n            }\n\n            this.hiddenTextarea.value = this.text;\n            this.hiddenTextarea.selectionStart = this.selectionStart;\n        },\n\n        /**\n         * @private\n         */\n        _saveEditingProps: function() {\n            this._savedProps = {\n                hasControls: this.hasControls,\n                borderColor: this.borderColor,\n                lockMovementX: this.lockMovementX,\n                lockMovementY: this.lockMovementY,\n                hoverCursor: this.hoverCursor,\n                defaultCursor: this.canvas && this.canvas.defaultCursor,\n                moveCursor: this.canvas && this.canvas.moveCursor\n            };\n        },\n\n        /**\n         * @private\n         */\n        _restoreEditingProps: function() {\n            if (!this._savedProps) {\n                return;\n            }\n\n            this.hoverCursor = this._savedProps.overCursor;\n            this.hasControls = this._savedProps.hasControls;\n            this.borderColor = this._savedProps.borderColor;\n            this.lockMovementX = this._savedProps.lockMovementX;\n            this.lockMovementY = this._savedProps.lockMovementY;\n\n            if (this.canvas) {\n                this.canvas.defaultCursor = this._savedProps.defaultCursor;\n                this.canvas.moveCursor = this._savedProps.moveCursor;\n            }\n        },\n\n        /**\n         * Exits from editing state\n         * @return {fabric.IText} thisArg\n         * @chainable\n         */\n        exitEditing: function() {\n\n            this.selected = false;\n            this.isEditing = false;\n            this.selectable = true;\n\n            this.selectionEnd = this.selectionStart;\n            this.hiddenTextarea && this.canvas && this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea);\n            this.hiddenTextarea = null;\n\n            this.abortCursorAnimation();\n            this._restoreEditingProps();\n            this._currentCursorOpacity = 0;\n\n            this.fire('editing:exited');\n            this.canvas && this.canvas.fire('text:editing:exited', { target: this });\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _removeExtraneousStyles: function() {\n            var textLines = this.text.split(this._reNewline);\n            for (var prop in this.styles) {\n                if (!textLines[prop]) {\n                    delete this.styles[prop];\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _removeCharsFromTo: function(start, end) {\n\n            var i = end;\n            while (i !== start) {\n\n                var prevIndex = this.get2DCursorLocation(i).charIndex;\n                i--;\n\n                var index = this.get2DCursorLocation(i).charIndex,\n                    isNewline = index > prevIndex;\n\n                if (isNewline) {\n                    this.removeStyleObject(isNewline, i + 1);\n                }\n                else {\n                    this.removeStyleObject(this.get2DCursorLocation(i).charIndex === 0, i);\n                }\n\n            }\n\n            this.text = this.text.slice(0, start) +\n                this.text.slice(end);\n        },\n\n        /**\n         * Inserts a character where cursor is (replacing selection if one exists)\n         * @param {String} _chars Characters to insert\n         */\n        insertChars: function(_chars) {\n            var isEndOfLine = this.text.slice(this.selectionStart, this.selectionStart + 1) === '\\n';\n\n            this.text = this.text.slice(0, this.selectionStart) +\n                _chars +\n                this.text.slice(this.selectionEnd);\n\n            if (this.selectionStart === this.selectionEnd) {\n                this.insertStyleObjects(_chars, isEndOfLine, this.copiedStyles);\n            }\n            // else if (this.selectionEnd - this.selectionStart > 1) {\n            // TODO: replace styles properly\n            // console.log('replacing MORE than 1 char');\n            // }\n\n            this.selectionStart += _chars.length;\n            this.selectionEnd = this.selectionStart;\n\n            if (this.canvas) {\n                // TODO: double renderAll gets rid of text box shift happenning sometimes\n                // need to find out what exactly causes it and fix it\n                this.canvas.renderAll().renderAll();\n            }\n\n            this.setCoords();\n            this.fire('changed');\n            this.canvas && this.canvas.fire('text:changed', { target: this });\n        },\n\n        /**\n         * Inserts new style object\n         * @param {Number} lineIndex Index of a line\n         * @param {Number} charIndex Index of a char\n         * @param {Boolean} isEndOfLine True if it's end of line\n         */\n        insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) {\n\n            this.shiftLineStyles(lineIndex, +1);\n\n            if (!this.styles[lineIndex + 1]) {\n                this.styles[lineIndex + 1] = { };\n            }\n\n            var currentCharStyle = this.styles[lineIndex][charIndex - 1],\n                newLineStyles = { };\n\n            // if there's nothing after cursor,\n            // we clone current char style onto the next (otherwise empty) line\n            if (isEndOfLine) {\n                newLineStyles[0] = clone(currentCharStyle);\n                this.styles[lineIndex + 1] = newLineStyles;\n            }\n            // otherwise we clone styles of all chars\n            // after cursor onto the next line, from the beginning\n            else {\n                for (var index in this.styles[lineIndex]) {\n                    if (parseInt(index, 10) >= charIndex) {\n                        newLineStyles[parseInt(index, 10) - charIndex] = this.styles[lineIndex][index];\n                        // remove lines from the previous line since they're on a new line now\n                        delete this.styles[lineIndex][index];\n                    }\n                }\n                this.styles[lineIndex + 1] = newLineStyles;\n            }\n        },\n\n        /**\n         * Inserts style object for a given line/char index\n         * @param {Number} lineIndex Index of a line\n         * @param {Number} charIndex Index of a char\n         * @param {Object} [style] Style object to insert, if given\n         */\n        insertCharStyleObject: function(lineIndex, charIndex, style) {\n\n            var currentLineStyles = this.styles[lineIndex],\n                currentLineStylesCloned = clone(currentLineStyles);\n\n            if (charIndex === 0 && !style) {\n                charIndex = 1;\n            }\n\n            // shift all char styles by 1 forward\n            // 0,1,2,3 -> (charIndex=2) -> 0,1,3,4 -> (insert 2) -> 0,1,2,3,4\n            for (var index in currentLineStylesCloned) {\n                var numericIndex = parseInt(index, 10);\n                if (numericIndex >= charIndex) {\n                    currentLineStyles[numericIndex + 1] = currentLineStylesCloned[numericIndex];\n                    //delete currentLineStyles[index];\n                }\n            }\n\n            this.styles[lineIndex][charIndex] =\n                style || clone(currentLineStyles[charIndex - 1]);\n        },\n\n        /**\n         * Inserts style object(s)\n         * @param {String} _chars Characters at the location where style is inserted\n         * @param {Boolean} isEndOfLine True if it's end of line\n         * @param {Array} [styles] Styles to insert\n         */\n        insertStyleObjects: function(_chars, isEndOfLine, styles) {\n\n            // short-circuit\n            if (this.isEmptyStyles()) {\n                return;\n            }\n\n            var cursorLocation = this.get2DCursorLocation(),\n                lineIndex = cursorLocation.lineIndex,\n                charIndex = cursorLocation.charIndex;\n\n            if (!this.styles[lineIndex]) {\n                this.styles[lineIndex] = { };\n            }\n\n            if (_chars === '\\n') {\n                this.insertNewlineStyleObject(lineIndex, charIndex, isEndOfLine);\n            }\n            else {\n                if (styles) {\n                    this._insertStyles(styles);\n                }\n                else {\n                    // TODO: support multiple style insertion if _chars.length > 1\n                    this.insertCharStyleObject(lineIndex, charIndex);\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _insertStyles: function(styles) {\n            for (var i = 0, len = styles.length; i < len; i++) {\n\n                var cursorLocation = this.get2DCursorLocation(this.selectionStart + i),\n                    lineIndex = cursorLocation.lineIndex,\n                    charIndex = cursorLocation.charIndex;\n\n                this.insertCharStyleObject(lineIndex, charIndex, styles[i]);\n            }\n        },\n\n        /**\n         * Shifts line styles up or down\n         * @param {Number} lineIndex Index of a line\n         * @param {Number} offset Can be -1 or +1\n         */\n        shiftLineStyles: function(lineIndex, offset) {\n            // shift all line styles by 1 upward\n            var clonedStyles = clone(this.styles);\n            for (var line in this.styles) {\n                var numericLine = parseInt(line, 10);\n                if (numericLine > lineIndex) {\n                    this.styles[numericLine + offset] = clonedStyles[numericLine];\n                }\n            }\n        },\n\n        /**\n         * Removes style object\n         * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line\n         * @param {Number} [index] Optional index. When not given, current selectionStart is used.\n         */\n        removeStyleObject: function(isBeginningOfLine, index) {\n\n            var cursorLocation = this.get2DCursorLocation(index),\n                lineIndex = cursorLocation.lineIndex,\n                charIndex = cursorLocation.charIndex;\n\n            if (isBeginningOfLine) {\n\n                var textLines = this.text.split(this._reNewline),\n                    textOnPreviousLine = textLines[lineIndex - 1],\n                    newCharIndexOnPrevLine = textOnPreviousLine\n                        ? textOnPreviousLine.length\n                        : 0;\n\n                if (!this.styles[lineIndex - 1]) {\n                    this.styles[lineIndex - 1] = { };\n                }\n\n                for (charIndex in this.styles[lineIndex]) {\n                    this.styles[lineIndex - 1][parseInt(charIndex, 10) + newCharIndexOnPrevLine]\n                        = this.styles[lineIndex][charIndex];\n                }\n\n                this.shiftLineStyles(lineIndex, -1);\n            }\n            else {\n                var currentLineStyles = this.styles[lineIndex];\n\n                if (currentLineStyles) {\n                    var offset = this.selectionStart === this.selectionEnd ? -1 : 0;\n                    delete currentLineStyles[charIndex + offset];\n                    // console.log('deleting', lineIndex, charIndex + offset);\n                }\n\n                var currentLineStylesCloned = clone(currentLineStyles);\n\n                // shift all styles by 1 backwards\n                for (var i in currentLineStylesCloned) {\n                    var numericIndex = parseInt(i, 10);\n                    if (numericIndex >= charIndex && numericIndex !== 0) {\n                        currentLineStyles[numericIndex - 1] = currentLineStylesCloned[numericIndex];\n                        delete currentLineStyles[numericIndex];\n                    }\n                }\n            }\n        },\n\n        /**\n         * Inserts new line\n         */\n        insertNewline: function() {\n            this.insertChars('\\n');\n        }\n    });\n})();\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n    /**\n     * Initializes \"dbclick\" event handler\n     */\n    initDoubleClickSimulation: function() {\n\n        // for double click\n        this.__lastClickTime = +new Date();\n\n        // for triple click\n        this.__lastLastClickTime = +new Date();\n\n        this.__lastPointer = { };\n\n        this.on('mousedown', this.onMouseDown.bind(this));\n    },\n\n    onMouseDown: function(options) {\n\n        this.__newClickTime = +new Date();\n        var newPointer = this.canvas.getPointer(options.e);\n\n        if (this.isTripleClick(newPointer)) {\n            this.fire('tripleclick', options);\n            this._stopEvent(options.e);\n        }\n        else if (this.isDoubleClick(newPointer)) {\n            this.fire('dblclick', options);\n            this._stopEvent(options.e);\n        }\n\n        this.__lastLastClickTime = this.__lastClickTime;\n        this.__lastClickTime = this.__newClickTime;\n        this.__lastPointer = newPointer;\n        this.__lastIsEditing = this.isEditing;\n        this.__lastSelected = this.selected;\n    },\n\n    isDoubleClick: function(newPointer) {\n        return this.__newClickTime - this.__lastClickTime < 500 &&\n            this.__lastPointer.x === newPointer.x &&\n            this.__lastPointer.y === newPointer.y && this.__lastIsEditing;\n    },\n\n    isTripleClick: function(newPointer) {\n        return this.__newClickTime - this.__lastClickTime < 500 &&\n            this.__lastClickTime - this.__lastLastClickTime < 500 &&\n            this.__lastPointer.x === newPointer.x &&\n            this.__lastPointer.y === newPointer.y;\n    },\n\n    /**\n     * @private\n     */\n    _stopEvent: function(e) {\n        e.preventDefault && e.preventDefault();\n        e.stopPropagation && e.stopPropagation();\n    },\n\n    /**\n     * Initializes event handlers related to cursor or selection\n     */\n    initCursorSelectionHandlers: function() {\n        this.initSelectedHandler();\n        this.initMousedownHandler();\n        this.initMousemoveHandler();\n        this.initMouseupHandler();\n        this.initClicks();\n    },\n\n    /**\n     * Initializes double and triple click event handlers\n     */\n    initClicks: function() {\n        this.on('dblclick', function(options) {\n            this.selectWord(this.getSelectionStartFromPointer(options.e));\n        });\n        this.on('tripleclick', function(options) {\n            this.selectLine(this.getSelectionStartFromPointer(options.e));\n        });\n    },\n\n    /**\n     * Initializes \"mousedown\" event handler\n     */\n    initMousedownHandler: function() {\n        this.on('mousedown', function(options) {\n\n            var pointer = this.canvas.getPointer(options.e);\n\n            this.__mousedownX = pointer.x;\n            this.__mousedownY = pointer.y;\n            this.__isMousedown = true;\n\n            if (this.hiddenTextarea && this.canvas) {\n                this.canvas.wrapperEl.appendChild(this.hiddenTextarea);\n            }\n\n            if (this.selected) {\n                this.setCursorByClick(options.e);\n            }\n\n            if (this.isEditing) {\n                this.__selectionStartOnMouseDown = this.selectionStart;\n                this.initDelayedCursor(true);\n            }\n        });\n    },\n\n    /**\n     * Initializes \"mousemove\" event handler\n     */\n    initMousemoveHandler: function() {\n        this.on('mousemove', function(options) {\n            if (!this.__isMousedown || !this.isEditing) {\n                return;\n            }\n\n            var newSelectionStart = this.getSelectionStartFromPointer(options.e);\n\n            if (newSelectionStart >= this.__selectionStartOnMouseDown) {\n                this.setSelectionStart(this.__selectionStartOnMouseDown);\n                this.setSelectionEnd(newSelectionStart);\n            }\n            else {\n                this.setSelectionStart(newSelectionStart);\n                this.setSelectionEnd(this.__selectionStartOnMouseDown);\n            }\n        });\n    },\n\n    /**\n     * @private\n     */\n    _isObjectMoved: function(e) {\n        var pointer = this.canvas.getPointer(e);\n\n        return this.__mousedownX !== pointer.x ||\n            this.__mousedownY !== pointer.y;\n    },\n\n    /**\n     * Initializes \"mouseup\" event handler\n     */\n    initMouseupHandler: function() {\n        this.on('mouseup', function(options) {\n            this.__isMousedown = false;\n            if (this._isObjectMoved(options.e)) {\n                return;\n            }\n\n            if (this.__lastSelected) {\n                this.enterEditing();\n                this.initDelayedCursor(true);\n            }\n            this.selected = true;\n        });\n    },\n\n    /**\n     * Changes cursor location in a text depending on passed pointer (x/y) object\n     * @param {Event} e Event object\n     */\n    setCursorByClick: function(e) {\n        var newSelectionStart = this.getSelectionStartFromPointer(e);\n\n        if (e.shiftKey) {\n            if (newSelectionStart < this.selectionStart) {\n                this.setSelectionEnd(this.selectionStart);\n                this.setSelectionStart(newSelectionStart);\n            }\n            else {\n                this.setSelectionEnd(newSelectionStart);\n            }\n        }\n        else {\n            this.setSelectionStart(newSelectionStart);\n            this.setSelectionEnd(newSelectionStart);\n        }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @return {Object} Coordinates of a pointer (x, y)\n     */\n    _getLocalRotatedPointer: function(e) {\n        var pointer = this.canvas.getPointer(e),\n\n            pClicked = new fabric.Point(pointer.x, pointer.y),\n            pLeftTop = new fabric.Point(this.left, this.top),\n\n            rotated = fabric.util.rotatePoint(\n                pClicked, pLeftTop, fabric.util.degreesToRadians(-this.angle));\n\n        return this.getLocalPointer(e, rotated);\n    },\n\n    /**\n     * Returns index of a character corresponding to where an object was clicked\n     * @param {Event} e Event object\n     * @return {Number} Index of a character\n     */\n    getSelectionStartFromPointer: function(e) {\n        var mouseOffset = this._getLocalRotatedPointer(e),\n            textLines = this.text.split(this._reNewline),\n            prevWidth = 0,\n            width = 0,\n            height = 0,\n            charIndex = 0,\n            newSelectionStart;\n\n        for (var i = 0, len = textLines.length; i < len; i++) {\n\n            height += this._getHeightOfLine(this.ctx, i) * this.scaleY;\n\n            var widthOfLine = this._getWidthOfLine(this.ctx, i, textLines),\n                lineLeftOffset = this._getLineLeftOffset(widthOfLine);\n\n            width = lineLeftOffset * this.scaleX;\n\n            if (this.flipX) {\n                // when oject is horizontally flipped we reverse chars\n                textLines[i] = textLines[i].split('').reverse().join('');\n            }\n\n            for (var j = 0, jlen = textLines[i].length; j < jlen; j++) {\n\n                var _char = textLines[i][j];\n                prevWidth = width;\n\n                width += this._getWidthOfChar(this.ctx, _char, i, this.flipX ? jlen - j : j) *\n                    this.scaleX;\n\n                if (height <= mouseOffset.y || width <= mouseOffset.x) {\n                    charIndex++;\n                    continue;\n                }\n\n                return this._getNewSelectionStartFromOffset(\n                    mouseOffset, prevWidth, width, charIndex + i, jlen);\n            }\n\n            if (mouseOffset.y < height) {\n                return this._getNewSelectionStartFromOffset(\n                    mouseOffset, prevWidth, width, charIndex + i, jlen);\n            }\n        }\n\n        // clicked somewhere after all chars, so set at the end\n        if (typeof newSelectionStart === 'undefined') {\n            return this.text.length;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _getNewSelectionStartFromOffset: function(mouseOffset, prevWidth, width, index, jlen) {\n\n        var distanceBtwLastCharAndCursor = mouseOffset.x - prevWidth,\n            distanceBtwNextCharAndCursor = width - mouseOffset.x,\n            offset = distanceBtwNextCharAndCursor > distanceBtwLastCharAndCursor ? 0 : 1,\n            newSelectionStart = index + offset;\n\n        // if object is horizontally flipped, mirror cursor location from the end\n        if (this.flipX) {\n            newSelectionStart = jlen - newSelectionStart;\n        }\n\n        if (newSelectionStart > this.text.length) {\n            newSelectionStart = this.text.length;\n        }\n\n        return newSelectionStart;\n    }\n});\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * Initializes hidden textarea (needed to bring up keyboard in iOS)\n     */\n    initHiddenTextarea: function() {\n        this.hiddenTextarea = fabric.document.createElement('textarea');\n\n        this.hiddenTextarea.setAttribute('autocapitalize', 'off');\n        this.hiddenTextarea.style.cssText = 'position: absolute; top: 0; left: -9999px';\n\n        fabric.document.body.appendChild(this.hiddenTextarea);\n\n        fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));\n        fabric.util.addListener(this.hiddenTextarea, 'keypress', this.onKeyPress.bind(this));\n        fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this));\n        fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this));\n\n        if (!this._clickHandlerInitialized && this.canvas) {\n            fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this));\n            this._clickHandlerInitialized = true;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _keysMap: {\n        8:  'removeChars',\n        9:  'exitEditing',\n        27: 'exitEditing',\n        13: 'insertNewline',\n        33: 'moveCursorUp',\n        34: 'moveCursorDown',\n        35: 'moveCursorRight',\n        36: 'moveCursorLeft',\n        37: 'moveCursorLeft',\n        38: 'moveCursorUp',\n        39: 'moveCursorRight',\n        40: 'moveCursorDown',\n        46: 'forwardDelete'\n    },\n\n    /**\n     * @private\n     */\n    _ctrlKeysMap: {\n        65: 'selectAll',\n        88: 'cut'\n    },\n\n    onClick: function() {\n        // No need to trigger click event here, focus is enough to have the keyboard appear on Android\n        this.hiddenTextarea && this.hiddenTextarea.focus();\n    },\n\n    /**\n     * Handles keyup event\n     * @param {Event} e Event object\n     */\n    onKeyDown: function(e) {\n        if (!this.isEditing) {\n            return;\n        }\n\n        if (e.keyCode in this._keysMap) {\n            this[this._keysMap[e.keyCode]](e);\n        }\n        else if ((e.keyCode in this._ctrlKeysMap) && (e.ctrlKey || e.metaKey)) {\n            this[this._ctrlKeysMap[e.keyCode]](e);\n        }\n        else {\n            return;\n        }\n\n        e.stopImmediatePropagation();\n        e.preventDefault();\n\n        this.canvas && this.canvas.renderAll();\n    },\n\n    /**\n     * Forward delete\n     */\n    forwardDelete: function(e) {\n        if (this.selectionStart === this.selectionEnd) {\n            this.moveCursorRight(e);\n        }\n        this.removeChars(e);\n    },\n\n    /**\n     * Copies selected text\n     * @param {Event} e Event object\n     */\n    copy: function(e) {\n        var selectedText = this.getSelectedText(),\n            clipboardData = this._getClipboardData(e);\n\n        // Check for backward compatibility with old browsers\n        if (clipboardData) {\n            clipboardData.setData('text', selectedText);\n        }\n\n        this.copiedText = selectedText;\n        this.copiedStyles = this.getSelectionStyles(\n            this.selectionStart,\n            this.selectionEnd);\n    },\n\n    /**\n     * Pastes text\n     * @param {Event} e Event object\n     */\n    paste: function(e) {\n        var copiedText = null,\n            clipboardData = this._getClipboardData(e);\n\n        // Check for backward compatibility with old browsers\n        if (clipboardData) {\n            copiedText = clipboardData.getData('text');\n        }\n        else {\n            copiedText = this.copiedText;\n        }\n\n        if (copiedText) {\n            this.insertChars(copiedText);\n        }\n    },\n\n    /**\n     * Cuts text\n     * @param {Event} e Event object\n     */\n    cut: function(e) {\n        if (this.selectionStart === this.selectionEnd) {\n            return;\n        }\n\n        this.copy();\n        this.removeChars(e);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @return {Object} Clipboard data object\n     */\n    _getClipboardData: function(e) {\n        return e && (e.clipboardData || fabric.window.clipboardData);\n    },\n\n    /**\n     * Handles keypress event\n     * @param {Event} e Event object\n     */\n    onKeyPress: function(e) {\n        if (!this.isEditing || e.metaKey || e.ctrlKey) {\n            return;\n        }\n        if (e.which !== 0) {\n            this.insertChars(String.fromCharCode(e.which));\n        }\n        e.stopPropagation();\n    },\n\n    /**\n     * Gets start offset of a selection\n     * @param {Event} e Event object\n     * @param {Boolean} isRight\n     * @return {Number}\n     */\n    getDownCursorOffset: function(e, isRight) {\n        var selectionProp = isRight ? this.selectionEnd : this.selectionStart,\n            textLines = this.text.split(this._reNewline),\n            _char,\n            lineLeftOffset,\n\n            textBeforeCursor = this.text.slice(0, selectionProp),\n            textAfterCursor = this.text.slice(selectionProp),\n\n            textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\\n') + 1),\n            textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\\n?/)[1],\n            textOnNextLine = (textAfterCursor.match(/.*\\n(.*)\\n?/) || { })[1] || '',\n\n            cursorLocation = this.get2DCursorLocation(selectionProp);\n\n        // if on last line, down cursor goes to end of line\n        if (cursorLocation.lineIndex === textLines.length - 1 || e.metaKey || e.keyCode === 34) {\n\n            // move to the end of a text\n            return this.text.length - selectionProp;\n        }\n\n        var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines);\n        lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor);\n\n        var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset,\n            lineIndex = cursorLocation.lineIndex;\n\n        for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) {\n            _char = textOnSameLineBeforeCursor[i];\n            widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);\n        }\n\n        var indexOnNextLine = this._getIndexOnNextLine(\n            cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor, textLines);\n\n        return textOnSameLineAfterCursor.length + 1 + indexOnNextLine;\n    },\n\n    /**\n     * @private\n     */\n    _getIndexOnNextLine: function(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor, textLines) {\n        var lineIndex = cursorLocation.lineIndex + 1,\n            widthOfNextLine = this._getWidthOfLine(this.ctx, lineIndex, textLines),\n            lineLeftOffset = this._getLineLeftOffset(widthOfNextLine),\n            widthOfCharsOnNextLine = lineLeftOffset,\n            indexOnNextLine = 0,\n            foundMatch;\n\n        for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) {\n\n            var _char = textOnNextLine[j],\n                widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j);\n\n            widthOfCharsOnNextLine += widthOfChar;\n\n            if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) {\n\n                foundMatch = true;\n\n                var leftEdge = widthOfCharsOnNextLine - widthOfChar,\n                    rightEdge = widthOfCharsOnNextLine,\n                    offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor),\n                    offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor);\n\n                indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j;\n\n                break;\n            }\n        }\n\n        // reached end\n        if (!foundMatch) {\n            indexOnNextLine = textOnNextLine.length;\n        }\n\n        return indexOnNextLine;\n    },\n\n    /**\n     * Moves cursor down\n     * @param {Event} e Event object\n     */\n    moveCursorDown: function(e) {\n        this.abortCursorAnimation();\n        this._currentCursorOpacity = 1;\n\n        var offset = this.getDownCursorOffset(e, this._selectionDirection === 'right');\n\n        if (e.shiftKey) {\n            this.moveCursorDownWithShift(offset);\n        }\n        else {\n            this.moveCursorDownWithoutShift(offset);\n        }\n\n        this.initDelayedCursor();\n    },\n\n    /**\n     * Moves cursor down without keeping selection\n     * @param {Number} offset\n     */\n    moveCursorDownWithoutShift: function(offset) {\n        this._selectionDirection = 'right';\n        this.selectionStart += offset;\n\n        if (this.selectionStart > this.text.length) {\n            this.selectionStart = this.text.length;\n        }\n        this.selectionEnd = this.selectionStart;\n    },\n\n    /**\n     * private\n     */\n    swapSelectionPoints: function() {\n        var swapSel = this.selectionEnd;\n        this.selectionEnd = this.selectionStart;\n        this.selectionStart = swapSel;\n    },\n\n    /**\n     * Moves cursor down while keeping selection\n     * @param {Number} offset\n     */\n    moveCursorDownWithShift: function(offset) {\n        if (this.selectionEnd === this.selectionStart) {\n            this._selectionDirection = 'right';\n        }\n        var prop = this._selectionDirection === 'right' ? 'selectionEnd' : 'selectionStart';\n        this[prop] += offset;\n        if (this.selectionEnd < this.selectionStart  && this._selectionDirection === 'left') {\n            this.swapSelectionPoints();\n            this._selectionDirection = 'right';\n        }\n        if (this.selectionEnd > this.text.length) {\n            this.selectionEnd = this.text.length;\n        }\n    },\n\n    /**\n     * @param {Event} e Event object\n     * @param {Boolean} isRight\n     * @return {Number}\n     */\n    getUpCursorOffset: function(e, isRight) {\n        var selectionProp = isRight ? this.selectionEnd : this.selectionStart,\n            cursorLocation = this.get2DCursorLocation(selectionProp);\n        // if on first line, up cursor goes to start of line\n        if (cursorLocation.lineIndex === 0 || e.metaKey || e.keyCode === 33) {\n            return selectionProp;\n        }\n\n        var textBeforeCursor = this.text.slice(0, selectionProp),\n            textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\\n') + 1),\n            textOnPreviousLine = (textBeforeCursor.match(/\\n?(.*)\\n.*$/) || {})[1] || '',\n            textLines = this.text.split(this._reNewline),\n            _char,\n            widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines),\n            lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor),\n            widthOfCharsOnSameLineBeforeCursor = lineLeftOffset,\n            lineIndex = cursorLocation.lineIndex;\n\n        for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) {\n            _char = textOnSameLineBeforeCursor[i];\n            widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);\n        }\n\n        var indexOnPrevLine = this._getIndexOnPrevLine(\n            cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor, textLines);\n\n        return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length;\n    },\n\n    /**\n     * @private\n     */\n    _getIndexOnPrevLine: function(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor, textLines) {\n\n        var lineIndex = cursorLocation.lineIndex - 1,\n            widthOfPreviousLine = this._getWidthOfLine(this.ctx, lineIndex, textLines),\n            lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine),\n            widthOfCharsOnPreviousLine = lineLeftOffset,\n            indexOnPrevLine = 0,\n            foundMatch;\n\n        for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) {\n\n            var _char = textOnPreviousLine[j],\n                widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j);\n\n            widthOfCharsOnPreviousLine += widthOfChar;\n\n            if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) {\n\n                foundMatch = true;\n\n                var leftEdge = widthOfCharsOnPreviousLine - widthOfChar,\n                    rightEdge = widthOfCharsOnPreviousLine,\n                    offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor),\n                    offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor);\n\n                indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);\n\n                break;\n            }\n        }\n\n        // reached end\n        if (!foundMatch) {\n            indexOnPrevLine = textOnPreviousLine.length - 1;\n        }\n\n        return indexOnPrevLine;\n    },\n\n    /**\n     * Moves cursor up\n     * @param {Event} e Event object\n     */\n    moveCursorUp: function(e) {\n\n        this.abortCursorAnimation();\n        this._currentCursorOpacity = 1;\n\n        var offset = this.getUpCursorOffset(e, this._selectionDirection === 'right');\n        if (e.shiftKey) {\n            this.moveCursorUpWithShift(offset);\n        }\n        else {\n            this.moveCursorUpWithoutShift(offset);\n        }\n\n        this.initDelayedCursor();\n    },\n\n    /**\n     * Moves cursor up with shift\n     * @param {Number} offset\n     */\n    moveCursorUpWithShift: function(offset) {\n        if (this.selectionEnd === this.selectionStart) {\n            this._selectionDirection = 'left';\n        }\n        var prop = this._selectionDirection === 'right' ? 'selectionEnd' : 'selectionStart';\n        this[prop] -= offset;\n        if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'right') {\n            this.swapSelectionPoints();\n            this._selectionDirection = 'left';\n        }\n        if (this.selectionStart < 0) {\n            this.selectionStart = 0;\n        }\n    },\n\n    /**\n     * Moves cursor up without shift\n     * @param {Number} offset\n     */\n    moveCursorUpWithoutShift: function(offset) {\n        if (this.selectionStart === this.selectionEnd) {\n            this.selectionStart -= offset;\n        }\n        if (this.selectionStart < 0) {\n            this.selectionStart = 0;\n        }\n        this.selectionEnd = this.selectionStart;\n\n        this._selectionDirection = 'left';\n    },\n\n    /**\n     * Moves cursor left\n     * @param {Event} e Event object\n     */\n    moveCursorLeft: function(e) {\n        if (this.selectionStart === 0 && this.selectionEnd === 0) {\n            return;\n        }\n\n        this.abortCursorAnimation();\n        this._currentCursorOpacity = 1;\n\n        if (e.shiftKey) {\n            this.moveCursorLeftWithShift(e);\n        }\n        else {\n            this.moveCursorLeftWithoutShift(e);\n        }\n\n        this.initDelayedCursor();\n    },\n\n    /**\n     * @private\n     */\n    _move: function(e, prop, direction) {\n        if (e.altKey) {\n            this[prop] = this['findWordBoundary' + direction](this[prop]);\n        }\n        else if (e.metaKey || e.keyCode === 35 ||  e.keyCode === 36 ) {\n            this[prop] = this['findLineBoundary' + direction](this[prop]);\n        }\n        else {\n            this[prop] += (direction === 'Left' ? -1 : 1);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _moveLeft: function(e, prop) {\n        this._move(e, prop, 'Left');\n    },\n\n    /**\n     * @private\n     */\n    _moveRight: function(e, prop) {\n        this._move(e, prop, 'Right');\n    },\n\n    /**\n     * Moves cursor left without keeping selection\n     * @param {Event} e\n     */\n    moveCursorLeftWithoutShift: function(e) {\n        this._selectionDirection = 'left';\n\n        // only move cursor when there is no selection,\n        // otherwise we discard it, and leave cursor on same place\n        if (this.selectionEnd === this.selectionStart) {\n            this._moveLeft(e, 'selectionStart');\n        }\n        this.selectionEnd = this.selectionStart;\n    },\n\n    /**\n     * Moves cursor left while keeping selection\n     * @param {Event} e\n     */\n    moveCursorLeftWithShift: function(e) {\n        if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) {\n            this._moveLeft(e, 'selectionEnd');\n        }\n        else {\n            this._selectionDirection = 'left';\n            this._moveLeft(e, 'selectionStart');\n\n            // increase selection by one if it's a newline\n            if (this.text.charAt(this.selectionStart) === '\\n') {\n                this.selectionStart--;\n            }\n            if (this.selectionStart < 0) {\n                this.selectionStart = 0;\n            }\n        }\n    },\n\n    /**\n     * Moves cursor right\n     * @param {Event} e Event object\n     */\n    moveCursorRight: function(e) {\n        if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) {\n            return;\n        }\n\n        this.abortCursorAnimation();\n        this._currentCursorOpacity = 1;\n\n        if (e.shiftKey) {\n            this.moveCursorRightWithShift(e);\n        }\n        else {\n            this.moveCursorRightWithoutShift(e);\n        }\n\n        this.initDelayedCursor();\n    },\n\n    /**\n     * Moves cursor right while keeping selection\n     * @param {Event} e\n     */\n    moveCursorRightWithShift: function(e) {\n        if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) {\n            this._moveRight(e, 'selectionStart');\n        }\n        else {\n            this._selectionDirection = 'right';\n            this._moveRight(e, 'selectionEnd');\n\n            // increase selection by one if it's a newline\n            if (this.text.charAt(this.selectionEnd - 1) === '\\n') {\n                this.selectionEnd++;\n            }\n            if (this.selectionEnd > this.text.length) {\n                this.selectionEnd = this.text.length;\n            }\n        }\n    },\n\n    /**\n     * Moves cursor right without keeping selection\n     * @param {Event} e Event object\n     */\n    moveCursorRightWithoutShift: function(e) {\n        this._selectionDirection = 'right';\n\n        if (this.selectionStart === this.selectionEnd) {\n            this._moveRight(e, 'selectionStart');\n            this.selectionEnd = this.selectionStart;\n        }\n        else {\n            this.selectionEnd += this.getNumNewLinesInSelectedText();\n            if (this.selectionEnd > this.text.length) {\n                this.selectionEnd = this.text.length;\n            }\n            this.selectionStart = this.selectionEnd;\n        }\n    },\n\n    /**\n     * Inserts a character where cursor is (replacing selection if one exists)\n     * @param {Event} e Event object\n     */\n    removeChars: function(e) {\n        if (this.selectionStart === this.selectionEnd) {\n            this._removeCharsNearCursor(e);\n        }\n        else {\n            this._removeCharsFromTo(this.selectionStart, this.selectionEnd);\n        }\n\n        this.selectionEnd = this.selectionStart;\n\n        this._removeExtraneousStyles();\n\n        if (this.canvas) {\n            // TODO: double renderAll gets rid of text box shift happenning sometimes\n            // need to find out what exactly causes it and fix it\n            this.canvas.renderAll().renderAll();\n        }\n\n        this.setCoords();\n        this.fire('changed');\n        this.canvas && this.canvas.fire('text:changed', { target: this });\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     */\n    _removeCharsNearCursor: function(e) {\n        if (this.selectionStart !== 0) {\n\n            if (e.metaKey) {\n                // remove all till the start of current line\n                var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart);\n\n                this._removeCharsFromTo(leftLineBoundary, this.selectionStart);\n                this.selectionStart = leftLineBoundary;\n            }\n            else if (e.altKey) {\n                // remove all till the start of current word\n                var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart);\n\n                this._removeCharsFromTo(leftWordBoundary, this.selectionStart);\n                this.selectionStart = leftWordBoundary;\n            }\n            else {\n                var isBeginningOfLine = this.text.slice(this.selectionStart - 1, this.selectionStart) === '\\n';\n                this.removeStyleObject(isBeginningOfLine);\n\n                this.selectionStart--;\n                this.text = this.text.slice(0, this.selectionStart) +\n                    this.text.slice(this.selectionStart + 1);\n            }\n        }\n    }\n});\n\n\n/* _TO_SVG_START_ */\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * @private\n     */\n    _setSVGTextLineText: function(textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects) {\n        if (!this.styles[lineIndex]) {\n            this.callSuper('_setSVGTextLineText',\n                textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier);\n        }\n        else {\n            this._setSVGTextLineChars(\n                textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGTextLineChars: function(textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects) {\n\n        var yProp = lineIndex === 0 || this.useNative ? 'y' : 'dy',\n            chars = textLine.split(''),\n            charOffset = 0,\n            lineLeftOffset = this._getSVGLineLeftOffset(lineIndex),\n            lineTopOffset = this._getSVGLineTopOffset(lineIndex),\n            heightOfLine = this._getHeightOfLine(this.ctx, lineIndex);\n\n        for (var i = 0, len = chars.length; i < len; i++) {\n            var styleDecl = this.styles[lineIndex][i] || { };\n\n            textSpans.push(\n                this._createTextCharSpan(\n                    chars[i], styleDecl, lineLeftOffset, lineTopOffset, yProp, charOffset));\n\n            var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i);\n\n            if (styleDecl.textBackgroundColor) {\n                textBgRects.push(\n                    this._createTextCharBg(\n                        styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset));\n            }\n\n            charOffset += charWidth;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _getSVGLineLeftOffset: function(lineIndex) {\n        return (this._boundaries && this._boundaries[lineIndex])\n            ? fabric.util.toFixed(this._boundaries[lineIndex].left, 2)\n            : 0;\n    },\n\n    /**\n     * @private\n     */\n    _getSVGLineTopOffset: function(lineIndex) {\n        var lineTopOffset = 0;\n        for (var j = 0; j <= lineIndex; j++) {\n            lineTopOffset += this._getHeightOfLine(this.ctx, j);\n        }\n        return lineTopOffset - this.height / 2;\n    },\n\n    /**\n     * @private\n     */\n    _createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) {\n        return [\n            //jscs:disable validateIndentation\n            '<rect fill=\"', styleDecl.textBackgroundColor,\n            '\" transform=\"translate(',\n                -this.width / 2, ' ',\n                -this.height + heightOfLine, ')',\n            '\" x=\"', lineLeftOffset + charOffset,\n            '\" y=\"', lineTopOffset + heightOfLine,\n            '\" width=\"', charWidth,\n            '\" height=\"', heightOfLine,\n            '\"></rect>'\n            //jscs:enable validateIndentation\n        ].join('');\n    },\n\n    /**\n     * @private\n     */\n    _createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, yProp, charOffset) {\n\n        var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({\n            visible: true,\n            fill: this.fill,\n            stroke: this.stroke,\n            type: 'text'\n        }, styleDecl));\n\n        return [\n            //jscs:disable validateIndentation\n            '<tspan x=\"', lineLeftOffset + charOffset, '\" ',\n            yProp, '=\"', lineTopOffset, '\" ',\n\n            (styleDecl.fontFamily ? 'font-family=\"' + styleDecl.fontFamily.replace(/\"/g, '\\'') + '\" ': ''),\n            (styleDecl.fontSize ? 'font-size=\"' + styleDecl.fontSize + '\" ': ''),\n            (styleDecl.fontStyle ? 'font-style=\"' + styleDecl.fontStyle + '\" ': ''),\n            (styleDecl.fontWeight ? 'font-weight=\"' + styleDecl.fontWeight + '\" ': ''),\n            (styleDecl.textDecoration ? 'text-decoration=\"' + styleDecl.textDecoration + '\" ': ''),\n            'style=\"', fillStyles, '\">',\n\n            fabric.util.string.escapeXml(_char),\n            '</tspan>'\n            //jscs:enable validateIndentation\n        ].join('');\n    }\n});\n/* _TO_SVG_END_ */\n\n\n(function() {\n\n    if (typeof document !== 'undefined' && typeof window !== 'undefined') {\n        return;\n    }\n\n    var DOMParser = require('xmldom').DOMParser,\n        URL = require('url'),\n        HTTP = require('http'),\n        HTTPS = require('https'),\n\n        Canvas = require('canvas'),\n        Image = require('canvas').Image;\n\n    /** @private */\n    function request(url, encoding, callback) {\n        var oURL = URL.parse(url);\n\n        // detect if http or https is used\n        if ( !oURL.port ) {\n            oURL.port = ( oURL.protocol.indexOf('https:') === 0 ) ? 443 : 80;\n        }\n\n        // assign request handler based on protocol\n        var reqHandler = ( oURL.port === 443 ) ? HTTPS : HTTP,\n            req = reqHandler.request({\n                hostname: oURL.hostname,\n                port: oURL.port,\n                path: oURL.path,\n                method: 'GET'\n            }, function(response) {\n                var body = '';\n                if (encoding) {\n                    response.setEncoding(encoding);\n                }\n                response.on('end', function () {\n                    callback(body);\n                });\n                response.on('data', function (chunk) {\n                    if (response.statusCode === 200) {\n                        body += chunk;\n                    }\n                });\n            });\n\n        req.on('error', function(err) {\n            if (err.errno === process.ECONNREFUSED) {\n                fabric.log('ECONNREFUSED: connection refused to ' + oURL.hostname + ':' + oURL.port);\n            }\n            else {\n                fabric.log(err.message);\n            }\n        });\n\n        req.end();\n    }\n\n    /** @private */\n    function requestFs(path, callback) {\n        var fs = require('fs');\n        fs.readFile(path, function (err, data) {\n            if (err) {\n                fabric.log(err);\n                throw err;\n            }\n            else {\n                callback(data);\n            }\n        });\n    }\n\n    fabric.util.loadImage = function(url, callback, context) {\n        function createImageAndCallBack(data) {\n            img.src = new Buffer(data, 'binary');\n            // preserving original url, which seems to be lost in node-canvas\n            img._src = url;\n            callback && callback.call(context, img);\n        }\n        var img = new Image();\n        if (url && (url instanceof Buffer || url.indexOf('data') === 0)) {\n            img.src = img._src = url;\n            callback && callback.call(context, img);\n        }\n        else if (url && url.indexOf('http') !== 0) {\n            requestFs(url, createImageAndCallBack);\n        }\n        else if (url) {\n            request(url, 'binary', createImageAndCallBack);\n        }\n        else {\n            callback && callback.call(context, url);\n        }\n    };\n\n    fabric.loadSVGFromURL = function(url, callback, reviver) {\n        url = url.replace(/^\\n\\s*/, '').replace(/\\?.*$/, '').trim();\n        if (url.indexOf('http') !== 0) {\n            requestFs(url, function(body) {\n                fabric.loadSVGFromString(body.toString(), callback, reviver);\n            });\n        }\n        else {\n            request(url, '', function(body) {\n                fabric.loadSVGFromString(body, callback, reviver);\n            });\n        }\n    };\n\n    fabric.loadSVGFromString = function(string, callback, reviver) {\n        var doc = new DOMParser().parseFromString(string);\n        fabric.parseSVGDocument(doc.documentElement, function(results, options) {\n            callback && callback(results, options);\n        }, reviver);\n    };\n\n    fabric.util.getScript = function(url, callback) {\n        request(url, '', function(body) {\n            eval(body);\n            callback && callback();\n        });\n    };\n\n    fabric.Image.fromObject = function(object, callback) {\n        fabric.util.loadImage(object.src, function(img) {\n            var oImg = new fabric.Image(img);\n\n            oImg._initConfig(object);\n            oImg._initFilters(object, function(filters) {\n                oImg.filters = filters || [ ];\n                callback && callback(oImg);\n            });\n        });\n    };\n\n    /**\n     * Only available when running fabric on node.js\n     * @param {Number} width Canvas width\n     * @param {Number} height Canvas height\n     * @param {Object} [options] Options to pass to FabricCanvas.\n     * @param {Object} [nodeCanvasOptions] Options to pass to NodeCanvas.\n     * @return {Object} wrapped canvas instance\n     */\n    fabric.createCanvasForNode = function(width, height, options, nodeCanvasOptions) {\n        nodeCanvasOptions = nodeCanvasOptions || options;\n\n        var canvasEl = fabric.document.createElement('canvas'),\n            nodeCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions);\n\n        // jsdom doesn't create style on canvas element, so here be temp. workaround\n        canvasEl.style = { };\n\n        canvasEl.width = nodeCanvas.width;\n        canvasEl.height = nodeCanvas.height;\n\n        var FabricCanvas = fabric.Canvas || fabric.StaticCanvas,\n            fabricCanvas = new FabricCanvas(canvasEl, options);\n\n        fabricCanvas.contextContainer = nodeCanvas.getContext('2d');\n        fabricCanvas.nodeCanvas = nodeCanvas;\n        fabricCanvas.Font = Canvas.Font;\n\n        return fabricCanvas;\n    };\n\n    /** @ignore */\n    fabric.StaticCanvas.prototype.createPNGStream = function() {\n        return this.nodeCanvas.createPNGStream();\n    };\n\n    fabric.StaticCanvas.prototype.createJPEGStream = function(opts) {\n        return this.nodeCanvas.createJPEGStream(opts);\n    };\n\n    var origSetWidth = fabric.StaticCanvas.prototype.setWidth;\n    fabric.StaticCanvas.prototype.setWidth = function(width, options) {\n        origSetWidth.call(this, width, options);\n        this.nodeCanvas.width = width;\n        return this;\n    };\n    if (fabric.Canvas) {\n        fabric.Canvas.prototype.setWidth = fabric.StaticCanvas.prototype.setWidth;\n    }\n\n    var origSetHeight = fabric.StaticCanvas.prototype.setHeight;\n    fabric.StaticCanvas.prototype.setHeight = function(height, options) {\n        origSetHeight.call(this, height, options);\n        this.nodeCanvas.height = height;\n        return this;\n    };\n    if (fabric.Canvas) {\n        fabric.Canvas.prototype.setHeight = fabric.StaticCanvas.prototype.setHeight;\n    }\n\n})();\n\n\n\n"
  },
  {
    "path": "src/libs/fabric.require1-4-12.min.js",
    "content": "var fabric=fabric||{version:\"1.4.12\"};\"undefined\"!=typeof exports&&(exports.fabric=fabric),\"undefined\"!=typeof document&&\"undefined\"!=typeof window?(fabric.document=document,fabric.window=window):(fabric.document=require(\"jsdom\").jsdom(\"<!DOCTYPE html><html><head></head><body></body></html>\"),fabric.window=fabric.document.createWindow()),fabric.isTouchSupported=\"ontouchstart\"in fabric.document.documentElement,fabric.isLikelyNode=\"undefined\"!=typeof Buffer&&\"undefined\"==typeof window,fabric.SHARED_ATTRIBUTES=[\"display\",\"transform\",\"fill\",\"fill-opacity\",\"fill-rule\",\"opacity\",\"stroke\",\"stroke-dasharray\",\"stroke-linecap\",\"stroke-linejoin\",\"stroke-miterlimit\",\"stroke-opacity\",\"stroke-width\"],fabric.DPI=96,function(){function a(a,b){this.__eventListeners[a]&&(b?fabric.util.removeFromArray(this.__eventListeners[a],b):this.__eventListeners[a].length=0)}function b(a,b){if(this.__eventListeners||(this.__eventListeners={}),1===arguments.length)for(var c in a)this.on(c,a[c]);else this.__eventListeners[a]||(this.__eventListeners[a]=[]),this.__eventListeners[a].push(b);return this}function c(b,c){if(this.__eventListeners){if(0===arguments.length)this.__eventListeners={};else if(1===arguments.length&&\"object\"==typeof arguments[0])for(var d in b)a.call(this,d,b[d]);else a.call(this,b,c);return this}}function d(a,b){if(this.__eventListeners){var c=this.__eventListeners[a];if(c){for(var d=0,e=c.length;d<e;d++)c[d].call(this,b||{});return this}}}fabric.Observable={observe:b,stopObserving:c,fire:d,on:b,off:c,trigger:d}}(),fabric.Collection={add:function(){this._objects.push.apply(this._objects,arguments);for(var a=0,b=arguments.length;a<b;a++)this._onObjectAdded(arguments[a]);return this.renderOnAddRemove&&this.renderAll(),this},insertAt:function(a,b,c){var d=this.getObjects();return c?d[b]=a:d.splice(b,0,a),this._onObjectAdded(a),this.renderOnAddRemove&&this.renderAll(),this},remove:function(){for(var b,a=this.getObjects(),c=0,d=arguments.length;c<d;c++)b=a.indexOf(arguments[c]),b!==-1&&(a.splice(b,1),this._onObjectRemoved(arguments[c]));return this.renderOnAddRemove&&this.renderAll(),this},forEachObject:function(a,b){for(var c=this.getObjects(),d=c.length;d--;)a.call(b,c[d],d,c);return this},getObjects:function(a){return\"undefined\"==typeof a?this._objects:this._objects.filter(function(b){return b.type===a})},item:function(a){return this.getObjects()[a]},isEmpty:function(){return 0===this.getObjects().length},size:function(){return this.getObjects().length},contains:function(a){return this.getObjects().indexOf(a)>-1},complexity:function(){return this.getObjects().reduce(function(a,b){return a+=b.complexity?b.complexity():0},0)}},function(a){var b=Math.sqrt,c=Math.atan2,d=Math.PI/180;fabric.util={removeFromArray:function(a,b){var c=a.indexOf(b);return c!==-1&&a.splice(c,1),a},getRandomInt:function(a,b){return Math.floor(Math.random()*(b-a+1))+a},degreesToRadians:function(a){return a*d},radiansToDegrees:function(a){return a/d},rotatePoint:function(a,b,c){var d=Math.sin(c),e=Math.cos(c);a.subtractEquals(b);var f=a.x*e-a.y*d,g=a.x*d+a.y*e;return new fabric.Point(f,g).addEquals(b)},transformPoint:function(a,b,c){return c?new fabric.Point(b[0]*a.x+b[1]*a.y,b[2]*a.x+b[3]*a.y):new fabric.Point(b[0]*a.x+b[1]*a.y+b[4],b[2]*a.x+b[3]*a.y+b[5])},invertTransform:function(a){var b=a.slice(),c=1/(a[0]*a[3]-a[1]*a[2]);b=[c*a[3],-c*a[1],-c*a[2],c*a[0],0,0];var d=fabric.util.transformPoint({x:a[4],y:a[5]},b);return b[4]=-d.x,b[5]=-d.y,b},toFixed:function(a,b){return parseFloat(Number(a).toFixed(b))},parseUnit:function(a){var b=/\\D{0,2}$/.exec(a),c=parseFloat(a);switch(b[0]){case\"mm\":return c*fabric.DPI/25.4;case\"cm\":return c*fabric.DPI/2.54;case\"in\":return c*fabric.DPI;case\"pt\":return c*fabric.DPI/72;case\"pc\":return c*fabric.DPI/72*12;default:return c}},falseFunction:function(){return!1},getKlass:function(a,b){return a=fabric.util.string.camelize(a.charAt(0).toUpperCase()+a.slice(1)),fabric.util.resolveNamespace(b)[a]},resolveNamespace:function(b){if(!b)return fabric;for(var c=b.split(\".\"),d=c.length,e=a||fabric.window,f=0;f<d;++f)e=e[c[f]];return e},loadImage:function(a,b,c,d){if(!a)return void(b&&b.call(c,a));var e=fabric.util.createImage();e.onload=function(){b&&b.call(c,e),e=e.onload=e.onerror=null},e.onerror=function(){fabric.log(\"Error loading \"+e.src),b&&b.call(c,null,!0),e=e.onload=e.onerror=null},0!==a.indexOf(\"data\")&&\"undefined\"!=typeof d&&(e.crossOrigin=d),e.src=a},enlivenObjects:function(a,b,c,d){function e(){++g===h&&b&&b(f)}a=a||[];var f=[],g=0,h=a.length;return h?void a.forEach(function(a,b){if(!a||!a.type)return void e();var g=fabric.util.getKlass(a.type,c);g.async?g.fromObject(a,function(c,g){g||(f[b]=c,d&&d(a,f[b])),e()}):(f[b]=g.fromObject(a),d&&d(a,f[b]),e())}):void(b&&b(f))},groupSVGElements:function(a,b,c){var d;return d=new fabric.PathGroup(a,b),\"undefined\"!=typeof c&&d.setSourcePath(c),d},populateWithProperties:function(a,b,c){if(c&&\"[object Array]\"===Object.prototype.toString.call(c))for(var d=0,e=c.length;d<e;d++)c[d]in a&&(b[c[d]]=a[c[d]])},drawDashedLine:function(a,d,e,f,g,h){var i=f-d,j=g-e,k=b(i*i+j*j),l=c(j,i),m=h.length,n=0,o=!0;for(a.save(),a.translate(d,e),a.moveTo(0,0),a.rotate(l),d=0;k>d;)d+=h[n++%m],d>k&&(d=k),a[o?\"lineTo\":\"moveTo\"](d,0),o=!o;a.restore()},createCanvasElement:function(a){return a||(a=fabric.document.createElement(\"canvas\")),a.getContext||\"undefined\"==typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(a),a},createImage:function(){return fabric.isLikelyNode?new(require(\"canvas\").Image):fabric.document.createElement(\"img\")},createAccessors:function(a){for(var b=a.prototype,c=b.stateProperties.length;c--;){var d=b.stateProperties[c],e=d.charAt(0).toUpperCase()+d.slice(1),f=\"set\"+e,g=\"get\"+e;b[g]||(b[g]=function(a){return new Function('return this.get(\"'+a+'\")')}(d)),b[f]||(b[f]=function(a){return new Function(\"value\",'return this.set(\"'+a+'\", value)')}(d))}},clipContext:function(a,b){b.save(),b.beginPath(),a.clipTo(b),b.clip()},multiplyTransformMatrices:function(a,b){for(var c=[[a[0],a[2],a[4]],[a[1],a[3],a[5]],[0,0,1]],d=[[b[0],b[2],b[4]],[b[1],b[3],b[5]],[0,0,1]],e=[],f=0;f<3;f++){e[f]=[];for(var g=0;g<3;g++){for(var h=0,i=0;i<3;i++)h+=c[f][i]*d[i][g];e[f][g]=h}}return[e[0][0],e[1][0],e[0][1],e[1][1],e[0][2],e[1][2]]},getFunctionBody:function(a){return(String(a).match(/function[^{]*\\{([\\s\\S]*)\\}/)||{})[1]},isTransparent:function(a,b,c,d){d>0&&(b>d?b-=d:b=0,c>d?c-=d:c=0);for(var e=!0,f=a.getImageData(b,c,2*d||1,2*d||1),g=3,h=f.data.length;g<h;g+=4){var i=f.data[g];if(e=i<=0,e===!1)break}return f=null,e}}}(\"undefined\"!=typeof exports?exports:this),function(){function e(b,c,e,h,i,j,k){var l=d.call(arguments);if(a[l])return a[l];var m=Math.PI,n=k*m/180,o=Math.sin(n),p=Math.cos(n),q=0,r=0;e=Math.abs(e),h=Math.abs(h);var s=-p*b*.5-o*c*.5,t=-p*c*.5+o*b*.5,u=e*e,v=h*h,w=t*t,x=s*s,y=u*v-u*w-v*x,z=0;if(y<0){var A=Math.sqrt(1-y/(u*v));e*=A,h*=A}else z=(i===j?-1:1)*Math.sqrt(y/(u*w+v*x));var B=z*e*t/h,C=-z*h*s/e,D=p*B-o*C+.5*b,E=o*B+p*C+.5*c,F=g(1,0,(s-B)/e,(t-C)/h),G=g((s-B)/e,(t-C)/h,(-s-B)/e,(-t-C)/h);0===j&&G>0?G-=2*m:1===j&&G<0&&(G+=2*m);for(var H=Math.ceil(Math.abs(G/m*2)),I=[],J=G/H,K=8/3*Math.sin(J/4)*Math.sin(J/4)/Math.sin(J/2),L=F+J,M=0;M<H;M++)I[M]=f(F,L,p,o,e,h,D,E,K,q,r),q=I[M][4],r=I[M][5],F=L,L+=J;return a[l]=I,I}function f(a,c,e,f,g,h,i,j,k,l,m){var n=d.call(arguments);if(b[n])return b[n];var o=Math.cos(a),p=Math.sin(a),q=Math.cos(c),r=Math.sin(c),s=e*g*q-f*h*r+i,t=f*g*q+e*h*r+j,u=l+k*(-e*g*p-f*h*o),v=m+k*(-f*g*p+e*h*o),w=s+k*(e*g*r+f*h*q),x=t+k*(f*g*r-e*h*q);return b[n]=[u,v,w,x,s,t],b[n]}function g(a,b,c,d){var e=Math.atan2(b,a),f=Math.atan2(d,c);return f>=e?f-e:2*Math.PI-(e-f)}function h(a,b,e,f,g,h,i,j){var k=d.call(arguments);if(c[k])return c[k];var r,s,t,u,v,w,x,y,l=Math.sqrt,m=Math.min,n=Math.max,o=Math.abs,p=[],q=[[],[]];s=6*a-12*e+6*g,r=-3*a+9*e-9*g+3*i,t=3*e-3*a;for(var z=0;z<2;++z)if(z>0&&(s=6*b-12*f+6*h,r=-3*b+9*f-9*h+3*j,t=3*f-3*b),o(r)<1e-12){if(o(s)<1e-12)continue;u=-t/s,0<u&&u<1&&p.push(u)}else x=s*s-4*t*r,x<0||(y=l(x),v=(-s+y)/(2*r),0<v&&v<1&&p.push(v),w=(-s-y)/(2*r),0<w&&w<1&&p.push(w));for(var A,B,E,C=p.length,D=C;C--;)u=p[C],E=1-u,A=E*E*E*a+3*E*E*u*e+3*E*u*u*g+u*u*u*i,q[0][C]=A,B=E*E*E*b+3*E*E*u*f+3*E*u*u*h+u*u*u*j,q[1][C]=B;q[0][D]=a,q[1][D]=b,q[0][D+1]=i,q[1][D+1]=j;var F=[{x:m.apply(null,q[0]),y:m.apply(null,q[1])},{x:n.apply(null,q[0]),y:n.apply(null,q[1])}];return c[k]=F,F}var a={},b={},c={},d=Array.prototype.join;fabric.util.drawArc=function(a,b,c,d){for(var f=d[0],g=d[1],h=d[2],i=d[3],j=d[4],k=d[5],l=d[6],m=[[],[],[],[]],n=e(k-b,l-c,f,g,i,j,h),o=0,p=n.length;o<p;o++)m[o][0]=n[o][0]+b,m[o][1]=n[o][1]+c,m[o][2]=n[o][2]+b,m[o][3]=n[o][3]+c,m[o][4]=n[o][4]+b,m[o][5]=n[o][5]+c,a.bezierCurveTo.apply(a,m[o])},fabric.util.getBoundsOfArc=function(a,b,c,d,f,g,i,j,k){for(var l=0,m=0,n=[],o=[],p=e(j-a,k-b,c,d,g,i,f),q=0,r=p.length;q<r;q++)n=h(l,m,p[q][0],p[q][1],p[q][2],p[q][3],p[q][4],p[q][5]),n[0].x+=a,n[0].y+=b,n[1].x+=a,n[1].y+=b,o.push(n[0]),o.push(n[1]),l=p[q][4],m=p[q][5];return o},fabric.util.getBoundsOfCurve=h}(),function(){function b(b,c){for(var d=a.call(arguments,2),e=[],f=0,g=b.length;f<g;f++)e[f]=d.length?b[f][c].apply(b[f],d):b[f][c].call(b[f]);return e}function c(a,b){return e(a,b,function(a,b){return a>=b})}function d(a,b){return e(a,b,function(a,b){return a<b})}function e(a,b,c){if(a&&0!==a.length){var d=a.length-1,e=b?a[d][b]:a[d];if(b)for(;d--;)c(a[d][b],e)&&(e=a[d][b]);else for(;d--;)c(a[d],e)&&(e=a[d]);return e}}var a=Array.prototype.slice;Array.prototype.indexOf||(Array.prototype.indexOf=function(a){if(void 0===this||null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>0&&(d=Number(arguments[1]),d!==d?d=0:0!==d&&d!==Number.POSITIVE_INFINITY&&d!==Number.NEGATIVE_INFINITY&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);e<c;e++)if(e in b&&b[e]===a)return e;return-1}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){for(var c=0,d=this.length>>>0;c<d;c++)c in this&&a.call(b,this[c],c,this)}),Array.prototype.map||(Array.prototype.map=function(a,b){for(var c=[],d=0,e=this.length>>>0;d<e;d++)d in this&&(c[d]=a.call(b,this[d],d,this));return c}),Array.prototype.every||(Array.prototype.every=function(a,b){for(var c=0,d=this.length>>>0;c<d;c++)if(c in this&&!a.call(b,this[c],c,this))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(a,b){for(var c=0,d=this.length>>>0;c<d;c++)if(c in this&&a.call(b,this[c],c,this))return!0;return!1}),Array.prototype.filter||(Array.prototype.filter=function(a,b){for(var d,c=[],e=0,f=this.length>>>0;e<f;e++)e in this&&(d=this[e],a.call(b,d,e,this)&&c.push(d));return c}),Array.prototype.reduce||(Array.prototype.reduce=function(a){var d,b=this.length>>>0,c=0;if(arguments.length>1)d=arguments[1];else for(;;){if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}for(;c<b;c++)c in this&&(d=a.call(null,d,this[c],c,this));return d}),fabric.util.array={invoke:b,min:d,max:c}}(),function(){function a(a,b){for(var c in b)a[c]=b[c];return a}function b(b){return a({},b)}fabric.util.object={extend:a,clone:b}}(),function(){function a(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():\"\"})}function b(a,b){return a.charAt(0).toUpperCase()+(b?a.slice(1):a.slice(1).toLowerCase())}function c(a){return a.replace(/&/g,\"&amp;\").replace(/\"/g,\"&quot;\").replace(/'/g,\"&apos;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\")}String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^[\\s\\xA0]+/,\"\").replace(/[\\s\\xA0]+$/,\"\")}),fabric.util.string={camelize:a,capitalize:b,escapeXml:c}}(),function(){var a=Array.prototype.slice,b=Function.prototype.apply,c=function(){};Function.prototype.bind||(Function.prototype.bind=function(d){var g,e=this,f=a.call(arguments,1);return g=f.length?function(){return b.call(e,this instanceof c?this:d,f.concat(a.call(arguments)))}:function(){return b.call(e,this instanceof c?this:d,arguments)},c.prototype=this.prototype,g.prototype=new c,g})}(),function(){function e(){}function f(b){var c=this.constructor.superclass.prototype[b];return arguments.length>1?c.apply(this,a.call(arguments,1)):c.call(this)}function g(){function h(){this.initialize.apply(this,arguments)}var c=null,g=a.call(arguments,0);\"function\"==typeof g[0]&&(c=g.shift()),h.superclass=c,h.subclasses=[],c&&(e.prototype=c.prototype,h.prototype=new e,c.subclasses.push(h));for(var i=0,j=g.length;i<j;i++)d(h,g[i],c);return h.prototype.initialize||(h.prototype.initialize=b),h.prototype.constructor=h,h.prototype.callSuper=f,h}var a=Array.prototype.slice,b=function(){},c=function(){for(var a in{toString:1})if(\"toString\"===a)return!1;return!0}(),d=function(a,b,d){for(var e in b)e in a.prototype&&\"function\"==typeof a.prototype[e]&&(b[e]+\"\").indexOf(\"callSuper\")>-1?a.prototype[e]=function(a){return function(){var c=this.constructor.superclass;this.constructor.superclass=d;var e=b[a].apply(this,arguments);if(this.constructor.superclass=c,\"initialize\"!==a)return e}}(e):a.prototype[e]=b[e],c&&(b.toString!==Object.prototype.toString&&(a.prototype.toString=b.toString),b.valueOf!==Object.prototype.valueOf&&(a.prototype.valueOf=b.valueOf))};fabric.util.createClass=g}(),function(){function b(a){var c,d,b=Array.prototype.slice.call(arguments,1),e=b.length;for(d=0;d<e;d++)if(c=typeof a[b[d]],!/^(?:function|object|unknown)$/.test(c))return!1;return!0}function f(a,b){return{handler:b,wrappedHandler:g(a,b)}}function g(a,b){return function(d){b.call(c(a),d||fabric.window.event)}}function h(a,b){return function(c){if(l[a]&&l[a][b])for(var d=l[a][b],e=0,f=d.length;e<f;e++)d[e].call(this,c||fabric.window.event)}}function o(b,c){b||(b=fabric.window.event);var d=b.target||(typeof b.srcElement!==a?b.srcElement:null),e=fabric.util.getScrollLeftTop(d,c);return{x:p(b)+e.left,y:q(b)+e.top}}function r(a,b,c){var d=\"touchend\"===a.type?\"changedTouches\":\"touches\";return a[d]&&a[d][0]?a[d][0][b]-(a[d][0][b]-a[d][0][c])||a[c]:a[c]}var c,d,a=\"unknown\",e=function(){var a=0;return function(b){return b.__uniqueID||(b.__uniqueID=\"uniqueID__\"+a++)}}();!function(){var a={};c=function(b){return a[b]},d=function(b,c){a[b]=c}}();var m,n,i=b(fabric.document.documentElement,\"addEventListener\",\"removeEventListener\")&&b(fabric.window,\"addEventListener\",\"removeEventListener\"),j=b(fabric.document.documentElement,\"attachEvent\",\"detachEvent\")&&b(fabric.window,\"attachEvent\",\"detachEvent\"),k={},l={};i?(m=function(a,b,c){a.addEventListener(b,c,!1)},n=function(a,b,c){a.removeEventListener(b,c,!1)}):j?(m=function(a,b,c){var g=e(a);d(g,a),k[g]||(k[g]={}),k[g][b]||(k[g][b]=[]);var h=f(g,c);k[g][b].push(h),a.attachEvent(\"on\"+b,h.wrappedHandler)},n=function(a,b,c){var f,d=e(a);if(k[d]&&k[d][b])for(var g=0,h=k[d][b].length;g<h;g++)f=k[d][b][g],f&&f.handler===c&&(a.detachEvent(\"on\"+b,f.wrappedHandler),k[d][b][g]=null)}):(m=function(a,b,c){var d=e(a);if(l[d]||(l[d]={}),!l[d][b]){l[d][b]=[];var f=a[\"on\"+b];f&&l[d][b].push(f),a[\"on\"+b]=h(d,b)}l[d][b].push(c)},n=function(a,b,c){var d=e(a);if(l[d]&&l[d][b])for(var f=l[d][b],g=0,h=f.length;g<h;g++)f[g]===c&&f.splice(g,1)}),fabric.util.addListener=m,fabric.util.removeListener=n;var p=function(b){return typeof b.clientX!==a?b.clientX:0},q=function(b){return typeof b.clientY!==a?b.clientY:0};fabric.isTouchSupported&&(p=function(a){return r(a,\"pageX\",\"clientX\")},q=function(a){return r(a,\"pageY\",\"clientY\")}),fabric.util.getPointer=o,fabric.util.object.extend(fabric.util,fabric.Observable)}(),function(){function a(a,b){var c=a.style;if(!c)return a;if(\"string\"==typeof b)return a.style.cssText+=\";\"+b,b.indexOf(\"opacity\")>-1?f(a,b.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1]):a;for(var d in b)if(\"opacity\"===d)f(a,b[d]);else{var e=\"float\"===d||\"cssFloat\"===d?\"undefined\"==typeof c.styleFloat?\"cssFloat\":\"styleFloat\":d;c[e]=b[d]}return a}var b=fabric.document.createElement(\"div\"),c=\"string\"==typeof b.style.opacity,d=\"string\"==typeof b.style.filter,e=/alpha\\s*\\(\\s*opacity\\s*=\\s*([^\\)]+)\\)/,f=function(a){return a};c?f=function(a,b){return a.style.opacity=b,a}:d&&(f=function(a,b){var c=a.style;return a.currentStyle&&!a.currentStyle.hasLayout&&(c.zoom=1),e.test(c.filter)?(b=b>=.9999?\"\":\"alpha(opacity=\"+100*b+\")\",c.filter=c.filter.replace(e,b)):c.filter+=\" alpha(opacity=\"+100*b+\")\",a}),fabric.util.setStyle=a}(),function(){function b(a){return\"string\"==typeof a?fabric.document.getElementById(a):a}function e(a,b){var c=fabric.document.createElement(a);for(var d in b)\"class\"===d?c.className=b[d]:\"for\"===d?c.htmlFor=b[d]:c.setAttribute(d,b[d]);return c}function f(a,b){a&&(\" \"+a.className+\" \").indexOf(\" \"+b+\" \")===-1&&(a.className+=(a.className?\" \":\"\")+b)}function g(a,b,c){return\"string\"==typeof b&&(b=e(b,c)),a.parentNode&&a.parentNode.replaceChild(b,a),b.appendChild(a),b}function h(a,b){var c,d,e=0,f=0,g=fabric.document.documentElement,h=fabric.document.body||{scrollLeft:0,scrollTop:0};for(d=a;a&&a.parentNode&&!c;)a=a.parentNode,1===a.nodeType&&\"fixed\"===fabric.util.getElementStyle(a,\"position\")&&(c=a),1===a.nodeType&&d!==b&&\"absolute\"===fabric.util.getElementStyle(a,\"position\")?(e=0,f=0):a===fabric.document?(e=h.scrollLeft||g.scrollLeft||0,f=h.scrollTop||g.scrollTop||0):(e+=a.scrollLeft||0,f+=a.scrollTop||0);return{left:e,top:f}}function i(a){var b,f,c=a&&a.ownerDocument,d={left:0,top:0},e={left:0,top:0},g={borderLeftWidth:\"left\",borderTopWidth:\"top\",paddingLeft:\"left\",paddingTop:\"top\"};if(!c)return{left:0,top:0};for(var h in g)e[g[h]]+=parseInt(j(a,h),10)||0;return b=c.documentElement,\"undefined\"!=typeof a.getBoundingClientRect&&(d=a.getBoundingClientRect()),f=fabric.util.getScrollLeftTop(a,null),{left:d.left+f.left-(b.clientLeft||0)+e.left,top:d.top+f.top-(b.clientTop||0)+e.top}}var c,a=Array.prototype.slice,d=function(b){return a.call(b,0)};try{c=d(fabric.document.childNodes)instanceof Array}catch(a){}c||(d=function(a){for(var b=new Array(a.length),c=a.length;c--;)b[c]=a[c];return b});var j;j=fabric.document.defaultView&&fabric.document.defaultView.getComputedStyle?function(a,b){var c=fabric.document.defaultView.getComputedStyle(a,null);return c?c[b]:void 0}:function(a,b){var c=a.style[b];return!c&&a.currentStyle&&(c=a.currentStyle[b]),c},function(){function c(a){return\"undefined\"!=typeof a.onselectstart&&(a.onselectstart=fabric.util.falseFunction),b?a.style[b]=\"none\":\"string\"==typeof a.unselectable&&(a.unselectable=\"on\"),a}function d(a){return\"undefined\"!=typeof a.onselectstart&&(a.onselectstart=null),b?a.style[b]=\"\":\"string\"==typeof a.unselectable&&(a.unselectable=\"\"),a}var a=fabric.document.documentElement.style,b=\"userSelect\"in a?\"userSelect\":\"MozUserSelect\"in a?\"MozUserSelect\":\"WebkitUserSelect\"in a?\"WebkitUserSelect\":\"KhtmlUserSelect\"in a?\"KhtmlUserSelect\":\"\";fabric.util.makeElementUnselectable=c,fabric.util.makeElementSelectable=d}(),function(){function a(a,b){var c=fabric.document.getElementsByTagName(\"head\")[0],d=fabric.document.createElement(\"script\"),e=!0;d.onload=d.onreadystatechange=function(a){if(e){if(\"string\"==typeof this.readyState&&\"loaded\"!==this.readyState&&\"complete\"!==this.readyState)return;e=!1,b(a||fabric.window.event),d=d.onload=d.onreadystatechange=null}},d.src=a,c.appendChild(d)}fabric.util.getScript=a}(),fabric.util.getById=b,fabric.util.toArray=d,fabric.util.makeElement=e,fabric.util.addClass=f,fabric.util.wrapElement=g,fabric.util.getScrollLeftTop=h,fabric.util.getElementOffset=i,fabric.util.getElementStyle=j}(),function(){function a(a,b){return a+(/\\?/.test(a)?\"&\":\"?\")+b}function c(){}function d(d,e){e||(e={});var i,f=e.method?e.method.toUpperCase():\"GET\",g=e.onComplete||function(){},h=b();return h.onreadystatechange=function(){4===h.readyState&&(g(h),h.onreadystatechange=c)},\"GET\"===f&&(i=null,\"string\"==typeof e.parameters&&(d=a(d,e.parameters))),h.open(f,d,!0),\"POST\"!==f&&\"PUT\"!==f||h.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\"),h.send(i),h}var b=function(){for(var a=[function(){return new ActiveXObject(\"Microsoft.XMLHTTP\")},function(){return new ActiveXObject(\"Msxml2.XMLHTTP\")},function(){return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\")},function(){return new XMLHttpRequest}],b=a.length;b--;)try{var c=a[b]();if(c)return a[b]}catch(a){}}();fabric.util.request=d}(),fabric.log=function(){},fabric.warn=function(){},\"undefined\"!=typeof console&&[\"log\",\"warn\"].forEach(function(a){\"undefined\"!=typeof console[a]&&console[a].apply&&(fabric[a]=function(){return console[a].apply(console,arguments)})}),function(){function a(a){c(function(b){a||(a={});var g,d=b||+new Date,e=a.duration||500,f=d+e,h=a.onChange||function(){},i=a.abort||function(){return!1},j=a.easing||function(a,b,c,d){return-c*Math.cos(a/d*(Math.PI/2))+c+b},k=\"startValue\"in a?a.startValue:0,l=\"endValue\"in a?a.endValue:100,m=a.byValue||l-k;a.onStart&&a.onStart(),function b(l){g=l||+new Date;var n=g>f?e:g-d;return i()?void(a.onComplete&&a.onComplete()):(h(j(n,k,m,e)),g>f?void(a.onComplete&&a.onComplete()):void c(b))}(d)})}function c(){return b.apply(fabric.window,arguments)}var b=fabric.window.requestAnimationFrame||fabric.window.webkitRequestAnimationFrame||fabric.window.mozRequestAnimationFrame||fabric.window.oRequestAnimationFrame||fabric.window.msRequestAnimationFrame||function(a){fabric.window.setTimeout(a,1e3/60)};fabric.util.animate=a,fabric.util.requestAnimFrame=c}(),function(){function a(a,b,c,d){return a<Math.abs(b)?(a=b,d=c/4):d=c/(2*Math.PI)*Math.asin(b/a),{a:a,c:b,p:c,s:d}}function b(a,b,c){return a.a*Math.pow(2,10*(b-=1))*Math.sin((b*c-a.s)*(2*Math.PI)/a.p)}function c(a,b,c,d){return c*((a=a/d-1)*a*a+1)+b}function d(a,b,c,d){return a/=d/2,a<1?c/2*a*a*a+b:c/2*((a-=2)*a*a+2)+b}function e(a,b,c,d){return c*(a/=d)*a*a*a+b}function f(a,b,c,d){return-c*((a=a/d-1)*a*a*a-1)+b}function g(a,b,c,d){return a/=d/2,a<1?c/2*a*a*a*a+b:-c/2*((a-=2)*a*a*a-2)+b}function h(a,b,c,d){return c*(a/=d)*a*a*a*a+b}function i(a,b,c,d){return c*((a=a/d-1)*a*a*a*a+1)+b}function j(a,b,c,d){return a/=d/2,a<1?c/2*a*a*a*a*a+b:c/2*((a-=2)*a*a*a*a+2)+b}function k(a,b,c,d){return-c*Math.cos(a/d*(Math.PI/2))+c+b}function l(a,b,c,d){return c*Math.sin(a/d*(Math.PI/2))+b}function m(a,b,c,d){return-c/2*(Math.cos(Math.PI*a/d)-1)+b}function n(a,b,c,d){return 0===a?b:c*Math.pow(2,10*(a/d-1))+b}function o(a,b,c,d){return a===d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b}function p(a,b,c,d){return 0===a?b:a===d?b+c:(a/=d/2,a<1?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b)}function q(a,b,c,d){return-c*(Math.sqrt(1-(a/=d)*a)-1)+b}function r(a,b,c,d){return c*Math.sqrt(1-(a=a/d-1)*a)+b}function s(a,b,c,d){return a/=d/2,a<1?-c/2*(Math.sqrt(1-a*a)-1)+b:c/2*(Math.sqrt(1-(a-=2)*a)+1)+b}function t(c,d,e,f){var g=1.70158,h=0,i=e;if(0===c)return d;if(c/=f,1===c)return d+e;h||(h=.3*f);var j=a(i,e,h,g);return-b(j,c,f)+d}function u(b,c,d,e){var f=1.70158,g=0,h=d;if(0===b)return c;if(b/=e,1===b)return c+d;g||(g=.3*e);var i=a(h,d,g,f);return i.a*Math.pow(2,-10*b)*Math.sin((b*e-i.s)*(2*Math.PI)/i.p)+i.c+c}function v(c,d,e,f){var g=1.70158,h=0,i=e;if(0===c)return d;if(c/=f/2,2===c)return d+e;h||(h=f*(.3*1.5));var j=a(i,e,h,g);return c<1?-.5*b(j,c,f)+d:j.a*Math.pow(2,-10*(c-=1))*Math.sin((c*f-j.s)*(2*Math.PI)/j.p)*.5+j.c+d}function w(a,b,c,d,e){return void 0===e&&(e=1.70158),c*(a/=d)*a*((e+1)*a-e)+b}function x(a,b,c,d,e){return void 0===e&&(e=1.70158),c*((a=a/d-1)*a*((e+1)*a+e)+1)+b}function y(a,b,c,d,e){return void 0===e&&(e=1.70158),a/=d/2,a<1?c/2*(a*a*(((e*=1.525)+1)*a-e))+b:c/2*((a-=2)*a*(((e*=1.525)+1)*a+e)+2)+b}function z(a,b,c,d){return c-A(d-a,0,c,d)+b}function A(a,b,c,d){return(a/=d)<1/2.75?c*(7.5625*a*a)+b:a<2/2.75?c*(7.5625*(a-=1.5/2.75)*a+.75)+b:a<2.5/2.75?c*(7.5625*(a-=2.25/2.75)*a+.9375)+b:c*(7.5625*(a-=2.625/2.75)*a+.984375)+b}function B(a,b,c,d){return a<d/2?.5*z(2*a,0,c,d)+b:.5*A(2*a-d,0,c,d)+.5*c+b}fabric.util.ease={easeInQuad:function(a,b,c,d){return c*(a/=d)*a+b},easeOutQuad:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOutQuad:function(a,b,c,d){return a/=d/2,a<1?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},easeInCubic:function(a,b,c,d){return c*(a/=d)*a*a+b},easeOutCubic:c,easeInOutCubic:d,easeInQuart:e,easeOutQuart:f,easeInOutQuart:g,easeInQuint:h,easeOutQuint:i,easeInOutQuint:j,easeInSine:k,easeOutSine:l,easeInOutSine:m,easeInExpo:n,easeOutExpo:o,easeInOutExpo:p,easeInCirc:q,easeOutCirc:r,easeInOutCirc:s,easeInElastic:t,easeOutElastic:u,easeInOutElastic:v,easeInBack:w,easeOutBack:x,easeInOutBack:y,easeInBounce:z,easeOutBounce:A,easeInOutBounce:B}}(),function(a){\"use strict\";function k(a){return a in i?i[a]:a}function l(a,c,d){var f,e=\"[object Array]\"===Object.prototype.toString.call(c);return\"fill\"!==a&&\"stroke\"!==a||\"none\"!==c?\"strokeDashArray\"===a?c=c.replace(/,/g,\" \").split(/\\s+/).map(function(a){return parseFloat(a)}):\"transformMatrix\"===a?c=d&&d.transformMatrix?h(d.transformMatrix,b.parseTransformAttribute(c)):b.parseTransformAttribute(c):\"visible\"===a?(c=\"none\"!==c&&\"hidden\"!==c,d&&d.visible===!1&&(c=!1)):\"originX\"===a?c=\"start\"===c?\"left\":\"end\"===c?\"right\":\"center\":f=e?c.map(g):g(c):c=\"\",!e&&isNaN(f)?c:f}function m(a){for(var c in j)if(a[c]&&\"undefined\"!=typeof a[j[c]]&&0!==a[c].indexOf(\"url(\")){var d=new b.Color(a[c]);a[c]=d.setAlpha(f(d.getAlpha()*a[j[c]],2)).toRgba()}return a}function n(a,b){var c=a.match(/(normal|italic)?\\s*(normal|small-caps)?\\s*(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\s*(\\d+)px(?:\\/(normal|[\\d\\.]+))?\\s+(.*)/);if(c){var d=c[1],e=c[3],f=c[4],g=c[5],h=c[6];d&&(b.fontStyle=d),e&&(b.fontWeight=isNaN(parseFloat(e))?e:parseFloat(e)),f&&(b.fontSize=parseFloat(f)),h&&(b.fontFamily=h),g&&(b.lineHeight=\"normal\"===g?1:g)}}function o(a,b){var c,d;a.replace(/;$/,\"\").split(\";\").forEach(function(a){var e=a.split(\":\");c=k(e[0].trim().toLowerCase()),d=l(c,e[1].trim()),\"font\"===c?n(d,b):b[c]=d})}function p(a,b){var c,d;for(var e in a)\"undefined\"!=typeof a[e]&&(c=k(e.toLowerCase()),d=l(c,a[e]),\"font\"===c?n(d,b):b[c]=d)}function q(a,c){var d={};for(var e in b.cssRules[c])if(r(a,e.split(\" \")))for(var f in b.cssRules[c][e])d[f]=b.cssRules[c][e][f];return d}function r(a,b){var c,d=!0;return c=t(a,b.pop()),c&&b.length&&(d=s(a,b)),c&&d&&0===b.length}function s(a,b){for(var c,d=!0;a.parentNode&&1===a.parentNode.nodeType&&b.length;)d&&(c=b.pop()),a=a.parentNode,d=t(a,c);return 0===b.length}function t(a,b){var f,c=a.nodeName,d=a.getAttribute(\"class\"),e=a.getAttribute(\"id\");if(f=new RegExp(\"^\"+c,\"i\"),b=b.replace(f,\"\"),e&&b.length&&(f=new RegExp(\"#\"+e+\"(?![a-zA-Z\\\\-]+)\",\"i\"),b=b.replace(f,\"\")),d&&b.length){d=d.split(\" \");for(var g=d.length;g--;)f=new RegExp(\"\\\\.\"+d[g]+\"(?![a-zA-Z\\\\-]+)\",\"i\"),b=b.replace(f,\"\")}return 0===b.length}function u(a){for(var b=a.getElementsByTagName(\"use\");b.length;){for(var i,c=b[0],d=c.getAttribute(\"xlink:href\").substr(1),e=c.getAttribute(\"x\")||0,f=c.getAttribute(\"y\")||0,g=a.getElementById(d).cloneNode(!0),h=(c.getAttribute(\"transform\")||\"\")+\" translate(\"+e+\", \"+f+\")\",j=0,k=c.attributes,l=k.length;j<l;j++){var m=k.item(j);\"x\"!==m.nodeName&&\"y\"!==m.nodeName&&\"xlink:href\"!==m.nodeName&&(\"transform\"===m.nodeName?h=h+\" \"+m.nodeValue:g.setAttribute(m.nodeName,m.nodeValue))}g.setAttribute(\"transform\",h),g.removeAttribute(\"id\"),i=c.parentNode,i.replaceChild(g,c)}}function v(a,b){if(b[3]=b[0]=b[0]>b[3]?b[3]:b[0],1!==b[0]||1!==b[3]||0!==b[4]||0!==b[5]){for(var c=a.ownerDocument.createElement(\"g\");null!=a.firstChild;)c.appendChild(a.firstChild);c.setAttribute(\"transform\",\"matrix(\"+b[0]+\" \"+b[1]+\" \"+b[2]+\" \"+b[3]+\" \"+b[4]+\" \"+b[5]+\")\"),a.appendChild(c)}}function x(a){var c=a.objects,e=a.options;return c=c.map(function(a){return b[d(a.type)].fromObject(a)}),{objects:c,options:e}}function y(a,b,c){b[c]&&b[c].toSVG&&a.push('<pattern x=\"0\" y=\"0\" id=\"',c,'Pattern\" ','width=\"',b[c].source.width,'\" height=\"',b[c].source.height,'\" patternUnits=\"userSpaceOnUse\">','<image x=\"0\" y=\"0\" ','width=\"',b[c].source.width,'\" height=\"',b[c].source.height,'\" xlink:href=\"',b[c].source.src,'\"></image></pattern>')}var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d=b.util.string.capitalize,e=b.util.object.clone,f=b.util.toFixed,g=b.util.parseUnit,h=b.util.multiplyTransformMatrices,i={cx:\"left\",x:\"left\",r:\"radius\",cy:\"top\",y:\"top\",display:\"visible\",visibility:\"visible\",transform:\"transformMatrix\",\"fill-opacity\":\"fillOpacity\",\"fill-rule\":\"fillRule\",\"font-family\":\"fontFamily\",\"font-size\":\"fontSize\",\"font-style\":\"fontStyle\",\"font-weight\":\"fontWeight\",\"stroke-dasharray\":\"strokeDashArray\",\"stroke-linecap\":\"strokeLineCap\",\"stroke-linejoin\":\"strokeLineJoin\",\"stroke-miterlimit\":\"strokeMiterLimit\",\"stroke-opacity\":\"strokeOpacity\",\"stroke-width\":\"strokeWidth\",\"text-decoration\":\"textDecoration\",\"text-anchor\":\"originX\"},j={stroke:\"strokeOpacity\",fill:\"fillOpacity\"};b.cssRules={},b.gradientDefs={},b.parseTransformAttribute=function(){function a(a,b){var c=b[0];a[0]=Math.cos(c),a[1]=Math.sin(c),a[2]=-Math.sin(c),a[3]=Math.cos(c)}function c(a,b){var c=b[0],d=2===b.length?b[1]:b[0];a[0]=c,a[3]=d}function d(a,c){a[2]=Math.tan(b.util.degreesToRadians(c[0]))}function e(a,c){a[1]=Math.tan(b.util.degreesToRadians(c[0]))}function f(a,b){a[4]=b[0],2===b.length&&(a[5]=b[1])}var g=[1,0,0,1,0,0],h=\"(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)\",i=\"(?:\\\\s+,?\\\\s*|,\\\\s*)\",j=\"(?:(skewX)\\\\s*\\\\(\\\\s*(\"+h+\")\\\\s*\\\\))\",k=\"(?:(skewY)\\\\s*\\\\(\\\\s*(\"+h+\")\\\\s*\\\\))\",l=\"(?:(rotate)\\\\s*\\\\(\\\\s*(\"+h+\")(?:\"+i+\"(\"+h+\")\"+i+\"(\"+h+\"))?\\\\s*\\\\))\",m=\"(?:(scale)\\\\s*\\\\(\\\\s*(\"+h+\")(?:\"+i+\"(\"+h+\"))?\\\\s*\\\\))\",n=\"(?:(translate)\\\\s*\\\\(\\\\s*(\"+h+\")(?:\"+i+\"(\"+h+\"))?\\\\s*\\\\))\",o=\"(?:(matrix)\\\\s*\\\\(\\\\s*(\"+h+\")\"+i+\"(\"+h+\")\"+i+\"(\"+h+\")\"+i+\"(\"+h+\")\"+i+\"(\"+h+\")\"+i+\"(\"+h+\")\\\\s*\\\\))\",p=\"(?:\"+o+\"|\"+n+\"|\"+m+\"|\"+l+\"|\"+j+\"|\"+k+\")\",q=\"(?:\"+p+\"(?:\"+i+p+\")*)\",r=\"^\\\\s*(?:\"+q+\"?)\\\\s*$\",s=new RegExp(r),t=new RegExp(p,\"g\");return function(h){var i=g.concat(),j=[];if(!h||h&&!s.test(h))return i;h.replace(t,function(h){var k=new RegExp(p).exec(h).filter(function(a){return\"\"!==a&&null!=a}),l=k[1],m=k.slice(2).map(parseFloat);switch(l){case\"translate\":f(i,m);break;case\"rotate\":m[0]=b.util.degreesToRadians(m[0]),a(i,m);break;case\"scale\":c(i,m);break;case\"skewX\":d(i,m);break;case\"skewY\":e(i,m);break;case\"matrix\":i=m}j.push(i.concat()),i=g.concat()});for(var k=j[0];j.length>1;)j.shift(),k=b.util.multiplyTransformMatrices(k,j[0]);return k}}(),b.parseSVGDocument=function(){function f(a,b){for(;a&&(a=a.parentNode);)if(b.test(a.nodeName))return!0;return!1}var a=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/,c=\"(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)\",d=new RegExp(\"^\\\\s*(\"+c+\"+)\\\\s*,?\\\\s*(\"+c+\"+)\\\\s*,?\\\\s*(\"+c+\"+)\\\\s*,?\\\\s*(\"+c+\"+)\\\\s*$\");return function(c,h,i){if(c){var j=new Date,k=b.Object.__uid++;u(c);var o,p,l=c.getAttribute(\"viewBox\"),m=g(c.getAttribute(\"width\")||\"100%\"),n=g(c.getAttribute(\"height\")||\"100%\");if(l&&(l=l.match(d))){var q=parseFloat(l[1]),r=parseFloat(l[2]),s=1,t=1;o=parseFloat(l[3]),p=parseFloat(l[4]),m&&m!==o&&(s=m/o),n&&n!==p&&(t=n/p),v(c,[s,0,0,t,s*-q,t*-r])}var w=b.util.toArray(c.getElementsByTagName(\"*\"));if(0===w.length&&b.isLikelyNode){w=c.selectNodes('//*[name(.)!=\"svg\"]');for(var x=[],y=0,z=w.length;y<z;y++)x[y]=w[y];w=x}var A=w.filter(function(b){return a.test(b.tagName)&&!f(b,/^(?:pattern|defs)$/)});if(!A||A&&!A.length)return void(h&&h([],{}));var B={width:m?m:o,height:n?n:p,widthAttr:m,heightAttr:n,svgUid:k};b.gradientDefs[k]=b.getGradientDefs(c),b.cssRules[k]=b.getCSSRules(c),b.parseElements(A,function(a){b.documentParsingTime=new Date-j,h&&h(a,B)},e(B),i)}}}();var w={has:function(a,b){b(!1)},get:function(){},set:function(){}};c(b,{getGradientDefs:function(a){var d,e,g,h,b=a.getElementsByTagName(\"linearGradient\"),c=a.getElementsByTagName(\"radialGradient\"),f=0,i=[],j={},k={};for(i.length=b.length+c.length,e=b.length;e--;)i[f++]=b[e];for(e=c.length;e--;)i[f++]=c[e];for(;f--;)d=i[f],h=d.getAttribute(\"xlink:href\"),g=d.getAttribute(\"id\"),h&&(k[g]=h.substr(1)),j[g]=d;for(g in k){var l=j[k[g]].cloneNode(!0);for(d=j[g];l.firstChild;)d.appendChild(l.firstChild)}return j},parseAttributes:function(a,d,e){if(a){var f,g={};\"undefined\"==typeof e&&(e=a.getAttribute(\"svgUid\")),a.parentNode&&/^symbol|[g|a]$/i.test(a.parentNode.nodeName)&&(g=b.parseAttributes(a.parentNode,d,e));var h=d.reduce(function(b,c){\nreturn f=a.getAttribute(c),f&&(c=k(c),f=l(c,f,g),b[c]=f),b},{});return h=c(h,c(q(a,e),b.parseStyleAttribute(a))),m(c(g,h))}},parseElements:function(a,c,d,e){new b.ElementsParser(a,c,d,e).parse()},parseStyleAttribute:function(a){var b={},c=a.getAttribute(\"style\");return c?(\"string\"==typeof c?o(c,b):p(c,b),b):b},parsePointsAttribute:function(a){if(!a)return null;a=a.replace(/,/g,\" \").trim(),a=a.split(/\\s+/);var c,d,b=[];for(c=0,d=a.length;c<d;c+=2)b.push({x:parseFloat(a[c]),y:parseFloat(a[c+1])});return b},getCSSRules:function(a){for(var e,c=a.getElementsByTagName(\"style\"),d={},f=0,g=c.length;f<g;f++){var h=c[f].textContent;h=h.replace(/\\/\\*[\\s\\S]*?\\*\\//g,\"\"),\"\"!==h.trim()&&(e=h.match(/[^{]*\\{[\\s\\S]*?\\}/g),e=e.map(function(a){return a.trim()}),e.forEach(function(a){for(var c=a.match(/([\\s\\S]*?)\\s*\\{([^}]*)\\}/),e={},f=c[2].trim(),g=f.replace(/;$/,\"\").split(/\\s*;\\s*/),h=0,i=g.length;h<i;h++){var j=g[h].split(/\\s*:\\s*/),m=k(j[0]),n=l(m,j[1],j[0]);e[m]=n}a=c[1],a.split(\",\").forEach(function(a){d[a.trim()]=b.util.object.clone(e)})}))}return d},loadSVGFromURL:function(a,c,d){function e(e){var f=e.responseXML;f&&!f.documentElement&&b.window.ActiveXObject&&e.responseText&&(f=new ActiveXObject(\"Microsoft.XMLDOM\"),f.async=\"false\",f.loadXML(e.responseText.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i,\"\"))),f&&f.documentElement&&b.parseSVGDocument(f.documentElement,function(d,e){w.set(a,{objects:b.util.array.invoke(d,\"toObject\"),options:e}),c(d,e)},d)}a=a.replace(/^\\n\\s*/,\"\").trim(),w.has(a,function(d){d?w.get(a,function(a){var b=x(a);c(b.objects,b.options)}):new b.util.request(a,{method:\"get\",onComplete:e})})},loadSVGFromString:function(a,c,d){a=a.trim();var e;if(\"undefined\"!=typeof DOMParser){var f=new DOMParser;f&&f.parseFromString&&(e=f.parseFromString(a,\"text/xml\"))}else b.window.ActiveXObject&&(e=new ActiveXObject(\"Microsoft.XMLDOM\"),e.async=\"false\",e.loadXML(a.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i,\"\")));b.parseSVGDocument(e.documentElement,function(a,b){c(a,b)},d)},createSVGFontFacesMarkup:function(a){for(var b=\"\",c=0,d=a.length;c<d;c++)\"text\"===a[c].type&&a[c].path&&(b+=[\"@font-face {\",\"font-family: \",a[c].fontFamily,\"; \",\"src: url('\",a[c].path,\"')\",\"}\"].join(\"\"));return b&&(b=['<style type=\"text/css\">',\"<![CDATA[\",b,\"]]>\",\"</style>\"].join(\"\")),b},createSVGRefElementsMarkup:function(a){var b=[];return y(b,a,\"backgroundColor\"),y(b,a,\"overlayColor\"),b.join(\"\")}})}(\"undefined\"!=typeof exports?exports:this),fabric.ElementsParser=function(a,b,c,d){this.elements=a,this.callback=b,this.options=c,this.reviver=d,this.svgUid=c&&c.svgUid||0},fabric.ElementsParser.prototype.parse=function(){this.instances=new Array(this.elements.length),this.numElements=this.elements.length,this.createObjects()},fabric.ElementsParser.prototype.createObjects=function(){for(var a=0,b=this.elements.length;a<b;a++)this.elements[a].setAttribute(\"svgUid\",this.svgUid),function(a,b){setTimeout(function(){a.createObject(a.elements[b],b)},0)}(this,a)},fabric.ElementsParser.prototype.createObject=function(a,b){var c=fabric[fabric.util.string.capitalize(a.tagName)];if(c&&c.fromElement)try{this._createObject(c,a,b)}catch(a){fabric.log(a)}else this.checkIfDone()},fabric.ElementsParser.prototype._createObject=function(a,b,c){if(a.async)a.fromElement(b,this.createCallback(c,b),this.options);else{var d=a.fromElement(b,this.options);this.resolveGradient(d,\"fill\"),this.resolveGradient(d,\"stroke\"),this.reviver&&this.reviver(b,d),this.instances[c]=d,this.checkIfDone()}},fabric.ElementsParser.prototype.createCallback=function(a,b){var c=this;return function(d){c.resolveGradient(d,\"fill\"),c.resolveGradient(d,\"stroke\"),c.reviver&&c.reviver(b,d),c.instances[a]=d,c.checkIfDone()}},fabric.ElementsParser.prototype.resolveGradient=function(a,b){var c=a.get(b);if(/^url\\(/.test(c)){var d=c.slice(5,c.length-1);fabric.gradientDefs[this.svgUid][d]&&a.set(b,fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][d],a))}},fabric.ElementsParser.prototype.checkIfDone=function(){0===--this.numElements&&(this.instances=this.instances.filter(function(a){return null!=a}),this.callback(this.instances))},function(a){\"use strict\";function c(a,b){this.x=a,this.y=b}var b=a.fabric||(a.fabric={});return b.Point?void b.warn(\"fabric.Point is already defined\"):(b.Point=c,void(c.prototype={constructor:c,add:function(a){return new c(this.x+a.x,this.y+a.y)},addEquals:function(a){return this.x+=a.x,this.y+=a.y,this},scalarAdd:function(a){return new c(this.x+a,this.y+a)},scalarAddEquals:function(a){return this.x+=a,this.y+=a,this},subtract:function(a){return new c(this.x-a.x,this.y-a.y)},subtractEquals:function(a){return this.x-=a.x,this.y-=a.y,this},scalarSubtract:function(a){return new c(this.x-a,this.y-a)},scalarSubtractEquals:function(a){return this.x-=a,this.y-=a,this},multiply:function(a){return new c(this.x*a,this.y*a)},multiplyEquals:function(a){return this.x*=a,this.y*=a,this},divide:function(a){return new c(this.x/a,this.y/a)},divideEquals:function(a){return this.x/=a,this.y/=a,this},eq:function(a){return this.x===a.x&&this.y===a.y},lt:function(a){return this.x<a.x&&this.y<a.y},lte:function(a){return this.x<=a.x&&this.y<=a.y},gt:function(a){return this.x>a.x&&this.y>a.y},gte:function(a){return this.x>=a.x&&this.y>=a.y},lerp:function(a,b){return new c(this.x+(a.x-this.x)*b,this.y+(a.y-this.y)*b)},distanceFrom:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},midPointFrom:function(a){return new c(this.x+(a.x-this.x)/2,this.y+(a.y-this.y)/2)},min:function(a){return new c(Math.min(this.x,a.x),Math.min(this.y,a.y))},max:function(a){return new c(Math.max(this.x,a.x),Math.max(this.y,a.y))},toString:function(){return this.x+\",\"+this.y},setXY:function(a,b){this.x=a,this.y=b},setFromPoint:function(a){this.x=a.x,this.y=a.y},swap:function(a){var b=this.x,c=this.y;this.x=a.x,this.y=a.y,a.x=b,a.y=c}}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";function c(a){this.status=a,this.points=[]}var b=a.fabric||(a.fabric={});return b.Intersection?void b.warn(\"fabric.Intersection is already defined\"):(b.Intersection=c,b.Intersection.prototype={appendPoint:function(a){this.points.push(a)},appendPoints:function(a){this.points=this.points.concat(a)}},b.Intersection.intersectLineLine=function(a,d,e,f){var g,h=(f.x-e.x)*(a.y-e.y)-(f.y-e.y)*(a.x-e.x),i=(d.x-a.x)*(a.y-e.y)-(d.y-a.y)*(a.x-e.x),j=(f.y-e.y)*(d.x-a.x)-(f.x-e.x)*(d.y-a.y);if(0!==j){var k=h/j,l=i/j;0<=k&&k<=1&&0<=l&&l<=1?(g=new c(\"Intersection\"),g.points.push(new b.Point(a.x+k*(d.x-a.x),a.y+k*(d.y-a.y)))):g=new c}else g=new c(0===h||0===i?\"Coincident\":\"Parallel\");return g},b.Intersection.intersectLinePolygon=function(a,b,d){for(var e=new c,f=d.length,g=0;g<f;g++){var h=d[g],i=d[(g+1)%f],j=c.intersectLineLine(a,b,h,i);e.appendPoints(j.points)}return e.points.length>0&&(e.status=\"Intersection\"),e},b.Intersection.intersectPolygonPolygon=function(a,b){for(var d=new c,e=a.length,f=0;f<e;f++){var g=a[f],h=a[(f+1)%e],i=c.intersectLinePolygon(g,h,b);d.appendPoints(i.points)}return d.points.length>0&&(d.status=\"Intersection\"),d},void(b.Intersection.intersectPolygonRectangle=function(a,d,e){var f=d.min(e),g=d.max(e),h=new b.Point(g.x,f.y),i=new b.Point(f.x,g.y),j=c.intersectLinePolygon(f,h,a),k=c.intersectLinePolygon(h,g,a),l=c.intersectLinePolygon(g,i,a),m=c.intersectLinePolygon(i,f,a),n=new c;return n.appendPoints(j.points),n.appendPoints(k.points),n.appendPoints(l.points),n.appendPoints(m.points),n.points.length>0&&(n.status=\"Intersection\"),n}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";function c(a){a?this._tryParsingColor(a):this.setSource([0,0,0,1])}function d(a,b,c){return c<0&&(c+=1),c>1&&(c-=1),c<1/6?a+6*(b-a)*c:c<.5?b:c<2/3?a+(b-a)*(2/3-c)*6:a}var b=a.fabric||(a.fabric={});return b.Color?void b.warn(\"fabric.Color is already defined.\"):(b.Color=c,b.Color.prototype={_tryParsingColor:function(a){var b;return a in c.colorNameMap&&(a=c.colorNameMap[a]),\"transparent\"===a?void this.setSource([255,255,255,0]):(b=c.sourceFromHex(a),b||(b=c.sourceFromRgb(a)),b||(b=c.sourceFromHsl(a)),void(b&&this.setSource(b)))},_rgbToHsl:function(a,c,d){a/=255,c/=255,d/=255;var e,f,g,h=b.util.array.max([a,c,d]),i=b.util.array.min([a,c,d]);if(g=(h+i)/2,h===i)e=f=0;else{var j=h-i;switch(f=g>.5?j/(2-h-i):j/(h+i),h){case a:e=(c-d)/j+(c<d?6:0);break;case c:e=(d-a)/j+2;break;case d:e=(a-c)/j+4}e/=6}return[Math.round(360*e),Math.round(100*f),Math.round(100*g)]},getSource:function(){return this._source},setSource:function(a){this._source=a},toRgb:function(){var a=this.getSource();return\"rgb(\"+a[0]+\",\"+a[1]+\",\"+a[2]+\")\"},toRgba:function(){var a=this.getSource();return\"rgba(\"+a[0]+\",\"+a[1]+\",\"+a[2]+\",\"+a[3]+\")\"},toHsl:function(){var a=this.getSource(),b=this._rgbToHsl(a[0],a[1],a[2]);return\"hsl(\"+b[0]+\",\"+b[1]+\"%,\"+b[2]+\"%)\"},toHsla:function(){var a=this.getSource(),b=this._rgbToHsl(a[0],a[1],a[2]);return\"hsla(\"+b[0]+\",\"+b[1]+\"%,\"+b[2]+\"%,\"+a[3]+\")\"},toHex:function(){var b,c,d,a=this.getSource();return b=a[0].toString(16),b=1===b.length?\"0\"+b:b,c=a[1].toString(16),c=1===c.length?\"0\"+c:c,d=a[2].toString(16),d=1===d.length?\"0\"+d:d,b.toUpperCase()+c.toUpperCase()+d.toUpperCase()},getAlpha:function(){return this.getSource()[3]},setAlpha:function(a){var b=this.getSource();return b[3]=a,this.setSource(b),this},toGrayscale:function(){var a=this.getSource(),b=parseInt((.3*a[0]+.59*a[1]+.11*a[2]).toFixed(0),10),c=a[3];return this.setSource([b,b,b,c]),this},toBlackWhite:function(a){var b=this.getSource(),c=(.3*b[0]+.59*b[1]+.11*b[2]).toFixed(0),d=b[3];return a=a||127,c=Number(c)<Number(a)?0:255,this.setSource([c,c,c,d]),this},overlayWith:function(a){a instanceof c||(a=new c(a));for(var b=[],d=this.getAlpha(),e=.5,f=this.getSource(),g=a.getSource(),h=0;h<3;h++)b.push(Math.round(f[h]*(1-e)+g[h]*e));return b[3]=d,this.setSource(b),this}},b.Color.reRGBa=/^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/,b.Color.reHSLa=/^hsla?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}\\%)\\s*,\\s*(\\d{1,3}\\%)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/,b.Color.reHex=/^#?([0-9a-f]{6}|[0-9a-f]{3})$/i,b.Color.colorNameMap={aqua:\"#00FFFF\",black:\"#000000\",blue:\"#0000FF\",fuchsia:\"#FF00FF\",gray:\"#808080\",green:\"#008000\",lime:\"#00FF00\",maroon:\"#800000\",navy:\"#000080\",olive:\"#808000\",orange:\"#FFA500\",purple:\"#800080\",red:\"#FF0000\",silver:\"#C0C0C0\",teal:\"#008080\",white:\"#FFFFFF\",yellow:\"#FFFF00\"},b.Color.fromRgb=function(a){return c.fromSource(c.sourceFromRgb(a))},b.Color.sourceFromRgb=function(a){var b=a.match(c.reRGBa);if(b){var d=parseInt(b[1],10)/(/%$/.test(b[1])?100:1)*(/%$/.test(b[1])?255:1),e=parseInt(b[2],10)/(/%$/.test(b[2])?100:1)*(/%$/.test(b[2])?255:1),f=parseInt(b[3],10)/(/%$/.test(b[3])?100:1)*(/%$/.test(b[3])?255:1);return[parseInt(d,10),parseInt(e,10),parseInt(f,10),b[4]?parseFloat(b[4]):1]}},b.Color.fromRgba=c.fromRgb,b.Color.fromHsl=function(a){return c.fromSource(c.sourceFromHsl(a))},b.Color.sourceFromHsl=function(a){var b=a.match(c.reHSLa);if(b){var h,i,j,e=(parseFloat(b[1])%360+360)%360/360,f=parseFloat(b[2])/(/%$/.test(b[2])?100:1),g=parseFloat(b[3])/(/%$/.test(b[3])?100:1);if(0===f)h=i=j=g;else{var k=g<=.5?g*(f+1):g+f-g*f,l=2*g-k;h=d(l,k,e+1/3),i=d(l,k,e),j=d(l,k,e-1/3)}return[Math.round(255*h),Math.round(255*i),Math.round(255*j),b[4]?parseFloat(b[4]):1]}},b.Color.fromHsla=c.fromHsl,b.Color.fromHex=function(a){return c.fromSource(c.sourceFromHex(a))},b.Color.sourceFromHex=function(a){if(a.match(c.reHex)){var b=a.slice(a.indexOf(\"#\")+1),d=3===b.length,e=d?b.charAt(0)+b.charAt(0):b.substring(0,2),f=d?b.charAt(1)+b.charAt(1):b.substring(2,4),g=d?b.charAt(2)+b.charAt(2):b.substring(4,6);return[parseInt(e,16),parseInt(f,16),parseInt(g,16),1]}},void(b.Color.fromSource=function(a){var b=new c;return b.setSource(a),b}))}(\"undefined\"!=typeof exports?exports:this),function(){function a(a){var d,e,f,b=a.getAttribute(\"style\"),c=a.getAttribute(\"offset\");if(c=parseFloat(c)/(/%$/.test(c)?100:1),c=c<0?0:c>1?1:c,b){var g=b.split(/\\s*;\\s*/);\"\"===g[g.length-1]&&g.pop();for(var h=g.length;h--;){var i=g[h].split(/\\s*:\\s*/),j=i[0].trim(),k=i[1].trim();\"stop-color\"===j?d=k:\"stop-opacity\"===j&&(f=k)}}return d||(d=a.getAttribute(\"stop-color\")||\"rgb(0,0,0)\"),f||(f=a.getAttribute(\"stop-opacity\")),d=new fabric.Color(d),e=d.getAlpha(),f=isNaN(parseFloat(f))?1:parseFloat(f),f*=e,{offset:c,color:d.toRgb(),opacity:f}}function b(a){return{x1:a.getAttribute(\"x1\")||0,y1:a.getAttribute(\"y1\")||0,x2:a.getAttribute(\"x2\")||\"100%\",y2:a.getAttribute(\"y2\")||0}}function c(a){return{x1:a.getAttribute(\"fx\")||a.getAttribute(\"cx\")||\"50%\",y1:a.getAttribute(\"fy\")||a.getAttribute(\"cy\")||\"50%\",r1:0,x2:a.getAttribute(\"cx\")||\"50%\",y2:a.getAttribute(\"cy\")||\"50%\",r2:a.getAttribute(\"r\")||\"50%\"}}function d(a,b,c){var d,e=0,f=1,g=\"\";for(var h in b)d=parseFloat(b[h],10),f=\"string\"==typeof b[h]&&/^\\d+%$/.test(b[h])?.01:1,\"x1\"===h||\"x2\"===h||\"r2\"===h?(f*=\"objectBoundingBox\"===c?a.width:1,e=\"objectBoundingBox\"===c?a.left||0:0):\"y1\"!==h&&\"y2\"!==h||(f*=\"objectBoundingBox\"===c?a.height:1,e=\"objectBoundingBox\"===c?a.top||0:0),b[h]=d*f+e;if(\"ellipse\"===a.type&&null!==b.r2&&\"objectBoundingBox\"===c&&a.rx!==a.ry){var i=a.ry/a.rx;g=\" scale(1, \"+i+\")\",b.y1&&(b.y1/=i),b.y2&&(b.y2/=i)}return g}fabric.Gradient=fabric.util.createClass({offsetX:0,offsetY:0,initialize:function(a){a||(a={});var b={};this.id=fabric.Object.__uid++,this.type=a.type||\"linear\",b={x1:a.coords.x1||0,y1:a.coords.y1||0,x2:a.coords.x2||0,y2:a.coords.y2||0},\"radial\"===this.type&&(b.r1=a.coords.r1||0,b.r2=a.coords.r2||0),this.coords=b,this.colorStops=a.colorStops.slice(),a.gradientTransform&&(this.gradientTransform=a.gradientTransform),this.offsetX=a.offsetX||this.offsetX,this.offsetY=a.offsetY||this.offsetY},addColorStop:function(a){for(var b in a){var c=new fabric.Color(a[b]);this.colorStops.push({offset:b,color:c.toRgb(),opacity:c.getAlpha()})}return this},toObject:function(){return{type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY}},toSVG:function(a){var c,d,b=fabric.util.object.clone(this.coords);if(this.colorStops.sort(function(a,b){return a.offset-b.offset}),!a.group||\"path-group\"!==a.group.type)for(var e in b)\"x1\"===e||\"x2\"===e||\"r2\"===e?b[e]+=this.offsetX-a.width/2:\"y1\"!==e&&\"y2\"!==e||(b[e]+=this.offsetY-a.height/2);d='id=\"SVGID_'+this.id+'\" gradientUnits=\"userSpaceOnUse\"',this.gradientTransform&&(d+=' gradientTransform=\"matrix('+this.gradientTransform.join(\" \")+')\" '),\"linear\"===this.type?c=[\"<linearGradient \",d,' x1=\"',b.x1,'\" y1=\"',b.y1,'\" x2=\"',b.x2,'\" y2=\"',b.y2,'\">\\n']:\"radial\"===this.type&&(c=[\"<radialGradient \",d,' cx=\"',b.x2,'\" cy=\"',b.y2,'\" r=\"',b.r2,'\" fx=\"',b.x1,'\" fy=\"',b.y1,'\">\\n']);for(var f=0;f<this.colorStops.length;f++)c.push(\"<stop \",'offset=\"',100*this.colorStops[f].offset+\"%\",'\" style=\"stop-color:',this.colorStops[f].color,null!=this.colorStops[f].opacity?\";stop-opacity: \"+this.colorStops[f].opacity:\";\",'\"/>\\n');return c.push(\"linear\"===this.type?\"</linearGradient>\\n\":\"</radialGradient>\\n\"),c.join(\"\")},toLive:function(a,b){var c,d=fabric.util.object.clone(this.coords);if(this.type){if(b.group&&\"path-group\"===b.group.type)for(var e in d)\"x1\"===e||\"x2\"===e?d[e]+=-this.offsetX+b.width/2:\"y1\"!==e&&\"y2\"!==e||(d[e]+=-this.offsetY+b.height/2);\"linear\"===this.type?c=a.createLinearGradient(d.x1,d.y1,d.x2,d.y2):\"radial\"===this.type&&(c=a.createRadialGradient(d.x1,d.y1,d.r1,d.x2,d.y2,d.r2));for(var f=0,g=this.colorStops.length;f<g;f++){var h=this.colorStops[f].color,i=this.colorStops[f].opacity,j=this.colorStops[f].offset;\"undefined\"!=typeof i&&(h=new fabric.Color(h).setAlpha(i).toRgba()),c.addColorStop(parseFloat(j),h)}return c}}}),fabric.util.object.extend(fabric.Gradient,{fromElement:function(e,f){var m,g=e.getElementsByTagName(\"stop\"),h=\"linearGradient\"===e.nodeName?\"linear\":\"radial\",i=e.getAttribute(\"gradientUnits\")||\"objectBoundingBox\",j=e.getAttribute(\"gradientTransform\"),k=[],l={};\"linear\"===h?l=b(e):\"radial\"===h&&(l=c(e));for(var n=g.length;n--;)k.push(a(g[n]));m=d(f,l,i);var o=new fabric.Gradient({type:h,coords:l,colorStops:k,offsetX:-f.left,offsetY:-f.top});return(j||\"\"!==m)&&(o.gradientTransform=fabric.parseTransformAttribute((j||\"\")+m)),o},forObject:function(a,b){return b||(b={}),d(a,b.coords,\"userSpaceOnUse\"),new fabric.Gradient(b)}})}(),fabric.Pattern=fabric.util.createClass({repeat:\"repeat\",offsetX:0,offsetY:0,initialize:function(a){if(a||(a={}),this.id=fabric.Object.__uid++,a.source)if(\"string\"==typeof a.source)if(\"undefined\"!=typeof fabric.util.getFunctionBody(a.source))this.source=new Function(fabric.util.getFunctionBody(a.source));else{var b=this;this.source=fabric.util.createImage(),fabric.util.loadImage(a.source,function(a){b.source=a})}else this.source=a.source;a.repeat&&(this.repeat=a.repeat),a.offsetX&&(this.offsetX=a.offsetX),a.offsetY&&(this.offsetY=a.offsetY)},toObject:function(){var a;return\"function\"==typeof this.source?a=String(this.source):\"string\"==typeof this.source.src&&(a=this.source.src),{source:a,repeat:this.repeat,offsetX:this.offsetX,offsetY:this.offsetY}},toSVG:function(a){var b=\"function\"==typeof this.source?this.source():this.source,c=b.width/a.getWidth(),d=b.height/a.getHeight(),e=\"\";return b.src?e=b.src:b.toDataURL&&(e=b.toDataURL()),'<pattern id=\"SVGID_'+this.id+'\" x=\"'+this.offsetX+'\" y=\"'+this.offsetY+'\" width=\"'+c+'\" height=\"'+d+'\"><image x=\"0\" y=\"0\" width=\"'+b.width+'\" height=\"'+b.height+'\" xlink:href=\"'+e+'\"></image></pattern>'},toLive:function(a){var b=\"function\"==typeof this.source?this.source():this.source;if(!b)return\"\";if(\"undefined\"!=typeof b.src){if(!b.complete)return\"\";if(0===b.naturalWidth||0===b.naturalHeight)return\"\"}return a.createPattern(b,this.repeat)}}),function(a){\"use strict\";var b=a.fabric||(a.fabric={});return b.Shadow?void b.warn(\"fabric.Shadow is already defined.\"):(b.Shadow=b.util.createClass({color:\"rgb(0,0,0)\",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(a){\"string\"==typeof a&&(a=this._parseShadow(a));for(var c in a)this[c]=a[c];this.id=b.Object.__uid++},_parseShadow:function(a){var c=a.trim(),d=b.Shadow.reOffsetsAndBlur.exec(c)||[],e=c.replace(b.Shadow.reOffsetsAndBlur,\"\")||\"rgb(0,0,0)\";return{color:e.trim(),offsetX:parseInt(d[1],10)||0,offsetY:parseInt(d[2],10)||0,blur:parseInt(d[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join(\"px \")},toSVG:function(a){var b=\"SourceAlpha\";return!a||a.fill!==this.color&&a.stroke!==this.color||(b=\"SourceGraphic\"),'<filter id=\"SVGID_'+this.id+'\" y=\"-40%\" height=\"180%\"><feGaussianBlur in=\"'+b+'\" stdDeviation=\"'+(this.blur?this.blur/3:0)+'\"></feGaussianBlur><feOffset dx=\"'+this.offsetX+'\" dy=\"'+this.offsetY+'\"></feOffset><feMerge><feMergeNode></feMergeNode><feMergeNode in=\"SourceGraphic\"></feMergeNode></feMerge></filter>'},toObject:function(){if(this.includeDefaultValues)return{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY};var a={},c=b.Shadow.prototype;return this.color!==c.color&&(a.color=this.color),this.blur!==c.blur&&(a.blur=this.blur),this.offsetX!==c.offsetX&&(a.offsetX=this.offsetX),this.offsetY!==c.offsetY&&(a.offsetY=this.offsetY),a}}),void(b.Shadow.reOffsetsAndBlur=/(?:\\s|^)(-?\\d+(?:px)?(?:\\s?|$))?(-?\\d+(?:px)?(?:\\s?|$))?(\\d+(?:px)?)?(?:\\s?|$)(?:$|\\s)/))}(\"undefined\"!=typeof exports?exports:this),function(){\"use strict\";if(fabric.StaticCanvas)return void fabric.warn(\"fabric.StaticCanvas is already defined.\");var a=fabric.util.object.extend,b=fabric.util.getElementOffset,c=fabric.util.removeFromArray,d=new Error(\"Could not initialize `canvas` element\");fabric.StaticCanvas=fabric.util.createClass({initialize:function(a,b){b||(b={}),this._initStatic(a,b),fabric.StaticCanvas.activeInstance=this},backgroundColor:\"\",backgroundImage:null,overlayColor:\"\",overlayImage:null,includeDefaultValues:!0,stateful:!0,renderOnAddRemove:!0,clipTo:null,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,preserveObjectStacking:!1,viewportTransform:[1,0,0,1,0,0],onBeforeScaleRotate:function(){},_initStatic:function(a,b){this._objects=[],this._createLowerCanvas(a),this._initOptions(b),this._setImageSmoothing(),b.overlayImage&&this.setOverlayImage(b.overlayImage,this.renderAll.bind(this)),b.backgroundImage&&this.setBackgroundImage(b.backgroundImage,this.renderAll.bind(this)),b.backgroundColor&&this.setBackgroundColor(b.backgroundColor,this.renderAll.bind(this)),b.overlayColor&&this.setOverlayColor(b.overlayColor,this.renderAll.bind(this)),this.calcOffset()},calcOffset:function(){return this._offset=b(this.lowerCanvasEl),this},setOverlayImage:function(a,b,c){return this.__setBgOverlayImage(\"overlayImage\",a,b,c)},setBackgroundImage:function(a,b,c){return this.__setBgOverlayImage(\"backgroundImage\",a,b,c)},setOverlayColor:function(a,b){return this.__setBgOverlayColor(\"overlayColor\",a,b)},setBackgroundColor:function(a,b){return this.__setBgOverlayColor(\"backgroundColor\",a,b)},_setImageSmoothing:function(){var a=this.getContext();a.imageSmoothingEnabled=this.imageSmoothingEnabled,a.imageSmoothingEnabled=this.imageSmoothingEnabled,a.mozImageSmoothingEnabled=this.imageSmoothingEnabled,a.msImageSmoothingEnabled=this.imageSmoothingEnabled,a.oImageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(a,b,c,d){return\"string\"==typeof b?fabric.util.loadImage(b,function(b){this[a]=new fabric.Image(b,d),c&&c()},this):(this[a]=b,c&&c()),this},__setBgOverlayColor:function(a,b,c){if(b&&b.source){var d=this;fabric.util.loadImage(b.source,function(e){d[a]=new fabric.Pattern({source:e,repeat:b.repeat,offsetX:b.offsetX,offsetY:b.offsetY}),c&&c()})}else this[a]=b,c&&c();return this},_createCanvasElement:function(){var a=fabric.document.createElement(\"canvas\");if(a.style||(a.style={}),!a)throw d;return this._initCanvasElement(a),a},_initCanvasElement:function(a){if(fabric.util.createCanvasElement(a),\"undefined\"==typeof a.getContext)throw d},_initOptions:function(a){for(var b in a)this[b]=a[b];this.width=this.width||parseInt(this.lowerCanvasEl.width,10)||0,this.height=this.height||parseInt(this.lowerCanvasEl.height,10)||0,this.lowerCanvasEl.style&&(this.lowerCanvasEl.width=this.width,this.lowerCanvasEl.height=this.height,this.lowerCanvasEl.style.width=this.width+\"px\",this.lowerCanvasEl.style.height=this.height+\"px\",this.viewportTransform=this.viewportTransform.slice())},_createLowerCanvas:function(a){this.lowerCanvasEl=fabric.util.getById(a)||this._createCanvasElement(),this._initCanvasElement(this.lowerCanvasEl),fabric.util.addClass(this.lowerCanvasEl,\"lower-canvas\"),this.interactive&&this._applyCanvasStyle(this.lowerCanvasEl),this.contextContainer=this.lowerCanvasEl.getContext(\"2d\")},getWidth:function(){return this.width},getHeight:function(){return this.height},setWidth:function(a,b){return this.setDimensions({width:a},b)},setHeight:function(a,b){return this.setDimensions({height:a},b)},setDimensions:function(a,b){var c;b=b||{};for(var d in a)c=a[d],b.cssOnly||(this._setBackstoreDimension(d,a[d]),c+=\"px\"),b.backstoreOnly||this._setCssDimension(d,c);return b.cssOnly||this.renderAll(),this.calcOffset(),this},_setBackstoreDimension:function(a,b){return this.lowerCanvasEl[a]=b,this.upperCanvasEl&&(this.upperCanvasEl[a]=b),this.cacheCanvasEl&&(this.cacheCanvasEl[a]=b),this[a]=b,this},_setCssDimension:function(a,b){return this.lowerCanvasEl.style[a]=b,this.upperCanvasEl&&(this.upperCanvasEl.style[a]=b),this.wrapperEl&&(this.wrapperEl.style[a]=b),this},getZoom:function(){return Math.sqrt(this.viewportTransform[0]*this.viewportTransform[3])},setViewportTransform:function(a){this.viewportTransform=a,this.renderAll();for(var b=0,c=this._objects.length;b<c;b++)this._objects[b].setCoords();return this},zoomToPoint:function(a,b){var c=a;a=fabric.util.transformPoint(a,fabric.util.invertTransform(this.viewportTransform)),this.viewportTransform[0]=b,this.viewportTransform[3]=b;var d=fabric.util.transformPoint(a,this.viewportTransform);this.viewportTransform[4]+=c.x-d.x,this.viewportTransform[5]+=c.y-d.y,this.renderAll();for(var e=0,f=this._objects.length;e<f;e++)this._objects[e].setCoords();return this},setZoom:function(a){return this.zoomToPoint(new fabric.Point(0,0),a),this},absolutePan:function(a){this.viewportTransform[4]=-a.x,this.viewportTransform[5]=-a.y,this.renderAll();for(var b=0,c=this._objects.length;b<c;b++)this._objects[b].setCoords();return this},relativePan:function(a){return this.absolutePan(new fabric.Point(-a.x-this.viewportTransform[4],-a.y-this.viewportTransform[5]))},getElement:function(){return this.lowerCanvasEl},getActiveObject:function(){return null},getActiveGroup:function(){return null},_draw:function(a,b){if(b){a.save();var c=this.viewportTransform;a.transform(c[0],c[1],c[2],c[3],c[4],c[5]),this._shouldRenderObject(b)&&b.render(a),a.restore(),this.controlsAboveOverlay||b._renderControls(a)}},_shouldRenderObject:function(a){return!!a&&(a!==this.getActiveGroup()||!this.preserveObjectStacking)},_onObjectAdded:function(a){this.stateful&&a.setupState(),a.canvas=this,a.setCoords(),this.fire(\"object:added\",{target:a}),a.fire(\"added\")},_onObjectRemoved:function(a){this.getActiveObject()===a&&(this.fire(\"before:selection:cleared\",{target:a}),this._discardActiveObject(),this.fire(\"selection:cleared\")),this.fire(\"object:removed\",{target:a}),a.fire(\"removed\")},clearContext:function(a){return a.clearRect(0,0,this.width,this.height),this},getContext:function(){return this.contextContainer},clear:function(){return this._objects.length=0,this.discardActiveGroup&&this.discardActiveGroup(),this.discardActiveObject&&this.discardActiveObject(),this.clearContext(this.contextContainer),this.contextTop&&this.clearContext(this.contextTop),this.fire(\"canvas:cleared\"),this.renderAll(),this},renderAll:function(a){var b=this[a===!0&&this.interactive?\"contextTop\":\"contextContainer\"],c=this.getActiveGroup();return this.contextTop&&this.selection&&!this._groupSelector&&this.clearContext(this.contextTop),a||this.clearContext(b),this.fire(\"before:render\"),this.clipTo&&fabric.util.clipContext(this,b),this._renderBackground(b),this._renderObjects(b,c),this._renderActiveGroup(b,c),this.clipTo&&b.restore(),this._renderOverlay(b),this.controlsAboveOverlay&&this.interactive&&this.drawControls(b),this.fire(\"after:render\"),this},_renderObjects:function(a,b){var c,d;if(!b||this.preserveObjectStacking)for(c=0,d=this._objects.length;c<d;++c)this._draw(a,this._objects[c]);else for(c=0,d=this._objects.length;c<d;++c)this._objects[c]&&!b.contains(this._objects[c])&&this._draw(a,this._objects[c])},_renderActiveGroup:function(a,b){if(b){var c=[];this.forEachObject(function(a){b.contains(a)&&c.push(a)}),b._set(\"objects\",c),this._draw(a,b)}},_renderBackground:function(a){this.backgroundColor&&(a.fillStyle=this.backgroundColor.toLive?this.backgroundColor.toLive(a):this.backgroundColor,a.fillRect(this.backgroundColor.offsetX||0,this.backgroundColor.offsetY||0,this.width,this.height)),this.backgroundImage&&this._draw(a,this.backgroundImage)},_renderOverlay:function(a){this.overlayColor&&(a.fillStyle=this.overlayColor.toLive?this.overlayColor.toLive(a):this.overlayColor,a.fillRect(this.overlayColor.offsetX||0,this.overlayColor.offsetY||0,this.width,this.height)),this.overlayImage&&this._draw(a,this.overlayImage)},renderTop:function(){var a=this.contextTop||this.contextContainer;this.clearContext(a),this.selection&&this._groupSelector&&this._drawSelection();var b=this.getActiveGroup();return b&&b.render(a),this._renderOverlay(a),this.fire(\"after:render\"),this},getCenter:function(){return{top:this.getHeight()/2,left:this.getWidth()/2}},centerObjectH:function(a){return this._centerObject(a,new fabric.Point(this.getCenter().left,a.getCenterPoint().y)),this.renderAll(),this},centerObjectV:function(a){return this._centerObject(a,new fabric.Point(a.getCenterPoint().x,this.getCenter().top)),this.renderAll(),this},centerObject:function(a){var b=this.getCenter();return this._centerObject(a,new fabric.Point(b.left,b.top)),this.renderAll(),this},_centerObject:function(a,b){return a.setPositionByOrigin(b,\"center\",\"center\"),this},toDatalessJSON:function(a){return this.toDatalessObject(a)},toObject:function(a){return this._toObjectMethod(\"toObject\",a)},toDatalessObject:function(a){return this._toObjectMethod(\"toDatalessObject\",a)},_toObjectMethod:function(b,c){var d=this.getActiveGroup();d&&this.discardActiveGroup();var e={objects:this._toObjects(b,c)};return a(e,this.__serializeBgOverlay()),fabric.util.populateWithProperties(this,e,c),d&&(this.setActiveGroup(new fabric.Group(d.getObjects(),{originX:\"center\",originY:\"center\"})),d.forEachObject(function(a){a.set(\"active\",!0)}),this._currentTransform&&(this._currentTransform.target=this.getActiveGroup())),e},_toObjects:function(a,b){return this.getObjects().map(function(c){return this._toObject(c,a,b)},this)},_toObject:function(a,b,c){var d;this.includeDefaultValues||(d=a.includeDefaultValues,a.includeDefaultValues=!1);var e=a[b](c);return this.includeDefaultValues||(a.includeDefaultValues=d),e},__serializeBgOverlay:function(){var a={background:this.backgroundColor&&this.backgroundColor.toObject?this.backgroundColor.toObject():this.backgroundColor};return this.overlayColor&&(a.overlay=this.overlayColor.toObject?this.overlayColor.toObject():this.overlayColor),this.backgroundImage&&(a.backgroundImage=this.backgroundImage.toObject()),this.overlayImage&&(a.overlayImage=this.overlayImage.toObject()),a},svgViewportTransformation:!0,toSVG:function(a,b){a||(a={});var c=[];return this._setSVGPreamble(c,a),this._setSVGHeader(c,a),this._setSVGBgOverlayColor(c,\"backgroundColor\"),this._setSVGBgOverlayImage(c,\"backgroundImage\"),this._setSVGObjects(c,b),this._setSVGBgOverlayColor(c,\"overlayColor\"),this._setSVGBgOverlayImage(c,\"overlayImage\"),c.push(\"</svg>\"),c.join(\"\")},_setSVGPreamble:function(a,b){b.suppressPreamble||a.push('<?xml version=\"1.0\" encoding=\"',b.encoding||\"UTF-8\",'\" standalone=\"no\" ?>','<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ','\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\\n')},_setSVGHeader:function(a,b){var c,d,e;b.viewBox?(c=b.viewBox.width,d=b.viewBox.height):(c=this.width,d=this.height,this.svgViewportTransformation||(e=this.viewportTransform,c/=e[0],d/=e[3])),a.push(\"<svg \",'xmlns=\"http://www.w3.org/2000/svg\" ','xmlns:xlink=\"http://www.w3.org/1999/xlink\" ','version=\"1.1\" ','width=\"',c,'\" ','height=\"',d,'\" ',this.backgroundColor&&!this.backgroundColor.toLive?'style=\"background-color: '+this.backgroundColor+'\" ':null,b.viewBox?'viewBox=\"'+b.viewBox.x+\" \"+b.viewBox.y+\" \"+b.viewBox.width+\" \"+b.viewBox.height+'\" ':null,'xml:space=\"preserve\">',\"<desc>Created with Fabric.js \",fabric.version,\"</desc>\",\"<defs>\",fabric.createSVGFontFacesMarkup(this.getObjects()),fabric.createSVGRefElementsMarkup(this),\"</defs>\")},_setSVGObjects:function(a,b){var c=this.getActiveGroup();c&&this.discardActiveGroup();for(var d=0,e=this.getObjects(),f=e.length;d<f;d++)a.push(e[d].toSVG(b));c&&(this.setActiveGroup(new fabric.Group(c.getObjects())),c.forEachObject(function(a){a.set(\"active\",!0)}))},_setSVGBgOverlayImage:function(a,b){this[b]&&this[b].toSVG&&a.push(this[b].toSVG())},_setSVGBgOverlayColor:function(a,b){this[b]&&this[b].source?a.push('<rect x=\"',this[b].offsetX,'\" y=\"',this[b].offsetY,'\" ','width=\"',\"repeat-y\"===this[b].repeat||\"no-repeat\"===this[b].repeat?this[b].source.width:this.width,'\" height=\"',\"repeat-x\"===this[b].repeat||\"no-repeat\"===this[b].repeat?this[b].source.height:this.height,'\" fill=\"url(#'+b+'Pattern)\"',\"></rect>\"):this[b]&&\"overlayColor\"===b&&a.push('<rect x=\"0\" y=\"0\" ','width=\"',this.width,'\" height=\"',this.height,'\" fill=\"',this[b],'\"',\"></rect>\")},sendToBack:function(a){return c(this._objects,a),this._objects.unshift(a),this.renderAll&&this.renderAll()},bringToFront:function(a){return c(this._objects,a),this._objects.push(a),this.renderAll&&this.renderAll()},sendBackwards:function(a,b){var d=this._objects.indexOf(a);if(0!==d){var e=this._findNewLowerIndex(a,d,b);c(this._objects,a),this._objects.splice(e,0,a),this.renderAll&&this.renderAll()}return this},\n_findNewLowerIndex:function(a,b,c){var d;if(c){d=b;for(var e=b-1;e>=0;--e){var f=a.intersectsWithObject(this._objects[e])||a.isContainedWithinObject(this._objects[e])||this._objects[e].isContainedWithinObject(a);if(f){d=e;break}}}else d=b-1;return d},bringForward:function(a,b){var d=this._objects.indexOf(a);if(d!==this._objects.length-1){var e=this._findNewUpperIndex(a,d,b);c(this._objects,a),this._objects.splice(e,0,a),this.renderAll&&this.renderAll()}return this},_findNewUpperIndex:function(a,b,c){var d;if(c){d=b;for(var e=b+1;e<this._objects.length;++e){var f=a.intersectsWithObject(this._objects[e])||a.isContainedWithinObject(this._objects[e])||this._objects[e].isContainedWithinObject(a);if(f){d=e;break}}}else d=b+1;return d},moveTo:function(a,b){return c(this._objects,a),this._objects.splice(b,0,a),this.renderAll&&this.renderAll()},dispose:function(){return this.clear(),this.interactive&&this.removeListeners(),this},toString:function(){return\"#<fabric.Canvas (\"+this.complexity()+\"): { objects: \"+this.getObjects().length+\" }>\"}}),a(fabric.StaticCanvas.prototype,fabric.Observable),a(fabric.StaticCanvas.prototype,fabric.Collection),a(fabric.StaticCanvas.prototype,fabric.DataURLExporter),a(fabric.StaticCanvas,{EMPTY_JSON:'{\"objects\": [], \"background\": \"white\"}',supports:function(a){var b=fabric.util.createCanvasElement();if(!b||!b.getContext)return null;var c=b.getContext(\"2d\");if(!c)return null;switch(a){case\"getImageData\":return\"undefined\"!=typeof c.getImageData;case\"setLineDash\":return\"undefined\"!=typeof c.setLineDash;case\"toDataURL\":return\"undefined\"!=typeof b.toDataURL;case\"toDataURLWithQuality\":try{return b.toDataURL(\"image/jpeg\",0),!0}catch(a){}return!1;default:return null}}}),fabric.StaticCanvas.prototype.toJSON=fabric.StaticCanvas.prototype.toObject}(),fabric.BaseBrush=fabric.util.createClass({color:\"rgb(0, 0, 0)\",width:1,shadow:null,strokeLineCap:\"round\",strokeLineJoin:\"round\",setShadow:function(a){return this.shadow=new fabric.Shadow(a),this},_setBrushStyles:function(){var a=this.canvas.contextTop;a.strokeStyle=this.color,a.lineWidth=this.width,a.lineCap=this.strokeLineCap,a.lineJoin=this.strokeLineJoin},_setShadow:function(){if(this.shadow){var a=this.canvas.contextTop;a.shadowColor=this.shadow.color,a.shadowBlur=this.shadow.blur,a.shadowOffsetX=this.shadow.offsetX,a.shadowOffsetY=this.shadow.offsetY}},_resetShadow:function(){var a=this.canvas.contextTop;a.shadowColor=\"\",a.shadowBlur=a.shadowOffsetX=a.shadowOffsetY=0}}),function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(a){this.canvas=a,this._points=[]},onMouseDown:function(a){this._prepareForDrawing(a),this._captureDrawingPath(a),this._render()},onMouseMove:function(a){this._captureDrawingPath(a),this.canvas.clearContext(this.canvas.contextTop),this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(a){var b=new fabric.Point(a.x,a.y);this._reset(),this._addPoint(b),this.canvas.contextTop.moveTo(b.x,b.y)},_addPoint:function(a){this._points.push(a)},_reset:function(){this._points.length=0,this._setBrushStyles(),this._setShadow()},_captureDrawingPath:function(a){var b=new fabric.Point(a.x,a.y);this._addPoint(b)},_render:function(){var a=this.canvas.contextTop,b=this.canvas.viewportTransform,c=this._points[0],d=this._points[1];a.save(),a.transform(b[0],b[1],b[2],b[3],b[4],b[5]),a.beginPath(),2===this._points.length&&c.x===d.x&&c.y===d.y&&(c.x-=.5,d.x+=.5),a.moveTo(c.x,c.y);for(var e=1,f=this._points.length;e<f;e++){var g=c.midPointFrom(d);a.quadraticCurveTo(c.x,c.y,g.x,g.y),c=this._points[e],d=this._points[e+1]}a.lineTo(c.x,c.y),a.stroke(),a.restore()},convertPointsToSVGPath:function(a){var b=[],c=new fabric.Point(a[0].x,a[0].y),d=new fabric.Point(a[1].x,a[1].y);b.push(\"M \",a[0].x,\" \",a[0].y,\" \");for(var e=1,f=a.length;e<f;e++){var g=c.midPointFrom(d);b.push(\"Q \",c.x,\" \",c.y,\" \",g.x,\" \",g.y,\" \"),c=new fabric.Point(a[e].x,a[e].y),e+1<a.length&&(d=new fabric.Point(a[e+1].x,a[e+1].y))}return b.push(\"L \",c.x,\" \",c.y,\" \"),b},createPath:function(a){var b=new fabric.Path(a);return b.fill=null,b.stroke=this.color,b.strokeWidth=this.width,b.strokeLineCap=this.strokeLineCap,b.strokeLineJoin=this.strokeLineJoin,this.shadow&&(this.shadow.affectStroke=!0,b.setShadow(this.shadow)),b},_finalizeAndAddPath:function(){var a=this.canvas.contextTop;a.closePath();var b=this.convertPointsToSVGPath(this._points).join(\"\");if(\"M 0 0 Q 0 0 0 0 L 0 0\"===b)return void this.canvas.renderAll();var c=this.createPath(b);this.canvas.add(c),c.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire(\"path:created\",{path:c})}})}(),fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(a){this.canvas=a,this.points=[]},drawDot:function(a){var b=this.addPoint(a),c=this.canvas.contextTop,d=this.canvas.viewportTransform;c.save(),c.transform(d[0],d[1],d[2],d[3],d[4],d[5]),c.fillStyle=b.fill,c.beginPath(),c.arc(b.x,b.y,b.radius,0,2*Math.PI,!1),c.closePath(),c.fill(),c.restore()},onMouseDown:function(a){this.points.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.drawDot(a)},onMouseMove:function(a){this.drawDot(a)},onMouseUp:function(){var a=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var b=[],c=0,d=this.points.length;c<d;c++){var e=this.points[c],f=new fabric.Circle({radius:e.radius,left:e.x,top:e.y,originX:\"center\",originY:\"center\",fill:e.fill});this.shadow&&f.setShadow(this.shadow),b.push(f)}var g=new fabric.Group(b,{originX:\"center\",originY:\"center\"});g.canvas=this.canvas,this.canvas.add(g),this.canvas.fire(\"path:created\",{path:g}),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderOnAddRemove=a,this.canvas.renderAll()},addPoint:function(a){var b=new fabric.Point(a.x,a.y),c=fabric.util.getRandomInt(Math.max(0,this.width-20),this.width+20)/2,d=new fabric.Color(this.color).setAlpha(fabric.util.getRandomInt(0,100)/100).toRgba();return b.radius=c,b.fill=d,this.points.push(b),b}}),fabric.SprayBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,density:20,dotWidth:1,dotWidthVariance:1,randomOpacity:!1,optimizeOverlapping:!0,initialize:function(a){this.canvas=a,this.sprayChunks=[]},onMouseDown:function(a){this.sprayChunks.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.addSprayChunk(a),this.render()},onMouseMove:function(a){this.addSprayChunk(a),this.render()},onMouseUp:function(){var a=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var b=[],c=0,d=this.sprayChunks.length;c<d;c++)for(var e=this.sprayChunks[c],f=0,g=e.length;f<g;f++){var h=new fabric.Rect({width:e[f].width,height:e[f].width,left:e[f].x+1,top:e[f].y+1,originX:\"center\",originY:\"center\",fill:this.color});this.shadow&&h.setShadow(this.shadow),b.push(h)}this.optimizeOverlapping&&(b=this._getOptimizedRects(b));var i=new fabric.Group(b,{originX:\"center\",originY:\"center\"});i.canvas=this.canvas,this.canvas.add(i),this.canvas.fire(\"path:created\",{path:i}),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderOnAddRemove=a,this.canvas.renderAll()},_getOptimizedRects:function(a){for(var c,b={},d=0,e=a.length;d<e;d++)c=a[d].left+\"\"+a[d].top,b[c]||(b[c]=a[d]);var f=[];for(c in b)f.push(b[c]);return f},render:function(){var a=this.canvas.contextTop;a.fillStyle=this.color;var b=this.canvas.viewportTransform;a.save(),a.transform(b[0],b[1],b[2],b[3],b[4],b[5]);for(var c=0,d=this.sprayChunkPoints.length;c<d;c++){var e=this.sprayChunkPoints[c];\"undefined\"!=typeof e.opacity&&(a.globalAlpha=e.opacity),a.fillRect(e.x,e.y,e.width,e.width)}a.restore()},addSprayChunk:function(a){this.sprayChunkPoints=[];for(var b,c,d,e=this.width/2,f=0;f<this.density;f++){b=fabric.util.getRandomInt(a.x-e,a.x+e),c=fabric.util.getRandomInt(a.y-e,a.y+e),d=this.dotWidthVariance?fabric.util.getRandomInt(Math.max(1,this.dotWidth-this.dotWidthVariance),this.dotWidth+this.dotWidthVariance):this.dotWidth;var g=new fabric.Point(b,c);g.width=d,this.randomOpacity&&(g.opacity=fabric.util.getRandomInt(0,100)/100),this.sprayChunkPoints.push(g)}this.sprayChunks.push(this.sprayChunkPoints)}}),fabric.PatternBrush=fabric.util.createClass(fabric.PencilBrush,{getPatternSrc:function(){var a=20,b=5,c=fabric.document.createElement(\"canvas\"),d=c.getContext(\"2d\");return c.width=c.height=a+b,d.fillStyle=this.color,d.beginPath(),d.arc(a/2,a/2,a/2,0,2*Math.PI,!1),d.closePath(),d.fill(),c},getPatternSrcFunction:function(){return String(this.getPatternSrc).replace(\"this.color\",'\"'+this.color+'\"')},getPattern:function(){return this.canvas.contextTop.createPattern(this.source||this.getPatternSrc(),\"repeat\")},_setBrushStyles:function(){this.callSuper(\"_setBrushStyles\"),this.canvas.contextTop.strokeStyle=this.getPattern()},createPath:function(a){var b=this.callSuper(\"createPath\",a);return b.stroke=new fabric.Pattern({source:this.source||this.getPatternSrcFunction()}),b}}),function(){var a=fabric.util.getPointer,b=fabric.util.degreesToRadians,c=fabric.util.radiansToDegrees,d=Math.atan2,e=Math.abs,f=.5;fabric.Canvas=fabric.util.createClass(fabric.StaticCanvas,{initialize:function(a,b){b||(b={}),this._initStatic(a,b),this._initInteractive(),this._createCacheCanvas(),fabric.Canvas.activeInstance=this},uniScaleTransform:!1,centeredScaling:!1,centeredRotation:!1,interactive:!0,selection:!0,selectionColor:\"rgba(100, 100, 255, 0.3)\",selectionDashArray:[],selectionBorderColor:\"rgba(255, 255, 255, 0.3)\",selectionLineWidth:1,hoverCursor:\"move\",moveCursor:\"move\",defaultCursor:\"default\",freeDrawingCursor:\"crosshair\",rotationCursor:\"crosshair\",containerClass:\"canvas-container\",perPixelTargetFind:!1,targetFindTolerance:0,skipTargetFind:!1,_initInteractive:function(){this._currentTransform=null,this._groupSelector=null,this._initWrapperElement(),this._createUpperCanvas(),this._initEventListeners(),this.freeDrawingBrush=fabric.PencilBrush&&new fabric.PencilBrush(this),this.calcOffset()},_resetCurrentTransform:function(a){var b=this._currentTransform;b.target.set({scaleX:b.original.scaleX,scaleY:b.original.scaleY,left:b.original.left,top:b.original.top}),this._shouldCenterTransform(a,b.target)?\"rotate\"===b.action?this._setOriginToCenter(b.target):(\"center\"!==b.originX&&(\"right\"===b.originX?b.mouseXSign=-1:b.mouseXSign=1),\"center\"!==b.originY&&(\"bottom\"===b.originY?b.mouseYSign=-1:b.mouseYSign=1),b.originX=\"center\",b.originY=\"center\"):(b.originX=b.original.originX,b.originY=b.original.originY)},containsPoint:function(a,b){var c=this.getPointer(a,!0),d=this._normalizePointer(b,c);return b.containsPoint(d)||b._findTargetCorner(c)},_normalizePointer:function(a,b){var g,c=this.getActiveGroup(),d=b.x,e=b.y,f=c&&\"group\"!==a.type&&c.contains(a);return f&&(g=new fabric.Point(c.left,c.top),g=fabric.util.transformPoint(g,this.viewportTransform,!0),d-=g.x,e-=g.y),{x:d,y:e}},isTargetTransparent:function(a,b,c){var d=a.hasBorders,e=a.transparentCorners;a.hasBorders=a.transparentCorners=!1,this._draw(this.contextCache,a),a.hasBorders=d,a.transparentCorners=e;var f=fabric.util.isTransparent(this.contextCache,b,c,this.targetFindTolerance);return this.clearContext(this.contextCache),f},_shouldClearSelection:function(a,b){var c=this.getActiveGroup(),d=this.getActiveObject();return!b||b&&c&&!c.contains(b)&&c!==b&&!a.shiftKey||b&&!b.evented||b&&!b.selectable&&d&&d!==b},_shouldCenterTransform:function(a,b){if(b){var d,c=this._currentTransform;return\"scale\"===c.action||\"scaleX\"===c.action||\"scaleY\"===c.action?d=this.centeredScaling||b.centeredScaling:\"rotate\"===c.action&&(d=this.centeredRotation||b.centeredRotation),d?!a.altKey:a.altKey}},_getOriginFromCorner:function(a,b){var c={x:a.originX,y:a.originY};return\"ml\"===b||\"tl\"===b||\"bl\"===b?c.x=\"right\":\"mr\"!==b&&\"tr\"!==b&&\"br\"!==b||(c.x=\"left\"),\"tl\"===b||\"mt\"===b||\"tr\"===b?c.y=\"bottom\":\"bl\"!==b&&\"mb\"!==b&&\"br\"!==b||(c.y=\"top\"),c},_getActionFromCorner:function(a,b){var c=\"drag\";return b&&(c=\"ml\"===b||\"mr\"===b?\"scaleX\":\"mt\"===b||\"mb\"===b?\"scaleY\":\"mtr\"===b?\"rotate\":\"scale\"),c},_setupCurrentTransform:function(a,c){if(c){var d=this.getPointer(a),e=c._findTargetCorner(this.getPointer(a,!0)),f=this._getActionFromCorner(c,e),g=this._getOriginFromCorner(c,e);this._currentTransform={target:c,action:f,scaleX:c.scaleX,scaleY:c.scaleY,offsetX:d.x-c.left,offsetY:d.y-c.top,originX:g.x,originY:g.y,ex:d.x,ey:d.y,left:c.left,top:c.top,theta:b(c.angle),width:c.width*c.scaleX,mouseXSign:1,mouseYSign:1},this._currentTransform.original={left:c.left,top:c.top,scaleX:c.scaleX,scaleY:c.scaleY,originX:g.x,originY:g.y},this._resetCurrentTransform(a)}},_translateObject:function(a,b){var c=this._currentTransform.target;c.get(\"lockMovementX\")||c.set(\"left\",a-this._currentTransform.offsetX),c.get(\"lockMovementY\")||c.set(\"top\",b-this._currentTransform.offsetY)},_scaleObject:function(a,b,c){var d=this._currentTransform,e=d.target,f=e.get(\"lockScalingX\"),g=e.get(\"lockScalingY\"),h=e.get(\"lockScalingFlip\");if(!f||!g){var i=e.translateToOriginPoint(e.getCenterPoint(),d.originX,d.originY),j=e.toLocalPoint(new fabric.Point(a,b),d.originX,d.originY);this._setLocalMouse(j,d),this._setObjectScale(j,d,f,g,c,h),e.setPositionByOrigin(i,d.originX,d.originY)}},_setObjectScale:function(a,b,c,d,e,f){var g=b.target,h=!1,i=!1;b.newScaleX=a.x/(g.width+g.strokeWidth),b.newScaleY=a.y/(g.height+g.strokeWidth),f&&b.newScaleX<=0&&b.newScaleX<g.scaleX&&(h=!0),f&&b.newScaleY<=0&&b.newScaleY<g.scaleY&&(i=!0),\"equally\"!==e||c||d?e?\"x\"!==e||g.get(\"lockUniScaling\")?\"y\"!==e||g.get(\"lockUniScaling\")||i||d||g.set(\"scaleY\",b.newScaleY):h||c||g.set(\"scaleX\",b.newScaleX):(h||c||g.set(\"scaleX\",b.newScaleX),i||d||g.set(\"scaleY\",b.newScaleY)):h||i||this._scaleObjectEqually(a,g,b),h||i||this._flipObject(b,e)},_scaleObjectEqually:function(a,b,c){var d=a.y+a.x,e=(b.height+b.strokeWidth)*c.original.scaleY+(b.width+b.strokeWidth)*c.original.scaleX;c.newScaleX=c.original.scaleX*d/e,c.newScaleY=c.original.scaleY*d/e,b.set(\"scaleX\",c.newScaleX),b.set(\"scaleY\",c.newScaleY)},_flipObject:function(a,b){a.newScaleX<0&&\"y\"!==b&&(\"left\"===a.originX?a.originX=\"right\":\"right\"===a.originX&&(a.originX=\"left\")),a.newScaleY<0&&\"x\"!==b&&(\"top\"===a.originY?a.originY=\"bottom\":\"bottom\"===a.originY&&(a.originY=\"top\"))},_setLocalMouse:function(a,b){var c=b.target;\"right\"===b.originX?a.x*=-1:\"center\"===b.originX&&(a.x*=2*b.mouseXSign,a.x<0&&(b.mouseXSign=-b.mouseXSign)),\"bottom\"===b.originY?a.y*=-1:\"center\"===b.originY&&(a.y*=2*b.mouseYSign,a.y<0&&(b.mouseYSign=-b.mouseYSign)),e(a.x)>c.padding?a.x<0?a.x+=c.padding:a.x-=c.padding:a.x=0,e(a.y)>c.padding?a.y<0?a.y+=c.padding:a.y-=c.padding:a.y=0},_rotateObject:function(a,b){var e=this._currentTransform;if(!e.target.get(\"lockRotation\")){var f=d(e.ey-e.top,e.ex-e.left),g=d(b-e.top,a-e.left),h=c(g-f+e.theta);h<0&&(h=360+h),e.target.angle=h}},setCursor:function(a){this.upperCanvasEl.style.cursor=a},_resetObjectTransform:function(a){a.scaleX=1,a.scaleY=1,a.setAngle(0)},_drawSelection:function(){var a=this.contextTop,b=this._groupSelector,c=b.left,d=b.top,g=e(c),h=e(d);if(a.fillStyle=this.selectionColor,a.fillRect(b.ex-(c>0?0:-c),b.ey-(d>0?0:-d),g,h),a.lineWidth=this.selectionLineWidth,a.strokeStyle=this.selectionBorderColor,this.selectionDashArray.length>1){var i=b.ex+f-(c>0?0:g),j=b.ey+f-(d>0?0:h);a.beginPath(),fabric.util.drawDashedLine(a,i,j,i+g,j,this.selectionDashArray),fabric.util.drawDashedLine(a,i,j+h-1,i+g,j+h-1,this.selectionDashArray),fabric.util.drawDashedLine(a,i,j,i,j+h,this.selectionDashArray),fabric.util.drawDashedLine(a,i+g-1,j,i+g-1,j+h,this.selectionDashArray),a.closePath(),a.stroke()}else a.strokeRect(b.ex+f-(c>0?0:g),b.ey+f-(d>0?0:h),g,h)},_isLastRenderedObject:function(a){return this.controlsAboveOverlay&&this.lastRenderedObjectWithControlsAboveOverlay&&this.lastRenderedObjectWithControlsAboveOverlay.visible&&this.containsPoint(a,this.lastRenderedObjectWithControlsAboveOverlay)&&this.lastRenderedObjectWithControlsAboveOverlay._findTargetCorner(this.getPointer(a,!0))},findTarget:function(a,b){if(!this.skipTargetFind){if(this._isLastRenderedObject(a))return this.lastRenderedObjectWithControlsAboveOverlay;var c=this.getActiveGroup();if(c&&!b&&this.containsPoint(a,c))return c;var d=this._searchPossibleTargets(a);return this._fireOverOutEvents(d),d}},_fireOverOutEvents:function(a){if(a){if(this._hoveredTarget!==a){if(this.fire(\"mouse:over\",{target:a}),a.fire(\"mouseover\"),this._hoveredTarget){if(this.fire(\"mouse:out\",{target:this._hoveredTarget}),!this._hoveredTarget.fire)return;this._hoveredTarget.fire(\"mouseout\")}this._hoveredTarget=a}}else if(this._hoveredTarget){if(this.fire(\"mouse:out\",{target:this._hoveredTarget}),!this._hoveredTarget.fire)return;this._hoveredTarget.fire(\"mouseout\"),this._hoveredTarget=null}},_checkTarget:function(a,b,c){if(b&&b.visible&&b.evented&&this.containsPoint(a,b)){if(!this.perPixelTargetFind&&!b.perPixelTargetFind||b.isEditing)return!0;var d=this.isTargetTransparent(b,c.x,c.y);if(!d)return!0}},_searchPossibleTargets:function(a){for(var b,c=this.getPointer(a,!0),d=this._objects.length;d--;)if(this._checkTarget(a,this._objects[d],c)){this.relatedTarget=this._objects[d],b=this._objects[d];break}return b},getPointer:function(b,c,d){d||(d=this.upperCanvasEl);var i,e=a(b,d),f=d.getBoundingClientRect(),g=f.width||0,h=f.height||0;return g&&h||(\"top\"in f&&\"bottom\"in f&&(h=Math.abs(f.top-f.bottom)),\"right\"in f&&\"left\"in f&&(g=Math.abs(f.right-f.left))),this.calcOffset(),e.x=e.x-this._offset.left,e.y=e.y-this._offset.top,c||(e=fabric.util.transformPoint(e,fabric.util.invertTransform(this.viewportTransform))),i=0===g||0===h?{width:1,height:1}:{width:d.width/g,height:d.height/h},{x:e.x*i.width,y:e.y*i.height}},_createUpperCanvas:function(){var a=this.lowerCanvasEl.className.replace(/\\s*lower-canvas\\s*/,\"\");this.upperCanvasEl=this._createCanvasElement(),fabric.util.addClass(this.upperCanvasEl,\"upper-canvas \"+a),this.wrapperEl.appendChild(this.upperCanvasEl),this._copyCanvasStyle(this.lowerCanvasEl,this.upperCanvasEl),this._applyCanvasStyle(this.upperCanvasEl),this.contextTop=this.upperCanvasEl.getContext(\"2d\")},_createCacheCanvas:function(){this.cacheCanvasEl=this._createCanvasElement(),this.cacheCanvasEl.setAttribute(\"width\",this.width),this.cacheCanvasEl.setAttribute(\"height\",this.height),this.contextCache=this.cacheCanvasEl.getContext(\"2d\")},_initWrapperElement:function(){this.wrapperEl=fabric.util.wrapElement(this.lowerCanvasEl,\"div\",{class:this.containerClass}),fabric.util.setStyle(this.wrapperEl,{width:this.getWidth()+\"px\",height:this.getHeight()+\"px\",position:\"relative\"}),fabric.util.makeElementUnselectable(this.wrapperEl)},_applyCanvasStyle:function(a){var b=this.getWidth()||a.width,c=this.getHeight()||a.height;fabric.util.setStyle(a,{position:\"absolute\",width:b+\"px\",height:c+\"px\",left:0,top:0}),a.width=b,a.height=c,fabric.util.makeElementUnselectable(a)},_copyCanvasStyle:function(a,b){b.style.cssText=a.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl},_setActiveObject:function(a){this._activeObject&&this._activeObject.set(\"active\",!1),this._activeObject=a,a.set(\"active\",!0)},setActiveObject:function(a,b){return this._setActiveObject(a),this.renderAll(),this.fire(\"object:selected\",{target:a,e:b}),a.fire(\"selected\",{e:b}),this},getActiveObject:function(){return this._activeObject},_discardActiveObject:function(){this._activeObject&&this._activeObject.set(\"active\",!1),this._activeObject=null},discardActiveObject:function(a){return this._discardActiveObject(),this.renderAll(),this.fire(\"selection:cleared\",{e:a}),this},_setActiveGroup:function(a){this._activeGroup=a,a&&a.set(\"active\",!0)},setActiveGroup:function(a,b){return this._setActiveGroup(a),a&&(this.fire(\"object:selected\",{target:a,e:b}),a.fire(\"selected\",{e:b})),this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var a=this.getActiveGroup();a&&a.destroy(),this.setActiveGroup(null)},discardActiveGroup:function(a){return this._discardActiveGroup(),this.fire(\"selection:cleared\",{e:a}),this},deactivateAll:function(){for(var a=this.getObjects(),b=0,c=a.length;b<c;b++)a[b].set(\"active\",!1);return this._discardActiveGroup(),this._discardActiveObject(),this},deactivateAllWithDispatch:function(a){var b=this.getActiveGroup()||this.getActiveObject();return b&&this.fire(\"before:selection:cleared\",{target:b,e:a}),this.deactivateAll(),b&&this.fire(\"selection:cleared\",{e:a}),this},drawControls:function(a){var b=this.getActiveGroup();b?this._drawGroupControls(a,b):this._drawObjectsControls(a)},_drawGroupControls:function(a,b){b._renderControls(a)},_drawObjectsControls:function(a){for(var b=0,c=this._objects.length;b<c;++b)this._objects[b]&&this._objects[b].active&&(this._objects[b]._renderControls(a),this.lastRenderedObjectWithControlsAboveOverlay=this._objects[b])}});for(var g in fabric.StaticCanvas)\"prototype\"!==g&&(fabric.Canvas[g]=fabric.StaticCanvas[g]);fabric.isTouchSupported&&(fabric.Canvas.prototype._setCursorFromEvent=function(){}),fabric.Element=fabric.Canvas}(),function(){var a={mt:0,tr:1,mr:2,br:3,mb:4,bl:5,ml:6,tl:7},b=fabric.util.addListener,c=fabric.util.removeListener;fabric.util.object.extend(fabric.Canvas.prototype,{cursorMap:[\"n-resize\",\"ne-resize\",\"e-resize\",\"se-resize\",\"s-resize\",\"sw-resize\",\"w-resize\",\"nw-resize\"],_initEventListeners:function(){this._bindEvents(),b(fabric.window,\"resize\",this._onResize),b(this.upperCanvasEl,\"mousedown\",this._onMouseDown),b(this.upperCanvasEl,\"mousemove\",this._onMouseMove),b(this.upperCanvasEl,\"mousewheel\",this._onMouseWheel),b(this.upperCanvasEl,\"touchstart\",this._onMouseDown),b(this.upperCanvasEl,\"touchmove\",this._onMouseMove),\"undefined\"!=typeof Event&&\"add\"in Event&&(Event.add(this.upperCanvasEl,\"gesture\",this._onGesture),Event.add(this.upperCanvasEl,\"drag\",this._onDrag),Event.add(this.upperCanvasEl,\"orientation\",this._onOrientationChange),Event.add(this.upperCanvasEl,\"shake\",this._onShake))},_bindEvents:function(){this._onMouseDown=this._onMouseDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseUp=this._onMouseUp.bind(this),this._onResize=this._onResize.bind(this),this._onGesture=this._onGesture.bind(this),this._onDrag=this._onDrag.bind(this),this._onShake=this._onShake.bind(this),this._onOrientationChange=this._onOrientationChange.bind(this),this._onMouseWheel=this._onMouseWheel.bind(this)},removeListeners:function(){c(fabric.window,\"resize\",this._onResize),c(this.upperCanvasEl,\"mousedown\",this._onMouseDown),c(this.upperCanvasEl,\"mousemove\",this._onMouseMove),c(this.upperCanvasEl,\"mousewheel\",this._onMouseWheel),c(this.upperCanvasEl,\"touchstart\",this._onMouseDown),c(this.upperCanvasEl,\"touchmove\",this._onMouseMove),\"undefined\"!=typeof Event&&\"remove\"in Event&&(Event.remove(this.upperCanvasEl,\"gesture\",this._onGesture),Event.remove(this.upperCanvasEl,\"drag\",this._onDrag),Event.remove(this.upperCanvasEl,\"orientation\",this._onOrientationChange),Event.remove(this.upperCanvasEl,\"shake\",this._onShake))},_onGesture:function(a,b){this.__onTransformGesture&&this.__onTransformGesture(a,b)},_onDrag:function(a,b){this.__onDrag&&this.__onDrag(a,b)},_onMouseWheel:function(a,b){this.__onMouseWheel&&this.__onMouseWheel(a,b)},_onOrientationChange:function(a,b){this.__onOrientationChange&&this.__onOrientationChange(a,b)},_onShake:function(a,b){this.__onShake&&this.__onShake(a,b)},_onMouseDown:function(a){this.__onMouseDown(a),b(fabric.document,\"touchend\",this._onMouseUp),b(fabric.document,\"touchmove\",this._onMouseMove),c(this.upperCanvasEl,\"mousemove\",this._onMouseMove),c(this.upperCanvasEl,\"touchmove\",this._onMouseMove),\"touchstart\"===a.type?c(this.upperCanvasEl,\"mousedown\",this._onMouseDown):(b(fabric.document,\"mouseup\",this._onMouseUp),b(fabric.document,\"mousemove\",this._onMouseMove))},_onMouseUp:function(a){if(this.__onMouseUp(a),c(fabric.document,\"mouseup\",this._onMouseUp),c(fabric.document,\"touchend\",this._onMouseUp),c(fabric.document,\"mousemove\",this._onMouseMove),c(fabric.document,\"touchmove\",this._onMouseMove),b(this.upperCanvasEl,\"mousemove\",this._onMouseMove),b(this.upperCanvasEl,\"touchmove\",this._onMouseMove),\"touchend\"===a.type){var d=this;setTimeout(function(){b(d.upperCanvasEl,\"mousedown\",d._onMouseDown)},400)}},_onMouseMove:function(a){!this.allowTouchScrolling&&a.preventDefault&&a.preventDefault(),this.__onMouseMove(a)},_onResize:function(){this.calcOffset()},_shouldRender:function(a,b){var c=this.getActiveGroup()||this.getActiveObject();return!!(a&&(a.isMoving||a!==c)||!a&&c||!a&&!c&&!this._groupSelector||b&&this._previousPointer&&this.selection&&(b.x!==this._previousPointer.x||b.y!==this._previousPointer.y))},__onMouseUp:function(a){var b;if(this.isDrawingMode&&this._isCurrentlyDrawing)return void this._onMouseUpInDrawingMode(a);this._currentTransform?(this._finalizeCurrentTransform(),b=this._currentTransform.target):b=this.findTarget(a,!0);var c=this._shouldRender(b,this.getPointer(a));this._maybeGroupObjects(a),b&&(b.isMoving=!1),c&&this.renderAll(),this._handleCursorAndEvent(a,b)},_handleCursorAndEvent:function(a,b){this._setCursorFromEvent(a,b);var c=this;setTimeout(function(){c._setCursorFromEvent(a,b)},50),this.fire(\"mouse:up\",{target:b,e:a}),b&&b.fire(\"mouseup\",{e:a})},_finalizeCurrentTransform:function(){var a=this._currentTransform,b=a.target;b._scaling&&(b._scaling=!1),b.setCoords(),this.stateful&&b.hasStateChanged()&&(this.fire(\"object:modified\",{target:b}),b.fire(\"modified\")),this._restoreOriginXY(b)},_restoreOriginXY:function(a){if(this._previousOriginX&&this._previousOriginY){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX,a.originY=this._previousOriginY,a.left=b.x,a.top=b.y,this._previousOriginX=null,this._previousOriginY=null}},_onMouseDownInDrawingMode:function(a){this._isCurrentlyDrawing=!0,this.discardActiveObject(a).renderAll(),this.clipTo&&fabric.util.clipContext(this,this.contextTop);var b=fabric.util.invertTransform(this.viewportTransform),c=fabric.util.transformPoint(this.getPointer(a,!0),b);this.freeDrawingBrush.onMouseDown(c),this.fire(\"mouse:down\",{e:a})},_onMouseMoveInDrawingMode:function(a){if(this._isCurrentlyDrawing){var b=fabric.util.invertTransform(this.viewportTransform),c=fabric.util.transformPoint(this.getPointer(a,!0),b);this.freeDrawingBrush.onMouseMove(c)}this.setCursor(this.freeDrawingCursor),this.fire(\"mouse:move\",{e:a})},_onMouseUpInDrawingMode:function(a){this._isCurrentlyDrawing=!1,this.clipTo&&this.contextTop.restore(),this.freeDrawingBrush.onMouseUp(),this.fire(\"mouse:up\",{e:a})},__onMouseDown:function(a){var b=\"which\"in a?1===a.which:1===a.button;if(b||fabric.isTouchSupported){if(this.isDrawingMode)return void this._onMouseDownInDrawingMode(a);if(!this._currentTransform){var c=this.findTarget(a),d=this.getPointer(a,!0);this._previousPointer=d;var e=this._shouldRender(c,d),f=this._shouldGroup(a,c);this._shouldClearSelection(a,c)?this._clearSelection(a,c,d):f&&(this._handleGrouping(a,c),c=this.getActiveGroup()),c&&c.selectable&&!f&&(this._beforeTransform(a,c),this._setupCurrentTransform(a,c)),e&&this.renderAll(),this.fire(\"mouse:down\",{target:c,e:a}),c&&c.fire(\"mousedown\",{e:a})}}},_beforeTransform:function(a,b){var c;this.stateful&&b.saveState(),(c=b._findTargetCorner(this.getPointer(a)))&&this.onBeforeScaleRotate(b),b!==this.getActiveGroup()&&b!==this.getActiveObject()&&(this.deactivateAll(),this.setActiveObject(b,a))},_clearSelection:function(a,b,c){this.deactivateAllWithDispatch(a),b&&b.selectable?this.setActiveObject(b,a):this.selection&&(this._groupSelector={ex:c.x,ey:c.y,top:0,left:0})},_setOriginToCenter:function(a){this._previousOriginX=this._currentTransform.target.originX,this._previousOriginY=this._currentTransform.target.originY;var b=a.getCenterPoint();a.originX=\"center\",a.originY=\"center\",a.left=b.x,a.top=b.y,this._currentTransform.left=a.left,this._currentTransform.top=a.top},_setCenterToOrigin:function(a){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX,a.originY=this._previousOriginY,a.left=b.x,a.top=b.y,this._previousOriginX=null,this._previousOriginY=null},__onMouseMove:function(a){var b,c;if(this.isDrawingMode)return void this._onMouseMoveInDrawingMode(a);var d=this._groupSelector;d?(c=this.getPointer(a,!0),d.left=c.x-d.ex,d.top=c.y-d.ey,this.renderTop()):this._currentTransform?this._transformObject(a):(b=this.findTarget(a),!b||b&&!b.selectable?this.setCursor(this.defaultCursor):this._setCursorFromEvent(a,b)),this.fire(\"mouse:move\",{target:b,e:a}),b&&b.fire(\"mousemove\",{e:a})},_transformObject:function(a){var b=this.getPointer(a),c=this._currentTransform;c.reset=!1,c.target.isMoving=!0,this._beforeScaleTransform(a,c),this._performTransformAction(a,c,b),this.renderAll()},_performTransformAction:function(a,b,c){var d=c.x,e=c.y,f=b.target,g=b.action;\"rotate\"===g?(this._rotateObject(d,e),this._fire(\"rotating\",f,a)):\"scale\"===g?(this._onScale(a,b,d,e),this._fire(\"scaling\",f,a)):\"scaleX\"===g?(this._scaleObject(d,e,\"x\"),this._fire(\"scaling\",f,a)):\"scaleY\"===g?(this._scaleObject(d,e,\"y\"),this._fire(\"scaling\",f,a)):(this._translateObject(d,e),this._fire(\"moving\",f,a),this.setCursor(this.moveCursor))},_fire:function(a,b,c){this.fire(\"object:\"+a,{target:b,e:c}),b.fire(a,{e:c})},_beforeScaleTransform:function(a,b){if(\"scale\"===b.action||\"scaleX\"===b.action||\"scaleY\"===b.action){var c=this._shouldCenterTransform(a,b.target);(c&&(\"center\"!==b.originX||\"center\"!==b.originY)||!c&&\"center\"===b.originX&&\"center\"===b.originY)&&(this._resetCurrentTransform(a),b.reset=!0)}},_onScale:function(a,b,c,d){!a.shiftKey&&!this.uniScaleTransform||b.target.get(\"lockUniScaling\")?(b.reset||\"scale\"!==b.currentAction||this._resetCurrentTransform(a,b.target),b.currentAction=\"scaleEqually\",this._scaleObject(c,d,\"equally\")):(b.currentAction=\"scale\",this._scaleObject(c,d))},_setCursorFromEvent:function(a,b){if(!b||!b.selectable)return this.setCursor(this.defaultCursor),!1;var c=this.getActiveGroup(),d=b._findTargetCorner&&(!c||!c.contains(b))&&b._findTargetCorner(this.getPointer(a,!0));return d?this._setCornerCursor(d,b):this.setCursor(b.hoverCursor||this.hoverCursor),!0},_setCornerCursor:function(b,c){if(b in a)this.setCursor(this._getRotatedCornerCursor(b,c));else{if(\"mtr\"!==b||!c.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(b,c){var d=Math.round(c.getAngle()%360/45);return d<0&&(d+=8),d+=a[b],d%=8,this.cursorMap[d]}})}(),function(){var a=Math.min,b=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(a,b){var c=this.getActiveObject();return a.shiftKey&&(this.getActiveGroup()||c&&c!==b)&&this.selection},_handleGrouping:function(a,b){b===this.getActiveGroup()&&(b=this.findTarget(a,!0),!b||b.isType(\"group\"))||(this.getActiveGroup()?this._updateActiveGroup(b,a):this._createActiveGroup(b,a),this._activeGroup&&this._activeGroup.saveCoords())},_updateActiveGroup:function(a,b){var c=this.getActiveGroup();if(c.contains(a)){if(c.removeWithUpdate(a),this._resetObjectTransform(c),a.set(\"active\",!1),1===c.size())return this.discardActiveGroup(b),void this.setActiveObject(c.item(0))}else c.addWithUpdate(a),this._resetObjectTransform(c);this.fire(\"selection:created\",{target:c,e:b}),c.set(\"active\",!0)},_createActiveGroup:function(a,b){if(this._activeObject&&a!==this._activeObject){var c=this._createGroup(a);c.addWithUpdate(),this.setActiveGroup(c),this._activeObject=null,this.fire(\"selection:created\",{target:c,e:b})}a.set(\"active\",!0)},_createGroup:function(a){var b=this.getObjects(),c=b.indexOf(this._activeObject)<b.indexOf(a),d=c?[this._activeObject,a]:[a,this._activeObject];return new fabric.Group(d,{originX:\"center\",originY:\"center\",canvas:this})},_groupSelectedObjects:function(a){var b=this._collectObjects();1===b.length?this.setActiveObject(b[0],a):b.length>1&&(b=new fabric.Group(b.reverse(),{originX:\"center\",\noriginY:\"center\",canvas:this}),b.addWithUpdate(),this.setActiveGroup(b,a),b.saveCoords(),this.fire(\"selection:created\",{target:b}),this.renderAll())},_collectObjects:function(){for(var d,c=[],e=this._groupSelector.ex,f=this._groupSelector.ey,g=e+this._groupSelector.left,h=f+this._groupSelector.top,i=new fabric.Point(a(e,g),a(f,h)),j=new fabric.Point(b(e,g),b(f,h)),k=e===g&&f===h,l=this._objects.length;l--&&(d=this._objects[l],!(d&&d.selectable&&d.visible&&(d.intersectsWithRect(i,j)||d.isContainedWithinRect(i,j)||d.containsPoint(i)||d.containsPoint(j))&&(d.set(\"active\",!0),c.push(d),k))););return c},_maybeGroupObjects:function(a){this.selection&&this._groupSelector&&this._groupSelectedObjects(a);var b=this.getActiveGroup();b&&(b.setObjectsCoords().setCoords(),b.isMoving=!1,this.setCursor(this.defaultCursor)),this._groupSelector=null,this._currentTransform=null}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(a){a||(a={});var b=a.format||\"png\",c=a.quality||1,d=a.multiplier||1,e={left:a.left,top:a.top,width:a.width,height:a.height};return 1!==d?this.__toDataURLWithMultiplier(b,c,e,d):this.__toDataURL(b,c,e)},__toDataURL:function(a,b,c){this.renderAll(!0);var d=this.upperCanvasEl||this.lowerCanvasEl,e=this.__getCroppedCanvas(d,c);\"jpg\"===a&&(a=\"jpeg\");var f=fabric.StaticCanvas.supports(\"toDataURLWithQuality\")?(e||d).toDataURL(\"image/\"+a,b):(e||d).toDataURL(\"image/\"+a);return this.contextTop&&this.clearContext(this.contextTop),this.renderAll(),e&&(e=null),f},__getCroppedCanvas:function(a,b){var c,d,e=\"left\"in b||\"top\"in b||\"width\"in b||\"height\"in b;return e&&(c=fabric.util.createCanvasElement(),d=c.getContext(\"2d\"),c.width=b.width||this.width,c.height=b.height||this.height,d.drawImage(a,-b.left||0,-b.top||0)),c},__toDataURLWithMultiplier:function(a,b,c,d){var e=this.getWidth(),f=this.getHeight(),g=e*d,h=f*d,i=this.getActiveObject(),j=this.getActiveGroup(),k=this.contextTop||this.contextContainer;d>1&&this.setWidth(g).setHeight(h),k.scale(d,d),c.left&&(c.left*=d),c.top&&(c.top*=d),c.width?c.width*=d:d<1&&(c.width=g),c.height?c.height*=d:d<1&&(c.height=h),j?this._tempRemoveBordersControlsFromGroup(j):i&&this.deactivateAll&&this.deactivateAll(),this.renderAll(!0);var l=this.__toDataURL(a,b,c);return this.width=e,this.height=f,k.scale(1/d,1/d),this.setWidth(e).setHeight(f),j?this._restoreBordersControlsOnGroup(j):i&&this.setActiveObject&&this.setActiveObject(i),this.contextTop&&this.clearContext(this.contextTop),this.renderAll(),l},toDataURLWithMultiplier:function(a,b,c){return this.toDataURL({format:a,multiplier:b,quality:c})},_tempRemoveBordersControlsFromGroup:function(a){a.origHasControls=a.hasControls,a.origBorderColor=a.borderColor,a.hasControls=!0,a.borderColor=\"rgba(0,0,0,0)\",a.forEachObject(function(a){a.origBorderColor=a.borderColor,a.borderColor=\"rgba(0,0,0,0)\"})},_restoreBordersControlsOnGroup:function(a){a.hideControls=a.origHideControls,a.borderColor=a.origBorderColor,a.forEachObject(function(a){a.borderColor=a.origBorderColor,delete a.origBorderColor})}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(a,b,c){return this.loadFromJSON(a,b,c)},loadFromJSON:function(a,b,c){if(a){var d=\"string\"==typeof a?JSON.parse(a):a;this.clear();var e=this;return this._enlivenObjects(d.objects,function(){e._setBgOverlay(d,b)},c),this}},_setBgOverlay:function(a,b){var c=this,d={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(!(a.backgroundImage||a.overlayImage||a.background||a.overlay))return void(b&&b());var e=function(){d.backgroundImage&&d.overlayImage&&d.backgroundColor&&d.overlayColor&&(c.renderAll(),b&&b())};this.__setBgOverlay(\"backgroundImage\",a.backgroundImage,d,e),this.__setBgOverlay(\"overlayImage\",a.overlayImage,d,e),this.__setBgOverlay(\"backgroundColor\",a.background,d,e),this.__setBgOverlay(\"overlayColor\",a.overlay,d,e),e()},__setBgOverlay:function(a,b,c,d){var e=this;return b?void(\"backgroundImage\"===a||\"overlayImage\"===a?fabric.Image.fromObject(b,function(b){e[a]=b,c[a]=!0,d&&d()}):this[\"set\"+fabric.util.string.capitalize(a,!0)](b,function(){c[a]=!0,d&&d()})):void(c[a]=!0)},_enlivenObjects:function(a,b,c){var d=this;if(!a||0===a.length)return void(b&&b());var e=this.renderOnAddRemove;this.renderOnAddRemove=!1,fabric.util.enlivenObjects(a,function(a){a.forEach(function(a,b){d.insertAt(a,b,!0)}),d.renderOnAddRemove=e,b&&b()},null,c)},_toDataURL:function(a,b){this.clone(function(c){b(c.toDataURL(a))})},_toDataURLWithMultiplier:function(a,b,c){this.clone(function(d){c(d.toDataURLWithMultiplier(a,b))})},clone:function(a,b){var c=JSON.stringify(this.toJSON(b));this.cloneWithoutData(function(b){b.loadFromJSON(c,function(){a&&a(b)})})},cloneWithoutData:function(a){var b=fabric.document.createElement(\"canvas\");b.width=this.getWidth(),b.height=this.getHeight();var c=new fabric.Canvas(b);c.clipTo=this.clipTo,this.backgroundImage?(c.setBackgroundImage(this.backgroundImage.src,function(){c.renderAll(),a&&a(c)}),c.backgroundImageOpacity=this.backgroundImageOpacity,c.backgroundImageStretch=this.backgroundImageStretch):a&&a(c)}}),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d=b.util.toFixed,e=b.util.string.capitalize,f=b.util.degreesToRadians,g=b.StaticCanvas.supports(\"setLineDash\");b.Object||(b.Object=b.util.createClass({type:\"object\",originX:\"left\",originY:\"top\",top:0,left:0,width:0,height:0,scaleX:1,scaleY:1,flipX:!1,flipY:!1,opacity:1,angle:0,cornerSize:12,transparentCorners:!0,hoverCursor:null,padding:0,borderColor:\"rgba(102,153,255,0.75)\",cornerColor:\"rgba(102,153,255,0.5)\",centeredScaling:!1,centeredRotation:!0,fill:\"rgb(0,0,0)\",fillRule:\"nonzero\",globalCompositeOperation:\"source-over\",backgroundColor:\"\",stroke:null,strokeWidth:1,strokeDashArray:null,strokeLineCap:\"butt\",strokeLineJoin:\"miter\",strokeMiterLimit:10,shadow:null,borderOpacityWhenMoving:.4,borderScaleFactor:1,transformMatrix:null,minScaleLimit:.01,selectable:!0,evented:!0,visible:!0,hasControls:!0,hasBorders:!0,hasRotatingPoint:!0,rotatingPointOffset:40,perPixelTargetFind:!1,includeDefaultValues:!0,clipTo:null,lockMovementX:!1,lockMovementY:!1,lockRotation:!1,lockScalingX:!1,lockScalingY:!1,lockUniScaling:!1,lockScalingFlip:!1,stateProperties:\"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor\".split(\" \"),initialize:function(a){a&&this.setOptions(a)},_initGradient:function(a){!a.fill||!a.fill.colorStops||a.fill instanceof b.Gradient||this.set(\"fill\",new b.Gradient(a.fill))},_initPattern:function(a){!a.fill||!a.fill.source||a.fill instanceof b.Pattern||this.set(\"fill\",new b.Pattern(a.fill)),!a.stroke||!a.stroke.source||a.stroke instanceof b.Pattern||this.set(\"stroke\",new b.Pattern(a.stroke))},_initClipping:function(a){if(a.clipTo&&\"string\"==typeof a.clipTo){var c=b.util.getFunctionBody(a.clipTo);\"undefined\"!=typeof c&&(this.clipTo=new Function(\"ctx\",c))}},setOptions:function(a){for(var b in a)this.set(b,a[b]);this._initGradient(a),this._initPattern(a),this._initClipping(a)},transform:function(a,b){this.group&&this.group.transform(a,b);var c=b?this._getLeftTopCoords():this.getCenterPoint();a.translate(c.x,c.y),a.rotate(f(this.angle)),a.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1))},toObject:function(a){var c=b.Object.NUM_FRACTION_DIGITS,e={type:this.type,originX:this.originX,originY:this.originY,left:d(this.left,c),top:d(this.top,c),width:d(this.width,c),height:d(this.height,c),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject?this.stroke.toObject():this.stroke,strokeWidth:d(this.strokeWidth,c),strokeDashArray:this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:d(this.strokeMiterLimit,c),scaleX:d(this.scaleX,c),scaleY:d(this.scaleY,c),angle:d(this.getAngle(),c),flipX:this.flipX,flipY:this.flipY,opacity:d(this.opacity,c),shadow:this.shadow&&this.shadow.toObject?this.shadow.toObject():this.shadow,visible:this.visible,clipTo:this.clipTo&&String(this.clipTo),backgroundColor:this.backgroundColor,fillRule:this.fillRule,globalCompositeOperation:this.globalCompositeOperation};return this.includeDefaultValues||(e=this._removeDefaultValues(e)),b.util.populateWithProperties(this,e,a),e},toDatalessObject:function(a){return this.toObject(a)},_removeDefaultValues:function(a){var c=b.util.getKlass(a.type).prototype,d=c.stateProperties;return d.forEach(function(b){a[b]===c[b]&&delete a[b]}),a},toString:function(){return\"#<fabric.\"+e(this.type)+\">\"},get:function(a){return this[a]},_setObject:function(a){for(var b in a)this._set(b,a[b])},set:function(a,b){return\"object\"==typeof a?this._setObject(a):\"function\"==typeof b&&\"clipTo\"!==a?this._set(a,b(this.get(a))):this._set(a,b),this},_set:function(a,c){var e=\"scaleX\"===a||\"scaleY\"===a;return e&&(c=this._constrainScale(c)),\"scaleX\"===a&&c<0?(this.flipX=!this.flipX,c*=-1):\"scaleY\"===a&&c<0?(this.flipY=!this.flipY,c*=-1):\"width\"===a||\"height\"===a?this.minScaleLimit=d(Math.min(.1,1/Math.max(this.width,this.height)),2):\"shadow\"!==a||!c||c instanceof b.Shadow||(c=new b.Shadow(c)),this[a]=c,this},toggle:function(a){var b=this.get(a);return\"boolean\"==typeof b&&this.set(a,!b),this},setSourcePath:function(a){return this.sourcePath=a,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:[1,0,0,1,0,0]},render:function(a,c){0!==this.width&&0!==this.height&&this.visible&&(a.save(),this._setupCompositeOperation(a),c||this.transform(a),this._setStrokeStyles(a),this._setFillStyles(a),this.group&&\"path-group\"===this.group.type&&a.translate(-this.group.width/2,-this.group.height/2),this.transformMatrix&&a.transform.apply(a,this.transformMatrix),this._setOpacity(a),this._setShadow(a),this.clipTo&&b.util.clipContext(this,a),this._render(a,c),this.clipTo&&a.restore(),this._removeShadow(a),this._restoreCompositeOperation(a),a.restore())},_setOpacity:function(a){this.group&&this.group._setOpacity(a),a.globalAlpha*=this.opacity},_setStrokeStyles:function(a){this.stroke&&(a.lineWidth=this.strokeWidth,a.lineCap=this.strokeLineCap,a.lineJoin=this.strokeLineJoin,a.miterLimit=this.strokeMiterLimit,a.strokeStyle=this.stroke.toLive?this.stroke.toLive(a,this):this.stroke)},_setFillStyles:function(a){this.fill&&(a.fillStyle=this.fill.toLive?this.fill.toLive(a,this):this.fill)},_renderControls:function(a,c){var d=this.getViewportTransform();if(a.save(),this.active&&!c){var e;this.group&&(e=b.util.transformPoint(this.group.getCenterPoint(),d),a.translate(e.x,e.y),a.rotate(f(this.group.angle))),e=b.util.transformPoint(this.getCenterPoint(),d,null!=this.group),this.group&&(e.x*=this.group.scaleX,e.y*=this.group.scaleY),a.translate(e.x,e.y),a.rotate(f(this.angle)),this.drawBorders(a),this.drawControls(a)}a.restore()},_setShadow:function(a){this.shadow&&(a.shadowColor=this.shadow.color,a.shadowBlur=this.shadow.blur,a.shadowOffsetX=this.shadow.offsetX,a.shadowOffsetY=this.shadow.offsetY)},_removeShadow:function(a){this.shadow&&(a.shadowColor=\"\",a.shadowBlur=a.shadowOffsetX=a.shadowOffsetY=0)},_renderFill:function(a){if(this.fill){if(a.save(),this.fill.gradientTransform){var b=this.fill.gradientTransform;a.transform.apply(a,b)}this.fill.toLive&&a.translate(-this.width/2+this.fill.offsetX||0,-this.height/2+this.fill.offsetY||0),\"evenodd\"===this.fillRule?a.fill(\"evenodd\"):a.fill(),a.restore(),this.shadow&&!this.shadow.affectStroke&&this._removeShadow(a)}},_renderStroke:function(a){if(this.stroke&&0!==this.strokeWidth){if(a.save(),this.strokeDashArray)1&this.strokeDashArray.length&&this.strokeDashArray.push.apply(this.strokeDashArray,this.strokeDashArray),g?(a.setLineDash(this.strokeDashArray),this._stroke&&this._stroke(a)):this._renderDashedStroke&&this._renderDashedStroke(a),a.stroke();else{if(this.stroke.gradientTransform){var b=this.stroke.gradientTransform;a.transform.apply(a,b)}this._stroke?this._stroke(a):a.stroke()}this._removeShadow(a),a.restore()}},clone:function(a,c){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(c),a):new b.Object(this.toObject(c))},cloneAsImage:function(a){var c=this.toDataURL();return b.util.loadImage(c,function(c){a&&a(new b.Image(c))}),this},toDataURL:function(a){a||(a={});var c=b.util.createCanvasElement(),d=this.getBoundingRect();c.width=d.width,c.height=d.height,b.util.wrapElement(c,\"div\");var e=new b.Canvas(c);\"jpg\"===a.format&&(a.format=\"jpeg\"),\"jpeg\"===a.format&&(e.backgroundColor=\"#fff\");var f={active:this.get(\"active\"),left:this.getLeft(),top:this.getTop()};this.set(\"active\",!1),this.setPositionByOrigin(new b.Point(c.width/2,c.height/2),\"center\",\"center\");var g=this.canvas;e.add(this);var h=e.toDataURL(a);return this.set(f).setCoords(),this.canvas=g,e.dispose(),e=null,h},isType:function(a){return this.type===a},complexity:function(){return 0},toJSON:function(a){return this.toObject(a)},setGradient:function(a,c){c||(c={});var d={colorStops:[]};d.type=c.type||(c.r1||c.r2?\"radial\":\"linear\"),d.coords={x1:c.x1,y1:c.y1,x2:c.x2,y2:c.y2},(c.r1||c.r2)&&(d.coords.r1=c.r1,d.coords.r2=c.r2);for(var e in c.colorStops){var f=new b.Color(c.colorStops[e]);d.colorStops.push({offset:e,color:f.toRgb(),opacity:f.getAlpha()})}return this.set(a,b.Gradient.forObject(this,d))},setPatternFill:function(a){return this.set(\"fill\",new b.Pattern(a))},setShadow:function(a){return this.set(\"shadow\",a?new b.Shadow(a):null)},setColor:function(a){return this.set(\"fill\",a),this},setAngle:function(a){var b=(\"center\"!==this.originX||\"center\"!==this.originY)&&this.centeredRotation;return b&&this._setOriginToCenter(),this.set(\"angle\",a),b&&this._resetOrigin(),this},centerH:function(){return this.canvas.centerObjectH(this),this},centerV:function(){return this.canvas.centerObjectV(this),this},center:function(){return this.canvas.centerObject(this),this},remove:function(){return this.canvas.remove(this),this},getLocalPointer:function(a,b){b=b||this.canvas.getPointer(a);var c=this.translateToOriginPoint(this.getCenterPoint(),\"left\",\"top\");return{x:b.x-c.x,y:b.y-c.y}},_setupCompositeOperation:function(a){this.globalCompositeOperation&&(this._prevGlobalCompositeOperation=a.globalCompositeOperation,a.globalCompositeOperation=this.globalCompositeOperation)},_restoreCompositeOperation:function(a){this.globalCompositeOperation&&this._prevGlobalCompositeOperation&&(a.globalCompositeOperation=this._prevGlobalCompositeOperation)}}),b.util.createAccessors(b.Object),b.Object.prototype.rotate=b.Object.prototype.setAngle,c(b.Object.prototype,b.Observable),b.Object.NUM_FRACTION_DIGITS=2,b.Object.__uid=0)}(\"undefined\"!=typeof exports?exports:this),function(){var a=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{translateToCenterPoint:function(b,c,d){var e=b.x,f=b.y,g=this.stroke?this.strokeWidth:0;return\"left\"===c?e=b.x+(this.getWidth()+g*this.scaleX)/2:\"right\"===c&&(e=b.x-(this.getWidth()+g*this.scaleX)/2),\"top\"===d?f=b.y+(this.getHeight()+g*this.scaleY)/2:\"bottom\"===d&&(f=b.y-(this.getHeight()+g*this.scaleY)/2),fabric.util.rotatePoint(new fabric.Point(e,f),b,a(this.angle))},translateToOriginPoint:function(b,c,d){var e=b.x,f=b.y,g=this.stroke?this.strokeWidth:0;return\"left\"===c?e=b.x-(this.getWidth()+g*this.scaleX)/2:\"right\"===c&&(e=b.x+(this.getWidth()+g*this.scaleX)/2),\"top\"===d?f=b.y-(this.getHeight()+g*this.scaleY)/2:\"bottom\"===d&&(f=b.y+(this.getHeight()+g*this.scaleY)/2),fabric.util.rotatePoint(new fabric.Point(e,f),b,a(this.angle))},getCenterPoint:function(){var a=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(a,this.originX,this.originY)},getPointByOrigin:function(a,b){var c=this.getCenterPoint();return this.translateToOriginPoint(c,a,b)},toLocalPoint:function(b,c,d){var g,h,e=this.getCenterPoint(),f=this.stroke?this.strokeWidth:0;return c&&d?(g=\"left\"===c?e.x-(this.getWidth()+f*this.scaleX)/2:\"right\"===c?e.x+(this.getWidth()+f*this.scaleX)/2:e.x,h=\"top\"===d?e.y-(this.getHeight()+f*this.scaleY)/2:\"bottom\"===d?e.y+(this.getHeight()+f*this.scaleY)/2:e.y):(g=this.left,h=this.top),fabric.util.rotatePoint(new fabric.Point(b.x,b.y),e,-a(this.angle)).subtractEquals(new fabric.Point(g,h))},setPositionByOrigin:function(a,b,c){var d=this.translateToCenterPoint(a,b,c),e=this.translateToOriginPoint(d,this.originX,this.originY);this.set(\"left\",e.x),this.set(\"top\",e.y)},adjustPosition:function(b){var c=a(this.angle),d=this.getWidth()/2,e=Math.cos(c)*d,f=Math.sin(c)*d,g=this.getWidth(),h=Math.cos(c)*g,i=Math.sin(c)*g;\"center\"===this.originX&&\"left\"===b||\"right\"===this.originX&&\"center\"===b?(this.left-=e,this.top-=f):\"left\"===this.originX&&\"center\"===b||\"center\"===this.originX&&\"right\"===b?(this.left+=e,this.top+=f):\"left\"===this.originX&&\"right\"===b?(this.left+=h,this.top+=i):\"right\"===this.originX&&\"left\"===b&&(this.left-=h,this.top-=i),this.setCoords(),this.originX=b},_setOriginToCenter:function(){this._originalOriginX=this.originX,this._originalOriginY=this.originY;var a=this.getCenterPoint();this.originX=\"center\",this.originY=\"center\",this.left=a.x,this.top=a.y},_resetOrigin:function(){var a=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX,this._originalOriginY);this.originX=this._originalOriginX,this.originY=this._originalOriginY,this.left=a.x,this.top=a.y,this._originalOriginX=null,this._originalOriginY=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),\"left\",\"center\")}})}(),function(){var a=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,intersectsWithRect:function(a,b){var c=this.oCoords,d=new fabric.Point(c.tl.x,c.tl.y),e=new fabric.Point(c.tr.x,c.tr.y),f=new fabric.Point(c.bl.x,c.bl.y),g=new fabric.Point(c.br.x,c.br.y),h=fabric.Intersection.intersectPolygonRectangle([d,e,g,f],a,b);return\"Intersection\"===h.status},intersectsWithObject:function(a){function b(a){return{tl:new fabric.Point(a.tl.x,a.tl.y),tr:new fabric.Point(a.tr.x,a.tr.y),bl:new fabric.Point(a.bl.x,a.bl.y),br:new fabric.Point(a.br.x,a.br.y)}}var c=b(this.oCoords),d=b(a.oCoords),e=fabric.Intersection.intersectPolygonPolygon([c.tl,c.tr,c.br,c.bl],[d.tl,d.tr,d.br,d.bl]);return\"Intersection\"===e.status},isContainedWithinObject:function(a){var b=a.getBoundingRect(),c=new fabric.Point(b.left,b.top),d=new fabric.Point(b.left+b.width,b.top+b.height);return this.isContainedWithinRect(c,d)},isContainedWithinRect:function(a,b){var c=this.getBoundingRect();return c.left>=a.x&&c.left+c.width<=b.x&&c.top>=a.y&&c.top+c.height<=b.y},containsPoint:function(a){var b=this._getImageLines(this.oCoords),c=this._findCrossPoints(a,b);return 0!==c&&c%2===1},_getImageLines:function(a){return{topline:{o:a.tl,d:a.tr},rightline:{o:a.tr,d:a.br},bottomline:{o:a.br,d:a.bl},leftline:{o:a.bl,d:a.tl}}},_findCrossPoints:function(a,b){var c,d,e,f,g,h,j,i=0;for(var k in b)if(j=b[k],!(j.o.y<a.y&&j.d.y<a.y||j.o.y>=a.y&&j.d.y>=a.y||(j.o.x===j.d.x&&j.o.x>=a.x?(g=j.o.x,h=a.y):(c=0,d=(j.d.y-j.o.y)/(j.d.x-j.o.x),e=a.y-c*a.x,f=j.o.y-d*j.o.x,g=-(e-f)/(c-d),h=e+c*g),g>=a.x&&(i+=1),2!==i)))break;return i},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(){this.oCoords||this.setCoords();var a=[this.oCoords.tl.x,this.oCoords.tr.x,this.oCoords.br.x,this.oCoords.bl.x],b=fabric.util.array.min(a),c=fabric.util.array.max(a),d=Math.abs(b-c),e=[this.oCoords.tl.y,this.oCoords.tr.y,this.oCoords.br.y,this.oCoords.bl.y],f=fabric.util.array.min(e),g=fabric.util.array.max(e),h=Math.abs(f-g);return{left:b,top:f,width:d,height:h}},getWidth:function(){return this.width*this.scaleX},getHeight:function(){return this.height*this.scaleY},_constrainScale:function(a){return Math.abs(a)<this.minScaleLimit?a<0?-this.minScaleLimit:this.minScaleLimit:a},scale:function(a){return a=this._constrainScale(a),a<0&&(this.flipX=!this.flipX,this.flipY=!this.flipY,a*=-1),this.scaleX=a,this.scaleY=a,this.setCoords(),this},scaleToWidth:function(a){var b=this.getBoundingRectWidth()/this.getWidth();return this.scale(a/this.width/b)},scaleToHeight:function(a){var b=this.getBoundingRectHeight()/this.getHeight();return this.scale(a/this.height/b)},setCoords:function(){var b=this.strokeWidth>1?this.strokeWidth:0,c=a(this.angle),d=this.getViewportTransform(),e=function(a){return fabric.util.transformPoint(a,d)},f=this.width,g=this.height,h=\"round\"===this.strokeLineCap||\"square\"===this.strokeLineCap,i=\"line\"===this.type&&1===this.width,j=\"line\"===this.type&&1===this.height,k=h&&j||\"line\"!==this.type,l=h&&i||\"line\"!==this.type;i?f=b:j&&(g=b),k&&(f+=b),l&&(g+=b),this.currentWidth=f*this.scaleX,this.currentHeight=g*this.scaleY,this.currentWidth<0&&(this.currentWidth=Math.abs(this.currentWidth));var m=Math.sqrt(Math.pow(this.currentWidth/2,2)+Math.pow(this.currentHeight/2,2)),n=Math.atan(isFinite(this.currentHeight/this.currentWidth)?this.currentHeight/this.currentWidth:0),o=Math.cos(n+c)*m,p=Math.sin(n+c)*m,q=Math.sin(c),r=Math.cos(c),s=this.getCenterPoint(),t=new fabric.Point(this.currentWidth,this.currentHeight),u=new fabric.Point(s.x-o,s.y-p),v=new fabric.Point(u.x+t.x*r,u.y+t.x*q),w=new fabric.Point(u.x-t.y*q,u.y+t.y*r),x=new fabric.Point(u.x+t.x/2*r,u.y+t.x/2*q),y=e(u),z=e(v),A=e(new fabric.Point(v.x-t.y*q,v.y+t.y*r)),B=e(w),C=e(new fabric.Point(u.x-t.y/2*q,u.y+t.y/2*r)),D=e(x),E=e(new fabric.Point(v.x-t.y/2*q,v.y+t.y/2*r)),F=e(new fabric.Point(w.x+t.x/2*r,w.y+t.x/2*q)),G=e(new fabric.Point(x.x,x.y)),H=Math.cos(n+c)*this.padding*Math.sqrt(2),I=Math.sin(n+c)*this.padding*Math.sqrt(2);return y=y.add(new fabric.Point(-H,-I)),z=z.add(new fabric.Point(I,-H)),A=A.add(new fabric.Point(H,I)),B=B.add(new fabric.Point(-I,H)),C=C.add(new fabric.Point((-H-I)/2,(-I+H)/2)),D=D.add(new fabric.Point((I-H)/2,-(I+H)/2)),E=E.add(new fabric.Point((I+H)/2,(I-H)/2)),F=F.add(new fabric.Point((H-I)/2,(H+I)/2)),G=G.add(new fabric.Point((I-H)/2,-(I+H)/2)),this.oCoords={tl:y,tr:z,br:A,bl:B,ml:C,mt:D,mr:E,mb:F,mtr:G},this._setCornerCoords&&this._setCornerCoords(),this}})}(),fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){return this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this),this},bringToFront:function(){return this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this),this},sendBackwards:function(a){return this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,a):this.canvas.sendBackwards(this,a),this},bringForward:function(a){return this.group?fabric.StaticCanvas.prototype.bringForward.call(this.group,this,a):this.canvas.bringForward(this,a),this},moveTo:function(a){return this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,a):this.canvas.moveTo(this,a),this}}),fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(){var a=this.fill?this.fill.toLive?\"url(#SVGID_\"+this.fill.id+\")\":this.fill:\"none\",b=this.fillRule,c=this.stroke?this.stroke.toLive?\"url(#SVGID_\"+this.stroke.id+\")\":this.stroke:\"none\",d=this.strokeWidth?this.strokeWidth:\"0\",e=this.strokeDashArray?this.strokeDashArray.join(\" \"):\"\",f=this.strokeLineCap?this.strokeLineCap:\"butt\",g=this.strokeLineJoin?this.strokeLineJoin:\"miter\",h=this.strokeMiterLimit?this.strokeMiterLimit:\"4\",i=\"undefined\"!=typeof this.opacity?this.opacity:\"1\",j=this.visible?\"\":\" visibility: hidden;\",k=this.shadow&&\"text\"!==this.type?\"filter: url(#SVGID_\"+this.shadow.id+\");\":\"\";return[\"stroke: \",c,\"; \",\"stroke-width: \",d,\"; \",\"stroke-dasharray: \",e,\"; \",\"stroke-linecap: \",f,\"; \",\"stroke-linejoin: \",g,\"; \",\"stroke-miterlimit: \",h,\"; \",\"fill: \",a,\"; \",\"fill-rule: \",b,\"; \",\"opacity: \",i,\";\",k,j].join(\"\")},getSvgTransform:function(){if(this.group&&\"path-group\"===this.group.type)return\"\";var a=fabric.util.toFixed,b=this.getAngle(),c=!this.canvas||this.canvas.svgViewportTransformation?this.getViewportTransform():[1,0,0,1,0,0],d=fabric.util.transformPoint(this.getCenterPoint(),c),e=fabric.Object.NUM_FRACTION_DIGITS,f=\"path-group\"===this.type?\"\":\"translate(\"+a(d.x,e)+\" \"+a(d.y,e)+\")\",g=0!==b?\" rotate(\"+a(b,e)+\")\":\"\",h=1===this.scaleX&&1===this.scaleY&&1===c[0]&&1===c[3]?\"\":\" scale(\"+a(this.scaleX*c[0],e)+\" \"+a(this.scaleY*c[3],e)+\")\",i=\"path-group\"===this.type?this.width*c[0]:0,j=this.flipX?\" matrix(-1 0 0 1 \"+i+\" 0) \":\"\",k=\"path-group\"===this.type?this.height*c[3]:0,l=this.flipY?\" matrix(1 0 0 -1 0 \"+k+\")\":\"\";return[f,g,h,j,l].join(\"\")},getSvgTransformMatrix:function(){return this.transformMatrix?\" matrix(\"+this.transformMatrix.join(\" \")+\")\":\"\"},_createBaseSVGMarkup:function(){var a=[];return this.fill&&this.fill.toLive&&a.push(this.fill.toSVG(this,!1)),this.stroke&&this.stroke.toLive&&a.push(this.stroke.toSVG(this,!1)),this.shadow&&a.push(this.shadow.toSVG(this)),a}}),fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(){return this.stateProperties.some(function(a){return this.get(a)!==this.originalState[a]},this)},saveState:function(a){return this.stateProperties.forEach(function(a){this.originalState[a]=this.get(a)},this),a&&a.stateProperties&&a.stateProperties.forEach(function(a){this.originalState[a]=this.get(a)},this),this},setupState:function(){return this.originalState={},this.saveState(),this}}),function(){var a=fabric.util.degreesToRadians,b=function(){return\"undefined\"!=typeof G_vmlCanvasManager};fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(a){if(!this.hasControls||!this.active)return!1;var d,e,b=a.x,c=a.y;for(var f in this.oCoords)if(this.isControlVisible(f)&&(\"mtr\"!==f||this.hasRotatingPoint)&&(!this.get(\"lockUniScaling\")||\"mt\"!==f&&\"mr\"!==f&&\"mb\"!==f&&\"ml\"!==f)&&(e=this._getImageLines(this.oCoords[f].corner),d=this._findCrossPoints({x:b,y:c},e),0!==d&&d%2===1))return this.__corner=f,f;return!1},_setCornerCoords:function(){var b=this.oCoords,c=a(this.angle),d=a(45-this.angle),e=Math.sqrt(2*Math.pow(this.cornerSize,2))/2,f=e*Math.cos(d),g=e*Math.sin(d),h=Math.sin(c),i=Math.cos(c);b.tl.corner={tl:{x:b.tl.x-g,y:b.tl.y-f},tr:{x:b.tl.x+f,y:b.tl.y-g},bl:{x:b.tl.x-f,y:b.tl.y+g},br:{x:b.tl.x+g,y:b.tl.y+f}},b.tr.corner={tl:{x:b.tr.x-g,y:b.tr.y-f},tr:{x:b.tr.x+f,y:b.tr.y-g},br:{x:b.tr.x+g,y:b.tr.y+f},bl:{x:b.tr.x-f,y:b.tr.y+g}},b.bl.corner={tl:{x:b.bl.x-g,y:b.bl.y-f},bl:{x:b.bl.x-f,y:b.bl.y+g},br:{x:b.bl.x+g,y:b.bl.y+f},tr:{x:b.bl.x+f,y:b.bl.y-g}},b.br.corner={tr:{x:b.br.x+f,y:b.br.y-g},bl:{x:b.br.x-f,y:b.br.y+g},br:{x:b.br.x+g,y:b.br.y+f},tl:{x:b.br.x-g,y:b.br.y-f}},b.ml.corner={tl:{x:b.ml.x-g,y:b.ml.y-f},tr:{x:b.ml.x+f,y:b.ml.y-g},bl:{x:b.ml.x-f,y:b.ml.y+g},br:{x:b.ml.x+g,y:b.ml.y+f}},b.mt.corner={tl:{x:b.mt.x-g,y:b.mt.y-f},tr:{x:b.mt.x+f,y:b.mt.y-g},bl:{x:b.mt.x-f,y:b.mt.y+g},br:{x:b.mt.x+g,y:b.mt.y+f}},b.mr.corner={tl:{x:b.mr.x-g,y:b.mr.y-f},tr:{x:b.mr.x+f,y:b.mr.y-g},bl:{x:b.mr.x-f,y:b.mr.y+g},br:{x:b.mr.x+g,y:b.mr.y+f}},b.mb.corner={tl:{x:b.mb.x-g,y:b.mb.y-f},tr:{x:b.mb.x+f,y:b.mb.y-g},bl:{x:b.mb.x-f,y:b.mb.y+g},br:{x:b.mb.x+g,y:b.mb.y+f}},b.mtr.corner={tl:{x:b.mtr.x-g+h*this.rotatingPointOffset,y:b.mtr.y-f-i*this.rotatingPointOffset},tr:{x:b.mtr.x+f+h*this.rotatingPointOffset,y:b.mtr.y-g-i*this.rotatingPointOffset},bl:{x:b.mtr.x-f+h*this.rotatingPointOffset,y:b.mtr.y+g-i*this.rotatingPointOffset},br:{x:b.mtr.x+g+h*this.rotatingPointOffset,y:b.mtr.y+f-i*this.rotatingPointOffset}}},drawBorders:function(a){if(!this.hasBorders)return this;var b=this.padding,c=2*b,d=this.getViewportTransform();a.save(),a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,a.strokeStyle=this.borderColor;var e=1/this._constrainScale(this.scaleX),f=1/this._constrainScale(this.scaleY);a.lineWidth=1/this.borderScaleFactor;var g=this.getWidth(),h=this.getHeight(),i=this.strokeWidth>1?this.strokeWidth:0,j=\"round\"===this.strokeLineCap||\"square\"===this.strokeLineCap,k=\"line\"===this.type&&1===this.width,l=\"line\"===this.type&&1===this.height,m=j&&l||\"line\"!==this.type,n=j&&k||\"line\"!==this.type;k?g=i/e:l&&(h=i/f),m&&(g+=i/e),n&&(h+=i/f);var o=fabric.util.transformPoint(new fabric.Point(g,h),d,!0),p=o.x,q=o.y;if(this.group&&(p*=this.group.scaleX,q*=this.group.scaleY),a.strokeRect(~~(-(p/2)-b)-.5,~~(-(q/2)-b)-.5,~~(p+c)+1,~~(q+c)+1),this.hasRotatingPoint&&this.isControlVisible(\"mtr\")&&!this.get(\"lockRotation\")&&this.hasControls){var r=(-q-2*b)/2;a.beginPath(),a.moveTo(0,r),a.lineTo(0,r-this.rotatingPointOffset),a.closePath(),a.stroke()}return a.restore(),this},drawControls:function(a){if(!this.hasControls)return this;var b=this.cornerSize,c=b/2,d=this.getViewportTransform(),e=this.strokeWidth>1?this.strokeWidth:0,f=this.width,g=this.height,h=\"round\"===this.strokeLineCap||\"square\"===this.strokeLineCap,i=\"line\"===this.type&&1===this.width,j=\"line\"===this.type&&1===this.height,k=h&&j||\"line\"!==this.type,l=h&&i||\"line\"!==this.type;i?f=e:j&&(g=e),k&&(f+=e),l&&(g+=e),f*=this.scaleX,g*=this.scaleY;var m=fabric.util.transformPoint(new fabric.Point(f,g),d,!0),n=m.x,o=m.y,p=-(n/2),q=-(o/2),r=this.padding,s=c,t=c-b,u=this.transparentCorners?\"strokeRect\":\"fillRect\";return a.save(),a.lineWidth=1,a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,a.strokeStyle=a.fillStyle=this.cornerColor,this._drawControl(\"tl\",a,u,p-s-r,q-s-r),this._drawControl(\"tr\",a,u,p+n-s+r,q-s-r),this._drawControl(\"bl\",a,u,p-s-r,q+o+t+r),this._drawControl(\"br\",a,u,p+n+t+r,q+o+t+r),this.get(\"lockUniScaling\")||(this._drawControl(\"mt\",a,u,p+n/2-s,q-s-r),this._drawControl(\"mb\",a,u,p+n/2-s,q+o+t+r),this._drawControl(\"mr\",a,u,p+n+t+r,q+o/2-s),this._drawControl(\"ml\",a,u,p-s-r,q+o/2-s)),this.hasRotatingPoint&&this._drawControl(\"mtr\",a,u,p+n/2-s,q-this.rotatingPointOffset-this.cornerSize/2-r),a.restore(),this},_drawControl:function(a,c,d,e,f){var g=this.cornerSize;this.isControlVisible(a)&&(b()||this.transparentCorners||c.clearRect(e,f,g,g),c[d](e,f,g,g))},isControlVisible:function(a){return this._getControlsVisibility()[a]},setControlVisible:function(a,b){return this._getControlsVisibility()[a]=b,this},setControlsVisibility:function(a){a||(a={});for(var b in a)this.setControlVisible(b,a[b]);return this},_getControlsVisibility:function(){return this._controlsVisibility||(this._controlsVisibility={tl:!0,tr:!0,br:!0,bl:!0,ml:!0,mt:!0,mr:!0,mb:!0,mtr:!0}),this._controlsVisibility}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(a,b){b=b||{};var c=function(){},d=b.onComplete||c,e=b.onChange||c,f=this;return fabric.util.animate({startValue:a.get(\"left\"),endValue:this.getCenter().left,duration:this.FX_DURATION,onChange:function(b){a.set(\"left\",b),f.renderAll(),e()},onComplete:function(){a.setCoords(),d()}}),this},fxCenterObjectV:function(a,b){b=b||{};var c=function(){},d=b.onComplete||c,e=b.onChange||c,f=this;return fabric.util.animate({startValue:a.get(\"top\"),endValue:this.getCenter().top,duration:this.FX_DURATION,onChange:function(b){a.set(\"top\",b),f.renderAll(),e()},onComplete:function(){a.setCoords(),d()}}),this},fxRemove:function(a,b){b=b||{};var c=function(){},d=b.onComplete||c,e=b.onChange||c,f=this;return fabric.util.animate({startValue:a.get(\"opacity\"),endValue:0,duration:this.FX_DURATION,onStart:function(){a.set(\"active\",!1)},onChange:function(b){a.set(\"opacity\",b),f.renderAll(),e()},onComplete:function(){f.remove(a),d()}}),this}}),fabric.util.object.extend(fabric.Object.prototype,{animate:function(){if(arguments[0]&&\"object\"==typeof arguments[0]){var b,c,a=[];for(b in arguments[0])a.push(b);for(var d=0,e=a.length;d<e;d++)b=a[d],c=d!==e-1,this._animate(b,arguments[0][b],arguments[1],c)}else this._animate.apply(this,arguments);return this},_animate:function(a,b,c,d){var f,e=this;b=b.toString(),c=c?fabric.util.object.clone(c):{},~a.indexOf(\".\")&&(f=a.split(\".\"));var g=f?this.get(f[0])[f[1]]:this.get(a);\"from\"in c||(c.from=g),b=~b.indexOf(\"=\")?g+parseFloat(b.replace(\"=\",\"\")):parseFloat(b),fabric.util.animate({startValue:c.from,\nendValue:b,byValue:c.by,easing:c.easing,duration:c.duration,abort:c.abort&&function(){return c.abort.call(e)},onChange:function(b){f?e[f[0]][f[1]]=b:e.set(a,b),d||c.onChange&&c.onChange()},onComplete:function(){d||(e.setCoords(),c.onComplete&&c.onComplete())}})}}),function(a){\"use strict\";function f(a,b){var c=a.origin,d=a.axis1,e=a.axis2,f=a.dimension,g=b.nearest,h=b.center,i=b.farthest;return function(){switch(this.get(c)){case g:return Math.min(this.get(d),this.get(e));case h:return Math.min(this.get(d),this.get(e))+.5*this.get(f);case i:return Math.max(this.get(d),this.get(e))}}}var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d={x1:1,x2:1,y1:1,y2:1},e=b.StaticCanvas.supports(\"setLineDash\");return b.Line?void b.warn(\"fabric.Line is already defined\"):(b.Line=b.util.createClass(b.Object,{type:\"line\",x1:0,y1:0,x2:0,y2:0,initialize:function(a,b){b=b||{},a||(a=[0,0,0,0]),this.callSuper(\"initialize\",b),this.set(\"x1\",a[0]),this.set(\"y1\",a[1]),this.set(\"x2\",a[2]),this.set(\"y2\",a[3]),this._setWidthHeight(b)},_setWidthHeight:function(a){a||(a={}),this.width=Math.abs(this.x2-this.x1)||1,this.height=Math.abs(this.y2-this.y1)||1,this.left=\"left\"in a?a.left:this._getLeftToOriginX(),this.top=\"top\"in a?a.top:this._getTopToOriginY()},_set:function(a,b){return this.callSuper(\"_set\",a,b),\"undefined\"!=typeof d[a]&&this._setWidthHeight(),this},_getLeftToOriginX:f({origin:\"originX\",axis1:\"x1\",axis2:\"x2\",dimension:\"width\"},{nearest:\"left\",center:\"center\",farthest:\"right\"}),_getTopToOriginY:f({origin:\"originY\",axis1:\"y1\",axis2:\"y2\",dimension:\"height\"},{nearest:\"top\",center:\"center\",farthest:\"bottom\"}),_render:function(a,b){if(a.beginPath(),b){var c=this.getCenterPoint();a.translate(c.x,c.y)}if(!this.strokeDashArray||this.strokeDashArray&&e){var d=this.x1<=this.x2?-1:1,f=this.y1<=this.y2?-1:1;a.moveTo(1===this.width?0:d*this.width/2,1===this.height?0:f*this.height/2),a.lineTo(1===this.width?0:d*-1*this.width/2,1===this.height?0:f*-1*this.height/2)}a.lineWidth=this.strokeWidth;var g=a.strokeStyle;a.strokeStyle=this.stroke||a.fillStyle,this.stroke&&this._renderStroke(a),a.strokeStyle=g},_renderDashedStroke:function(a){var c=this.x1<=this.x2?-1:1,d=this.y1<=this.y2?-1:1,e=1===this.width?0:c*this.width/2,f=1===this.height?0:d*this.height/2;a.beginPath(),b.util.drawDashedLine(a,e,f,-e,-f,this.strokeDashArray),a.closePath()},toObject:function(a){return c(this.callSuper(\"toObject\",a),this.calcLinePoints())},calcLinePoints:function(){var a=this.x1<=this.x2?-1:1,b=this.y1<=this.y2?-1:1,c=a*this.width/2,d=b*this.height/2,e=a*-1*this.width/2,f=b*-1*this.height/2;return{x1:c,x2:e,y1:d,y2:f}},toSVG:function(a){var b=this._createBaseSVGMarkup(),c={x1:this.x1,x2:this.x2,y1:this.y1,y2:this.y2};return this.group&&\"path-group\"===this.group.type||(c=this.calcLinePoints()),b.push(\"<line \",'x1=\"',c.x1,'\" y1=\"',c.y1,'\" x2=\"',c.x2,'\" y2=\"',c.y2,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\"/>\\n'),a?a(b.join(\"\")):b.join(\"\")},complexity:function(){return 1}}),b.Line.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(\"x1 y1 x2 y2\".split(\" \")),b.Line.fromElement=function(a,d){var e=b.parseAttributes(a,b.Line.ATTRIBUTE_NAMES),f=[e.x1||0,e.y1||0,e.x2||0,e.y2||0];return new b.Line(f,c(e,d))},void(b.Line.fromObject=function(a){var c=[a.x1,a.y1,a.x2,a.y2];return new b.Line(c,a)}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";function e(a){return\"radius\"in a&&a.radius>0}var b=a.fabric||(a.fabric={}),c=Math.PI,d=b.util.object.extend;return b.Circle?void b.warn(\"fabric.Circle is already defined.\"):(b.Circle=b.util.createClass(b.Object,{type:\"circle\",radius:0,startAngle:0,endAngle:2*c,initialize:function(a){a=a||{},this.callSuper(\"initialize\",a),this.set(\"radius\",a.radius||0),this.startAngle=a.startAngle||this.startAngle,this.endAngle=a.endAngle||this.endAngle},_set:function(a,b){return this.callSuper(\"_set\",a,b),\"radius\"===a&&this.setRadius(b),this},toObject:function(a){return d(this.callSuper(\"toObject\",a),{radius:this.get(\"radius\"),startAngle:this.startAngle,endAngle:this.endAngle})},toSVG:function(a){var b=this._createBaseSVGMarkup(),d=0,e=0,f=(this.endAngle-this.startAngle)%(2*c);if(0===f)this.group&&\"path-group\"===this.group.type&&(d=this.left+this.radius,e=this.top+this.radius),b.push(\"<circle \",'cx=\"'+d+'\" cy=\"'+e+'\" ','r=\"',this.radius,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),\" \",this.getSvgTransformMatrix(),'\"/>\\n');else{var g=Math.cos(this.startAngle)*this.radius,h=Math.sin(this.startAngle)*this.radius,i=Math.cos(this.endAngle)*this.radius,j=Math.sin(this.endAngle)*this.radius,k=f>c?\"1\":\"0\";b.push('<path d=\"M '+g+\" \"+h,\" A \"+this.radius+\" \"+this.radius,\" 0 \",+k+\" 1\",\" \"+i+\" \"+j,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),\" \",this.getSvgTransformMatrix(),'\"/>\\n')}return a?a(b.join(\"\")):b.join(\"\")},_render:function(a,b){a.beginPath(),a.arc(b?this.left+this.radius:0,b?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1),this._renderFill(a),this._renderStroke(a)},getRadiusX:function(){return this.get(\"radius\")*this.get(\"scaleX\")},getRadiusY:function(){return this.get(\"radius\")*this.get(\"scaleY\")},setRadius:function(a){this.radius=a,this.set(\"width\",2*a).set(\"height\",2*a)},complexity:function(){return 1}}),b.Circle.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(\"cx cy r\".split(\" \")),b.Circle.fromElement=function(a,c){c||(c={});var f=b.parseAttributes(a,b.Circle.ATTRIBUTE_NAMES);if(!e(f))throw new Error(\"value of `r` attribute is required and can not be negative\");f.left=f.left||0,f.top=f.top||0;var g=new b.Circle(d(f,c));return g.left-=g.radius,g.top-=g.radius,g},void(b.Circle.fromObject=function(a){return new b.Circle(a)}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={});return b.Triangle?void b.warn(\"fabric.Triangle is already defined\"):(b.Triangle=b.util.createClass(b.Object,{type:\"triangle\",initialize:function(a){a=a||{},this.callSuper(\"initialize\",a),this.set(\"width\",a.width||100).set(\"height\",a.height||100)},_render:function(a){var b=this.width/2,c=this.height/2;a.beginPath(),a.moveTo(-b,c),a.lineTo(0,-c),a.lineTo(b,c),a.closePath(),this._renderFill(a),this._renderStroke(a)},_renderDashedStroke:function(a){var c=this.width/2,d=this.height/2;a.beginPath(),b.util.drawDashedLine(a,-c,d,0,-d,this.strokeDashArray),b.util.drawDashedLine(a,0,-d,c,d,this.strokeDashArray),b.util.drawDashedLine(a,c,d,-c,d,this.strokeDashArray),a.closePath()},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=this.width/2,d=this.height/2,e=[-c+\" \"+d,\"0 \"+-d,c+\" \"+d].join(\",\");return b.push(\"<polygon \",'points=\"',e,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),'\"/>'),a?a(b.join(\"\")):b.join(\"\")},complexity:function(){return 1}}),void(b.Triangle.fromObject=function(a){return new b.Triangle(a)}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=2*Math.PI,d=b.util.object.extend;return b.Ellipse?void b.warn(\"fabric.Ellipse is already defined.\"):(b.Ellipse=b.util.createClass(b.Object,{type:\"ellipse\",rx:0,ry:0,initialize:function(a){a=a||{},this.callSuper(\"initialize\",a),this.set(\"rx\",a.rx||0),this.set(\"ry\",a.ry||0)},_set:function(a,b){switch(this.callSuper(\"_set\",a,b),a){case\"rx\":this.rx=b,this.set(\"width\",2*b);break;case\"ry\":this.ry=b,this.set(\"height\",2*b)}return this},getRx:function(){return this.get(\"rx\")*this.get(\"scaleX\")},getRy:function(){return this.get(\"ry\")*this.get(\"scaleY\")},toObject:function(a){return d(this.callSuper(\"toObject\",a),{rx:this.get(\"rx\"),ry:this.get(\"ry\")})},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,d=0;return this.group&&\"path-group\"===this.group.type&&(c=this.left+this.rx,d=this.top+this.ry),b.push(\"<ellipse \",'cx=\"',c,'\" cy=\"',d,'\" ','rx=\"',this.rx,'\" ry=\"',this.ry,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\"/>\\n'),a?a(b.join(\"\")):b.join(\"\")},_render:function(a,b){a.beginPath(),a.save(),a.transform(1,0,0,this.ry/this.rx,0,0),a.arc(b?this.left+this.rx:0,b?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,c,!1),a.restore(),this._renderFill(a),this._renderStroke(a)},complexity:function(){return 1}}),b.Ellipse.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(\"cx cy rx ry\".split(\" \")),b.Ellipse.fromElement=function(a,c){c||(c={});var e=b.parseAttributes(a,b.Ellipse.ATTRIBUTE_NAMES);e.left=e.left||0,e.top=e.top||0;var f=new b.Ellipse(d(e,c));return f.top-=f.ry,f.left-=f.rx,f},void(b.Ellipse.fromObject=function(a){return new b.Ellipse(a)}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;if(b.Rect)return void console.warn(\"fabric.Rect is already defined\");var d=b.Object.prototype.stateProperties.concat();d.push(\"rx\",\"ry\",\"x\",\"y\"),b.Rect=b.util.createClass(b.Object,{stateProperties:d,type:\"rect\",rx:0,ry:0,strokeDashArray:null,initialize:function(a){a=a||{},this.callSuper(\"initialize\",a),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(a,b){if(1===this.width&&1===this.height)return void a.fillRect(0,0,1,1);var c=this.rx?Math.min(this.rx,this.width/2):0,d=this.ry?Math.min(this.ry,this.height/2):0,e=this.width,f=this.height,g=b?this.left:-this.width/2,h=b?this.top:-this.height/2,i=0!==c||0!==d,j=.4477152502;a.beginPath(),a.moveTo(g+c,h),a.lineTo(g+e-c,h),i&&a.bezierCurveTo(g+e-j*c,h,g+e,h+j*d,g+e,h+d),a.lineTo(g+e,h+f-d),i&&a.bezierCurveTo(g+e,h+f-j*d,g+e-j*c,h+f,g+e-c,h+f),a.lineTo(g+c,h+f),i&&a.bezierCurveTo(g+j*c,h+f,g,h+f-j*d,g,h+f-d),a.lineTo(g,h+d),i&&a.bezierCurveTo(g,h+j*d,g+j*c,h,g+c,h),a.closePath(),this._renderFill(a),this._renderStroke(a)},_renderDashedStroke:function(a){var c=-this.width/2,d=-this.height/2,e=this.width,f=this.height;a.beginPath(),b.util.drawDashedLine(a,c,d,c+e,d,this.strokeDashArray),b.util.drawDashedLine(a,c+e,d,c+e,d+f,this.strokeDashArray),b.util.drawDashedLine(a,c+e,d+f,c,d+f,this.strokeDashArray),b.util.drawDashedLine(a,c,d+f,c,d,this.strokeDashArray),a.closePath()},toObject:function(a){var b=c(this.callSuper(\"toObject\",a),{rx:this.get(\"rx\")||0,ry:this.get(\"ry\")||0});return this.includeDefaultValues||this._removeDefaultValues(b),b},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=this.left,d=this.top;return this.group&&\"path-group\"===this.group.type||(c=-this.width/2,d=-this.height/2),b.push(\"<rect \",'x=\"',c,'\" y=\"',d,'\" rx=\"',this.get(\"rx\"),'\" ry=\"',this.get(\"ry\"),'\" width=\"',this.width,'\" height=\"',this.height,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\"/>\\n'),a?a(b.join(\"\")):b.join(\"\")},complexity:function(){return 1}}),b.Rect.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(\"x y rx ry width height\".split(\" \")),b.Rect.fromElement=function(a,d){if(!a)return null;d=d||{};var e=b.parseAttributes(a,b.Rect.ATTRIBUTE_NAMES);return e.left=e.left||0,e.top=e.top||0,new b.Rect(c(d?b.util.object.clone(d):{},e))},b.Rect.fromObject=function(a){return new b.Rect(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={});return b.Polyline?void b.warn(\"fabric.Polyline is already defined\"):(b.Polyline=b.util.createClass(b.Object,{type:\"polyline\",points:null,minX:0,minY:0,initialize:function(a,c){return b.Polygon.prototype.initialize.call(this,a,c)},_calcDimensions:function(){return b.Polygon.prototype._calcDimensions.call(this)},_applyPointOffset:function(){return b.Polygon.prototype._applyPointOffset.call(this)},toObject:function(a){return b.Polygon.prototype.toObject.call(this,a)},toSVG:function(a){return b.Polygon.prototype.toSVG.call(this,a)},_render:function(a){b.Polygon.prototype.commonRender.call(this,a),this._renderFill(a),this._renderStroke(a)},_renderDashedStroke:function(a){var c,d;a.beginPath();for(var e=0,f=this.points.length;e<f;e++)c=this.points[e],d=this.points[e+1]||c,b.util.drawDashedLine(a,c.x,c.y,d.x,d.y,this.strokeDashArray)},complexity:function(){return this.get(\"points\").length}}),b.Polyline.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polyline.fromElement=function(a,c){if(!a)return null;c||(c={});var d=b.parsePointsAttribute(a.getAttribute(\"points\")),e=b.parseAttributes(a,b.Polyline.ATTRIBUTE_NAMES);return null===d?null:new b.Polyline(d,b.util.object.extend(e,c))},void(b.Polyline.fromObject=function(a){var c=a.points;return new b.Polyline(c,a,!0)}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d=b.util.array.min,e=b.util.array.max,f=b.util.toFixed;return b.Polygon?void b.warn(\"fabric.Polygon is already defined\"):(b.Polygon=b.util.createClass(b.Object,{type:\"polygon\",points:null,minX:0,minY:0,initialize:function(a,b){b=b||{},this.points=a,this.callSuper(\"initialize\",b),this._calcDimensions(),\"top\"in b||(this.top=this.minY),\"left\"in b||(this.left=this.minX)},_calcDimensions:function(){var a=this.points,b=d(a,\"x\"),c=d(a,\"y\"),f=e(a,\"x\"),g=e(a,\"y\");this.width=f-b||1,this.height=g-c||1,this.minX=b,this.minY=c},_applyPointOffset:function(){this.points.forEach(function(a){a.x-=this.minX+this.width/2,a.y-=this.minY+this.height/2},this)},toObject:function(a){return c(this.callSuper(\"toObject\",a),{points:this.points.concat()})},toSVG:function(a){for(var b=[],c=this._createBaseSVGMarkup(),d=0,e=this.points.length;d<e;d++)b.push(f(this.points[d].x,2),\",\",f(this.points[d].y,2),\" \");return c.push(\"<\",this.type,\" \",'points=\"',b.join(\"\"),'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),\" \",this.getSvgTransformMatrix(),'\"/>\\n'),a?a(c.join(\"\")):c.join(\"\")},_render:function(a){this.commonRender(a),this._renderFill(a),(this.stroke||this.strokeDashArray)&&(a.closePath(),this._renderStroke(a))},commonRender:function(a){var b;a.beginPath(),this._applyPointOffset&&(this.group&&\"path-group\"===this.group.type||this._applyPointOffset(),this._applyPointOffset=null),a.moveTo(this.points[0].x,this.points[0].y);for(var c=0,d=this.points.length;c<d;c++)b=this.points[c],a.lineTo(b.x,b.y)},_renderDashedStroke:function(a){b.Polyline.prototype._renderDashedStroke.call(this,a),a.closePath()},complexity:function(){return this.points.length}}),b.Polygon.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polygon.fromElement=function(a,d){if(!a)return null;d||(d={});var e=b.parsePointsAttribute(a.getAttribute(\"points\")),f=b.parseAttributes(a,b.Polygon.ATTRIBUTE_NAMES);return null===e?null:new b.Polygon(e,c(f,d))},void(b.Polygon.fromObject=function(a){return new b.Polygon(a.points,a,!0)}))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.array.min,d=b.util.array.max,e=b.util.object.extend,f=Object.prototype.toString,g=b.util.drawArc,h={m:2,l:2,h:1,v:1,c:6,s:4,q:4,t:2,a:7},i={m:\"l\",M:\"L\"};return b.Path?void b.warn(\"fabric.Path is already defined\"):(b.Path=b.util.createClass(b.Object,{type:\"path\",path:null,minX:0,minY:0,initialize:function(a,b){if(b=b||{},this.setOptions(b),!a)throw new Error(\"`path` argument is required\");var c=\"[object Array]\"===f.call(a);if(this.path=c?a:a.match&&a.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi),this.path){c||(this.path=this._parsePath());var d=this._parseDimensions();this.minX=d.left,this.minY=d.top,this.width=d.width,this.height=d.height,this.top=this.top||this.minY,this.left=this.left||this.minX,this.pathOffset=this.pathOffset||{x:this.minX+this.width/2,y:this.minY+this.height/2},b.sourcePath&&this.setSourcePath(b.sourcePath)}},_render:function(a){var b,k,l,m,n,c=null,d=0,e=0,f=0,h=0,i=0,j=0,o=-this.pathOffset.x,p=-this.pathOffset.y;this.group&&\"path-group\"===this.group.type&&(o=0,p=0),a.beginPath();for(var q=0,r=this.path.length;q<r;++q){switch(b=this.path[q],b[0]){case\"l\":f+=b[1],h+=b[2],a.lineTo(f+o,h+p);break;case\"L\":f=b[1],h=b[2],a.lineTo(f+o,h+p);break;case\"h\":f+=b[1],a.lineTo(f+o,h+p);break;case\"H\":f=b[1],a.lineTo(f+o,h+p);break;case\"v\":h+=b[1],a.lineTo(f+o,h+p);break;case\"V\":h=b[1],a.lineTo(f+o,h+p);break;case\"m\":f+=b[1],h+=b[2],d=f,e=h,a.moveTo(f+o,h+p);break;case\"M\":f=b[1],h=b[2],d=f,e=h,a.moveTo(f+o,h+p);break;case\"c\":k=f+b[5],l=h+b[6],i=f+b[3],j=h+b[4],a.bezierCurveTo(f+b[1]+o,h+b[2]+p,i+o,j+p,k+o,l+p),f=k,h=l;break;case\"C\":f=b[5],h=b[6],i=b[3],j=b[4],a.bezierCurveTo(b[1]+o,b[2]+p,i+o,j+p,f+o,h+p);break;case\"s\":k=f+b[3],l=h+b[4],i=i?2*f-i:f,j=j?2*h-j:h,a.bezierCurveTo(i+o,j+p,f+b[1]+o,h+b[2]+p,k+o,l+p),i=f+b[1],j=h+b[2],f=k,h=l;break;case\"S\":k=b[3],l=b[4],i=2*f-i,j=2*h-j,a.bezierCurveTo(i+o,j+p,b[1]+o,b[2]+p,k+o,l+p),f=k,h=l,i=b[1],j=b[2];break;case\"q\":k=f+b[3],l=h+b[4],i=f+b[1],j=h+b[2],a.quadraticCurveTo(i+o,j+p,k+o,l+p),f=k,h=l;break;case\"Q\":k=b[3],l=b[4],a.quadraticCurveTo(b[1]+o,b[2]+p,k+o,l+p),f=k,h=l,i=b[1],j=b[2];break;case\"t\":k=f+b[1],l=h+b[2],null===c[0].match(/[QqTt]/)?(i=f,j=h):\"t\"===c[0]?(i=2*f-m,j=2*h-n):\"q\"===c[0]&&(i=2*f-i,j=2*h-j),m=i,n=j,a.quadraticCurveTo(i+o,j+p,k+o,l+p),f=k,h=l,i=f+b[1],j=h+b[2];break;case\"T\":k=b[1],l=b[2],i=2*f-i,j=2*h-j,a.quadraticCurveTo(i+o,j+p,k+o,l+p),f=k,h=l;break;case\"a\":g(a,f+o,h+p,[b[1],b[2],b[3],b[4],b[5],b[6]+f+o,b[7]+h+p]),f+=b[6],h+=b[7];break;case\"A\":g(a,f+o,h+p,[b[1],b[2],b[3],b[4],b[5],b[6]+o,b[7]+p]),f=b[6],h=b[7];break;case\"z\":case\"Z\":f=d,h=e,a.closePath()}c=b}this._renderFill(a),this._renderStroke(a)},render:function(a,c){this.visible&&(a.save(),this._setupCompositeOperation(a),c||this.transform(a),this._setStrokeStyles(a),this._setFillStyles(a),this.group&&\"path-group\"===this.group.type&&a.translate(-this.group.width/2,-this.group.height/2),this.transformMatrix&&a.transform.apply(a,this.transformMatrix),this._setOpacity(a),this._setShadow(a),this.clipTo&&b.util.clipContext(this,a),this._render(a,c),this.clipTo&&a.restore(),this._removeShadow(a),this._restoreCompositeOperation(a),a.restore())},toString:function(){return\"#<fabric.Path (\"+this.complexity()+'): { \"top\": '+this.top+', \"left\": '+this.left+\" }>\"},toObject:function(a){var b=e(this.callSuper(\"toObject\",a),{path:this.path.map(function(a){return a.slice()}),pathOffset:this.pathOffset});return this.sourcePath&&(b.sourcePath=this.sourcePath),this.transformMatrix&&(b.transformMatrix=this.transformMatrix),b},toDatalessObject:function(a){var b=this.toObject(a);return this.sourcePath&&(b.path=this.sourcePath),delete b.sourcePath,b},toSVG:function(a){for(var b=[],c=this._createBaseSVGMarkup(),d=\"\",e=0,f=this.path.length;e<f;e++)b.push(this.path[e].join(\" \"));var g=b.join(\" \");return this.group&&\"path-group\"===this.group.type||(d=\"translate(\"+-this.pathOffset.x+\", \"+-this.pathOffset.y+\")\"),c.push(\"<path \",'d=\"',g,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),d,this.getSvgTransformMatrix(),'\" stroke-linecap=\"round\" ',\"/>\\n\"),a?a(c.join(\"\")):c.join(\"\")},complexity:function(){return this.path.length},_parsePath:function(){for(var c,d,f,g,k,a=[],b=[],e=/([-+]?((\\d+\\.\\d+)|((\\d+)|(\\.\\d+)))(?:e[-+]?\\d+)?)/gi,j=0,l=this.path.length;j<l;j++){for(c=this.path[j],g=c.slice(1).trim(),b.length=0;f=e.exec(g);)b.push(f[0]);k=[c.charAt(0)];for(var m=0,n=b.length;m<n;m++)d=parseFloat(b[m]),isNaN(d)||k.push(d);var o=k[0],p=h[o.toLowerCase()],q=i[o]||o;if(k.length-1>p)for(var r=1,s=k.length;r<s;r+=p)a.push([o].concat(k.slice(r,r+p))),o=q;else a.push(k)}return a},_parseDimensions:function(){for(var f,n,o,p,q,r,a=[],e=[],g=null,h=0,i=0,j=0,k=0,l=0,m=0,s=0,t=this.path.length;s<t;++s){switch(f=this.path[s],f[0]){case\"l\":j+=f[1],k+=f[2],r=[];break;case\"L\":j=f[1],k=f[2],r=[];break;case\"h\":j+=f[1],r=[];break;case\"H\":j=f[1],r=[];break;case\"v\":k+=f[1],r=[];break;case\"V\":k=f[1],r=[];break;case\"m\":j+=f[1],k+=f[2],h=j,i=k,r=[];break;case\"M\":j=f[1],k=f[2],h=j,i=k,r=[];break;case\"c\":n=j+f[5],o=k+f[6],l=j+f[3],m=k+f[4],r=b.util.getBoundsOfCurve(j,k,j+f[1],k+f[2],l,m,n,o),j=n,k=o;break;case\"C\":j=f[5],k=f[6],l=f[3],m=f[4],r=b.util.getBoundsOfCurve(j,k,f[1],f[2],l,m,j,k);break;case\"s\":n=j+f[3],o=k+f[4],l=l?2*j-l:j,m=m?2*k-m:k,r=b.util.getBoundsOfCurve(j,k,l,m,j+f[1],k+f[2],n,o),l=j+f[1],m=k+f[2],j=n,k=o;break;case\"S\":n=f[3],o=f[4],l=2*j-l,m=2*k-m,r=b.util.getBoundsOfCurve(j,k,l,m,f[1],f[2],n,o),j=n,k=o,l=f[1],m=f[2];break;case\"q\":n=j+f[3],o=k+f[4],l=j+f[1],m=k+f[2],r=b.util.getBoundsOfCurve(j,k,l,m,l,m,n,o),j=n,k=o;break;case\"Q\":l=f[1],m=f[2],r=b.util.getBoundsOfCurve(j,k,l,m,l,m,f[3],f[4]),j=f[3],k=f[4];break;case\"t\":n=j+f[1],o=k+f[2],null===g[0].match(/[QqTt]/)?(l=j,m=k):\"t\"===g[0]?(l=2*j-p,m=2*k-q):\"q\"===g[0]&&(l=2*j-l,m=2*k-m),p=l,q=m,r=b.util.getBoundsOfCurve(j,k,l,m,l,m,n,o),j=n,k=o,l=j+f[1],m=k+f[2];break;case\"T\":n=f[1],o=f[2],l=2*j-l,m=2*k-m,r=b.util.getBoundsOfCurve(j,k,l,m,l,m,n,o),j=n,k=o;break;case\"a\":r=b.util.getBoundsOfArc(j,k,f[1],f[2],f[3],f[4],f[5],f[6]+j,f[7]+k),j+=f[6],k+=f[7];break;case\"A\":r=b.util.getBoundsOfArc(j,k,f[1],f[2],f[3],f[4],f[5],f[6],f[7]),j=f[6],k=f[7];break;case\"z\":case\"Z\":j=h,k=i}g=f,r.forEach(function(b){a.push(b.x),e.push(b.y)}),a.push(j),e.push(k)}var u=c(a),v=c(e),w=d(a),x=d(e),y=w-u,z=x-v,A={left:u,top:v,width:y,height:z};return A}}),b.Path.fromObject=function(a,c){\"string\"==typeof a.path?b.loadSVGFromURL(a.path,function(d){var e=d[0],f=a.path;delete a.path,b.util.object.extend(e,a),e.setSourcePath(f),c(e)}):c(new b.Path(a.path,a))},b.Path.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat([\"d\"]),b.Path.fromElement=function(a,c,d){var f=b.parseAttributes(a,b.Path.ATTRIBUTE_NAMES);c&&c(new b.Path(f.d,e(f,d)))},void(b.Path.async=!0))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d=b.util.array.invoke,e=b.Object.prototype.toObject;return b.PathGroup?void b.warn(\"fabric.PathGroup is already defined\"):(b.PathGroup=b.util.createClass(b.Path,{type:\"path-group\",fill:\"\",initialize:function(a,b){b=b||{},this.paths=a||[];for(var c=this.paths.length;c--;)this.paths[c].group=this;this.setOptions(b),b.widthAttr&&(this.scaleX=b.widthAttr/b.width),b.heightAttr&&(this.scaleY=b.heightAttr/b.height),this.setCoords(),b.sourcePath&&this.setSourcePath(b.sourcePath)},render:function(a){if(this.visible){a.save();var c=this.transformMatrix;c&&a.transform(c[0],c[1],c[2],c[3],c[4],c[5]),this.transform(a),this._setShadow(a),this.clipTo&&b.util.clipContext(this,a);for(var d=0,e=this.paths.length;d<e;++d)this.paths[d].render(a,!0);this.clipTo&&a.restore(),this._removeShadow(a),a.restore()}},_set:function(a,b){if(\"fill\"===a&&b&&this.isSameColor())for(var c=this.paths.length;c--;)this.paths[c]._set(a,b);return this.callSuper(\"_set\",a,b)},toObject:function(a){var b=c(e.call(this,a),{paths:d(this.getObjects(),\"toObject\",a)});return this.sourcePath&&(b.sourcePath=this.sourcePath),b},toDatalessObject:function(a){var b=this.toObject(a);return this.sourcePath&&(b.paths=this.sourcePath),b},toSVG:function(a){for(var b=this.getObjects(),c=\"translate(\"+this.left+\" \"+this.top+\")\",d=[\"<g \",'style=\"',this.getSvgStyles(),'\" ','transform=\"',c,this.getSvgTransform(),'\" ',\">\\n\"],e=0,f=b.length;e<f;e++)d.push(b[e].toSVG(a));return d.push(\"</g>\\n\"),a?a(d.join(\"\")):d.join(\"\")},toString:function(){return\"#<fabric.PathGroup (\"+this.complexity()+\"): { top: \"+this.top+\", left: \"+this.left+\" }>\"},isSameColor:function(){var a=(this.getObjects()[0].get(\"fill\")||\"\").toLowerCase();return this.getObjects().every(function(b){return(b.get(\"fill\")||\"\").toLowerCase()===a})},complexity:function(){return this.paths.reduce(function(a,b){return a+(b&&b.complexity?b.complexity():0)},0)},getObjects:function(){return this.paths}}),b.PathGroup.fromObject=function(a,c){\"string\"==typeof a.paths?b.loadSVGFromURL(a.paths,function(d){var e=a.paths;delete a.paths;var f=b.util.groupSVGElements(d,a,e);c(f)}):b.util.enlivenObjects(a.paths,function(d){delete a.paths,c(new b.PathGroup(d,a))})},void(b.PathGroup.async=!0))}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d=b.util.array.min,e=b.util.array.max,f=b.util.array.invoke;if(!b.Group){var g={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};b.Group=b.util.createClass(b.Object,b.Collection,{type:\"group\",initialize:function(a,b){b=b||{},this._objects=a||[];for(var d=this._objects.length;d--;)this._objects[d].group=this;this.originalState={},this.callSuper(\"initialize\"),this._calcBounds(),this._updateObjectsCoords(),b&&c(this,b),this.setCoords(),this.saveCoords()},_updateObjectsCoords:function(){this.forEachObject(this._updateObjectCoords,this)},_updateObjectCoords:function(a){var b=a.getLeft(),c=a.getTop();a.set({originalLeft:b,originalTop:c,left:b-this.left,top:c-this.top}),a.setCoords(),a.__origHasControls=a.hasControls,a.hasControls=!1},toString:function(){return\"#<fabric.Group: (\"+this.complexity()+\")>\"},addWithUpdate:function(a){return this._restoreObjectsState(),a&&(this._objects.push(a),a.group=this),this.forEachObject(this._setObjectActive,this),this._calcBounds(),this._updateObjectsCoords(),this},_setObjectActive:function(a){a.set(\"active\",!0),a.group=this},removeWithUpdate:function(a){return this._moveFlippedObject(a),this._restoreObjectsState(),this.forEachObject(this._setObjectActive,this),this.remove(a),this._calcBounds(),this._updateObjectsCoords(),this},_onObjectAdded:function(a){a.group=this},_onObjectRemoved:function(a){delete a.group,a.set(\"active\",!1)},delegatedProperties:{fill:!0,opacity:!0,fontFamily:!0,fontWeight:!0,fontSize:!0,fontStyle:!0,lineHeight:!0,textDecoration:!0,textAlign:!0,backgroundColor:!0},_set:function(a,b){if(a in this.delegatedProperties){var c=this._objects.length;for(this[a]=b;c--;)this._objects[c].set(a,b)}else this[a]=b},toObject:function(a){return c(this.callSuper(\"toObject\",a),{objects:f(this._objects,\"toObject\",a)})},render:function(a){if(this.visible){a.save(),this.clipTo&&b.util.clipContext(this,a);for(var c=0,d=this._objects.length;c<d;c++)this._renderObject(this._objects[c],a);this.clipTo&&a.restore(),a.restore()}},_renderControls:function(a,b){this.callSuper(\"_renderControls\",a,b);for(var c=0,d=this._objects.length;c<d;c++)this._objects[c]._renderControls(a)},_renderObject:function(a,b){var c=a.hasRotatingPoint;a.visible&&(a.hasRotatingPoint=!1,a.render(b),a.hasRotatingPoint=c)},_restoreObjectsState:function(){return this._objects.forEach(this._restoreObjectState,this),this},_moveFlippedObject:function(a){var b=a.get(\"originX\"),c=a.get(\"originY\"),d=a.getCenterPoint();a.set({originX:\"center\",originY:\"center\",left:d.x,top:d.y}),this._toggleFlipping(a);var e=a.getPointByOrigin(b,c);return a.set({originX:b,originY:c,left:e.x,top:e.y}),this},_toggleFlipping:function(a){this.flipX&&(a.toggle(\"flipX\"),a.set(\"left\",-a.get(\"left\")),a.setAngle(-a.getAngle())),this.flipY&&(a.toggle(\"flipY\"),a.set(\"top\",-a.get(\"top\")),a.setAngle(-a.getAngle()))},_restoreObjectState:function(a){return this._setObjectPosition(a),a.setCoords(),a.hasControls=a.__origHasControls,delete a.__origHasControls,a.set(\"active\",!1),a.setCoords(),delete a.group,this},_setObjectPosition:function(a){var b=this.getLeft(),c=this.getTop(),d=this._getRotatedLeftTop(a);a.set({angle:a.getAngle()+this.getAngle(),left:b+d.left,top:c+d.top,scaleX:a.get(\"scaleX\")*this.get(\"scaleX\"),scaleY:a.get(\"scaleY\")*this.get(\"scaleY\")})},_getRotatedLeftTop:function(a){var b=this.getAngle()*(Math.PI/180);return{left:-Math.sin(b)*a.getTop()*this.get(\"scaleY\")+Math.cos(b)*a.getLeft()*this.get(\"scaleX\"),top:Math.cos(b)*a.getTop()*this.get(\"scaleY\")+Math.sin(b)*a.getLeft()*this.get(\"scaleX\")}},destroy:function(){return this._objects.forEach(this._moveFlippedObject,this),this._restoreObjectsState()},saveCoords:function(){return this._originalLeft=this.get(\"left\"),this._originalTop=this.get(\"top\"),this},hasMoved:function(){return this._originalLeft!==this.get(\"left\")||this._originalTop!==this.get(\"top\")},setObjectsCoords:function(){return this.forEachObject(function(a){a.setCoords()}),this},_calcBounds:function(a){for(var d,b=[],c=[],e=0,f=this._objects.length;e<f;++e){d=this._objects[e],d.setCoords();for(var g in d.oCoords)b.push(d.oCoords[g].x),c.push(d.oCoords[g].y)}this.set(this._getBounds(b,c,a))},_getBounds:function(a,c,f){var g=b.util.invertTransform(this.getViewportTransform()),h=b.util.transformPoint(new b.Point(d(a),d(c)),g),i=b.util.transformPoint(new b.Point(e(a),e(c)),g),j={width:i.x-h.x||0,height:i.y-h.y||0};return f||(j.left=(h.x+i.x)/2||0,j.top=(h.y+i.y)/2||0),j},toSVG:function(a){for(var b=[\"<g \",'transform=\"',this.getSvgTransform(),'\">\\n'],c=0,d=this._objects.length;c<d;c++)b.push(this._objects[c].toSVG(a));return b.push(\"</g>\\n\"),a?a(b.join(\"\")):b.join(\"\")},get:function(a){if(a in g){if(this[a])return this[a];for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b][a])return!0;return!1}return a in this.delegatedProperties?this._objects[0]&&this._objects[0].get(a):this[a]}}),b.Group.fromObject=function(a,c){b.util.enlivenObjects(a.objects,function(d){delete a.objects,c&&c(new b.Group(d,a))})},b.Group.async=!0}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=fabric.util.object.extend;return a.fabric||(a.fabric={}),a.fabric.Image?void fabric.warn(\"fabric.Image is already defined.\"):(fabric.Image=fabric.util.createClass(fabric.Object,{type:\"image\",crossOrigin:\"\",initialize:function(a,b){b||(b={}),this.filters=[],this.callSuper(\"initialize\",b),this._initElement(a,b),this._initConfig(b),b.filters&&(this.filters=b.filters,this.applyFilters())},getElement:function(){return this._element},setElement:function(a,b){return this._element=a,this._originalElement=a,this._initConfig(),0!==this.filters.length&&this.applyFilters(b),this},setCrossOrigin:function(a){return this.crossOrigin=a,this._element.crossOrigin=a,this},getOriginalSize:function(){var a=this.getElement();return{width:a.width,height:a.height}},_stroke:function(a){a.save(),this._setStrokeStyles(a),a.beginPath(),a.strokeRect(-this.width/2,-this.height/2,this.width,this.height),a.closePath(),a.restore()},_renderDashedStroke:function(a){var b=-this.width/2,c=-this.height/2,d=this.width,e=this.height;a.save(),this._setStrokeStyles(a),a.beginPath(),fabric.util.drawDashedLine(a,b,c,b+d,c,this.strokeDashArray),fabric.util.drawDashedLine(a,b+d,c,b+d,c+e,this.strokeDashArray),fabric.util.drawDashedLine(a,b+d,c+e,b,c+e,this.strokeDashArray),fabric.util.drawDashedLine(a,b,c+e,b,c,this.strokeDashArray),a.closePath(),a.restore()},toObject:function(a){return b(this.callSuper(\"toObject\",a),{src:this._originalElement.src||this._originalElement._src,filters:this.filters.map(function(a){return a&&a.toObject()}),crossOrigin:this.crossOrigin})},toSVG:function(a){var b=[],c=-this.width/2,d=-this.height/2;if(this.group&&\"path-group\"===this.group.type&&(c=this.left,d=this.top),b.push('<g transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\">\\n','<image xlink:href=\"',this.getSvgSrc(),'\" x=\"',c,'\" y=\"',d,'\" style=\"',this.getSvgStyles(),'\" width=\"',this.width,'\" height=\"',this.height,'\" preserveAspectRatio=\"none\"',\"></image>\\n\"),this.stroke||this.strokeDashArray){var e=this.fill;this.fill=null,b.push(\"<rect \",'x=\"',c,'\" y=\"',d,'\" width=\"',this.width,'\" height=\"',this.height,'\" style=\"',this.getSvgStyles(),'\"/>\\n'),this.fill=e}return b.push(\"</g>\\n\"),a?a(b.join(\"\")):b.join(\"\")},getSrc:function(){if(this.getElement())return this.getElement().src||this.getElement()._src},toString:function(){return'#<fabric.Image: { src: \"'+this.getSrc()+'\" }>'},clone:function(a,b){this.constructor.fromObject(this.toObject(b),a)},applyFilters:function(a){if(this._originalElement){if(0===this.filters.length)return this._element=this._originalElement,void(a&&a());var b=this._originalElement,c=fabric.util.createCanvasElement(),d=fabric.util.createImage(),e=this;return c.width=b.width,c.height=b.height,c.getContext(\"2d\").drawImage(b,0,0,b.width,b.height),this.filters.forEach(function(a){a&&a.applyTo(c)}),d.width=b.width,d.height=b.height,fabric.isLikelyNode?(d.src=c.toBuffer(void 0,fabric.Image.pngCompression),e._element=d,a&&a()):(d.onload=function(){e._element=d,a&&a(),d.onload=c=b=null},d.src=c.toDataURL(\"image/png\")),this}},_render:function(a,b){\nthis._element&&a.drawImage(this._element,b?this.left:-this.width/2,b?this.top:-this.height/2,this.width,this.height),this._renderStroke(a)},_resetWidthHeight:function(){var a=this.getElement();this.set(\"width\",a.width),this.set(\"height\",a.height)},_initElement:function(a){this.setElement(fabric.util.getById(a)),fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(a){a||(a={}),this.setOptions(a),this._setWidthHeight(a),this._element&&this.crossOrigin&&(this._element.crossOrigin=this.crossOrigin)},_initFilters:function(a,b){a.filters&&a.filters.length?fabric.util.enlivenObjects(a.filters,function(a){b&&b(a)},\"fabric.Image.filters\"):b&&b()},_setWidthHeight:function(a){this.width=\"width\"in a?a.width:this.getElement()?this.getElement().width||0:0,this.height=\"height\"in a?a.height:this.getElement()?this.getElement().height||0:0},complexity:function(){return 1}}),fabric.Image.CSS_CANVAS=\"canvas-img\",fabric.Image.prototype.getSvgSrc=fabric.Image.prototype.getSrc,fabric.Image.fromObject=function(a,b){fabric.util.loadImage(a.src,function(c){fabric.Image.prototype._initFilters.call(a,a,function(d){a.filters=d||[];var e=new fabric.Image(c,a);b&&b(e)})},null,a.crossOrigin)},fabric.Image.fromURL=function(a,b,c){fabric.util.loadImage(a,function(a){b(new fabric.Image(a,c))},null,c&&c.crossOrigin)},fabric.Image.ATTRIBUTE_NAMES=fabric.SHARED_ATTRIBUTES.concat(\"x y width height xlink:href\".split(\" \")),fabric.Image.fromElement=function(a,c,d){var e=fabric.parseAttributes(a,fabric.Image.ATTRIBUTE_NAMES);fabric.Image.fromURL(e[\"xlink:href\"],c,b(d?fabric.util.object.clone(d):{},e))},fabric.Image.async=!0,void(fabric.Image.pngCompression=1))}(\"undefined\"!=typeof exports?exports:this),fabric.util.object.extend(fabric.Object.prototype,{_getAngleValueForStraighten:function(){var a=this.getAngle()%360;return a>0?90*Math.round((a-1)/90):90*Math.round(a/90)},straighten:function(){return this.setAngle(this._getAngleValueForStraighten()),this},fxStraighten:function(a){a=a||{};var b=function(){},c=a.onComplete||b,d=a.onChange||b,e=this;return fabric.util.animate({startValue:this.get(\"angle\"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(a){e.setAngle(a),d()},onComplete:function(){e.setCoords(),c()},onStart:function(){e.set(\"active\",!1)}}),this}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(a){return a.straighten(),this.renderAll(),this},fxStraightenObject:function(a){return a.fxStraighten({onChange:this.renderAll.bind(this)}),this}}),fabric.Image.filters=fabric.Image.filters||{},fabric.Image.filters.BaseFilter=fabric.util.createClass({type:\"BaseFilter\",toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}}),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Brightness=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Brightness\",initialize:function(a){a=a||{},this.brightness=a.brightness||0},applyTo:function(a){for(var b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=this.brightness,f=0,g=d.length;f<g;f+=4)d[f]+=e,d[f+1]+=e,d[f+2]+=e;b.putImageData(c,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{brightness:this.brightness})}}),b.Image.filters.Brightness.fromObject=function(a){return new b.Image.filters.Brightness(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Convolute=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Convolute\",initialize:function(a){a=a||{},this.opaque=a.opaque,this.matrix=a.matrix||[0,0,0,0,1,0,0,0,0];var c=b.util.createCanvasElement();this.tmpCtx=c.getContext(\"2d\")},_createImageData:function(a,b){return this.tmpCtx.createImageData(a,b)},applyTo:function(a){for(var b=this.matrix,c=a.getContext(\"2d\"),d=c.getImageData(0,0,a.width,a.height),e=Math.round(Math.sqrt(b.length)),f=Math.floor(e/2),g=d.data,h=d.width,i=d.height,j=h,k=i,l=this._createImageData(j,k),m=l.data,n=this.opaque?1:0,o=0;o<k;o++)for(var p=0;p<j;p++){for(var q=o,r=p,s=4*(o*j+p),t=0,u=0,v=0,w=0,x=0;x<e;x++)for(var y=0;y<e;y++){var z=q+x-f,A=r+y-f;if(!(z<0||z>i||A<0||A>h)){var B=4*(z*h+A),C=b[x*e+y];t+=g[B]*C,u+=g[B+1]*C,v+=g[B+2]*C,w+=g[B+3]*C}}m[s]=t,m[s+1]=u,m[s+2]=v,m[s+3]=w+n*(255-w)}c.putImageData(l,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{opaque:this.opaque,matrix:this.matrix})}}),b.Image.filters.Convolute.fromObject=function(a){return new b.Image.filters.Convolute(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.GradientTransparency=b.util.createClass(b.Image.filters.BaseFilter,{type:\"GradientTransparency\",initialize:function(a){a=a||{},this.threshold=a.threshold||100},applyTo:function(a){for(var b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=this.threshold,f=d.length,g=0,h=d.length;g<h;g+=4)d[g+3]=e+255*(f-g)/f;b.putImageData(c,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{threshold:this.threshold})}}),b.Image.filters.GradientTransparency.fromObject=function(a){return new b.Image.filters.GradientTransparency(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={});b.Image.filters.Grayscale=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Grayscale\",applyTo:function(a){for(var g,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=c.width*c.height*4,f=0;f<e;)g=(d[f]+d[f+1]+d[f+2])/3,d[f]=g,d[f+1]=g,d[f+2]=g,f+=4;b.putImageData(c,0,0)}}),b.Image.filters.Grayscale.fromObject=function(){return new b.Image.filters.Grayscale}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={});b.Image.filters.Invert=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Invert\",applyTo:function(a){var f,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=d.length;for(f=0;f<e;f+=4)d[f]=255-d[f],d[f+1]=255-d[f+1],d[f+2]=255-d[f+2];b.putImageData(c,0,0)}}),b.Image.filters.Invert.fromObject=function(){return new b.Image.filters.Invert}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Mask=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Mask\",initialize:function(a){a=a||{},this.mask=a.mask,this.channel=[0,1,2,3].indexOf(a.channel)>-1?a.channel:0},applyTo:function(a){if(this.mask){var i,c=a.getContext(\"2d\"),d=c.getImageData(0,0,a.width,a.height),e=d.data,f=this.mask.getElement(),g=b.util.createCanvasElement(),h=this.channel,j=d.width*d.height*4;g.width=f.width,g.height=f.height,g.getContext(\"2d\").drawImage(f,0,0,f.width,f.height);var k=g.getContext(\"2d\").getImageData(0,0,f.width,f.height),l=k.data;for(i=0;i<j;i+=4)e[i+3]=l[i+h];c.putImageData(d,0,0)}},toObject:function(){return c(this.callSuper(\"toObject\"),{mask:this.mask.toObject(),channel:this.channel})}}),b.Image.filters.Mask.fromObject=function(a,c){b.util.loadImage(a.mask.src,function(d){a.mask=new b.Image(d,a.mask),c&&c(new b.Image.filters.Mask(a))})},b.Image.filters.Mask.async=!0}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Noise=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Noise\",initialize:function(a){a=a||{},this.noise=a.noise||0},applyTo:function(a){for(var f,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=this.noise,g=0,h=d.length;g<h;g+=4)f=(.5-Math.random())*e,d[g]+=f,d[g+1]+=f,d[g+2]+=f;b.putImageData(c,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{noise:this.noise})}}),b.Image.filters.Noise.fromObject=function(a){return new b.Image.filters.Noise(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Pixelate=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Pixelate\",initialize:function(a){a=a||{},this.blocksize=a.blocksize||4},applyTo:function(a){var g,h,i,j,k,l,m,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=c.height,f=c.width;for(h=0;h<e;h+=this.blocksize)for(i=0;i<f;i+=this.blocksize){g=4*h*f+4*i,j=d[g],k=d[g+1],l=d[g+2],m=d[g+3];for(var n=h,o=h+this.blocksize;n<o;n++)for(var p=i,q=i+this.blocksize;p<q;p++)g=4*n*f+4*p,d[g]=j,d[g+1]=k,d[g+2]=l,d[g+3]=m}b.putImageData(c,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{blocksize:this.blocksize})}}),b.Image.filters.Pixelate.fromObject=function(a){return new b.Image.filters.Pixelate(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.RemoveWhite=b.util.createClass(b.Image.filters.BaseFilter,{type:\"RemoveWhite\",initialize:function(a){a=a||{},this.threshold=a.threshold||30,this.distance=a.distance||20},applyTo:function(a){for(var i,j,k,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=this.threshold,f=this.distance,g=255-e,h=Math.abs,l=0,m=d.length;l<m;l+=4)i=d[l],j=d[l+1],k=d[l+2],i>g&&j>g&&k>g&&h(i-j)<f&&h(i-k)<f&&h(j-k)<f&&(d[l+3]=1);b.putImageData(c,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{threshold:this.threshold,distance:this.distance})}}),b.Image.filters.RemoveWhite.fromObject=function(a){return new b.Image.filters.RemoveWhite(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={});b.Image.filters.Sepia=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Sepia\",applyTo:function(a){var f,g,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=d.length;for(f=0;f<e;f+=4)g=.3*d[f]+.59*d[f+1]+.11*d[f+2],d[f]=g+100,d[f+1]=g+50,d[f+2]=g+255;b.putImageData(c,0,0)}}),b.Image.filters.Sepia.fromObject=function(){return new b.Image.filters.Sepia}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={});b.Image.filters.Sepia2=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Sepia2\",applyTo:function(a){var f,g,h,i,b=a.getContext(\"2d\"),c=b.getImageData(0,0,a.width,a.height),d=c.data,e=d.length;for(f=0;f<e;f+=4)g=d[f],h=d[f+1],i=d[f+2],d[f]=(.393*g+.769*h+.189*i)/1.351,d[f+1]=(.349*g+.686*h+.168*i)/1.203,d[f+2]=(.272*g+.534*h+.131*i)/2.14;b.putImageData(c,0,0)}}),b.Image.filters.Sepia2.fromObject=function(){return new b.Image.filters.Sepia2}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Tint=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Tint\",initialize:function(a){a=a||{},this.color=a.color||\"#000000\",this.opacity=\"undefined\"!=typeof a.opacity?a.opacity:new b.Color(this.color).getAlpha()},applyTo:function(a){var g,h,i,j,k,l,m,n,o,c=a.getContext(\"2d\"),d=c.getImageData(0,0,a.width,a.height),e=d.data,f=e.length;for(o=new b.Color(this.color).getSource(),h=o[0]*this.opacity,i=o[1]*this.opacity,j=o[2]*this.opacity,n=1-this.opacity,g=0;g<f;g+=4)k=e[g],l=e[g+1],m=e[g+2],e[g]=h+k*n,e[g+1]=i+l*n,e[g+2]=j+m*n;c.putImageData(d,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{color:this.color,opacity:this.opacity})}}),b.Image.filters.Tint.fromObject=function(a){return new b.Image.filters.Tint(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend;b.Image.filters.Multiply=b.util.createClass(b.Image.filters.BaseFilter,{type:\"Multiply\",initialize:function(a){a=a||{},this.color=a.color||\"#000000\"},applyTo:function(a){var g,h,c=a.getContext(\"2d\"),d=c.getImageData(0,0,a.width,a.height),e=d.data,f=e.length;for(h=new b.Color(this.color).getSource(),g=0;g<f;g+=4)e[g]*=h[0]/255,e[g+1]*=h[1]/255,e[g+2]*=h[2]/255;c.putImageData(d,0,0)},toObject:function(){return c(this.callSuper(\"toObject\"),{color:this.color})}}),b.Image.filters.Multiply.fromObject=function(a){return new b.Image.filters.Multiply(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric;b.Image.filters.Blend=b.util.createClass({type:\"Blend\",initialize:function(a){a=a||{},this.color=a.color||\"#000\",this.image=a.image||!1,this.mode=a.mode||\"multiply\",this.alpha=a.alpha||1},applyTo:function(a){var f,g,h,i,j,k,l,c=a.getContext(\"2d\"),d=c.getImageData(0,0,a.width,a.height),e=d.data,m=!1;if(this.image){m=!0;var n=b.util.createCanvasElement();n.width=this.image.width,n.height=this.image.height;var o=new b.StaticCanvas(n);o.add(this.image);var p=o.getContext(\"2d\");l=p.getImageData(0,0,o.width,o.height).data}else l=new b.Color(this.color).getSource(),f=l[0]*this.alpha,g=l[1]*this.alpha,h=l[2]*this.alpha;for(var q=0,r=e.length;q<r;q+=4)switch(i=e[q],j=e[q+1],k=e[q+2],m&&(f=l[q]*this.alpha,g=l[q+1]*this.alpha,h=l[q+2]*this.alpha),this.mode){case\"multiply\":e[q]=i*f/255,e[q+1]=j*g/255,e[q+2]=k*h/255;break;case\"screen\":e[q]=1-(1-i)*(1-f),e[q+1]=1-(1-j)*(1-g),e[q+2]=1-(1-k)*(1-h);break;case\"add\":e[q]=Math.min(255,i+f),e[q+1]=Math.min(255,j+g),e[q+2]=Math.min(255,k+h);break;case\"diff\":case\"difference\":e[q]=Math.abs(i-f),e[q+1]=Math.abs(j-g),e[q+2]=Math.abs(k-h);break;case\"subtract\":var s=i-f,t=j-g,u=k-h;e[q]=s<0?0:s,e[q+1]=t<0?0:t,e[q+2]=u<0?0:u;break;case\"darken\":e[q]=Math.min(i,f),e[q+1]=Math.min(j,g),e[q+2]=Math.min(k,h);break;case\"lighten\":e[q]=Math.max(i,f),e[q+1]=Math.max(j,g),e[q+2]=Math.max(k,h)}c.putImageData(d,0,0)},toObject:function(){return{color:this.color,image:this.image,mode:this.mode,alpha:this.alpha}}}),b.Image.filters.Blend.fromObject=function(a){return new b.Image.filters.Blend(a)}}(\"undefined\"!=typeof exports?exports:this),function(a){\"use strict\";var b=a.fabric||(a.fabric={}),c=b.util.object.extend,d=b.util.object.clone,e=b.util.toFixed,f=b.StaticCanvas.supports(\"setLineDash\");if(b.Text)return void b.warn(\"fabric.Text is already defined\");var g=b.Object.prototype.stateProperties.concat();g.push(\"fontFamily\",\"fontWeight\",\"fontSize\",\"text\",\"textDecoration\",\"textAlign\",\"fontStyle\",\"lineHeight\",\"textBackgroundColor\",\"useNative\",\"path\"),b.Text=b.util.createClass(b.Object,{_dimensionAffectingProps:{fontSize:!0,fontWeight:!0,fontFamily:!0,textDecoration:!0,fontStyle:!0,lineHeight:!0,stroke:!0,strokeWidth:!0,text:!0},_reNewline:/\\r?\\n/,type:\"text\",fontSize:40,fontWeight:\"normal\",fontFamily:\"Times New Roman\",textDecoration:\"\",textAlign:\"left\",fontStyle:\"\",lineHeight:1.3,textBackgroundColor:\"\",path:null,useNative:!0,stateProperties:g,stroke:null,shadow:null,initialize:function(a,b){b=b||{},this.text=a,this.__skipDimension=!0,this.setOptions(b),this.__skipDimension=!1,this._initDimensions()},_initDimensions:function(){if(!this.__skipDimension){var a=b.util.createCanvasElement();this._render(a.getContext(\"2d\"))}},toString:function(){return\"#<fabric.Text (\"+this.complexity()+'): { \"text\": \"'+this.text+'\", \"fontFamily\": \"'+this.fontFamily+'\" }>'},_render:function(a){\"undefined\"==typeof Cufon||this.useNative===!0?this._renderViaNative(a):this._renderViaCufon(a)},_renderViaNative:function(a){var c=this.text.split(this._reNewline);this._setTextStyles(a),this.width=this._getTextWidth(a,c),this.height=this._getTextHeight(a,c),this.clipTo&&b.util.clipContext(this,a),this._renderTextBackground(a,c),this._translateForTextAlign(a),this._renderText(a,c),\"left\"!==this.textAlign&&\"justify\"!==this.textAlign&&a.restore(),this._renderTextDecoration(a,c),this.clipTo&&a.restore(),this._setBoundaries(a,c),this._totalLineHeight=0},_renderText:function(a,b){a.save(),this._setShadow(a),this._setupCompositeOperation(a),this._renderTextFill(a,b),this._renderTextStroke(a,b),this._restoreCompositeOperation(a),this._removeShadow(a),a.restore()},_translateForTextAlign:function(a){\"left\"!==this.textAlign&&\"justify\"!==this.textAlign&&(a.save(),a.translate(\"center\"===this.textAlign?this.width/2:this.width,0))},_setBoundaries:function(a,b){this._boundaries=[];for(var c=0,d=b.length;c<d;c++){var e=this._getLineWidth(a,b[c]),f=this._getLineLeftOffset(e);this._boundaries.push({height:this.fontSize*this.lineHeight,width:e,left:f})}},_setTextStyles:function(a){this._setFillStyles(a),this._setStrokeStyles(a),a.textBaseline=\"alphabetic\",this.skipTextAlign||(a.textAlign=this.textAlign),a.font=this._getFontDeclaration()},_getTextHeight:function(a,b){return this.fontSize*b.length*this.lineHeight},_getTextWidth:function(a,b){for(var c=a.measureText(b[0]||\"|\").width,d=1,e=b.length;d<e;d++){var f=a.measureText(b[d]).width;f>c&&(c=f)}return c},_renderChars:function(a,b,c,d,e){b[a](c,d,e)},_renderTextLine:function(a,b,c,d,e,f){if(e-=this.fontSize/4,\"justify\"!==this.textAlign)return void this._renderChars(a,b,c,d,e,f);var g=b.measureText(c).width,h=this.width;if(h>g)for(var i=c.split(/\\s+/),j=b.measureText(c.replace(/\\s+/g,\"\")).width,k=h-j,l=i.length-1,m=k/l,n=0,o=0,p=i.length;o<p;o++)this._renderChars(a,b,i[o],d+n,e,f),n+=b.measureText(i[o]).width+m;else this._renderChars(a,b,c,d,e,f)},_getLeftOffset:function(){return b.isLikelyNode?0:-this.width/2},_getTopOffset:function(){return-this.height/2},_renderTextFill:function(a,b){if(this.fill||this._skipFillStrokeCheck){this._boundaries=[];for(var c=0,d=0,e=b.length;d<e;d++){var f=this._getHeightOfLine(a,d,b);c+=f,this._renderTextLine(\"fillText\",a,b[d],this._getLeftOffset(),this._getTopOffset()+c,d)}this.shadow&&!this.shadow.affectStroke&&this._removeShadow(a)}},_renderTextStroke:function(a,b){if(this.stroke&&0!==this.strokeWidth||this._skipFillStrokeCheck){var c=0;a.save(),this.strokeDashArray&&(1&this.strokeDashArray.length&&this.strokeDashArray.push.apply(this.strokeDashArray,this.strokeDashArray),f&&a.setLineDash(this.strokeDashArray)),a.beginPath();for(var d=0,e=b.length;d<e;d++){var g=this._getHeightOfLine(a,d,b);c+=g,this._renderTextLine(\"strokeText\",a,b[d],this._getLeftOffset(),this._getTopOffset()+c,d)}a.closePath(),a.restore()}},_getHeightOfLine:function(){return this.fontSize*this.lineHeight},_renderTextBackground:function(a,b){this._renderTextBoxBackground(a),this._renderTextLinesBackground(a,b)},_renderTextBoxBackground:function(a){this.backgroundColor&&(a.save(),a.fillStyle=this.backgroundColor,a.fillRect(this._getLeftOffset(),this._getTopOffset(),this.width,this.height),a.restore())},_renderTextLinesBackground:function(a,b){if(this.textBackgroundColor){a.save(),a.fillStyle=this.textBackgroundColor;for(var c=0,d=b.length;c<d;c++)if(\"\"!==b[c]){var e=this._getLineWidth(a,b[c]),f=this._getLineLeftOffset(e);a.fillRect(this._getLeftOffset()+f,this._getTopOffset()+c*this.fontSize*this.lineHeight,e,this.fontSize*this.lineHeight)}a.restore()}},_getLineLeftOffset:function(a){return\"center\"===this.textAlign?(this.width-a)/2:\"right\"===this.textAlign?this.width-a:0},_getLineWidth:function(a,b){return\"justify\"===this.textAlign?this.width:a.measureText(b).width},_renderTextDecoration:function(a,b){function e(e){for(var f=0,g=b.length;f<g;f++){var h=d._getLineWidth(a,b[f]),i=d._getLineLeftOffset(h);a.fillRect(d._getLeftOffset()+i,~~(e+f*d._getHeightOfLine(a,f,b)-c),h,1)}}if(this.textDecoration){var c=this._getTextHeight(a,b)/2,d=this;this.textDecoration.indexOf(\"underline\")>-1&&e(this.fontSize*this.lineHeight),this.textDecoration.indexOf(\"line-through\")>-1&&e(this.fontSize*this.lineHeight-this.fontSize/2),this.textDecoration.indexOf(\"overline\")>-1&&e(this.fontSize*this.lineHeight-this.fontSize)}},_getFontDeclaration:function(){return[b.isLikelyNode?this.fontWeight:this.fontStyle,b.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+\"px\",b.isLikelyNode?'\"'+this.fontFamily+'\"':this.fontFamily].join(\" \")},render:function(a,b){if(this.visible){a.save(),b||this.transform(a);var c=this.group&&\"path-group\"===this.group.type;c&&a.translate(-this.group.width/2,-this.group.height/2),this.transformMatrix&&a.transform.apply(a,this.transformMatrix),c&&a.translate(this.left,this.top),this._render(a),a.restore()}},toObject:function(a){var b=c(this.callSuper(\"toObject\",a),{text:this.text,fontSize:this.fontSize,fontWeight:this.fontWeight,fontFamily:this.fontFamily,fontStyle:this.fontStyle,lineHeight:this.lineHeight,textDecoration:this.textDecoration,textAlign:this.textAlign,path:this.path,textBackgroundColor:this.textBackgroundColor,useNative:this.useNative});return this.includeDefaultValues||this._removeDefaultValues(b),b},toSVG:function(a){var b=[],c=this.text.split(this._reNewline),d=this._getSVGLeftTopOffsets(c),e=this._getSVGTextAndBg(d.lineTop,d.textLeft,c),f=this._getSVGShadows(d.lineTop,c);return d.textTop+=this._fontAscent?this._fontAscent/5*this.lineHeight:0,this._wrapSVGTextAndBg(b,e,f,d),a?a(b.join(\"\")):b.join(\"\")},_getSVGLeftTopOffsets:function(a){var b=this.useNative?this.fontSize*this.lineHeight:-this._fontAscent-this._fontAscent/5*this.lineHeight,c=-(this.width/2),d=this.useNative?this.fontSize-1:this.height/2-a.length*this.fontSize-this._totalLineHeight;return{textLeft:c+(this.group&&\"path-group\"===this.group.type?this.left:0),textTop:d+(this.group&&\"path-group\"===this.group.type?this.top:0),lineTop:b}},_wrapSVGTextAndBg:function(a,b,c,d){a.push('<g transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\">\\n',b.textBgRects.join(\"\"),\"<text \",this.fontFamily?'font-family=\"'+this.fontFamily.replace(/\"/g,\"'\")+'\" ':\"\",this.fontSize?'font-size=\"'+this.fontSize+'\" ':\"\",this.fontStyle?'font-style=\"'+this.fontStyle+'\" ':\"\",this.fontWeight?'font-weight=\"'+this.fontWeight+'\" ':\"\",this.textDecoration?'text-decoration=\"'+this.textDecoration+'\" ':\"\",'style=\"',this.getSvgStyles(),'\" ','transform=\"translate(',e(d.textLeft,2),\" \",e(d.textTop,2),')\">',c.join(\"\"),b.textSpans.join(\"\"),\"</text>\\n\",\"</g>\\n\")},_getSVGShadows:function(a,c){var f,g,d=[],h=1;if(!this.shadow||!this._boundaries)return d;for(f=0,g=c.length;f<g;f++)if(\"\"!==c[f]){var i=this._boundaries&&this._boundaries[f]?this._boundaries[f].left:0;d.push('<tspan x=\"',e(i+h+this.shadow.offsetX,2),0===f||this.useNative?'\" y':'\" dy','=\"',e(this.useNative?a*f-this.height/2+this.shadow.offsetY:a+(0===f?this.shadow.offsetY:0),2),'\" ',this._getFillAttributes(this.shadow.color),\">\",b.util.string.escapeXml(c[f]),\"</tspan>\"),h=1}else h++;return d},_getSVGTextAndBg:function(a,b,c){var d=[],e=[],f=1;this._setSVGBg(e);for(var g=0,h=c.length;g<h;g++)\"\"!==c[g]?(this._setSVGTextLineText(c[g],g,d,a,f,e),f=1):f++,this.textBackgroundColor&&this._boundaries&&this._setSVGTextLineBg(e,g,b,a);return{textSpans:d,textBgRects:e}},_setSVGTextLineText:function(a,c,d,f,g){var h=this._boundaries&&this._boundaries[c]?e(this._boundaries[c].left,2):0;d.push('<tspan x=\"',h,'\" ',0===c||this.useNative?\"y\":\"dy\",'=\"',e(this.useNative?f*c-this.height/2:f*g,2),'\" ',this._getFillAttributes(this.fill),\">\",b.util.string.escapeXml(a),\"</tspan>\")},_setSVGTextLineBg:function(a,b,c,d){a.push(\"<rect \",this._getFillAttributes(this.textBackgroundColor),' x=\"',e(c+this._boundaries[b].left,2),'\" y=\"',e(d*b-this.height/2,2),'\" width=\"',e(this._boundaries[b].width,2),'\" height=\"',e(this._boundaries[b].height,2),'\"></rect>\\n')},_setSVGBg:function(a){this.backgroundColor&&this._boundaries&&a.push(\"<rect \",this._getFillAttributes(this.backgroundColor),' x=\"',e(-this.width/2,2),'\" y=\"',e(-this.height/2,2),'\" width=\"',e(this.width,2),'\" height=\"',e(this.height,2),'\"></rect>')},_getFillAttributes:function(a){var c=a&&\"string\"==typeof a?new b.Color(a):\"\";return c&&c.getSource()&&1!==c.getAlpha()?'opacity=\"'+c.getAlpha()+'\" fill=\"'+c.setAlpha(1).toRgb()+'\"':'fill=\"'+a+'\"'},_set:function(a,b){\"fontFamily\"===a&&this.path&&(this.path=this.path.replace(/(.*?)([^\\/]*)(\\.font\\.js)/,\"$1\"+b+\"$3\")),this.callSuper(\"_set\",a,b),a in this._dimensionAffectingProps&&(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),b.Text.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(\"x y dx dy font-family font-style font-weight font-size text-decoration text-anchor\".split(\" \")),b.Text.DEFAULT_SVG_FONT_SIZE=16,b.Text.fromElement=function(a,c){if(!a)return null;var d=b.parseAttributes(a,b.Text.ATTRIBUTE_NAMES);c=b.util.object.extend(c?b.util.object.clone(c):{},d),\"dx\"in d&&(c.left+=d.dx),\"dy\"in d&&(c.top+=d.dy),\"fontSize\"in c||(c.fontSize=b.Text.DEFAULT_SVG_FONT_SIZE),c.originX||(c.originX=\"left\");var e=new b.Text(a.textContent,c),f=0;return\"left\"===e.originX&&(f=e.getWidth()/2),\"right\"===e.originX&&(f=-e.getWidth()/2),e.set({left:e.getLeft()+f,top:e.getTop()-e.getHeight()/2}),e},b.Text.fromObject=function(a){return new b.Text(a.text,d(a))},b.util.createAccessors(b.Text)}(\"undefined\"!=typeof exports?exports:this),function(){var a=fabric.util.object.clone;fabric.IText=fabric.util.createClass(fabric.Text,fabric.Observable,{type:\"i-text\",selectionStart:0,selectionEnd:0,selectionColor:\"rgba(17,119,255,0.3)\",isEditing:!1,editable:!0,editingBorderColor:\"rgba(102,153,255,0.25)\",cursorWidth:2,cursorColor:\"#333\",cursorDelay:1e3,cursorDuration:600,styles:null,caching:!0,_skipFillStrokeCheck:!0,_reSpace:/\\s|\\n/,_fontSizeFraction:4,_currentCursorOpacity:0,_selectionDirection:null,_abortCursorAnimation:!1,_charWidthsCache:{},initialize:function(a,b){this.styles=b?b.styles||{}:{},this.callSuper(\"initialize\",a,b),this.initBehavior(),fabric.IText.instances.push(this),this.__lineWidths={},this.__lineHeights={},this.__lineOffsets={}},isEmptyStyles:function(){if(!this.styles)return!0;var a=this.styles;for(var b in a)for(var c in a[b])for(var d in a[b][c])return!1;return!0},setSelectionStart:function(a){this.selectionStart!==a&&(this.fire(\"selection:changed\"),this.canvas&&this.canvas.fire(\"text:selection:changed\",{target:this})),this.selectionStart=a,this.hiddenTextarea&&(this.hiddenTextarea.selectionStart=a)},setSelectionEnd:function(a){this.selectionEnd!==a&&(this.fire(\"selection:changed\"),this.canvas&&this.canvas.fire(\"text:selection:changed\",{target:this})),this.selectionEnd=a,this.hiddenTextarea&&(this.hiddenTextarea.selectionEnd=a)},getSelectionStyles:function(a,b){if(2===arguments.length){for(var c=[],d=a;d<b;d++)c.push(this.getSelectionStyles(d));return c}var e=this.get2DCursorLocation(a);return this.styles[e.lineIndex]?this.styles[e.lineIndex][e.charIndex]||{}:{}},setSelectionStyles:function(a){if(this.selectionStart===this.selectionEnd)this._extendStyles(this.selectionStart,a);else for(var b=this.selectionStart;b<this.selectionEnd;b++)this._extendStyles(b,a);return this},_extendStyles:function(a,b){var c=this.get2DCursorLocation(a);this.styles[c.lineIndex]||(this.styles[c.lineIndex]={}),this.styles[c.lineIndex][c.charIndex]||(this.styles[c.lineIndex][c.charIndex]={}),fabric.util.object.extend(this.styles[c.lineIndex][c.charIndex],b)},_render:function(a){this.callSuper(\"_render\",a),this.ctx=a,this.isEditing&&this.renderCursorOrSelection()},renderCursorOrSelection:function(){if(this.active){var b,a=this.text.split(\"\");this.selectionStart===this.selectionEnd?(b=this._getCursorBoundaries(a,\"cursor\"),this.renderCursor(b)):(b=this._getCursorBoundaries(a,\"selection\"),this.renderSelection(a,b))}},get2DCursorLocation:function(a){\"undefined\"==typeof a&&(a=this.selectionStart);var b=this.text.slice(0,a),c=b.split(this._reNewline);return{lineIndex:c.length-1,charIndex:c[c.length-1].length}},getCurrentCharStyle:function(a,b){var c=this.styles[a]&&this.styles[a][0===b?0:b-1];return{fontSize:c&&c.fontSize||this.fontSize,fill:c&&c.fill||this.fill,textBackgroundColor:c&&c.textBackgroundColor||this.textBackgroundColor,textDecoration:c&&c.textDecoration||this.textDecoration,fontFamily:c&&c.fontFamily||this.fontFamily,fontWeight:c&&c.fontWeight||this.fontWeight,fontStyle:c&&c.fontStyle||this.fontStyle,stroke:c&&c.stroke||this.stroke,strokeWidth:c&&c.strokeWidth||this.strokeWidth}},getCurrentCharFontSize:function(a,b){return this.styles[a]&&this.styles[a][0===b?0:b-1]&&this.styles[a][0===b?0:b-1].fontSize||this.fontSize},getCurrentCharColor:function(a,b){return this.styles[a]&&this.styles[a][0===b?0:b-1]&&this.styles[a][0===b?0:b-1].fill||this.cursorColor},_getCursorBoundaries:function(a,b){var c=this.get2DCursorLocation(),d=this.text.split(this._reNewline),e=Math.round(this._getLeftOffset()),f=this._getTopOffset(),g=this._getCursorBoundariesOffsets(a,b,c,d);return{left:e,top:f,leftOffset:g.left+g.lineLeft,topOffset:g.top}},_getCursorBoundariesOffsets:function(a,b,c,d){for(var e=0,f=0,g=0,h=0,i=\"cursor\"===b?this._getHeightOfLine(this.ctx,0)-this.getCurrentCharFontSize(c.lineIndex,c.charIndex):0,j=0;j<this.selectionStart;j++){if(\"\\n\"===a[j]){h=0;var k=f+(\"cursor\"===b?1:0);i+=this._getCachedLineHeight(k),f++,g=0}else h+=this._getWidthOfChar(this.ctx,a[j],f,g),g++;e=this._getCachedLineOffset(f,d)}return this._clearCache(),{top:i,left:h,lineLeft:e}},_clearCache:function(){this.__lineWidths={},this.__lineHeights={},this.__lineOffsets={}},_getCachedLineHeight:function(a){return this.__lineHeights[a]||(this.__lineHeights[a]=this._getHeightOfLine(this.ctx,a))},_getCachedLineWidth:function(a,b){return this.__lineWidths[a]||(this.__lineWidths[a]=this._getWidthOfLine(this.ctx,a,b))},_getCachedLineOffset:function(a,b){var c=this._getCachedLineWidth(a,b);return this.__lineOffsets[a]||(this.__lineOffsets[a]=this._getLineLeftOffset(c))},renderCursor:function(a){var b=this.ctx;b.save();var c=this.get2DCursorLocation(),d=c.lineIndex,e=c.charIndex,f=this.getCurrentCharFontSize(d,e),g=0===d&&0===e?this._getCachedLineOffset(d,this.text.split(this._reNewline)):a.leftOffset;b.fillStyle=this.getCurrentCharColor(d,e),b.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity,b.fillRect(a.left+g,a.top+a.topOffset,this.cursorWidth/this.scaleX,f),b.restore()},renderSelection:function(a,b){var c=this.ctx;c.save(),c.fillStyle=this.selectionColor;for(var d=this.get2DCursorLocation(this.selectionStart),e=this.get2DCursorLocation(this.selectionEnd),f=d.lineIndex,g=e.lineIndex,h=this.text.split(this._reNewline),i=f;i<=g;i++){var j=this._getCachedLineOffset(i,h)||0,k=this._getCachedLineHeight(i),l=0;if(i===f)for(var m=0,n=h[i].length;m<n;m++)m>=d.charIndex&&(i!==g||m<e.charIndex)&&(l+=this._getWidthOfChar(c,h[i][m],i,m)),m<d.charIndex&&(j+=this._getWidthOfChar(c,h[i][m],i,m));else if(i>f&&i<g)l+=this._getCachedLineWidth(i,h)||5;else if(i===g)for(var o=0,p=e.charIndex;o<p;o++)l+=this._getWidthOfChar(c,h[i][o],i,o);c.fillRect(b.left+j,b.top+b.topOffset,l,k),b.topOffset+=k}c.restore()},_renderChars:function(a,b,c,d,e,f){if(this.isEmptyStyles())return this._renderCharsFast(a,b,c,d,e);this.skipTextAlign=!0,d-=\"center\"===this.textAlign?this.width/2:\"right\"===this.textAlign?this.width:0;var l,g=this.text.split(this._reNewline),h=this._getWidthOfLine(b,f,g),i=this._getHeightOfLine(b,f,g),j=this._getLineLeftOffset(h),k=c.split(\"\"),m=\"\";d+=j||0,b.save();for(var n=0,o=k.length;n<=o;n++){l=l||this.getCurrentCharStyle(f,n);var p=this.getCurrentCharStyle(f,n+1);(this._hasStyleChanged(l,p)||n===o)&&(this._renderChar(a,b,f,n-1,m,d,e,i),m=\"\",l=p),m+=k[n]}b.restore()},_renderCharsFast:function(a,b,c,d,e){this.skipTextAlign=!1,\"fillText\"===a&&this.fill&&this.callSuper(\"_renderChars\",a,b,c,d,e),\"strokeText\"===a&&this.stroke&&this.callSuper(\"_renderChars\",a,b,c,d,e)},_renderChar:function(a,b,c,d,e,f,g,h){var i,j,k;if(this.styles&&this.styles[c]&&(i=this.styles[c][d])){var l=i.stroke||this.stroke,m=i.fill||this.fill;b.save(),j=this._applyCharStylesGetWidth(b,e,c,d,i),k=this._getHeightOfChar(b,e,c,d),m&&b.fillText(e,f,g),l&&b.strokeText(e,f,g),this._renderCharDecoration(b,i,f,g,j,h,k),b.restore(),b.translate(j,0)}else\"strokeText\"===a&&this.stroke&&b[a](e,f,g),\"fillText\"===a&&this.fill&&b[a](e,f,g),j=this._applyCharStylesGetWidth(b,e,c,d),this._renderCharDecoration(b,null,f,g,j,h),b.translate(b.measureText(e).width,0)},_hasStyleChanged:function(a,b){return a.fill!==b.fill||a.fontSize!==b.fontSize||a.textBackgroundColor!==b.textBackgroundColor||a.textDecoration!==b.textDecoration||a.fontFamily!==b.fontFamily||a.fontWeight!==b.fontWeight||a.fontStyle!==b.fontStyle||a.stroke!==b.stroke||a.strokeWidth!==b.strokeWidth},_renderCharDecoration:function(a,b,c,d,e,f,g){var h=b?b.textDecoration||this.textDecoration:this.textDecoration,i=(b?b.fontSize:null)||this.fontSize;h&&(h.indexOf(\"underline\")>-1&&this._renderCharDecorationAtOffset(a,c,d+this.fontSize/this._fontSizeFraction,e,0,this.fontSize/20),\nh.indexOf(\"line-through\")>-1&&this._renderCharDecorationAtOffset(a,c,d+this.fontSize/this._fontSizeFraction,e,g/2,i/20),h.indexOf(\"overline\")>-1&&this._renderCharDecorationAtOffset(a,c,d,e,f-this.fontSize/this._fontSizeFraction,this.fontSize/20))},_renderCharDecorationAtOffset:function(a,b,c,d,e,f){a.fillRect(b,c-e,d,f)},_renderTextLine:function(a,b,c,d,e,f){e+=this.fontSize/4,this.callSuper(\"_renderTextLine\",a,b,c,d,e,f)},_renderTextDecoration:function(a,b){if(this.isEmptyStyles())return this.callSuper(\"_renderTextDecoration\",a,b)},_renderTextLinesBackground:function(a,b){if(this.textBackgroundColor||this.styles){a.save(),this.textBackgroundColor&&(a.fillStyle=this.textBackgroundColor);for(var c=0,d=this.fontSize/this._fontSizeFraction,e=0,f=b.length;e<f;e++){var g=this._getHeightOfLine(a,e,b);if(\"\"!==b[e]){var h=this._getWidthOfLine(a,e,b),i=this._getLineLeftOffset(h);if(this.textBackgroundColor&&(a.fillStyle=this.textBackgroundColor,a.fillRect(this._getLeftOffset()+i,this._getTopOffset()+c+d,h,g)),this.styles[e])for(var j=0,k=b[e].length;j<k;j++)if(this.styles[e]&&this.styles[e][j]&&this.styles[e][j].textBackgroundColor){var l=b[e][j];a.fillStyle=this.styles[e][j].textBackgroundColor,a.fillRect(this._getLeftOffset()+i+this._getWidthOfCharsAt(a,e,j,b),this._getTopOffset()+c+d,this._getWidthOfChar(a,l,e,j,b)+1,g)}c+=g}else c+=g}a.restore()}},_getCacheProp:function(a,b){return a+b.fontFamily+b.fontSize+b.fontWeight+b.fontStyle+b.shadow},_applyCharStylesGetWidth:function(b,c,d,e,f){var g=f||this.styles[d]&&this.styles[d][e];g=g?a(g):{},this._applyFontStyles(g);var h=this._getCacheProp(c,g);if(this.isEmptyStyles()&&this._charWidthsCache[h]&&this.caching)return this._charWidthsCache[h];\"string\"==typeof g.shadow&&(g.shadow=new fabric.Shadow(g.shadow));var i=g.fill||this.fill;return b.fillStyle=i.toLive?i.toLive(b):i,g.stroke&&(b.strokeStyle=g.stroke&&g.stroke.toLive?g.stroke.toLive(b):g.stroke),b.lineWidth=g.strokeWidth||this.strokeWidth,b.font=this._getFontDeclaration.call(g),this._setShadow.call(g,b),this.caching?(this._charWidthsCache[h]||(this._charWidthsCache[h]=b.measureText(c).width),this._charWidthsCache[h]):b.measureText(c).width},_applyFontStyles:function(a){a.fontFamily||(a.fontFamily=this.fontFamily),a.fontSize||(a.fontSize=this.fontSize),a.fontWeight||(a.fontWeight=this.fontWeight),a.fontStyle||(a.fontStyle=this.fontStyle)},_getStyleDeclaration:function(b,c){return this.styles[b]&&this.styles[b][c]?a(this.styles[b][c]):{}},_getWidthOfChar:function(a,b,c,d){if(\"justify\"===this.textAlign&&/\\s/.test(b))return this._getWidthOfSpace(a,c);var e=this._getStyleDeclaration(c,d);this._applyFontStyles(e);var f=this._getCacheProp(b,e);if(this._charWidthsCache[f]&&this.caching)return this._charWidthsCache[f];if(a){a.save();var g=this._applyCharStylesGetWidth(a,b,c,d);return a.restore(),g}},_getHeightOfChar:function(a,b,c,d){return this.styles[c]&&this.styles[c][d]?this.styles[c][d].fontSize||this.fontSize:this.fontSize},_getWidthOfCharAt:function(a,b,c,d){d=d||this.text.split(this._reNewline);var e=d[b].split(\"\")[c];return this._getWidthOfChar(a,e,b,c)},_getHeightOfCharAt:function(a,b,c,d){d=d||this.text.split(this._reNewline);var e=d[b].split(\"\")[c];return this._getHeightOfChar(a,e,b,c)},_getWidthOfCharsAt:function(a,b,c,d){for(var e=0,f=0;f<c;f++)e+=this._getWidthOfCharAt(a,b,f,d);return e},_getWidthOfLine:function(a,b,c){return this._getWidthOfCharsAt(a,b,c[b].length,c)},_getWidthOfSpace:function(a,b){var c=this.text.split(this._reNewline),d=c[b],e=d.split(/\\s+/),f=this._getWidthOfWords(a,d,b),g=this.width-f,h=e.length-1,i=g/h;return i},_getWidthOfWords:function(a,b,c){for(var d=0,e=0;e<b.length;e++){var f=b[e];f.match(/\\s/)||(d+=this._getWidthOfChar(a,f,c,e))}return d},_getTextWidth:function(a,b){if(this.isEmptyStyles())return this.callSuper(\"_getTextWidth\",a,b);for(var c=this._getWidthOfLine(a,0,b),d=1,e=b.length;d<e;d++){var f=this._getWidthOfLine(a,d,b);f>c&&(c=f)}return c},_getHeightOfLine:function(a,b,c){c=c||this.text.split(this._reNewline);for(var d=this._getHeightOfChar(a,c[b][0],b,0),e=c[b],f=e.split(\"\"),g=1,h=f.length;g<h;g++){var i=this._getHeightOfChar(a,f[g],b,g);i>d&&(d=i)}return d*this.lineHeight},_getTextHeight:function(a,b){for(var c=0,d=0,e=b.length;d<e;d++)c+=this._getHeightOfLine(a,d,b);return c},_getTopOffset:function(){var a=fabric.Text.prototype._getTopOffset.call(this);return a-this.fontSize/this._fontSizeFraction},_renderTextBoxBackground:function(a){this.backgroundColor&&(a.save(),a.fillStyle=this.backgroundColor,a.fillRect(this._getLeftOffset(),this._getTopOffset()+this.fontSize/this._fontSizeFraction,this.width,this.height),a.restore())},toObject:function(b){return fabric.util.object.extend(this.callSuper(\"toObject\",b),{styles:a(this.styles)})}}),fabric.IText.fromObject=function(b){return new fabric.IText(b.text,a(b))},fabric.IText.instances=[]}(),function(){var a=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initAddedHandler(),this.initCursorSelectionHandlers(),this.initDoubleClickSimulation()},initSelectedHandler:function(){this.on(\"selected\",function(){var a=this;setTimeout(function(){a.selected=!0},100)})},initAddedHandler:function(){this.on(\"added\",function(){this.canvas&&!this.canvas._hasITextHandlers&&(this.canvas._hasITextHandlers=!0,this._initCanvasHandlers())})},_initCanvasHandlers:function(){this.canvas.on(\"selection:cleared\",function(){fabric.IText.prototype.exitEditingOnOthers.call()}),this.canvas.on(\"mouse:up\",function(){fabric.IText.instances.forEach(function(a){a.__isMousedown=!1})}),this.canvas.on(\"object:selected\",function(a){fabric.IText.prototype.exitEditingOnOthers.call(a.target)})},_tick:function(){if(!this._abortCursorAnimation){var a=this;this.animate(\"_currentCursorOpacity\",1,{duration:this.cursorDuration,onComplete:function(){a._onTickComplete()},onChange:function(){a.canvas&&a.canvas.renderAll()},abort:function(){return a._abortCursorAnimation}})}},_onTickComplete:function(){if(!this._abortCursorAnimation){var a=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1),this._cursorTimeout1=setTimeout(function(){a.animate(\"_currentCursorOpacity\",0,{duration:this.cursorDuration/2,onComplete:function(){a._tick()},onChange:function(){a.canvas&&a.canvas.renderAll()},abort:function(){return a._abortCursorAnimation}})},100)}},initDelayedCursor:function(a){var b=this,c=a?0:this.cursorDelay;a&&(this._abortCursorAnimation=!0,clearTimeout(this._cursorTimeout1),this._currentCursorOpacity=1,this.canvas&&this.canvas.renderAll()),this._cursorTimeout2&&clearTimeout(this._cursorTimeout2),this._cursorTimeout2=setTimeout(function(){b._abortCursorAnimation=!1,b._tick()},c)},abortCursorAnimation:function(){this._abortCursorAnimation=!0,clearTimeout(this._cursorTimeout1),clearTimeout(this._cursorTimeout2),this._currentCursorOpacity=0,this.canvas&&this.canvas.renderAll();var a=this;setTimeout(function(){a._abortCursorAnimation=!1},10)},selectAll:function(){this.selectionStart=0,this.selectionEnd=this.text.length,this.fire(\"selection:changed\"),this.canvas&&this.canvas.fire(\"text:selection:changed\",{target:this})},getSelectedText:function(){return this.text.slice(this.selectionStart,this.selectionEnd)},findWordBoundaryLeft:function(a){var b=0,c=a-1;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)b++,c--;for(;/\\S/.test(this.text.charAt(c))&&c>-1;)b++,c--;return a-b},findWordBoundaryRight:function(a){var b=0,c=a;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)b++,c++;for(;/\\S/.test(this.text.charAt(c))&&c<this.text.length;)b++,c++;return a+b},findLineBoundaryLeft:function(a){for(var b=0,c=a-1;!/\\n/.test(this.text.charAt(c))&&c>-1;)b++,c--;return a-b},findLineBoundaryRight:function(a){for(var b=0,c=a;!/\\n/.test(this.text.charAt(c))&&c<this.text.length;)b++,c++;return a+b},getNumNewLinesInSelectedText:function(){for(var a=this.getSelectedText(),b=0,c=0,d=a.split(\"\"),e=d.length;c<e;c++)\"\\n\"===d[c]&&b++;return b},searchWordBoundary:function(a,b){for(var c=this._reSpace.test(this.text.charAt(a))?a-1:a,d=this.text.charAt(c),e=/[ \\n\\.,;!\\?\\-]/;!e.test(d)&&c>0&&c<this.text.length;)c+=b,d=this.text.charAt(c);return e.test(d)&&\"\\n\"!==d&&(c+=1===b?0:1),c},selectWord:function(a){var b=this.searchWordBoundary(a,-1),c=this.searchWordBoundary(a,1);this.setSelectionStart(b),this.setSelectionEnd(c),this.initDelayedCursor(!0)},selectLine:function(a){var b=this.findLineBoundaryLeft(a),c=this.findLineBoundaryRight(a);this.setSelectionStart(b),this.setSelectionEnd(c),this.initDelayedCursor(!0)},enterEditing:function(){if(!this.isEditing&&this.editable)return this.exitEditingOnOthers(),this.isEditing=!0,this.initHiddenTextarea(),this._updateTextarea(),this._saveEditingProps(),this._setEditingProps(),this._tick(),this.canvas&&this.canvas.renderAll(),this.fire(\"editing:entered\"),this.canvas&&this.canvas.fire(\"text:editing:entered\",{target:this}),this},exitEditingOnOthers:function(){fabric.IText.instances.forEach(function(a){a.selected=!1,a.isEditing&&a.exitEditing()},this)},_setEditingProps:function(){this.hoverCursor=\"text\",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor=\"text\"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},_updateTextarea:function(){this.hiddenTextarea&&(this.hiddenTextarea.value=this.text,this.hiddenTextarea.selectionStart=this.selectionStart)},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){this._savedProps&&(this.hoverCursor=this._savedProps.overCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY,this.canvas&&(this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor))},exitEditing:function(){return this.selected=!1,this.isEditing=!1,this.selectable=!0,this.selectionEnd=this.selectionStart,this.hiddenTextarea&&this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,this.fire(\"editing:exited\"),this.canvas&&this.canvas.fire(\"text:editing:exited\",{target:this}),this},_removeExtraneousStyles:function(){var a=this.text.split(this._reNewline);for(var b in this.styles)a[b]||delete this.styles[b]},_removeCharsFromTo:function(a,b){for(var c=b;c!==a;){var d=this.get2DCursorLocation(c).charIndex;c--;var e=this.get2DCursorLocation(c).charIndex,f=e>d;f?this.removeStyleObject(f,c+1):this.removeStyleObject(0===this.get2DCursorLocation(c).charIndex,c)}this.text=this.text.slice(0,a)+this.text.slice(b)},insertChars:function(a){var b=\"\\n\"===this.text.slice(this.selectionStart,this.selectionStart+1);this.text=this.text.slice(0,this.selectionStart)+a+this.text.slice(this.selectionEnd),this.selectionStart===this.selectionEnd&&this.insertStyleObjects(a,b,this.copiedStyles),this.selectionStart+=a.length,this.selectionEnd=this.selectionStart,this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire(\"changed\"),this.canvas&&this.canvas.fire(\"text:changed\",{target:this})},insertNewlineStyleObject:function(b,c,d){this.shiftLineStyles(b,1),this.styles[b+1]||(this.styles[b+1]={});var e=this.styles[b][c-1],f={};if(d)f[0]=a(e),this.styles[b+1]=f;else{for(var g in this.styles[b])parseInt(g,10)>=c&&(f[parseInt(g,10)-c]=this.styles[b][g],delete this.styles[b][g]);this.styles[b+1]=f}},insertCharStyleObject:function(b,c,d){var e=this.styles[b],f=a(e);0!==c||d||(c=1);for(var g in f){var h=parseInt(g,10);h>=c&&(e[h+1]=f[h])}this.styles[b][c]=d||a(e[c-1])},insertStyleObjects:function(a,b,c){if(!this.isEmptyStyles()){var d=this.get2DCursorLocation(),e=d.lineIndex,f=d.charIndex;this.styles[e]||(this.styles[e]={}),\"\\n\"===a?this.insertNewlineStyleObject(e,f,b):c?this._insertStyles(c):this.insertCharStyleObject(e,f)}},_insertStyles:function(a){for(var b=0,c=a.length;b<c;b++){var d=this.get2DCursorLocation(this.selectionStart+b),e=d.lineIndex,f=d.charIndex;this.insertCharStyleObject(e,f,a[b])}},shiftLineStyles:function(b,c){var d=a(this.styles);for(var e in this.styles){var f=parseInt(e,10);f>b&&(this.styles[f+c]=d[f])}},removeStyleObject:function(b,c){var d=this.get2DCursorLocation(c),e=d.lineIndex,f=d.charIndex;if(b){var g=this.text.split(this._reNewline),h=g[e-1],i=h?h.length:0;this.styles[e-1]||(this.styles[e-1]={});for(f in this.styles[e])this.styles[e-1][parseInt(f,10)+i]=this.styles[e][f];this.shiftLineStyles(e,-1)}else{var j=this.styles[e];if(j){var k=this.selectionStart===this.selectionEnd?-1:0;delete j[f+k]}var l=a(j);for(var m in l){var n=parseInt(m,10);n>=f&&0!==n&&(j[n-1]=l[n],delete j[n])}}},insertNewline:function(){this.insertChars(\"\\n\")}})}(),fabric.util.object.extend(fabric.IText.prototype,{initDoubleClickSimulation:function(){this.__lastClickTime=+new Date,this.__lastLastClickTime=+new Date,this.__lastPointer={},this.on(\"mousedown\",this.onMouseDown.bind(this))},onMouseDown:function(a){this.__newClickTime=+new Date;var b=this.canvas.getPointer(a.e);this.isTripleClick(b)?(this.fire(\"tripleclick\",a),this._stopEvent(a.e)):this.isDoubleClick(b)&&(this.fire(\"dblclick\",a),this._stopEvent(a.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=b,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected},isDoubleClick:function(a){return this.__newClickTime-this.__lastClickTime<500&&this.__lastPointer.x===a.x&&this.__lastPointer.y===a.y&&this.__lastIsEditing},isTripleClick:function(a){return this.__newClickTime-this.__lastClickTime<500&&this.__lastClickTime-this.__lastLastClickTime<500&&this.__lastPointer.x===a.x&&this.__lastPointer.y===a.y},_stopEvent:function(a){a.preventDefault&&a.preventDefault(),a.stopPropagation&&a.stopPropagation()},initCursorSelectionHandlers:function(){this.initSelectedHandler(),this.initMousedownHandler(),this.initMousemoveHandler(),this.initMouseupHandler(),this.initClicks()},initClicks:function(){this.on(\"dblclick\",function(a){this.selectWord(this.getSelectionStartFromPointer(a.e))}),this.on(\"tripleclick\",function(a){this.selectLine(this.getSelectionStartFromPointer(a.e))})},initMousedownHandler:function(){this.on(\"mousedown\",function(a){var b=this.canvas.getPointer(a.e);this.__mousedownX=b.x,this.__mousedownY=b.y,this.__isMousedown=!0,this.hiddenTextarea&&this.canvas&&this.canvas.wrapperEl.appendChild(this.hiddenTextarea),this.selected&&this.setCursorByClick(a.e),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.initDelayedCursor(!0))})},initMousemoveHandler:function(){this.on(\"mousemove\",function(a){if(this.__isMousedown&&this.isEditing){var b=this.getSelectionStartFromPointer(a.e);b>=this.__selectionStartOnMouseDown?(this.setSelectionStart(this.__selectionStartOnMouseDown),this.setSelectionEnd(b)):(this.setSelectionStart(b),this.setSelectionEnd(this.__selectionStartOnMouseDown))}})},_isObjectMoved:function(a){var b=this.canvas.getPointer(a);return this.__mousedownX!==b.x||this.__mousedownY!==b.y},initMouseupHandler:function(){this.on(\"mouseup\",function(a){this.__isMousedown=!1,this._isObjectMoved(a.e)||(this.__lastSelected&&(this.enterEditing(),this.initDelayedCursor(!0)),this.selected=!0)})},setCursorByClick:function(a){var b=this.getSelectionStartFromPointer(a);a.shiftKey?b<this.selectionStart?(this.setSelectionEnd(this.selectionStart),this.setSelectionStart(b)):this.setSelectionEnd(b):(this.setSelectionStart(b),this.setSelectionEnd(b))},_getLocalRotatedPointer:function(a){var b=this.canvas.getPointer(a),c=new fabric.Point(b.x,b.y),d=new fabric.Point(this.left,this.top),e=fabric.util.rotatePoint(c,d,fabric.util.degreesToRadians(-this.angle));return this.getLocalPointer(a,e)},getSelectionStartFromPointer:function(a){for(var h,b=this._getLocalRotatedPointer(a),c=this.text.split(this._reNewline),d=0,e=0,f=0,g=0,i=0,j=c.length;i<j;i++){f+=this._getHeightOfLine(this.ctx,i)*this.scaleY;var k=this._getWidthOfLine(this.ctx,i,c),l=this._getLineLeftOffset(k);e=l*this.scaleX,this.flipX&&(c[i]=c[i].split(\"\").reverse().join(\"\"));for(var m=0,n=c[i].length;m<n;m++){var o=c[i][m];if(d=e,e+=this._getWidthOfChar(this.ctx,o,i,this.flipX?n-m:m)*this.scaleX,!(f<=b.y||e<=b.x))return this._getNewSelectionStartFromOffset(b,d,e,g+i,n);g++}if(b.y<f)return this._getNewSelectionStartFromOffset(b,d,e,g+i,n)}if(\"undefined\"==typeof h)return this.text.length},_getNewSelectionStartFromOffset:function(a,b,c,d,e){var f=a.x-b,g=c-a.x,h=g>f?0:1,i=d+h;return this.flipX&&(i=e-i),i>this.text.length&&(i=this.text.length),i}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement(\"textarea\"),this.hiddenTextarea.setAttribute(\"autocapitalize\",\"off\"),this.hiddenTextarea.style.cssText=\"position: absolute; top: 0; left: -9999px\",fabric.document.body.appendChild(this.hiddenTextarea),fabric.util.addListener(this.hiddenTextarea,\"keydown\",this.onKeyDown.bind(this)),fabric.util.addListener(this.hiddenTextarea,\"keypress\",this.onKeyPress.bind(this)),fabric.util.addListener(this.hiddenTextarea,\"copy\",this.copy.bind(this)),fabric.util.addListener(this.hiddenTextarea,\"paste\",this.paste.bind(this)),!this._clickHandlerInitialized&&this.canvas&&(fabric.util.addListener(this.canvas.upperCanvasEl,\"click\",this.onClick.bind(this)),this._clickHandlerInitialized=!0)},_keysMap:{8:\"removeChars\",9:\"exitEditing\",27:\"exitEditing\",13:\"insertNewline\",33:\"moveCursorUp\",34:\"moveCursorDown\",35:\"moveCursorRight\",36:\"moveCursorLeft\",37:\"moveCursorLeft\",38:\"moveCursorUp\",39:\"moveCursorRight\",40:\"moveCursorDown\",46:\"forwardDelete\"},_ctrlKeysMap:{65:\"selectAll\",88:\"cut\"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(a){if(this.isEditing){if(a.keyCode in this._keysMap)this[this._keysMap[a.keyCode]](a);else{if(!(a.keyCode in this._ctrlKeysMap&&(a.ctrlKey||a.metaKey)))return;this[this._ctrlKeysMap[a.keyCode]](a)}a.stopImmediatePropagation(),a.preventDefault(),this.canvas&&this.canvas.renderAll()}},forwardDelete:function(a){this.selectionStart===this.selectionEnd&&this.moveCursorRight(a),this.removeChars(a)},copy:function(a){var b=this.getSelectedText(),c=this._getClipboardData(a);c&&c.setData(\"text\",b),this.copiedText=b,this.copiedStyles=this.getSelectionStyles(this.selectionStart,this.selectionEnd)},paste:function(a){var b=null,c=this._getClipboardData(a);b=c?c.getData(\"text\"):this.copiedText,b&&this.insertChars(b)},cut:function(a){this.selectionStart!==this.selectionEnd&&(this.copy(),this.removeChars(a))},_getClipboardData:function(a){return a&&(a.clipboardData||fabric.window.clipboardData)},onKeyPress:function(a){!this.isEditing||a.metaKey||a.ctrlKey||(0!==a.which&&this.insertChars(String.fromCharCode(a.which)),a.stopPropagation())},getDownCursorOffset:function(a,b){var e,f,c=b?this.selectionEnd:this.selectionStart,d=this.text.split(this._reNewline),g=this.text.slice(0,c),h=this.text.slice(c),i=g.slice(g.lastIndexOf(\"\\n\")+1),j=h.match(/(.*)\\n?/)[1],k=(h.match(/.*\\n(.*)\\n?/)||{})[1]||\"\",l=this.get2DCursorLocation(c);if(l.lineIndex===d.length-1||a.metaKey||34===a.keyCode)return this.text.length-c;var m=this._getWidthOfLine(this.ctx,l.lineIndex,d);f=this._getLineLeftOffset(m);for(var n=f,o=l.lineIndex,p=0,q=i.length;p<q;p++)e=i[p],n+=this._getWidthOfChar(this.ctx,e,o,p);var r=this._getIndexOnNextLine(l,k,n,d);return j.length+1+r},_getIndexOnNextLine:function(a,b,c,d){for(var j,e=a.lineIndex+1,f=this._getWidthOfLine(this.ctx,e,d),g=this._getLineLeftOffset(f),h=g,i=0,k=0,l=b.length;k<l;k++){var m=b[k],n=this._getWidthOfChar(this.ctx,m,e,k);if(h+=n,h>c){j=!0;var o=h-n,p=h,q=Math.abs(o-c),r=Math.abs(p-c);i=r<q?k+1:k;break}}return j||(i=b.length),i},moveCursorDown:function(a){this.abortCursorAnimation(),this._currentCursorOpacity=1;var b=this.getDownCursorOffset(a,\"right\"===this._selectionDirection);a.shiftKey?this.moveCursorDownWithShift(b):this.moveCursorDownWithoutShift(b),this.initDelayedCursor()},moveCursorDownWithoutShift:function(a){this._selectionDirection=\"right\",this.selectionStart+=a,this.selectionStart>this.text.length&&(this.selectionStart=this.text.length),this.selectionEnd=this.selectionStart},swapSelectionPoints:function(){var a=this.selectionEnd;this.selectionEnd=this.selectionStart,this.selectionStart=a},moveCursorDownWithShift:function(a){this.selectionEnd===this.selectionStart&&(this._selectionDirection=\"right\");var b=\"right\"===this._selectionDirection?\"selectionEnd\":\"selectionStart\";this[b]+=a,this.selectionEnd<this.selectionStart&&\"left\"===this._selectionDirection&&(this.swapSelectionPoints(),this._selectionDirection=\"right\"),this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length)},getUpCursorOffset:function(a,b){var c=b?this.selectionEnd:this.selectionStart,d=this.get2DCursorLocation(c);if(0===d.lineIndex||a.metaKey||33===a.keyCode)return c;for(var i,e=this.text.slice(0,c),f=e.slice(e.lastIndexOf(\"\\n\")+1),g=(e.match(/\\n?(.*)\\n.*$/)||{})[1]||\"\",h=this.text.split(this._reNewline),j=this._getWidthOfLine(this.ctx,d.lineIndex,h),k=this._getLineLeftOffset(j),l=k,m=d.lineIndex,n=0,o=f.length;n<o;n++)i=f[n],l+=this._getWidthOfChar(this.ctx,i,m,n);var p=this._getIndexOnPrevLine(d,g,l,h);return g.length-p+f.length},_getIndexOnPrevLine:function(a,b,c,d){for(var j,e=a.lineIndex-1,f=this._getWidthOfLine(this.ctx,e,d),g=this._getLineLeftOffset(f),h=g,i=0,k=0,l=b.length;k<l;k++){var m=b[k],n=this._getWidthOfChar(this.ctx,m,e,k);if(h+=n,h>c){j=!0;var o=h-n,p=h,q=Math.abs(o-c),r=Math.abs(p-c);i=r<q?k:k-1;break}}return j||(i=b.length-1),i},moveCursorUp:function(a){this.abortCursorAnimation(),this._currentCursorOpacity=1;var b=this.getUpCursorOffset(a,\"right\"===this._selectionDirection);a.shiftKey?this.moveCursorUpWithShift(b):this.moveCursorUpWithoutShift(b),this.initDelayedCursor()},moveCursorUpWithShift:function(a){this.selectionEnd===this.selectionStart&&(this._selectionDirection=\"left\");var b=\"right\"===this._selectionDirection?\"selectionEnd\":\"selectionStart\";this[b]-=a,this.selectionEnd<this.selectionStart&&\"right\"===this._selectionDirection&&(this.swapSelectionPoints(),this._selectionDirection=\"left\"),this.selectionStart<0&&(this.selectionStart=0)},moveCursorUpWithoutShift:function(a){this.selectionStart===this.selectionEnd&&(this.selectionStart-=a),this.selectionStart<0&&(this.selectionStart=0),this.selectionEnd=this.selectionStart,this._selectionDirection=\"left\"},moveCursorLeft:function(a){0===this.selectionStart&&0===this.selectionEnd||(this.abortCursorAnimation(),this._currentCursorOpacity=1,a.shiftKey?this.moveCursorLeftWithShift(a):this.moveCursorLeftWithoutShift(a),this.initDelayedCursor())},_move:function(a,b,c){a.altKey?this[b]=this[\"findWordBoundary\"+c](this[b]):a.metaKey||35===a.keyCode||36===a.keyCode?this[b]=this[\"findLineBoundary\"+c](this[b]):this[b]+=\"Left\"===c?-1:1},_moveLeft:function(a,b){this._move(a,b,\"Left\")},_moveRight:function(a,b){this._move(a,b,\"Right\")},moveCursorLeftWithoutShift:function(a){this._selectionDirection=\"left\",this.selectionEnd===this.selectionStart&&this._moveLeft(a,\"selectionStart\"),this.selectionEnd=this.selectionStart},moveCursorLeftWithShift:function(a){\"right\"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(a,\"selectionEnd\"):(this._selectionDirection=\"left\",this._moveLeft(a,\"selectionStart\"),\"\\n\"===this.text.charAt(this.selectionStart)&&this.selectionStart--,this.selectionStart<0&&(this.selectionStart=0))},moveCursorRight:function(a){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||(this.abortCursorAnimation(),this._currentCursorOpacity=1,a.shiftKey?this.moveCursorRightWithShift(a):this.moveCursorRightWithoutShift(a),this.initDelayedCursor())},moveCursorRightWithShift:function(a){\"left\"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(a,\"selectionStart\"):(this._selectionDirection=\"right\",this._moveRight(a,\"selectionEnd\"),\"\\n\"===this.text.charAt(this.selectionEnd-1)&&this.selectionEnd++,this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length))},moveCursorRightWithoutShift:function(a){this._selectionDirection=\"right\",this.selectionStart===this.selectionEnd?(this._moveRight(a,\"selectionStart\"),this.selectionEnd=this.selectionStart):(this.selectionEnd+=this.getNumNewLinesInSelectedText(),this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length),this.selectionStart=this.selectionEnd)},removeChars:function(a){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(a):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.selectionEnd=this.selectionStart,this._removeExtraneousStyles(),this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire(\"changed\"),this.canvas&&this.canvas.fire(\"text:changed\",{target:this})},_removeCharsNearCursor:function(a){if(0!==this.selectionStart)if(a.metaKey){var b=this.findLineBoundaryLeft(this.selectionStart);this._removeCharsFromTo(b,this.selectionStart),this.selectionStart=b}else if(a.altKey){var c=this.findWordBoundaryLeft(this.selectionStart);this._removeCharsFromTo(c,this.selectionStart),this.selectionStart=c}else{var d=\"\\n\"===this.text.slice(this.selectionStart-1,this.selectionStart);this.removeStyleObject(d),this.selectionStart--,this.text=this.text.slice(0,this.selectionStart)+this.text.slice(this.selectionStart+1)}}}),fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(a,b,c,d,e,f){this.styles[b]?this._setSVGTextLineChars(a,b,c,d,e,f):this.callSuper(\"_setSVGTextLineText\",a,b,c,d,e)},_setSVGTextLineChars:function(a,b,c,d,e,f){for(var g=0===b||this.useNative?\"y\":\"dy\",h=a.split(\"\"),i=0,j=this._getSVGLineLeftOffset(b),k=this._getSVGLineTopOffset(b),l=this._getHeightOfLine(this.ctx,b),m=0,n=h.length;m<n;m++){var o=this.styles[b][m]||{};c.push(this._createTextCharSpan(h[m],o,j,k,g,i));var p=this._getWidthOfChar(this.ctx,h[m],b,m);o.textBackgroundColor&&f.push(this._createTextCharBg(o,j,k,l,p,i)),i+=p}},_getSVGLineLeftOffset:function(a){return this._boundaries&&this._boundaries[a]?fabric.util.toFixed(this._boundaries[a].left,2):0},_getSVGLineTopOffset:function(a){for(var b=0,c=0;c<=a;c++)b+=this._getHeightOfLine(this.ctx,c);return b-this.height/2},_createTextCharBg:function(a,b,c,d,e,f){return['<rect fill=\"',a.textBackgroundColor,'\" transform=\"translate(',-this.width/2,\" \",-this.height+d,\")\",'\" x=\"',b+f,'\" y=\"',c+d,'\" width=\"',e,'\" height=\"',d,'\"></rect>'].join(\"\")},_createTextCharSpan:function(a,b,c,d,e,f){var g=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:\"text\"},b));return['<tspan x=\"',c+f,'\" ',e,'=\"',d,'\" ',b.fontFamily?'font-family=\"'+b.fontFamily.replace(/\"/g,\"'\")+'\" ':\"\",b.fontSize?'font-size=\"'+b.fontSize+'\" ':\"\",b.fontStyle?'font-style=\"'+b.fontStyle+'\" ':\"\",b.fontWeight?'font-weight=\"'+b.fontWeight+'\" ':\"\",b.textDecoration?'text-decoration=\"'+b.textDecoration+'\" ':\"\",'style=\"',g,'\">',fabric.util.string.escapeXml(a),\"</tspan>\"].join(\"\")}}),function(){function request(a,b,c){var d=URL.parse(a);d.port||(d.port=0===d.protocol.indexOf(\"https:\")?443:80);var e=443===d.port?HTTPS:HTTP,f=e.request({hostname:d.hostname,port:d.port,path:d.path,method:\"GET\"},function(a){var d=\"\";b&&a.setEncoding(b),a.on(\"end\",function(){c(d)}),a.on(\"data\",function(b){200===a.statusCode&&(d+=b)})});f.on(\"error\",function(a){a.errno===process.ECONNREFUSED?fabric.log(\"ECONNREFUSED: connection refused to \"+d.hostname+\":\"+d.port):fabric.log(a.message)}),f.end()}function requestFs(a,b){var c=require(\"fs\");c.readFile(a,function(a,c){if(a)throw fabric.log(a),a;b(c)})}if(\"undefined\"==typeof document||\"undefined\"==typeof window){var DOMParser=require(\"xmldom\").DOMParser,URL=require(\"url\"),HTTP=require(\"http\"),HTTPS=require(\"https\"),Canvas=require(\"canvas\"),Image=require(\"canvas\").Image;fabric.util.loadImage=function(a,b,c){function d(d){e.src=new Buffer(d,\"binary\"),e._src=a,b&&b.call(c,e)}var e=new Image;a&&(a instanceof Buffer||0===a.indexOf(\"data\"))?(e.src=e._src=a,b&&b.call(c,e)):a&&0!==a.indexOf(\"http\")?requestFs(a,d):a?request(a,\"binary\",d):b&&b.call(c,a)},fabric.loadSVGFromURL=function(a,b,c){a=a.replace(/^\\n\\s*/,\"\").replace(/\\?.*$/,\"\").trim(),0!==a.indexOf(\"http\")?requestFs(a,function(a){fabric.loadSVGFromString(a.toString(),b,c)}):request(a,\"\",function(a){fabric.loadSVGFromString(a,b,c)})},fabric.loadSVGFromString=function(a,b,c){var d=(new DOMParser).parseFromString(a);fabric.parseSVGDocument(d.documentElement,function(a,c){b&&b(a,c)},c)},fabric.util.getScript=function(url,callback){request(url,\"\",function(body){eval(body),callback&&callback()})},fabric.Image.fromObject=function(a,b){fabric.util.loadImage(a.src,function(c){var d=new fabric.Image(c);d._initConfig(a),d._initFilters(a,function(a){d.filters=a||[],b&&b(d)})})},fabric.createCanvasForNode=function(a,b,c,d){d=d||c;var e=fabric.document.createElement(\"canvas\"),f=new Canvas(a||600,b||600,d);e.style={},e.width=f.width,e.height=f.height;var g=fabric.Canvas||fabric.StaticCanvas,h=new g(e,c);return h.contextContainer=f.getContext(\"2d\"),h.nodeCanvas=f,h.Font=Canvas.Font,h},fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(a){return this.nodeCanvas.createJPEGStream(a)};var origSetWidth=fabric.StaticCanvas.prototype.setWidth;fabric.StaticCanvas.prototype.setWidth=function(a,b){return origSetWidth.call(this,a,b),this.nodeCanvas.width=a,this},fabric.Canvas&&(fabric.Canvas.prototype.setWidth=fabric.StaticCanvas.prototype.setWidth);var origSetHeight=fabric.StaticCanvas.prototype.setHeight;fabric.StaticCanvas.prototype.setHeight=function(a,b){return origSetHeight.call(this,a,b),this.nodeCanvas.height=a,this},fabric.Canvas&&(fabric.Canvas.prototype.setHeight=fabric.StaticCanvas.prototype.setHeight)}}();"
  },
  {
    "path": "src/libs/fabric1-4-2.min.js",
    "content": "/* build: `node build.js modules=ALL exclude=gestures,cufon,json minifier=uglifyjs` *//*! Fabric.js Copyright 2008-2014, Printio (Juriy Zaytsev, Maxim Chernyak) */var fabric=fabric||{version:\"1.4.12\"};typeof exports!=\"undefined\"&&(exports.fabric=fabric),typeof document!=\"undefined\"&&typeof window!=\"undefined\"?(fabric.document=document,fabric.window=window):(fabric.document=require(\"jsdom\").jsdom(\"<!DOCTYPE html><html><head></head><body></body></html>\"),fabric.window=fabric.document.createWindow()),fabric.isTouchSupported=\"ontouchstart\"in fabric.document.documentElement,fabric.isLikelyNode=typeof Buffer!=\"undefined\"&&typeof window==\"undefined\",fabric.SHARED_ATTRIBUTES=[\"display\",\"transform\",\"fill\",\"fill-opacity\",\"fill-rule\",\"opacity\",\"stroke\",\"stroke-dasharray\",\"stroke-linecap\",\"stroke-linejoin\",\"stroke-miterlimit\",\"stroke-opacity\",\"stroke-width\"],fabric.DPI=96,function(){function e(e,t){if(!this.__eventListeners[e])return;t?fabric.util.removeFromArray(this.__eventListeners[e],t):this.__eventListeners[e].length=0}function t(e,t){this.__eventListeners||(this.__eventListeners={});if(arguments.length===1)for(var n in e)this.on(n,e[n]);else this.__eventListeners[e]||(this.__eventListeners[e]=[]),this.__eventListeners[e].push(t);return this}function n(t,n){if(!this.__eventListeners)return;if(arguments.length===0)this.__eventListeners={};else if(arguments.length===1&&typeof arguments[0]==\"object\")for(var r in t)e.call(this,r,t[r]);else e.call(this,t,n);return this}function r(e,t){if(!this.__eventListeners)return;var n=this.__eventListeners[e];if(!n)return;for(var r=0,i=n.length;r<i;r++)n[r].call(this,t||{});return this}fabric.Observable={observe:t,stopObserving:n,fire:r,on:t,off:n,trigger:r}}(),fabric.Collection={add:function(){this._objects.push.apply(this._objects,arguments);for(var e=0,t=arguments.length;e<t;e++)this._onObjectAdded(arguments[e]);return this.renderOnAddRemove&&this.renderAll(),this},insertAt:function(e,t,n){var r=this.getObjects();return n?r[t]=e:r.splice(t,0,e),this._onObjectAdded(e),this.renderOnAddRemove&&this.renderAll(),this},remove:function(){var e=this.getObjects(),t;for(var n=0,r=arguments.length;n<r;n++)t=e.indexOf(arguments[n]),t!==-1&&(e.splice(t,1),this._onObjectRemoved(arguments[n]));return this.renderOnAddRemove&&this.renderAll(),this},forEachObject:function(e,t){var n=this.getObjects(),r=n.length;while(r--)e.call(t,n[r],r,n);return this},getObjects:function(e){return typeof e==\"undefined\"?this._objects:this._objects.filter(function(t){return t.type===e})},item:function(e){return this.getObjects()[e]},isEmpty:function(){return this.getObjects().length===0},size:function(){return this.getObjects().length},contains:function(e){return this.getObjects().indexOf(e)>-1},complexity:function(){return this.getObjects().reduce(function(e,t){return e+=t.complexity?t.complexity():0,e},0)}},function(e){var t=Math.sqrt,n=Math.atan2,r=Math.PI/180;fabric.util={removeFromArray:function(e,t){var n=e.indexOf(t);return n!==-1&&e.splice(n,1),e},getRandomInt:function(e,t){return Math.floor(Math.random()*(t-e+1))+e},degreesToRadians:function(e){return e*r},radiansToDegrees:function(e){return e/r},rotatePoint:function(e,t,n){var r=Math.sin(n),i=Math.cos(n);e.subtractEquals(t);var s=e.x*i-e.y*r,o=e.x*r+e.y*i;return(new fabric.Point(s,o)).addEquals(t)},transformPoint:function(e,t,n){return n?new fabric.Point(t[0]*e.x+t[1]*e.y,t[2]*e.x+t[3]*e.y):new fabric.Point(t[0]*e.x+t[1]*e.y+t[4],t[2]*e.x+t[3]*e.y+t[5])},invertTransform:function(e){var t=e.slice(),n=1/(e[0]*e[3]-e[1]*e[2]);t=[n*e[3],-n*e[1],-n*e[2],n*e[0],0,0];var r=fabric.util.transformPoint({x:e[4],y:e[5]},t);return t[4]=-r.x,t[5]=-r.y,t},toFixed:function(e,t){return parseFloat(Number(e).toFixed(t))},parseUnit:function(e){var t=/\\D{0,2}$/.exec(e),n=parseFloat(e);switch(t[0]){case\"mm\":return n*fabric.DPI/25.4;case\"cm\":return n*fabric.DPI/2.54;case\"in\":return n*fabric.DPI;case\"pt\":return n*fabric.DPI/72;case\"pc\":return n*fabric.DPI/72*12;default:return n}},falseFunction:function(){return!1},getKlass:function(e,t){return e=fabric.util.string.camelize(e.charAt(0).toUpperCase()+e.slice(1)),fabric.util.resolveNamespace(t)[e]},resolveNamespace:function(t){if(!t)return fabric;var n=t.split(\".\"),r=n.length,i=e||fabric.window;for(var s=0;s<r;++s)i=i[n[s]];return i},loadImage:function(e,t,n,r){if(!e){t&&t.call(n,e);return}var i=fabric.util.createImage();i.onload=function(){t&&t.call(n,i),i=i.onload=i.onerror=null},i.onerror=function(){fabric.log(\"Error loading \"+i.src),t&&t.call(n,null,!0),i=i.onload=i.onerror=null},e.indexOf(\"data\")!==0&&typeof r!=\"undefined\"&&(i.crossOrigin=r),i.src=e},enlivenObjects:function(e,t,n,r){function i(){++o===u&&t&&t(s)}e=e||[];var s=[],o=0,u=e.length;if(!u){t&&t(s);return}e.forEach(function(e,t){if(!e||!e.type){i();return}var o=fabric.util.getKlass(e.type,n);o.async?o.fromObject(e,function(n,o){o||(s[t]=n,r&&r(e,s[t])),i()}):(s[t]=o.fromObject(e),r&&r(e,s[t]),i())})},groupSVGElements:function(e,t,n){var r;return r=new fabric.PathGroup(e,t),typeof n!=\"undefined\"&&r.setSourcePath(n),r},populateWithProperties:function(e,t,n){if(n&&Object.prototype.toString.call(n)===\"[object Array]\")for(var r=0,i=n.length;r<i;r++)n[r]in e&&(t[n[r]]=e[n[r]])},drawDashedLine:function(e,r,i,s,o,u){var a=s-r,f=o-i,l=t(a*a+f*f),c=n(f,a),h=u.length,p=0,d=!0;e.save(),e.translate(r,i),e.moveTo(0,0),e.rotate(c),r=0;while(l>r)r+=u[p++%h],r>l&&(r=l),e[d?\"lineTo\":\"moveTo\"](r,0),d=!d;e.restore()},createCanvasElement:function(e){return e||(e=fabric.document.createElement(\"canvas\")),!e.getContext&&typeof G_vmlCanvasManager!=\"undefined\"&&G_vmlCanvasManager.initElement(e),e},createImage:function(){return fabric.isLikelyNode?new(require(\"canvas\").Image):fabric.document.createElement(\"img\")},createAccessors:function(e){var t=e.prototype;for(var n=t.stateProperties.length;n--;){var r=t.stateProperties[n],i=r.charAt(0).toUpperCase()+r.slice(1),s=\"set\"+i,o=\"get\"+i;t[o]||(t[o]=function(e){return new Function('return this.get(\"'+e+'\")')}(r)),t[s]||(t[s]=function(e){return new Function(\"value\",'return this.set(\"'+e+'\", value)')}(r))}},clipContext:function(e,t){t.save(),t.beginPath(),e.clipTo(t),t.clip()},multiplyTransformMatrices:function(e,t){var n=[[e[0],e[2],e[4]],[e[1],e[3],e[5]],[0,0,1]],r=[[t[0],t[2],t[4]],[t[1],t[3],t[5]],[0,0,1]],i=[];for(var s=0;s<3;s++){i[s]=[];for(var o=0;o<3;o++){var u=0;for(var a=0;a<3;a++)u+=n[s][a]*r[a][o];i[s][o]=u}}return[i[0][0],i[1][0],i[0][1],i[1][1],i[0][2],i[1][2]]},getFunctionBody:function(e){return(String(e).match(/function[^{]*\\{([\\s\\S]*)\\}/)||{})[1]},isTransparent:function(e,t,n,r){r>0&&(t>r?t-=r:t=0,n>r?n-=r:n=0);var i=!0,s=e.getImageData(t,n,r*2||1,r*2||1);for(var o=3,u=s.data.length;o<u;o+=4){var a=s.data[o];i=a<=0;if(i===!1)break}return s=null,i}}}(typeof exports!=\"undefined\"?exports:this),function(){function i(t,n,i,u,a,f,l){var c=r.call(arguments);if(e[c])return e[c];var h=Math.PI,p=l*h/180,d=Math.sin(p),v=Math.cos(p),m=0,g=0;i=Math.abs(i),u=Math.abs(u);var y=-v*t*.5-d*n*.5,b=-v*n*.5+d*t*.5,w=i*i,E=u*u,S=b*b,x=y*y,T=w*E-w*S-E*x,N=0;if(T<0){var C=Math.sqrt(1-T/(w*E));i*=C,u*=C}else N=(a===f?-1:1)*Math.sqrt(T/(w*S+E*x));var k=N*i*b/u,L=-N*u*y/i,A=v*k-d*L+t*.5,O=d*k+v*L+n*.5,M=o(1,0,(y-k)/i,(b-L)/u),_=o((y-k)/i,(b-L)/u,(-y-k)/i,(-b-L)/u);f===0&&_>0?_-=2*h:f===1&&_<0&&(_+=2*h);var D=Math.ceil(Math.abs(_/h*2)),P=[],H=_/D,B=8/3*Math.sin(H/4)*Math.sin(H/4)/Math.sin(H/2),j=M+H;for(var F=0;F<D;F++)P[F]=s(M,j,v,d,i,u,A,O,B,m,g),m=P[F][4],g=P[F][5],M=j,j+=H;return e[c]=P,P}function s(e,n,i,s,o,u,a,f,l,c,h){var p=r.call(arguments);if(t[p])return t[p];var d=Math.cos(e),v=Math.sin(e),m=Math.cos(n),g=Math.sin(n),y=i*o*m-s*u*g+a,b=s*o*m+i*u*g+f,w=c+l*(-i*o*v-s*u*d),E=h+l*(-s*o*v+i*u*d),S=y+l*(i*o*g+s*u*m),x=b+l*(s*o*g-i*u*m);return t[p]=[w,E,S,x,y,b],t[p]}function o(e,t,n,r){var i=Math.atan2(t,e),s=Math.atan2(r,n);return s>=i?s-i:2*Math.PI-(i-s)}function u(e,t,i,s,o,u,a,f){var l=r.call(arguments);if(n[l])return n[l];var c=Math.sqrt,h=Math.min,p=Math.max,d=Math.abs,v=[],m=[[],[]],g,y,b,w,E,S,x,T;y=6*e-12*i+6*o,g=-3*e+9*i-9*o+3*a,b=3*i-3*e;for(var N=0;N<2;++N){N>0&&(y=6*t-12*s+6*u,g=-3*t+9*s-9*u+3*f,b=3*s-3*t);if(d(g)<1e-12){if(d(y)<1e-12)continue;w=-b/y,0<w&&w<1&&v.push(w);continue}x=y*y-4*b*g;if(x<0)continue;T=c(x),E=(-y+T)/(2*g),0<E&&E<1&&v.push(E),S=(-y-T)/(2*g),0<S&&S<1&&v.push(S)}var C,k,L=v.length,A=L,O;while(L--)w=v[L],O=1-w,C=O*O*O*e+3*O*O*w*i+3*O*w*w*o+w*w*w*a,m[0][L]=C,k=O*O*O*t+3*O*O*w*s+3*O*w*w*u+w*w*w*f,m[1][L]=k;m[0][A]=e,m[1][A]=t,m[0][A+1]=a,m[1][A+1]=f;var M=[{x:h.apply(null,m[0]),y:h.apply(null,m[1])},{x:p.apply(null,m[0]),y:p.apply(null,m[1])}];return n[l]=M,M}var e={},t={},n={},r=Array.prototype.join;fabric.util.drawArc=function(e,t,n,r){var s=r[0],o=r[1],u=r[2],a=r[3],f=r[4],l=r[5],c=r[6],h=[[],[],[],[]],p=i(l-t,c-n,s,o,a,f,u);for(var d=0,v=p.length;d<v;d++)h[d][0]=p[d][0]+t,h[d][1]=p[d][1]+n,h[d][2]=p[d][2]+t,h[d][3]=p[d][3]+n,h[d][4]=p[d][4]+t,h[d][5]=p[d][5]+n,e.bezierCurveTo.apply(e,h[d])},fabric.util.getBoundsOfArc=function(e,t,n,r,s,o,a,f,l){var c=0,h=0,p=[],d=[],v=i(f-e,l-t,n,r,o,a,s);for(var m=0,g=v.length;m<g;m++)p=u(c,h,v[m][0],v[m][1],v[m][2],v[m][3],v[m][4],v[m][5]),p[0].x+=e,p[0].y+=t,p[1].x+=e,p[1].y+=t,d.push(p[0]),d.push(p[1]),c=v[m][4],h=v[m][5];return d},fabric.util.getBoundsOfCurve=u}(),function(){function t(t,n){var r=e.call(arguments,2),i=[];for(var s=0,o=t.length;s<o;s++)i[s]=r.length?t[s][n].apply(t[s],r):t[s][n].call(t[s]);return i}function n(e,t){return i(e,t,function(e,t){return e>=t})}function r(e,t){return i(e,t,function(e,t){return e<t})}function i(e,t,n){if(!e||e.length===0)return;var r=e.length-1,i=t?e[r][t]:e[r];if(t)while(r--)n(e[r][t],i)&&(i=e[r][t]);else while(r--)n(e[r],i)&&(i=e[r]);return i}var e=Array.prototype.slice;Array.prototype.indexOf||(Array.prototype.indexOf=function(e){if(this===void 0||this===null)throw new TypeError;var t=Object(this),n=t.length>>>0;if(n===0)return-1;var r=0;arguments.length>0&&(r=Number(arguments[1]),r!==r?r=0:r!==0&&r!==Number.POSITIVE_INFINITY&&r!==Number.NEGATIVE_INFINITY&&(r=(r>0||-1)*Math.floor(Math.abs(r))));if(r>=n)return-1;var i=r>=0?r:Math.max(n-Math.abs(r),0);for(;i<n;i++)if(i in t&&t[i]===e)return i;return-1}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){for(var n=0,r=this.length>>>0;n<r;n++)n in this&&e.call(t,this[n],n,this)}),Array.prototype.map||(Array.prototype.map=function(e,t){var n=[];for(var r=0,i=this.length>>>0;r<i;r++)r in this&&(n[r]=e.call(t,this[r],r,this));return n}),Array.prototype.every||(Array.prototype.every=function(e,t){for(var n=0,r=this.length>>>0;n<r;n++)if(n in this&&!e.call(t,this[n],n,this))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(e,t){for(var n=0,r=this.length>>>0;n<r;n++)if(n in this&&e.call(t,this[n],n,this))return!0;return!1}),Array.prototype.filter||(Array.prototype.filter=function(e,t){var n=[],r;for(var i=0,s=this.length>>>0;i<s;i++)i in this&&(r=this[i],e.call(t,r,i,this)&&n.push(r));return n}),Array.prototype.reduce||(Array.prototype.reduce=function(e){var t=this.length>>>0,n=0,r;if(arguments.length>1)r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n<t;n++)n in this&&(r=e.call(null,r,this[n],n,this));return r}),fabric.util.array={invoke:t,min:r,max:n}}(),function(){function e(e,t){for(var n in t)e[n]=t[n];return e}function t(t){return e({},t)}fabric.util.object={extend:e,clone:t}}(),function(){function e(e){return e.replace(/-+(.)?/g,function(e,t){return t?t.toUpperCase():\"\"})}function t(e,t){return e.charAt(0).toUpperCase()+(t?e.slice(1):e.slice(1).toLowerCase())}function n(e){return e.replace(/&/g,\"&amp;\").replace(/\"/g,\"&quot;\").replace(/'/g,\"&apos;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\")}String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^[\\s\\xA0]+/,\"\").replace(/[\\s\\xA0]+$/,\"\")}),fabric.util.string={camelize:e,capitalize:t,escapeXml:n}}(),function(){var e=Array.prototype.slice,t=Function.prototype.apply,n=function(){};Function.prototype.bind||(Function.prototype.bind=function(r){var i=this,s=e.call(arguments,1),o;return s.length?o=function(){return t.call(i,this instanceof n?this:r,s.concat(e.call(arguments)))}:o=function(){return t.call(i,this instanceof n?this:r,arguments)},n.prototype=this.prototype,o.prototype=new n,o})}(),function(){function i(){}function s(t){var n=this.constructor.superclass.prototype[t];return arguments.length>1?n.apply(this,e.call(arguments,1)):n.call(this)}function o(){function u(){this.initialize.apply(this,arguments)}var n=null,o=e.call(arguments,0);typeof o[0]==\"function\"&&(n=o.shift()),u.superclass=n,u.subclasses=[],n&&(i.prototype=n.prototype,u.prototype=new i,n.subclasses.push(u));for(var a=0,f=o.length;a<f;a++)r(u,o[a],n);return u.prototype.initialize||(u.prototype.initialize=t),u.prototype.constructor=u,u.prototype.callSuper=s,u}var e=Array.prototype.slice,t=function(){},n=function(){for(var e in{toString:1})if(e===\"toString\")return!1;return!0}(),r=function(e,t,r){for(var i in t)i in e.prototype&&typeof e.prototype[i]==\"function\"&&(t[i]+\"\").indexOf(\"callSuper\")>-1?e.prototype[i]=function(e){return function(){var n=this.constructor.superclass;this.constructor.superclass=r;var i=t[e].apply(this,arguments);this.constructor.superclass=n;if(e!==\"initialize\")return i}}(i):e.prototype[i]=t[i],n&&(t.toString!==Object.prototype.toString&&(e.prototype.toString=t.toString),t.valueOf!==Object.prototype.valueOf&&(e.prototype.valueOf=t.valueOf))};fabric.util.createClass=o}(),function(){function t(e){var t=Array.prototype.slice.call(arguments,1),n,r,i=t.length;for(r=0;r<i;r++){n=typeof e[t[r]];if(!/^(?:function|object|unknown)$/.test(n))return!1}return!0}function s(e,t){return{handler:t,wrappedHandler:o(e,t)}}function o(e,t){return function(r){t.call(n(e),r||fabric.window.event)}}function u(e,t){return function(n){if(c[e]&&c[e][t]){var r=c[e][t];for(var i=0,s=r.length;i<s;i++)r[i].call(this,n||fabric.window.event)}}}function d(t,n){t||(t=fabric.window.event);var r=t.target||(typeof t.srcElement!==e?t.srcElement:null),i=fabric.util.getScrollLeftTop(r,n);return{x:v(t)+i.left,y:m(t)+i.top}}function g(e,t,n){var r=e.type===\"touchend\"?\"changedTouches\":\"touches\";return e[r]&&e[r][0]?e[r][0][t]-(e[r][0][t]-e[r][0][n])||e[n]:e[n]}var e=\"unknown\",n,r,i=function(){var e=0;return function(t){return t.__uniqueID||(t.__uniqueID=\"uniqueID__\"+e++)}}();(function(){var e={};n=function(t){return e[t]},r=function(t,n){e[t]=n}})();var a=t(fabric.document.documentElement,\"addEventListener\",\"removeEventListener\")&&t(fabric.window,\"addEventListener\",\"removeEventListener\"),f=t(fabric.document.documentElement,\"attachEvent\",\"detachEvent\")&&t(fabric.window,\"attachEvent\",\"detachEvent\"),l={},c={},h,p;a?(h=function(e,t,n){e.addEventListener(t,n,!1)},p=function(e,t,n){e.removeEventListener(t,n,!1)}):f?(h=function(e,t,n){var o=i(e);r(o,e),l[o]||(l[o]={}),l[o][t]||(l[o][t]=[]);var u=s(o,n);l[o][t].push(u),e.attachEvent(\"on\"+t,u.wrappedHandler)},p=function(e,t,n){var r=i(e),s;if(l[r]&&l[r][t])for(var o=0,u=l[r][t].length;o<u;o++)s=l[r][t][o],s&&s.handler===n&&(e.detachEvent(\"on\"+t,s.wrappedHandler),l[r][t][o]=null)}):(h=function(e,t,n){var r=i(e);c[r]||(c[r]={});if(!c[r][t]){c[r][t]=[];var s=e[\"on\"+t];s&&c[r][t].push(s),e[\"on\"+t]=u(r,t)}c[r][t].push(n)},p=function(e,t,n){var r=i(e);if(c[r]&&c[r][t]){var s=c[r][t];for(var o=0,u=s.length;o<u;o++)s[o]===n&&s.splice(o,1)}}),fabric.util.addListener=h,fabric.util.removeListener=p;var v=function(t){return typeof t.clientX!==e?t.clientX:0},m=function(t){return typeof t.clientY!==e?t.clientY:0};fabric.isTouchSupported&&(v=function(e){return g(e,\"pageX\",\"clientX\")},m=function(e){return g(e,\"pageY\",\"clientY\")}),fabric.util.getPointer=d,fabric.util.object.extend(fabric.util,fabric.Observable)}(),function(){function e(e,t){var n=e.style;if(!n)return e;if(typeof t==\"string\")return e.style.cssText+=\";\"+t,t.indexOf(\"opacity\")>-1?s(e,t.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1]):e;for(var r in t)if(r===\"opacity\")s(e,t[r]);else{var i=r===\"float\"||r===\"cssFloat\"?typeof n.styleFloat==\"undefined\"?\"cssFloat\":\"styleFloat\":r;n[i]=t[r]}return e}var t=fabric.document.createElement(\"div\"),n=typeof t.style.opacity==\"string\",r=typeof t.style.filter==\"string\",i=/alpha\\s*\\(\\s*opacity\\s*=\\s*([^\\)]+)\\)/,s=function(e){return e};n?s=function(e,t){return e.style.opacity=t,e}:r&&(s=function(e,t){var n=e.style;return e.currentStyle&&!e.currentStyle.hasLayout&&(n.zoom=1),i.test(n.filter)?(t=t>=.9999?\"\":\"alpha(opacity=\"+t*100+\")\",n.filter=n.filter.replace(i,t)):n.filter+=\" alpha(opacity=\"+t*100+\")\",e}),fabric.util.setStyle=e}(),function(){function t(e){return typeof e==\"string\"?fabric.document.getElementById(e):e}function s(e,t){var n=fabric.document.createElement(e);for(var r in t)r===\"class\"?n.className=t[r]:r===\"for\"?n.htmlFor=t[r]:n.setAttribute(r,t[r]);return n}function o(e,t){e&&(\" \"+e.className+\" \").indexOf(\" \"+t+\" \")===-1&&(e.className+=(e.className?\" \":\"\")+t)}function u(e,t,n){return typeof t==\"string\"&&(t=s(t,n)),e.parentNode&&e.parentNode.replaceChild(t,e),t.appendChild(e),t}function a(e,t){var n,r,i=0,s=0,o=fabric.document.documentElement,u=fabric.document.body||{scrollLeft:0,scrollTop:0};r=e;while(e&&e.parentNode&&!n)e=e.parentNode,e.nodeType===1&&fabric.util.getElementStyle(e,\"position\")===\"fixed\"&&(n=e),e.nodeType===1&&r!==t&&fabric.util.getElementStyle(e,\"position\")===\"absolute\"?(i=0,s=0):e===fabric.document?(i=u.scrollLeft||o.scrollLeft||0,s=u.scrollTop||o.scrollTop||0):(i+=e.scrollLeft||0,s+=e.scrollTop||0);return{left:i,top:s}}function f(e){var t,n=e&&e.ownerDocument,r={left:0,top:0},i={left:0,top:0},s,o={borderLeftWidth:\"left\",borderTopWidth:\"top\",paddingLeft:\"left\",paddingTop:\"top\"};if(!n)return{left:0,top:0};for(var u in o)i[o[u]]+=parseInt(l(e,u),10)||0;return t=n.documentElement,typeof e.getBoundingClientRect!=\"undefined\"&&(r=e.getBoundingClientRect()),s=fabric.util.getScrollLeftTop(e,null),{left:r.left+s.left-(t.clientLeft||0)+i.left,top:r.top+s.top-(t.clientTop||0)+i.top}}var e=Array.prototype.slice,n,r=function(t){return e.call(t,0)};try{n=r(fabric.document.childNodes)instanceof Array}catch(i){}n||(r=function(e){var t=new Array(e.length),n=e.length;while(n--)t[n]=e[n];return t});var l;fabric.document.defaultView&&fabric.document.defaultView.getComputedStyle?l=function(e,t){var n=fabric.document.defaultView.getComputedStyle(e,null);return n?n[t]:undefined}:l=function(e,t){var n=e.style[t];return!n&&e.currentStyle&&(n=e.currentStyle[t]),n},function(){function n(e){return typeof e.onselectstart!=\"undefined\"&&(e.onselectstart=fabric.util.falseFunction),t?e.style[t]=\"none\":typeof e.unselectable==\"string\"&&(e.unselectable=\"on\"),e}function r(e){return typeof e.onselectstart!=\"undefined\"&&(e.onselectstart=null),t?e.style[t]=\"\":typeof e.unselectable==\"string\"&&(e.unselectable=\"\"),e}var e=fabric.document.documentElement.style,t=\"userSelect\"in e?\"userSelect\":\"MozUserSelect\"in e?\"MozUserSelect\":\"WebkitUserSelect\"in e?\"WebkitUserSelect\":\"KhtmlUserSelect\"in e?\"KhtmlUserSelect\":\"\";fabric.util.makeElementUnselectable=n,fabric.util.makeElementSelectable=r}(),function(){function e(e,t){var n=fabric.document.getElementsByTagName(\"head\")[0],r=fabric.document.createElement(\"script\"),i=!0;r.onload=r.onreadystatechange=function(e){if(i){if(typeof this.readyState==\"string\"&&this.readyState!==\"loaded\"&&this.readyState!==\"complete\")return;i=!1,t(e||fabric.window.event),r=r.onload=r.onreadystatechange=null}},r.src=e,n.appendChild(r)}fabric.util.getScript=e}(),fabric.util.getById=t,fabric.util.toArray=r,fabric.util.makeElement=s,fabric.util.addClass=o,fabric.util.wrapElement=u,fabric.util.getScrollLeftTop=a,fabric.util.getElementOffset=f,fabric.util.getElementStyle=l}(),function(){function e(e,t){return e+(/\\?/.test(e)?\"&\":\"?\")+t}function n(){}function r(r,i){i||(i={});var s=i.method?i.method.toUpperCase():\"GET\",o=i.onComplete||function(){},u=t(),a;return u.onreadystatechange=function(){u.readyState===4&&(o(u),u.onreadystatechange=n)},s===\"GET\"&&(a=null,typeof i.parameters==\"string\"&&(r=e(r,i.parameters))),u.open(s,r,!0),(s===\"POST\"||s===\"PUT\")&&u.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\"),u.send(a),u}var t=function(){var e=[function(){return new ActiveXObject(\"Microsoft.XMLHTTP\")},function(){return new ActiveXObject(\"Msxml2.XMLHTTP\")},function(){return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\")},function(){return new XMLHttpRequest}];for(var t=e.length;t--;)try{var n=e[t]();if(n)return e[t]}catch(r){}}();fabric.util.request=r}(),fabric.log=function(){},fabric.warn=function(){},typeof console!=\"undefined\"&&[\"log\",\"warn\"].forEach(function(e){typeof console[e]!=\"undefined\"&&console[e].apply&&(fabric[e]=function(){return console[e].apply(console,arguments)})}),function(){function e(e){n(function(t){e||(e={});var r=t||+(new Date),i=e.duration||500,s=r+i,o,u=e.onChange||function(){},a=e.abort||function(){return!1},f=e.easing||function(e,t,n,r){return-n*Math.cos(e/r*(Math.PI/2))+n+t},l=\"startValue\"in e?e.startValue:0,c=\"endValue\"in e?e.endValue:100,h=e.byValue||c-l;e.onStart&&e.onStart(),function p(t){o=t||+(new Date);var c=o>s?i:o-r;if(a()){e.onComplete&&e.onComplete();return}u(f(c,l,h,i));if(o>s){e.onComplete&&e.onComplete();return}n(p)}(r)})}function n(){return t.apply(fabric.window,arguments)}var t=fabric.window.requestAnimationFrame||fabric.window.webkitRequestAnimationFrame||fabric.window.mozRequestAnimationFrame||fabric.window.oRequestAnimationFrame||fabric.window.msRequestAnimationFrame||function(e){fabric.window.setTimeout(e,1e3/60)};fabric.util.animate=e,fabric.util.requestAnimFrame=n}(),function(){function e(e,t,n,r){return e<Math.abs(t)?(e=t,r=n/4):r=n/(2*Math.PI)*Math.asin(t/e),{a:e,c:t,p:n,s:r}}function t(e,t,n){return e.a*Math.pow(2,10*(t-=1))*Math.sin((t*n-e.s)*2*Math.PI/e.p)}function n(e,t,n,r){return n*((e=e/r-1)*e*e+1)+t}function r(e,t,n,r){return e/=r/2,e<1?n/2*e*e*e+t:n/2*((e-=2)*e*e+2)+t}function i(e,t,n,r){return n*(e/=r)*e*e*e+t}function s(e,t,n,r){return-n*((e=e/r-1)*e*e*e-1)+t}function o(e,t,n,r){return e/=r/2,e<1?n/2*e*e*e*e+t:-n/2*((e-=2)*e*e*e-2)+t}function u(e,t,n,r){return n*(e/=r)*e*e*e*e+t}function a(e,t,n,r){return n*((e=e/r-1)*e*e*e*e+1)+t}function f(e,t,n,r){return e/=r/2,e<1?n/2*e*e*e*e*e+t:n/2*((e-=2)*e*e*e*e+2)+t}function l(e,t,n,r){return-n*Math.cos(e/r*(Math.PI/2))+n+t}function c(e,t,n,r){return n*Math.sin(e/r*(Math.PI/2))+t}function h(e,t,n,r){return-n/2*(Math.cos(Math.PI*e/r)-1)+t}function p(e,t,n,r){return e===0?t:n*Math.pow(2,10*(e/r-1))+t}function d(e,t,n,r){return e===r?t+n:n*(-Math.pow(2,-10*e/r)+1)+t}function v(e,t,n,r){return e===0?t:e===r?t+n:(e/=r/2,e<1?n/2*Math.pow(2,10*(e-1))+t:n/2*(-Math.pow(2,-10*--e)+2)+t)}function m(e,t,n,r){return-n*(Math.sqrt(1-(e/=r)*e)-1)+t}function g(e,t,n,r){return n*Math.sqrt(1-(e=e/r-1)*e)+t}function y(e,t,n,r){return e/=r/2,e<1?-n/2*(Math.sqrt(1-e*e)-1)+t:n/2*(Math.sqrt(1-(e-=2)*e)+1)+t}function b(n,r,i,s){var o=1.70158,u=0,a=i;if(n===0)return r;n/=s;if(n===1)return r+i;u||(u=s*.3);var f=e(a,i,u,o);return-t(f,n,s)+r}function w(t,n,r,i){var s=1.70158,o=0,u=r;if(t===0)return n;t/=i;if(t===1)return n+r;o||(o=i*.3);var a=e(u,r,o,s);return a.a*Math.pow(2,-10*t)*Math.sin((t*i-a.s)*2*Math.PI/a.p)+a.c+n}function E(n,r,i,s){var o=1.70158,u=0,a=i;if(n===0)return r;n/=s/2;if(n===2)return r+i;u||(u=s*.3*1.5);var f=e(a,i,u,o);return n<1?-0.5*t(f,n,s)+r:f.a*Math.pow(2,-10*(n-=1))*Math.sin((n*s-f.s)*2*Math.PI/f.p)*.5+f.c+r}function S(e,t,n,r,i){return i===undefined&&(i=1.70158),n*(e/=r)*e*((i+1)*e-i)+t}function x(e,t,n,r,i){return i===undefined&&(i=1.70158),n*((e=e/r-1)*e*((i+1)*e+i)+1)+t}function T(e,t,n,r,i){return i===undefined&&(i=1.70158),e/=r/2,e<1?n/2*e*e*(((i*=1.525)+1)*e-i)+t:n/2*((e-=2)*e*(((i*=1.525)+1)*e+i)+2)+t}function N(e,t,n,r){return n-C(r-e,0,n,r)+t}function C(e,t,n,r){return(e/=r)<1/2.75?n*7.5625*e*e+t:e<2/2.75?n*(7.5625*(e-=1.5/2.75)*e+.75)+t:e<2.5/2.75?n*(7.5625*(e-=2.25/2.75)*e+.9375)+t:n*(7.5625*(e-=2.625/2.75)*e+.984375)+t}function k(e,t,n,r){return e<r/2?N(e*2,0,n,r)*.5+t:C(e*2-r,0,n,r)*.5+n*.5+t}fabric.util.ease={easeInQuad:function(e,t,n,r){return n*(e/=r)*e+t},easeOutQuad:function(e,t,n,r){return-n*(e/=r)*(e-2)+t},easeInOutQuad:function(e,t,n,r){return e/=r/2,e<1?n/2*e*e+t:-n/2*(--e*(e-2)-1)+t},easeInCubic:function(e,t,n,r){return n*(e/=r)*e*e+t},easeOutCubic:n,easeInOutCubic:r,easeInQuart:i,easeOutQuart:s,easeInOutQuart:o,easeInQuint:u,easeOutQuint:a,easeInOutQuint:f,easeInSine:l,easeOutSine:c,easeInOutSine:h,easeInExpo:p,easeOutExpo:d,easeInOutExpo:v,easeInCirc:m,easeOutCirc:g,easeInOutCirc:y,easeInElastic:b,easeOutElastic:w,easeInOutElastic:E,easeInBack:S,easeOutBack:x,easeInOutBack:T,easeInBounce:N,easeOutBounce:C,easeInOutBounce:k}}(),function(e){\"use strict\";function l(e){return e in a?a[e]:e}function c(e,n,r){var i=Object.prototype.toString.call(n)===\"[object Array]\",s;return e!==\"fill\"&&e!==\"stroke\"||n!==\"none\"?e===\"strokeDashArray\"?n=n.replace(/,/g,\" \").split(/\\s+/).map(function(e){return parseFloat(e)}):e===\"transformMatrix\"?r&&r.transformMatrix?n=u(r.transformMatrix,t.parseTransformAttribute(n)):n=t.parseTransformAttribute(n):e===\"visible\"?(n=n===\"none\"||n===\"hidden\"?!1:!0,r&&r.visible===!1&&(n=!1)):e===\"originX\"?n=n===\"start\"?\"left\":n===\"end\"?\"right\":\"center\":s=i?n.map(o):o(n):n=\"\",!i&&isNaN(s)?n:s}function h(e){for(var n in f){if(!e[n]||typeof e[f[n]]==\"undefined\")continue;if(e[n].indexOf(\"url(\")===0)continue;var r=new t.Color(e[n]);e[n]=r.setAlpha(s(r.getAlpha()*e[f[n]],2)).toRgba()}return e}function p(e,t){var n=e.match(/(normal|italic)?\\s*(normal|small-caps)?\\s*(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\s*(\\d+)px(?:\\/(normal|[\\d\\.]+))?\\s+(.*)/);if(!n)return;var r=n[1],i=n[3],s=n[4],o=n[5],u=n[6];r&&(t.fontStyle=r),i&&(t.fontWeight=isNaN(parseFloat(i))?i:parseFloat(i)),s&&(t.fontSize=parseFloat(s)),u&&(t.fontFamily=u),o&&(t.lineHeight=o===\"normal\"?1:o)}function d(e,t){var n,r;e.replace(/;$/,\"\").split(\";\").forEach(function(e){var i=e.split(\":\");n=l(i[0].trim().toLowerCase()),r=c(n,i[1].trim()),n===\"font\"?p(r,t):t[n]=r})}function v(e,t){var n,r;for(var i in e){if(typeof e[i]==\"undefined\")continue;n=l(i.toLowerCase()),r=c(n,e[i]),n===\"font\"?p(r,t):t[n]=r}}function m(e,n){var r={};for(var i in t.cssRules[n])if(g(e,i.split(\" \")))for(var s in t.cssRules[n][i])r[s]=t.cssRules[n][i][s];return r}function g(e,t){var n,r=!0;return n=b(e,t.pop()),n&&t.length&&(r=y(e,t)),n&&r&&t.length===0}function y(e,t){var n,r=!0;while(e.parentNode&&e.parentNode.nodeType===1&&t.length)r&&(n=t.pop()),e=e.parentNode,r=b(e,n);return t.length===0}function b(e,t){var n=e.nodeName,r=e.getAttribute(\"class\"),i=e.getAttribute(\"id\"),s;s=new RegExp(\"^\"+n,\"i\"),t=t.replace(s,\"\"),i&&t.length&&(s=new RegExp(\"#\"+i+\"(?![a-zA-Z\\\\-]+)\",\"i\"),t=t.replace(s,\"\"));if(r&&t.length){r=r.split(\" \");for(var o=r.length;o--;)s=new RegExp(\"\\\\.\"+r[o]+\"(?![a-zA-Z\\\\-]+)\",\"i\"),t=t.replace(s,\"\")}return t.length===0}function w(e){var t=e.getElementsByTagName(\"use\");while(t.length){var n=t[0],r=n.getAttribute(\"xlink:href\").substr(1),i=n.getAttribute(\"x\")||0,s=n.getAttribute(\"y\")||0,o=e.getElementById(r).cloneNode(!0),u=(n.getAttribute(\"transform\")||\"\")+\" translate(\"+i+\", \"+s+\")\",a;for(var f=0,l=n.attributes,c=l.length;f<c;f++){var h=l.item(f);if(h.nodeName===\"x\"||h.nodeName===\"y\"||h.nodeName===\"xlink:href\")continue;h.nodeName===\"transform\"?u=u+\" \"+h.nodeValue:o.setAttribute(h.nodeName,h.nodeValue)}o.setAttribute(\"transform\",u),o.removeAttribute(\"id\"),a=n.parentNode,a.replaceChild(o,n)}}function E(e,t){t[3]=t[0]=t[0]>t[3]?t[3]:t[0];if(t[0]===1&&t[3]===1&&t[4]===0&&t[5]===0)return;var n=e.ownerDocument.createElement(\"g\");while(e.firstChild!=null)n.appendChild(e.firstChild);n.setAttribute(\"transform\",\"matrix(\"+t[0]+\" \"+t[1]+\" \"+t[2]+\" \"+t[3]+\" \"+t[4]+\" \"+t[5]+\")\"),e.appendChild(n)}function x(e){var n=e.objects,i=e.options;return n=n.map(function(e){return t[r(e.type)].fromObject(e)}),{objects:n,options:i}}function T(e,t,n){t[n]&&t[n].toSVG&&e.push('<pattern x=\"0\" y=\"0\" id=\"',n,'Pattern\" ','width=\"',t[n].source.width,'\" height=\"',t[n].source.height,'\" patternUnits=\"userSpaceOnUse\">','<image x=\"0\" y=\"0\" ','width=\"',t[n].source.width,'\" height=\"',t[n].source.height,'\" xlink:href=\"',t[n].source.src,'\"></image></pattern>')}var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.string.capitalize,i=t.util.object.clone,s=t.util.toFixed,o=t.util.parseUnit,u=t.util.multiplyTransformMatrices,a={cx:\"left\",x:\"left\",r:\"radius\",cy:\"top\",y:\"top\",display:\"visible\",visibility:\"visible\",transform:\"transformMatrix\",\"fill-opacity\":\"fillOpacity\",\"fill-rule\":\"fillRule\",\"font-family\":\"fontFamily\",\"font-size\":\"fontSize\",\"font-style\":\"fontStyle\",\"font-weight\":\"fontWeight\",\"stroke-dasharray\":\"strokeDashArray\",\"stroke-linecap\":\"strokeLineCap\",\"stroke-linejoin\":\"strokeLineJoin\",\"stroke-miterlimit\":\"strokeMiterLimit\",\"stroke-opacity\":\"strokeOpacity\",\"stroke-width\":\"strokeWidth\",\"text-decoration\":\"textDecoration\",\"text-anchor\":\"originX\"},f={stroke:\"strokeOpacity\",fill:\"fillOpacity\"};t.cssRules={},t.gradientDefs={},t.parseTransformAttribute=function(){function e(e,t){var n=t[0];e[0]=Math.cos(n),e[1]=Math.sin(n),e[2]=-Math.sin(n),e[3]=Math.cos(n)}function n(e,t){var n=t[0],r=t.length===2?t[1]:t[0];e[0]=n,e[3]=r}function r(e,n){e[2]=Math.tan(t.util.degreesToRadians(n[0]))}function i(e,n){e[1]=Math.tan(t.util.degreesToRadians(n[0]))}function s(e,t){e[4]=t[0],t.length===2&&(e[5]=t[1])}var o=[1,0,0,1,0,0],u=\"(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)\",a=\"(?:\\\\s+,?\\\\s*|,\\\\s*)\",f=\"(?:(skewX)\\\\s*\\\\(\\\\s*(\"+u+\")\\\\s*\\\\))\",l=\"(?:(skewY)\\\\s*\\\\(\\\\s*(\"+u+\")\\\\s*\\\\))\",c=\"(?:(rotate)\\\\s*\\\\(\\\\s*(\"+u+\")(?:\"+a+\"(\"+u+\")\"+a+\"(\"+u+\"))?\\\\s*\\\\))\",h=\"(?:(scale)\\\\s*\\\\(\\\\s*(\"+u+\")(?:\"+a+\"(\"+u+\"))?\\\\s*\\\\))\",p=\"(?:(translate)\\\\s*\\\\(\\\\s*(\"+u+\")(?:\"+a+\"(\"+u+\"))?\\\\s*\\\\))\",d=\"(?:(matrix)\\\\s*\\\\(\\\\s*(\"+u+\")\"+a+\"(\"+u+\")\"+a+\"(\"+u+\")\"+a+\"(\"+u+\")\"+a+\"(\"+u+\")\"+a+\"(\"+u+\")\"+\"\\\\s*\\\\))\",v=\"(?:\"+d+\"|\"+p+\"|\"+h+\"|\"+c+\"|\"+f+\"|\"+l+\")\",m=\"(?:\"+v+\"(?:\"+a+v+\")*\"+\")\",g=\"^\\\\s*(?:\"+m+\"?)\\\\s*$\",y=new RegExp(g),b=new RegExp(v,\"g\");return function(u){var a=o.concat(),f=[];if(!u||u&&!y.test(u))return a;u.replace(b,function(u){var l=(new RegExp(v)).exec(u).filter(function(e){return e!==\"\"&&e!=null}),c=l[1],h=l.slice(2).map(parseFloat);switch(c){case\"translate\":s(a,h);break;case\"rotate\":h[0]=t.util.degreesToRadians(h[0]),e(a,h);break;case\"scale\":n(a,h);break;case\"skewX\":r(a,h);break;case\"skewY\":i(a,h);break;case\"matrix\":a=h}f.push(a.concat()),a=o.concat()});var l=f[0];while(f.length>1)f.shift(),l=t.util.multiplyTransformMatrices(l,f[0]);return l}}(),t.parseSVGDocument=function(){function s(e,t){while(e&&(e=e.parentNode))if(t.test(e.nodeName))return!0;return!1}var e=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/,n=\"(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)\",r=new RegExp(\"^\\\\s*(\"+n+\"+)\\\\s*,?\"+\"\\\\s*(\"+n+\"+)\\\\s*,?\"+\"\\\\s*(\"+n+\"+)\\\\s*,?\"+\"\\\\s*(\"+n+\"+)\\\\s*\"+\"$\");return function(n,u,a){if(!n)return;var f=new Date,l=t.Object.__uid++;w(n);var c=n.getAttribute(\"viewBox\"),h=o(n.getAttribute(\"width\")||\"100%\"),p=o(n.getAttribute(\"height\")||\"100%\"),d,v;if(c&&(c=c.match(r))){var m=parseFloat(c[1]),g=parseFloat(c[2]),y=1,b=1;d=parseFloat(c[3]),v=parseFloat(c[4]),h&&h!==d&&(y=h/d),p&&p!==v&&(b=p/v),E(n,[y,0,0,b,y*-m,b*-g])}var S=t.util.toArray(n.getElementsByTagName(\"*\"));if(S.length===0&&t.isLikelyNode){S=n.selectNodes('//*[name(.)!=\"svg\"]');var x=[];for(var T=0,N=S.length;T<N;T++)x[T]=S[T];S=x}var C=S.filter(function(t){return e.test(t.tagName)&&!s(t,/^(?:pattern|defs)$/)});if(!C||C&&!C.length){u&&u([],{});return}var k={width:h?h:d,height:p?p:v,widthAttr:h,heightAttr:p,svgUid:l};t.gradientDefs[l]=t.getGradientDefs(n),t.cssRules[l]=t.getCSSRules(n),t.parseElements(C,function(e){t.documentParsingTime=new Date-f,u&&u(e,k)},i(k),a)}}();var S={has:function(e,t){t(!1)},get:function(){},set:function(){}};n(t,{getGradientDefs:function(e){var t=e.getElementsByTagName(\"linearGradient\"),n=e.getElementsByTagName(\"radialGradient\"),r,i,s=0,o,u,a=[],f={},l={};a.length=t.length+n.length,i=t.length;while(i--)a[s++]=t[i];i=n.length;while(i--)a[s++]=n[i];while(s--)r=a[s],u=r.getAttribute(\"xlink:href\"),o=r.getAttribute(\"id\"),u&&(l[o]=u.substr(1)),f[o]=r;for(o in l){var c=f[l[o]].cloneNode(!0);r=f[o];while(c.firstChild)r.appendChild(c.firstChild)}return f},parseAttributes:function(e,r,i){if(!e)return;var s,o={};typeof i==\"undefined\"&&(i=e.getAttribute(\"svgUid\")),e.parentNode&&/^symbol|[g|a]$/i.test(e.parentNode.nodeName)&&(o=t.parseAttributes(e.parentNode,r,i));var u=r.reduce(function(t,n){return s=e.getAttribute(n),s&&(n=l(n),s=c(n,s,o),t[n]=s),t},{});return u=n(u,n(m(e,i),t.parseStyleAttribute(e))),h(n(o,u))},parseElements:function(e,n,r,i){(new t.ElementsParser(e,n,r,i)).parse()},parseStyleAttribute:function(e){var t={},n=e.getAttribute(\"style\");return n?(typeof n==\"string\"?d(n,t):v(n,t),t):t},parsePointsAttribute:function(e){if(!\ne)return null;e=e.replace(/,/g,\" \").trim(),e=e.split(/\\s+/);var t=[],n,r;n=0,r=e.length;for(;n<r;n+=2)t.push({x:parseFloat(e[n]),y:parseFloat(e[n+1])});return t},getCSSRules:function(e){var n=e.getElementsByTagName(\"style\"),r={},i;for(var s=0,o=n.length;s<o;s++){var u=n[s].textContent;u=u.replace(/\\/\\*[\\s\\S]*?\\*\\//g,\"\");if(u.trim()===\"\")continue;i=u.match(/[^{]*\\{[\\s\\S]*?\\}/g),i=i.map(function(e){return e.trim()}),i.forEach(function(e){var n=e.match(/([\\s\\S]*?)\\s*\\{([^}]*)\\}/),i={},s=n[2].trim(),o=s.replace(/;$/,\"\").split(/\\s*;\\s*/);for(var u=0,a=o.length;u<a;u++){var f=o[u].split(/\\s*:\\s*/),h=l(f[0]),p=c(h,f[1],f[0]);i[h]=p}e=n[1],e.split(\",\").forEach(function(e){r[e.trim()]=t.util.object.clone(i)})})}return r},loadSVGFromURL:function(e,n,r){function i(i){var s=i.responseXML;s&&!s.documentElement&&t.window.ActiveXObject&&i.responseText&&(s=new ActiveXObject(\"Microsoft.XMLDOM\"),s.async=\"false\",s.loadXML(i.responseText.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i,\"\")));if(!s||!s.documentElement)return;t.parseSVGDocument(s.documentElement,function(r,i){S.set(e,{objects:t.util.array.invoke(r,\"toObject\"),options:i}),n(r,i)},r)}e=e.replace(/^\\n\\s*/,\"\").trim(),S.has(e,function(r){r?S.get(e,function(e){var t=x(e);n(t.objects,t.options)}):new t.util.request(e,{method:\"get\",onComplete:i})})},loadSVGFromString:function(e,n,r){e=e.trim();var i;if(typeof DOMParser!=\"undefined\"){var s=new DOMParser;s&&s.parseFromString&&(i=s.parseFromString(e,\"text/xml\"))}else t.window.ActiveXObject&&(i=new ActiveXObject(\"Microsoft.XMLDOM\"),i.async=\"false\",i.loadXML(e.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i,\"\")));t.parseSVGDocument(i.documentElement,function(e,t){n(e,t)},r)},createSVGFontFacesMarkup:function(e){var t=\"\";for(var n=0,r=e.length;n<r;n++){if(e[n].type!==\"text\"||!e[n].path)continue;t+=[\"@font-face {\",\"font-family: \",e[n].fontFamily,\"; \",\"src: url('\",e[n].path,\"')\",\"}\"].join(\"\")}return t&&(t=['<style type=\"text/css\">',\"<![CDATA[\",t,\"]]>\",\"</style>\"].join(\"\")),t},createSVGRefElementsMarkup:function(e){var t=[];return T(t,e,\"backgroundColor\"),T(t,e,\"overlayColor\"),t.join(\"\")}})}(typeof exports!=\"undefined\"?exports:this),fabric.ElementsParser=function(e,t,n,r){this.elements=e,this.callback=t,this.options=n,this.reviver=r,this.svgUid=n&&n.svgUid||0},fabric.ElementsParser.prototype.parse=function(){this.instances=new Array(this.elements.length),this.numElements=this.elements.length,this.createObjects()},fabric.ElementsParser.prototype.createObjects=function(){for(var e=0,t=this.elements.length;e<t;e++)this.elements[e].setAttribute(\"svgUid\",this.svgUid),function(e,t){setTimeout(function(){e.createObject(e.elements[t],t)},0)}(this,e)},fabric.ElementsParser.prototype.createObject=function(e,t){var n=fabric[fabric.util.string.capitalize(e.tagName)];if(n&&n.fromElement)try{this._createObject(n,e,t)}catch(r){fabric.log(r)}else this.checkIfDone()},fabric.ElementsParser.prototype._createObject=function(e,t,n){if(e.async)e.fromElement(t,this.createCallback(n,t),this.options);else{var r=e.fromElement(t,this.options);this.resolveGradient(r,\"fill\"),this.resolveGradient(r,\"stroke\"),this.reviver&&this.reviver(t,r),this.instances[n]=r,this.checkIfDone()}},fabric.ElementsParser.prototype.createCallback=function(e,t){var n=this;return function(r){n.resolveGradient(r,\"fill\"),n.resolveGradient(r,\"stroke\"),n.reviver&&n.reviver(t,r),n.instances[e]=r,n.checkIfDone()}},fabric.ElementsParser.prototype.resolveGradient=function(e,t){var n=e.get(t);if(!/^url\\(/.test(n))return;var r=n.slice(5,n.length-1);fabric.gradientDefs[this.svgUid][r]&&e.set(t,fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][r],e))},fabric.ElementsParser.prototype.checkIfDone=function(){--this.numElements===0&&(this.instances=this.instances.filter(function(e){return e!=null}),this.callback(this.instances))},function(e){\"use strict\";function n(e,t){this.x=e,this.y=t}var t=e.fabric||(e.fabric={});if(t.Point){t.warn(\"fabric.Point is already defined\");return}t.Point=n,n.prototype={constructor:n,add:function(e){return new n(this.x+e.x,this.y+e.y)},addEquals:function(e){return this.x+=e.x,this.y+=e.y,this},scalarAdd:function(e){return new n(this.x+e,this.y+e)},scalarAddEquals:function(e){return this.x+=e,this.y+=e,this},subtract:function(e){return new n(this.x-e.x,this.y-e.y)},subtractEquals:function(e){return this.x-=e.x,this.y-=e.y,this},scalarSubtract:function(e){return new n(this.x-e,this.y-e)},scalarSubtractEquals:function(e){return this.x-=e,this.y-=e,this},multiply:function(e){return new n(this.x*e,this.y*e)},multiplyEquals:function(e){return this.x*=e,this.y*=e,this},divide:function(e){return new n(this.x/e,this.y/e)},divideEquals:function(e){return this.x/=e,this.y/=e,this},eq:function(e){return this.x===e.x&&this.y===e.y},lt:function(e){return this.x<e.x&&this.y<e.y},lte:function(e){return this.x<=e.x&&this.y<=e.y},gt:function(e){return this.x>e.x&&this.y>e.y},gte:function(e){return this.x>=e.x&&this.y>=e.y},lerp:function(e,t){return new n(this.x+(e.x-this.x)*t,this.y+(e.y-this.y)*t)},distanceFrom:function(e){var t=this.x-e.x,n=this.y-e.y;return Math.sqrt(t*t+n*n)},midPointFrom:function(e){return new n(this.x+(e.x-this.x)/2,this.y+(e.y-this.y)/2)},min:function(e){return new n(Math.min(this.x,e.x),Math.min(this.y,e.y))},max:function(e){return new n(Math.max(this.x,e.x),Math.max(this.y,e.y))},toString:function(){return this.x+\",\"+this.y},setXY:function(e,t){this.x=e,this.y=t},setFromPoint:function(e){this.x=e.x,this.y=e.y},swap:function(e){var t=this.x,n=this.y;this.x=e.x,this.y=e.y,e.x=t,e.y=n}}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";function n(e){this.status=e,this.points=[]}var t=e.fabric||(e.fabric={});if(t.Intersection){t.warn(\"fabric.Intersection is already defined\");return}t.Intersection=n,t.Intersection.prototype={appendPoint:function(e){this.points.push(e)},appendPoints:function(e){this.points=this.points.concat(e)}},t.Intersection.intersectLineLine=function(e,r,i,s){var o,u=(s.x-i.x)*(e.y-i.y)-(s.y-i.y)*(e.x-i.x),a=(r.x-e.x)*(e.y-i.y)-(r.y-e.y)*(e.x-i.x),f=(s.y-i.y)*(r.x-e.x)-(s.x-i.x)*(r.y-e.y);if(f!==0){var l=u/f,c=a/f;0<=l&&l<=1&&0<=c&&c<=1?(o=new n(\"Intersection\"),o.points.push(new t.Point(e.x+l*(r.x-e.x),e.y+l*(r.y-e.y)))):o=new n}else u===0||a===0?o=new n(\"Coincident\"):o=new n(\"Parallel\");return o},t.Intersection.intersectLinePolygon=function(e,t,r){var i=new n,s=r.length;for(var o=0;o<s;o++){var u=r[o],a=r[(o+1)%s],f=n.intersectLineLine(e,t,u,a);i.appendPoints(f.points)}return i.points.length>0&&(i.status=\"Intersection\"),i},t.Intersection.intersectPolygonPolygon=function(e,t){var r=new n,i=e.length;for(var s=0;s<i;s++){var o=e[s],u=e[(s+1)%i],a=n.intersectLinePolygon(o,u,t);r.appendPoints(a.points)}return r.points.length>0&&(r.status=\"Intersection\"),r},t.Intersection.intersectPolygonRectangle=function(e,r,i){var s=r.min(i),o=r.max(i),u=new t.Point(o.x,s.y),a=new t.Point(s.x,o.y),f=n.intersectLinePolygon(s,u,e),l=n.intersectLinePolygon(u,o,e),c=n.intersectLinePolygon(o,a,e),h=n.intersectLinePolygon(a,s,e),p=new n;return p.appendPoints(f.points),p.appendPoints(l.points),p.appendPoints(c.points),p.appendPoints(h.points),p.points.length>0&&(p.status=\"Intersection\"),p}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";function n(e){e?this._tryParsingColor(e):this.setSource([0,0,0,1])}function r(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+(t-e)*6*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e}var t=e.fabric||(e.fabric={});if(t.Color){t.warn(\"fabric.Color is already defined.\");return}t.Color=n,t.Color.prototype={_tryParsingColor:function(e){var t;e in n.colorNameMap&&(e=n.colorNameMap[e]);if(e===\"transparent\"){this.setSource([255,255,255,0]);return}t=n.sourceFromHex(e),t||(t=n.sourceFromRgb(e)),t||(t=n.sourceFromHsl(e)),t&&this.setSource(t)},_rgbToHsl:function(e,n,r){e/=255,n/=255,r/=255;var i,s,o,u=t.util.array.max([e,n,r]),a=t.util.array.min([e,n,r]);o=(u+a)/2;if(u===a)i=s=0;else{var f=u-a;s=o>.5?f/(2-u-a):f/(u+a);switch(u){case e:i=(n-r)/f+(n<r?6:0);break;case n:i=(r-e)/f+2;break;case r:i=(e-n)/f+4}i/=6}return[Math.round(i*360),Math.round(s*100),Math.round(o*100)]},getSource:function(){return this._source},setSource:function(e){this._source=e},toRgb:function(){var e=this.getSource();return\"rgb(\"+e[0]+\",\"+e[1]+\",\"+e[2]+\")\"},toRgba:function(){var e=this.getSource();return\"rgba(\"+e[0]+\",\"+e[1]+\",\"+e[2]+\",\"+e[3]+\")\"},toHsl:function(){var e=this.getSource(),t=this._rgbToHsl(e[0],e[1],e[2]);return\"hsl(\"+t[0]+\",\"+t[1]+\"%,\"+t[2]+\"%)\"},toHsla:function(){var e=this.getSource(),t=this._rgbToHsl(e[0],e[1],e[2]);return\"hsla(\"+t[0]+\",\"+t[1]+\"%,\"+t[2]+\"%,\"+e[3]+\")\"},toHex:function(){var e=this.getSource(),t,n,r;return t=e[0].toString(16),t=t.length===1?\"0\"+t:t,n=e[1].toString(16),n=n.length===1?\"0\"+n:n,r=e[2].toString(16),r=r.length===1?\"0\"+r:r,t.toUpperCase()+n.toUpperCase()+r.toUpperCase()},getAlpha:function(){return this.getSource()[3]},setAlpha:function(e){var t=this.getSource();return t[3]=e,this.setSource(t),this},toGrayscale:function(){var e=this.getSource(),t=parseInt((e[0]*.3+e[1]*.59+e[2]*.11).toFixed(0),10),n=e[3];return this.setSource([t,t,t,n]),this},toBlackWhite:function(e){var t=this.getSource(),n=(t[0]*.3+t[1]*.59+t[2]*.11).toFixed(0),r=t[3];return e=e||127,n=Number(n)<Number(e)?0:255,this.setSource([n,n,n,r]),this},overlayWith:function(e){e instanceof n||(e=new n(e));var t=[],r=this.getAlpha(),i=.5,s=this.getSource(),o=e.getSource();for(var u=0;u<3;u++)t.push(Math.round(s[u]*(1-i)+o[u]*i));return t[3]=r,this.setSource(t),this}},t.Color.reRGBa=/^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/,t.Color.reHSLa=/^hsla?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}\\%)\\s*,\\s*(\\d{1,3}\\%)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/,t.Color.reHex=/^#?([0-9a-f]{6}|[0-9a-f]{3})$/i,t.Color.colorNameMap={aqua:\"#00FFFF\",black:\"#000000\",blue:\"#0000FF\",fuchsia:\"#FF00FF\",gray:\"#808080\",green:\"#008000\",lime:\"#00FF00\",maroon:\"#800000\",navy:\"#000080\",olive:\"#808000\",orange:\"#FFA500\",purple:\"#800080\",red:\"#FF0000\",silver:\"#C0C0C0\",teal:\"#008080\",white:\"#FFFFFF\",yellow:\"#FFFF00\"},t.Color.fromRgb=function(e){return n.fromSource(n.sourceFromRgb(e))},t.Color.sourceFromRgb=function(e){var t=e.match(n.reRGBa);if(t){var r=parseInt(t[1],10)/(/%$/.test(t[1])?100:1)*(/%$/.test(t[1])?255:1),i=parseInt(t[2],10)/(/%$/.test(t[2])?100:1)*(/%$/.test(t[2])?255:1),s=parseInt(t[3],10)/(/%$/.test(t[3])?100:1)*(/%$/.test(t[3])?255:1);return[parseInt(r,10),parseInt(i,10),parseInt(s,10),t[4]?parseFloat(t[4]):1]}},t.Color.fromRgba=n.fromRgb,t.Color.fromHsl=function(e){return n.fromSource(n.sourceFromHsl(e))},t.Color.sourceFromHsl=function(e){var t=e.match(n.reHSLa);if(!t)return;var i=(parseFloat(t[1])%360+360)%360/360,s=parseFloat(t[2])/(/%$/.test(t[2])?100:1),o=parseFloat(t[3])/(/%$/.test(t[3])?100:1),u,a,f;if(s===0)u=a=f=o;else{var l=o<=.5?o*(s+1):o+s-o*s,c=o*2-l;u=r(c,l,i+1/3),a=r(c,l,i),f=r(c,l,i-1/3)}return[Math.round(u*255),Math.round(a*255),Math.round(f*255),t[4]?parseFloat(t[4]):1]},t.Color.fromHsla=n.fromHsl,t.Color.fromHex=function(e){return n.fromSource(n.sourceFromHex(e))},t.Color.sourceFromHex=function(e){if(e.match(n.reHex)){var t=e.slice(e.indexOf(\"#\")+1),r=t.length===3,i=r?t.charAt(0)+t.charAt(0):t.substring(0,2),s=r?t.charAt(1)+t.charAt(1):t.substring(2,4),o=r?t.charAt(2)+t.charAt(2):t.substring(4,6);return[parseInt(i,16),parseInt(s,16),parseInt(o,16),1]}},t.Color.fromSource=function(e){var t=new n;return t.setSource(e),t}}(typeof exports!=\"undefined\"?exports:this),function(){function e(e){var t=e.getAttribute(\"style\"),n=e.getAttribute(\"offset\"),r,i,s;n=parseFloat(n)/(/%$/.test(n)?100:1),n=n<0?0:n>1?1:n;if(t){var o=t.split(/\\s*;\\s*/);o[o.length-1]===\"\"&&o.pop();for(var u=o.length;u--;){var a=o[u].split(/\\s*:\\s*/),f=a[0].trim(),l=a[1].trim();f===\"stop-color\"?r=l:f===\"stop-opacity\"&&(s=l)}}return r||(r=e.getAttribute(\"stop-color\")||\"rgb(0,0,0)\"),s||(s=e.getAttribute(\"stop-opacity\")),r=new fabric.Color(r),i=r.getAlpha(),s=isNaN(parseFloat(s))?1:parseFloat(s),s*=i,{offset:n,color:r.toRgb(),opacity:s}}function t(e){return{x1:e.getAttribute(\"x1\")||0,y1:e.getAttribute(\"y1\")||0,x2:e.getAttribute(\"x2\")||\"100%\",y2:e.getAttribute(\"y2\")||0}}function n(e){return{x1:e.getAttribute(\"fx\")||e.getAttribute(\"cx\")||\"50%\",y1:e.getAttribute(\"fy\")||e.getAttribute(\"cy\")||\"50%\",r1:0,x2:e.getAttribute(\"cx\")||\"50%\",y2:e.getAttribute(\"cy\")||\"50%\",r2:e.getAttribute(\"r\")||\"50%\"}}function r(e,t,n){var r,i=0,s=1,o=\"\";for(var u in t){r=parseFloat(t[u],10),typeof t[u]==\"string\"&&/^\\d+%$/.test(t[u])?s=.01:s=1;if(u===\"x1\"||u===\"x2\"||u===\"r2\")s*=n===\"objectBoundingBox\"?e.width:1,i=n===\"objectBoundingBox\"?e.left||0:0;else if(u===\"y1\"||u===\"y2\")s*=n===\"objectBoundingBox\"?e.height:1,i=n===\"objectBoundingBox\"?e.top||0:0;t[u]=r*s+i}if(e.type===\"ellipse\"&&t.r2!==null&&n===\"objectBoundingBox\"&&e.rx!==e.ry){var a=e.ry/e.rx;o=\" scale(1, \"+a+\")\",t.y1&&(t.y1/=a),t.y2&&(t.y2/=a)}return o}fabric.Gradient=fabric.util.createClass({offsetX:0,offsetY:0,initialize:function(e){e||(e={});var t={};this.id=fabric.Object.__uid++,this.type=e.type||\"linear\",t={x1:e.coords.x1||0,y1:e.coords.y1||0,x2:e.coords.x2||0,y2:e.coords.y2||0},this.type===\"radial\"&&(t.r1=e.coords.r1||0,t.r2=e.coords.r2||0),this.coords=t,this.colorStops=e.colorStops.slice(),e.gradientTransform&&(this.gradientTransform=e.gradientTransform),this.offsetX=e.offsetX||this.offsetX,this.offsetY=e.offsetY||this.offsetY},addColorStop:function(e){for(var t in e){var n=new fabric.Color(e[t]);this.colorStops.push({offset:t,color:n.toRgb(),opacity:n.getAlpha()})}return this},toObject:function(){return{type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY}},toSVG:function(e){var t=fabric.util.object.clone(this.coords),n,r;this.colorStops.sort(function(e,t){return e.offset-t.offset});if(!e.group||e.group.type!==\"path-group\")for(var i in t)if(i===\"x1\"||i===\"x2\"||i===\"r2\")t[i]+=this.offsetX-e.width/2;else if(i===\"y1\"||i===\"y2\")t[i]+=this.offsetY-e.height/2;r='id=\"SVGID_'+this.id+'\" gradientUnits=\"userSpaceOnUse\"',this.gradientTransform&&(r+=' gradientTransform=\"matrix('+this.gradientTransform.join(\" \")+')\" '),this.type===\"linear\"?n=[\"<linearGradient \",r,' x1=\"',t.x1,'\" y1=\"',t.y1,'\" x2=\"',t.x2,'\" y2=\"',t.y2,'\">\\n']:this.type===\"radial\"&&(n=[\"<radialGradient \",r,' cx=\"',t.x2,'\" cy=\"',t.y2,'\" r=\"',t.r2,'\" fx=\"',t.x1,'\" fy=\"',t.y1,'\">\\n']);for(var s=0;s<this.colorStops.length;s++)n.push(\"<stop \",'offset=\"',this.colorStops[s].offset*100+\"%\",'\" style=\"stop-color:',this.colorStops[s].color,this.colorStops[s].opacity!=null?\";stop-opacity: \"+this.colorStops[s].opacity:\";\",'\"/>\\n');return n.push(this.type===\"linear\"?\"</linearGradient>\\n\":\"</radialGradient>\\n\"),n.join(\"\")},toLive:function(e,t){var n,r=fabric.util.object.clone(this.coords);if(!this.type)return;if(t.group&&t.group.type===\"path-group\")for(var i in r)if(i===\"x1\"||i===\"x2\")r[i]+=-this.offsetX+t.width/2;else if(i===\"y1\"||i===\"y2\")r[i]+=-this.offsetY+t.height/2;this.type===\"linear\"?n=e.createLinearGradient(r.x1,r.y1,r.x2,r.y2):this.type===\"radial\"&&(n=e.createRadialGradient(r.x1,r.y1,r.r1,r.x2,r.y2,r.r2));for(var s=0,o=this.colorStops.length;s<o;s++){var u=this.colorStops[s].color,a=this.colorStops[s].opacity,f=this.colorStops[s].offset;typeof a!=\"undefined\"&&(u=(new fabric.Color(u)).setAlpha(a).toRgba()),n.addColorStop(parseFloat(f),u)}return n}}),fabric.util.object.extend(fabric.Gradient,{fromElement:function(i,s){var o=i.getElementsByTagName(\"stop\"),u=i.nodeName===\"linearGradient\"?\"linear\":\"radial\",a=i.getAttribute(\"gradientUnits\")||\"objectBoundingBox\",f=i.getAttribute(\"gradientTransform\"),l=[],c={},h;u===\"linear\"?c=t(i):u===\"radial\"&&(c=n(i));for(var p=o.length;p--;)l.push(e(o[p]));h=r(s,c,a);var d=new fabric.Gradient({type:u,coords:c,colorStops:l,offsetX:-s.left,offsetY:-s.top});if(f||h!==\"\")d.gradientTransform=fabric.parseTransformAttribute((f||\"\")+h);return d},forObject:function(e,t){return t||(t={}),r(e,t.coords,\"userSpaceOnUse\"),new fabric.Gradient(t)}})}(),fabric.Pattern=fabric.util.createClass({repeat:\"repeat\",offsetX:0,offsetY:0,initialize:function(e){e||(e={}),this.id=fabric.Object.__uid++;if(e.source)if(typeof e.source==\"string\")if(typeof fabric.util.getFunctionBody(e.source)!=\"undefined\")this.source=new Function(fabric.util.getFunctionBody(e.source));else{var t=this;this.source=fabric.util.createImage(),fabric.util.loadImage(e.source,function(e){t.source=e})}else this.source=e.source;e.repeat&&(this.repeat=e.repeat),e.offsetX&&(this.offsetX=e.offsetX),e.offsetY&&(this.offsetY=e.offsetY)},toObject:function(){var e;return typeof this.source==\"function\"?e=String(this.source):typeof this.source.src==\"string\"&&(e=this.source.src),{source:e,repeat:this.repeat,offsetX:this.offsetX,offsetY:this.offsetY}},toSVG:function(e){var t=typeof this.source==\"function\"?this.source():this.source,n=t.width/e.getWidth(),r=t.height/e.getHeight(),i=\"\";return t.src?i=t.src:t.toDataURL&&(i=t.toDataURL()),'<pattern id=\"SVGID_'+this.id+'\" x=\"'+this.offsetX+'\" y=\"'+this.offsetY+'\" width=\"'+n+'\" height=\"'+r+'\">'+'<image x=\"0\" y=\"0\"'+' width=\"'+t.width+'\" height=\"'+t.height+'\" xlink:href=\"'+i+'\"></image>'+\"</pattern>\"},toLive:function(e){var t=typeof this.source==\"function\"?this.source():this.source;if(!t)return\"\";if(typeof t.src!=\"undefined\"){if(!t.complete)return\"\";if(t.naturalWidth===0||t.naturalHeight===0)return\"\"}return e.createPattern(t,this.repeat)}}),function(e){\"use strict\";var t=e.fabric||(e.fabric={});if(t.Shadow){t.warn(\"fabric.Shadow is already defined.\");return}t.Shadow=t.util.createClass({color:\"rgb(0,0,0)\",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(e){typeof e==\"string\"&&(e=this._parseShadow(e));for(var n in e)this[n]=e[n];this.id=t.Object.__uid++},_parseShadow:function(e){var n=e.trim(),r=t.Shadow.reOffsetsAndBlur.exec(n)||[],i=n.replace(t.Shadow.reOffsetsAndBlur,\"\")||\"rgb(0,0,0)\";return{color:i.trim(),offsetX:parseInt(r[1],10)||0,offsetY:parseInt(r[2],10)||0,blur:parseInt(r[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join(\"px \")},toSVG:function(e){var t=\"SourceAlpha\";return e&&(e.fill===this.color||e.stroke===this.color)&&(t=\"SourceGraphic\"),'<filter id=\"SVGID_'+this.id+'\" y=\"-40%\" height=\"180%\">'+'<feGaussianBlur in=\"'+t+'\" stdDeviation=\"'+(this.blur?this.blur/3:0)+'\"></feGaussianBlur>'+'<feOffset dx=\"'+this.offsetX+'\" dy=\"'+this.offsetY+'\"></feOffset>'+\"<feMerge>\"+\"<feMergeNode></feMergeNode>\"+'<feMergeNode in=\"SourceGraphic\"></feMergeNode>'+\"</feMerge>\"+\"</filter>\"},toObject:function(){if(this.includeDefaultValues)return{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY};var e={},n=t.Shadow.prototype;return this.color!==n.color&&(e.color=this.color),this.blur!==n.blur&&(e.blur=this.blur),this.offsetX!==n.offsetX&&(e.offsetX=this.offsetX),this.offsetY!==n.offsetY&&(e.offsetY=this.offsetY),e}}),t.Shadow.reOffsetsAndBlur=/(?:\\s|^)(-?\\d+(?:px)?(?:\\s?|$))?(-?\\d+(?:px)?(?:\\s?|$))?(\\d+(?:px)?)?(?:\\s?|$)(?:$|\\s)/}(typeof exports!=\"undefined\"?exports:this),function(){\"use strict\";if(fabric.StaticCanvas){fabric.warn(\"fabric.StaticCanvas is already defined.\");return}var e=fabric.util.object.extend,t=fabric.util.getElementOffset,n=fabric.util.removeFromArray,r=new Error(\"Could not initialize `canvas` element\");fabric.StaticCanvas=fabric.util.createClass({initialize:function(e,t){t||(t={}),this._initStatic(e,t),fabric.StaticCanvas.activeInstance=this},backgroundColor:\"\",backgroundImage:null,overlayColor:\"\",overlayImage:null,includeDefaultValues:!0,stateful:!0,renderOnAddRemove:!0,clipTo:null,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,preserveObjectStacking:!1,viewportTransform:[1,0,0,1,0,0],onBeforeScaleRotate:function(){},_initStatic:function(e,t){this._objects=[],this._createLowerCanvas(e),this._initOptions(t),this._setImageSmoothing(),t.overlayImage&&this.setOverlayImage(t.overlayImage,this.renderAll.bind(this)),t.backgroundImage&&this.setBackgroundImage(t.backgroundImage,this.renderAll.bind(this)),t.backgroundColor&&this.setBackgroundColor(t.backgroundColor,this.renderAll.bind(this)),t.overlayColor&&this.setOverlayColor(t.overlayColor,this.renderAll.bind(this)),this.calcOffset()},calcOffset:function(){return this._offset=t(this.lowerCanvasEl),this},setOverlayImage:function(e,t,n){return this.__setBgOverlayImage(\"overlayImage\",e,t,n)},setBackgroundImage:function(e,t,n){return this.__setBgOverlayImage(\"backgroundImage\",e,t,n)},setOverlayColor:function(e,t){return this.__setBgOverlayColor(\"overlayColor\",e,t)},setBackgroundColor:function(e,t){return this.__setBgOverlayColor(\"backgroundColor\",e,t)},_setImageSmoothing:function(){var e=this.getContext();e.imageSmoothingEnabled=this.imageSmoothingEnabled,e.webkitImageSmoothingEnabled=this.imageSmoothingEnabled,e.mozImageSmoothingEnabled=this.imageSmoothingEnabled,e.msImageSmoothingEnabled=this.imageSmoothingEnabled,e.oImageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(e,t,n,r){return typeof t==\"string\"?fabric.util.loadImage(t,function(t){this[e]=new fabric.Image(t,r),n&&n()},this):(this[e]=t,n&&n()),this},__setBgOverlayColor:function(e,t,n){if(t&&t.source){var r=this;fabric.util.loadImage(t.source,function(i){r[e]=new fabric.Pattern({source:i,repeat:t.repeat,offsetX:t.offsetX,offsetY:t.offsetY}),n&&n()})}else this[e]=t,n&&n();return this},_createCanvasElement:function(){var e=fabric.document.createElement(\"canvas\");e.style||(e.style={});if(!e)throw r;return this._initCanvasElement(e),e},_initCanvasElement:function(e){fabric.util.createCanvasElement(e);if(typeof e.getContext==\"undefined\")throw r},_initOptions:function(e){for(var t in e)this[t]=e[t];this.width=this.width||parseInt(this.lowerCanvasEl.width,10)||0,this.height=this.height||parseInt(this.lowerCanvasEl.height,10)||0;if(!this.lowerCanvasEl.style)return;this.lowerCanvasEl.width=this.width,this.lowerCanvasEl.height=this.height,this.lowerCanvasEl.style.width=this.width+\"px\",this.lowerCanvasEl.style.height=this.height+\"px\",this.viewportTransform=this.viewportTransform.slice()},_createLowerCanvas:function(e){this.lowerCanvasEl=fabric.util.getById(e)||this._createCanvasElement(),this._initCanvasElement(this.lowerCanvasEl),fabric.util.addClass(this.lowerCanvasEl,\"lower-canvas\"),this.interactive&&this._applyCanvasStyle(this.lowerCanvasEl),this.contextContainer=this.lowerCanvasEl.getContext(\"2d\")},getWidth:function(){return this.width},getHeight:function(){return this.height},setWidth:function(e,t){return this.setDimensions({width:e},t)},setHeight:function(e,t){return this.setDimensions({height:e},t)},setDimensions:function(e,t){var n;t=t||{};for(var r in e)n=e[r],t.cssOnly||(this._setBackstoreDimension(r,e[r]),n+=\"px\"),t.backstoreOnly||this._setCssDimension(r,n);return t.cssOnly||this.renderAll(),this.calcOffset(),this},_setBackstoreDimension:function(e,t){return this.lowerCanvasEl[e]=t,this.upperCanvasEl&&(this.upperCanvasEl[e]=t),this.cacheCanvasEl&&(this.cacheCanvasEl[e]=t),this[e]=t,this},_setCssDimension:function(e,t){return this.lowerCanvasEl.style[e]=t,this.upperCanvasEl&&(this.upperCanvasEl.style[e]=t),this.wrapperEl&&(this.wrapperEl.style[e]=t),this},getZoom:function(){return Math.sqrt(this.viewportTransform[0]*this.viewportTransform[3])},setViewportTransform:function(e){this.viewportTransform=e,this.renderAll();for(var t=0,n=this._objects.length;t<n;t++)this._objects[t].setCoords();return this},zoomToPoint:function(e,t){var n=e;e=fabric.util.transformPoint(e,fabric.util.invertTransform(this.viewportTransform)),this.viewportTransform[0]=t,this.viewportTransform[3]=t;var r=fabric.util.transformPoint(e,this.viewportTransform);this.viewportTransform[4]+=n.x-r.x,this.viewportTransform[5]+=n.y-r.y,this.renderAll();for(var i=0,s=this._objects.length;i<s;i++)this._objects[i].setCoords();return this},setZoom:function(e){return this.zoomToPoint(new fabric.Point(0,0),e),this},absolutePan:function(e){this.viewportTransform[4]=-e.x,this.viewportTransform[5]=-e.y,this.renderAll();for(var t=0,n=this._objects.length;t<n;t++)this._objects[t].setCoords();return this},relativePan:function(e){return this.absolutePan(new fabric.Point(-e.x-this.viewportTransform[4],-e.y-this.viewportTransform[5]))},getElement:function(){return this.lowerCanvasEl},getActiveObject:function(){return null},getActiveGroup:function(){return null},_draw:function(e,t){if(!t)return;e.save();var n=this.viewportTransform;e.transform(n[0],n[1],n[2],n[3],n[4],n[5]),this._shouldRenderObject(t)&&t.render(e),e.restore(),this.controlsAboveOverlay||t._renderControls(e)},_shouldRenderObject:function(e){return e?e!==this.getActiveGroup()||!this.preserveObjectStacking:!1},_onObjectAdded:function(e){this.stateful&&e.setupState(),e.canvas=this,e.setCoords(),this.fire(\"object:added\",{target:e}),e.fire(\"added\")},_onObjectRemoved:function(e){this.getActiveObject()===e&&(this.fire(\"before:selection:cleared\",{target:e}),this._discardActiveObject(),this.fire(\"selection:cleared\")),this.fire(\"object:removed\",{target:e}),e.fire(\"removed\")},clearContext:function(e){return e.clearRect(0,0,this.width,this.height),this},getContext:function(){return this.contextContainer},clear:function(){return this._objects.length=0,this.discardActiveGroup&&this.discardActiveGroup(),this.discardActiveObject&&this.discardActiveObject(),this.clearContext(this.contextContainer),this.contextTop&&this.clearContext(this.contextTop),this.fire(\"canvas:cleared\"),this.renderAll(),this},renderAll:function(e){var t=this[e===!0&&this.interactive?\"contextTop\":\"contextContainer\"],n=this.getActiveGroup();return this.contextTop&&this.selection&&!this._groupSelector&&this.clearContext(this.contextTop),e||this.clearContext(t),this.fire(\"before:render\"),this.clipTo&&fabric.util.clipContext(this,t),this._renderBackground(t),this._renderObjects(t,n),this._renderActiveGroup(t,n),this.clipTo&&t.restore(),this._renderOverlay(t),this.controlsAboveOverlay&&this.interactive&&this.drawControls(t),this.fire(\"after:render\"),this},_renderObjects:function(e,t){var n,r;if(!t||this.preserveObjectStacking)for(n=0,r=this._objects.length;n<r;++n)this._draw(e,this._objects[n]);else for(n=0,r=this._objects.length;n<r;++n)this._objects[n]&&!t.contains(this._objects[n])&&this._draw(e,this._objects[n])},_renderActiveGroup:function(e,t){if(t){var n=[];this.forEachObject(function(e){t.contains(e)&&n.push(e)}),t._set(\"objects\",n),this._draw(e,t)}},_renderBackground:function(e){this.backgroundColor&&(e.fillStyle=this.backgroundColor.toLive?this.backgroundColor.toLive(e):this.backgroundColor,e.fillRect(this.backgroundColor.offsetX||0,this.backgroundColor.offsetY||0,this.width,this.height)),this.backgroundImage&&this._draw(e,this.backgroundImage)},_renderOverlay:function(e){this.overlayColor&&(e.fillStyle=this.overlayColor.toLive?this.overlayColor.toLive(e):this.overlayColor,e.fillRect(this.overlayColor.offsetX||0,this.overlayColor.offsetY||0,this.width,this.height)),this.overlayImage&&this._draw(e,this.overlayImage)},renderTop:function(){var e=this.contextTop||this.contextContainer;this.clearContext(e),this.selection&&this._groupSelector&&this._drawSelection();var t=this.getActiveGroup();return t&&t.render(e),this._renderOverlay(e),this.fire(\"after:render\"),this},getCenter:function(){return{top:this.getHeight()/2,left:this.getWidth()/2}},centerObjectH:function(e){return this._centerObject(e,new fabric.Point(this.getCenter().left,e.getCenterPoint().y)),this.renderAll(),this},centerObjectV:function(e){return this._centerObject(e,new fabric.Point(e.getCenterPoint().x,this.getCenter().top)),this.renderAll(),this},centerObject:function(e){var t=this.getCenter();return this._centerObject(e,new fabric.Point(t.left,t.top)),this.renderAll(),this},_centerObject:function(e,t){return e.setPositionByOrigin(t,\"center\",\"center\"),this},toDatalessJSON:function(e){return this.toDatalessObject(e)},toObject:function(e){return this._toObjectMethod(\"toObject\",e)},toDatalessObject:function(e){return this._toObjectMethod(\"toDatalessObject\",e)},_toObjectMethod:function(t,n){var r=this.getActiveGroup();r&&this.discardActiveGroup();var i={objects:this._toObjects(t,n)};return e(i,this.__serializeBgOverlay()),fabric.util.populateWithProperties(this,i,n),r&&(this.setActiveGroup(new fabric.Group(r.getObjects(),{originX:\"center\",originY:\"center\"})),r.forEachObject(function(e){e.set(\"active\",!0)}),this._currentTransform&&(this._currentTransform.target=this.getActiveGroup())),i},_toObjects:function(e,t){return this.getObjects().map(function(n){return this._toObject(n,e,t)},this)},_toObject:function(e,t,n){var r;this.includeDefaultValues||(r=e.includeDefaultValues,e.includeDefaultValues=!1);var i=e[t](n);return this.includeDefaultValues||(e.includeDefaultValues=r),i},__serializeBgOverlay:function(){var e={background:this.backgroundColor&&this.backgroundColor.toObject?this.backgroundColor.toObject():this.backgroundColor};return this.overlayColor&&(e.overlay=this.overlayColor.toObject?this.overlayColor.toObject():this.overlayColor),this.backgroundImage&&(e.backgroundImage=this.backgroundImage.toObject()),this.overlayImage&&(e.overlayImage=this.overlayImage.toObject()),e},svgViewportTransformation:!0,toSVG:function(e,t){e||(e={});var n=[];return this._setSVGPreamble(n,e),this._setSVGHeader(n,e),this._setSVGBgOverlayColor(n,\"backgroundColor\"),this._setSVGBgOverlayImage(n,\"backgroundImage\"),this._setSVGObjects(n,t),this._setSVGBgOverlayColor(n,\"overlayColor\"),this._setSVGBgOverlayImage(n,\"overlayImage\"),n.push(\"</svg>\"),n.join(\"\")},_setSVGPreamble:function(e,t){t.suppressPreamble||e.push('<?xml version=\"1.0\" encoding=\"',t.encoding||\"UTF-8\",'\" standalone=\"no\" ?>','<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ','\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\\n')},_setSVGHeader:function(e,t){var n,r,i;t.viewBox?(n=t.viewBox.width,r=t.viewBox.height):(n=this.width,r=this.height,this.svgViewportTransformation||(i=this.viewportTransform,n/=i[0],r/=i[3])),e.push(\"<svg \",'xmlns=\"http://www.w3.org/2000/svg\" ','xmlns:xlink=\"http://www.w3.org/1999/xlink\" ','version=\"1.1\" ','width=\"',n,'\" ','height=\"',r,'\" ',this.backgroundColor&&!this.backgroundColor.toLive?'style=\"background-color: '+this.backgroundColor+'\" ':null,t.viewBox?'viewBox=\"'+t.viewBox.x+\" \"+t.viewBox.y+\" \"+t.viewBox.width+\" \"+t.viewBox.height+'\" ':null,'xml:space=\"preserve\">',\"<desc>Created with Fabric.js \",fabric.version,\"</desc>\",\"<defs>\",fabric.createSVGFontFacesMarkup(this.getObjects()),fabric.createSVGRefElementsMarkup(this),\"</defs>\")},_setSVGObjects:function(e,t){var n=this.getActiveGroup();n&&this.discardActiveGroup();for(var r=0,i=this.getObjects(),s=i.length;r<s;r++)e.push(i[r].toSVG(t));n&&(this.setActiveGroup(new fabric.Group(n.getObjects())),n.forEachObject(function(e){e.set(\"active\",!0)}))},_setSVGBgOverlayImage:function(e,t){this[t]&&this[t].toSVG&&e.push(this[t].toSVG())},_setSVGBgOverlayColor:function(e,t){this[t]&&this[t].source?e.push('<rect x=\"',this[t].offsetX,'\" y=\"',this[t].offsetY,'\" ','width=\"',this[t].repeat===\"repeat-y\"||this[t].repeat===\"no-repeat\"?this[t].source.width:this.width,'\" height=\"',this[t].repeat===\"repeat-x\"||this[t].repeat===\"no-repeat\"?this[t].source.height:this.height,'\" fill=\"url(#'+t+'Pattern)\"',\"></rect>\"):this[t]&&t===\"overlayColor\"&&e.push('<rect x=\"0\" y=\"0\" ','width=\"',this.width,'\" height=\"',this.height,'\" fill=\"',this[t],'\"',\"></rect>\")},sendToBack:function(e){return n(this._objects,e),this._objects.unshift(e),this.renderAll&&this.renderAll()},bringToFront:function(e){return n(this._objects,e),this._objects.push(e),this.renderAll&&this.renderAll()},sendBackwards:function(e,t){var r=this._objects.indexOf(e);if(r!==0){var i=this._findNewLowerIndex(e,r,t);n(this._objects,e),this._objects.splice(i,0,e),this.renderAll&&this.renderAll()}return this},_findNewLowerIndex:function(e,t,n){var r;if(n){r=t;for(var i=t-1;i>=0;--i){var s=e.intersectsWithObject(this._objects[i])||e.isContainedWithinObject(this._objects[i])||this._objects[i].isContainedWithinObject(e);if(s){r=i;break}}}else r=t-1;return r},bringForward:function(e,t){var r=this._objects.indexOf(e);if(r!==this._objects.length-1){var i=this._findNewUpperIndex(e,r,t);n(this._objects,e),this._objects.splice(i,0,e),this.renderAll&&this.renderAll()}return this},_findNewUpperIndex:function(e,t,n){var r;if(n){r=t;for(var i=t+1;i<this._objects.length;++i){var s=e.intersectsWithObject(this._objects[i])||e.isContainedWithinObject(this._objects[i])||this._objects[i].isContainedWithinObject(e);if(s){r=i;break}}}else r=t+1;return r},moveTo:function(e,t){return n(this._objects,e),this._objects.splice(t,0,e),this.renderAll&&this.renderAll()},dispose:function(){return this.clear(),this.interactive&&this.removeListeners(),this},toString:function(){return\"#<fabric.Canvas (\"+this.complexity()+\"): \"+\"{ objects: \"+\nthis.getObjects().length+\" }>\"}}),e(fabric.StaticCanvas.prototype,fabric.Observable),e(fabric.StaticCanvas.prototype,fabric.Collection),e(fabric.StaticCanvas.prototype,fabric.DataURLExporter),e(fabric.StaticCanvas,{EMPTY_JSON:'{\"objects\": [], \"background\": \"white\"}',supports:function(e){var t=fabric.util.createCanvasElement();if(!t||!t.getContext)return null;var n=t.getContext(\"2d\");if(!n)return null;switch(e){case\"getImageData\":return typeof n.getImageData!=\"undefined\";case\"setLineDash\":return typeof n.setLineDash!=\"undefined\";case\"toDataURL\":return typeof t.toDataURL!=\"undefined\";case\"toDataURLWithQuality\":try{return t.toDataURL(\"image/jpeg\",0),!0}catch(r){}return!1;default:return null}}}),fabric.StaticCanvas.prototype.toJSON=fabric.StaticCanvas.prototype.toObject}(),fabric.BaseBrush=fabric.util.createClass({color:\"rgb(0, 0, 0)\",width:1,shadow:null,strokeLineCap:\"round\",strokeLineJoin:\"round\",setShadow:function(e){return this.shadow=new fabric.Shadow(e),this},_setBrushStyles:function(){var e=this.canvas.contextTop;e.strokeStyle=this.color,e.lineWidth=this.width,e.lineCap=this.strokeLineCap,e.lineJoin=this.strokeLineJoin},_setShadow:function(){if(!this.shadow)return;var e=this.canvas.contextTop;e.shadowColor=this.shadow.color,e.shadowBlur=this.shadow.blur,e.shadowOffsetX=this.shadow.offsetX,e.shadowOffsetY=this.shadow.offsetY},_resetShadow:function(){var e=this.canvas.contextTop;e.shadowColor=\"\",e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0}}),function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(e){this.canvas=e,this._points=[]},onMouseDown:function(e){this._prepareForDrawing(e),this._captureDrawingPath(e),this._render()},onMouseMove:function(e){this._captureDrawingPath(e),this.canvas.clearContext(this.canvas.contextTop),this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(e){var t=new fabric.Point(e.x,e.y);this._reset(),this._addPoint(t),this.canvas.contextTop.moveTo(t.x,t.y)},_addPoint:function(e){this._points.push(e)},_reset:function(){this._points.length=0,this._setBrushStyles(),this._setShadow()},_captureDrawingPath:function(e){var t=new fabric.Point(e.x,e.y);this._addPoint(t)},_render:function(){var e=this.canvas.contextTop,t=this.canvas.viewportTransform,n=this._points[0],r=this._points[1];e.save(),e.transform(t[0],t[1],t[2],t[3],t[4],t[5]),e.beginPath(),this._points.length===2&&n.x===r.x&&n.y===r.y&&(n.x-=.5,r.x+=.5),e.moveTo(n.x,n.y);for(var i=1,s=this._points.length;i<s;i++){var o=n.midPointFrom(r);e.quadraticCurveTo(n.x,n.y,o.x,o.y),n=this._points[i],r=this._points[i+1]}e.lineTo(n.x,n.y),e.stroke(),e.restore()},convertPointsToSVGPath:function(e){var t=[],n=new fabric.Point(e[0].x,e[0].y),r=new fabric.Point(e[1].x,e[1].y);t.push(\"M \",e[0].x,\" \",e[0].y,\" \");for(var i=1,s=e.length;i<s;i++){var o=n.midPointFrom(r);t.push(\"Q \",n.x,\" \",n.y,\" \",o.x,\" \",o.y,\" \"),n=new fabric.Point(e[i].x,e[i].y),i+1<e.length&&(r=new fabric.Point(e[i+1].x,e[i+1].y))}return t.push(\"L \",n.x,\" \",n.y,\" \"),t},createPath:function(e){var t=new fabric.Path(e);return t.fill=null,t.stroke=this.color,t.strokeWidth=this.width,t.strokeLineCap=this.strokeLineCap,t.strokeLineJoin=this.strokeLineJoin,this.shadow&&(this.shadow.affectStroke=!0,t.setShadow(this.shadow)),t},_finalizeAndAddPath:function(){var e=this.canvas.contextTop;e.closePath();var t=this.convertPointsToSVGPath(this._points).join(\"\");if(t===\"M 0 0 Q 0 0 0 0 L 0 0\"){this.canvas.renderAll();return}var n=this.createPath(t);this.canvas.add(n),n.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire(\"path:created\",{path:n})}})}(),fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(e){this.canvas=e,this.points=[]},drawDot:function(e){var t=this.addPoint(e),n=this.canvas.contextTop,r=this.canvas.viewportTransform;n.save(),n.transform(r[0],r[1],r[2],r[3],r[4],r[5]),n.fillStyle=t.fill,n.beginPath(),n.arc(t.x,t.y,t.radius,0,Math.PI*2,!1),n.closePath(),n.fill(),n.restore()},onMouseDown:function(e){this.points.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.drawDot(e)},onMouseMove:function(e){this.drawDot(e)},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;var t=[];for(var n=0,r=this.points.length;n<r;n++){var i=this.points[n],s=new fabric.Circle({radius:i.radius,left:i.x,top:i.y,originX:\"center\",originY:\"center\",fill:i.fill});this.shadow&&s.setShadow(this.shadow),t.push(s)}var o=new fabric.Group(t,{originX:\"center\",originY:\"center\"});o.canvas=this.canvas,this.canvas.add(o),this.canvas.fire(\"path:created\",{path:o}),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderOnAddRemove=e,this.canvas.renderAll()},addPoint:function(e){var t=new fabric.Point(e.x,e.y),n=fabric.util.getRandomInt(Math.max(0,this.width-20),this.width+20)/2,r=(new fabric.Color(this.color)).setAlpha(fabric.util.getRandomInt(0,100)/100).toRgba();return t.radius=n,t.fill=r,this.points.push(t),t}}),fabric.SprayBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,density:20,dotWidth:1,dotWidthVariance:1,randomOpacity:!1,optimizeOverlapping:!0,initialize:function(e){this.canvas=e,this.sprayChunks=[]},onMouseDown:function(e){this.sprayChunks.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.addSprayChunk(e),this.render()},onMouseMove:function(e){this.addSprayChunk(e),this.render()},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;var t=[];for(var n=0,r=this.sprayChunks.length;n<r;n++){var i=this.sprayChunks[n];for(var s=0,o=i.length;s<o;s++){var u=new fabric.Rect({width:i[s].width,height:i[s].width,left:i[s].x+1,top:i[s].y+1,originX:\"center\",originY:\"center\",fill:this.color});this.shadow&&u.setShadow(this.shadow),t.push(u)}}this.optimizeOverlapping&&(t=this._getOptimizedRects(t));var a=new fabric.Group(t,{originX:\"center\",originY:\"center\"});a.canvas=this.canvas,this.canvas.add(a),this.canvas.fire(\"path:created\",{path:a}),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderOnAddRemove=e,this.canvas.renderAll()},_getOptimizedRects:function(e){var t={},n;for(var r=0,i=e.length;r<i;r++)n=e[r].left+\"\"+e[r].top,t[n]||(t[n]=e[r]);var s=[];for(n in t)s.push(t[n]);return s},render:function(){var e=this.canvas.contextTop;e.fillStyle=this.color;var t=this.canvas.viewportTransform;e.save(),e.transform(t[0],t[1],t[2],t[3],t[4],t[5]);for(var n=0,r=this.sprayChunkPoints.length;n<r;n++){var i=this.sprayChunkPoints[n];typeof i.opacity!=\"undefined\"&&(e.globalAlpha=i.opacity),e.fillRect(i.x,i.y,i.width,i.width)}e.restore()},addSprayChunk:function(e){this.sprayChunkPoints=[];var t,n,r,i=this.width/2;for(var s=0;s<this.density;s++){t=fabric.util.getRandomInt(e.x-i,e.x+i),n=fabric.util.getRandomInt(e.y-i,e.y+i),this.dotWidthVariance?r=fabric.util.getRandomInt(Math.max(1,this.dotWidth-this.dotWidthVariance),this.dotWidth+this.dotWidthVariance):r=this.dotWidth;var o=new fabric.Point(t,n);o.width=r,this.randomOpacity&&(o.opacity=fabric.util.getRandomInt(0,100)/100),this.sprayChunkPoints.push(o)}this.sprayChunks.push(this.sprayChunkPoints)}}),fabric.PatternBrush=fabric.util.createClass(fabric.PencilBrush,{getPatternSrc:function(){var e=20,t=5,n=fabric.document.createElement(\"canvas\"),r=n.getContext(\"2d\");return n.width=n.height=e+t,r.fillStyle=this.color,r.beginPath(),r.arc(e/2,e/2,e/2,0,Math.PI*2,!1),r.closePath(),r.fill(),n},getPatternSrcFunction:function(){return String(this.getPatternSrc).replace(\"this.color\",'\"'+this.color+'\"')},getPattern:function(){return this.canvas.contextTop.createPattern(this.source||this.getPatternSrc(),\"repeat\")},_setBrushStyles:function(){this.callSuper(\"_setBrushStyles\"),this.canvas.contextTop.strokeStyle=this.getPattern()},createPath:function(e){var t=this.callSuper(\"createPath\",e);return t.stroke=new fabric.Pattern({source:this.source||this.getPatternSrcFunction()}),t}}),function(){var e=fabric.util.getPointer,t=fabric.util.degreesToRadians,n=fabric.util.radiansToDegrees,r=Math.atan2,i=Math.abs,s=.5;fabric.Canvas=fabric.util.createClass(fabric.StaticCanvas,{initialize:function(e,t){t||(t={}),this._initStatic(e,t),this._initInteractive(),this._createCacheCanvas(),fabric.Canvas.activeInstance=this},uniScaleTransform:!1,centeredScaling:!1,centeredRotation:!1,interactive:!0,selection:!0,selectionColor:\"rgba(100, 100, 255, 0.3)\",selectionDashArray:[],selectionBorderColor:\"rgba(255, 255, 255, 0.3)\",selectionLineWidth:1,hoverCursor:\"move\",moveCursor:\"move\",defaultCursor:\"default\",freeDrawingCursor:\"crosshair\",rotationCursor:\"crosshair\",containerClass:\"canvas-container\",perPixelTargetFind:!1,targetFindTolerance:0,skipTargetFind:!1,_initInteractive:function(){this._currentTransform=null,this._groupSelector=null,this._initWrapperElement(),this._createUpperCanvas(),this._initEventListeners(),this.freeDrawingBrush=fabric.PencilBrush&&new fabric.PencilBrush(this),this.calcOffset()},_resetCurrentTransform:function(e){var t=this._currentTransform;t.target.set({scaleX:t.original.scaleX,scaleY:t.original.scaleY,left:t.original.left,top:t.original.top}),this._shouldCenterTransform(e,t.target)?t.action===\"rotate\"?this._setOriginToCenter(t.target):(t.originX!==\"center\"&&(t.originX===\"right\"?t.mouseXSign=-1:t.mouseXSign=1),t.originY!==\"center\"&&(t.originY===\"bottom\"?t.mouseYSign=-1:t.mouseYSign=1),t.originX=\"center\",t.originY=\"center\"):(t.originX=t.original.originX,t.originY=t.original.originY)},containsPoint:function(e,t){var n=this.getPointer(e,!0),r=this._normalizePointer(t,n);return t.containsPoint(r)||t._findTargetCorner(n)},_normalizePointer:function(e,t){var n=this.getActiveGroup(),r=t.x,i=t.y,s=n&&e.type!==\"group\"&&n.contains(e),o;return s&&(o=new fabric.Point(n.left,n.top),o=fabric.util.transformPoint(o,this.viewportTransform,!0),r-=o.x,i-=o.y),{x:r,y:i}},isTargetTransparent:function(e,t,n){var r=e.hasBorders,i=e.transparentCorners;e.hasBorders=e.transparentCorners=!1,this._draw(this.contextCache,e),e.hasBorders=r,e.transparentCorners=i;var s=fabric.util.isTransparent(this.contextCache,t,n,this.targetFindTolerance);return this.clearContext(this.contextCache),s},_shouldClearSelection:function(e,t){var n=this.getActiveGroup(),r=this.getActiveObject();return!t||t&&n&&!n.contains(t)&&n!==t&&!e.shiftKey||t&&!t.evented||t&&!t.selectable&&r&&r!==t},_shouldCenterTransform:function(e,t){if(!t)return;var n=this._currentTransform,r;return n.action===\"scale\"||n.action===\"scaleX\"||n.action===\"scaleY\"?r=this.centeredScaling||t.centeredScaling:n.action===\"rotate\"&&(r=this.centeredRotation||t.centeredRotation),r?!e.altKey:e.altKey},_getOriginFromCorner:function(e,t){var n={x:e.originX,y:e.originY};if(t===\"ml\"||t===\"tl\"||t===\"bl\")n.x=\"right\";else if(t===\"mr\"||t===\"tr\"||t===\"br\")n.x=\"left\";if(t===\"tl\"||t===\"mt\"||t===\"tr\")n.y=\"bottom\";else if(t===\"bl\"||t===\"mb\"||t===\"br\")n.y=\"top\";return n},_getActionFromCorner:function(e,t){var n=\"drag\";return t&&(n=t===\"ml\"||t===\"mr\"?\"scaleX\":t===\"mt\"||t===\"mb\"?\"scaleY\":t===\"mtr\"?\"rotate\":\"scale\"),n},_setupCurrentTransform:function(e,n){if(!n)return;var r=this.getPointer(e),i=n._findTargetCorner(this.getPointer(e,!0)),s=this._getActionFromCorner(n,i),o=this._getOriginFromCorner(n,i);this._currentTransform={target:n,action:s,scaleX:n.scaleX,scaleY:n.scaleY,offsetX:r.x-n.left,offsetY:r.y-n.top,originX:o.x,originY:o.y,ex:r.x,ey:r.y,left:n.left,top:n.top,theta:t(n.angle),width:n.width*n.scaleX,mouseXSign:1,mouseYSign:1},this._currentTransform.original={left:n.left,top:n.top,scaleX:n.scaleX,scaleY:n.scaleY,originX:o.x,originY:o.y},this._resetCurrentTransform(e)},_translateObject:function(e,t){var n=this._currentTransform.target;n.get(\"lockMovementX\")||n.set(\"left\",e-this._currentTransform.offsetX),n.get(\"lockMovementY\")||n.set(\"top\",t-this._currentTransform.offsetY)},_scaleObject:function(e,t,n){var r=this._currentTransform,i=r.target,s=i.get(\"lockScalingX\"),o=i.get(\"lockScalingY\"),u=i.get(\"lockScalingFlip\");if(s&&o)return;var a=i.translateToOriginPoint(i.getCenterPoint(),r.originX,r.originY),f=i.toLocalPoint(new fabric.Point(e,t),r.originX,r.originY);this._setLocalMouse(f,r),this._setObjectScale(f,r,s,o,n,u),i.setPositionByOrigin(a,r.originX,r.originY)},_setObjectScale:function(e,t,n,r,i,s){var o=t.target,u=!1,a=!1;t.newScaleX=e.x/(o.width+o.strokeWidth),t.newScaleY=e.y/(o.height+o.strokeWidth),s&&t.newScaleX<=0&&t.newScaleX<o.scaleX&&(u=!0),s&&t.newScaleY<=0&&t.newScaleY<o.scaleY&&(a=!0),i===\"equally\"&&!n&&!r?u||a||this._scaleObjectEqually(e,o,t):i?i===\"x\"&&!o.get(\"lockUniScaling\")?u||n||o.set(\"scaleX\",t.newScaleX):i===\"y\"&&!o.get(\"lockUniScaling\")&&(a||r||o.set(\"scaleY\",t.newScaleY)):(u||n||o.set(\"scaleX\",t.newScaleX),a||r||o.set(\"scaleY\",t.newScaleY)),u||a||this._flipObject(t,i)},_scaleObjectEqually:function(e,t,n){var r=e.y+e.x,i=(t.height+t.strokeWidth)*n.original.scaleY+(t.width+t.strokeWidth)*n.original.scaleX;n.newScaleX=n.original.scaleX*r/i,n.newScaleY=n.original.scaleY*r/i,t.set(\"scaleX\",n.newScaleX),t.set(\"scaleY\",n.newScaleY)},_flipObject:function(e,t){e.newScaleX<0&&t!==\"y\"&&(e.originX===\"left\"?e.originX=\"right\":e.originX===\"right\"&&(e.originX=\"left\")),e.newScaleY<0&&t!==\"x\"&&(e.originY===\"top\"?e.originY=\"bottom\":e.originY===\"bottom\"&&(e.originY=\"top\"))},_setLocalMouse:function(e,t){var n=t.target;t.originX===\"right\"?e.x*=-1:t.originX===\"center\"&&(e.x*=t.mouseXSign*2,e.x<0&&(t.mouseXSign=-t.mouseXSign)),t.originY===\"bottom\"?e.y*=-1:t.originY===\"center\"&&(e.y*=t.mouseYSign*2,e.y<0&&(t.mouseYSign=-t.mouseYSign)),i(e.x)>n.padding?e.x<0?e.x+=n.padding:e.x-=n.padding:e.x=0,i(e.y)>n.padding?e.y<0?e.y+=n.padding:e.y-=n.padding:e.y=0},_rotateObject:function(e,t){var i=this._currentTransform;if(i.target.get(\"lockRotation\"))return;var s=r(i.ey-i.top,i.ex-i.left),o=r(t-i.top,e-i.left),u=n(o-s+i.theta);u<0&&(u=360+u),i.target.angle=u},setCursor:function(e){this.upperCanvasEl.style.cursor=e},_resetObjectTransform:function(e){e.scaleX=1,e.scaleY=1,e.setAngle(0)},_drawSelection:function(){var e=this.contextTop,t=this._groupSelector,n=t.left,r=t.top,o=i(n),u=i(r);e.fillStyle=this.selectionColor,e.fillRect(t.ex-(n>0?0:-n),t.ey-(r>0?0:-r),o,u),e.lineWidth=this.selectionLineWidth,e.strokeStyle=this.selectionBorderColor;if(this.selectionDashArray.length>1){var a=t.ex+s-(n>0?0:o),f=t.ey+s-(r>0?0:u);e.beginPath(),fabric.util.drawDashedLine(e,a,f,a+o,f,this.selectionDashArray),fabric.util.drawDashedLine(e,a,f+u-1,a+o,f+u-1,this.selectionDashArray),fabric.util.drawDashedLine(e,a,f,a,f+u,this.selectionDashArray),fabric.util.drawDashedLine(e,a+o-1,f,a+o-1,f+u,this.selectionDashArray),e.closePath(),e.stroke()}else e.strokeRect(t.ex+s-(n>0?0:o),t.ey+s-(r>0?0:u),o,u)},_isLastRenderedObject:function(e){return this.controlsAboveOverlay&&this.lastRenderedObjectWithControlsAboveOverlay&&this.lastRenderedObjectWithControlsAboveOverlay.visible&&this.containsPoint(e,this.lastRenderedObjectWithControlsAboveOverlay)&&this.lastRenderedObjectWithControlsAboveOverlay._findTargetCorner(this.getPointer(e,!0))},findTarget:function(e,t){if(this.skipTargetFind)return;if(this._isLastRenderedObject(e))return this.lastRenderedObjectWithControlsAboveOverlay;var n=this.getActiveGroup();if(n&&!t&&this.containsPoint(e,n))return n;var r=this._searchPossibleTargets(e);return this._fireOverOutEvents(r),r},_fireOverOutEvents:function(e){e?this._hoveredTarget!==e&&(this.fire(\"mouse:over\",{target:e}),e.fire(\"mouseover\"),this._hoveredTarget&&(this.fire(\"mouse:out\",{target:this._hoveredTarget}),this._hoveredTarget.fire(\"mouseout\")),this._hoveredTarget=e):this._hoveredTarget&&(this.fire(\"mouse:out\",{target:this._hoveredTarget}),this._hoveredTarget.fire(\"mouseout\"),this._hoveredTarget=null)},_checkTarget:function(e,t,n){if(t&&t.visible&&t.evented&&this.containsPoint(e,t)){if(!this.perPixelTargetFind&&!t.perPixelTargetFind||!!t.isEditing)return!0;var r=this.isTargetTransparent(t,n.x,n.y);if(!r)return!0}},_searchPossibleTargets:function(e){var t,n=this.getPointer(e,!0),r=this._objects.length;while(r--)if(this._checkTarget(e,this._objects[r],n)){this.relatedTarget=this._objects[r],t=this._objects[r];break}return t},getPointer:function(t,n,r){r||(r=this.upperCanvasEl);var i=e(t,r),s=r.getBoundingClientRect(),o=s.width||0,u=s.height||0,a;if(!o||!u)\"top\"in s&&\"bottom\"in s&&(u=Math.abs(s.top-s.bottom)),\"right\"in s&&\"left\"in s&&(o=Math.abs(s.right-s.left));return this.calcOffset(),i.x=i.x-this._offset.left,i.y=i.y-this._offset.top,n||(i=fabric.util.transformPoint(i,fabric.util.invertTransform(this.viewportTransform))),o===0||u===0?a={width:1,height:1}:a={width:r.width/o,height:r.height/u},{x:i.x*a.width,y:i.y*a.height}},_createUpperCanvas:function(){var e=this.lowerCanvasEl.className.replace(/\\s*lower-canvas\\s*/,\"\");this.upperCanvasEl=this._createCanvasElement(),fabric.util.addClass(this.upperCanvasEl,\"upper-canvas \"+e),this.wrapperEl.appendChild(this.upperCanvasEl),this._copyCanvasStyle(this.lowerCanvasEl,this.upperCanvasEl),this._applyCanvasStyle(this.upperCanvasEl),this.contextTop=this.upperCanvasEl.getContext(\"2d\")},_createCacheCanvas:function(){this.cacheCanvasEl=this._createCanvasElement(),this.cacheCanvasEl.setAttribute(\"width\",this.width),this.cacheCanvasEl.setAttribute(\"height\",this.height),this.contextCache=this.cacheCanvasEl.getContext(\"2d\")},_initWrapperElement:function(){this.wrapperEl=fabric.util.wrapElement(this.lowerCanvasEl,\"div\",{\"class\":this.containerClass}),fabric.util.setStyle(this.wrapperEl,{width:this.getWidth()+\"px\",height:this.getHeight()+\"px\",position:\"relative\"}),fabric.util.makeElementUnselectable(this.wrapperEl)},_applyCanvasStyle:function(e){var t=this.getWidth()||e.width,n=this.getHeight()||e.height;fabric.util.setStyle(e,{position:\"absolute\",width:t+\"px\",height:n+\"px\",left:0,top:0}),e.width=t,e.height=n,fabric.util.makeElementUnselectable(e)},_copyCanvasStyle:function(e,t){t.style.cssText=e.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl},_setActiveObject:function(e){this._activeObject&&this._activeObject.set(\"active\",!1),this._activeObject=e,e.set(\"active\",!0)},setActiveObject:function(e,t){return this._setActiveObject(e),this.renderAll(),this.fire(\"object:selected\",{target:e,e:t}),e.fire(\"selected\",{e:t}),this},getActiveObject:function(){return this._activeObject},_discardActiveObject:function(){this._activeObject&&this._activeObject.set(\"active\",!1),this._activeObject=null},discardActiveObject:function(e){return this._discardActiveObject(),this.renderAll(),this.fire(\"selection:cleared\",{e:e}),this},_setActiveGroup:function(e){this._activeGroup=e,e&&e.set(\"active\",!0)},setActiveGroup:function(e,t){return this._setActiveGroup(e),e&&(this.fire(\"object:selected\",{target:e,e:t}),e.fire(\"selected\",{e:t})),this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var e=this.getActiveGroup();e&&e.destroy(),this.setActiveGroup(null)},discardActiveGroup:function(e){return this._discardActiveGroup(),this.fire(\"selection:cleared\",{e:e}),this},deactivateAll:function(){var e=this.getObjects(),t=0,n=e.length;for(;t<n;t++)e[t].set(\"active\",!1);return this._discardActiveGroup(),this._discardActiveObject(),this},deactivateAllWithDispatch:function(e){var t=this.getActiveGroup()||this.getActiveObject();return t&&this.fire(\"before:selection:cleared\",{target:t,e:e}),this.deactivateAll(),t&&this.fire(\"selection:cleared\",{e:e}),this},drawControls:function(e){var t=this.getActiveGroup();t?this._drawGroupControls(e,t):this._drawObjectsControls(e)},_drawGroupControls:function(e,t){t._renderControls(e)},_drawObjectsControls:function(e){for(var t=0,n=this._objects.length;t<n;++t){if(!this._objects[t]||!this._objects[t].active)continue;this._objects[t]._renderControls(e),this.lastRenderedObjectWithControlsAboveOverlay=this._objects[t]}}});for(var o in fabric.StaticCanvas)o!==\"prototype\"&&(fabric.Canvas[o]=fabric.StaticCanvas[o]);fabric.isTouchSupported&&(fabric.Canvas.prototype._setCursorFromEvent=function(){}),fabric.Element=fabric.Canvas}(),function(){var e={mt:0,tr:1,mr:2,br:3,mb:4,bl:5,ml:6,tl:7},t=fabric.util.addListener,n=fabric.util.removeListener;fabric.util.object.extend(fabric.Canvas.prototype,{cursorMap:[\"n-resize\",\"ne-resize\",\"e-resize\",\"se-resize\",\"s-resize\",\"sw-resize\",\"w-resize\",\"nw-resize\"],_initEventListeners:function(){this._bindEvents(),t(fabric.window,\"resize\",this._onResize),t(this.upperCanvasEl,\"mousedown\",this._onMouseDown),t(this.upperCanvasEl,\"mousemove\",this._onMouseMove),t(this.upperCanvasEl,\"mousewheel\",this._onMouseWheel),t(this.upperCanvasEl,\"touchstart\",this._onMouseDown),t(this.upperCanvasEl,\"touchmove\",this._onMouseMove),typeof Event!=\"undefined\"&&\"add\"in Event&&(Event.add(this.upperCanvasEl,\"gesture\",this._onGesture),Event.add(this.upperCanvasEl,\"drag\",this._onDrag),Event.add(this.upperCanvasEl,\"orientation\",this._onOrientationChange),Event.add(this.upperCanvasEl,\"shake\",this._onShake))},_bindEvents:function(){this._onMouseDown=this._onMouseDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseUp=this._onMouseUp.bind(this),this._onResize=this._onResize.bind(this),this._onGesture=this._onGesture.bind(this),this._onDrag=this._onDrag.bind(this),this._onShake=this._onShake.bind(this),this._onOrientationChange=this._onOrientationChange.bind(this),this._onMouseWheel=this._onMouseWheel.bind(this)},removeListeners:function(){n(fabric.window,\"resize\",this._onResize),n(this.upperCanvasEl,\"mousedown\",this._onMouseDown),n(this.upperCanvasEl,\"mousemove\",this._onMouseMove),n(this.upperCanvasEl,\"mousewheel\",this._onMouseWheel),n(this.upperCanvasEl,\"touchstart\",this._onMouseDown),n(this.upperCanvasEl,\"touchmove\",this._onMouseMove),typeof Event!=\"undefined\"&&\"remove\"in Event&&(Event.remove(this.upperCanvasEl,\"gesture\",this._onGesture),Event.remove(this.upperCanvasEl,\"drag\",this._onDrag),Event.remove(this.upperCanvasEl,\"orientation\",this._onOrientationChange),Event.remove(this.upperCanvasEl,\"shake\",this._onShake))},_onGesture:function(e,t){this.__onTransformGesture&&this.__onTransformGesture(e,t)},_onDrag:function(e,t){this.__onDrag&&this.__onDrag(e,t)},_onMouseWheel:function(e,t){this.__onMouseWheel&&this.__onMouseWheel(e,t)},_onOrientationChange:function(e,t){this.__onOrientationChange&&this.__onOrientationChange(e,t)},_onShake:function(e,t){this.__onShake&&this.__onShake(e,t)},_onMouseDown:function(e){this.__onMouseDown(e),t(fabric.document,\"touchend\",this._onMouseUp),t(fabric.document,\"touchmove\",this._onMouseMove),n(this.upperCanvasEl,\"mousemove\",this._onMouseMove),n(this.upperCanvasEl,\"touchmove\",this._onMouseMove),e.type===\"touchstart\"?n(this.upperCanvasEl,\"mousedown\",this._onMouseDown):(t(fabric.document,\"mouseup\",this._onMouseUp),t(fabric.document,\"mousemove\",this._onMouseMove))},_onMouseUp:function(e){this.__onMouseUp(e),n(fabric.document,\"mouseup\",this._onMouseUp),n(fabric.document,\"touchend\",this._onMouseUp),n(fabric.document,\"mousemove\",this._onMouseMove),n(fabric.document,\"touchmove\",this._onMouseMove),t(this.upperCanvasEl,\"mousemove\",this._onMouseMove),t(this.upperCanvasEl,\"touchmove\",this._onMouseMove);if(e.type===\"touchend\"){var r=this;setTimeout(function(){t(r.upperCanvasEl,\"mousedown\",r._onMouseDown)},400)}},_onMouseMove:function(e){!this.allowTouchScrolling&&e.preventDefault&&e.preventDefault(),this.__onMouseMove(e)},_onResize:function(){this.calcOffset()},_shouldRender:function(e,t){var n=this.getActiveGroup()||this.getActiveObject();return!!(e&&(e.isMoving||e!==n)||!e&&!!n||!e&&!n&&!this._groupSelector||t&&this._previousPointer&&this.selection&&(t.x!==this._previousPointer.x||t.y!==this._previousPointer.y))},__onMouseUp:function(e){var t;if(this.isDrawingMode&&this._isCurrentlyDrawing){this._onMouseUpInDrawingMode(e);return}this._currentTransform?(this._finalizeCurrentTransform(),t=this._currentTransform.target):t=this.findTarget(e,!0);var n=this._shouldRender(t,this.getPointer(e));this._maybeGroupObjects(e),t&&(t.isMoving=!1),n&&this.renderAll(),this._handleCursorAndEvent(e,t)},_handleCursorAndEvent:function(e,t){this._setCursorFromEvent(e,t);var n=this;setTimeout(function(){n._setCursorFromEvent(e,t)},50),this.fire(\"mouse:up\",{target:t,e:e}),t&&t.fire(\"mouseup\",{e:e})},_finalizeCurrentTransform:function(){var e=this._currentTransform,t=e.target;t._scaling&&(t._scaling=!1),t.setCoords(),this.stateful&&t.hasStateChanged()&&(this.fire(\"object:modified\",{target:t}),t.fire(\"modified\")),this._restoreOriginXY(t)},_restoreOriginXY:function(e){if(this._previousOriginX&&this._previousOriginY){var t=e.translateToOriginPoint(e.getCenterPoint(),this._previousOriginX,this._previousOriginY);e.originX=this._previousOriginX,e.originY=this._previousOriginY,e.left=t.x,e.top=t.y,this._previousOriginX=null,this._previousOriginY=null}},_onMouseDownInDrawingMode:function(e){this._isCurrentlyDrawing=!0,this.discardActiveObject(e).renderAll(),this.clipTo&&fabric.util.clipContext(this,this.contextTop);var t=fabric.util.invertTransform(this.viewportTransform),n=fabric.util.transformPoint(this.getPointer(e,!0),t);this.freeDrawingBrush.onMouseDown(n),this.fire(\"mouse:down\",{e:e})},_onMouseMoveInDrawingMode:function(e){if(this._isCurrentlyDrawing){var t=fabric.util.invertTransform(this.viewportTransform),n=fabric.util.transformPoint(this.getPointer(e,!0),t);this.freeDrawingBrush.onMouseMove(n)}this.setCursor(this.freeDrawingCursor),this.fire(\"mouse:move\",{e:e})},_onMouseUpInDrawingMode:function(e){this._isCurrentlyDrawing=!1,this.clipTo&&this.contextTop.restore(),this.freeDrawingBrush.onMouseUp(),this.fire(\"mouse:up\",{e:e})},__onMouseDown:function(e){var t=\"which\"in e?e.which===1:e.button===1;if(!t&&!fabric.isTouchSupported)return;if(this.isDrawingMode){this._onMouseDownInDrawingMode(e);return}if(this._currentTransform)return;var n=this.findTarget(e),r=this.getPointer(e,!0);this._previousPointer=r;var i=this._shouldRender(n,r),s=this._shouldGroup(e,n);this._shouldClearSelection(e,n)?this._clearSelection(e,n,r):s&&(this._handleGrouping(e,n),n=this.getActiveGroup()),n&&n.selectable&&!s&&(this._beforeTransform(e,n),this._setupCurrentTransform(e,n)),i&&this.renderAll(),this.fire(\"mouse:down\",{target:n,e:e}),n&&n.fire(\"mousedown\",{e:e})},_beforeTransform:function(e,t){var n;this.stateful&&t.saveState(),(n=t._findTargetCorner(this.getPointer(e)))&&this.onBeforeScaleRotate(t),t!==this.getActiveGroup()&&t!==this.getActiveObject()&&(this.deactivateAll(),this.setActiveObject(t,e))},_clearSelection:function(e,t,n){this.deactivateAllWithDispatch(e),t&&t.selectable?this.setActiveObject(t,e):this.selection&&(this._groupSelector={ex:n.x,ey:n.y,top:0,left:0})},_setOriginToCenter:function(e){this._previousOriginX=this._currentTransform.target.originX,this._previousOriginY=this._currentTransform.target.originY;var t=e.getCenterPoint();e.originX=\"center\",e.originY=\"center\",e.left=t.x,e.top=t.y,this._currentTransform.left=e.left,this._currentTransform.top=e.top},_setCenterToOrigin:function(e){var t=e.translateToOriginPoint(e.getCenterPoint(),this._previousOriginX,this._previousOriginY);e.originX=this._previousOriginX,e.originY=this._previousOriginY,e.left=t.x,e.top=t.y,this._previousOriginX=null,this._previousOriginY=null},__onMouseMove:function(e){var t,n;if(this.isDrawingMode){this._onMouseMoveInDrawingMode(e);return}var r=this._groupSelector;r?(n=this.getPointer(e,!0),r.left=n.x-r.ex,r.top=n.y-r.ey,this.renderTop()):this._currentTransform?this._transformObject(e):(t=this.findTarget(e),!t||t&&!t.selectable?this.setCursor(this.defaultCursor):this._setCursorFromEvent(e,t)),this.fire(\"mouse:move\",{target:t,e:e}),t&&t.fire(\"mousemove\",{e:e})},_transformObject:function(e){var t=this.getPointer(e),n=this._currentTransform;n.reset=!1,n.target.isMoving=!0,this._beforeScaleTransform(e,n),this._performTransformAction(e,n,t),this.renderAll()},_performTransformAction:function(e,t,n){var r=n.x,i=n.y,s=t.target,o=t.action;o===\"rotate\"?(this._rotateObject(r,i),this._fire(\"rotating\",s,e)):o===\"scale\"?(this._onScale(e,t,r,i),this._fire(\"scaling\",s,e)):o===\"scaleX\"?(this._scaleObject(r,i,\"x\"),this._fire(\"scaling\",s,e)):o===\"scaleY\"?(this._scaleObject(r,i,\"y\"),this._fire(\"scaling\",s,e)):(this._translateObject(r,i),this._fire(\"moving\",s,e),this.setCursor(this.moveCursor))},_fire:function(e,t,n){this.fire(\"object:\"+e,{target:t,e:n}),t.fire(e,{e:n})},_beforeScaleTransform:function(e,t){if(t.action===\"scale\"||t.action===\"scaleX\"||t.action===\"scaleY\"){var n=this._shouldCenterTransform(e,t.target);if(n&&(t.originX!==\"center\"||t.originY!==\"center\")||!n&&t.originX===\"center\"&&t.originY===\"center\")this._resetCurrentTransform(e),t.reset=!0}},_onScale:function(e,t,n,r){(e.shiftKey||this.uniScaleTransform)&&!t.target.get(\"lockUniScaling\")?(t.currentAction=\"scale\",this._scaleObject(n,r)):(!t.reset&&t.currentAction===\"scale\"&&this._resetCurrentTransform(e,t.target),t.currentAction=\"scaleEqually\",this._scaleObject(n,r,\"equally\"))},_setCursorFromEvent:function(e,t){if(!t||!t.selectable)return this.setCursor(this.defaultCursor),!1;var n=this.getActiveGroup(),r=t._findTargetCorner&&(!n||!n.contains(t))&&t._findTargetCorner(this.getPointer(e,!0));return r?this._setCornerCursor(r,t):this.setCursor(t.hoverCursor||this.hoverCursor),!0},_setCornerCursor:function(t,n){if(t in e)this.setCursor(this._getRotatedCornerCursor(t,n));else{if(t!==\"mtr\"||!n.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(t,n){var r=Math.round(n.getAngle()%360/45);return r<0&&(r+=8),r+=e[t],r%=8,this.cursorMap[r]}})}(),function(){var e=Math.min,t=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(e,t){var n=this.getActiveObject();return e.shiftKey&&(this.getActiveGroup()||n&&n!==t)&&this.selection},_handleGrouping:function(e,t){if(t===this.getActiveGroup()){t=this.findTarget(e,!0);if(!t||t.isType(\"group\"))return}this.getActiveGroup()?this._updateActiveGroup(t,e):this._createActiveGroup(t,e),this._activeGroup&&this._activeGroup.saveCoords()},_updateActiveGroup:function(e,t){var n=this.getActiveGroup();if(n.contains(e)){n.removeWithUpdate(e),this._resetObjectTransform(n),e.set(\"active\",!1);if(n.size()===1){this.discardActiveGroup(t),this.setActiveObject(n.item(0));return}}else n.addWithUpdate(e),this._resetObjectTransform(n);this.fire(\"selection:created\",{target:n,e:t}),n.set(\"active\",!0)},_createActiveGroup:function(e,t){if(this._activeObject&&e!==this._activeObject){var n=this._createGroup(e);n.addWithUpdate(),this.setActiveGroup(n),this._activeObject=null,this.fire(\"selection:created\",{target:n,e:t})}e.set(\"active\",!0)},_createGroup:function(e){var t=this.getObjects(),n=t.indexOf(this._activeObject)<t.indexOf(e),r=n?[this._activeObject,e]:[e,this._activeObject];return new fabric.Group(r,{originX:\"center\",originY:\"center\",canvas:this})},_groupSelectedObjects:function(e){var t=this._collectObjects();t.length===1?this.setActiveObject(t[0],e):t.length>1&&(t=new fabric.Group(t.reverse(),{originX:\"center\",originY:\"center\",canvas:this}),t.addWithUpdate(),this.setActiveGroup(t,e),t.saveCoords(),this.fire(\"selection:created\",{target:t}),this.renderAll())},_collectObjects:function(){var n=[],r,i=this._groupSelector.ex,s=this._groupSelector.ey,o=i+this._groupSelector.left,u=s+this._groupSelector.top,a=new fabric.Point(e(i,o),e(s,u)),f=new fabric.Point(t(i,o),t(s,u)),l=i===o&&s===u;for(var c=this._objects.length;c--;){r=this._objects[c];if(!r||!r.selectable||!r.visible)continue;if(r.intersectsWithRect(a,f)||r.isContainedWithinRect(a,f)||r.containsPoint(a)||r.containsPoint(f)){r.set(\"active\",!0),n.push(r);if(l)break}}return n},_maybeGroupObjects:function(e){this.selection&&this._groupSelector&&this._groupSelectedObjects(e);var t=this.getActiveGroup();t&&(t.setObjectsCoords().setCoords(),t.isMoving=!1,this.setCursor(this.defaultCursor)),this._groupSelector=null,this._currentTransform=null}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(e){e||(e={});var t=e.format||\"png\",n=e.quality||1,r=e.multiplier||1,i={left:e.left,top:e.top,width:e.width,height:e.height};return r!==1?this.__toDataURLWithMultiplier(t,n,i,r):this.__toDataURL(t,n,i)},__toDataURL:function(e,t,n){this.renderAll(!0);var r=this.upperCanvasEl||this.lowerCanvasEl,i=this.__getCroppedCanvas(r,n);e===\"jpg\"&&(e=\"jpeg\");var s=fabric.StaticCanvas.supports(\"toDataURLWithQuality\")?(i||r).toDataURL(\"image/\"+e,t):(i||r).toDataURL(\"image/\"+e);return this.contextTop&&this.clearContext(this.contextTop),this.renderAll(),i&&(i=null),s},__getCroppedCanvas:function(e,t){var n,r,i=\"left\"in t||\"top\"in t||\"width\"in t||\"height\"in t;return i&&(n=fabric.util.createCanvasElement(),r=n.getContext(\"2d\"),n.width=t.width||this.width,n.height=t.height||this.height,r.drawImage\n(e,-t.left||0,-t.top||0)),n},__toDataURLWithMultiplier:function(e,t,n,r){var i=this.getWidth(),s=this.getHeight(),o=i*r,u=s*r,a=this.getActiveObject(),f=this.getActiveGroup(),l=this.contextTop||this.contextContainer;r>1&&this.setWidth(o).setHeight(u),l.scale(r,r),n.left&&(n.left*=r),n.top&&(n.top*=r),n.width?n.width*=r:r<1&&(n.width=o),n.height?n.height*=r:r<1&&(n.height=u),f?this._tempRemoveBordersControlsFromGroup(f):a&&this.deactivateAll&&this.deactivateAll(),this.renderAll(!0);var c=this.__toDataURL(e,t,n);return this.width=i,this.height=s,l.scale(1/r,1/r),this.setWidth(i).setHeight(s),f?this._restoreBordersControlsOnGroup(f):a&&this.setActiveObject&&this.setActiveObject(a),this.contextTop&&this.clearContext(this.contextTop),this.renderAll(),c},toDataURLWithMultiplier:function(e,t,n){return this.toDataURL({format:e,multiplier:t,quality:n})},_tempRemoveBordersControlsFromGroup:function(e){e.origHasControls=e.hasControls,e.origBorderColor=e.borderColor,e.hasControls=!0,e.borderColor=\"rgba(0,0,0,0)\",e.forEachObject(function(e){e.origBorderColor=e.borderColor,e.borderColor=\"rgba(0,0,0,0)\"})},_restoreBordersControlsOnGroup:function(e){e.hideControls=e.origHideControls,e.borderColor=e.origBorderColor,e.forEachObject(function(e){e.borderColor=e.origBorderColor,delete e.origBorderColor})}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(e,t,n){return this.loadFromJSON(e,t,n)},loadFromJSON:function(e,t,n){if(!e)return;var r=typeof e==\"string\"?JSON.parse(e):e;this.clear();var i=this;return this._enlivenObjects(r.objects,function(){i._setBgOverlay(r,t)},n),this},_setBgOverlay:function(e,t){var n=this,r={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(!e.backgroundImage&&!e.overlayImage&&!e.background&&!e.overlay){t&&t();return}var i=function(){r.backgroundImage&&r.overlayImage&&r.backgroundColor&&r.overlayColor&&(n.renderAll(),t&&t())};this.__setBgOverlay(\"backgroundImage\",e.backgroundImage,r,i),this.__setBgOverlay(\"overlayImage\",e.overlayImage,r,i),this.__setBgOverlay(\"backgroundColor\",e.background,r,i),this.__setBgOverlay(\"overlayColor\",e.overlay,r,i),i()},__setBgOverlay:function(e,t,n,r){var i=this;if(!t){n[e]=!0;return}e===\"backgroundImage\"||e===\"overlayImage\"?fabric.Image.fromObject(t,function(t){i[e]=t,n[e]=!0,r&&r()}):this[\"set\"+fabric.util.string.capitalize(e,!0)](t,function(){n[e]=!0,r&&r()})},_enlivenObjects:function(e,t,n){var r=this;if(!e||e.length===0){t&&t();return}var i=this.renderOnAddRemove;this.renderOnAddRemove=!1,fabric.util.enlivenObjects(e,function(e){e.forEach(function(e,t){r.insertAt(e,t,!0)}),r.renderOnAddRemove=i,t&&t()},null,n)},_toDataURL:function(e,t){this.clone(function(n){t(n.toDataURL(e))})},_toDataURLWithMultiplier:function(e,t,n){this.clone(function(r){n(r.toDataURLWithMultiplier(e,t))})},clone:function(e,t){var n=JSON.stringify(this.toJSON(t));this.cloneWithoutData(function(t){t.loadFromJSON(n,function(){e&&e(t)})})},cloneWithoutData:function(e){var t=fabric.document.createElement(\"canvas\");t.width=this.getWidth(),t.height=this.getHeight();var n=new fabric.Canvas(t);n.clipTo=this.clipTo,this.backgroundImage?(n.setBackgroundImage(this.backgroundImage.src,function(){n.renderAll(),e&&e(n)}),n.backgroundImageOpacity=this.backgroundImageOpacity,n.backgroundImageStretch=this.backgroundImageStretch):e&&e(n)}}),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.toFixed,i=t.util.string.capitalize,s=t.util.degreesToRadians,o=t.StaticCanvas.supports(\"setLineDash\");if(t.Object)return;t.Object=t.util.createClass({type:\"object\",originX:\"left\",originY:\"top\",top:0,left:0,width:0,height:0,scaleX:1,scaleY:1,flipX:!1,flipY:!1,opacity:1,angle:0,cornerSize:12,transparentCorners:!0,hoverCursor:null,padding:0,borderColor:\"rgba(102,153,255,0.75)\",cornerColor:\"rgba(102,153,255,0.5)\",centeredScaling:!1,centeredRotation:!0,fill:\"rgb(0,0,0)\",fillRule:\"nonzero\",globalCompositeOperation:\"source-over\",backgroundColor:\"\",stroke:null,strokeWidth:1,strokeDashArray:null,strokeLineCap:\"butt\",strokeLineJoin:\"miter\",strokeMiterLimit:10,shadow:null,borderOpacityWhenMoving:.4,borderScaleFactor:1,transformMatrix:null,minScaleLimit:.01,selectable:!0,evented:!0,visible:!0,hasControls:!0,hasBorders:!0,hasRotatingPoint:!0,rotatingPointOffset:40,perPixelTargetFind:!1,includeDefaultValues:!0,clipTo:null,lockMovementX:!1,lockMovementY:!1,lockRotation:!1,lockScalingX:!1,lockScalingY:!1,lockUniScaling:!1,lockScalingFlip:!1,stateProperties:\"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor\".split(\" \"),initialize:function(e){e&&this.setOptions(e)},_initGradient:function(e){e.fill&&e.fill.colorStops&&!(e.fill instanceof t.Gradient)&&this.set(\"fill\",new t.Gradient(e.fill))},_initPattern:function(e){e.fill&&e.fill.source&&!(e.fill instanceof t.Pattern)&&this.set(\"fill\",new t.Pattern(e.fill)),e.stroke&&e.stroke.source&&!(e.stroke instanceof t.Pattern)&&this.set(\"stroke\",new t.Pattern(e.stroke))},_initClipping:function(e){if(!e.clipTo||typeof e.clipTo!=\"string\")return;var n=t.util.getFunctionBody(e.clipTo);typeof n!=\"undefined\"&&(this.clipTo=new Function(\"ctx\",n))},setOptions:function(e){for(var t in e)this.set(t,e[t]);this._initGradient(e),this._initPattern(e),this._initClipping(e)},transform:function(e,t){this.group&&this.group.transform(e,t);var n=t?this._getLeftTopCoords():this.getCenterPoint();e.translate(n.x,n.y),e.rotate(s(this.angle)),e.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1))},toObject:function(e){var n=t.Object.NUM_FRACTION_DIGITS,i={type:this.type,originX:this.originX,originY:this.originY,left:r(this.left,n),top:r(this.top,n),width:r(this.width,n),height:r(this.height,n),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject?this.stroke.toObject():this.stroke,strokeWidth:r(this.strokeWidth,n),strokeDashArray:this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:r(this.strokeMiterLimit,n),scaleX:r(this.scaleX,n),scaleY:r(this.scaleY,n),angle:r(this.getAngle(),n),flipX:this.flipX,flipY:this.flipY,opacity:r(this.opacity,n),shadow:this.shadow&&this.shadow.toObject?this.shadow.toObject():this.shadow,visible:this.visible,clipTo:this.clipTo&&String(this.clipTo),backgroundColor:this.backgroundColor,fillRule:this.fillRule,globalCompositeOperation:this.globalCompositeOperation};return this.includeDefaultValues||(i=this._removeDefaultValues(i)),t.util.populateWithProperties(this,i,e),i},toDatalessObject:function(e){return this.toObject(e)},_removeDefaultValues:function(e){var n=t.util.getKlass(e.type).prototype,r=n.stateProperties;return r.forEach(function(t){e[t]===n[t]&&delete e[t]}),e},toString:function(){return\"#<fabric.\"+i(this.type)+\">\"},get:function(e){return this[e]},_setObject:function(e){for(var t in e)this._set(t,e[t])},set:function(e,t){return typeof e==\"object\"?this._setObject(e):typeof t==\"function\"&&e!==\"clipTo\"?this._set(e,t(this.get(e))):this._set(e,t),this},_set:function(e,n){var i=e===\"scaleX\"||e===\"scaleY\";return i&&(n=this._constrainScale(n)),e===\"scaleX\"&&n<0?(this.flipX=!this.flipX,n*=-1):e===\"scaleY\"&&n<0?(this.flipY=!this.flipY,n*=-1):e===\"width\"||e===\"height\"?this.minScaleLimit=r(Math.min(.1,1/Math.max(this.width,this.height)),2):e===\"shadow\"&&n&&!(n instanceof t.Shadow)&&(n=new t.Shadow(n)),this[e]=n,this},toggle:function(e){var t=this.get(e);return typeof t==\"boolean\"&&this.set(e,!t),this},setSourcePath:function(e){return this.sourcePath=e,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:[1,0,0,1,0,0]},render:function(e,n){if(this.width===0||this.height===0||!this.visible)return;e.save(),this._setupCompositeOperation(e),n||this.transform(e),this._setStrokeStyles(e),this._setFillStyles(e),this.group&&this.group.type===\"path-group\"&&e.translate(-this.group.width/2,-this.group.height/2),this.transformMatrix&&e.transform.apply(e,this.transformMatrix),this._setOpacity(e),this._setShadow(e),this.clipTo&&t.util.clipContext(this,e),this._render(e,n),this.clipTo&&e.restore(),this._removeShadow(e),this._restoreCompositeOperation(e),e.restore()},_setOpacity:function(e){this.group&&this.group._setOpacity(e),e.globalAlpha*=this.opacity},_setStrokeStyles:function(e){this.stroke&&(e.lineWidth=this.strokeWidth,e.lineCap=this.strokeLineCap,e.lineJoin=this.strokeLineJoin,e.miterLimit=this.strokeMiterLimit,e.strokeStyle=this.stroke.toLive?this.stroke.toLive(e,this):this.stroke)},_setFillStyles:function(e){this.fill&&(e.fillStyle=this.fill.toLive?this.fill.toLive(e,this):this.fill)},_renderControls:function(e,n){var r=this.getViewportTransform();e.save();if(this.active&&!n){var i;this.group&&(i=t.util.transformPoint(this.group.getCenterPoint(),r),e.translate(i.x,i.y),e.rotate(s(this.group.angle))),i=t.util.transformPoint(this.getCenterPoint(),r,null!=this.group),this.group&&(i.x*=this.group.scaleX,i.y*=this.group.scaleY),e.translate(i.x,i.y),e.rotate(s(this.angle)),this.drawBorders(e),this.drawControls(e)}e.restore()},_setShadow:function(e){if(!this.shadow)return;e.shadowColor=this.shadow.color,e.shadowBlur=this.shadow.blur,e.shadowOffsetX=this.shadow.offsetX,e.shadowOffsetY=this.shadow.offsetY},_removeShadow:function(e){if(!this.shadow)return;e.shadowColor=\"\",e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0},_renderFill:function(e){if(!this.fill)return;e.save();if(this.fill.gradientTransform){var t=this.fill.gradientTransform;e.transform.apply(e,t)}this.fill.toLive&&e.translate(-this.width/2+this.fill.offsetX||0,-this.height/2+this.fill.offsetY||0),this.fillRule===\"evenodd\"?e.fill(\"evenodd\"):e.fill(),e.restore(),this.shadow&&!this.shadow.affectStroke&&this._removeShadow(e)},_renderStroke:function(e){if(!this.stroke||this.strokeWidth===0)return;e.save();if(this.strokeDashArray)1&this.strokeDashArray.length&&this.strokeDashArray.push.apply(this.strokeDashArray,this.strokeDashArray),o?(e.setLineDash(this.strokeDashArray),this._stroke&&this._stroke(e)):this._renderDashedStroke&&this._renderDashedStroke(e),e.stroke();else{if(this.stroke.gradientTransform){var t=this.stroke.gradientTransform;e.transform.apply(e,t)}this._stroke?this._stroke(e):e.stroke()}this._removeShadow(e),e.restore()},clone:function(e,n){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(n),e):new t.Object(this.toObject(n))},cloneAsImage:function(e){var n=this.toDataURL();return t.util.loadImage(n,function(n){e&&e(new t.Image(n))}),this},toDataURL:function(e){e||(e={});var n=t.util.createCanvasElement(),r=this.getBoundingRect();n.width=r.width,n.height=r.height,t.util.wrapElement(n,\"div\");var i=new t.Canvas(n);e.format===\"jpg\"&&(e.format=\"jpeg\"),e.format===\"jpeg\"&&(i.backgroundColor=\"#fff\");var s={active:this.get(\"active\"),left:this.getLeft(),top:this.getTop()};this.set(\"active\",!1),this.setPositionByOrigin(new t.Point(n.width/2,n.height/2),\"center\",\"center\");var o=this.canvas;i.add(this);var u=i.toDataURL(e);return this.set(s).setCoords(),this.canvas=o,i.dispose(),i=null,u},isType:function(e){return this.type===e},complexity:function(){return 0},toJSON:function(e){return this.toObject(e)},setGradient:function(e,n){n||(n={});var r={colorStops:[]};r.type=n.type||(n.r1||n.r2?\"radial\":\"linear\"),r.coords={x1:n.x1,y1:n.y1,x2:n.x2,y2:n.y2};if(n.r1||n.r2)r.coords.r1=n.r1,r.coords.r2=n.r2;for(var i in n.colorStops){var s=new t.Color(n.colorStops[i]);r.colorStops.push({offset:i,color:s.toRgb(),opacity:s.getAlpha()})}return this.set(e,t.Gradient.forObject(this,r))},setPatternFill:function(e){return this.set(\"fill\",new t.Pattern(e))},setShadow:function(e){return this.set(\"shadow\",e?new t.Shadow(e):null)},setColor:function(e){return this.set(\"fill\",e),this},setAngle:function(e){var t=(this.originX!==\"center\"||this.originY!==\"center\")&&this.centeredRotation;return t&&this._setOriginToCenter(),this.set(\"angle\",e),t&&this._resetOrigin(),this},centerH:function(){return this.canvas.centerObjectH(this),this},centerV:function(){return this.canvas.centerObjectV(this),this},center:function(){return this.canvas.centerObject(this),this},remove:function(){return this.canvas.remove(this),this},getLocalPointer:function(e,t){t=t||this.canvas.getPointer(e);var n=this.translateToOriginPoint(this.getCenterPoint(),\"left\",\"top\");return{x:t.x-n.x,y:t.y-n.y}},_setupCompositeOperation:function(e){this.globalCompositeOperation&&(this._prevGlobalCompositeOperation=e.globalCompositeOperation,e.globalCompositeOperation=this.globalCompositeOperation)},_restoreCompositeOperation:function(e){this.globalCompositeOperation&&this._prevGlobalCompositeOperation&&(e.globalCompositeOperation=this._prevGlobalCompositeOperation)}}),t.util.createAccessors(t.Object),t.Object.prototype.rotate=t.Object.prototype.setAngle,n(t.Object.prototype,t.Observable),t.Object.NUM_FRACTION_DIGITS=2,t.Object.__uid=0}(typeof exports!=\"undefined\"?exports:this),function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{translateToCenterPoint:function(t,n,r){var i=t.x,s=t.y,o=this.stroke?this.strokeWidth:0;return n===\"left\"?i=t.x+(this.getWidth()+o*this.scaleX)/2:n===\"right\"&&(i=t.x-(this.getWidth()+o*this.scaleX)/2),r===\"top\"?s=t.y+(this.getHeight()+o*this.scaleY)/2:r===\"bottom\"&&(s=t.y-(this.getHeight()+o*this.scaleY)/2),fabric.util.rotatePoint(new fabric.Point(i,s),t,e(this.angle))},translateToOriginPoint:function(t,n,r){var i=t.x,s=t.y,o=this.stroke?this.strokeWidth:0;return n===\"left\"?i=t.x-(this.getWidth()+o*this.scaleX)/2:n===\"right\"&&(i=t.x+(this.getWidth()+o*this.scaleX)/2),r===\"top\"?s=t.y-(this.getHeight()+o*this.scaleY)/2:r===\"bottom\"&&(s=t.y+(this.getHeight()+o*this.scaleY)/2),fabric.util.rotatePoint(new fabric.Point(i,s),t,e(this.angle))},getCenterPoint:function(){var e=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(e,this.originX,this.originY)},getPointByOrigin:function(e,t){var n=this.getCenterPoint();return this.translateToOriginPoint(n,e,t)},toLocalPoint:function(t,n,r){var i=this.getCenterPoint(),s=this.stroke?this.strokeWidth:0,o,u;return n&&r?(n===\"left\"?o=i.x-(this.getWidth()+s*this.scaleX)/2:n===\"right\"?o=i.x+(this.getWidth()+s*this.scaleX)/2:o=i.x,r===\"top\"?u=i.y-(this.getHeight()+s*this.scaleY)/2:r===\"bottom\"?u=i.y+(this.getHeight()+s*this.scaleY)/2:u=i.y):(o=this.left,u=this.top),fabric.util.rotatePoint(new fabric.Point(t.x,t.y),i,-e(this.angle)).subtractEquals(new fabric.Point(o,u))},setPositionByOrigin:function(e,t,n){var r=this.translateToCenterPoint(e,t,n),i=this.translateToOriginPoint(r,this.originX,this.originY);this.set(\"left\",i.x),this.set(\"top\",i.y)},adjustPosition:function(t){var n=e(this.angle),r=this.getWidth()/2,i=Math.cos(n)*r,s=Math.sin(n)*r,o=this.getWidth(),u=Math.cos(n)*o,a=Math.sin(n)*o;this.originX===\"center\"&&t===\"left\"||this.originX===\"right\"&&t===\"center\"?(this.left-=i,this.top-=s):this.originX===\"left\"&&t===\"center\"||this.originX===\"center\"&&t===\"right\"?(this.left+=i,this.top+=s):this.originX===\"left\"&&t===\"right\"?(this.left+=u,this.top+=a):this.originX===\"right\"&&t===\"left\"&&(this.left-=u,this.top-=a),this.setCoords(),this.originX=t},_setOriginToCenter:function(){this._originalOriginX=this.originX,this._originalOriginY=this.originY;var e=this.getCenterPoint();this.originX=\"center\",this.originY=\"center\",this.left=e.x,this.top=e.y},_resetOrigin:function(){var e=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX,this._originalOriginY);this.originX=this._originalOriginX,this.originY=this._originalOriginY,this.left=e.x,this.top=e.y,this._originalOriginX=null,this._originalOriginY=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),\"left\",\"center\")}})}(),function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,intersectsWithRect:function(e,t){var n=this.oCoords,r=new fabric.Point(n.tl.x,n.tl.y),i=new fabric.Point(n.tr.x,n.tr.y),s=new fabric.Point(n.bl.x,n.bl.y),o=new fabric.Point(n.br.x,n.br.y),u=fabric.Intersection.intersectPolygonRectangle([r,i,o,s],e,t);return u.status===\"Intersection\"},intersectsWithObject:function(e){function t(e){return{tl:new fabric.Point(e.tl.x,e.tl.y),tr:new fabric.Point(e.tr.x,e.tr.y),bl:new fabric.Point(e.bl.x,e.bl.y),br:new fabric.Point(e.br.x,e.br.y)}}var n=t(this.oCoords),r=t(e.oCoords),i=fabric.Intersection.intersectPolygonPolygon([n.tl,n.tr,n.br,n.bl],[r.tl,r.tr,r.br,r.bl]);return i.status===\"Intersection\"},isContainedWithinObject:function(e){var t=e.getBoundingRect(),n=new fabric.Point(t.left,t.top),r=new fabric.Point(t.left+t.width,t.top+t.height);return this.isContainedWithinRect(n,r)},isContainedWithinRect:function(e,t){var n=this.getBoundingRect();return n.left>=e.x&&n.left+n.width<=t.x&&n.top>=e.y&&n.top+n.height<=t.y},containsPoint:function(e){var t=this._getImageLines(this.oCoords),n=this._findCrossPoints(e,t);return n!==0&&n%2===1},_getImageLines:function(e){return{topline:{o:e.tl,d:e.tr},rightline:{o:e.tr,d:e.br},bottomline:{o:e.br,d:e.bl},leftline:{o:e.bl,d:e.tl}}},_findCrossPoints:function(e,t){var n,r,i,s,o,u,a=0,f;for(var l in t){f=t[l];if(f.o.y<e.y&&f.d.y<e.y)continue;if(f.o.y>=e.y&&f.d.y>=e.y)continue;f.o.x===f.d.x&&f.o.x>=e.x?(o=f.o.x,u=e.y):(n=0,r=(f.d.y-f.o.y)/(f.d.x-f.o.x),i=e.y-n*e.x,s=f.o.y-r*f.o.x,o=-(i-s)/(n-r),u=i+n*o),o>=e.x&&(a+=1);if(a===2)break}return a},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(){this.oCoords||this.setCoords();var e=[this.oCoords.tl.x,this.oCoords.tr.x,this.oCoords.br.x,this.oCoords.bl.x],t=fabric.util.array.min(e),n=fabric.util.array.max(e),r=Math.abs(t-n),i=[this.oCoords.tl.y,this.oCoords.tr.y,this.oCoords.br.y,this.oCoords.bl.y],s=fabric.util.array.min(i),o=fabric.util.array.max(i),u=Math.abs(s-o);return{left:t,top:s,width:r,height:u}},getWidth:function(){return this.width*this.scaleX},getHeight:function(){return this.height*this.scaleY},_constrainScale:function(e){return Math.abs(e)<this.minScaleLimit?e<0?-this.minScaleLimit:this.minScaleLimit:e},scale:function(e){return e=this._constrainScale(e),e<0&&(this.flipX=!this.flipX,this.flipY=!this.flipY,e*=-1),this.scaleX=e,this.scaleY=e,this.setCoords(),this},scaleToWidth:function(e){var t=this.getBoundingRectWidth()/this.getWidth();return this.scale(e/this.width/t)},scaleToHeight:function(e){var t=this.getBoundingRectHeight()/this.getHeight();return this.scale(e/this.height/t)},setCoords:function(){var t=this.strokeWidth>1?this.strokeWidth:0,n=e(this.angle),r=this.getViewportTransform(),i=function(e){return fabric.util.transformPoint(e,r)},s=this.width,o=this.height,u=this.strokeLineCap===\"round\"||this.strokeLineCap===\"square\",a=this.type===\"line\"&&this.width===1,f=this.type===\"line\"&&this.height===1,l=u&&f||this.type!==\"line\",c=u&&a||this.type!==\"line\";a?s=t:f&&(o=t),l&&(s+=t),c&&(o+=t),this.currentWidth=s*this.scaleX,this.currentHeight=o*this.scaleY,this.currentWidth<0&&(this.currentWidth=Math.abs(this.currentWidth));var h=Math.sqrt(Math.pow(this.currentWidth/2,2)+Math.pow(this.currentHeight/2,2)),p=Math.atan(isFinite(this.currentHeight/this.currentWidth)?this.currentHeight/this.currentWidth:0),d=Math.cos(p+n)*h,v=Math.sin(p+n)*h,m=Math.sin(n),g=Math.cos(n),y=this.getCenterPoint(),b=new fabric.Point(this.currentWidth,this.currentHeight),w=new fabric.Point(y.x-d,y.y-v),E=new fabric.Point(w.x+b.x*g,w.y+b.x*m),S=new fabric.Point(w.x-b.y*m,w.y+b.y*g),x=new fabric.Point(w.x+b.x/2*g,w.y+b.x/2*m),T=i(w),N=i(E),C=i(new fabric.Point(E.x-b.y*m,E.y+b.y*g)),k=i(S),L=i(new fabric.Point(w.x-b.y/2*m,w.y+b.y/2*g)),A=i(x),O=i(new fabric.Point(E.x-b.y/2*m,E.y+b.y/2*g)),M=i(new fabric.Point(S.x+b.x/2*g,S.y+b.x/2*m)),_=i(new fabric.Point(x.x,x.y)),D=Math.cos(p+n)*this.padding*Math.sqrt(2),P=Math.sin(p+n)*this.padding*Math.sqrt(2);return T=T.add(new fabric.Point(-D,-P)),N=N.add(new fabric.Point(P,-D)),C=C.add(new fabric.Point(D,P)),k=k.add(new fabric.Point(-P,D)),L=L.add(new fabric.Point((-D-P)/2,(-P+D)/2)),A=A.add(new fabric.Point((P-D)/2,-(P+D)/2)),O=O.add(new fabric.Point((P+D)/2,(P-D)/2)),M=M.add(new fabric.Point((D-P)/2,(D+P)/2)),_=_.add(new fabric.Point((P-D)/2,-(P+D)/2)),this.oCoords={tl:T,tr:N,br:C,bl:k,ml:L,mt:A,mr:O,mb:M,mtr:_},this._setCornerCoords&&this._setCornerCoords(),this}})}(),fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){return this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this),this},bringToFront:function(){return this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this),this},sendBackwards:function(e){return this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,e):this.canvas.sendBackwards(this,e),this},bringForward:function(e){return this.group?fabric.StaticCanvas.prototype.bringForward.call(this.group,this,e):this.canvas.bringForward(this,e),this},moveTo:function(e){return this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,e):this.canvas.moveTo(this,e),this}}),fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(){var e=this.fill?this.fill.toLive?\"url(#SVGID_\"+this.fill.id+\")\":this.fill:\"none\",t=this.fillRule,n=this.stroke?this.stroke.toLive?\"url(#SVGID_\"+this.stroke.id+\")\":this.stroke:\"none\",r=this.strokeWidth?this.strokeWidth:\"0\",i=this.strokeDashArray?this.strokeDashArray.join(\" \"):\"\",s=this.strokeLineCap?this.strokeLineCap:\"butt\",o=this.strokeLineJoin?this.strokeLineJoin:\"miter\",u=this.strokeMiterLimit?this.strokeMiterLimit:\"4\",a=typeof this.opacity!=\"undefined\"?this.opacity:\"1\",f=this.visible?\"\":\" visibility: hidden;\",l=this.shadow&&this.type!==\"text\"?\"filter: url(#SVGID_\"+this.shadow.id+\");\":\"\";return[\"stroke: \",n,\"; \",\"stroke-width: \",r,\"; \",\"stroke-dasharray: \",i,\"; \",\"stroke-linecap: \",s,\"; \",\"stroke-linejoin: \",o,\"; \",\"stroke-miterlimit: \",u,\"; \",\"fill: \",e,\"; \",\"fill-rule: \",t,\"; \",\"opacity: \",a,\";\",l,f].join(\"\")},getSvgTransform:function(){if(this.group&&this.group.type===\"path-group\")return\"\";var e=fabric.util.toFixed,t=this.getAngle(),n=!this.canvas||this.canvas.svgViewportTransformation?this.getViewportTransform():[1,0,0,1,0,0],r=fabric.util.transformPoint(this.getCenterPoint(),n),i=fabric.Object.NUM_FRACTION_DIGITS,s=this.type===\"path-group\"?\"\":\"translate(\"+e(r.x,i)+\" \"+e(r.y,i)+\")\",o=t!==0?\" rotate(\"+e(t,i)+\")\":\"\",u=this.scaleX===1&&this.scaleY===1&&n[0]===1&&n[3]===1?\"\":\" scale(\"+e(this.scaleX*n[0],i)+\" \"+e(this.scaleY*n[3],i)+\")\",a=this.type===\"path-group\"?this.width*n[0]:0,f=this.flipX?\" matrix(-1 0 0 1 \"+a+\" 0) \":\"\",l=this.type===\"path-group\"?this.height*n[3]:0,c=this.flipY?\" matrix(1 0 0 -1 0 \"+l+\")\":\"\";return[s,o,u,f,c].join(\"\")},getSvgTransformMatrix:function(){return this.transformMatrix?\" matrix(\"+this.transformMatrix.join(\" \")+\")\":\"\"},_createBaseSVGMarkup:function(){var e=[];return this.fill&&this.fill.toLive&&e.push(this.fill.toSVG(this,!1)),this.stroke&&this.stroke.toLive&&e.push(this.stroke.toSVG(this,!1)),this.shadow&&e.push(this.shadow.toSVG(this)),e}}),fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(){return this.stateProperties.some(function(e){return this.get(e)!==this.originalState[e]},this)},saveState:function(e){return this.stateProperties.forEach(function(e){this.originalState[e]=this.get(e)},this),e&&e.stateProperties&&e.stateProperties.forEach(function(e){this.originalState[e]=this.get(e)},this),this},setupState:function(){return this.originalState={},this.saveState(),this}}),function(){var e=fabric.util.degreesToRadians,t=function(){return typeof G_vmlCanvasManager!=\"undefined\"};fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(e){if(!this.hasControls||!this.active)return!1;var t=e.x,n=e.y,r,i;for(var s in this.oCoords){if(!this.isControlVisible(s))continue;if(s===\"mtr\"&&!this.hasRotatingPoint)continue;if(!(!this.get(\"lockUniScaling\")||s!==\"mt\"&&s!==\"mr\"&&s!==\"mb\"&&s!==\"ml\"))continue;i=this._getImageLines(this.oCoords[s].corner),r=this._findCrossPoints({x:t,y:n},i);if(r!==0&&r%2===1)return this.__corner=s,s}return!1},_setCornerCoords:function(){var t=this.oCoords,n=e(this.angle),r=e(45-this.angle),i=Math.sqrt(2*Math.pow(this.cornerSize,2))/2,s=i*Math.cos(r),o=i*Math.sin(r),u=Math.sin(n),a=Math.cos(n);t.tl.corner={tl:{x:t.tl.x-o,y:t.tl.y-s},tr:{x:t.tl.x+s,y:t.tl.y-o},bl:{x:t.tl.x-s,y:t.tl.y+o},br:{x:t.tl.x+o,y:t.tl.y+s}},t.tr.corner={tl:{x:t.tr.x-o,y:t.tr.y-s},tr:{x:t.tr.x+s,y:t.tr.y-o},br:{x:t.tr.x+o,y:t.tr.y+s},bl:{x:t.tr.x-s,y:t.tr.y+o}},t.bl.corner={tl:{x:t.bl.x-o,y:t.bl.y-s},bl:{x:t.bl.x-s,y:t.bl.y+o},br:{x:t.bl.x+o,y:t.bl.y+s},tr:{x:t.bl.x+s,y:t.bl.y-o}},t.br.corner={tr:{x:t.br.x+s,y:t.br.y-o},bl:{x:t.br.x-s,y:t.br.y+o},br:{x:t.br.x+o,y:t.br.y+s},tl:{x:t.br.x-o,y:t.br.y-s}},t.ml.corner={tl:{x:t.ml.x-o,y:t.ml.y-s},tr:{x:t.ml.x+s,y:t.ml.y-o},bl:{x:t.ml.x-s,y:t.ml.y+o},br:{x:t.ml.x+o,y:t.ml.y+s}},t.mt.corner={tl:{x:t.mt.x-o,y:t.mt.y-s},tr:{x:t.mt.x+s,y:t.mt.y-o},bl:{x:t.mt.x-s,y:t.mt.y+o},br:{x:t.mt.x+o,y:t.mt.y+s}},t.mr.corner={tl:{x:t.mr.x-o,y:t.mr.y-s},tr:{x:t.mr.x+s,y:t.mr.y-o},bl:{x:t.mr.x-s,y:t.mr.y+o},br:{x:t.mr.x+o,y:t.mr.y+s}},t.mb.corner={tl:{x:t.mb.x-o,y:t.mb.y-s},tr:{x:t.mb.x+s,y:t.mb.y-o},bl:{x:t.mb.x-s,y:t.mb.y+o},br:{x:t.mb.x+o,y:t.mb.y+s}},t.mtr.corner={tl:{x:t.mtr.x-o+u*this.rotatingPointOffset,y:t.mtr.y-s-a*this.rotatingPointOffset},tr:{x:t.mtr.x+s+u*this.rotatingPointOffset,y:t.mtr.y-o-a*this.rotatingPointOffset},bl:{x:t.mtr.x-s+u*this.rotatingPointOffset,y:t.mtr.y+o-a*this.rotatingPointOffset},br:{x:t.mtr.x+o+u*this.rotatingPointOffset,y:t.mtr.y+s-a*this.rotatingPointOffset}}},drawBorders:function(e){if(!this.hasBorders)return this;var t=this.padding,n=t*2,r=this.getViewportTransform();e.save(),e.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,e.strokeStyle=this.borderColor;var i=1/this._constrainScale(this.scaleX),s=1/this._constrainScale(this.scaleY);e.lineWidth=1/this.borderScaleFactor;var o=this.getWidth(),u=this.getHeight(),a=this.strokeWidth>1?this.strokeWidth:0,f=this.strokeLineCap===\"round\"||this.strokeLineCap===\"square\",l=this.type===\"line\"&&this.width===1,c=this.type===\"line\"&&this.height===1,h=f&&c||this.type!==\"line\",p=f&&l||this.type!==\"line\";l?o=a/i:c&&(u=a/s),h&&(o+=a/i),p&&(u+=a/s);var d=fabric.util.transformPoint(new fabric.Point(o,u),r,!0),v=d.x,m=d.y;this.group&&(v*=this.group.scaleX,m*=this.group.scaleY),e.strokeRect(~~(-(v/2)-t)-.5,~~(-(m/2)-t)-.5,~~(v+n)+1,~~(m+n)+1);if(this.hasRotatingPoint&&this.isControlVisible(\"mtr\")&&!this.get(\"lockRotation\")&&this.hasControls){var g=(-m-t*2)/2;e.beginPath(),e.moveTo(0,g),e.lineTo(0,g-this.rotatingPointOffset),e.closePath(),e.stroke()}return e.restore(),this},drawControls:function(e){if(!this.hasControls)return this;var t=this.cornerSize,n=t/2,r=this.getViewportTransform(),i=this.strokeWidth>1?this.strokeWidth:0,s=this.width,o=this.height,u=this.strokeLineCap===\"round\"||this.strokeLineCap===\"square\",a=this.type===\"line\"&&this.width===1,f=this.type===\"line\"&&this.height===1,l=u&&f||this.type!==\"line\",c=u&&a||this.type!==\"line\";a?s=i:f&&(o=i),l&&(s+=i),c&&(o+=i),s*=this.scaleX,o*=this.scaleY;var h=fabric.util.transformPoint(new fabric.Point(s,o),r,!0),p=h.x,d=h.y,v=-(p/2),m=-(d/2),g=this.padding,y=n,b=n-t,w=this.transparentCorners?\"strokeRect\":\"fillRect\";return e.save(),e.lineWidth=1,e.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,e.strokeStyle=e.fillStyle=this.cornerColor,this._drawControl(\"tl\",e,w,v-y-g,m-y-g),this._drawControl(\"tr\",e,w,v+p-y+g,m-y-g),this._drawControl(\"bl\",e,w,v-y-g,m+d+b+g),this._drawControl(\"br\",e,w,v+p+b+g,m+d+b+g),this.get(\"lockUniScaling\")||(this._drawControl(\"mt\",e,w,v+p/2-y,m-y-g),this._drawControl(\"mb\",e,w,v+p/2-y,m+d+b+g),this._drawControl(\"mr\",e,w,v+p+b+g,m+d/2-y),this._drawControl(\"ml\",e,w,v-y-g,m+d/2-y)),this.hasRotatingPoint&&this._drawControl(\"mtr\",e,w,v+p/2-y,m-this.rotatingPointOffset-this.cornerSize/2-g),e.restore(),this},_drawControl:function(e,n,r,i,s){var o=this.cornerSize;this.isControlVisible(e)&&(t()||this.transparentCorners||n.clearRect(i,s,o,o),n[r](i,s,o,o))},isControlVisible:function(e){return this._getControlsVisibility()[e]},setControlVisible:function(e,t){return this._getControlsVisibility()[e]=t,this},setControlsVisibility:function(e){e||(e={});for(var t in e)this.setControlVisible(t,e[t]);return this},_getControlsVisibility:function(){return this._controlsVisibility||(this._controlsVisibility={tl:!0,tr:!0,br:!0,bl:!0,ml:!0,mt:!0,mr:!0,mb:!0,mtr:!0}),this._controlsVisibility}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(e,t){t=t||{};var n=function(){},r=t.onComplete||n,i=t.onChange||n,s=this;return fabric.util.animate({startValue:e.get(\"left\"),endValue:this.getCenter().left,duration:this.FX_DURATION,onChange:function(t){e.set(\"left\",t),s.renderAll(),i()},onComplete:function(){e.setCoords(),r()}}),this},fxCenterObjectV:function(e,t){t=t||{};var n=function(){},r=t.onComplete||n,i=t.onChange||n,s=this;return fabric.util.animate({startValue:e.get(\"top\"),endValue:this.getCenter().top,duration:this.FX_DURATION,onChange:function(t){e.set(\"top\",t),s.renderAll(),i()},onComplete:function(){e.setCoords(),r()}}),this},fxRemove:function(e,t){t=t||{};var n=function(){},r=t.onComplete||n,i=t.onChange||n,s=this;return fabric.util.animate({startValue:e.get(\"opacity\"),endValue:0,duration:this.FX_DURATION,onStart:function(){e.set(\"active\",!1)},onChange:function(t){e.set(\"opacity\",t),s.renderAll(),i()},onComplete:function(){s.remove(e),r()}}),this}}),fabric.util.object.extend(fabric.Object.prototype,{animate:function(){if(arguments[0]&&typeof arguments[0]==\"object\"){var e=[],t,n;for(t in arguments[0])e.push(t);for(var r=0,i=e.length;r<i;r++)t=e[r],n=r!==i-1,this._animate(t,arguments[0][t],arguments[1],n)}else this._animate.apply(this,arguments);return this},_animate:function(e,t,n,r){var i=this,s;t=t.toString(),n?n=fabric.util.object.clone(n):n={},~e.indexOf(\".\")&&(s=e.split(\".\"));var o=s?this.get(s[0])[s[1]]:this.get(e);\"from\"in n||(n.from=o),~t.indexOf(\"=\")?t=o+parseFloat(t.replace(\"=\",\"\")):t=parseFloat(t),fabric.util.animate({startValue:n.from,endValue:t,byValue:n.by,easing:n.easing,duration:n.duration,abort:n.abort&&function(){return n.abort.call(i)},onChange:function(t){s?i[s[0]][s[1]]=t:i.set(e,t);if(r)return;n.onChange&&n.onChange()},onComplete:function(){if(r)return;i.setCoords(),n.onComplete&&n.onComplete()}})}}),function(e){\"use strict\";function s(e,t){var n=e.origin,r=e.axis1,i=e.axis2,s=e.dimension,o=t.nearest,u=t.center,a=t.farthest;return function(){switch(this.get(n)){case o:return Math.min(this.get(r),this.get(i));case u:return Math.min(this.get(r),this.get(i))+.5*this.get(s);case a:return Math.max(this.get(r),this.get(i))}}}var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r={x1:1,x2:1,y1:1,y2:1},i=t.StaticCanvas.supports(\"setLineDash\");if(t.Line){t.warn(\"fabric.Line is already defined\");return}t.Line=t.util.createClass(t.Object,{type:\"line\",x1:0,y1:0,x2:0,y2:0,initialize:function(e,t){t=t||{},e||(e=[0,0,0,0]),this.callSuper(\"initialize\",t),this.set(\"x1\",e[0]),this.set(\"y1\",e[1]),this.set(\"x2\",e[2]),this.set(\"y2\",e[3]),this._setWidthHeight(t)},_setWidthHeight:function(e){e||(e={}),this.width=Math.abs(this.x2-this.x1)||1,this.height=Math.abs(this.y2-this.y1)||1,this.left=\"left\"in e?e.left:this._getLeftToOriginX(),this.top=\"top\"in e?e.top:this._getTopToOriginY()},_set:function(e,t){return this.callSuper(\"_set\",e,t),typeof r[e]!=\"undefined\"&&this._setWidthHeight(),this},_getLeftToOriginX:s({origin:\"originX\",axis1:\"x1\",axis2:\"x2\",dimension:\"width\"},{nearest:\"left\",center:\"center\",farthest:\"right\"}),_getTopToOriginY:s({origin:\"originY\",axis1:\"y1\",axis2:\"y2\",dimension:\"height\"},{nearest:\"top\",center:\"center\",farthest:\"bottom\"}),_render:function(e,t){e.beginPath();if(t){var n=this.getCenterPoint();e.translate(n.x,n.y)}if(!this.strokeDashArray||this.strokeDashArray&&i){var r=this.x1<=this.x2?-1:1,s=this.y1<=this.y2?-1:1;e.moveTo(this.width===1?0:r*this.width/2,this.height===1?0:s*this.height/2),e.lineTo(this.width===1?0:r*-1*this.width/2,this.height===1?0:s*-1*this.height/2)}e.lineWidth=this.strokeWidth;var o=e.strokeStyle;e.strokeStyle=this.stroke||e.fillStyle,this.stroke&&this._renderStroke(e),e.strokeStyle=o},_renderDashedStroke:function(e){var n=this.x1<=this.x2?-1:1,r=this.y1<=this.y2?-1:1,i=this.width===1?0:n*this.width/2,s=this.height===1?0:r*this.height/2;e.beginPath(),t.util.drawDashedLine(e,i,s,-i,-s,this.strokeDashArray),e.closePath()},toObject:function(e){return n\n(this.callSuper(\"toObject\",e),this.calcLinePoints())},calcLinePoints:function(){var e=this.x1<=this.x2?-1:1,t=this.y1<=this.y2?-1:1,n=e*this.width/2,r=t*this.height/2,i=e*-1*this.width/2,s=t*-1*this.height/2;return{x1:n,x2:i,y1:r,y2:s}},toSVG:function(e){var t=this._createBaseSVGMarkup(),n={x1:this.x1,x2:this.x2,y1:this.y1,y2:this.y2};if(!this.group||this.group.type!==\"path-group\")n=this.calcLinePoints();return t.push(\"<line \",'x1=\"',n.x1,'\" y1=\"',n.y1,'\" x2=\"',n.x2,'\" y2=\"',n.y2,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\"/>\\n'),e?e(t.join(\"\")):t.join(\"\")},complexity:function(){return 1}}),t.Line.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(\"x1 y1 x2 y2\".split(\" \")),t.Line.fromElement=function(e,r){var i=t.parseAttributes(e,t.Line.ATTRIBUTE_NAMES),s=[i.x1||0,i.y1||0,i.x2||0,i.y2||0];return new t.Line(s,n(i,r))},t.Line.fromObject=function(e){var n=[e.x1,e.y1,e.x2,e.y2];return new t.Line(n,e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";function i(e){return\"radius\"in e&&e.radius>0}var t=e.fabric||(e.fabric={}),n=Math.PI,r=t.util.object.extend;if(t.Circle){t.warn(\"fabric.Circle is already defined.\");return}t.Circle=t.util.createClass(t.Object,{type:\"circle\",radius:0,startAngle:0,endAngle:n*2,initialize:function(e){e=e||{},this.callSuper(\"initialize\",e),this.set(\"radius\",e.radius||0),this.startAngle=e.startAngle||this.startAngle,this.endAngle=e.endAngle||this.endAngle},_set:function(e,t){return this.callSuper(\"_set\",e,t),e===\"radius\"&&this.setRadius(t),this},toObject:function(e){return r(this.callSuper(\"toObject\",e),{radius:this.get(\"radius\"),startAngle:this.startAngle,endAngle:this.endAngle})},toSVG:function(e){var t=this._createBaseSVGMarkup(),r=0,i=0,s=(this.endAngle-this.startAngle)%(2*n);if(s===0)this.group&&this.group.type===\"path-group\"&&(r=this.left+this.radius,i=this.top+this.radius),t.push(\"<circle \",'cx=\"'+r+'\" cy=\"'+i+'\" ','r=\"',this.radius,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),\" \",this.getSvgTransformMatrix(),'\"/>\\n');else{var o=Math.cos(this.startAngle)*this.radius,u=Math.sin(this.startAngle)*this.radius,a=Math.cos(this.endAngle)*this.radius,f=Math.sin(this.endAngle)*this.radius,l=s>n?\"1\":\"0\";t.push('<path d=\"M '+o+\" \"+u,\" A \"+this.radius+\" \"+this.radius,\" 0 \",+l+\" 1\",\" \"+a+\" \"+f,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),\" \",this.getSvgTransformMatrix(),'\"/>\\n')}return e?e(t.join(\"\")):t.join(\"\")},_render:function(e,t){e.beginPath(),e.arc(t?this.left+this.radius:0,t?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1),this._renderFill(e),this._renderStroke(e)},getRadiusX:function(){return this.get(\"radius\")*this.get(\"scaleX\")},getRadiusY:function(){return this.get(\"radius\")*this.get(\"scaleY\")},setRadius:function(e){this.radius=e,this.set(\"width\",e*2).set(\"height\",e*2)},complexity:function(){return 1}}),t.Circle.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(\"cx cy r\".split(\" \")),t.Circle.fromElement=function(e,n){n||(n={});var s=t.parseAttributes(e,t.Circle.ATTRIBUTE_NAMES);if(!i(s))throw new Error(\"value of `r` attribute is required and can not be negative\");s.left=s.left||0,s.top=s.top||0;var o=new t.Circle(r(s,n));return o.left-=o.radius,o.top-=o.radius,o},t.Circle.fromObject=function(e){return new t.Circle(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={});if(t.Triangle){t.warn(\"fabric.Triangle is already defined\");return}t.Triangle=t.util.createClass(t.Object,{type:\"triangle\",initialize:function(e){e=e||{},this.callSuper(\"initialize\",e),this.set(\"width\",e.width||100).set(\"height\",e.height||100)},_render:function(e){var t=this.width/2,n=this.height/2;e.beginPath(),e.moveTo(-t,n),e.lineTo(0,-n),e.lineTo(t,n),e.closePath(),this._renderFill(e),this._renderStroke(e)},_renderDashedStroke:function(e){var n=this.width/2,r=this.height/2;e.beginPath(),t.util.drawDashedLine(e,-n,r,0,-r,this.strokeDashArray),t.util.drawDashedLine(e,0,-r,n,r,this.strokeDashArray),t.util.drawDashedLine(e,n,r,-n,r,this.strokeDashArray),e.closePath()},toSVG:function(e){var t=this._createBaseSVGMarkup(),n=this.width/2,r=this.height/2,i=[-n+\" \"+r,\"0 \"+ -r,n+\" \"+r].join(\",\");return t.push(\"<polygon \",'points=\"',i,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),'\"/>'),e?e(t.join(\"\")):t.join(\"\")},complexity:function(){return 1}}),t.Triangle.fromObject=function(e){return new t.Triangle(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=Math.PI*2,r=t.util.object.extend;if(t.Ellipse){t.warn(\"fabric.Ellipse is already defined.\");return}t.Ellipse=t.util.createClass(t.Object,{type:\"ellipse\",rx:0,ry:0,initialize:function(e){e=e||{},this.callSuper(\"initialize\",e),this.set(\"rx\",e.rx||0),this.set(\"ry\",e.ry||0)},_set:function(e,t){this.callSuper(\"_set\",e,t);switch(e){case\"rx\":this.rx=t,this.set(\"width\",t*2);break;case\"ry\":this.ry=t,this.set(\"height\",t*2)}return this},getRx:function(){return this.get(\"rx\")*this.get(\"scaleX\")},getRy:function(){return this.get(\"ry\")*this.get(\"scaleY\")},toObject:function(e){return r(this.callSuper(\"toObject\",e),{rx:this.get(\"rx\"),ry:this.get(\"ry\")})},toSVG:function(e){var t=this._createBaseSVGMarkup(),n=0,r=0;return this.group&&this.group.type===\"path-group\"&&(n=this.left+this.rx,r=this.top+this.ry),t.push(\"<ellipse \",'cx=\"',n,'\" cy=\"',r,'\" ','rx=\"',this.rx,'\" ry=\"',this.ry,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\"/>\\n'),e?e(t.join(\"\")):t.join(\"\")},_render:function(e,t){e.beginPath(),e.save(),e.transform(1,0,0,this.ry/this.rx,0,0),e.arc(t?this.left+this.rx:0,t?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,n,!1),e.restore(),this._renderFill(e),this._renderStroke(e)},complexity:function(){return 1}}),t.Ellipse.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(\"cx cy rx ry\".split(\" \")),t.Ellipse.fromElement=function(e,n){n||(n={});var i=t.parseAttributes(e,t.Ellipse.ATTRIBUTE_NAMES);i.left=i.left||0,i.top=i.top||0;var s=new t.Ellipse(r(i,n));return s.top-=s.ry,s.left-=s.rx,s},t.Ellipse.fromObject=function(e){return new t.Ellipse(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;if(t.Rect){console.warn(\"fabric.Rect is already defined\");return}var r=t.Object.prototype.stateProperties.concat();r.push(\"rx\",\"ry\",\"x\",\"y\"),t.Rect=t.util.createClass(t.Object,{stateProperties:r,type:\"rect\",rx:0,ry:0,strokeDashArray:null,initialize:function(e){e=e||{},this.callSuper(\"initialize\",e),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(e,t){if(this.width===1&&this.height===1){e.fillRect(0,0,1,1);return}var n=this.rx?Math.min(this.rx,this.width/2):0,r=this.ry?Math.min(this.ry,this.height/2):0,i=this.width,s=this.height,o=t?this.left:-this.width/2,u=t?this.top:-this.height/2,a=n!==0||r!==0,f=.4477152502;e.beginPath(),e.moveTo(o+n,u),e.lineTo(o+i-n,u),a&&e.bezierCurveTo(o+i-f*n,u,o+i,u+f*r,o+i,u+r),e.lineTo(o+i,u+s-r),a&&e.bezierCurveTo(o+i,u+s-f*r,o+i-f*n,u+s,o+i-n,u+s),e.lineTo(o+n,u+s),a&&e.bezierCurveTo(o+f*n,u+s,o,u+s-f*r,o,u+s-r),e.lineTo(o,u+r),a&&e.bezierCurveTo(o,u+f*r,o+f*n,u,o+n,u),e.closePath(),this._renderFill(e),this._renderStroke(e)},_renderDashedStroke:function(e){var n=-this.width/2,r=-this.height/2,i=this.width,s=this.height;e.beginPath(),t.util.drawDashedLine(e,n,r,n+i,r,this.strokeDashArray),t.util.drawDashedLine(e,n+i,r,n+i,r+s,this.strokeDashArray),t.util.drawDashedLine(e,n+i,r+s,n,r+s,this.strokeDashArray),t.util.drawDashedLine(e,n,r+s,n,r,this.strokeDashArray),e.closePath()},toObject:function(e){var t=n(this.callSuper(\"toObject\",e),{rx:this.get(\"rx\")||0,ry:this.get(\"ry\")||0});return this.includeDefaultValues||this._removeDefaultValues(t),t},toSVG:function(e){var t=this._createBaseSVGMarkup(),n=this.left,r=this.top;if(!this.group||this.group.type!==\"path-group\")n=-this.width/2,r=-this.height/2;return t.push(\"<rect \",'x=\"',n,'\" y=\"',r,'\" rx=\"',this.get(\"rx\"),'\" ry=\"',this.get(\"ry\"),'\" width=\"',this.width,'\" height=\"',this.height,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\"/>\\n'),e?e(t.join(\"\")):t.join(\"\")},complexity:function(){return 1}}),t.Rect.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(\"x y rx ry width height\".split(\" \")),t.Rect.fromElement=function(e,r){if(!e)return null;r=r||{};var i=t.parseAttributes(e,t.Rect.ATTRIBUTE_NAMES);return i.left=i.left||0,i.top=i.top||0,new t.Rect(n(r?t.util.object.clone(r):{},i))},t.Rect.fromObject=function(e){return new t.Rect(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={});if(t.Polyline){t.warn(\"fabric.Polyline is already defined\");return}t.Polyline=t.util.createClass(t.Object,{type:\"polyline\",points:null,minX:0,minY:0,initialize:function(e,n){return t.Polygon.prototype.initialize.call(this,e,n)},_calcDimensions:function(){return t.Polygon.prototype._calcDimensions.call(this)},_applyPointOffset:function(){return t.Polygon.prototype._applyPointOffset.call(this)},toObject:function(e){return t.Polygon.prototype.toObject.call(this,e)},toSVG:function(e){return t.Polygon.prototype.toSVG.call(this,e)},_render:function(e){t.Polygon.prototype.commonRender.call(this,e),this._renderFill(e),this._renderStroke(e)},_renderDashedStroke:function(e){var n,r;e.beginPath();for(var i=0,s=this.points.length;i<s;i++)n=this.points[i],r=this.points[i+1]||n,t.util.drawDashedLine(e,n.x,n.y,r.x,r.y,this.strokeDashArray)},complexity:function(){return this.get(\"points\").length}}),t.Polyline.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(),t.Polyline.fromElement=function(e,n){if(!e)return null;n||(n={});var r=t.parsePointsAttribute(e.getAttribute(\"points\")),i=t.parseAttributes(e,t.Polyline.ATTRIBUTE_NAMES);return r===null?null:new t.Polyline(r,t.util.object.extend(i,n))},t.Polyline.fromObject=function(e){var n=e.points;return new t.Polyline(n,e,!0)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.array.min,i=t.util.array.max,s=t.util.toFixed;if(t.Polygon){t.warn(\"fabric.Polygon is already defined\");return}t.Polygon=t.util.createClass(t.Object,{type:\"polygon\",points:null,minX:0,minY:0,initialize:function(e,t){t=t||{},this.points=e,this.callSuper(\"initialize\",t),this._calcDimensions(),\"top\"in t||(this.top=this.minY),\"left\"in t||(this.left=this.minX)},_calcDimensions:function(){var e=this.points,t=r(e,\"x\"),n=r(e,\"y\"),s=i(e,\"x\"),o=i(e,\"y\");this.width=s-t||1,this.height=o-n||1,this.minX=t,this.minY=n},_applyPointOffset:function(){this.points.forEach(function(e){e.x-=this.minX+this.width/2,e.y-=this.minY+this.height/2},this)},toObject:function(e){return n(this.callSuper(\"toObject\",e),{points:this.points.concat()})},toSVG:function(e){var t=[],n=this._createBaseSVGMarkup();for(var r=0,i=this.points.length;r<i;r++)t.push(s(this.points[r].x,2),\",\",s(this.points[r].y,2),\" \");return n.push(\"<\",this.type,\" \",'points=\"',t.join(\"\"),'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),\" \",this.getSvgTransformMatrix(),'\"/>\\n'),e?e(n.join(\"\")):n.join(\"\")},_render:function(e){this.commonRender(e),this._renderFill(e);if(this.stroke||this.strokeDashArray)e.closePath(),this._renderStroke(e)},commonRender:function(e){var t;e.beginPath(),this._applyPointOffset&&((!this.group||this.group.type!==\"path-group\")&&this._applyPointOffset(),this._applyPointOffset=null),e.moveTo(this.points[0].x,this.points[0].y);for(var n=0,r=this.points.length;n<r;n++)t=this.points[n],e.lineTo(t.x,t.y)},_renderDashedStroke:function(e){t.Polyline.prototype._renderDashedStroke.call(this,e),e.closePath()},complexity:function(){return this.points.length}}),t.Polygon.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(),t.Polygon.fromElement=function(e,r){if(!e)return null;r||(r={});var i=t.parsePointsAttribute(e.getAttribute(\"points\")),s=t.parseAttributes(e,t.Polygon.ATTRIBUTE_NAMES);return i===null?null:new t.Polygon(i,n(s,r))},t.Polygon.fromObject=function(e){return new t.Polygon(e.points,e,!0)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.array.min,r=t.util.array.max,i=t.util.object.extend,s=Object.prototype.toString,o=t.util.drawArc,u={m:2,l:2,h:1,v:1,c:6,s:4,q:4,t:2,a:7},a={m:\"l\",M:\"L\"};if(t.Path){t.warn(\"fabric.Path is already defined\");return}t.Path=t.util.createClass(t.Object,{type:\"path\",path:null,minX:0,minY:0,initialize:function(e,t){t=t||{},this.setOptions(t);if(!e)throw new Error(\"`path` argument is required\");var n=s.call(e)===\"[object Array]\";this.path=n?e:e.match&&e.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);if(!this.path)return;n||(this.path=this._parsePath());var r=this._parseDimensions();this.minX=r.left,this.minY=r.top,this.width=r.width,this.height=r.height,this.top=this.top||this.minY,this.left=this.left||this.minX,this.pathOffset=this.pathOffset||{x:this.minX+this.width/2,y:this.minY+this.height/2},t.sourcePath&&this.setSourcePath(t.sourcePath)},_render:function(e){var t,n=null,r=0,i=0,s=0,u=0,a=0,f=0,l,c,h,p,d=-this.pathOffset.x,v=-this.pathOffset.y;this.group&&this.group.type===\"path-group\"&&(d=0,v=0),e.beginPath();for(var m=0,g=this.path.length;m<g;++m){t=this.path[m];switch(t[0]){case\"l\":s+=t[1],u+=t[2],e.lineTo(s+d,u+v);break;case\"L\":s=t[1],u=t[2],e.lineTo(s+d,u+v);break;case\"h\":s+=t[1],e.lineTo(s+d,u+v);break;case\"H\":s=t[1],e.lineTo(s+d,u+v);break;case\"v\":u+=t[1],e.lineTo(s+d,u+v);break;case\"V\":u=t[1],e.lineTo(s+d,u+v);break;case\"m\":s+=t[1],u+=t[2],r=s,i=u,e.moveTo(s+d,u+v);break;case\"M\":s=t[1],u=t[2],r=s,i=u,e.moveTo(s+d,u+v);break;case\"c\":l=s+t[5],c=u+t[6],a=s+t[3],f=u+t[4],e.bezierCurveTo(s+t[1]+d,u+t[2]+v,a+d,f+v,l+d,c+v),s=l,u=c;break;case\"C\":s=t[5],u=t[6],a=t[3],f=t[4],e.bezierCurveTo(t[1]+d,t[2]+v,a+d,f+v,s+d,u+v);break;case\"s\":l=s+t[3],c=u+t[4],a=a?2*s-a:s,f=f?2*u-f:u,e.bezierCurveTo(a+d,f+v,s+t[1]+d,u+t[2]+v,l+d,c+v),a=s+t[1],f=u+t[2],s=l,u=c;break;case\"S\":l=t[3],c=t[4],a=2*s-a,f=2*u-f,e.bezierCurveTo(a+d,f+v,t[1]+d,t[2]+v,l+d,c+v),s=l,u=c,a=t[1],f=t[2];break;case\"q\":l=s+t[3],c=u+t[4],a=s+t[1],f=u+t[2],e.quadraticCurveTo(a+d,f+v,l+d,c+v),s=l,u=c;break;case\"Q\":l=t[3],c=t[4],e.quadraticCurveTo(t[1]+d,t[2]+v,l+d,c+v),s=l,u=c,a=t[1],f=t[2];break;case\"t\":l=s+t[1],c=u+t[2],n[0].match(/[QqTt]/)===null?(a=s,f=u):n[0]===\"t\"?(a=2*s-h,f=2*u-p):n[0]===\"q\"&&(a=2*s-a,f=2*u-f),h=a,p=f,e.quadraticCurveTo(a+d,f+v,l+d,c+v),s=l,u=c,a=s+t[1],f=u+t[2];break;case\"T\":l=t[1],c=t[2],a=2*s-a,f=2*u-f,e.quadraticCurveTo(a+d,f+v,l+d,c+v),s=l,u=c;break;case\"a\":o(e,s+d,u+v,[t[1],t[2],t[3],t[4],t[5],t[6]+s+d,t[7]+u+v]),s+=t[6],u+=t[7];break;case\"A\":o(e,s+d,u+v,[t[1],t[2],t[3],t[4],t[5],t[6]+d,t[7]+v]),s=t[6],u=t[7];break;case\"z\":case\"Z\":s=r,u=i,e.closePath()}n=t}this._renderFill(e),this._renderStroke(e)},render:function(e,n){if(!this.visible)return;e.save(),this._setupCompositeOperation(e),n||this.transform(e),this._setStrokeStyles(e),this._setFillStyles(e),this.group&&this.group.type===\"path-group\"&&e.translate(-this.group.width/2,-this.group.height/2),this.transformMatrix&&e.transform.apply(e,this.transformMatrix),this._setOpacity(e),this._setShadow(e),this.clipTo&&t.util.clipContext(this,e),this._render(e,n),this.clipTo&&e.restore(),this._removeShadow(e),this._restoreCompositeOperation(e),e.restore()},toString:function(){return\"#<fabric.Path (\"+this.complexity()+'): { \"top\": '+this.top+', \"left\": '+this.left+\" }>\"},toObject:function(e){var t=i(this.callSuper(\"toObject\",e),{path:this.path.map(function(e){return e.slice()}),pathOffset:this.pathOffset});return this.sourcePath&&(t.sourcePath=this.sourcePath),this.transformMatrix&&(t.transformMatrix=this.transformMatrix),t},toDatalessObject:function(e){var t=this.toObject(e);return this.sourcePath&&(t.path=this.sourcePath),delete t.sourcePath,t},toSVG:function(e){var t=[],n=this._createBaseSVGMarkup(),r=\"\";for(var i=0,s=this.path.length;i<s;i++)t.push(this.path[i].join(\" \"));var o=t.join(\" \");if(!this.group||this.group.type!==\"path-group\")r=\"translate(\"+ -this.pathOffset.x+\", \"+ -this.pathOffset.y+\")\";return n.push(\"<path \",'d=\"',o,'\" style=\"',this.getSvgStyles(),'\" transform=\"',this.getSvgTransform(),r,this.getSvgTransformMatrix(),'\" stroke-linecap=\"round\" ',\"/>\\n\"),e?e(n.join(\"\")):n.join(\"\")},complexity:function(){return this.path.length},_parsePath:function(){var e=[],t=[],n,r,i=/([-+]?((\\d+\\.\\d+)|((\\d+)|(\\.\\d+)))(?:e[-+]?\\d+)?)/ig,s,o;for(var f=0,l,c=this.path.length;f<c;f++){n=this.path[f],o=n.slice(1).trim(),t.length=0;while(s=i.exec(o))t.push(s[0]);l=[n.charAt(0)];for(var h=0,p=t.length;h<p;h++)r=parseFloat(t[h]),isNaN(r)||l.push(r);var d=l[0],v=u[d.toLowerCase()],m=a[d]||d;if(l.length-1>v)for(var g=1,y=l.length;g<y;g+=v)e.push([d].concat(l.slice(g,g+v))),d=m;else e.push(l)}return e},_parseDimensions:function(){var e=[],i=[],s,o=null,u=0,a=0,f=0,l=0,c=0,h=0,p,d,v,m,g;for(var y=0,b=this.path.length;y<b;++y){s=this.path[y];switch(s[0]){case\"l\":f+=s[1],l+=s[2],g=[];break;case\"L\":f=s[1],l=s[2],g=[];break;case\"h\":f+=s[1],g=[];break;case\"H\":f=s[1],g=[];break;case\"v\":l+=s[1],g=[];break;case\"V\":l=s[1],g=[];break;case\"m\":f+=s[1],l+=s[2],u=f,a=l,g=[];break;case\"M\":f=s[1],l=s[2],u=f,a=l,g=[];break;case\"c\":p=f+s[5],d=l+s[6],c=f+s[3],h=l+s[4],g=t.util.getBoundsOfCurve(f,l,f+s[1],l+s[2],c,h,p,d),f=p,l=d;break;case\"C\":f=s[5],l=s[6],c=s[3],h=s[4],g=t.util.getBoundsOfCurve(f,l,s[1],s[2],c,h,f,l);break;case\"s\":p=f+s[3],d=l+s[4],c=c?2*f-c:f,h=h?2*l-h:l,g=t.util.getBoundsOfCurve(f,l,c,h,f+s[1],l+s[2],p,d),c=f+s[1],h=l+s[2],f=p,l=d;break;case\"S\":p=s[3],d=s[4],c=2*f-c,h=2*l-h,g=t.util.getBoundsOfCurve(f,l,c,h,s[1],s[2],p,d),f=p,l=d,c=s[1],h=s[2];break;case\"q\":p=f+s[3],d=l+s[4],c=f+s[1],h=l+s[2],g=t.util.getBoundsOfCurve(f,l,c,h,c,h,p,d),f=p,l=d;break;case\"Q\":c=s[1],h=s[2],g=t.util.getBoundsOfCurve(f,l,c,h,c,h,s[3],s[4]),f=s[3],l=s[4];break;case\"t\":p=f+s[1],d=l+s[2],o[0].match(/[QqTt]/)===null?(c=f,h=l):o[0]===\"t\"?(c=2*f-v,h=2*l-m):o[0]===\"q\"&&(c=2*f-c,h=2*l-h),v=c,m=h,g=t.util.getBoundsOfCurve(f,l,c,h,c,h,p,d),f=p,l=d,c=f+s[1],h=l+s[2];break;case\"T\":p=s[1],d=s[2],c=2*f-c,h=2*l-h,g=t.util.getBoundsOfCurve(f,l,c,h,c,h,p,d),f=p,l=d;break;case\"a\":g=t.util.getBoundsOfArc(f,l,s[1],s[2],s[3],s[4],s[5],s[6]+f,s[7]+l),f+=s[6],l+=s[7];break;case\"A\":g=t.util.getBoundsOfArc(f,l,s[1],s[2],s[3],s[4],s[5],s[6],s[7]),f=s[6],l=s[7];break;case\"z\":case\"Z\":f=u,l=a}o=s,g.forEach(function(t){e.push(t.x),i.push(t.y)}),e.push(f),i.push(l)}var w=n(e),E=n(i),S=r(e),x=r(i),T=S-w,N=x-E,C={left:w,top:E,width:T,height:N};return C}}),t.Path.fromObject=function(e,n){typeof e.path==\"string\"?t.loadSVGFromURL(e.path,function(r){var i=r[0],s=e.path;delete e.path,t.util.object.extend(i,e),i.setSourcePath(s),n(i)}):n(new t.Path(e.path,e))},t.Path.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat([\"d\"]),t.Path.fromElement=function(e,n,r){var s=t.parseAttributes(e,t.Path.ATTRIBUTE_NAMES);n&&n(new t.Path(s.d,i(s,r)))},t.Path.async=!0}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.array.invoke,i=t.Object.prototype.toObject;if(t.PathGroup){t.warn(\"fabric.PathGroup is already defined\");return}t.PathGroup=t.util.createClass(t.Path,{type:\"path-group\",fill:\"\",initialize:function(e,t){t=t||{},this.paths=e||[];for(var n=this.paths.length;n--;)this.paths[n].group=this;this.setOptions(t),t.widthAttr&&(this.scaleX=t.widthAttr/t.width),t.heightAttr&&(this.scaleY=t.heightAttr/t.height),this.setCoords(),t.sourcePath&&this.setSourcePath(t.sourcePath)},render:function(e){if(!this.visible)return;e.save();var n=this.transformMatrix;n&&e.transform(n[0],n[1],n[2],n[3],n[4],n[5]),this.transform(e),this._setShadow(e),this.clipTo&&t.util.clipContext(this,e);for(var r=0,i=this.paths.length;r<i;++r)this.paths[r].render(e,!0);this.clipTo&&e.restore(),this._removeShadow(e),e.restore()},_set:function(e,t){if(e===\"fill\"&&t&&this.isSameColor()){var n=this.paths.length;while(n--)this.paths[n]._set(e,t)}return this.callSuper(\"_set\",e,t)},toObject:function(e){var t=n(i.call(this,e),{paths:r(this.getObjects(),\"toObject\",e)});return this.sourcePath&&(t.sourcePath=this.sourcePath),t},toDatalessObject:function(e){var t=this.toObject(e);return this.sourcePath&&(t.paths=this.sourcePath),t},toSVG:function(e){var t=this.getObjects(),n=\"translate(\"+this.left+\" \"+this.top+\")\",r=[\"<g \",'style=\"',this.getSvgStyles(),'\" ','transform=\"',n,this.getSvgTransform(),'\" ',\">\\n\"];for(var i=0,s=t.length;i<s;i++)r.push(t[i].toSVG(e));return r.push(\"</g>\\n\"),e?e(r.join(\"\")):r.join(\"\")},toString:function(){return\"#<fabric.PathGroup (\"+this.complexity()+\"): { top: \"+this.top+\", left: \"+this.left+\" }>\"},isSameColor:function(){var e=(this.getObjects()[0].get(\"fill\")||\"\").toLowerCase();return this.getObjects().every(function(t){return(t.get(\"fill\")||\"\").toLowerCase()===e})},complexity:function(){return this.paths.reduce(function(e,t){return e+(t&&t.complexity?t.complexity():0)},0)},getObjects:function(){return this.paths}}),t.PathGroup.fromObject=function(e,n){typeof e.paths==\"string\"?t.loadSVGFromURL(e.paths,function(r){var i=e.paths;delete e.paths;var s=t.util.groupSVGElements(r,e,i);n(s)}):t.util.enlivenObjects(e.paths,function(r){delete e.paths,n(new t.PathGroup(r,e))})},t.PathGroup.async=!0}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.array.min,i=t.util.array.max,s=t.util.array.invoke;if(t.Group)return;var o={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};t.Group=t.util.createClass(t.Object,t.Collection,{type:\"group\",initialize:function(e,t){t=t||{},this._objects=e||[];for(var r=this._objects.length;r--;)this._objects[r].group=this;this.originalState={},this.callSuper(\"initialize\"),this._calcBounds(),this._updateObjectsCoords(),t&&n(this,t),this.setCoords(),this.saveCoords()},_updateObjectsCoords:function(){this.forEachObject(this._updateObjectCoords,this)},_updateObjectCoords:function(e){var t=e.getLeft(),n=e.getTop();e.set({originalLeft:t,originalTop:n,left:t-this.left,top:n-this.top}),e.setCoords(),e.__origHasControls=e.hasControls,e.hasControls=!1},toString:function(){return\"#<fabric.Group: (\"+this.complexity()+\")>\"},addWithUpdate:function(e){return this._restoreObjectsState(),e&&(this._objects.push(e),e.group=this),this.forEachObject(this._setObjectActive,this),this._calcBounds(),this._updateObjectsCoords(),this},_setObjectActive:function(e){e.set(\"active\",!0),e.group=this},removeWithUpdate:function(e){return this._moveFlippedObject(e),this._restoreObjectsState(),this.forEachObject(this._setObjectActive,this),this.remove(e),this._calcBounds(),this._updateObjectsCoords(),this},_onObjectAdded:function(e){e.group=this},_onObjectRemoved:function(e){delete e.group,e.set(\"active\",!1)},delegatedProperties:{fill:!0,opacity:!0,fontFamily:!0,fontWeight:!0,fontSize:!0,fontStyle:!0,lineHeight:!0,textDecoration:!0,textAlign:!0,backgroundColor:!0},_set:function(e,t){if(e in this.delegatedProperties){var n=this._objects.length;this[e]=t;while(n--)this._objects[n].set(e,t)}else this[e]=t},toObject:function(e){return n(this.callSuper(\"toObject\",e),{objects:s(this._objects,\"toObject\",e)})},render:function(e){if(!this.visible)return;e.save(),this.clipTo&&t.util.clipContext(this,e);for(var n=0,r=this._objects.length;n<r;n++)this._renderObject(this._objects[n],e);this.clipTo&&e.restore(),e.restore()},_renderControls:function(e,t){this.callSuper(\"_renderControls\",e,t);for(var n=0,r=this._objects.length;n<r;n++)this._objects[n]._renderControls(e)},_renderObject:function(e,t){var n=e.hasRotatingPoint;if(!e.visible)return;e.hasRotatingPoint=!1,e.render(t),e.hasRotatingPoint=n},_restoreObjectsState:function(){return this._objects.forEach(this._restoreObjectState,this),this},_moveFlippedObject:function(e){var t=e.get(\"originX\"),n=e.get(\"originY\"),r=e.getCenterPoint();e.set({originX:\"center\",originY:\"center\",left:r.x,top:r.y}),this._toggleFlipping(e);var i=e.getPointByOrigin(t,n);return e.set({originX:t,originY:n,left:i.x,top:i.y}),this},_toggleFlipping:function(e){this.flipX&&(e.toggle(\"flipX\"),e.set(\"left\",-e.get(\"left\")),e.setAngle(-e.getAngle())),this.flipY&&(e.toggle(\"flipY\"),e.set(\"top\",-e.get(\"top\")),e.setAngle(-e.getAngle()))},_restoreObjectState:function(e){return this._setObjectPosition(e),e.setCoords(),e.hasControls=e.__origHasControls,delete e.__origHasControls,e.set(\"active\",!1),e.setCoords(),delete e.group,this},_setObjectPosition:function(e){var t=this.getLeft(),n=this.getTop(),r=this._getRotatedLeftTop(e);e.set({angle:e.getAngle()+this.getAngle(),left:t+r.left,top:n+r.top,scaleX:e.get(\"scaleX\")*this.get(\"scaleX\"),scaleY:e.get(\"scaleY\")*this.get(\"scaleY\")})},_getRotatedLeftTop:function(e){var t=this.getAngle()*(Math.PI/180);return{left:-Math.sin(t)*e.getTop()*this.get(\"scaleY\")+Math.cos(t)*e.getLeft()*this.get(\"scaleX\"),top:Math.cos(t)*e.getTop()*this.get(\"scaleY\")+Math.sin(t)*e.getLeft()*this.get(\"scaleX\")}},destroy:function(){return this._objects.forEach(this._moveFlippedObject,this),this._restoreObjectsState()},saveCoords:function(){return this._originalLeft=this.get(\"left\"),this._originalTop=this.get(\"top\"),this},hasMoved:function(){return this._originalLeft!==this.get(\"left\")||this._originalTop!==this.get(\"top\")},setObjectsCoords:function(){return this.forEachObject(function(e){e.setCoords()}),this},_calcBounds:function(e){var t=[],n=[],r;for(var i=0,s=this._objects.length;i<s;++i){r=this._objects[i],r.setCoords();for(var o in r.oCoords)t.push(r.oCoords[o].x),n.push(r.oCoords[o].y)}this.set(this._getBounds(t,n,e))},_getBounds:function(e,n,s){var o=t.util.invertTransform(this.getViewportTransform()),u=t.util.transformPoint(new t.Point(r(e),r(n)),o),a=t.util.transformPoint(new t.Point(i(e),i(n)),o),f={width:a.x-u.x||0,height:a.y-u.y||0};return s||(f.left=(u.x+a.x)/2||0,f.top=(u.y+a.y)/2||0),f},toSVG:function(e){var t=[\"<g \",'transform=\"',this.getSvgTransform(),'\">\\n'];for(var n=0,r=this._objects.length;n<r;n++)t.push(this._objects[n].toSVG(e));return t.push(\"</g>\\n\"),e?e(t.join(\"\")):t.join(\"\")},get:function(e){if(e in o){if(this[e])return this[e];for(var t=0,n=this._objects.length;t<n;t++)if(this._objects[t][e])return!0;return!1}return e in this.delegatedProperties?this._objects[0]&&this._objects[0].get(e):this[e]}}),t.Group.fromObject=function(e,n){t.util.enlivenObjects(e.objects,function(r){delete e.objects,n&&n(new t.Group(r,e))})},t.Group.async=!0}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=fabric.util.object.extend;e.fabric||(e.fabric={});if(e.fabric.Image){fabric.warn(\"fabric.Image is already defined.\");return}fabric.Image=fabric.util.createClass(fabric.Object,{type:\"image\",crossOrigin:\"\",initialize:function(e,t){t||(t={}),this.filters=[],this.callSuper(\"initialize\",t),this._initElement(e,t),this._initConfig(t),t.filters&&(this.filters=t.filters,this.applyFilters())},getElement:function(){return this._element},setElement:function(e,t){return this._element=e,this._originalElement=e,this._initConfig(),this.filters.length!==0&&this.applyFilters(t),this},setCrossOrigin:function(e){return this.crossOrigin=e,this._element.crossOrigin=e,this},getOriginalSize:function(){var e=this.getElement();return{width:e.width,height:e.height}},_stroke:function(e){e.save(),this._setStrokeStyles(e),e.beginPath(),e.strokeRect(-this.width/2,-this.height/2,this.width,this.height),e.closePath(),e.restore()},_renderDashedStroke:function(e){var t=-this.width/2,n=-this.height/2,r=this.width,i=this.height;e.save(),this._setStrokeStyles(e),e.beginPath(),fabric.util.drawDashedLine(e,t,n,t+r,n,this.strokeDashArray),fabric.util.drawDashedLine(e,t+r,n,t+r,n+i,this.strokeDashArray),fabric.util.drawDashedLine(e,t+r,n+i,t,n+i,this.strokeDashArray),fabric.util.drawDashedLine(e,t,n+i,t,n,this.strokeDashArray),e.closePath(),e.restore()},toObject:function(e){return t(this.callSuper(\"toObject\",e),{src:this._originalElement.src||this._originalElement._src,filters:this.filters.map(function(e){return e&&e.toObject()}),crossOrigin:this.crossOrigin})},toSVG:function(e){var t=[],n=-this.width/2,r=-this.height/2;this.group&&this.group.type===\"path-group\"&&(n=this.left,r=this.top),t.push('<g transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\">\\n','<image xlink:href=\"',this.getSvgSrc(),'\" x=\"',n,'\" y=\"',r,'\" style=\"',this.getSvgStyles(),'\" width=\"',this.width,'\" height=\"',this.height,'\" preserveAspectRatio=\"none\"',\"></image>\\n\");if(this.stroke||this.strokeDashArray){var i=this.fill;this.fill=null,t.push(\"<rect \",'x=\"',n,'\" y=\"',r,'\" width=\"',this.width,'\" height=\"',this.height,'\" style=\"',this.getSvgStyles(),'\"/>\\n'),this.fill=i}return t.push(\"</g>\\n\"),e?e(t.join(\"\")):t.join(\"\")},getSrc:function(){if(this.getElement())return this.getElement().src||this.getElement()._src},toString:function(){return'#<fabric.Image: { src: \"'+this.getSrc()+'\" }>'},clone:function(e,t){this.constructor.fromObject(this.toObject(t),e)},applyFilters:function(e){if(!this._originalElement)return;if(this.filters.length===0){this._element=this._originalElement,e&&e();return}var t=this._originalElement,n=fabric.util.createCanvasElement(),r=fabric.util.createImage(),i=this;return n.width=t.width,n.height=t.height,n.getContext(\"2d\").drawImage(t,0,0,t.width,t.height),this.filters.forEach(function(e){e&&e.applyTo(n)}),r.width=t.width,r.height=t.height,fabric.isLikelyNode?(r.src=n.toBuffer(undefined,fabric.Image.pngCompression),i._element=r,e&&e()):(r.onload=function(){i._element=r,e&&e(),r.onload=n=t=null},r.src=n.toDataURL(\"image/png\")),this},_render:function(e,t){this._element&&e.drawImage(this._element,t?this.left:-this.width/2,t?this.top:-this.height/2,this.width,this.height),this._renderStroke(e)},_resetWidthHeight:function(){var e=this.getElement();this.set(\"width\",e.width),this.set(\"height\",e.height)},_initElement:function(e){this.setElement(fabric.util.getById(e)),fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(e){e||(e={}),this.setOptions(e),this._setWidthHeight(e),this._element&&this.crossOrigin&&(this._element.crossOrigin=this.crossOrigin)},_initFilters:function(e,t){e.filters&&e.filters.length?fabric.util.enlivenObjects(e.filters,function(e){t&&t(e)},\"fabric.Image.filters\"):t&&t()},_setWidthHeight:function(e){this.width=\"width\"in e?e.width:this.getElement()?this.getElement().width||0:0,this.height=\"height\"in e?e.height:this.getElement()?this.getElement().height||0:0},complexity:function(){return 1}}),fabric.Image.CSS_CANVAS=\"canvas-img\",fabric.Image.prototype.getSvgSrc=fabric.Image.prototype.getSrc,fabric.Image.fromObject=function(e,t){fabric.util.loadImage(e.src,function(n){fabric.Image.prototype._initFilters.call(e,e,function(r){e.filters=r||[];var i=new fabric.Image(n,e);t&&t(i)})},null,e.crossOrigin)},fabric.Image.fromURL=function(e,t,n){fabric.util.loadImage(e,function(e){t(new fabric.Image(e,n))},null,n&&n.crossOrigin)},fabric.Image.ATTRIBUTE_NAMES=fabric.SHARED_ATTRIBUTES.concat(\"x y width height xlink:href\".split(\" \")),fabric.Image.fromElement=function(e,n,r){var i=fabric.parseAttributes(e,fabric.Image.ATTRIBUTE_NAMES);fabric.Image.fromURL(i[\"xlink:href\"],n,t(r?fabric.util.object.clone(r):{},i))},fabric.Image.async=!0,fabric.Image.pngCompression=1}(typeof exports!=\"undefined\"?exports:this),fabric.util.object.extend(fabric.Object.prototype,{_getAngleValueForStraighten:function(){var e=this.getAngle()%360;return e>0?Math.round((e-1)/90)*90:Math.round(e/90)*90},straighten:function(){return this.setAngle(this._getAngleValueForStraighten()),this},fxStraighten:function(e){e=e||{};var t=function(){},n=e.onComplete||t,r=e.onChange||t,i=this;return fabric.util.animate({startValue:this.get(\"angle\"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(e){i.setAngle(e),r()},onComplete:function(){i.setCoords(),n()},onStart:function(){i.set(\"active\",!1)}}),this}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(e){return e.straighten(),this.renderAll(),this},fxStraightenObject:function(e){return e.fxStraighten({onChange:this.renderAll.bind(this)}),this}}),fabric.Image.filters=fabric.Image.filters||{},fabric.Image.filters.BaseFilter=fabric.util.createClass({type:\"BaseFilter\",toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}}),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Brightness=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Brightness\",initialize:function(e){e=e||{},this.brightness=e.brightness||0},applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=this.brightness;for(var s=0,o=r.length\n;s<o;s+=4)r[s]+=i,r[s+1]+=i,r[s+2]+=i;t.putImageData(n,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{brightness:this.brightness})}}),t.Image.filters.Brightness.fromObject=function(e){return new t.Image.filters.Brightness(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Convolute=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Convolute\",initialize:function(e){e=e||{},this.opaque=e.opaque,this.matrix=e.matrix||[0,0,0,0,1,0,0,0,0];var n=t.util.createCanvasElement();this.tmpCtx=n.getContext(\"2d\")},_createImageData:function(e,t){return this.tmpCtx.createImageData(e,t)},applyTo:function(e){var t=this.matrix,n=e.getContext(\"2d\"),r=n.getImageData(0,0,e.width,e.height),i=Math.round(Math.sqrt(t.length)),s=Math.floor(i/2),o=r.data,u=r.width,a=r.height,f=u,l=a,c=this._createImageData(f,l),h=c.data,p=this.opaque?1:0;for(var d=0;d<l;d++)for(var v=0;v<f;v++){var m=d,g=v,y=(d*f+v)*4,b=0,w=0,E=0,S=0;for(var x=0;x<i;x++)for(var T=0;T<i;T++){var N=m+x-s,C=g+T-s;if(N<0||N>a||C<0||C>u)continue;var k=(N*u+C)*4,L=t[x*i+T];b+=o[k]*L,w+=o[k+1]*L,E+=o[k+2]*L,S+=o[k+3]*L}h[y]=b,h[y+1]=w,h[y+2]=E,h[y+3]=S+p*(255-S)}n.putImageData(c,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{opaque:this.opaque,matrix:this.matrix})}}),t.Image.filters.Convolute.fromObject=function(e){return new t.Image.filters.Convolute(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.GradientTransparency=t.util.createClass(t.Image.filters.BaseFilter,{type:\"GradientTransparency\",initialize:function(e){e=e||{},this.threshold=e.threshold||100},applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=this.threshold,s=r.length;for(var o=0,u=r.length;o<u;o+=4)r[o+3]=i+255*(s-o)/s;t.putImageData(n,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{threshold:this.threshold})}}),t.Image.filters.GradientTransparency.fromObject=function(e){return new t.Image.filters.GradientTransparency(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={});t.Image.filters.Grayscale=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Grayscale\",applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=n.width*n.height*4,s=0,o;while(s<i)o=(r[s]+r[s+1]+r[s+2])/3,r[s]=o,r[s+1]=o,r[s+2]=o,s+=4;t.putImageData(n,0,0)}}),t.Image.filters.Grayscale.fromObject=function(){return new t.Image.filters.Grayscale}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={});t.Image.filters.Invert=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Invert\",applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=r.length,s;for(s=0;s<i;s+=4)r[s]=255-r[s],r[s+1]=255-r[s+1],r[s+2]=255-r[s+2];t.putImageData(n,0,0)}}),t.Image.filters.Invert.fromObject=function(){return new t.Image.filters.Invert}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Mask=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Mask\",initialize:function(e){e=e||{},this.mask=e.mask,this.channel=[0,1,2,3].indexOf(e.channel)>-1?e.channel:0},applyTo:function(e){if(!this.mask)return;var n=e.getContext(\"2d\"),r=n.getImageData(0,0,e.width,e.height),i=r.data,s=this.mask.getElement(),o=t.util.createCanvasElement(),u=this.channel,a,f=r.width*r.height*4;o.width=s.width,o.height=s.height,o.getContext(\"2d\").drawImage(s,0,0,s.width,s.height);var l=o.getContext(\"2d\").getImageData(0,0,s.width,s.height),c=l.data;for(a=0;a<f;a+=4)i[a+3]=c[a+u];n.putImageData(r,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{mask:this.mask.toObject(),channel:this.channel})}}),t.Image.filters.Mask.fromObject=function(e,n){t.util.loadImage(e.mask.src,function(r){e.mask=new t.Image(r,e.mask),n&&n(new t.Image.filters.Mask(e))})},t.Image.filters.Mask.async=!0}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Noise=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Noise\",initialize:function(e){e=e||{},this.noise=e.noise||0},applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=this.noise,s;for(var o=0,u=r.length;o<u;o+=4)s=(.5-Math.random())*i,r[o]+=s,r[o+1]+=s,r[o+2]+=s;t.putImageData(n,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{noise:this.noise})}}),t.Image.filters.Noise.fromObject=function(e){return new t.Image.filters.Noise(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Pixelate=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Pixelate\",initialize:function(e){e=e||{},this.blocksize=e.blocksize||4},applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=n.height,s=n.width,o,u,a,f,l,c,h;for(u=0;u<i;u+=this.blocksize)for(a=0;a<s;a+=this.blocksize){o=u*4*s+a*4,f=r[o],l=r[o+1],c=r[o+2],h=r[o+3];for(var p=u,d=u+this.blocksize;p<d;p++)for(var v=a,m=a+this.blocksize;v<m;v++)o=p*4*s+v*4,r[o]=f,r[o+1]=l,r[o+2]=c,r[o+3]=h}t.putImageData(n,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{blocksize:this.blocksize})}}),t.Image.filters.Pixelate.fromObject=function(e){return new t.Image.filters.Pixelate(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.RemoveWhite=t.util.createClass(t.Image.filters.BaseFilter,{type:\"RemoveWhite\",initialize:function(e){e=e||{},this.threshold=e.threshold||30,this.distance=e.distance||20},applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=this.threshold,s=this.distance,o=255-i,u=Math.abs,a,f,l;for(var c=0,h=r.length;c<h;c+=4)a=r[c],f=r[c+1],l=r[c+2],a>o&&f>o&&l>o&&u(a-f)<s&&u(a-l)<s&&u(f-l)<s&&(r[c+3]=1);t.putImageData(n,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{threshold:this.threshold,distance:this.distance})}}),t.Image.filters.RemoveWhite.fromObject=function(e){return new t.Image.filters.RemoveWhite(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={});t.Image.filters.Sepia=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Sepia\",applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=r.length,s,o;for(s=0;s<i;s+=4)o=.3*r[s]+.59*r[s+1]+.11*r[s+2],r[s]=o+100,r[s+1]=o+50,r[s+2]=o+255;t.putImageData(n,0,0)}}),t.Image.filters.Sepia.fromObject=function(){return new t.Image.filters.Sepia}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={});t.Image.filters.Sepia2=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Sepia2\",applyTo:function(e){var t=e.getContext(\"2d\"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=r.length,s,o,u,a;for(s=0;s<i;s+=4)o=r[s],u=r[s+1],a=r[s+2],r[s]=(o*.393+u*.769+a*.189)/1.351,r[s+1]=(o*.349+u*.686+a*.168)/1.203,r[s+2]=(o*.272+u*.534+a*.131)/2.14;t.putImageData(n,0,0)}}),t.Image.filters.Sepia2.fromObject=function(){return new t.Image.filters.Sepia2}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Tint=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Tint\",initialize:function(e){e=e||{},this.color=e.color||\"#000000\",this.opacity=typeof e.opacity!=\"undefined\"?e.opacity:(new t.Color(this.color)).getAlpha()},applyTo:function(e){var n=e.getContext(\"2d\"),r=n.getImageData(0,0,e.width,e.height),i=r.data,s=i.length,o,u,a,f,l,c,h,p,d;d=(new t.Color(this.color)).getSource(),u=d[0]*this.opacity,a=d[1]*this.opacity,f=d[2]*this.opacity,p=1-this.opacity;for(o=0;o<s;o+=4)l=i[o],c=i[o+1],h=i[o+2],i[o]=u+l*p,i[o+1]=a+c*p,i[o+2]=f+h*p;n.putImageData(r,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{color:this.color,opacity:this.opacity})}}),t.Image.filters.Tint.fromObject=function(e){return new t.Image.filters.Tint(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Multiply=t.util.createClass(t.Image.filters.BaseFilter,{type:\"Multiply\",initialize:function(e){e=e||{},this.color=e.color||\"#000000\"},applyTo:function(e){var n=e.getContext(\"2d\"),r=n.getImageData(0,0,e.width,e.height),i=r.data,s=i.length,o,u;u=(new t.Color(this.color)).getSource();for(o=0;o<s;o+=4)i[o]*=u[0]/255,i[o+1]*=u[1]/255,i[o+2]*=u[2]/255;n.putImageData(r,0,0)},toObject:function(){return n(this.callSuper(\"toObject\"),{color:this.color})}}),t.Image.filters.Multiply.fromObject=function(e){return new t.Image.filters.Multiply(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric;t.Image.filters.Blend=t.util.createClass({type:\"Blend\",initialize:function(e){e=e||{},this.color=e.color||\"#000\",this.image=e.image||!1,this.mode=e.mode||\"multiply\",this.alpha=e.alpha||1},applyTo:function(e){var n=e.getContext(\"2d\"),r=n.getImageData(0,0,e.width,e.height),i=r.data,s,o,u,a,f,l,c,h=!1;if(this.image){h=!0;var p=t.util.createCanvasElement();p.width=this.image.width,p.height=this.image.height;var d=new t.StaticCanvas(p);d.add(this.image);var v=d.getContext(\"2d\");c=v.getImageData(0,0,d.width,d.height).data}else c=(new t.Color(this.color)).getSource(),s=c[0]*this.alpha,o=c[1]*this.alpha,u=c[2]*this.alpha;for(var m=0,g=i.length;m<g;m+=4){a=i[m],f=i[m+1],l=i[m+2],h&&(s=c[m]*this.alpha,o=c[m+1]*this.alpha,u=c[m+2]*this.alpha);switch(this.mode){case\"multiply\":i[m]=a*s/255,i[m+1]=f*o/255,i[m+2]=l*u/255;break;case\"screen\":i[m]=1-(1-a)*(1-s),i[m+1]=1-(1-f)*(1-o),i[m+2]=1-(1-l)*(1-u);break;case\"add\":i[m]=Math.min(255,a+s),i[m+1]=Math.min(255,f+o),i[m+2]=Math.min(255,l+u);break;case\"diff\":case\"difference\":i[m]=Math.abs(a-s),i[m+1]=Math.abs(f-o),i[m+2]=Math.abs(l-u);break;case\"subtract\":var y=a-s,b=f-o,w=l-u;i[m]=y<0?0:y,i[m+1]=b<0?0:b,i[m+2]=w<0?0:w;break;case\"darken\":i[m]=Math.min(a,s),i[m+1]=Math.min(f,o),i[m+2]=Math.min(l,u);break;case\"lighten\":i[m]=Math.max(a,s),i[m+1]=Math.max(f,o),i[m+2]=Math.max(l,u)}}n.putImageData(r,0,0)},toObject:function(){return{color:this.color,image:this.image,mode:this.mode,alpha:this.alpha}}}),t.Image.filters.Blend.fromObject=function(e){return new t.Image.filters.Blend(e)}}(typeof exports!=\"undefined\"?exports:this),function(e){\"use strict\";var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.object.clone,i=t.util.toFixed,s=t.StaticCanvas.supports(\"setLineDash\");if(t.Text){t.warn(\"fabric.Text is already defined\");return}var o=t.Object.prototype.stateProperties.concat();o.push(\"fontFamily\",\"fontWeight\",\"fontSize\",\"text\",\"textDecoration\",\"textAlign\",\"fontStyle\",\"lineHeight\",\"textBackgroundColor\",\"useNative\",\"path\"),t.Text=t.util.createClass(t.Object,{_dimensionAffectingProps:{fontSize:!0,fontWeight:!0,fontFamily:!0,textDecoration:!0,fontStyle:!0,lineHeight:!0,stroke:!0,strokeWidth:!0,text:!0},_reNewline:/\\r?\\n/,type:\"text\",fontSize:40,fontWeight:\"normal\",fontFamily:\"Times New Roman\",textDecoration:\"\",textAlign:\"left\",fontStyle:\"\",lineHeight:1.3,textBackgroundColor:\"\",path:null,useNative:!0,stateProperties:o,stroke:null,shadow:null,initialize:function(e,t){t=t||{},this.text=e,this.__skipDimension=!0,this.setOptions(t),this.__skipDimension=!1,this._initDimensions()},_initDimensions:function(){if(this.__skipDimension)return;var e=t.util.createCanvasElement();this._render(e.getContext(\"2d\"))},toString:function(){return\"#<fabric.Text (\"+this.complexity()+'): { \"text\": \"'+this.text+'\", \"fontFamily\": \"'+this.fontFamily+'\" }>'},_render:function(e){typeof Cufon==\"undefined\"||this.useNative===!0?this._renderViaNative(e):this._renderViaCufon(e)},_renderViaNative:function(e){var n=this.text.split(this._reNewline);this._setTextStyles(e),this.width=this._getTextWidth(e,n),this.height=this._getTextHeight(e,n),this.clipTo&&t.util.clipContext(this,e),this._renderTextBackground(e,n),this._translateForTextAlign(e),this._renderText(e,n),this.textAlign!==\"left\"&&this.textAlign!==\"justify\"&&e.restore(),this._renderTextDecoration(e,n),this.clipTo&&e.restore(),this._setBoundaries(e,n),this._totalLineHeight=0},_renderText:function(e,t){e.save(),this._setShadow(e),this._setupCompositeOperation(e),this._renderTextFill(e,t),this._renderTextStroke(e,t),this._restoreCompositeOperation(e),this._removeShadow(e),e.restore()},_translateForTextAlign:function(e){this.textAlign!==\"left\"&&this.textAlign!==\"justify\"&&(e.save(),e.translate(this.textAlign===\"center\"?this.width/2:this.width,0))},_setBoundaries:function(e,t){this._boundaries=[];for(var n=0,r=t.length;n<r;n++){var i=this._getLineWidth(e,t[n]),s=this._getLineLeftOffset(i);this._boundaries.push({height:this.fontSize*this.lineHeight,width:i,left:s})}},_setTextStyles:function(e){this._setFillStyles(e),this._setStrokeStyles(e),e.textBaseline=\"alphabetic\",this.skipTextAlign||(e.textAlign=this.textAlign),e.font=this._getFontDeclaration()},_getTextHeight:function(e,t){return this.fontSize*t.length*this.lineHeight},_getTextWidth:function(e,t){var n=e.measureText(t[0]||\"|\").width;for(var r=1,i=t.length;r<i;r++){var s=e.measureText(t[r]).width;s>n&&(n=s)}return n},_renderChars:function(e,t,n,r,i){t[e](n,r,i)},_renderTextLine:function(e,t,n,r,i,s){i-=this.fontSize/4;if(this.textAlign!==\"justify\"){this._renderChars(e,t,n,r,i,s);return}var o=t.measureText(n).width,u=this.width;if(u>o){var a=n.split(/\\s+/),f=t.measureText(n.replace(/\\s+/g,\"\")).width,l=u-f,c=a.length-1,h=l/c,p=0;for(var d=0,v=a.length;d<v;d++)this._renderChars(e,t,a[d],r+p,i,s),p+=t.measureText(a[d]).width+h}else this._renderChars(e,t,n,r,i,s)},_getLeftOffset:function(){return t.isLikelyNode?0:-this.width/2},_getTopOffset:function(){return-this.height/2},_renderTextFill:function(e,t){if(!this.fill&&!this._skipFillStrokeCheck)return;this._boundaries=[];var n=0;for(var r=0,i=t.length;r<i;r++){var s=this._getHeightOfLine(e,r,t);n+=s,this._renderTextLine(\"fillText\",e,t[r],this._getLeftOffset(),this._getTopOffset()+n,r)}this.shadow&&!this.shadow.affectStroke&&this._removeShadow(e)},_renderTextStroke:function(e,t){if((!this.stroke||this.strokeWidth===0)&&!this._skipFillStrokeCheck)return;var n=0;e.save(),this.strokeDashArray&&(1&this.strokeDashArray.length&&this.strokeDashArray.push.apply(this.strokeDashArray,this.strokeDashArray),s&&e.setLineDash(this.strokeDashArray)),e.beginPath();for(var r=0,i=t.length;r<i;r++){var o=this._getHeightOfLine(e,r,t);n+=o,this._renderTextLine(\"strokeText\",e,t[r],this._getLeftOffset(),this._getTopOffset()+n,r)}e.closePath(),e.restore()},_getHeightOfLine:function(){return this.fontSize*this.lineHeight},_renderTextBackground:function(e,t){this._renderTextBoxBackground(e),this._renderTextLinesBackground(e,t)},_renderTextBoxBackground:function(e){if(!this.backgroundColor)return;e.save(),e.fillStyle=this.backgroundColor,e.fillRect(this._getLeftOffset(),this._getTopOffset(),this.width,this.height),e.restore()},_renderTextLinesBackground:function(e,t){if(!this.textBackgroundColor)return;e.save(),e.fillStyle=this.textBackgroundColor;for(var n=0,r=t.length;n<r;n++)if(t[n]!==\"\"){var i=this._getLineWidth(e,t[n]),s=this._getLineLeftOffset(i);e.fillRect(this._getLeftOffset()+s,this._getTopOffset()+n*this.fontSize*this.lineHeight,i,this.fontSize*this.lineHeight)}e.restore()},_getLineLeftOffset:function(e){return this.textAlign===\"center\"?(this.width-e)/2:this.textAlign===\"right\"?this.width-e:0},_getLineWidth:function(e,t){return this.textAlign===\"justify\"?this.width:e.measureText(t).width},_renderTextDecoration:function(e,t){function i(i){for(var s=0,o=t.length;s<o;s++){var u=r._getLineWidth(e,t[s]),a=r._getLineLeftOffset(u);e.fillRect(r._getLeftOffset()+a,~~(i+s*r._getHeightOfLine(e,s,t)-n),u,1)}}if(!this.textDecoration)return;var n=this._getTextHeight(e,t)/2,r=this;this.textDecoration.indexOf(\"underline\")>-1&&i(this.fontSize*this.lineHeight),this.textDecoration.indexOf(\"line-through\")>-1&&i(this.fontSize*this.lineHeight-this.fontSize/2),this.textDecoration.indexOf(\"overline\")>-1&&i(this.fontSize*this.lineHeight-this.fontSize)},_getFontDeclaration:function(){return[t.isLikelyNode?this.fontWeight:this.fontStyle,t.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+\"px\",t.isLikelyNode?'\"'+this.fontFamily+'\"':this.fontFamily].join(\" \")},render:function(e,t){if(!this.visible)return;e.save(),t||this.transform(e);var n=this.group&&this.group.type===\"path-group\";n&&e.translate(-this.group.width/2,-this.group.height/2),this.transformMatrix&&e.transform.apply(e,this.transformMatrix),n&&e.translate(this.left,this.top),this._render(e),e.restore()},toObject:function(e){var t=n(this.callSuper(\"toObject\",e),{text:this.text,fontSize:this.fontSize,fontWeight:this.fontWeight,fontFamily:this.fontFamily,fontStyle:this.fontStyle,lineHeight:this.lineHeight,textDecoration:this.textDecoration,textAlign:this.textAlign,path:this.path,textBackgroundColor:this.textBackgroundColor,useNative:this.useNative});return this.includeDefaultValues||this._removeDefaultValues(t),t},toSVG:function(e){var t=[],n=this.text.split(this._reNewline),r=this._getSVGLeftTopOffsets(n),i=this._getSVGTextAndBg(r.lineTop,r.textLeft,n),s=this._getSVGShadows(r.lineTop,n);return r.textTop+=this._fontAscent?this._fontAscent/5*this.lineHeight:0,this._wrapSVGTextAndBg(t,i,s,r),e?e(t.join(\"\")):t.join(\"\")},_getSVGLeftTopOffsets:function(e){var t=this.useNative?this.fontSize*this.lineHeight:-this._fontAscent-this._fontAscent/5*this.lineHeight,n=-(this.width/2),r=this.useNative?this.fontSize-1:this.height/2-e.length*this.fontSize-this._totalLineHeight;return{textLeft:n+(this.group&&this.group.type===\"path-group\"?this.left:0),textTop:r+(this.group&&this.group.type===\"path-group\"?this.top:0),lineTop:t}},_wrapSVGTextAndBg:function(e,t,n,r){e.push('<g transform=\"',this.getSvgTransform(),this.getSvgTransformMatrix(),'\">\\n',t.textBgRects.join(\"\"),\"<text \",this.fontFamily?'font-family=\"'+this.fontFamily.replace(/\"/g,\"'\")+'\" ':\"\",this.fontSize?'font-size=\"'+this.fontSize+'\" ':\"\",this.fontStyle?'font-style=\"'+this.fontStyle+'\" ':\"\",this.fontWeight?'font-weight=\"'+this.fontWeight+'\" ':\"\",this.textDecoration?'text-decoration=\"'+this.textDecoration+'\" ':\"\",'style=\"',this.getSvgStyles(),'\" ','transform=\"translate(',i(r.textLeft,2),\" \",i(r.textTop,2),')\">',n.join(\"\"),t.textSpans.join(\"\"),\"</text>\\n\",\"</g>\\n\")},_getSVGShadows:function(e,n){var r=[],s,o,u=1;if(!this.shadow||!this._boundaries)return r;for(s=0,o=n.length;s<o;s++)if(n[s]!==\"\"){var a=this._boundaries&&this._boundaries[s]?this._boundaries[s].left:0;r.push('<tspan x=\"',i(a+u+this.shadow.offsetX,2),s===0||this.useNative?'\" y':'\" dy','=\"',i(this.useNative?e*s-this.height/2+this.shadow.offsetY:e+(s===0?this.shadow.offsetY:0),2),'\" ',this._getFillAttributes(this.shadow.color),\">\",t.util.string.escapeXml(n[s]),\"</tspan>\"),u=1}else u++;return r},_getSVGTextAndBg:function(e,t,n){var r=[],i=[],s=1;this._setSVGBg(i);for(var o=0,u=n.length;o<u;o++){n[o]!==\"\"?(this._setSVGTextLineText(n[o],o,r,e,s,i),s=1):s++;if(!this.textBackgroundColor||!this._boundaries)continue;this._setSVGTextLineBg(i,o,t,e)}return{textSpans:r,textBgRects:i}},_setSVGTextLineText:function(e,n,r,s,o){var u=this._boundaries&&this._boundaries[n]?i(this._boundaries[n].left,2):0;r.push('<tspan x=\"',u,'\" ',n===0||this.useNative?\"y\":\"dy\",'=\"',i(this.useNative?s*n-this.height/2:s*o,2),'\" ',this._getFillAttributes(this.fill),\">\",t.util.string.escapeXml(e),\"</tspan>\")},_setSVGTextLineBg:function(e,t,n,r){e.push(\"<rect \",this._getFillAttributes(this.textBackgroundColor),' x=\"',i(n+this._boundaries[t].left,2),'\" y=\"',i(r*t-this.height/2,2),'\" width=\"',i(this._boundaries[t].width,2),'\" height=\"',i(this._boundaries[t].height,2),'\"></rect>\\n')},_setSVGBg:function(e){this.backgroundColor&&this._boundaries&&e.push(\"<rect \",this._getFillAttributes(this.backgroundColor),' x=\"',i(-this.width/2,2),'\" y=\"',i(-this.height/2,2),'\" width=\"',i(this.width,2),'\" height=\"',i(this.height,2),'\"></rect>')},_getFillAttributes:function(e){var n=e&&typeof e==\"string\"?new t.Color(e):\"\";return!n||!n.getSource()||n.getAlpha()===1?'fill=\"'+e+'\"':'opacity=\"'+n.getAlpha()+'\" fill=\"'+n.setAlpha(1).toRgb()+'\"'},_set:function(e,t){e===\"fontFamily\"&&this.path&&(this.path=this.path.replace(/(.*?)([^\\/]*)(\\.font\\.js)/,\"$1\"+t+\"$3\")),this.callSuper(\"_set\",e,t),e in this._dimensionAffectingProps&&(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),t.Text.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat(\"x y dx dy font-family font-style font-weight font-size text-decoration text-anchor\".split(\" \")),t.Text.DEFAULT_SVG_FONT_SIZE=16,t.Text.fromElement=function(e,n){if(!e)return null;var r=t.parseAttributes(e,t.Text.ATTRIBUTE_NAMES);n=t.util.object.extend(n?t.util.object.clone(n):{},r),\"dx\"in r&&(n.left+=r.dx),\"dy\"in r&&(n.top+=r.dy),\"fontSize\"in n||(n.fontSize=t.Text.DEFAULT_SVG_FONT_SIZE),n.originX||(n.originX=\"left\");var i=new t.Text(e.textContent,n),s=0;return i.originX===\"left\"&&(s=i.getWidth()/2),i.originX===\"right\"&&(s=-i.getWidth()/2),i.set({left:i.getLeft()+s,top:i.getTop()-i.getHeight()/2}),i},t.Text.fromObject=function(e){return new t.Text(e.text,r(e))},t.util.createAccessors(t.Text)}(typeof exports!=\"undefined\"?exports:this),function(){var e=fabric.util.object.clone;fabric.IText=fabric.util.createClass(fabric.Text,fabric.Observable,{type:\"i-text\",selectionStart:0,selectionEnd:0,selectionColor:\"rgba(17,119,255,0.3)\",isEditing:!1,editable:!0,editingBorderColor:\"rgba(102,153,255,0.25)\",cursorWidth:2,cursorColor:\"#333\",cursorDelay:1e3,cursorDuration:600,styles:null,caching:!0,_skipFillStrokeCheck:!0,_reSpace:/\\s|\\n/,_fontSizeFraction:4,_currentCursorOpacity:0,_selectionDirection:null,_abortCursorAnimation:!1,_charWidthsCache:{},initialize:function(e,t){this.styles=t?t.styles||{}:{},this.callSuper(\"initialize\",e,t),this.initBehavior(),fabric.IText.instances.push(this),this.__lineWidths={},this.__lineHeights={},this.__lineOffsets={}},isEmptyStyles:function(){if(!this.styles)return!0;var e=this.styles;for(var t in e)for(var n in e[t])for(var r in e[t][n])return!1;return!0},setSelectionStart:function(e){this.selectionStart!==e&&(this.fire(\"selection:changed\"),this.canvas&&this.canvas.fire(\"text:selection:changed\",{target:this})),this.selectionStart=e,this.hiddenTextarea&&(this.hiddenTextarea.selectionStart=e)},setSelectionEnd:function(e){this.selectionEnd!==e&&(this.fire(\"selection:changed\"),this.canvas&&this.canvas.fire(\"text:selection:changed\",{target:this})),this.selectionEnd=e,this.hiddenTextarea&&(this.hiddenTextarea.selectionEnd=e)},getSelectionStyles:function(e,t){if(arguments.length===2){var n=[];for(var r=e;r<t;r++)n.push(this.getSelectionStyles(r));return n}var i=this.get2DCursorLocation(e);return this.styles[i.lineIndex]?this.styles[i.lineIndex][i.charIndex]||{}:{}},setSelectionStyles:function(e){if(this.selectionStart===this.selectionEnd)this._extendStyles(this.selectionStart,e);else for(var t=this.selectionStart;t<this.selectionEnd;t++)this._extendStyles(t,e);return this},_extendStyles:function(e,t){var n=this.get2DCursorLocation(e);this.styles[n.lineIndex]||(this.styles[n.lineIndex]={}),this.styles[n.lineIndex][n.charIndex]||(this.styles[n.lineIndex][n.charIndex]={}),fabric.util.object.extend(this.styles[n.lineIndex][n.charIndex],t)},_render:function(e){this.callSuper(\"_render\",e),this.ctx=e,this.isEditing&&this.renderCursorOrSelection()},renderCursorOrSelection:function(){if(!this.active)return;var e=this.text.split(\"\"),t;this.selectionStart===this.selectionEnd?(t=this._getCursorBoundaries(e,\"cursor\"),this.renderCursor(t)):(t=this._getCursorBoundaries(e,\"selection\"),this.renderSelection(e,t))},get2DCursorLocation:function(e){typeof e==\"undefined\"&&(e=this.selectionStart);var t=this.text.slice(0,e),n=t.split(this._reNewline);return{lineIndex:n.length-1,charIndex:n[n.length-1].length}},getCurrentCharStyle:function(e,t){var n=this.styles[e]&&this.styles[e][t===0?0:t-1];return{fontSize:n&&n.fontSize||this.fontSize,fill:n&&n.fill||this.fill,textBackgroundColor:n&&n.textBackgroundColor||this.textBackgroundColor,textDecoration:n&&n.textDecoration||this.textDecoration,fontFamily:n&&n.fontFamily||this.fontFamily,fontWeight:n&&n.fontWeight||this.fontWeight,fontStyle:n&&n.fontStyle||this.fontStyle,stroke:n&&n.stroke||this.stroke,strokeWidth:n&&n.strokeWidth||this.strokeWidth}},getCurrentCharFontSize:function(e,t){return this.styles[e]&&this.styles[e][t===0?0:t-1]&&this.styles[e][t===0?0:t-1].fontSize||this.fontSize},getCurrentCharColor:function(e,t){return this.styles[e]&&this.styles[e][t===0?0:t-1]&&this.styles[e][t===0?0:t-1].fill||this.cursorColor},_getCursorBoundaries:function(e,t){var n=this.get2DCursorLocation(),r=this.text.split(this._reNewline),i=Math.round(this._getLeftOffset()),s=this._getTopOffset(),o=this._getCursorBoundariesOffsets(e,t,n,r);return{left:i,top:s,leftOffset:o.left+o.lineLeft,topOffset:o.top}},_getCursorBoundariesOffsets:function(e,t,n,r){var i=0,s=0,o=0,u=0,a=t===\"cursor\"?this._getHeightOfLine(this.ctx,0)-this.getCurrentCharFontSize(n.lineIndex,n.charIndex):0;for(var f=0;f<this.selectionStart;f++){if(e[f]===\"\\n\"){u=0;var l=s+(t===\"cursor\"?1:0);a+=this._getCachedLineHeight(l),s++,o=0}else u+=this._getWidthOfChar(this.ctx,e[f],s,o),o++;i=this._getCachedLineOffset(s,r)}return this._clearCache(),{top:a,left:u,lineLeft:i}},_clearCache:function(){this.__lineWidths={},this.__lineHeights={},this.__lineOffsets={}},_getCachedLineHeight:function(e){return this.__lineHeights[e]||(this.__lineHeights[e]=this._getHeightOfLine(this.ctx,e))},_getCachedLineWidth:function(e,t){return this.__lineWidths[e]||(this.__lineWidths[e]=this._getWidthOfLine(this.ctx,e,t))},_getCachedLineOffset:function(e,t){var n=this._getCachedLineWidth(e,t);return this.__lineOffsets[e]||(this.__lineOffsets[e]=this._getLineLeftOffset(n))},renderCursor:function(e){var t=this.ctx;t.save();var n=this.get2DCursorLocation(),r=n.lineIndex,i=n.charIndex,s=this.getCurrentCharFontSize(r,i),o=r===0&&i===0?this._getCachedLineOffset(r,this.text.split(this._reNewline)):e.leftOffset;t.fillStyle=this.getCurrentCharColor(r,i),t.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity,t.fillRect(e.left+o,e.top+e.topOffset,this.cursorWidth/this.scaleX,s),t.restore()},renderSelection:function(e,t){var n=this.ctx;n.save(),n.fillStyle=this.selectionColor;var r=this.get2DCursorLocation(this.selectionStart),i=this.get2DCursorLocation(this.selectionEnd),s=r.lineIndex,o=i.lineIndex,u=this.text.split(this._reNewline);for(var a=s;a<=o;a++){var f=this._getCachedLineOffset(a,u)||0,l=this._getCachedLineHeight(a),c=0;if(a===s)for(var h=0,p=u[a].length;h<p;h++)h>=r.charIndex&&(a!==o||h<i.charIndex)&&(c+=this._getWidthOfChar(n,u[a][h],a,h)),h<r.charIndex&&(f+=this._getWidthOfChar(n,u[a][h],a,h));else if(a>s&&a<o)c+=this._getCachedLineWidth(a,u)||5;else if(a===o)for(var d=0,v=i.charIndex;d<v;d++)c+=this._getWidthOfChar(n,u[a][d],a,d);n.fillRect(t.left+f,t.top+t.topOffset,c,l),t.topOffset+=l}n.restore()},_renderChars:function(e,t,n,r,i,s){if(this.isEmptyStyles())return this._renderCharsFast(e,t,n,r,i);this.skipTextAlign=!0,r-=this.textAlign===\"center\"?this.width/2:this.textAlign===\"right\"?this.width:0;var o=this.text.split(this._reNewline),u=this._getWidthOfLine(t,s,o),a=this._getHeightOfLine(t,s,o),f=this._getLineLeftOffset(u),l=n.split(\"\"),c,h=\"\";r+=f||0,t.save();for(var p=0,d=l.length;p<=d;p++){c=c||this.getCurrentCharStyle(s,p);var v=this.getCurrentCharStyle(s,p+1);if(this._hasStyleChanged(c,v)||p===d)this._renderChar(e,t,s,p-1,h,r,i,a),h=\"\",c=v;h+=l[p]}t.restore()},_renderCharsFast:function(e,t,n,r,i){this.skipTextAlign=!1,e===\"fillText\"&&this.fill&&this.callSuper(\"_renderChars\",e,t,n,r,i),e===\"strokeText\"&&this.stroke&&this.callSuper(\"_renderChars\",e,t,n,r,i)},_renderChar:function(e,t,n,r,i,s,o,u){var a,f,l;if(this.styles&&this.styles[n]&&(a=this.styles[n][r])){var c=a.stroke||this.stroke,h=a.fill||this.fill;t.save(),f=this._applyCharStylesGetWidth(t,i,n,r,a),l=this._getHeightOfChar(t,i,n,r),h&&t.fillText(i,s,o),c&&t.strokeText(i,s,o),this._renderCharDecoration(t,a,s,o,f,u,l),t.restore(),t.translate(f,0)}else e===\"strokeText\"&&this.stroke&&t[e](i,s,o),e===\"fillText\"&&this.fill&&t[e](i,s,o),f=this._applyCharStylesGetWidth(t,i,n,r),this._renderCharDecoration(t,null,s,o,f,u),t.translate(t.measureText(i).width,0)},_hasStyleChanged:function(e,t){return e.fill!==t.fill||e.fontSize!==t.fontSize||e.textBackgroundColor!==t.textBackgroundColor||e.textDecoration!==t.textDecoration||e.fontFamily!==t.fontFamily||e.fontWeight!==t.fontWeight||e.fontStyle!==t.fontStyle||e.stroke!==t.stroke||e.strokeWidth!==t.strokeWidth},_renderCharDecoration:function(e,t,n,r,i,s,o){var u=t?t.textDecoration||this.textDecoration:this.textDecoration,a=(t?t.fontSize:null)||this.fontSize;if(!u)return;u.indexOf(\"underline\")>-1&&this._renderCharDecorationAtOffset(e,n,r+this.fontSize/this._fontSizeFraction,i,0,this.fontSize/20),u.indexOf(\"line-through\")>-1&&this._renderCharDecorationAtOffset(e,n,r+this.fontSize/this._fontSizeFraction,i,o/2,a/20),u.indexOf(\"overline\")>-1&&this._renderCharDecorationAtOffset(e,n,r,i,s-this.fontSize/this._fontSizeFraction,this.fontSize/20)},_renderCharDecorationAtOffset:function(e,t,n,r,i,s){e.fillRect(t,n-i,r,s)},_renderTextLine:function(e,t,n,r,i,s){i+=this.fontSize/4,this.callSuper(\"_renderTextLine\",e,t,n,r,i,s)},_renderTextDecoration:function(e,t){if(this.isEmptyStyles())return this.callSuper(\"_renderTextDecoration\",e,t)},_renderTextLinesBackground:function(e,t){if(!this.textBackgroundColor&&!this.styles)return;e.save(),this.textBackgroundColor&&(e.fillStyle=this.textBackgroundColor);var n=0,r=this.fontSize/this._fontSizeFraction;for(var i=0,s=t.length;i<s;i++){var o=this._getHeightOfLine(e,i,t);if(t[i]===\"\"){n+=o;continue}var u=this._getWidthOfLine(e,i,t),a=this._getLineLeftOffset(u);this.textBackgroundColor&&(e.fillStyle=this.textBackgroundColor,e.fillRect(this._getLeftOffset()+a,this._getTopOffset()+n+r,u,o));if(this.styles[i])for(var f=0,l=t[i].length;f<l;f++)if(this.styles[i]&&this.styles[i][f]&&this.styles[i][f].textBackgroundColor){var c=t[i][f];e.fillStyle=this.styles[i][f].textBackgroundColor,e.fillRect(this._getLeftOffset()+a+this._getWidthOfCharsAt(e,i,f,t),this._getTopOffset()+n+r,this._getWidthOfChar(e,c,i,f,t)+1,o)}n+=o}e.restore()},_getCacheProp:function(e,t){return e+t.fontFamily+t.fontSize+t.fontWeight+t.fontStyle+t.shadow},_applyCharStylesGetWidth:function(t,n,r,i,s){var o=s||this.styles[r]&&this.styles[r][i];o?o=e(o):o={},this._applyFontStyles(o);var u=this._getCacheProp(n,o);if(this.isEmptyStyles()&&this._charWidthsCache[u]&&this.caching)return this._charWidthsCache[u];typeof o.shadow==\"string\"&&(o.shadow=new fabric.Shadow(o.shadow));var a=o.fill||this.fill;return t.fillStyle=a.toLive?a.toLive(t):a,o.stroke&&(t.strokeStyle=o.stroke&&o.stroke.toLive?o.stroke.toLive(t):o.stroke),t.lineWidth=o.strokeWidth||this.strokeWidth,t.font=this._getFontDeclaration.call(o),this._setShadow.call(o,t),this.caching?(this._charWidthsCache[u]||(this._charWidthsCache[u]=t.measureText(n).width),this._charWidthsCache[u]):t.measureText(n).width},_applyFontStyles:function(e){e.fontFamily||(e.fontFamily=this.fontFamily),e.fontSize||(e.fontSize=this.fontSize),e.fontWeight||(e.fontWeight=this.fontWeight),e.fontStyle||(e.fontStyle=this.fontStyle)},_getStyleDeclaration:function(t,n){return this.styles[t]&&this.styles[t][n]?e(this.styles[t][n]):{}},_getWidthOfChar:function(e,t,n,r){if(this.textAlign===\"justify\"&&/\\s/.test(t))return this._getWidthOfSpace(e,n);var i=this._getStyleDeclaration(n,r);this._applyFontStyles(i);var s=this._getCacheProp(t,i);if(this._charWidthsCache[s]&&this.caching)return this._charWidthsCache[s];if(e){e.save();var o=this._applyCharStylesGetWidth(e,t,n,r);return e.restore(),o}},_getHeightOfChar:function(e,t,n,r){return this.styles[n]&&this.styles[n][r]?this.styles[n][r].fontSize||this.fontSize:this.fontSize},_getWidthOfCharAt:function(e,t,n,r){r=r||this.text.split(this._reNewline);var i=r[t].split(\"\")[n];return this._getWidthOfChar(e,i,t,n)},_getHeightOfCharAt:function(e,t,n,r){r=r||this.text.split(this._reNewline);var i=r[t].split(\"\")[n];return this._getHeightOfChar(e,i,t,n)},_getWidthOfCharsAt:function(e,t,n,r){var i=0;for(var s=0;s<n;s++)i+=this._getWidthOfCharAt(e,t,s,r);return i},_getWidthOfLine:function(e,t,n){return this._getWidthOfCharsAt(e,t,n[t].length,n)},_getWidthOfSpace:function(e,t){var n=this.text.split(this._reNewline),r=n[t],i=r.split(/\\s+/),s=this._getWidthOfWords(e,r,t),o=this.width-s,u=i.length-1,a=o/u;return a},_getWidthOfWords:function(e,t,n){var r=0;for(var i=0;i<t.length;i++\n){var s=t[i];s.match(/\\s/)||(r+=this._getWidthOfChar(e,s,n,i))}return r},_getTextWidth:function(e,t){if(this.isEmptyStyles())return this.callSuper(\"_getTextWidth\",e,t);var n=this._getWidthOfLine(e,0,t);for(var r=1,i=t.length;r<i;r++){var s=this._getWidthOfLine(e,r,t);s>n&&(n=s)}return n},_getHeightOfLine:function(e,t,n){n=n||this.text.split(this._reNewline);var r=this._getHeightOfChar(e,n[t][0],t,0),i=n[t],s=i.split(\"\");for(var o=1,u=s.length;o<u;o++){var a=this._getHeightOfChar(e,s[o],t,o);a>r&&(r=a)}return r*this.lineHeight},_getTextHeight:function(e,t){var n=0;for(var r=0,i=t.length;r<i;r++)n+=this._getHeightOfLine(e,r,t);return n},_getTopOffset:function(){var e=fabric.Text.prototype._getTopOffset.call(this);return e-this.fontSize/this._fontSizeFraction},_renderTextBoxBackground:function(e){if(!this.backgroundColor)return;e.save(),e.fillStyle=this.backgroundColor,e.fillRect(this._getLeftOffset(),this._getTopOffset()+this.fontSize/this._fontSizeFraction,this.width,this.height),e.restore()},toObject:function(t){return fabric.util.object.extend(this.callSuper(\"toObject\",t),{styles:e(this.styles)})}}),fabric.IText.fromObject=function(t){return new fabric.IText(t.text,e(t))},fabric.IText.instances=[]}(),function(){var e=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initAddedHandler(),this.initCursorSelectionHandlers(),this.initDoubleClickSimulation()},initSelectedHandler:function(){this.on(\"selected\",function(){var e=this;setTimeout(function(){e.selected=!0},100)})},initAddedHandler:function(){this.on(\"added\",function(){this.canvas&&!this.canvas._hasITextHandlers&&(this.canvas._hasITextHandlers=!0,this._initCanvasHandlers())})},_initCanvasHandlers:function(){this.canvas.on(\"selection:cleared\",function(){fabric.IText.prototype.exitEditingOnOthers.call()}),this.canvas.on(\"mouse:up\",function(){fabric.IText.instances.forEach(function(e){e.__isMousedown=!1})}),this.canvas.on(\"object:selected\",function(e){fabric.IText.prototype.exitEditingOnOthers.call(e.target)})},_tick:function(){if(this._abortCursorAnimation)return;var e=this;this.animate(\"_currentCursorOpacity\",1,{duration:this.cursorDuration,onComplete:function(){e._onTickComplete()},onChange:function(){e.canvas&&e.canvas.renderAll()},abort:function(){return e._abortCursorAnimation}})},_onTickComplete:function(){if(this._abortCursorAnimation)return;var e=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1),this._cursorTimeout1=setTimeout(function(){e.animate(\"_currentCursorOpacity\",0,{duration:this.cursorDuration/2,onComplete:function(){e._tick()},onChange:function(){e.canvas&&e.canvas.renderAll()},abort:function(){return e._abortCursorAnimation}})},100)},initDelayedCursor:function(e){var t=this,n=e?0:this.cursorDelay;e&&(this._abortCursorAnimation=!0,clearTimeout(this._cursorTimeout1),this._currentCursorOpacity=1,this.canvas&&this.canvas.renderAll()),this._cursorTimeout2&&clearTimeout(this._cursorTimeout2),this._cursorTimeout2=setTimeout(function(){t._abortCursorAnimation=!1,t._tick()},n)},abortCursorAnimation:function(){this._abortCursorAnimation=!0,clearTimeout(this._cursorTimeout1),clearTimeout(this._cursorTimeout2),this._currentCursorOpacity=0,this.canvas&&this.canvas.renderAll();var e=this;setTimeout(function(){e._abortCursorAnimation=!1},10)},selectAll:function(){this.selectionStart=0,this.selectionEnd=this.text.length,this.fire(\"selection:changed\"),this.canvas&&this.canvas.fire(\"text:selection:changed\",{target:this})},getSelectedText:function(){return this.text.slice(this.selectionStart,this.selectionEnd)},findWordBoundaryLeft:function(e){var t=0,n=e-1;if(this._reSpace.test(this.text.charAt(n)))while(this._reSpace.test(this.text.charAt(n)))t++,n--;while(/\\S/.test(this.text.charAt(n))&&n>-1)t++,n--;return e-t},findWordBoundaryRight:function(e){var t=0,n=e;if(this._reSpace.test(this.text.charAt(n)))while(this._reSpace.test(this.text.charAt(n)))t++,n++;while(/\\S/.test(this.text.charAt(n))&&n<this.text.length)t++,n++;return e+t},findLineBoundaryLeft:function(e){var t=0,n=e-1;while(!/\\n/.test(this.text.charAt(n))&&n>-1)t++,n--;return e-t},findLineBoundaryRight:function(e){var t=0,n=e;while(!/\\n/.test(this.text.charAt(n))&&n<this.text.length)t++,n++;return e+t},getNumNewLinesInSelectedText:function(){var e=this.getSelectedText(),t=0;for(var n=0,r=e.split(\"\"),i=r.length;n<i;n++)r[n]===\"\\n\"&&t++;return t},searchWordBoundary:function(e,t){var n=this._reSpace.test(this.text.charAt(e))?e-1:e,r=this.text.charAt(n),i=/[ \\n\\.,;!\\?\\-]/;while(!i.test(r)&&n>0&&n<this.text.length)n+=t,r=this.text.charAt(n);return i.test(r)&&r!==\"\\n\"&&(n+=t===1?0:1),n},selectWord:function(e){var t=this.searchWordBoundary(e,-1),n=this.searchWordBoundary(e,1);this.setSelectionStart(t),this.setSelectionEnd(n),this.initDelayedCursor(!0)},selectLine:function(e){var t=this.findLineBoundaryLeft(e),n=this.findLineBoundaryRight(e);this.setSelectionStart(t),this.setSelectionEnd(n),this.initDelayedCursor(!0)},enterEditing:function(){if(this.isEditing||!this.editable)return;return this.exitEditingOnOthers(),this.isEditing=!0,this.initHiddenTextarea(),this._updateTextarea(),this._saveEditingProps(),this._setEditingProps(),this._tick(),this.canvas&&this.canvas.renderAll(),this.fire(\"editing:entered\"),this.canvas&&this.canvas.fire(\"text:editing:entered\",{target:this}),this},exitEditingOnOthers:function(){fabric.IText.instances.forEach(function(e){e.selected=!1,e.isEditing&&e.exitEditing()},this)},_setEditingProps:function(){this.hoverCursor=\"text\",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor=\"text\"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},_updateTextarea:function(){if(!this.hiddenTextarea)return;this.hiddenTextarea.value=this.text,this.hiddenTextarea.selectionStart=this.selectionStart},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){if(!this._savedProps)return;this.hoverCursor=this._savedProps.overCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY,this.canvas&&(this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor)},exitEditing:function(){return this.selected=!1,this.isEditing=!1,this.selectable=!0,this.selectionEnd=this.selectionStart,this.hiddenTextarea&&this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,this.fire(\"editing:exited\"),this.canvas&&this.canvas.fire(\"text:editing:exited\",{target:this}),this},_removeExtraneousStyles:function(){var e=this.text.split(this._reNewline);for(var t in this.styles)e[t]||delete this.styles[t]},_removeCharsFromTo:function(e,t){var n=t;while(n!==e){var r=this.get2DCursorLocation(n).charIndex;n--;var i=this.get2DCursorLocation(n).charIndex,s=i>r;s?this.removeStyleObject(s,n+1):this.removeStyleObject(this.get2DCursorLocation(n).charIndex===0,n)}this.text=this.text.slice(0,e)+this.text.slice(t)},insertChars:function(e){var t=this.text.slice(this.selectionStart,this.selectionStart+1)===\"\\n\";this.text=this.text.slice(0,this.selectionStart)+e+this.text.slice(this.selectionEnd),this.selectionStart===this.selectionEnd&&this.insertStyleObjects(e,t,this.copiedStyles),this.selectionStart+=e.length,this.selectionEnd=this.selectionStart,this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire(\"changed\"),this.canvas&&this.canvas.fire(\"text:changed\",{target:this})},insertNewlineStyleObject:function(t,n,r){this.shiftLineStyles(t,1),this.styles[t+1]||(this.styles[t+1]={});var i=this.styles[t][n-1],s={};if(r)s[0]=e(i),this.styles[t+1]=s;else{for(var o in this.styles[t])parseInt(o,10)>=n&&(s[parseInt(o,10)-n]=this.styles[t][o],delete this.styles[t][o]);this.styles[t+1]=s}},insertCharStyleObject:function(t,n,r){var i=this.styles[t],s=e(i);n===0&&!r&&(n=1);for(var o in s){var u=parseInt(o,10);u>=n&&(i[u+1]=s[u])}this.styles[t][n]=r||e(i[n-1])},insertStyleObjects:function(e,t,n){if(this.isEmptyStyles())return;var r=this.get2DCursorLocation(),i=r.lineIndex,s=r.charIndex;this.styles[i]||(this.styles[i]={}),e===\"\\n\"?this.insertNewlineStyleObject(i,s,t):n?this._insertStyles(n):this.insertCharStyleObject(i,s)},_insertStyles:function(e){for(var t=0,n=e.length;t<n;t++){var r=this.get2DCursorLocation(this.selectionStart+t),i=r.lineIndex,s=r.charIndex;this.insertCharStyleObject(i,s,e[t])}},shiftLineStyles:function(t,n){var r=e(this.styles);for(var i in this.styles){var s=parseInt(i,10);s>t&&(this.styles[s+n]=r[s])}},removeStyleObject:function(t,n){var r=this.get2DCursorLocation(n),i=r.lineIndex,s=r.charIndex;if(t){var o=this.text.split(this._reNewline),u=o[i-1],a=u?u.length:0;this.styles[i-1]||(this.styles[i-1]={});for(s in this.styles[i])this.styles[i-1][parseInt(s,10)+a]=this.styles[i][s];this.shiftLineStyles(i,-1)}else{var f=this.styles[i];if(f){var l=this.selectionStart===this.selectionEnd?-1:0;delete f[s+l]}var c=e(f);for(var h in c){var p=parseInt(h,10);p>=s&&p!==0&&(f[p-1]=c[p],delete f[p])}}},insertNewline:function(){this.insertChars(\"\\n\")}})}(),fabric.util.object.extend(fabric.IText.prototype,{initDoubleClickSimulation:function(){this.__lastClickTime=+(new Date),this.__lastLastClickTime=+(new Date),this.__lastPointer={},this.on(\"mousedown\",this.onMouseDown.bind(this))},onMouseDown:function(e){this.__newClickTime=+(new Date);var t=this.canvas.getPointer(e.e);this.isTripleClick(t)?(this.fire(\"tripleclick\",e),this._stopEvent(e.e)):this.isDoubleClick(t)&&(this.fire(\"dblclick\",e),this._stopEvent(e.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=t,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected},isDoubleClick:function(e){return this.__newClickTime-this.__lastClickTime<500&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y&&this.__lastIsEditing},isTripleClick:function(e){return this.__newClickTime-this.__lastClickTime<500&&this.__lastClickTime-this.__lastLastClickTime<500&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y},_stopEvent:function(e){e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation()},initCursorSelectionHandlers:function(){this.initSelectedHandler(),this.initMousedownHandler(),this.initMousemoveHandler(),this.initMouseupHandler(),this.initClicks()},initClicks:function(){this.on(\"dblclick\",function(e){this.selectWord(this.getSelectionStartFromPointer(e.e))}),this.on(\"tripleclick\",function(e){this.selectLine(this.getSelectionStartFromPointer(e.e))})},initMousedownHandler:function(){this.on(\"mousedown\",function(e){var t=this.canvas.getPointer(e.e);this.__mousedownX=t.x,this.__mousedownY=t.y,this.__isMousedown=!0,this.hiddenTextarea&&this.canvas&&this.canvas.wrapperEl.appendChild(this.hiddenTextarea),this.selected&&this.setCursorByClick(e.e),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.initDelayedCursor(!0))})},initMousemoveHandler:function(){this.on(\"mousemove\",function(e){if(!this.__isMousedown||!this.isEditing)return;var t=this.getSelectionStartFromPointer(e.e);t>=this.__selectionStartOnMouseDown?(this.setSelectionStart(this.__selectionStartOnMouseDown),this.setSelectionEnd(t)):(this.setSelectionStart(t),this.setSelectionEnd(this.__selectionStartOnMouseDown))})},_isObjectMoved:function(e){var t=this.canvas.getPointer(e);return this.__mousedownX!==t.x||this.__mousedownY!==t.y},initMouseupHandler:function(){this.on(\"mouseup\",function(e){this.__isMousedown=!1;if(this._isObjectMoved(e.e))return;this.__lastSelected&&(this.enterEditing(),this.initDelayedCursor(!0)),this.selected=!0})},setCursorByClick:function(e){var t=this.getSelectionStartFromPointer(e);e.shiftKey?t<this.selectionStart?(this.setSelectionEnd(this.selectionStart),this.setSelectionStart(t)):this.setSelectionEnd(t):(this.setSelectionStart(t),this.setSelectionEnd(t))},_getLocalRotatedPointer:function(e){var t=this.canvas.getPointer(e),n=new fabric.Point(t.x,t.y),r=new fabric.Point(this.left,this.top),i=fabric.util.rotatePoint(n,r,fabric.util.degreesToRadians(-this.angle));return this.getLocalPointer(e,i)},getSelectionStartFromPointer:function(e){var t=this._getLocalRotatedPointer(e),n=this.text.split(this._reNewline),r=0,i=0,s=0,o=0,u;for(var a=0,f=n.length;a<f;a++){s+=this._getHeightOfLine(this.ctx,a)*this.scaleY;var l=this._getWidthOfLine(this.ctx,a,n),c=this._getLineLeftOffset(l);i=c*this.scaleX,this.flipX&&(n[a]=n[a].split(\"\").reverse().join(\"\"));for(var h=0,p=n[a].length;h<p;h++){var d=n[a][h];r=i,i+=this._getWidthOfChar(this.ctx,d,a,this.flipX?p-h:h)*this.scaleX;if(s<=t.y||i<=t.x){o++;continue}return this._getNewSelectionStartFromOffset(t,r,i,o+a,p)}if(t.y<s)return this._getNewSelectionStartFromOffset(t,r,i,o+a,p)}if(typeof u==\"undefined\")return this.text.length},_getNewSelectionStartFromOffset:function(e,t,n,r,i){var s=e.x-t,o=n-e.x,u=o>s?0:1,a=r+u;return this.flipX&&(a=i-a),a>this.text.length&&(a=this.text.length),a}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement(\"textarea\"),this.hiddenTextarea.setAttribute(\"autocapitalize\",\"off\"),this.hiddenTextarea.style.cssText=\"position: absolute; top: 0; left: -9999px\",fabric.document.body.appendChild(this.hiddenTextarea),fabric.util.addListener(this.hiddenTextarea,\"keydown\",this.onKeyDown.bind(this)),fabric.util.addListener(this.hiddenTextarea,\"keypress\",this.onKeyPress.bind(this)),fabric.util.addListener(this.hiddenTextarea,\"copy\",this.copy.bind(this)),fabric.util.addListener(this.hiddenTextarea,\"paste\",this.paste.bind(this)),!this._clickHandlerInitialized&&this.canvas&&(fabric.util.addListener(this.canvas.upperCanvasEl,\"click\",this.onClick.bind(this)),this._clickHandlerInitialized=!0)},_keysMap:{8:\"removeChars\",9:\"exitEditing\",27:\"exitEditing\",13:\"insertNewline\",33:\"moveCursorUp\",34:\"moveCursorDown\",35:\"moveCursorRight\",36:\"moveCursorLeft\",37:\"moveCursorLeft\",38:\"moveCursorUp\",39:\"moveCursorRight\",40:\"moveCursorDown\",46:\"forwardDelete\"},_ctrlKeysMap:{65:\"selectAll\",88:\"cut\"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(e){if(!this.isEditing)return;if(e.keyCode in this._keysMap)this[this._keysMap[e.keyCode]](e);else{if(!(e.keyCode in this._ctrlKeysMap&&(e.ctrlKey||e.metaKey)))return;this[this._ctrlKeysMap[e.keyCode]](e)}e.stopImmediatePropagation(),e.preventDefault(),this.canvas&&this.canvas.renderAll()},forwardDelete:function(e){this.selectionStart===this.selectionEnd&&this.moveCursorRight(e),this.removeChars(e)},copy:function(e){var t=this.getSelectedText(),n=this._getClipboardData(e);n&&n.setData(\"text\",t),this.copiedText=t,this.copiedStyles=this.getSelectionStyles(this.selectionStart,this.selectionEnd)},paste:function(e){var t=null,n=this._getClipboardData(e);n?t=n.getData(\"text\"):t=this.copiedText,t&&this.insertChars(t)},cut:function(e){if(this.selectionStart===this.selectionEnd)return;this.copy(),this.removeChars(e)},_getClipboardData:function(e){return e&&(e.clipboardData||fabric.window.clipboardData)},onKeyPress:function(e){if(!this.isEditing||e.metaKey||e.ctrlKey)return;e.which!==0&&this.insertChars(String.fromCharCode(e.which)),e.stopPropagation()},getDownCursorOffset:function(e,t){var n=t?this.selectionEnd:this.selectionStart,r=this.text.split(this._reNewline),i,s,o=this.text.slice(0,n),u=this.text.slice(n),a=o.slice(o.lastIndexOf(\"\\n\")+1),f=u.match(/(.*)\\n?/)[1],l=(u.match(/.*\\n(.*)\\n?/)||{})[1]||\"\",c=this.get2DCursorLocation(n);if(c.lineIndex===r.length-1||e.metaKey||e.keyCode===34)return this.text.length-n;var h=this._getWidthOfLine(this.ctx,c.lineIndex,r);s=this._getLineLeftOffset(h);var p=s,d=c.lineIndex;for(var v=0,m=a.length;v<m;v++)i=a[v],p+=this._getWidthOfChar(this.ctx,i,d,v);var g=this._getIndexOnNextLine(c,l,p,r);return f.length+1+g},_getIndexOnNextLine:function(e,t,n,r){var i=e.lineIndex+1,s=this._getWidthOfLine(this.ctx,i,r),o=this._getLineLeftOffset(s),u=o,a=0,f;for(var l=0,c=t.length;l<c;l++){var h=t[l],p=this._getWidthOfChar(this.ctx,h,i,l);u+=p;if(u>n){f=!0;var d=u-p,v=u,m=Math.abs(d-n),g=Math.abs(v-n);a=g<m?l+1:l;break}}return f||(a=t.length),a},moveCursorDown:function(e){this.abortCursorAnimation(),this._currentCursorOpacity=1;var t=this.getDownCursorOffset(e,this._selectionDirection===\"right\");e.shiftKey?this.moveCursorDownWithShift(t):this.moveCursorDownWithoutShift(t),this.initDelayedCursor()},moveCursorDownWithoutShift:function(e){this._selectionDirection=\"right\",this.selectionStart+=e,this.selectionStart>this.text.length&&(this.selectionStart=this.text.length),this.selectionEnd=this.selectionStart},swapSelectionPoints:function(){var e=this.selectionEnd;this.selectionEnd=this.selectionStart,this.selectionStart=e},moveCursorDownWithShift:function(e){this.selectionEnd===this.selectionStart&&(this._selectionDirection=\"right\");var t=this._selectionDirection===\"right\"?\"selectionEnd\":\"selectionStart\";this[t]+=e,this.selectionEnd<this.selectionStart&&this._selectionDirection===\"left\"&&(this.swapSelectionPoints(),this._selectionDirection=\"right\"),this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length)},getUpCursorOffset:function(e,t){var n=t?this.selectionEnd:this.selectionStart,r=this.get2DCursorLocation(n);if(r.lineIndex===0||e.metaKey||e.keyCode===33)return n;var i=this.text.slice(0,n),s=i.slice(i.lastIndexOf(\"\\n\")+1),o=(i.match(/\\n?(.*)\\n.*$/)||{})[1]||\"\",u=this.text.split(this._reNewline),a,f=this._getWidthOfLine(this.ctx,r.lineIndex,u),l=this._getLineLeftOffset(f),c=l,h=r.lineIndex;for(var p=0,d=s.length;p<d;p++)a=s[p],c+=this._getWidthOfChar(this.ctx,a,h,p);var v=this._getIndexOnPrevLine(r,o,c,u);return o.length-v+s.length},_getIndexOnPrevLine:function(e,t,n,r){var i=e.lineIndex-1,s=this._getWidthOfLine(this.ctx,i,r),o=this._getLineLeftOffset(s),u=o,a=0,f;for(var l=0,c=t.length;l<c;l++){var h=t[l],p=this._getWidthOfChar(this.ctx,h,i,l);u+=p;if(u>n){f=!0;var d=u-p,v=u,m=Math.abs(d-n),g=Math.abs(v-n);a=g<m?l:l-1;break}}return f||(a=t.length-1),a},moveCursorUp:function(e){this.abortCursorAnimation(),this._currentCursorOpacity=1;var t=this.getUpCursorOffset(e,this._selectionDirection===\"right\");e.shiftKey?this.moveCursorUpWithShift(t):this.moveCursorUpWithoutShift(t),this.initDelayedCursor()},moveCursorUpWithShift:function(e){this.selectionEnd===this.selectionStart&&(this._selectionDirection=\"left\");var t=this._selectionDirection===\"right\"?\"selectionEnd\":\"selectionStart\";this[t]-=e,this.selectionEnd<this.selectionStart&&this._selectionDirection===\"right\"&&(this.swapSelectionPoints(),this._selectionDirection=\"left\"),this.selectionStart<0&&(this.selectionStart=0)},moveCursorUpWithoutShift:function(e){this.selectionStart===this.selectionEnd&&(this.selectionStart-=e),this.selectionStart<0&&(this.selectionStart=0),this.selectionEnd=this.selectionStart,this._selectionDirection=\"left\"},moveCursorLeft:function(e){if(this.selectionStart===0&&this.selectionEnd===0)return;this.abortCursorAnimation(),this._currentCursorOpacity=1,e.shiftKey?this.moveCursorLeftWithShift(e):this.moveCursorLeftWithoutShift(e),this.initDelayedCursor()},_move:function(e,t,n){e.altKey?this[t]=this[\"findWordBoundary\"+n](this[t]):e.metaKey||e.keyCode===35||e.keyCode===36?this[t]=this[\"findLineBoundary\"+n](this[t]):this[t]+=n===\"Left\"?-1:1},_moveLeft:function(e,t){this._move(e,t,\"Left\")},_moveRight:function(e,t){this._move(e,t,\"Right\")},moveCursorLeftWithoutShift:function(e){this._selectionDirection=\"left\",this.selectionEnd===this.selectionStart&&this._moveLeft(e,\"selectionStart\"),this.selectionEnd=this.selectionStart},moveCursorLeftWithShift:function(e){this._selectionDirection===\"right\"&&this.selectionStart!==this.selectionEnd?this._moveLeft(e,\"selectionEnd\"):(this._selectionDirection=\"left\",this._moveLeft(e,\"selectionStart\"),this.text.charAt(this.selectionStart)===\"\\n\"&&this.selectionStart--,this.selectionStart<0&&(this.selectionStart=0))},moveCursorRight:function(e){if(this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length)return;this.abortCursorAnimation(),this._currentCursorOpacity=1,e.shiftKey?this.moveCursorRightWithShift(e):this.moveCursorRightWithoutShift(e),this.initDelayedCursor()},moveCursorRightWithShift:function(e){this._selectionDirection===\"left\"&&this.selectionStart!==this.selectionEnd?this._moveRight(e,\"selectionStart\"):(this._selectionDirection=\"right\",this._moveRight(e,\"selectionEnd\"),this.text.charAt(this.selectionEnd-1)===\"\\n\"&&this.selectionEnd++,this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length))},moveCursorRightWithoutShift:function(e){this._selectionDirection=\"right\",this.selectionStart===this.selectionEnd?(this._moveRight(e,\"selectionStart\"),this.selectionEnd=this.selectionStart):(this.selectionEnd+=this.getNumNewLinesInSelectedText(),this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length),this.selectionStart=this.selectionEnd)},removeChars:function(e){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(e):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.selectionEnd=this.selectionStart,this._removeExtraneousStyles(),this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire(\"changed\"),this.canvas&&this.canvas.fire(\"text:changed\",{target:this})},_removeCharsNearCursor:function(e){if(this.selectionStart!==0)if(e.metaKey){var t=this.findLineBoundaryLeft(this.selectionStart);this._removeCharsFromTo(t,this.selectionStart),this.selectionStart=t}else if(e.altKey){var n=this.findWordBoundaryLeft(this.selectionStart);this._removeCharsFromTo(n,this.selectionStart),this.selectionStart=n}else{var r=this.text.slice(this.selectionStart-1,this.selectionStart)===\"\\n\";this.removeStyleObject(r),this.selectionStart--,this.text=this.text.slice(0,this.selectionStart)+this.text.slice(this.selectionStart+1)}}}),fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(e,t,n,r,i,s){this.styles[t]?this._setSVGTextLineChars(e,t,n,r,i,s):this.callSuper(\"_setSVGTextLineText\",e,t,n,r,i)},_setSVGTextLineChars:function(e,t,n,r,i,s){var o=t===0||this.useNative?\"y\":\"dy\",u=e.split(\"\"),a=0,f=this._getSVGLineLeftOffset(t),l=this._getSVGLineTopOffset(t),c=this._getHeightOfLine(this.ctx,t);for(var h=0,p=u.length;h<p;h++){var d=this.styles[t][h]||{};n.push(this._createTextCharSpan(u[h],d,f,l,o,a));var v=this._getWidthOfChar(this.ctx,u[h],t,h);d.textBackgroundColor&&s.push(this._createTextCharBg(d,f,l,c,v,a)),a+=v}},_getSVGLineLeftOffset:function(e){return this._boundaries&&this._boundaries[e]?fabric.util.toFixed(this._boundaries[e].left,2):0},_getSVGLineTopOffset:function(e){var t=0;for(var n=0;n<=e;n++)t+=this._getHeightOfLine(this.ctx,n);return t-this.height/2},_createTextCharBg:function(e,t,n,r,i,s){return['<rect fill=\"',e.textBackgroundColor,'\" transform=\"translate(',-this.width/2,\" \",-this.height+r,\")\",'\" x=\"',t+s,'\" y=\"',n+r,'\" width=\"',i,'\" height=\"',r,'\"></rect>'].join(\"\")},_createTextCharSpan:function(e,t,n,r,i,s){var o=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:\"text\"},t));return['<tspan x=\"',n+s,'\" ',i,'=\"',r,'\" ',t.fontFamily?'font-family=\"'+t.fontFamily.replace(/\"/g,\"'\")+'\" ':\"\",t.fontSize?'font-size=\"'+t.fontSize+'\" ':\"\",t.fontStyle?'font-style=\"'+t.fontStyle+'\" ':\"\",t.fontWeight?'font-weight=\"'+t.fontWeight+'\" ':\"\",t.textDecoration?'text-decoration=\"'+t.textDecoration+'\" ':\"\",'style=\"',o,'\">',fabric.util.string.escapeXml(e),\"</tspan>\"].join(\"\")}}),function(){function request(e,t,n){var r=URL.parse(e);r.port||(r.port=r.protocol.indexOf(\"https:\")===0?443:80);var i=r.port===443?HTTPS:HTTP,s=i.request({hostname:r.hostname,port:r.port,path:r.path,method:\"GET\"},function(e){var r=\"\";t&&e.setEncoding(t),e.on(\"end\",function(){n(r)}),e.on(\"data\",function(t){e.statusCode===200&&(r+=t)})});s.on(\"error\",function(e){e.errno===process.ECONNREFUSED?fabric.log(\"ECONNREFUSED: connection refused to \"+r.hostname+\":\"+r.port):fabric.log(e.message)}),s.end()}function requestFs(e,t){var n=require(\"fs\");n.readFile(e,function(e,n){if(e)throw fabric.log(e),e;t(n)})}if(typeof document!=\"undefined\"&&typeof window!=\"undefined\")return;var DOMParser=require(\"xmldom\").DOMParser,URL=require(\"url\"),HTTP=require(\"http\"),HTTPS=require(\"https\"),Canvas=require(\"canvas\"),Image=require(\"canvas\").Image;fabric.util.loadImage=function(e,t,n){function r(r){i.src=new Buffer(r,\"binary\"),i._src=e,t&&t.call(n,i)}var i=new Image;e&&(e instanceof Buffer||e.indexOf(\"data\")===0)?(i.src=i._src=e,t&&t.call(n,i)):e&&e.indexOf(\"http\")!==0?requestFs(e,r):e?request(e,\"binary\",r):t&&t.call(n,e)},fabric.loadSVGFromURL=function(e,t,n){e=e.replace(/^\\n\\s*/,\"\").replace(/\\?.*$/,\"\").trim(),e.indexOf(\"http\")!==0?requestFs(e,function(e){fabric.loadSVGFromString(e.toString(),t,n)}):request(e,\"\",function(e){fabric.loadSVGFromString(e,t,n)})},fabric.loadSVGFromString=function(e,t,n){var r=(new DOMParser).parseFromString(e);fabric.parseSVGDocument(r.documentElement,function(e,n){t&&t(e,n)},n)},fabric.util.getScript=function(url,callback){request(url,\"\",function(body){eval(body),callback&&callback()})},fabric.Image.fromObject=function(e,t){fabric.util.loadImage(e.src,function(n){var r=new fabric.Image(n);r._initConfig(e),r._initFilters(e,function(e){r.filters=e||[],t&&t(r)})})},fabric.createCanvasForNode=function(e,t,n,r){r=r||n;var i=fabric.document.createElement(\"canvas\"),s=new Canvas(e||600,t||600,r);i.style={},i.width=s.width,i.height=s.height;var o=fabric.Canvas||fabric.StaticCanvas,u=new o(i,n);return u.contextContainer=s.getContext(\"2d\"),u.nodeCanvas=s,u.Font=Canvas.Font,u},fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(e){return this.nodeCanvas.createJPEGStream(e)};var origSetWidth=fabric.StaticCanvas.prototype.setWidth;fabric.StaticCanvas.prototype.setWidth=function(e,t){return origSetWidth.call(this,e,t),this.nodeCanvas.width=e,this},fabric.Canvas&&(fabric.Canvas.prototype.setWidth=fabric.StaticCanvas.prototype.setWidth);var origSetHeight=fabric.StaticCanvas.prototype.setHeight;fabric.StaticCanvas.prototype.setHeight=function(e,t){return origSetHeight.call(this,e,t),this.nodeCanvas.height=e,this},fabric.Canvas&&(fabric.Canvas.prototype.setHeight=fabric.StaticCanvas.prototype.setHeight)}();"
  },
  {
    "path": "src/libs/flashdetect/flashdetect.js",
    "content": "/*\n Copyright (c) Copyright (c) 2007, Carl S. Yestrau All rights reserved.\n Code licensed under the BSD License: http://www.featureblend.com/license.txt\n Version: 1.0.4\n */\nvar FlashDetect = new function(){\n    var self = this;\n    self.installed = false;\n    self.raw = \"\";\n    self.major = -1;\n    self.minor = -1;\n    self.revision = -1;\n    self.revisionStr = \"\";\n    var activeXDetectRules = [\n        {\n            \"name\":\"ShockwaveFlash.ShockwaveFlash.7\",\n            \"version\":function(obj){\n                return getActiveXVersion(obj);\n            }\n        },\n        {\n            \"name\":\"ShockwaveFlash.ShockwaveFlash.6\",\n            \"version\":function(obj){\n                var version = \"6,0,21\";\n                try{\n                    obj.AllowScriptAccess = \"always\";\n                    version = getActiveXVersion(obj);\n                }catch(err){}\n                return version;\n            }\n        },\n        {\n            \"name\":\"ShockwaveFlash.ShockwaveFlash\",\n            \"version\":function(obj){\n                return getActiveXVersion(obj);\n            }\n        }\n    ];\n    /**\n     * Extract the ActiveX version of the plugin.\n     *\n     * @param {Object} The flash ActiveX object.\n     * @type String\n     */\n    var getActiveXVersion = function(activeXObj){\n        var version = -1;\n        try{\n            version = activeXObj.GetVariable(\"$version\");\n        }catch(err){}\n        return version;\n    };\n    /**\n     * Try and retrieve an ActiveX object having a specified name.\n     *\n     * @param {String} name The ActiveX object name lookup.\n     * @return One of ActiveX object or a simple object having an attribute of activeXError with a value of true.\n     * @type Object\n     */\n    var getActiveXObject = function(name){\n        var obj = -1;\n        try{\n            obj = new ActiveXObject(name);\n        }catch(err){\n            obj = {activeXError:true};\n        }\n        return obj;\n    };\n    /**\n     * Parse an ActiveX $version string into an object.\n     *\n     * @param {String} str The ActiveX Object GetVariable($version) return value.\n     * @return An object having raw, major, minor, revision and revisionStr attributes.\n     * @type Object\n     */\n    var parseActiveXVersion = function(str){\n        var versionArray = str.split(\",\");//replace with regex\n        return {\n            \"raw\":str,\n            \"major\":parseInt(versionArray[0].split(\" \")[1], 10),\n            \"minor\":parseInt(versionArray[1], 10),\n            \"revision\":parseInt(versionArray[2], 10),\n            \"revisionStr\":versionArray[2]\n        };\n    };\n    /**\n     * Parse a standard enabledPlugin.description into an object.\n     *\n     * @param {String} str The enabledPlugin.description value.\n     * @return An object having raw, major, minor, revision and revisionStr attributes.\n     * @type Object\n     */\n    var parseStandardVersion = function(str){\n        var descParts = str.split(/ +/);\n        var majorMinor = descParts[2].split(/\\./);\n        var revisionStr = descParts[3];\n        return {\n            \"raw\":str,\n            \"major\":parseInt(majorMinor[0], 10),\n            \"minor\":parseInt(majorMinor[1], 10),\n            \"revisionStr\":revisionStr,\n            \"revision\":parseRevisionStrToInt(revisionStr)\n        };\n    };\n    /**\n     * Parse the plugin revision string into an integer.\n     *\n     * @param {String} The revision in string format.\n     * @type Number\n     */\n    var parseRevisionStrToInt = function(str){\n        return parseInt(str.replace(/[a-zA-Z]/g, \"\"), 10) || self.revision;\n    };\n    /**\n     * Is the major version greater than or equal to a specified version.\n     *\n     * @param {Number} version The minimum required major version.\n     * @type Boolean\n     */\n    self.majorAtLeast = function(version){\n        return self.major >= version;\n    };\n    /**\n     * Is the minor version greater than or equal to a specified version.\n     *\n     * @param {Number} version The minimum required minor version.\n     * @type Boolean\n     */\n    self.minorAtLeast = function(version){\n        return self.minor >= version;\n    };\n    /**\n     * Is the revision version greater than or equal to a specified version.\n     *\n     * @param {Number} version The minimum required revision version.\n     * @type Boolean\n     */\n    self.revisionAtLeast = function(version){\n        return self.revision >= version;\n    };\n    /**\n     * Is the version greater than or equal to a specified major, minor and revision.\n     *\n     * @param {Number} major The minimum required major version.\n     * @param {Number} (Optional) minor The minimum required minor version.\n     * @param {Number} (Optional) revision The minimum required revision version.\n     * @type Boolean\n     */\n    self.versionAtLeast = function(major){\n        var properties = [self.major, self.minor, self.revision];\n        var len = Math.min(properties.length, arguments.length);\n        for(i=0; i<len; i++){\n            if(properties[i]>=arguments[i]){\n                if(i+1<len && properties[i]==arguments[i]){\n                    continue;\n                }else{\n                    return true;\n                }\n            }else{\n                return false;\n            }\n        }\n    };\n    /**\n     * Constructor, sets raw, major, minor, revisionStr, revision and installed public properties.\n     */\n    self.FlashDetect = function(){\n        if(navigator.plugins && navigator.plugins.length>0){\n            var type = 'application/x-shockwave-flash';\n            var mimeTypes = navigator.mimeTypes;\n            if(mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin && mimeTypes[type].enabledPlugin.description){\n                var version = mimeTypes[type].enabledPlugin.description;\n                var versionObj = parseStandardVersion(version);\n                self.raw = versionObj.raw;\n                self.major = versionObj.major;\n                self.minor = versionObj.minor;\n                self.revisionStr = versionObj.revisionStr;\n                self.revision = versionObj.revision;\n                self.installed = true;\n            }\n        }else if(navigator.appVersion.indexOf(\"Mac\")==-1 && window.execScript){\n            var version = -1;\n            for(var i=0; i<activeXDetectRules.length && version==-1; i++){\n                var obj = getActiveXObject(activeXDetectRules[i].name);\n                if(!obj.activeXError){\n                    self.installed = true;\n                    version = activeXDetectRules[i].version(obj);\n                    if(version!=-1){\n                        var versionObj = parseActiveXVersion(version);\n                        self.raw = versionObj.raw;\n                        self.major = versionObj.major;\n                        self.minor = versionObj.minor;\n                        self.revision = versionObj.revision;\n                        self.revisionStr = versionObj.revisionStr;\n                    }\n                }\n            }\n        }\n    }();\n};\nFlashDetect.JS_RELEASE = \"1.0.4\";\nwindow['FlashDetect'] = FlashDetect;"
  },
  {
    "path": "src/libs/gradient/colorpicker.js",
    "content": "/**\n *\n * Color picker\n * Author: Stefan Petre www.eyecon.ro\n * \n * Dual licensed under the MIT and GPL licenses\n * \n */\n(function ($) {\n\tvar ColorPicker = function () {\n\t\tvar\n\t\t\tids = {},\n\t\t\tinAction,\n\t\t\tcharMin = 65,\n\t\t\tvisible,\n\t\t\ttpl = '<div class=\"colorpicker\"><div class=\"colorpicker_color\"><div><div></div></div></div><div class=\"colorpicker_hue\"><div></div></div><div class=\"colorpicker_new_color\"></div><div class=\"colorpicker_current_color\"></div><div class=\"colorpicker_hex\"><input type=\"text\" maxlength=\"6\" size=\"6\" /></div><div class=\"colorpicker_rgb_r colorpicker_field\"><input type=\"text\" maxlength=\"3\" size=\"3\" /><span></span></div><div class=\"colorpicker_rgb_g colorpicker_field\"><input type=\"text\" maxlength=\"3\" size=\"3\" /><span></span></div><div class=\"colorpicker_rgb_b colorpicker_field\"><input type=\"text\" maxlength=\"3\" size=\"3\" /><span></span></div><div class=\"colorpicker_hsb_h colorpicker_field\"><input type=\"text\" maxlength=\"3\" size=\"3\" /><span></span></div><div class=\"colorpicker_hsb_s colorpicker_field\"><input type=\"text\" maxlength=\"3\" size=\"3\" /><span></span></div><div class=\"colorpicker_hsb_b colorpicker_field\"><input type=\"text\" maxlength=\"3\" size=\"3\" /><span></span></div><div class=\"colorpicker_submit\"></div></div>',\n\t\t\tdefaults = {\n\t\t\t\teventName: 'click',\n\t\t\t\tonShow: function () {},\n\t\t\t\tonBeforeShow: function(){},\n\t\t\t\tonHide: function () {},\n\t\t\t\tonChange: function () {},\n\t\t\t\tonSubmit: function () {},\n\t\t\t\tcolor: 'ff0000',\n\t\t\t\tlivePreview: true,\n\t\t\t\tflat: false\n\t\t\t},\n\t\t\tfillRGBFields = function  (hsb, cal) {\n\t\t\t\tvar rgb = HSBToRGB(hsb);\n\t\t\t\t$(cal).data('colorpicker').fields\n\t\t\t\t\t.eq(1).val(rgb.r).end()\n\t\t\t\t\t.eq(2).val(rgb.g).end()\n\t\t\t\t\t.eq(3).val(rgb.b).end();\n\t\t\t},\n\t\t\tfillHSBFields = function  (hsb, cal) {\n\t\t\t\t$(cal).data('colorpicker').fields\n\t\t\t\t\t.eq(4).val(hsb.h).end()\n\t\t\t\t\t.eq(5).val(hsb.s).end()\n\t\t\t\t\t.eq(6).val(hsb.b).end();\n\t\t\t},\n\t\t\tfillHexFields = function (hsb, cal) {\n\t\t\t\t$(cal).data('colorpicker').fields\n\t\t\t\t\t.eq(0).val(HSBToHex(hsb)).end();\n\t\t\t},\n\t\t\tsetSelector = function (hsb, cal) {\n\t\t\t\t$(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));\n\t\t\t\t$(cal).data('colorpicker').selectorIndic.css({\n\t\t\t\t\tleft: parseInt(150 * hsb.s/100, 10),\n\t\t\t\t\ttop: parseInt(150 * (100-hsb.b)/100, 10)\n\t\t\t\t});\n\t\t\t},\n\t\t\tsetHue = function (hsb, cal) {\n\t\t\t\t$(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));\n\t\t\t},\n\t\t\tsetCurrentColor = function (hsb, cal) {\n\t\t\t\t$(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));\n\t\t\t},\n\t\t\tsetNewColor = function (hsb, cal) {\n\t\t\t\t$(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));\n\t\t\t},\n\t\t\tkeyDown = function (ev) {\n\t\t\t\tvar pressedKey = ev.charCode || ev.keyCode || -1;\n\t\t\t\tif ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tvar cal = $(this).parent().parent();\n\t\t\t\tif (cal.data('colorpicker').livePreview === true) {\n\t\t\t\t\tchange.apply(this);\n\t\t\t\t}\n\t\t\t},\n\t\t\tchange = function (ev) {\n\t\t\t\tvar cal = $(this).parent().parent(), col;\n\t\t\t\tif (this.parentNode.className.indexOf('_hex') > 0) {\n\t\t\t\t\tcal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));\n\t\t\t\t} else if (this.parentNode.className.indexOf('_hsb') > 0) {\n\t\t\t\t\tcal.data('colorpicker').color = col = fixHSB({\n\t\t\t\t\t\th: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),\n\t\t\t\t\t\ts: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),\n\t\t\t\t\t\tb: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tcal.data('colorpicker').color = col = RGBToHSB(fixRGB({\n\t\t\t\t\t\tr: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),\n\t\t\t\t\t\tg: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),\n\t\t\t\t\t\tb: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tif (ev) {\n\t\t\t\t\tfillRGBFields(col, cal.get(0));\n\t\t\t\t\tfillHexFields(col, cal.get(0));\n\t\t\t\t\tfillHSBFields(col, cal.get(0));\n\t\t\t\t}\n\t\t\t\tsetSelector(col, cal.get(0));\n\t\t\t\tsetHue(col, cal.get(0));\n\t\t\t\tsetNewColor(col, cal.get(0));\n\t\t\t\tcal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);\n\t\t\t},\n\t\t\tblur = function (ev) {\n\t\t\t\tvar cal = $(this).parent().parent();\n\t\t\t\tcal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');\n\t\t\t},\n\t\t\tfocus = function () {\n\t\t\t\tcharMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;\n\t\t\t\t$(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');\n\t\t\t\t$(this).parent().addClass('colorpicker_focus');\n\t\t\t},\n\t\t\tdownIncrement = function (ev) {\n\t\t\t\tvar field = $(this).parent().find('input').focus();\n\t\t\t\tvar current = {\n\t\t\t\t\tel: $(this).parent().addClass('colorpicker_slider'),\n\t\t\t\t\tmax: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),\n\t\t\t\t\ty: ev.pageY,\n\t\t\t\t\tfield: field,\n\t\t\t\t\tval: parseInt(field.val(), 10),\n\t\t\t\t\tpreview: $(this).parent().parent().data('colorpicker').livePreview\t\t\t\t\t\n\t\t\t\t};\n\t\t\t\t$(document).bind('mouseup', current, upIncrement);\n\t\t\t\t$(document).bind('mousemove', current, moveIncrement);\n\t\t\t},\n\t\t\tmoveIncrement = function (ev) {\n\t\t\t\tev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));\n\t\t\t\tif (ev.data.preview) {\n\t\t\t\t\tchange.apply(ev.data.field.get(0), [true]);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tupIncrement = function (ev) {\n\t\t\t\tchange.apply(ev.data.field.get(0), [true]);\n\t\t\t\tev.data.el.removeClass('colorpicker_slider').find('input').focus();\n\t\t\t\t$(document).unbind('mouseup', upIncrement);\n\t\t\t\t$(document).unbind('mousemove', moveIncrement);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tdownHue = function (ev) {\n\t\t\t\tvar current = {\n\t\t\t\t\tcal: $(this).parent(),\n\t\t\t\t\ty: $(this).offset().top\n\t\t\t\t};\n\t\t\t\tcurrent.preview = current.cal.data('colorpicker').livePreview;\n\t\t\t\t$(document).bind('mouseup', current, upHue);\n\t\t\t\t$(document).bind('mousemove', current, moveHue);\n\t\t\t},\n\t\t\tmoveHue = function (ev) {\n\t\t\t\tchange.apply(\n\t\t\t\t\tev.data.cal.data('colorpicker')\n\t\t\t\t\t\t.fields\n\t\t\t\t\t\t.eq(4)\n\t\t\t\t\t\t.val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))\n\t\t\t\t\t\t.get(0),\n\t\t\t\t\t[ev.data.preview]\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tupHue = function (ev) {\n\t\t\t\tfillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\n\t\t\t\tfillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\n\t\t\t\t$(document).unbind('mouseup', upHue);\n\t\t\t\t$(document).unbind('mousemove', moveHue);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tdownSelector = function (ev) {\n\t\t\t\tvar current = {\n\t\t\t\t\tcal: $(this).parent(),\n\t\t\t\t\tpos: $(this).offset()\n\t\t\t\t};\n\t\t\t\tcurrent.preview = current.cal.data('colorpicker').livePreview;\n\t\t\t\t$(document).bind('mouseup', current, upSelector);\n\t\t\t\t$(document).bind('mousemove', current, moveSelector);\n\t\t\t},\n\t\t\tmoveSelector = function (ev) {\n\t\t\t\tchange.apply(\n\t\t\t\t\tev.data.cal.data('colorpicker')\n\t\t\t\t\t\t.fields\n\t\t\t\t\t\t.eq(6)\n\t\t\t\t\t\t.val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))\n\t\t\t\t\t\t.end()\n\t\t\t\t\t\t.eq(5)\n\t\t\t\t\t\t.val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))\n\t\t\t\t\t\t.get(0),\n\t\t\t\t\t[ev.data.preview]\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tupSelector = function (ev) {\n\t\t\t\tfillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\n\t\t\t\tfillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\n\t\t\t\t$(document).unbind('mouseup', upSelector);\n\t\t\t\t$(document).unbind('mousemove', moveSelector);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tenterSubmit = function (ev) {\n\t\t\t\t$(this).addClass('colorpicker_focus');\n\t\t\t},\n\t\t\tleaveSubmit = function (ev) {\n\t\t\t\t$(this).removeClass('colorpicker_focus');\n\t\t\t},\n\t\t\tclickSubmit = function (ev) {\n\t\t\t\tvar cal = $(this).parent();\n\t\t\t\tvar col = cal.data('colorpicker').color;\n\t\t\t\tcal.data('colorpicker').origColor = col;\n\t\t\t\tsetCurrentColor(col, cal.get(0));\n\t\t\t\tcal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);\n\t\t\t},\n\t\t\tshow = function (ev) {\n\t\t\t\tvar cal = $('#' + $(this).data('colorpickerId'));\n\t\t\t\tcal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);\n\t\t\t\tvar pos = $(this).offset();\n\t\t\t\tvar viewPort = getViewport();\n\t\t\t\tvar top = pos.top + this.offsetHeight;\n\t\t\t\tvar left = pos.left;\n\t\t\t\tif (top + 176 > viewPort.t + viewPort.h) {\n\t\t\t\t\ttop -= this.offsetHeight + 176;\n\t\t\t\t}\n\t\t\t\tif (left + 356 > viewPort.l + viewPort.w) {\n\t\t\t\t\tleft -= 356;\n\t\t\t\t}\n\t\t\t\tcal.css({left: left + 'px', top: top + 'px'});\n\t\t\t\tif (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {\n\t\t\t\t\tcal.show();\n\t\t\t\t}\n\t\t\t\t$(document).bind('mousedown', {cal: cal}, hide);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\thide = function (ev) {\n\t\t\t\tif (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {\n\t\t\t\t\tif (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {\n\t\t\t\t\t\tev.data.cal.hide();\n\t\t\t\t\t}\n\t\t\t\t\t$(document).unbind('mousedown', hide);\n\t\t\t\t}\n\t\t\t},\n\t\t\tisChildOf = function(parentEl, el, container) {\n\t\t\t\tif (parentEl == el) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (parentEl.contains) {\n\t\t\t\t\treturn parentEl.contains(el);\n\t\t\t\t}\n\t\t\t\tif ( parentEl.compareDocumentPosition ) {\n\t\t\t\t\treturn !!(parentEl.compareDocumentPosition(el) & 16);\n\t\t\t\t}\n\t\t\t\tvar prEl = el.parentNode;\n\t\t\t\twhile(prEl && prEl != container) {\n\t\t\t\t\tif (prEl == parentEl)\n\t\t\t\t\t\treturn true;\n\t\t\t\t\tprEl = prEl.parentNode;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tgetViewport = function () {\n\t\t\t\tvar m = document.compatMode == 'CSS1Compat';\n\t\t\t\treturn {\n\t\t\t\t\tl : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),\n\t\t\t\t\tt : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),\n\t\t\t\t\tw : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),\n\t\t\t\t\th : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)\n\t\t\t\t};\n\t\t\t},\n\t\t\tfixHSB = function (hsb) {\n\t\t\t\treturn {\n\t\t\t\t\th: Math.min(360, Math.max(0, hsb.h)),\n\t\t\t\t\ts: Math.min(100, Math.max(0, hsb.s)),\n\t\t\t\t\tb: Math.min(100, Math.max(0, hsb.b))\n\t\t\t\t};\n\t\t\t}, \n\t\t\tfixRGB = function (rgb) {\n\t\t\t\treturn {\n\t\t\t\t\tr: Math.min(255, Math.max(0, rgb.r)),\n\t\t\t\t\tg: Math.min(255, Math.max(0, rgb.g)),\n\t\t\t\t\tb: Math.min(255, Math.max(0, rgb.b))\n\t\t\t\t};\n\t\t\t},\n\t\t\tfixHex = function (hex) {\n\t\t\t\tvar len = 6 - hex.length;\n\t\t\t\tif (len > 0) {\n\t\t\t\t\tvar o = [];\n\t\t\t\t\tfor (var i=0; i<len; i++) {\n\t\t\t\t\t\to.push('0');\n\t\t\t\t\t}\n\t\t\t\t\to.push(hex);\n\t\t\t\t\thex = o.join('');\n\t\t\t\t}\n\t\t\t\treturn hex;\n\t\t\t}, \n\t\t\tHexToRGB = function (hex) {\n\t\t\t\tvar hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);\n\t\t\t\treturn {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};\n\t\t\t},\n\t\t\tHexToHSB = function (hex) {\n\t\t\t\treturn RGBToHSB(HexToRGB(hex));\n\t\t\t},\n\t\t\tRGBToHSB = function (rgb) {\n\t\t\t\tvar hsb = {\n\t\t\t\t\th: 0,\n\t\t\t\t\ts: 0,\n\t\t\t\t\tb: 0\n\t\t\t\t};\n\t\t\t\tvar min = Math.min(rgb.r, rgb.g, rgb.b);\n\t\t\t\tvar max = Math.max(rgb.r, rgb.g, rgb.b);\n\t\t\t\tvar delta = max - min;\n\t\t\t\thsb.b = max;\n\t\t\t\tif (max != 0) {\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\thsb.s = max != 0 ? 255 * delta / max : 0;\n\t\t\t\tif (hsb.s != 0) {\n\t\t\t\t\tif (rgb.r == max) {\n\t\t\t\t\t\thsb.h = (rgb.g - rgb.b) / delta;\n\t\t\t\t\t} else if (rgb.g == max) {\n\t\t\t\t\t\thsb.h = 2 + (rgb.b - rgb.r) / delta;\n\t\t\t\t\t} else {\n\t\t\t\t\t\thsb.h = 4 + (rgb.r - rgb.g) / delta;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\thsb.h = -1;\n\t\t\t\t}\n\t\t\t\thsb.h *= 60;\n\t\t\t\tif (hsb.h < 0) {\n\t\t\t\t\thsb.h += 360;\n\t\t\t\t}\n\t\t\t\thsb.s *= 100/255;\n\t\t\t\thsb.b *= 100/255;\n\t\t\t\treturn hsb;\n\t\t\t},\n\t\t\tHSBToRGB = function (hsb) {\n\t\t\t\tvar rgb = {};\n\t\t\t\tvar h = Math.round(hsb.h);\n\t\t\t\tvar s = Math.round(hsb.s*255/100);\n\t\t\t\tvar v = Math.round(hsb.b*255/100);\n\t\t\t\tif(s == 0) {\n\t\t\t\t\trgb.r = rgb.g = rgb.b = v;\n\t\t\t\t} else {\n\t\t\t\t\tvar t1 = v;\n\t\t\t\t\tvar t2 = (255-s)*v/255;\n\t\t\t\t\tvar t3 = (t1-t2)*(h%60)/60;\n\t\t\t\t\tif(h==360) h = 0;\n\t\t\t\t\tif(h<60) {rgb.r=t1;\trgb.b=t2; rgb.g=t2+t3}\n\t\t\t\t\telse if(h<120) {rgb.g=t1; rgb.b=t2;\trgb.r=t1-t3}\n\t\t\t\t\telse if(h<180) {rgb.g=t1; rgb.r=t2;\trgb.b=t2+t3}\n\t\t\t\t\telse if(h<240) {rgb.b=t1; rgb.r=t2;\trgb.g=t1-t3}\n\t\t\t\t\telse if(h<300) {rgb.b=t1; rgb.g=t2;\trgb.r=t2+t3}\n\t\t\t\t\telse if(h<360) {rgb.r=t1; rgb.g=t2;\trgb.b=t1-t3}\n\t\t\t\t\telse {rgb.r=0; rgb.g=0;\trgb.b=0}\n\t\t\t\t}\n\t\t\t\treturn {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};\n\t\t\t},\n\t\t\tRGBToHex = function (rgb) {\n\t\t\t\tvar hex = [\n\t\t\t\t\trgb.r.toString(16),\n\t\t\t\t\trgb.g.toString(16),\n\t\t\t\t\trgb.b.toString(16)\n\t\t\t\t];\n\t\t\t\t$.each(hex, function (nr, val) {\n\t\t\t\t\tif (val.length == 1) {\n\t\t\t\t\t\thex[nr] = '0' + val;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn hex.join('');\n\t\t\t},\n\t\t\tHSBToHex = function (hsb) {\n\t\t\t\treturn RGBToHex(HSBToRGB(hsb));\n\t\t\t},\n\t\t\trestoreOriginal = function () {\n\t\t\t\tvar cal = $(this).parent();\n\t\t\t\tvar col = cal.data('colorpicker').origColor;\n\t\t\t\tcal.data('colorpicker').color = col;\n\t\t\t\tfillRGBFields(col, cal.get(0));\n\t\t\t\tfillHexFields(col, cal.get(0));\n\t\t\t\tfillHSBFields(col, cal.get(0));\n\t\t\t\tsetSelector(col, cal.get(0));\n\t\t\t\tsetHue(col, cal.get(0));\n\t\t\t\tsetNewColor(col, cal.get(0));\n\t\t\t};\n\t\treturn {\n\t\t\tinit: function (opt) {\n\t\t\t\topt = $.extend({}, defaults, opt||{});\n\t\t\t\tif (typeof opt.color == 'string') {\n\t\t\t\t\topt.color = HexToHSB(opt.color);\n\t\t\t\t} else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {\n\t\t\t\t\topt.color = RGBToHSB(opt.color);\n\t\t\t\t} else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {\n\t\t\t\t\topt.color = fixHSB(opt.color);\n\t\t\t\t} else {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\treturn this.each(function () {\n\t\t\t\t\tif (!$(this).data('colorpickerId')) {\n\t\t\t\t\t\tvar options = $.extend({}, opt);\n\t\t\t\t\t\toptions.origColor = opt.color;\n\t\t\t\t\t\tvar id = 'collorpicker_' + parseInt(Math.random() * 1000);\n\t\t\t\t\t\t$(this).data('colorpickerId', id);\n\t\t\t\t\t\tvar cal = $(tpl).attr('id', id);\n\t\t\t\t\t\tif (options.flat) {\n\t\t\t\t\t\t\tcal.appendTo(this).show();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcal.appendTo(document.body);\n\t\t\t\t\t\t}\n\t\t\t\t\t\toptions.fields = cal\n\t\t\t\t\t\t\t\t\t\t\t.find('input')\n\t\t\t\t\t\t\t\t\t\t\t\t.bind('keyup', keyDown)\n\t\t\t\t\t\t\t\t\t\t\t\t.bind('change', change)\n\t\t\t\t\t\t\t\t\t\t\t\t.bind('blur', blur)\n\t\t\t\t\t\t\t\t\t\t\t\t.bind('focus', focus);\n\t\t\t\t\t\tcal\n\t\t\t\t\t\t\t.find('span').bind('mousedown', downIncrement).end()\n\t\t\t\t\t\t\t.find('>div.colorpicker_current_color').bind('click', restoreOriginal);\n\t\t\t\t\t\toptions.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);\n\t\t\t\t\t\toptions.selectorIndic = options.selector.find('div div');\n\t\t\t\t\t\toptions.el = this;\n\t\t\t\t\t\toptions.hue = cal.find('div.colorpicker_hue div');\n\t\t\t\t\t\tcal.find('div.colorpicker_hue').bind('mousedown', downHue);\n\t\t\t\t\t\toptions.newColor = cal.find('div.colorpicker_new_color');\n\t\t\t\t\t\toptions.currentColor = cal.find('div.colorpicker_current_color');\n\t\t\t\t\t\tcal.data('colorpicker', options);\n\t\t\t\t\t\tcal.find('div.colorpicker_submit')\n\t\t\t\t\t\t\t.bind('mouseenter', enterSubmit)\n\t\t\t\t\t\t\t.bind('mouseleave', leaveSubmit)\n\t\t\t\t\t\t\t.bind('click', clickSubmit);\n\t\t\t\t\t\tfillRGBFields(options.color, cal.get(0));\n\t\t\t\t\t\tfillHSBFields(options.color, cal.get(0));\n\t\t\t\t\t\tfillHexFields(options.color, cal.get(0));\n\t\t\t\t\t\tsetHue(options.color, cal.get(0));\n\t\t\t\t\t\tsetSelector(options.color, cal.get(0));\n\t\t\t\t\t\tsetCurrentColor(options.color, cal.get(0));\n\t\t\t\t\t\tsetNewColor(options.color, cal.get(0));\n\t\t\t\t\t\tif (options.flat) {\n\t\t\t\t\t\t\tcal.css({\n\t\t\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\t\t\tdisplay: 'block'\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$(this).bind(options.eventName, show);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\tshowPicker: function() {\n\t\t\t\treturn this.each( function () {\n\t\t\t\t\tif ($(this).data('colorpickerId')) {\n\t\t\t\t\t\tshow.apply(this);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\thidePicker: function() {\n\t\t\t\treturn this.each( function () {\n\t\t\t\t\tif ($(this).data('colorpickerId')) {\n\t\t\t\t\t\t$('#' + $(this).data('colorpickerId')).hide();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\tsetColor: function(col) {\n\t\t\t\tif (typeof col == 'string') {\n\t\t\t\t\tcol = HexToHSB(col);\n\t\t\t\t} else if (col.r != undefined && col.g != undefined && col.b != undefined) {\n\t\t\t\t\tcol = RGBToHSB(col);\n\t\t\t\t} else if (col.h != undefined && col.s != undefined && col.b != undefined) {\n\t\t\t\t\tcol = fixHSB(col);\n\t\t\t\t} else {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\treturn this.each(function(){\n\t\t\t\t\tif ($(this).data('colorpickerId')) {\n\t\t\t\t\t\tvar cal = $('#' + $(this).data('colorpickerId'));\n\t\t\t\t\t\tcal.data('colorpicker').color = col;\n\t\t\t\t\t\tcal.data('colorpicker').origColor = col;\n\t\t\t\t\t\tfillRGBFields(col, cal.get(0));\n\t\t\t\t\t\tfillHSBFields(col, cal.get(0));\n\t\t\t\t\t\tfillHexFields(col, cal.get(0));\n\t\t\t\t\t\tsetHue(col, cal.get(0));\n\t\t\t\t\t\tsetSelector(col, cal.get(0));\n\t\t\t\t\t\tsetCurrentColor(col, cal.get(0));\n\t\t\t\t\t\tsetNewColor(col, cal.get(0));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t}();\n\t$.fn.extend({\n\t\tColorPicker: ColorPicker.init,\n\t\tColorPickerHide: ColorPicker.hidePicker,\n\t\tColorPickerShow: ColorPicker.showPicker,\n\t\tColorPickerSetColor: ColorPicker.setColor\n\t});\n})(jQuery)"
  },
  {
    "path": "src/libs/gradient/jquery.gradientpicker.js",
    "content": "/**\n @author Matt Crinklaw-Vogt (tantaman)\n https://github.com/tantaman/jquery-gradient-picker\n */\n\n(function ($) {\n    if (!$.event.special.destroyed) {\n        $.event.special.destroyed = {\n            remove: function (o) {\n                if (o.handler) {\n                    o.handler();\n                }\n            }\n        }\n    }\n\n    function ctrlPtComparator(l, r) {\n        return l.position - r.position;\n    }\n\n    function bind(fn, ctx) {\n        if (typeof fn.bind === \"function\") {\n            return fn.bind(ctx);\n        } else {\n            return function () {\n                fn.apply(ctx, arguments);\n            }\n        }\n    }\n\n    var browserPrefix = \"\";\n    var agent = window.navigator.userAgent;\n    if (agent.indexOf('WebKit') >= 0)\n        browserPrefix = \"-webkit-\"\n    else if (agent.indexOf('Mozilla') >= 0)\n        browserPrefix = \"-moz-\"\n    else if (agent.indexOf('Microsoft') >= 0)\n        browserPrefix = \"-ms-\"\n    else\n        browserPrefix = \"\"\n\n    function GradientSelection($el, opts) {\n        this.$el = $el;\n        this.$el.css(\"position\", \"relative\");\n        this.opts = opts;\n\n        var $preview = $(\"<canvas class='gradientPicker-preview'></canvas>\");\n        this.$el.append($preview);\n        var canvas = $preview[0];\n        $preview.css({\n            width: $preview.parent().width(),\n            height: $preview.parent().height()\n        });\n        // canvas.width = canvas.clientWidth;\n        // canvas.height = canvas.clientHeight;\n        this.g2d = canvas.getContext(\"2d\");\n\n        var $ctrlPtContainer = $(\"<div class='gradientPicker-ctrlPts'></div>\");\n        this.$el.append($ctrlPtContainer)\n        this.$ctrlPtContainer = $ctrlPtContainer;\n\n        this.updatePreview = bind(this.updatePreview, this);\n        this.controlPoints = [];\n        this.ctrlPtConfig = new ControlPtConfig(this.$el, opts);\n        for (var i = 0; i < opts.controlPoints.length; ++i) {\n            var ctrlPt = this.createCtrlPt(opts.controlPoints[i]);\n            this.controlPoints.push(ctrlPt);\n        }\n\n        this.docClicked = bind(this.docClicked, this);\n        this.destroyed = bind(this.destroyed, this);\n        $(document).bind(\"click\", this.docClicked);\n        this.$el.bind(\"destroyed\", this.destroyed);\n        this.previewClicked = bind(this.previewClicked, this);\n        $preview.click(this.previewClicked);\n\n        this.updatePreview();\n    }\n\n    GradientSelection.prototype = {\n        docClicked: function () {\n            this.ctrlPtConfig.hide();\n        },\n\n        createCtrlPt: function (ctrlPtSetup) {\n            return new ControlPoint(this.$ctrlPtContainer, ctrlPtSetup, this.opts.orientation, this, this.ctrlPtConfig)\n        },\n\n        destroyed: function () {\n            $(document).unbind(\"click\", this.docClicked);\n        },\n\n        updateOptions: function (opts) {\n            $.extend(this.opts, opts);\n            this.updatePreview();\n        },\n\n        colorToHex: function (color) {\n            if (color.match('#')) {\n                return color;\n            }\n            if (color.match('rgb')) {\n                return '#' + this.rgbToHex(color);\n            }\n            return '#' + color;\n        },\n\n        rgbToHex: function (rgb) {\n            function componentFromStr(numStr, percent) {\n                var num = Math.max(0, parseInt(numStr, 10));\n                return percent ?\n                    Math.floor(255 * Math.min(100, num) / 100) : Math.min(255, num);\n            }\n\n            var rgbRegex = /^rgb\\(\\s*(-?\\d+)(%?)\\s*,\\s*(-?\\d+)(%?)\\s*,\\s*(-?\\d+)(%?)\\s*\\)$/;\n            var result, r, g, b, hex = \"\";\n            if ((result = rgbRegex.exec(rgb))) {\n                r = componentFromStr(result[1], result[2]);\n                g = componentFromStr(result[3], result[4]);\n                b = componentFromStr(result[5], result[6]);\n                hex = (0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1);\n            }\n            return hex;\n        },\n\n        updatePreview: function (quiet) {\n            var result = [];\n            this.controlPoints.sort(ctrlPtComparator);\n            if (this.opts.orientation == \"horizontal\") {\n                var grad = this.g2d.createLinearGradient(0, 0, this.g2d.canvas.width, 0);\n                for (var i = 0; i < this.controlPoints.length; ++i) {\n                    var pt = this.controlPoints[i];\n                    pt.color = this.colorToHex(pt.color);\n                    grad.addColorStop(pt.position, pt.color);\n                    result.push({\n                        position: pt.position,\n                        color: pt.color\n                    });\n                }\n            }\n\n            this.g2d.fillStyle = grad;\n            this.g2d.fillRect(0, 0, this.g2d.canvas.width, this.g2d.canvas.height);\n\n            if (this.opts.generateStyles)\n                var styles = this._generatePreviewStyles();\n\n            if (quiet)\n                return;\n            this.opts.change(result, styles);\n            // this.opts.closed(result, styles);\n            return {\n                result: result,\n                styles: styles\n            }\n        },\n\n        removeControlPoint: function (ctrlPt) {\n            var cpidx = this.controlPoints.indexOf(ctrlPt);\n\n            if (cpidx != -1) {\n                this.controlPoints.splice(cpidx, 1);\n                ctrlPt.$el.remove();\n            }\n        },\n\n        clear: function () {\n            var context = this.g2d.canvas.getContext('2d');\n            context.clearRect(0, 0, this.g2d.canvas.width,this.g2d.canvas.height);\n        },\n\n        /** webNeat modifications starts here */\n        addPoint: function (percent, colorStr, quiet) {\n            colorStr = this.colorToHex(colorStr);\n            var cp = this.createCtrlPt({\n                position: percent,\n                color: colorStr\n            });\n\n            this.controlPoints.push(cp);\n            this.controlPoints.sort(ctrlPtComparator);\n            this.updatePreview(quiet);\n        },\n\n        // removeAllPointsAAAA: function () {\n        //     this.controlPoints.forEach(function (point) {\n        //         point.$el.remove();\n        //     });\n        //     this.controlPoints = [];\n        //     this.addPoint(0,'#fff');\n        //     this.addPoint(1,'#fff');\n        //     this.updatePreview();\n        //     this.controlPoints.forEach(function (point) {\n        //         point.$el.remove();\n        //     });\n        // },\n\n        removeAllPoints: function () {\n            this.controlPoints.forEach(function (point) {\n                point.$el.remove();\n                ;\n            });\n            this.controlPoints = [];\n            // this.addPoint(0,'#fff');\n            // this.addPoint(1,'#fff');\n\n            this.updatePreview();\n        },\n\n\n        changeFillDirection: function (fd) {\n            this.opts.fillDirection = fd;\n            this.updatePreview();\n        },\n        /** webNeat modifications ends here */\n\n        previewClicked: function (e) {\n            var offset = $(e.target).offset();\n            var x = e.pageX - offset.left;\n            var y = e.pageY - offset.top;\n\n            var imgData = this.g2d.getImageData(x, y, 1, 1);\n            var colorStr = \"rgb(\" + imgData.data[0] + \",\" + imgData.data[1] + \",\" + imgData.data[2] + \")\";\n\n            var cp = this.createCtrlPt({\n                position: x / this.g2d.canvas.width,\n                color: colorStr\n            });\n\n            this.controlPoints.push(cp);\n            this.controlPoints.sort(ctrlPtComparator);\n        },\n\n        getChanges: function () {\n            this.updatePreview();\n        },\n\n        _generatePreviewStyles: function () {\n            //linear-gradient(top, rgb(217,230,163) 86%, rgb(227,249,159) 9%)\n            var str = this.opts.type + \"-gradient(\" + ((this.opts.type == \"linear\") ? (this.opts.fillDirection + \", \") : \"\");\n            var first = true;\n            for (var i = 0; i < this.controlPoints.length; ++i) {\n                var pt = this.controlPoints[i];\n                if (!first) {\n                    str += \", \";\n                } else {\n                    first = false;\n                }\n                str += pt.color + \" \" + ((pt.position * 100) | 0) + \"%\";\n            }\n\n            str = str + \")\"\n            var styles = [str, browserPrefix + str];\n            return styles;\n        }\n    };\n\n    function hexToRgb(hex) {\n        var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n        return result ? {\n            r: parseInt(result[1], 16),\n            g: parseInt(result[2], 16),\n            b: parseInt(result[3], 16)\n        } : null;\n    }\n\n    function ControlPoint($parentEl, initialState, orientation, listener, ctrlPtConfig) {\n        this.$el = $(\"<div class='gradientPicker-ctrlPt'></div>\");\n        $parentEl.append(this.$el);\n        this.$parentEl = $parentEl;\n        this.configView = ctrlPtConfig;\n\n        if (typeof initialState === \"string\") {\n            initialState = initialState.split(\" \");\n            this.position = parseFloat(initialState[1]) / 100;\n            this.color = initialState[0];\n        } else {\n            this.position = initialState.position;\n            this.color = initialState.color;\n        }\n\n        this.listener = listener;\n        this.outerWidth = this.$el.outerWidth();\n\n        this.$el.css(\"background-color\", '#' + this.color);\n\n        /* if (this.color.match('rgb')){\n         console.log('rgb color ' + this.color);\n         this.$el.css(\"background-color\", this.color);\n         } else {\n         var rgbc = hexToRgb(this.color);\n         var rgbv = 'rgb(' + rgbc.r + ',' + rgbc.g + ',' + rgbc.b + ')';\n         this.$el.css(\"background-color\", rgbv);\n         }  */\n\n\n        if (orientation == \"horizontal\") {\n            var pxLeft = ($parentEl.width() - this.$el.outerWidth()) * (this.position);\n            this.$el.css(\"left\", pxLeft);\n        } else {\n            var pxTop = ($parentEl.height() - this.$el.outerHeight()) * (this.position);\n            this.$el.css(\"top\", pxTop);\n        }\n\n        this.drag = bind(this.drag, this);\n        this.stop = bind(this.stop, this);\n        this.clicked = bind(this.clicked, this);\n        this.colorChanged = bind(this.colorChanged, this);\n        this.colorClosed = bind(this.colorClosed, this);\n        this.$el.draggable({\n            axis: (orientation == \"horizontal\") ? \"x\" : \"y\",\n            drag: this.drag,\n            stop: this.stop,\n            containment: $parentEl\n        });\n        this.$el.css(\"position\", 'absolute');\n        this.$el.click(this.clicked);\n    }\n\n    ControlPoint.prototype = {\n        drag: function (e, ui) {\n            // convert position to a %\n            var left = ui.position.left;\n            this.position = (left / (this.$parentEl.width() - this.outerWidth));\n            this.listener.updatePreview();\n        },\n\n        stop: function (e, ui) {\n            this.listener.updatePreview();\n            this.configView.show(this.$el.position(), this.color, this);\n            this.colorClosed();\n        },\n\n        clicked: function (e) {\n            this.configView.show(this.$el.position(), this.color, this);\n            console.log(this.color);\n            e.stopPropagation();\n            return false;\n        },\n\n        colorClosed: function () {\n            this.listener.ctrlPtConfig.opts.closed();\n        },\n\n        colorChanged: function (c) {\n            this.color = c;\n            // log(c);\n            this.$el.css(\"background-color\", this.color);\n            this.listener.updatePreview();\n        },\n\n        removeClicked: function () {\n            this.listener.removeControlPoint(this);\n            this.listener.updatePreview();\n        }\n    };\n\n    function ControlPtConfig($parent, opts) {\n        //color-chooser\n        this.$el = $('<div class=\"gradientPicker-ptConfig\" style=\"visibility: hidden\"></div>');\n        $parent.append(this.$el);\n        var $cpicker = $('<div class=\"color-chooser\"></div>');\n        this.$el.append($cpicker);\n        var $rmEl = $(\"<div class='gradientPicker-close'></div>\");\n        this.$el.append($rmEl);\n\n        this.colorChanged = bind(this.colorChanged, this);\n        this.colorClosed = bind(this.colorClosed, this);\n        this.removeClicked = bind(this.removeClicked, this);\n        $cpicker.ColorPicker({\n            onChange: this.colorChanged,\n            onHide: this.colorClosed\n        });\n        this.$cpicker = $cpicker;\n        this.opts = opts;\n        this.visible = false;\n\n        $rmEl.click(this.removeClicked);\n    }\n\n    ControlPtConfig.prototype = {\n        show: function (position, color, listener) {\n            this.visible = true;\n            this.listener = listener;\n            this.$el.css(\"visibility\", \"visible\");\n            this.$cpicker.ColorPickerSetColor(color);\n            this.$cpicker.css(\"background-color\", '#' + color);\n            if (this.opts.orientation === \"horizontal\") {\n                this.$el.css(\"left\", position.left);\n            } else {\n                this.$el.css(\"top\", position.top);\n            }\n            //else {\n            //\tthis.visible = false;\n            //this.$el.css(\"visibility\", \"hidden\");\n            //}\n        },\n\n        hide: function () {\n            if (this.visible) {\n                this.$el.css(\"visibility\", \"hidden\");\n                this.visible = false;\n            }\n        },\n\n        /*colorClosed: function(hsb, hex, rgb) {\n         if (this.opts.closed){\n         var changes = this.listener.listener.updatePreview(false);\n         this.opts.closed(changes.result, changes.styles)\n         }\n         },*/\n\n        colorClosed: function (hsb, hex, rgb) {\n            if (this.opts.closed) {\n                this.opts.closed();\n            }\n        },\n        colorChanged: function (hsb, hex, rgb) {\n            hex = \"#\" + hex;\n            this.listener.colorChanged(hex);\n            this.$cpicker.css(\"background-color\", hex)\n        },\n\n        removeClicked: function () {\n            this.listener.removeClicked();\n            this.hide();\n        }\n    };\n\n    var methods = {\n        init: function (opts) {\n            opts = $.extend({\n                //controlPoints: [\"#FFF 0%\", \"#000 100%\"],\n                controlPoints: [],\n                orientation: \"horizontal\",\n                type: \"linear\",\n                fillDirection: \"left\",\n                generateStyles: true,\n                change: function () {\n                }\n            }, opts);\n\n            this.each(function () {\n                var $this = $(this);\n                var gradSel = new GradientSelection($this, opts);\n                $this.data(\"gradientPicker-sel\", gradSel);\n            });\n        },\n\n        update: function (opts) {\n            this.each(function () {\n                var $this = $(this);\n                var gradSel = $this.data(\"gradientPicker-sel\");\n                if (gradSel != null) {\n                    gradSel.updateOptions(opts);\n                }\n            });\n        }\n    };\n\n    $.fn.gradientPicker = function (method, opts) {\n        if (typeof method === \"string\" && method !== \"init\") {\n            methods[method].call(this, opts);\n        } else {\n            opts = method;\n            methods.init.call(this, opts);\n        }\n    };\n})(jQuery);"
  },
  {
    "path": "src/libs/jquery-ui.js",
    "content": "/*! jQuery UI - v1.10.1 - 2013-02-15\n* http://jqueryui.com\n* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js\n* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */\n\n(function( $, undefined ) {\n\nvar uuid = 0,\n\truniqueId = /^ui-id-\\d+$/;\n\n// prevent duplicate loading\n// this is only a problem because we proxy existing functions\n// and we don't want to double proxy them\n$.ui = $.ui || {};\nif ( $.ui.version ) {\n\treturn;\n}\n\n$.extend( $.ui, {\n\tversion: \"1.10.1\",\n\n\tkeyCode: {\n\t\tBACKSPACE: 8,\n\t\tCOMMA: 188,\n\t\tDELETE: 46,\n\t\tDOWN: 40,\n\t\tEND: 35,\n\t\tENTER: 13,\n\t\tESCAPE: 27,\n\t\tHOME: 36,\n\t\tLEFT: 37,\n\t\tNUMPAD_ADD: 107,\n\t\tNUMPAD_DECIMAL: 110,\n\t\tNUMPAD_DIVIDE: 111,\n\t\tNUMPAD_ENTER: 108,\n\t\tNUMPAD_MULTIPLY: 106,\n\t\tNUMPAD_SUBTRACT: 109,\n\t\tPAGE_DOWN: 34,\n\t\tPAGE_UP: 33,\n\t\tPERIOD: 190,\n\t\tRIGHT: 39,\n\t\tSPACE: 32,\n\t\tTAB: 9,\n\t\tUP: 38\n\t}\n});\n\n// plugins\n$.fn.extend({\n\t_focus: $.fn.focus,\n\tfocus: function( delay, fn ) {\n\t\treturn typeof delay === \"number\" ?\n\t\t\tthis.each(function() {\n\t\t\t\tvar elem = this;\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t$( elem ).focus();\n\t\t\t\t\tif ( fn ) {\n\t\t\t\t\t\tfn.call( elem );\n\t\t\t\t\t}\n\t\t\t\t}, delay );\n\t\t\t}) :\n\t\t\tthis._focus.apply( this, arguments );\n\t},\n\n\tscrollParent: function() {\n\t\tvar scrollParent;\n\t\tif (($.ui.ie && (/(static|relative)/).test(this.css(\"position\"))) || (/absolute/).test(this.css(\"position\"))) {\n\t\t\tscrollParent = this.parents().filter(function() {\n\t\t\t\treturn (/(relative|absolute|fixed)/).test($.css(this,\"position\")) && (/(auto|scroll)/).test($.css(this,\"overflow\")+$.css(this,\"overflow-y\")+$.css(this,\"overflow-x\"));\n\t\t\t}).eq(0);\n\t\t} else {\n\t\t\tscrollParent = this.parents().filter(function() {\n\t\t\t\treturn (/(auto|scroll)/).test($.css(this,\"overflow\")+$.css(this,\"overflow-y\")+$.css(this,\"overflow-x\"));\n\t\t\t}).eq(0);\n\t\t}\n\n\t\treturn (/fixed/).test(this.css(\"position\")) || !scrollParent.length ? $(document) : scrollParent;\n\t},\n\n\tzIndex: function( zIndex ) {\n\t\tif ( zIndex !== undefined ) {\n\t\t\treturn this.css( \"zIndex\", zIndex );\n\t\t}\n\n\t\tif ( this.length ) {\n\t\t\tvar elem = $( this[ 0 ] ), position, value;\n\t\t\twhile ( elem.length && elem[ 0 ] !== document ) {\n\t\t\t\t// Ignore z-index if position is set to a value where z-index is ignored by the browser\n\t\t\t\t// This makes behavior of this function consistent across browsers\n\t\t\t\t// WebKit always returns auto if the element is positioned\n\t\t\t\tposition = elem.css( \"position\" );\n\t\t\t\tif ( position === \"absolute\" || position === \"relative\" || position === \"fixed\" ) {\n\t\t\t\t\t// IE returns 0 when zIndex is not specified\n\t\t\t\t\t// other browsers return a string\n\t\t\t\t\t// we ignore the case of nested elements with an explicit value of 0\n\t\t\t\t\t// <div style=\"z-index: -10;\"><div style=\"z-index: 0;\"></div></div>\n\t\t\t\t\tvalue = parseInt( elem.css( \"zIndex\" ), 10 );\n\t\t\t\t\tif ( !isNaN( value ) && value !== 0 ) {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telem = elem.parent();\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t},\n\n\tuniqueId: function() {\n\t\treturn this.each(function() {\n\t\t\tif ( !this.id ) {\n\t\t\t\tthis.id = \"ui-id-\" + (++uuid);\n\t\t\t}\n\t\t});\n\t},\n\n\tremoveUniqueId: function() {\n\t\treturn this.each(function() {\n\t\t\tif ( runiqueId.test( this.id ) ) {\n\t\t\t\t$( this ).removeAttr( \"id\" );\n\t\t\t}\n\t\t});\n\t}\n});\n\n// selectors\nfunction focusable( element, isTabIndexNotNaN ) {\n\tvar map, mapName, img,\n\t\tnodeName = element.nodeName.toLowerCase();\n\tif ( \"area\" === nodeName ) {\n\t\tmap = element.parentNode;\n\t\tmapName = map.name;\n\t\tif ( !element.href || !mapName || map.nodeName.toLowerCase() !== \"map\" ) {\n\t\t\treturn false;\n\t\t}\n\t\timg = $( \"img[usemap=#\" + mapName + \"]\" )[0];\n\t\treturn !!img && visible( img );\n\t}\n\treturn ( /input|select|textarea|button|object/.test( nodeName ) ?\n\t\t!element.disabled :\n\t\t\"a\" === nodeName ?\n\t\t\telement.href || isTabIndexNotNaN :\n\t\t\tisTabIndexNotNaN) &&\n\t\t// the element and all of its ancestors must be visible\n\t\tvisible( element );\n}\n\nfunction visible( element ) {\n\treturn $.expr.filters.visible( element ) &&\n\t\t!$( element ).parents().addBack().filter(function() {\n\t\t\treturn $.css( this, \"visibility\" ) === \"hidden\";\n\t\t}).length;\n}\n\n$.extend( $.expr[ \":\" ], {\n\tdata: $.expr.createPseudo ?\n\t\t$.expr.createPseudo(function( dataName ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn !!$.data( elem, dataName );\n\t\t\t};\n\t\t}) :\n\t\t// support: jQuery <1.8\n\t\tfunction( elem, i, match ) {\n\t\t\treturn !!$.data( elem, match[ 3 ] );\n\t\t},\n\n\tfocusable: function( element ) {\n\t\treturn focusable( element, !isNaN( $.attr( element, \"tabindex\" ) ) );\n\t},\n\n\ttabbable: function( element ) {\n\t\tvar tabIndex = $.attr( element, \"tabindex\" ),\n\t\t\tisTabIndexNaN = isNaN( tabIndex );\n\t\treturn ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );\n\t}\n});\n\n// support: jQuery <1.8\nif ( !$( \"<a>\" ).outerWidth( 1 ).jquery ) {\n\t$.each( [ \"Width\", \"Height\" ], function( i, name ) {\n\t\tvar side = name === \"Width\" ? [ \"Left\", \"Right\" ] : [ \"Top\", \"Bottom\" ],\n\t\t\ttype = name.toLowerCase(),\n\t\t\torig = {\n\t\t\t\tinnerWidth: $.fn.innerWidth,\n\t\t\t\tinnerHeight: $.fn.innerHeight,\n\t\t\t\touterWidth: $.fn.outerWidth,\n\t\t\t\touterHeight: $.fn.outerHeight\n\t\t\t};\n\n\t\tfunction reduce( elem, size, border, margin ) {\n\t\t\t$.each( side, function() {\n\t\t\t\tsize -= parseFloat( $.css( elem, \"padding\" + this ) ) || 0;\n\t\t\t\tif ( border ) {\n\t\t\t\t\tsize -= parseFloat( $.css( elem, \"border\" + this + \"Width\" ) ) || 0;\n\t\t\t\t}\n\t\t\t\tif ( margin ) {\n\t\t\t\t\tsize -= parseFloat( $.css( elem, \"margin\" + this ) ) || 0;\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn size;\n\t\t}\n\n\t\t$.fn[ \"inner\" + name ] = function( size ) {\n\t\t\tif ( size === undefined ) {\n\t\t\t\treturn orig[ \"inner\" + name ].call( this );\n\t\t\t}\n\n\t\t\treturn this.each(function() {\n\t\t\t\t$( this ).css( type, reduce( this, size ) + \"px\" );\n\t\t\t});\n\t\t};\n\n\t\t$.fn[ \"outer\" + name] = function( size, margin ) {\n\t\t\tif ( typeof size !== \"number\" ) {\n\t\t\t\treturn orig[ \"outer\" + name ].call( this, size );\n\t\t\t}\n\n\t\t\treturn this.each(function() {\n\t\t\t\t$( this).css( type, reduce( this, size, true, margin ) + \"px\" );\n\t\t\t});\n\t\t};\n\t});\n}\n\n// support: jQuery <1.8\nif ( !$.fn.addBack ) {\n\t$.fn.addBack = function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t};\n}\n\n// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)\nif ( $( \"<a>\" ).data( \"a-b\", \"a\" ).removeData( \"a-b\" ).data( \"a-b\" ) ) {\n\t$.fn.removeData = (function( removeData ) {\n\t\treturn function( key ) {\n\t\t\tif ( arguments.length ) {\n\t\t\t\treturn removeData.call( this, $.camelCase( key ) );\n\t\t\t} else {\n\t\t\t\treturn removeData.call( this );\n\t\t\t}\n\t\t};\n\t})( $.fn.removeData );\n}\n\n\n\n\n\n// deprecated\n$.ui.ie = !!/msie [\\w.]+/.exec( navigator.userAgent.toLowerCase() );\n\n$.support.selectstart = \"onselectstart\" in document.createElement( \"div\" );\n$.fn.extend({\n\tdisableSelection: function() {\n\t\treturn this.bind( ( $.support.selectstart ? \"selectstart\" : \"mousedown\" ) +\n\t\t\t\".ui-disableSelection\", function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t});\n\t},\n\n\tenableSelection: function() {\n\t\treturn this.unbind( \".ui-disableSelection\" );\n\t}\n});\n\n$.extend( $.ui, {\n\t// $.ui.plugin is deprecated.  Use the proxy pattern instead.\n\tplugin: {\n\t\tadd: function( module, option, set ) {\n\t\t\tvar i,\n\t\t\t\tproto = $.ui[ module ].prototype;\n\t\t\tfor ( i in set ) {\n\t\t\t\tproto.plugins[ i ] = proto.plugins[ i ] || [];\n\t\t\t\tproto.plugins[ i ].push( [ option, set[ i ] ] );\n\t\t\t}\n\t\t},\n\t\tcall: function( instance, name, args ) {\n\t\t\tvar i,\n\t\t\t\tset = instance.plugins[ name ];\n\t\t\tif ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor ( i = 0; i < set.length; i++ ) {\n\t\t\t\tif ( instance.options[ set[ i ][ 0 ] ] ) {\n\t\t\t\t\tset[ i ][ 1 ].apply( instance.element, args );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// only used by resizable\n\thasScroll: function( el, a ) {\n\n\t\t//If overflow is hidden, the element might have extra content, but the user wants to hide it\n\t\tif ( $( el ).css( \"overflow\" ) === \"hidden\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar scroll = ( a && a === \"left\" ) ? \"scrollLeft\" : \"scrollTop\",\n\t\t\thas = false;\n\n\t\tif ( el[ scroll ] > 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// TODO: determine which cases actually cause this to happen\n\t\t// if the element doesn't have the scroll set, see if it's possible to\n\t\t// set the scroll\n\t\tel[ scroll ] = 1;\n\t\thas = ( el[ scroll ] > 0 );\n\t\tel[ scroll ] = 0;\n\t\treturn has;\n\t}\n});\n\n})( jQuery );\n\n(function( $, undefined ) {\n\nvar uuid = 0,\n\tslice = Array.prototype.slice,\n\t_cleanData = $.cleanData;\n$.cleanData = function( elems ) {\n\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n\t\ttry {\n\t\t\t$( elem ).triggerHandler( \"remove\" );\n\t\t// http://bugs.jquery.com/ticket/8235\n\t\t} catch( e ) {}\n\t}\n\t_cleanData( elems );\n};\n\n$.widget = function( name, base, prototype ) {\n\tvar fullName, existingConstructor, constructor, basePrototype,\n\t\t// proxiedPrototype allows the provided prototype to remain unmodified\n\t\t// so that it can be used as a mixin for multiple widgets (#8876)\n\t\tproxiedPrototype = {},\n\t\tnamespace = name.split( \".\" )[ 0 ];\n\n\tname = name.split( \".\" )[ 1 ];\n\tfullName = namespace + \"-\" + name;\n\n\tif ( !prototype ) {\n\t\tprototype = base;\n\t\tbase = $.Widget;\n\t}\n\n\t// create selector for plugin\n\t$.expr[ \":\" ][ fullName.toLowerCase() ] = function( elem ) {\n\t\treturn !!$.data( elem, fullName );\n\t};\n\n\t$[ namespace ] = $[ namespace ] || {};\n\texistingConstructor = $[ namespace ][ name ];\n\tconstructor = $[ namespace ][ name ] = function( options, element ) {\n\t\t// allow instantiation without \"new\" keyword\n\t\tif ( !this._createWidget ) {\n\t\t\treturn new constructor( options, element );\n\t\t}\n\n\t\t// allow instantiation without initializing for simple inheritance\n\t\t// must use \"new\" keyword (the code above always passes args)\n\t\tif ( arguments.length ) {\n\t\t\tthis._createWidget( options, element );\n\t\t}\n\t};\n\t// extend with the existing constructor to carry over any static properties\n\t$.extend( constructor, existingConstructor, {\n\t\tversion: prototype.version,\n\t\t// copy the object used to create the prototype in case we need to\n\t\t// redefine the widget later\n\t\t_proto: $.extend( {}, prototype ),\n\t\t// track widgets that inherit from this widget in case this widget is\n\t\t// redefined after a widget inherits from it\n\t\t_childConstructors: []\n\t});\n\n\tbasePrototype = new base();\n\t// we need to make the options hash a property directly on the new instance\n\t// otherwise we'll modify the options hash on the prototype that we're\n\t// inheriting from\n\tbasePrototype.options = $.widget.extend( {}, basePrototype.options );\n\t$.each( prototype, function( prop, value ) {\n\t\tif ( !$.isFunction( value ) ) {\n\t\t\tproxiedPrototype[ prop ] = value;\n\t\t\treturn;\n\t\t}\n\t\tproxiedPrototype[ prop ] = (function() {\n\t\t\tvar _super = function() {\n\t\t\t\t\treturn base.prototype[ prop ].apply( this, arguments );\n\t\t\t\t},\n\t\t\t\t_superApply = function( args ) {\n\t\t\t\t\treturn base.prototype[ prop ].apply( this, args );\n\t\t\t\t};\n\t\t\treturn function() {\n\t\t\t\tvar __super = this._super,\n\t\t\t\t\t__superApply = this._superApply,\n\t\t\t\t\treturnValue;\n\n\t\t\t\tthis._super = _super;\n\t\t\t\tthis._superApply = _superApply;\n\n\t\t\t\treturnValue = value.apply( this, arguments );\n\n\t\t\t\tthis._super = __super;\n\t\t\t\tthis._superApply = __superApply;\n\n\t\t\t\treturn returnValue;\n\t\t\t};\n\t\t})();\n\t});\n\tconstructor.prototype = $.widget.extend( basePrototype, {\n\t\t// TODO: remove support for widgetEventPrefix\n\t\t// always use the name + a colon as the prefix, e.g., draggable:start\n\t\t// don't prefix for widgets that aren't DOM-based\n\t\twidgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name\n\t}, proxiedPrototype, {\n\t\tconstructor: constructor,\n\t\tnamespace: namespace,\n\t\twidgetName: name,\n\t\twidgetFullName: fullName\n\t});\n\n\t// If this widget is being redefined then we need to find all widgets that\n\t// are inheriting from it and redefine all of them so that they inherit from\n\t// the new version of this widget. We're essentially trying to replace one\n\t// level in the prototype chain.\n\tif ( existingConstructor ) {\n\t\t$.each( existingConstructor._childConstructors, function( i, child ) {\n\t\t\tvar childPrototype = child.prototype;\n\n\t\t\t// redefine the child widget using the same prototype that was\n\t\t\t// originally used, but inherit from the new version of the base\n\t\t\t$.widget( childPrototype.namespace + \".\" + childPrototype.widgetName, constructor, child._proto );\n\t\t});\n\t\t// remove the list of existing child constructors from the old constructor\n\t\t// so the old child constructors can be garbage collected\n\t\tdelete existingConstructor._childConstructors;\n\t} else {\n\t\tbase._childConstructors.push( constructor );\n\t}\n\n\t$.widget.bridge( name, constructor );\n};\n\n$.widget.extend = function( target ) {\n\tvar input = slice.call( arguments, 1 ),\n\t\tinputIndex = 0,\n\t\tinputLength = input.length,\n\t\tkey,\n\t\tvalue;\n\tfor ( ; inputIndex < inputLength; inputIndex++ ) {\n\t\tfor ( key in input[ inputIndex ] ) {\n\t\t\tvalue = input[ inputIndex ][ key ];\n\t\t\tif ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {\n\t\t\t\t// Clone objects\n\t\t\t\tif ( $.isPlainObject( value ) ) {\n\t\t\t\t\ttarget[ key ] = $.isPlainObject( target[ key ] ) ?\n\t\t\t\t\t\t$.widget.extend( {}, target[ key ], value ) :\n\t\t\t\t\t\t// Don't extend strings, arrays, etc. with objects\n\t\t\t\t\t\t$.widget.extend( {}, value );\n\t\t\t\t// Copy everything else by reference\n\t\t\t\t} else {\n\t\t\t\t\ttarget[ key ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn target;\n};\n\n$.widget.bridge = function( name, object ) {\n\tvar fullName = object.prototype.widgetFullName || name;\n\t$.fn[ name ] = function( options ) {\n\t\tvar isMethodCall = typeof options === \"string\",\n\t\t\targs = slice.call( arguments, 1 ),\n\t\t\treturnValue = this;\n\n\t\t// allow multiple hashes to be passed on init\n\t\toptions = !isMethodCall && args.length ?\n\t\t\t$.widget.extend.apply( null, [ options ].concat(args) ) :\n\t\t\toptions;\n\n\t\tif ( isMethodCall ) {\n\t\t\tthis.each(function() {\n\t\t\t\tvar methodValue,\n\t\t\t\t\tinstance = $.data( this, fullName );\n\t\t\t\tif ( !instance ) {\n\t\t\t\t\treturn $.error( \"cannot call methods on \" + name + \" prior to initialization; \" +\n\t\t\t\t\t\t\"attempted to call method '\" + options + \"'\" );\n\t\t\t\t}\n\t\t\t\tif ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === \"_\" ) {\n\t\t\t\t\treturn $.error( \"no such method '\" + options + \"' for \" + name + \" widget instance\" );\n\t\t\t\t}\n\t\t\t\tmethodValue = instance[ options ].apply( instance, args );\n\t\t\t\tif ( methodValue !== instance && methodValue !== undefined ) {\n\t\t\t\t\treturnValue = methodValue && methodValue.jquery ?\n\t\t\t\t\t\treturnValue.pushStack( methodValue.get() ) :\n\t\t\t\t\t\tmethodValue;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tthis.each(function() {\n\t\t\t\tvar instance = $.data( this, fullName );\n\t\t\t\tif ( instance ) {\n\t\t\t\t\tinstance.option( options || {} )._init();\n\t\t\t\t} else {\n\t\t\t\t\t$.data( this, fullName, new object( options, this ) );\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn returnValue;\n\t};\n};\n\n$.Widget = function( /* options, element */ ) {};\n$.Widget._childConstructors = [];\n\n$.Widget.prototype = {\n\twidgetName: \"widget\",\n\twidgetEventPrefix: \"\",\n\tdefaultElement: \"<div>\",\n\toptions: {\n\t\tdisabled: false,\n\n\t\t// callbacks\n\t\tcreate: null\n\t},\n\t_createWidget: function( options, element ) {\n\t\telement = $( element || this.defaultElement || this )[ 0 ];\n\t\tthis.element = $( element );\n\t\tthis.uuid = uuid++;\n\t\tthis.eventNamespace = \".\" + this.widgetName + this.uuid;\n\t\tthis.options = $.widget.extend( {},\n\t\t\tthis.options,\n\t\t\tthis._getCreateOptions(),\n\t\t\toptions );\n\n\t\tthis.bindings = $();\n\t\tthis.hoverable = $();\n\t\tthis.focusable = $();\n\n\t\tif ( element !== this ) {\n\t\t\t$.data( element, this.widgetFullName, this );\n\t\t\tthis._on( true, this.element, {\n\t\t\t\tremove: function( event ) {\n\t\t\t\t\tif ( event.target === element ) {\n\t\t\t\t\t\tthis.destroy();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.document = $( element.style ?\n\t\t\t\t// element within the document\n\t\t\t\telement.ownerDocument :\n\t\t\t\t// element is window or document\n\t\t\t\telement.document || element );\n\t\t\tthis.window = $( this.document[0].defaultView || this.document[0].parentWindow );\n\t\t}\n\n\t\tthis._create();\n\t\tthis._trigger( \"create\", null, this._getCreateEventData() );\n\t\tthis._init();\n\t},\n\t_getCreateOptions: $.noop,\n\t_getCreateEventData: $.noop,\n\t_create: $.noop,\n\t_init: $.noop,\n\n\tdestroy: function() {\n\t\tthis._destroy();\n\t\t// we can probably remove the unbind calls in 2.0\n\t\t// all event bindings should go through this._on()\n\t\tthis.element\n\t\t\t.unbind( this.eventNamespace )\n\t\t\t// 1.9 BC for #7810\n\t\t\t// TODO remove dual storage\n\t\t\t.removeData( this.widgetName )\n\t\t\t.removeData( this.widgetFullName )\n\t\t\t// support: jquery <1.6.3\n\t\t\t// http://bugs.jquery.com/ticket/9413\n\t\t\t.removeData( $.camelCase( this.widgetFullName ) );\n\t\tthis.widget()\n\t\t\t.unbind( this.eventNamespace )\n\t\t\t.removeAttr( \"aria-disabled\" )\n\t\t\t.removeClass(\n\t\t\t\tthis.widgetFullName + \"-disabled \" +\n\t\t\t\t\"ui-state-disabled\" );\n\n\t\t// clean up events and states\n\t\tthis.bindings.unbind( this.eventNamespace );\n\t\tthis.hoverable.removeClass( \"ui-state-hover\" );\n\t\tthis.focusable.removeClass( \"ui-state-focus\" );\n\t},\n\t_destroy: $.noop,\n\n\twidget: function() {\n\t\treturn this.element;\n\t},\n\n\toption: function( key, value ) {\n\t\tvar options = key,\n\t\t\tparts,\n\t\t\tcurOption,\n\t\t\ti;\n\n\t\tif ( arguments.length === 0 ) {\n\t\t\t// don't return a reference to the internal hash\n\t\t\treturn $.widget.extend( {}, this.options );\n\t\t}\n\n\t\tif ( typeof key === \"string\" ) {\n\t\t\t// handle nested keys, e.g., \"foo.bar\" => { foo: { bar: ___ } }\n\t\t\toptions = {};\n\t\t\tparts = key.split( \".\" );\n\t\t\tkey = parts.shift();\n\t\t\tif ( parts.length ) {\n\t\t\t\tcurOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );\n\t\t\t\tfor ( i = 0; i < parts.length - 1; i++ ) {\n\t\t\t\t\tcurOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};\n\t\t\t\t\tcurOption = curOption[ parts[ i ] ];\n\t\t\t\t}\n\t\t\t\tkey = parts.pop();\n\t\t\t\tif ( value === undefined ) {\n\t\t\t\t\treturn curOption[ key ] === undefined ? null : curOption[ key ];\n\t\t\t\t}\n\t\t\t\tcurOption[ key ] = value;\n\t\t\t} else {\n\t\t\t\tif ( value === undefined ) {\n\t\t\t\t\treturn this.options[ key ] === undefined ? null : this.options[ key ];\n\t\t\t\t}\n\t\t\t\toptions[ key ] = value;\n\t\t\t}\n\t\t}\n\n\t\tthis._setOptions( options );\n\n\t\treturn this;\n\t},\n\t_setOptions: function( options ) {\n\t\tvar key;\n\n\t\tfor ( key in options ) {\n\t\t\tthis._setOption( key, options[ key ] );\n\t\t}\n\n\t\treturn this;\n\t},\n\t_setOption: function( key, value ) {\n\t\tthis.options[ key ] = value;\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.widget()\n\t\t\t\t.toggleClass( this.widgetFullName + \"-disabled ui-state-disabled\", !!value )\n\t\t\t\t.attr( \"aria-disabled\", value );\n\t\t\tthis.hoverable.removeClass( \"ui-state-hover\" );\n\t\t\tthis.focusable.removeClass( \"ui-state-focus\" );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tenable: function() {\n\t\treturn this._setOption( \"disabled\", false );\n\t},\n\tdisable: function() {\n\t\treturn this._setOption( \"disabled\", true );\n\t},\n\n\t_on: function( suppressDisabledCheck, element, handlers ) {\n\t\tvar delegateElement,\n\t\t\tinstance = this;\n\n\t\t// no suppressDisabledCheck flag, shuffle arguments\n\t\tif ( typeof suppressDisabledCheck !== \"boolean\" ) {\n\t\t\thandlers = element;\n\t\t\telement = suppressDisabledCheck;\n\t\t\tsuppressDisabledCheck = false;\n\t\t}\n\n\t\t// no element argument, shuffle and use this.element\n\t\tif ( !handlers ) {\n\t\t\thandlers = element;\n\t\t\telement = this.element;\n\t\t\tdelegateElement = this.widget();\n\t\t} else {\n\t\t\t// accept selectors, DOM elements\n\t\t\telement = delegateElement = $( element );\n\t\t\tthis.bindings = this.bindings.add( element );\n\t\t}\n\n\t\t$.each( handlers, function( event, handler ) {\n\t\t\tfunction handlerProxy() {\n\t\t\t\t// allow widgets to customize the disabled handling\n\t\t\t\t// - disabled as an array instead of boolean\n\t\t\t\t// - disabled class as method for disabling individual parts\n\t\t\t\tif ( !suppressDisabledCheck &&\n\t\t\t\t\t\t( instance.options.disabled === true ||\n\t\t\t\t\t\t\t$( this ).hasClass( \"ui-state-disabled\" ) ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn ( typeof handler === \"string\" ? instance[ handler ] : handler )\n\t\t\t\t\t.apply( instance, arguments );\n\t\t\t}\n\n\t\t\t// copy the guid so direct unbinding works\n\t\t\tif ( typeof handler !== \"string\" ) {\n\t\t\t\thandlerProxy.guid = handler.guid =\n\t\t\t\t\thandler.guid || handlerProxy.guid || $.guid++;\n\t\t\t}\n\n\t\t\tvar match = event.match( /^(\\w+)\\s*(.*)$/ ),\n\t\t\t\teventName = match[1] + instance.eventNamespace,\n\t\t\t\tselector = match[2];\n\t\t\tif ( selector ) {\n\t\t\t\tdelegateElement.delegate( selector, eventName, handlerProxy );\n\t\t\t} else {\n\t\t\t\telement.bind( eventName, handlerProxy );\n\t\t\t}\n\t\t});\n\t},\n\n\t_off: function( element, eventName ) {\n\t\teventName = (eventName || \"\").split( \" \" ).join( this.eventNamespace + \" \" ) + this.eventNamespace;\n\t\telement.unbind( eventName ).undelegate( eventName );\n\t},\n\n\t_delay: function( handler, delay ) {\n\t\tfunction handlerProxy() {\n\t\t\treturn ( typeof handler === \"string\" ? instance[ handler ] : handler )\n\t\t\t\t.apply( instance, arguments );\n\t\t}\n\t\tvar instance = this;\n\t\treturn setTimeout( handlerProxy, delay || 0 );\n\t},\n\n\t_hoverable: function( element ) {\n\t\tthis.hoverable = this.hoverable.add( element );\n\t\tthis._on( element, {\n\t\t\tmouseenter: function( event ) {\n\t\t\t\t$( event.currentTarget ).addClass( \"ui-state-hover\" );\n\t\t\t},\n\t\t\tmouseleave: function( event ) {\n\t\t\t\t$( event.currentTarget ).removeClass( \"ui-state-hover\" );\n\t\t\t}\n\t\t});\n\t},\n\n\t_focusable: function( element ) {\n\t\tthis.focusable = this.focusable.add( element );\n\t\tthis._on( element, {\n\t\t\tfocusin: function( event ) {\n\t\t\t\t$( event.currentTarget ).addClass( \"ui-state-focus\" );\n\t\t\t},\n\t\t\tfocusout: function( event ) {\n\t\t\t\t$( event.currentTarget ).removeClass( \"ui-state-focus\" );\n\t\t\t}\n\t\t});\n\t},\n\n\t_trigger: function( type, event, data ) {\n\t\tvar prop, orig,\n\t\t\tcallback = this.options[ type ];\n\n\t\tdata = data || {};\n\t\tevent = $.Event( event );\n\t\tevent.type = ( type === this.widgetEventPrefix ?\n\t\t\ttype :\n\t\t\tthis.widgetEventPrefix + type ).toLowerCase();\n\t\t// the original event may come from any element\n\t\t// so we need to reset the target on the new event\n\t\tevent.target = this.element[ 0 ];\n\n\t\t// copy original event properties over to the new event\n\t\torig = event.originalEvent;\n\t\tif ( orig ) {\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tif ( !( prop in event ) ) {\n\t\t\t\t\tevent[ prop ] = orig[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.element.trigger( event, data );\n\t\treturn !( $.isFunction( callback ) &&\n\t\t\tcallback.apply( this.element[0], [ event ].concat( data ) ) === false ||\n\t\t\tevent.isDefaultPrevented() );\n\t}\n};\n\n$.each( { show: \"fadeIn\", hide: \"fadeOut\" }, function( method, defaultEffect ) {\n\t$.Widget.prototype[ \"_\" + method ] = function( element, options, callback ) {\n\t\tif ( typeof options === \"string\" ) {\n\t\t\toptions = { effect: options };\n\t\t}\n\t\tvar hasOptions,\n\t\t\teffectName = !options ?\n\t\t\t\tmethod :\n\t\t\t\toptions === true || typeof options === \"number\" ?\n\t\t\t\t\tdefaultEffect :\n\t\t\t\t\toptions.effect || defaultEffect;\n\t\toptions = options || {};\n\t\tif ( typeof options === \"number\" ) {\n\t\t\toptions = { duration: options };\n\t\t}\n\t\thasOptions = !$.isEmptyObject( options );\n\t\toptions.complete = callback;\n\t\tif ( options.delay ) {\n\t\t\telement.delay( options.delay );\n\t\t}\n\t\tif ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {\n\t\t\telement[ method ]( options );\n\t\t} else if ( effectName !== method && element[ effectName ] ) {\n\t\t\telement[ effectName ]( options.duration, options.easing, callback );\n\t\t} else {\n\t\t\telement.queue(function( next ) {\n\t\t\t\t$( this )[ method ]();\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback.call( element[ 0 ] );\n\t\t\t\t}\n\t\t\t\tnext();\n\t\t\t});\n\t\t}\n\t};\n});\n\n})( jQuery );\n\n(function( $, undefined ) {\n\nvar mouseHandled = false;\n$( document ).mouseup( function() {\n\tmouseHandled = false;\n});\n\n$.widget(\"ui.mouse\", {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\tcancel: \"input,textarea,button,select,option\",\n\t\tdistance: 1,\n\t\tdelay: 0\n\t},\n\t_mouseInit: function() {\n\t\tvar that = this;\n\n\t\tthis.element\n\t\t\t.bind(\"mousedown.\"+this.widgetName, function(event) {\n\t\t\t\treturn that._mouseDown(event);\n\t\t\t})\n\t\t\t.bind(\"click.\"+this.widgetName, function(event) {\n\t\t\t\tif (true === $.data(event.target, that.widgetName + \".preventClickEvent\")) {\n\t\t\t\t\t$.removeData(event.target, that.widgetName + \".preventClickEvent\");\n\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\n\t\tthis.started = false;\n\t},\n\n\t// TODO: make sure destroying one instance of mouse doesn't mess with\n\t// other instances of mouse\n\t_mouseDestroy: function() {\n\t\tthis.element.unbind(\".\"+this.widgetName);\n\t\tif ( this._mouseMoveDelegate ) {\n\t\t\t$(document)\n\t\t\t\t.unbind(\"mousemove.\"+this.widgetName, this._mouseMoveDelegate)\n\t\t\t\t.unbind(\"mouseup.\"+this.widgetName, this._mouseUpDelegate);\n\t\t}\n\t},\n\n\t_mouseDown: function(event) {\n\t\t// don't let more than one widget handle mouseStart\n\t\tif( mouseHandled ) { return; }\n\n\t\t// we may have missed mouseup (out of window)\n\t\t(this._mouseStarted && this._mouseUp(event));\n\n\t\tthis._mouseDownEvent = event;\n\n\t\tvar that = this,\n\t\t\tbtnIsLeft = (event.which === 1),\n\t\t\t// event.target.nodeName works around a bug in IE 8 with\n\t\t\t// disabled inputs (#7620)\n\t\t\telIsCancel = (typeof this.options.cancel === \"string\" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);\n\t\tif (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.mouseDelayMet = !this.options.delay;\n\t\tif (!this.mouseDelayMet) {\n\t\t\tthis._mouseDelayTimer = setTimeout(function() {\n\t\t\t\tthat.mouseDelayMet = true;\n\t\t\t}, this.options.delay);\n\t\t}\n\n\t\tif (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {\n\t\t\tthis._mouseStarted = (this._mouseStart(event) !== false);\n\t\t\tif (!this._mouseStarted) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Click event may never have fired (Gecko & Opera)\n\t\tif (true === $.data(event.target, this.widgetName + \".preventClickEvent\")) {\n\t\t\t$.removeData(event.target, this.widgetName + \".preventClickEvent\");\n\t\t}\n\n\t\t// these delegates are required to keep context\n\t\tthis._mouseMoveDelegate = function(event) {\n\t\t\treturn that._mouseMove(event);\n\t\t};\n\t\tthis._mouseUpDelegate = function(event) {\n\t\t\treturn that._mouseUp(event);\n\t\t};\n\t\t$(document)\n\t\t\t.bind(\"mousemove.\"+this.widgetName, this._mouseMoveDelegate)\n\t\t\t.bind(\"mouseup.\"+this.widgetName, this._mouseUpDelegate);\n\n\t\tevent.preventDefault();\n\n\t\tmouseHandled = true;\n\t\treturn true;\n\t},\n\n\t_mouseMove: function(event) {\n\t\t// IE mouseup check - mouseup happened when mouse was out of window\n\t\tif ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {\n\t\t\treturn this._mouseUp(event);\n\t\t}\n\n\t\tif (this._mouseStarted) {\n\t\t\tthis._mouseDrag(event);\n\t\t\treturn event.preventDefault();\n\t\t}\n\n\t\tif (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {\n\t\t\tthis._mouseStarted =\n\t\t\t\t(this._mouseStart(this._mouseDownEvent, event) !== false);\n\t\t\t(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));\n\t\t}\n\n\t\treturn !this._mouseStarted;\n\t},\n\n\t_mouseUp: function(event) {\n\t\t$(document)\n\t\t\t.unbind(\"mousemove.\"+this.widgetName, this._mouseMoveDelegate)\n\t\t\t.unbind(\"mouseup.\"+this.widgetName, this._mouseUpDelegate);\n\n\t\tif (this._mouseStarted) {\n\t\t\tthis._mouseStarted = false;\n\n\t\t\tif (event.target === this._mouseDownEvent.target) {\n\t\t\t\t$.data(event.target, this.widgetName + \".preventClickEvent\", true);\n\t\t\t}\n\n\t\t\tthis._mouseStop(event);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_mouseDistanceMet: function(event) {\n\t\treturn (Math.max(\n\t\t\t\tMath.abs(this._mouseDownEvent.pageX - event.pageX),\n\t\t\t\tMath.abs(this._mouseDownEvent.pageY - event.pageY)\n\t\t\t) >= this.options.distance\n\t\t);\n\t},\n\n\t_mouseDelayMet: function(/* event */) {\n\t\treturn this.mouseDelayMet;\n\t},\n\n\t// These are placeholder methods, to be overriden by extending plugin\n\t_mouseStart: function(/* event */) {},\n\t_mouseDrag: function(/* event */) {},\n\t_mouseStop: function(/* event */) {},\n\t_mouseCapture: function(/* event */) { return true; }\n});\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.widget(\"ui.draggable\", $.ui.mouse, {\n\tversion: \"1.10.1\",\n\twidgetEventPrefix: \"drag\",\n\toptions: {\n\t\taddClasses: true,\n\t\tappendTo: \"parent\",\n\t\taxis: false,\n\t\tconnectToSortable: false,\n\t\tcontainment: false,\n\t\tcursor: \"auto\",\n\t\tcursorAt: false,\n\t\tgrid: false,\n\t\thandle: false,\n\t\thelper: \"original\",\n\t\tiframeFix: false,\n\t\topacity: false,\n\t\trefreshPositions: false,\n\t\trevert: false,\n\t\trevertDuration: 500,\n\t\tscope: \"default\",\n\t\tscroll: true,\n\t\tscrollSensitivity: 20,\n\t\tscrollSpeed: 20,\n\t\tsnap: false,\n\t\tsnapMode: \"both\",\n\t\tsnapTolerance: 20,\n\t\tstack: false,\n\t\tzIndex: false,\n\n\t\t// callbacks\n\t\tdrag: null,\n\t\tstart: null,\n\t\tstop: null\n\t},\n\t_create: function() {\n\n\t\tif (this.options.helper === \"original\" && !(/^(?:r|a|f)/).test(this.element.css(\"position\"))) {\n\t\t\tthis.element[0].style.position = \"relative\";\n\t\t}\n\t\tif (this.options.addClasses){\n\t\t\tthis.element.addClass(\"ui-draggable\");\n\t\t}\n\t\tif (this.options.disabled){\n\t\t\tthis.element.addClass(\"ui-draggable-disabled\");\n\t\t}\n\n\t\tthis._mouseInit();\n\n\t},\n\n\t_destroy: function() {\n\t\tthis.element.removeClass( \"ui-draggable ui-draggable-dragging ui-draggable-disabled\" );\n\t\tthis._mouseDestroy();\n\t},\n\n\t_mouseCapture: function(event) {\n\n\t\tvar o = this.options;\n\n\t\t// among others, prevent a drag on a resizable-handle\n\t\tif (this.helper || o.disabled || $(event.target).closest(\".ui-resizable-handle\").length > 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\t//Quit if we're not on a valid handle\n\t\tthis.handle = this._getHandle(event);\n\t\tif (!this.handle) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$(o.iframeFix === true ? \"iframe\" : o.iframeFix).each(function() {\n\t\t\t$(\"<div class='ui-draggable-iframeFix' style='background: #fff;'></div>\")\n\t\t\t.css({\n\t\t\t\twidth: this.offsetWidth+\"px\", height: this.offsetHeight+\"px\",\n\t\t\t\tposition: \"absolute\", opacity: \"0.001\", zIndex: 1000\n\t\t\t})\n\t\t\t.css($(this).offset())\n\t\t\t.appendTo(\"body\");\n\t\t});\n\n\t\treturn true;\n\n\t},\n\n\t_mouseStart: function(event) {\n\n\t\tvar o = this.options;\n\n\t\t//Create and append the visible helper\n\t\tthis.helper = this._createHelper(event);\n\n\t\tthis.helper.addClass(\"ui-draggable-dragging\");\n\n\t\t//Cache the helper size\n\t\tthis._cacheHelperProportions();\n\n\t\t//If ddmanager is used for droppables, set the global draggable\n\t\tif($.ui.ddmanager) {\n\t\t\t$.ui.ddmanager.current = this;\n\t\t}\n\n\t\t/*\n\t\t * - Position generation -\n\t\t * This block generates everything position related - it's the core of draggables.\n\t\t */\n\n\t\t//Cache the margins of the original element\n\t\tthis._cacheMargins();\n\n\t\t//Store the helper's css position\n\t\tthis.cssPosition = this.helper.css(\"position\");\n\t\tthis.scrollParent = this.helper.scrollParent();\n\n\t\t//The element's absolute position on the page minus margins\n\t\tthis.offset = this.positionAbs = this.element.offset();\n\t\tthis.offset = {\n\t\t\ttop: this.offset.top - this.margins.top,\n\t\t\tleft: this.offset.left - this.margins.left\n\t\t};\n\n\t\t$.extend(this.offset, {\n\t\t\tclick: { //Where the click happened, relative to the element\n\t\t\t\tleft: event.pageX - this.offset.left,\n\t\t\t\ttop: event.pageY - this.offset.top\n\t\t\t},\n\t\t\tparent: this._getParentOffset(),\n\t\t\trelative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper\n\t\t});\n\n\t\t//Generate the original position\n\t\tthis.originalPosition = this.position = this._generatePosition(event);\n\t\tthis.originalPageX = event.pageX;\n\t\tthis.originalPageY = event.pageY;\n\n\t\t//Adjust the mouse offset relative to the helper if \"cursorAt\" is supplied\n\t\t(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));\n\n\t\t//Set a containment if given in the options\n\t\tif(o.containment) {\n\t\t\tthis._setContainment();\n\t\t}\n\n\t\t//Trigger event + callbacks\n\t\tif(this._trigger(\"start\", event) === false) {\n\t\t\tthis._clear();\n\t\t\treturn false;\n\t\t}\n\n\t\t//Recache the helper size\n\t\tthis._cacheHelperProportions();\n\n\t\t//Prepare the droppable offsets\n\t\tif ($.ui.ddmanager && !o.dropBehaviour) {\n\t\t\t$.ui.ddmanager.prepareOffsets(this, event);\n\t\t}\n\n\n\t\tthis._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position\n\n\t\t//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)\n\t\tif ( $.ui.ddmanager ) {\n\t\t\t$.ui.ddmanager.dragStart(this, event);\n\t\t}\n\n\t\treturn true;\n\t},\n\n\t_mouseDrag: function(event, noPropagation) {\n\n\t\t//Compute the helpers position\n\t\tthis.position = this._generatePosition(event);\n\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\n\t\t//Call plugins and callbacks and use the resulting position if something is returned\n\t\tif (!noPropagation) {\n\t\t\tvar ui = this._uiHash();\n\t\t\tif(this._trigger(\"drag\", event, ui) === false) {\n\t\t\t\tthis._mouseUp({});\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.position = ui.position;\n\t\t}\n\n\t\tif(!this.options.axis || this.options.axis !== \"y\") {\n\t\t\tthis.helper[0].style.left = this.position.left+\"px\";\n\t\t}\n\t\tif(!this.options.axis || this.options.axis !== \"x\") {\n\t\t\tthis.helper[0].style.top = this.position.top+\"px\";\n\t\t}\n\t\tif($.ui.ddmanager) {\n\t\t\t$.ui.ddmanager.drag(this, event);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function(event) {\n\n\t\t//If we are using droppables, inform the manager about the drop\n\t\tvar element,\n\t\t\tthat = this,\n\t\t\telementInDom = false,\n\t\t\tdropped = false;\n\t\tif ($.ui.ddmanager && !this.options.dropBehaviour) {\n\t\t\tdropped = $.ui.ddmanager.drop(this, event);\n\t\t}\n\n\t\t//if a drop comes from outside (a sortable)\n\t\tif(this.dropped) {\n\t\t\tdropped = this.dropped;\n\t\t\tthis.dropped = false;\n\t\t}\n\n\t\t//if the original element is no longer in the DOM don't bother to continue (see #8269)\n\t\telement = this.element[0];\n\t\twhile ( element && (element = element.parentNode) ) {\n\t\t\tif (element === document ) {\n\t\t\t\telementInDom = true;\n\t\t\t}\n\t\t}\n\t\tif ( !elementInDom && this.options.helper === \"original\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif((this.options.revert === \"invalid\" && !dropped) || (this.options.revert === \"valid\" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {\n\t\t\t$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {\n\t\t\t\tif(that._trigger(\"stop\", event) !== false) {\n\t\t\t\t\tthat._clear();\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tif(this._trigger(\"stop\", event) !== false) {\n\t\t\t\tthis._clear();\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_mouseUp: function(event) {\n\t\t//Remove frame helpers\n\t\t$(\"div.ui-draggable-iframeFix\").each(function() {\n\t\t\tthis.parentNode.removeChild(this);\n\t\t});\n\n\t\t//If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)\n\t\tif( $.ui.ddmanager ) {\n\t\t\t$.ui.ddmanager.dragStop(this, event);\n\t\t}\n\n\t\treturn $.ui.mouse.prototype._mouseUp.call(this, event);\n\t},\n\n\tcancel: function() {\n\n\t\tif(this.helper.is(\".ui-draggable-dragging\")) {\n\t\t\tthis._mouseUp({});\n\t\t} else {\n\t\t\tthis._clear();\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t_getHandle: function(event) {\n\n\t\tvar handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;\n\t\t$(this.options.handle, this.element)\n\t\t\t.find(\"*\")\n\t\t\t.addBack()\n\t\t\t.each(function() {\n\t\t\t\tif(this === event.target) {\n\t\t\t\t\thandle = true;\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn handle;\n\n\t},\n\n\t_createHelper: function(event) {\n\n\t\tvar o = this.options,\n\t\t\thelper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === \"clone\" ? this.element.clone().removeAttr(\"id\") : this.element);\n\n\t\tif(!helper.parents(\"body\").length) {\n\t\t\thelper.appendTo((o.appendTo === \"parent\" ? this.element[0].parentNode : o.appendTo));\n\t\t}\n\n\t\tif(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css(\"position\"))) {\n\t\t\thelper.css(\"position\", \"absolute\");\n\t\t}\n\n\t\treturn helper;\n\n\t},\n\n\t_adjustOffsetFromHelper: function(obj) {\n\t\tif (typeof obj === \"string\") {\n\t\t\tobj = obj.split(\" \");\n\t\t}\n\t\tif ($.isArray(obj)) {\n\t\t\tobj = {left: +obj[0], top: +obj[1] || 0};\n\t\t}\n\t\tif (\"left\" in obj) {\n\t\t\tthis.offset.click.left = obj.left + this.margins.left;\n\t\t}\n\t\tif (\"right\" in obj) {\n\t\t\tthis.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;\n\t\t}\n\t\tif (\"top\" in obj) {\n\t\t\tthis.offset.click.top = obj.top + this.margins.top;\n\t\t}\n\t\tif (\"bottom\" in obj) {\n\t\t\tthis.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;\n\t\t}\n\t},\n\n\t_getParentOffset: function() {\n\n\t\t//Get the offsetParent and cache its position\n\t\tthis.offsetParent = this.helper.offsetParent();\n\t\tvar po = this.offsetParent.offset();\n\n\t\t// This is a special case where we need to modify a offset calculated on start, since the following happened:\n\t\t// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent\n\t\t// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that\n\t\t//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag\n\t\tif(this.cssPosition === \"absolute\" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {\n\t\t\tpo.left += this.scrollParent.scrollLeft();\n\t\t\tpo.top += this.scrollParent.scrollTop();\n\t\t}\n\n\t\t//This needs to be actually done for all browsers, since pageX/pageY includes this information\n\t\t//Ugly IE fix\n\t\tif((this.offsetParent[0] === document.body) ||\n\t\t\t(this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === \"html\" && $.ui.ie)) {\n\t\t\tpo = { top: 0, left: 0 };\n\t\t}\n\n\t\treturn {\n\t\t\ttop: po.top + (parseInt(this.offsetParent.css(\"borderTopWidth\"),10) || 0),\n\t\t\tleft: po.left + (parseInt(this.offsetParent.css(\"borderLeftWidth\"),10) || 0)\n\t\t};\n\n\t},\n\n\t_getRelativeOffset: function() {\n\n\t\tif(this.cssPosition === \"relative\") {\n\t\t\tvar p = this.element.position();\n\t\t\treturn {\n\t\t\t\ttop: p.top - (parseInt(this.helper.css(\"top\"),10) || 0) + this.scrollParent.scrollTop(),\n\t\t\t\tleft: p.left - (parseInt(this.helper.css(\"left\"),10) || 0) + this.scrollParent.scrollLeft()\n\t\t\t};\n\t\t} else {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t},\n\n\t_cacheMargins: function() {\n\t\tthis.margins = {\n\t\t\tleft: (parseInt(this.element.css(\"marginLeft\"),10) || 0),\n\t\t\ttop: (parseInt(this.element.css(\"marginTop\"),10) || 0),\n\t\t\tright: (parseInt(this.element.css(\"marginRight\"),10) || 0),\n\t\t\tbottom: (parseInt(this.element.css(\"marginBottom\"),10) || 0)\n\t\t};\n\t},\n\n\t_cacheHelperProportions: function() {\n\t\tthis.helperProportions = {\n\t\t\twidth: this.helper.outerWidth(),\n\t\t\theight: this.helper.outerHeight()\n\t\t};\n\t},\n\n\t_setContainment: function() {\n\n\t\tvar over, c, ce,\n\t\t\to = this.options;\n\n\t\tif(o.containment === \"parent\") {\n\t\t\to.containment = this.helper[0].parentNode;\n\t\t}\n\t\tif(o.containment === \"document\" || o.containment === \"window\") {\n\t\t\tthis.containment = [\n\t\t\t\to.containment === \"document\" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,\n\t\t\t\to.containment === \"document\" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,\n\t\t\t\t(o.containment === \"document\" ? 0 : $(window).scrollLeft()) + $(o.containment === \"document\" ? document : window).width() - this.helperProportions.width - this.margins.left,\n\t\t\t\t(o.containment === \"document\" ? 0 : $(window).scrollTop()) + ($(o.containment === \"document\" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top\n\t\t\t];\n\t\t}\n\n\t\tif(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) {\n\t\t\tc = $(o.containment);\n\t\t\tce = c[0];\n\n\t\t\tif(!ce) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tover = ($(ce).css(\"overflow\") !== \"hidden\");\n\n\t\t\tthis.containment = [\n\t\t\t\t(parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingLeft\"),10) || 0),\n\t\t\t\t(parseInt($(ce).css(\"borderTopWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingTop\"),10) || 0),\n\t\t\t\t(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingRight\"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right,\n\t\t\t\t(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingBottom\"),10) || 0) - this.helperProportions.height - this.margins.top  - this.margins.bottom\n\t\t\t];\n\t\t\tthis.relative_container = c;\n\n\t\t} else if(o.containment.constructor === Array) {\n\t\t\tthis.containment = o.containment;\n\t\t}\n\n\t},\n\n\t_convertPositionTo: function(d, pos) {\n\n\t\tif(!pos) {\n\t\t\tpos = this.position;\n\t\t}\n\n\t\tvar mod = d === \"absolute\" ? 1 : -1,\n\t\t\tscroll = this.cssPosition === \"absolute\" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpos.top\t+\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.relative.top * mod +\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.top * mod -\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpos.left +\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.relative.left * mod +\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.left * mod\t-\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_generatePosition: function(event) {\n\n\t\tvar containment, co, top, left,\n\t\t\to = this.options,\n\t\t\tscroll = this.cssPosition === \"absolute\" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,\n\t\t\tscrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName),\n\t\t\tpageX = event.pageX,\n\t\t\tpageY = event.pageY;\n\n\t\t/*\n\t\t * - Position constraining -\n\t\t * Constrain the position to a mix of grid, containment.\n\t\t */\n\n\t\tif(this.originalPosition) { //If we are not dragging yet, we won't check for options\n\t\t\tif(this.containment) {\n\t\t\tif (this.relative_container){\n\t\t\t\tco = this.relative_container.offset();\n\t\t\t\tcontainment = [ this.containment[0] + co.left,\n\t\t\t\t\tthis.containment[1] + co.top,\n\t\t\t\t\tthis.containment[2] + co.left,\n\t\t\t\t\tthis.containment[3] + co.top ];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcontainment = this.containment;\n\t\t\t}\n\n\t\t\t\tif(event.pageX - this.offset.click.left < containment[0]) {\n\t\t\t\t\tpageX = containment[0] + this.offset.click.left;\n\t\t\t\t}\n\t\t\t\tif(event.pageY - this.offset.click.top < containment[1]) {\n\t\t\t\t\tpageY = containment[1] + this.offset.click.top;\n\t\t\t\t}\n\t\t\t\tif(event.pageX - this.offset.click.left > containment[2]) {\n\t\t\t\t\tpageX = containment[2] + this.offset.click.left;\n\t\t\t\t}\n\t\t\t\tif(event.pageY - this.offset.click.top > containment[3]) {\n\t\t\t\t\tpageY = containment[3] + this.offset.click.top;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(o.grid) {\n\t\t\t\t//Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)\n\t\t\t\ttop = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;\n\t\t\t\tpageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;\n\n\t\t\t\tleft = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;\n\t\t\t\tpageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpageY -\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.click.top\t-\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\tthis.offset.relative.top -\t\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.top +\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpageX -\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.click.left -\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\tthis.offset.relative.left -\t\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.left +\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_clear: function() {\n\t\tthis.helper.removeClass(\"ui-draggable-dragging\");\n\t\tif(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {\n\t\t\tthis.helper.remove();\n\t\t}\n\t\tthis.helper = null;\n\t\tthis.cancelHelperRemoval = false;\n\t},\n\n\t// From now on bulk stuff - mainly helpers\n\n\t_trigger: function(type, event, ui) {\n\t\tui = ui || this._uiHash();\n\t\t$.ui.plugin.call(this, type, [event, ui]);\n\t\t//The absolute position has to be recalculated after plugins\n\t\tif(type === \"drag\") {\n\t\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\t\t}\n\t\treturn $.Widget.prototype._trigger.call(this, type, event, ui);\n\t},\n\n\tplugins: {},\n\n\t_uiHash: function() {\n\t\treturn {\n\t\t\thelper: this.helper,\n\t\t\tposition: this.position,\n\t\t\toriginalPosition: this.originalPosition,\n\t\t\toffset: this.positionAbs\n\t\t};\n\t}\n\n});\n\n$.ui.plugin.add(\"draggable\", \"connectToSortable\", {\n\tstart: function(event, ui) {\n\n\t\tvar inst = $(this).data(\"ui-draggable\"), o = inst.options,\n\t\t\tuiSortable = $.extend({}, ui, { item: inst.element });\n\t\tinst.sortables = [];\n\t\t$(o.connectToSortable).each(function() {\n\t\t\tvar sortable = $.data(this, \"ui-sortable\");\n\t\t\tif (sortable && !sortable.options.disabled) {\n\t\t\t\tinst.sortables.push({\n\t\t\t\t\tinstance: sortable,\n\t\t\t\t\tshouldRevert: sortable.options.revert\n\t\t\t\t});\n\t\t\t\tsortable.refreshPositions();\t// Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).\n\t\t\t\tsortable._trigger(\"activate\", event, uiSortable);\n\t\t\t}\n\t\t});\n\n\t},\n\tstop: function(event, ui) {\n\n\t\t//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper\n\t\tvar inst = $(this).data(\"ui-draggable\"),\n\t\t\tuiSortable = $.extend({}, ui, { item: inst.element });\n\n\t\t$.each(inst.sortables, function() {\n\t\t\tif(this.instance.isOver) {\n\n\t\t\t\tthis.instance.isOver = 0;\n\n\t\t\t\tinst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance\n\t\t\t\tthis.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)\n\n\t\t\t\t//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: \"valid/invalid\"\n\t\t\t\tif(this.shouldRevert) {\n\t\t\t\t\tthis.instance.options.revert = true;\n\t\t\t\t}\n\n\t\t\t\t//Trigger the stop of the sortable\n\t\t\t\tthis.instance._mouseStop(event);\n\n\t\t\t\tthis.instance.options.helper = this.instance.options._helper;\n\n\t\t\t\t//If the helper has been the original item, restore properties in the sortable\n\t\t\t\tif(inst.options.helper === \"original\") {\n\t\t\t\t\tthis.instance.currentItem.css({ top: \"auto\", left: \"auto\" });\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tthis.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance\n\t\t\t\tthis.instance._trigger(\"deactivate\", event, uiSortable);\n\t\t\t}\n\n\t\t});\n\n\t},\n\tdrag: function(event, ui) {\n\n\t\tvar inst = $(this).data(\"ui-draggable\"), that = this;\n\n\t\t$.each(inst.sortables, function() {\n\n\t\t\tvar innermostIntersecting = false,\n\t\t\t\tthisSortable = this;\n\n\t\t\t//Copy over some variables to allow calling the sortable's native _intersectsWith\n\t\t\tthis.instance.positionAbs = inst.positionAbs;\n\t\t\tthis.instance.helperProportions = inst.helperProportions;\n\t\t\tthis.instance.offset.click = inst.offset.click;\n\n\t\t\tif(this.instance._intersectsWith(this.instance.containerCache)) {\n\t\t\t\tinnermostIntersecting = true;\n\t\t\t\t$.each(inst.sortables, function () {\n\t\t\t\t\tthis.instance.positionAbs = inst.positionAbs;\n\t\t\t\t\tthis.instance.helperProportions = inst.helperProportions;\n\t\t\t\t\tthis.instance.offset.click = inst.offset.click;\n\t\t\t\t\tif (this !== thisSortable &&\n\t\t\t\t\t\tthis.instance._intersectsWith(this.instance.containerCache) &&\n\t\t\t\t\t\t$.contains(thisSortable.instance.element[0], this.instance.element[0])\n\t\t\t\t\t) {\n\t\t\t\t\t\tinnermostIntersecting = false;\n\t\t\t\t\t}\n\t\t\t\t\treturn innermostIntersecting;\n\t\t\t\t});\n\t\t\t}\n\n\n\t\t\tif(innermostIntersecting) {\n\t\t\t\t//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once\n\t\t\t\tif(!this.instance.isOver) {\n\n\t\t\t\t\tthis.instance.isOver = 1;\n\t\t\t\t\t//Now we fake the start of dragging for the sortable instance,\n\t\t\t\t\t//by cloning the list group item, appending it to the sortable and using it as inst.currentItem\n\t\t\t\t\t//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)\n\t\t\t\t\tthis.instance.currentItem = $(that).clone().removeAttr(\"id\").appendTo(this.instance.element).data(\"ui-sortable-item\", true);\n\t\t\t\t\tthis.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it\n\t\t\t\t\tthis.instance.options.helper = function() { return ui.helper[0]; };\n\n\t\t\t\t\tevent.target = this.instance.currentItem[0];\n\t\t\t\t\tthis.instance._mouseCapture(event, true);\n\t\t\t\t\tthis.instance._mouseStart(event, true, true);\n\n\t\t\t\t\t//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes\n\t\t\t\t\tthis.instance.offset.click.top = inst.offset.click.top;\n\t\t\t\t\tthis.instance.offset.click.left = inst.offset.click.left;\n\t\t\t\t\tthis.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;\n\t\t\t\t\tthis.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;\n\n\t\t\t\t\tinst._trigger(\"toSortable\", event);\n\t\t\t\t\tinst.dropped = this.instance.element; //draggable revert needs that\n\t\t\t\t\t//hack so receive/update callbacks work (mostly)\n\t\t\t\t\tinst.currentItem = inst.element;\n\t\t\t\t\tthis.instance.fromOutside = inst;\n\n\t\t\t\t}\n\n\t\t\t\t//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable\n\t\t\t\tif(this.instance.currentItem) {\n\t\t\t\t\tthis.instance._mouseDrag(event);\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t//If it doesn't intersect with the sortable, and it intersected before,\n\t\t\t\t//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval\n\t\t\t\tif(this.instance.isOver) {\n\n\t\t\t\t\tthis.instance.isOver = 0;\n\t\t\t\t\tthis.instance.cancelHelperRemoval = true;\n\n\t\t\t\t\t//Prevent reverting on this forced stop\n\t\t\t\t\tthis.instance.options.revert = false;\n\n\t\t\t\t\t// The out event needs to be triggered independently\n\t\t\t\t\tthis.instance._trigger(\"out\", event, this.instance._uiHash(this.instance));\n\n\t\t\t\t\tthis.instance._mouseStop(event, true);\n\t\t\t\t\tthis.instance.options.helper = this.instance.options._helper;\n\n\t\t\t\t\t//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size\n\t\t\t\t\tthis.instance.currentItem.remove();\n\t\t\t\t\tif(this.instance.placeholder) {\n\t\t\t\t\t\tthis.instance.placeholder.remove();\n\t\t\t\t\t}\n\n\t\t\t\t\tinst._trigger(\"fromSortable\", event);\n\t\t\t\t\tinst.dropped = false; //draggable revert needs that\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t});\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"cursor\", {\n\tstart: function() {\n\t\tvar t = $(\"body\"), o = $(this).data(\"ui-draggable\").options;\n\t\tif (t.css(\"cursor\")) {\n\t\t\to._cursor = t.css(\"cursor\");\n\t\t}\n\t\tt.css(\"cursor\", o.cursor);\n\t},\n\tstop: function() {\n\t\tvar o = $(this).data(\"ui-draggable\").options;\n\t\tif (o._cursor) {\n\t\t\t$(\"body\").css(\"cursor\", o._cursor);\n\t\t}\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"opacity\", {\n\tstart: function(event, ui) {\n\t\tvar t = $(ui.helper), o = $(this).data(\"ui-draggable\").options;\n\t\tif(t.css(\"opacity\")) {\n\t\t\to._opacity = t.css(\"opacity\");\n\t\t}\n\t\tt.css(\"opacity\", o.opacity);\n\t},\n\tstop: function(event, ui) {\n\t\tvar o = $(this).data(\"ui-draggable\").options;\n\t\tif(o._opacity) {\n\t\t\t$(ui.helper).css(\"opacity\", o._opacity);\n\t\t}\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"scroll\", {\n\tstart: function() {\n\t\tvar i = $(this).data(\"ui-draggable\");\n\t\tif(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== \"HTML\") {\n\t\t\ti.overflowOffset = i.scrollParent.offset();\n\t\t}\n\t},\n\tdrag: function( event ) {\n\n\t\tvar i = $(this).data(\"ui-draggable\"), o = i.options, scrolled = false;\n\n\t\tif(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== \"HTML\") {\n\n\t\t\tif(!o.axis || o.axis !== \"x\") {\n\t\t\t\tif((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {\n\t\t\t\t\ti.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;\n\t\t\t\t} else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {\n\t\t\t\t\ti.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(!o.axis || o.axis !== \"y\") {\n\t\t\t\tif((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {\n\t\t\t\t\ti.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;\n\t\t\t\t} else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {\n\t\t\t\t\ti.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif(!o.axis || o.axis !== \"x\") {\n\t\t\t\tif(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);\n\t\t\t\t} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(!o.axis || o.axis !== \"y\") {\n\t\t\t\tif(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);\n\t\t\t\t} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tif(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {\n\t\t\t$.ui.ddmanager.prepareOffsets(i, event);\n\t\t}\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"snap\", {\n\tstart: function() {\n\n\t\tvar i = $(this).data(\"ui-draggable\"),\n\t\t\to = i.options;\n\n\t\ti.snapElements = [];\n\n\t\t$(o.snap.constructor !== String ? ( o.snap.items || \":data(ui-draggable)\" ) : o.snap).each(function() {\n\t\t\tvar $t = $(this),\n\t\t\t\t$o = $t.offset();\n\t\t\tif(this !== i.element[0]) {\n\t\t\t\ti.snapElements.push({\n\t\t\t\t\titem: this,\n\t\t\t\t\twidth: $t.outerWidth(), height: $t.outerHeight(),\n\t\t\t\t\ttop: $o.top, left: $o.left\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t},\n\tdrag: function(event, ui) {\n\n\t\tvar ts, bs, ls, rs, l, r, t, b, i, first,\n\t\t\tinst = $(this).data(\"ui-draggable\"),\n\t\t\to = inst.options,\n\t\t\td = o.snapTolerance,\n\t\t\tx1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,\n\t\t\ty1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;\n\n\t\tfor (i = inst.snapElements.length - 1; i >= 0; i--){\n\n\t\t\tl = inst.snapElements[i].left;\n\t\t\tr = l + inst.snapElements[i].width;\n\t\t\tt = inst.snapElements[i].top;\n\t\t\tb = t + inst.snapElements[i].height;\n\n\t\t\t//Yes, I know, this is insane ;)\n\t\t\tif(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {\n\t\t\t\tif(inst.snapElements[i].snapping) {\n\t\t\t\t\t(inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));\n\t\t\t\t}\n\t\t\t\tinst.snapElements[i].snapping = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(o.snapMode !== \"inner\") {\n\t\t\t\tts = Math.abs(t - y2) <= d;\n\t\t\t\tbs = Math.abs(b - y1) <= d;\n\t\t\t\tls = Math.abs(l - x2) <= d;\n\t\t\t\trs = Math.abs(r - x1) <= d;\n\t\t\t\tif(ts) {\n\t\t\t\t\tui.position.top = inst._convertPositionTo(\"relative\", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;\n\t\t\t\t}\n\t\t\t\tif(bs) {\n\t\t\t\t\tui.position.top = inst._convertPositionTo(\"relative\", { top: b, left: 0 }).top - inst.margins.top;\n\t\t\t\t}\n\t\t\t\tif(ls) {\n\t\t\t\t\tui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;\n\t\t\t\t}\n\t\t\t\tif(rs) {\n\t\t\t\t\tui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: r }).left - inst.margins.left;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfirst = (ts || bs || ls || rs);\n\n\t\t\tif(o.snapMode !== \"outer\") {\n\t\t\t\tts = Math.abs(t - y1) <= d;\n\t\t\t\tbs = Math.abs(b - y2) <= d;\n\t\t\t\tls = Math.abs(l - x1) <= d;\n\t\t\t\trs = Math.abs(r - x2) <= d;\n\t\t\t\tif(ts) {\n\t\t\t\t\tui.position.top = inst._convertPositionTo(\"relative\", { top: t, left: 0 }).top - inst.margins.top;\n\t\t\t\t}\n\t\t\t\tif(bs) {\n\t\t\t\t\tui.position.top = inst._convertPositionTo(\"relative\", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;\n\t\t\t\t}\n\t\t\t\tif(ls) {\n\t\t\t\t\tui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: l }).left - inst.margins.left;\n\t\t\t\t}\n\t\t\t\tif(rs) {\n\t\t\t\t\tui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {\n\t\t\t\t(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));\n\t\t\t}\n\t\t\tinst.snapElements[i].snapping = (ts || bs || ls || rs || first);\n\n\t\t}\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"stack\", {\n\tstart: function() {\n\t\tvar min,\n\t\t\to = this.data(\"ui-draggable\").options,\n\t\t\tgroup = $.makeArray($(o.stack)).sort(function(a,b) {\n\t\t\t\treturn (parseInt($(a).css(\"zIndex\"),10) || 0) - (parseInt($(b).css(\"zIndex\"),10) || 0);\n\t\t\t});\n\n\t\tif (!group.length) { return; }\n\n\t\tmin = parseInt($(group[0]).css(\"zIndex\"), 10) || 0;\n\t\t$(group).each(function(i) {\n\t\t\t$(this).css(\"zIndex\", min + i);\n\t\t});\n\t\tthis.css(\"zIndex\", (min + group.length));\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"zIndex\", {\n\tstart: function(event, ui) {\n\t\tvar t = $(ui.helper), o = $(this).data(\"ui-draggable\").options;\n\t\tif(t.css(\"zIndex\")) {\n\t\t\to._zIndex = t.css(\"zIndex\");\n\t\t}\n\t\tt.css(\"zIndex\", o.zIndex);\n\t},\n\tstop: function(event, ui) {\n\t\tvar o = $(this).data(\"ui-draggable\").options;\n\t\tif(o._zIndex) {\n\t\t\t$(ui.helper).css(\"zIndex\", o._zIndex);\n\t\t}\n\t}\n});\n\n})(jQuery);\n\n(function( $, undefined ) {\n\nfunction isOverAxis( x, reference, size ) {\n\treturn ( x > reference ) && ( x < ( reference + size ) );\n}\n\n$.widget(\"ui.droppable\", {\n\tversion: \"1.10.1\",\n\twidgetEventPrefix: \"drop\",\n\toptions: {\n\t\taccept: \"*\",\n\t\tactiveClass: false,\n\t\taddClasses: true,\n\t\tgreedy: false,\n\t\thoverClass: false,\n\t\tscope: \"default\",\n\t\ttolerance: \"intersect\",\n\n\t\t// callbacks\n\t\tactivate: null,\n\t\tdeactivate: null,\n\t\tdrop: null,\n\t\tout: null,\n\t\tover: null\n\t},\n\t_create: function() {\n\n\t\tvar o = this.options,\n\t\t\taccept = o.accept;\n\n\t\tthis.isover = false;\n\t\tthis.isout = true;\n\n\t\tthis.accept = $.isFunction(accept) ? accept : function(d) {\n\t\t\treturn d.is(accept);\n\t\t};\n\n\t\t//Store the droppable's proportions\n\t\tthis.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };\n\n\t\t// Add the reference and positions to the manager\n\t\t$.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];\n\t\t$.ui.ddmanager.droppables[o.scope].push(this);\n\n\t\t(o.addClasses && this.element.addClass(\"ui-droppable\"));\n\n\t},\n\n\t_destroy: function() {\n\t\tvar i = 0,\n\t\t\tdrop = $.ui.ddmanager.droppables[this.options.scope];\n\n\t\tfor ( ; i < drop.length; i++ ) {\n\t\t\tif ( drop[i] === this ) {\n\t\t\t\tdrop.splice(i, 1);\n\t\t\t}\n\t\t}\n\n\t\tthis.element.removeClass(\"ui-droppable ui-droppable-disabled\");\n\t},\n\n\t_setOption: function(key, value) {\n\n\t\tif(key === \"accept\") {\n\t\t\tthis.accept = $.isFunction(value) ? value : function(d) {\n\t\t\t\treturn d.is(value);\n\t\t\t};\n\t\t}\n\t\t$.Widget.prototype._setOption.apply(this, arguments);\n\t},\n\n\t_activate: function(event) {\n\t\tvar draggable = $.ui.ddmanager.current;\n\t\tif(this.options.activeClass) {\n\t\t\tthis.element.addClass(this.options.activeClass);\n\t\t}\n\t\tif(draggable){\n\t\t\tthis._trigger(\"activate\", event, this.ui(draggable));\n\t\t}\n\t},\n\n\t_deactivate: function(event) {\n\t\tvar draggable = $.ui.ddmanager.current;\n\t\tif(this.options.activeClass) {\n\t\t\tthis.element.removeClass(this.options.activeClass);\n\t\t}\n\t\tif(draggable){\n\t\t\tthis._trigger(\"deactivate\", event, this.ui(draggable));\n\t\t}\n\t},\n\n\t_over: function(event) {\n\n\t\tvar draggable = $.ui.ddmanager.current;\n\n\t\t// Bail if draggable and droppable are same element\n\t\tif (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\tif(this.options.hoverClass) {\n\t\t\t\tthis.element.addClass(this.options.hoverClass);\n\t\t\t}\n\t\t\tthis._trigger(\"over\", event, this.ui(draggable));\n\t\t}\n\n\t},\n\n\t_out: function(event) {\n\n\t\tvar draggable = $.ui.ddmanager.current;\n\n\t\t// Bail if draggable and droppable are same element\n\t\tif (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\tif(this.options.hoverClass) {\n\t\t\t\tthis.element.removeClass(this.options.hoverClass);\n\t\t\t}\n\t\t\tthis._trigger(\"out\", event, this.ui(draggable));\n\t\t}\n\n\t},\n\n\t_drop: function(event,custom) {\n\n\t\tvar draggable = custom || $.ui.ddmanager.current,\n\t\t\tchildrenIntersection = false;\n\n\t\t// Bail if draggable and droppable are same element\n\t\tif (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.element.find(\":data(ui-droppable)\").not(\".ui-draggable-dragging\").each(function() {\n\t\t\tvar inst = $.data(this, \"ui-droppable\");\n\t\t\tif(\n\t\t\t\tinst.options.greedy &&\n\t\t\t\t!inst.options.disabled &&\n\t\t\t\tinst.options.scope === draggable.options.scope &&\n\t\t\t\tinst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&\n\t\t\t\t$.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)\n\t\t\t) { childrenIntersection = true; return false; }\n\t\t});\n\t\tif(childrenIntersection) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\tif(this.options.activeClass) {\n\t\t\t\tthis.element.removeClass(this.options.activeClass);\n\t\t\t}\n\t\t\tif(this.options.hoverClass) {\n\t\t\t\tthis.element.removeClass(this.options.hoverClass);\n\t\t\t}\n\t\t\tthis._trigger(\"drop\", event, this.ui(draggable));\n\t\t\treturn this.element;\n\t\t}\n\n\t\treturn false;\n\n\t},\n\n\tui: function(c) {\n\t\treturn {\n\t\t\tdraggable: (c.currentItem || c.element),\n\t\t\thelper: c.helper,\n\t\t\tposition: c.position,\n\t\t\toffset: c.positionAbs\n\t\t};\n\t}\n\n});\n\n$.ui.intersect = function(draggable, droppable, toleranceMode) {\n\n\tif (!droppable.offset) {\n\t\treturn false;\n\t}\n\n\tvar draggableLeft, draggableTop,\n\t\tx1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,\n\t\ty1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,\n\t\tl = droppable.offset.left, r = l + droppable.proportions.width,\n\t\tt = droppable.offset.top, b = t + droppable.proportions.height;\n\n\tswitch (toleranceMode) {\n\t\tcase \"fit\":\n\t\t\treturn (l <= x1 && x2 <= r && t <= y1 && y2 <= b);\n\t\tcase \"intersect\":\n\t\t\treturn (l < x1 + (draggable.helperProportions.width / 2) && // Right Half\n\t\t\t\tx2 - (draggable.helperProportions.width / 2) < r && // Left Half\n\t\t\t\tt < y1 + (draggable.helperProportions.height / 2) && // Bottom Half\n\t\t\t\ty2 - (draggable.helperProportions.height / 2) < b ); // Top Half\n\t\tcase \"pointer\":\n\t\t\tdraggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);\n\t\t\tdraggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);\n\t\t\treturn isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );\n\t\tcase \"touch\":\n\t\t\treturn (\n\t\t\t\t(y1 >= t && y1 <= b) ||\t// Top edge touching\n\t\t\t\t(y2 >= t && y2 <= b) ||\t// Bottom edge touching\n\t\t\t\t(y1 < t && y2 > b)\t\t// Surrounded vertically\n\t\t\t) && (\n\t\t\t\t(x1 >= l && x1 <= r) ||\t// Left edge touching\n\t\t\t\t(x2 >= l && x2 <= r) ||\t// Right edge touching\n\t\t\t\t(x1 < l && x2 > r)\t\t// Surrounded horizontally\n\t\t\t);\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n};\n\n/*\n\tThis manager tracks offsets of draggables and droppables\n*/\n$.ui.ddmanager = {\n\tcurrent: null,\n\tdroppables: { \"default\": [] },\n\tprepareOffsets: function(t, event) {\n\n\t\tvar i, j,\n\t\t\tm = $.ui.ddmanager.droppables[t.options.scope] || [],\n\t\t\ttype = event ? event.type : null, // workaround for #2317\n\t\t\tlist = (t.currentItem || t.element).find(\":data(ui-droppable)\").addBack();\n\n\t\tdroppablesLoop: for (i = 0; i < m.length; i++) {\n\n\t\t\t//No disabled and non-accepted\n\t\t\tif(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Filter out elements in the current dragged item\n\t\t\tfor (j=0; j < list.length; j++) {\n\t\t\t\tif(list[j] === m[i].element[0]) {\n\t\t\t\t\tm[i].proportions.height = 0;\n\t\t\t\t\tcontinue droppablesLoop;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm[i].visible = m[i].element.css(\"display\") !== \"none\";\n\t\t\tif(!m[i].visible) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//Activate the droppable if used directly from draggables\n\t\t\tif(type === \"mousedown\") {\n\t\t\t\tm[i]._activate.call(m[i], event);\n\t\t\t}\n\n\t\t\tm[i].offset = m[i].element.offset();\n\t\t\tm[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };\n\n\t\t}\n\n\t},\n\tdrop: function(draggable, event) {\n\n\t\tvar dropped = false;\n\t\t$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {\n\n\t\t\tif(!this.options) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {\n\t\t\t\tdropped = this._drop.call(this, event) || dropped;\n\t\t\t}\n\n\t\t\tif (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\t\tthis.isout = true;\n\t\t\t\tthis.isover = false;\n\t\t\t\tthis._deactivate.call(this, event);\n\t\t\t}\n\n\t\t});\n\t\treturn dropped;\n\n\t},\n\tdragStart: function( draggable, event ) {\n\t\t//Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)\n\t\tdraggable.element.parentsUntil( \"body\" ).bind( \"scroll.droppable\", function() {\n\t\t\tif( !draggable.options.refreshPositions ) {\n\t\t\t\t$.ui.ddmanager.prepareOffsets( draggable, event );\n\t\t\t}\n\t\t});\n\t},\n\tdrag: function(draggable, event) {\n\n\t\t//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.\n\t\tif(draggable.options.refreshPositions) {\n\t\t\t$.ui.ddmanager.prepareOffsets(draggable, event);\n\t\t}\n\n\t\t//Run through all droppables and check their positions based on specific tolerance options\n\t\t$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {\n\n\t\t\tif(this.options.disabled || this.greedyChild || !this.visible) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar parentInstance, scope, parent,\n\t\t\t\tintersects = $.ui.intersect(draggable, this, this.options.tolerance),\n\t\t\t\tc = !intersects && this.isover ? \"isout\" : (intersects && !this.isover ? \"isover\" : null);\n\t\t\tif(!c) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this.options.greedy) {\n\t\t\t\t// find droppable parents with same scope\n\t\t\t\tscope = this.options.scope;\n\t\t\t\tparent = this.element.parents(\":data(ui-droppable)\").filter(function () {\n\t\t\t\t\treturn $.data(this, \"ui-droppable\").options.scope === scope;\n\t\t\t\t});\n\n\t\t\t\tif (parent.length) {\n\t\t\t\t\tparentInstance = $.data(parent[0], \"ui-droppable\");\n\t\t\t\t\tparentInstance.greedyChild = (c === \"isover\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// we just moved into a greedy child\n\t\t\tif (parentInstance && c === \"isover\") {\n\t\t\t\tparentInstance.isover = false;\n\t\t\t\tparentInstance.isout = true;\n\t\t\t\tparentInstance._out.call(parentInstance, event);\n\t\t\t}\n\n\t\t\tthis[c] = true;\n\t\t\tthis[c === \"isout\" ? \"isover\" : \"isout\"] = false;\n\t\t\tthis[c === \"isover\" ? \"_over\" : \"_out\"].call(this, event);\n\n\t\t\t// we just moved out of a greedy child\n\t\t\tif (parentInstance && c === \"isout\") {\n\t\t\t\tparentInstance.isout = false;\n\t\t\t\tparentInstance.isover = true;\n\t\t\t\tparentInstance._over.call(parentInstance, event);\n\t\t\t}\n\t\t});\n\n\t},\n\tdragStop: function( draggable, event ) {\n\t\tdraggable.element.parentsUntil( \"body\" ).unbind( \"scroll.droppable\" );\n\t\t//Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)\n\t\tif( !draggable.options.refreshPositions ) {\n\t\t\t$.ui.ddmanager.prepareOffsets( draggable, event );\n\t\t}\n\t}\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\nfunction num(v) {\n\treturn parseInt(v, 10) || 0;\n}\n\nfunction isNumber(value) {\n\treturn !isNaN(parseInt(value, 10));\n}\n\n$.widget(\"ui.resizable\", $.ui.mouse, {\n\tversion: \"1.10.1\",\n\twidgetEventPrefix: \"resize\",\n\toptions: {\n\t\talsoResize: false,\n\t\tanimate: false,\n\t\tanimateDuration: \"slow\",\n\t\tanimateEasing: \"swing\",\n\t\taspectRatio: false,\n\t\tautoHide: false,\n\t\tcontainment: false,\n\t\tghost: false,\n\t\tgrid: false,\n\t\thandles: \"e,s,se\",\n\t\thelper: false,\n\t\tmaxHeight: null,\n\t\tmaxWidth: null,\n\t\tminHeight: 10,\n\t\tminWidth: 10,\n\t\t// See #7960\n\t\tzIndex: 90,\n\n\t\t// callbacks\n\t\tresize: null,\n\t\tstart: null,\n\t\tstop: null\n\t},\n\t_create: function() {\n\n\t\tvar n, i, handle, axis, hname,\n\t\t\tthat = this,\n\t\t\to = this.options;\n\t\tthis.element.addClass(\"ui-resizable\");\n\n\t\t$.extend(this, {\n\t\t\t_aspectRatio: !!(o.aspectRatio),\n\t\t\taspectRatio: o.aspectRatio,\n\t\t\toriginalElement: this.element,\n\t\t\t_proportionallyResizeElements: [],\n\t\t\t_helper: o.helper || o.ghost || o.animate ? o.helper || \"ui-resizable-helper\" : null\n\t\t});\n\n\t\t//Wrap the element if it cannot hold child nodes\n\t\tif(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {\n\n\t\t\t//Create a wrapper element and set the wrapper to the new current internal element\n\t\t\tthis.element.wrap(\n\t\t\t\t$(\"<div class='ui-wrapper' style='overflow: hidden;'></div>\").css({\n\t\t\t\t\tposition: this.element.css(\"position\"),\n\t\t\t\t\twidth: this.element.outerWidth(),\n\t\t\t\t\theight: this.element.outerHeight(),\n\t\t\t\t\ttop: this.element.css(\"top\"),\n\t\t\t\t\tleft: this.element.css(\"left\")\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t//Overwrite the original this.element\n\t\t\tthis.element = this.element.parent().data(\n\t\t\t\t\"ui-resizable\", this.element.data(\"ui-resizable\")\n\t\t\t);\n\n\t\t\tthis.elementIsWrapper = true;\n\n\t\t\t//Move margins to the wrapper\n\t\t\tthis.element.css({ marginLeft: this.originalElement.css(\"marginLeft\"), marginTop: this.originalElement.css(\"marginTop\"), marginRight: this.originalElement.css(\"marginRight\"), marginBottom: this.originalElement.css(\"marginBottom\") });\n\t\t\tthis.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});\n\n\t\t\t//Prevent Safari textarea resize\n\t\t\tthis.originalResizeStyle = this.originalElement.css(\"resize\");\n\t\t\tthis.originalElement.css(\"resize\", \"none\");\n\n\t\t\t//Push the actual element to our proportionallyResize internal array\n\t\t\tthis._proportionallyResizeElements.push(this.originalElement.css({ position: \"static\", zoom: 1, display: \"block\" }));\n\n\t\t\t// avoid IE jump (hard set the margin)\n\t\t\tthis.originalElement.css({ margin: this.originalElement.css(\"margin\") });\n\n\t\t\t// fix handlers offset\n\t\t\tthis._proportionallyResize();\n\n\t\t}\n\n\t\tthis.handles = o.handles || (!$(\".ui-resizable-handle\", this.element).length ? \"e,s,se\" : { n: \".ui-resizable-n\", e: \".ui-resizable-e\", s: \".ui-resizable-s\", w: \".ui-resizable-w\", se: \".ui-resizable-se\", sw: \".ui-resizable-sw\", ne: \".ui-resizable-ne\", nw: \".ui-resizable-nw\" });\n\t\tif(this.handles.constructor === String) {\n\n\t\t\tif ( this.handles === \"all\") {\n\t\t\t\tthis.handles = \"n,e,s,w,se,sw,ne,nw\";\n\t\t\t}\n\n\t\t\tn = this.handles.split(\",\");\n\t\t\tthis.handles = {};\n\n\t\t\tfor(i = 0; i < n.length; i++) {\n\n\t\t\t\thandle = $.trim(n[i]);\n\t\t\t\thname = \"ui-resizable-\"+handle;\n\t\t\t\taxis = $(\"<div class='ui-resizable-handle \" + hname + \"'></div>\");\n\n\t\t\t\t// Apply zIndex to all handles - see #7960\n\t\t\t\taxis.css({ zIndex: o.zIndex });\n\n\t\t\t\t//TODO : What's going on here?\n\t\t\t\tif (\"se\" === handle) {\n\t\t\t\t\taxis.addClass(\"ui-icon ui-icon-gripsmall-diagonal-se\");\n\t\t\t\t}\n\n\t\t\t\t//Insert into internal handles object and append to element\n\t\t\t\tthis.handles[handle] = \".ui-resizable-\"+handle;\n\t\t\t\tthis.element.append(axis);\n\t\t\t}\n\n\t\t}\n\n\t\tthis._renderAxis = function(target) {\n\n\t\t\tvar i, axis, padPos, padWrapper;\n\n\t\t\ttarget = target || this.element;\n\n\t\t\tfor(i in this.handles) {\n\n\t\t\t\tif(this.handles[i].constructor === String) {\n\t\t\t\t\tthis.handles[i] = $(this.handles[i], this.element).show();\n\t\t\t\t}\n\n\t\t\t\t//Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)\n\t\t\t\tif (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {\n\n\t\t\t\t\taxis = $(this.handles[i], this.element);\n\n\t\t\t\t\t//Checking the correct pad and border\n\t\t\t\t\tpadWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();\n\n\t\t\t\t\t//The padding type i have to apply...\n\t\t\t\t\tpadPos = [ \"padding\",\n\t\t\t\t\t\t/ne|nw|n/.test(i) ? \"Top\" :\n\t\t\t\t\t\t/se|sw|s/.test(i) ? \"Bottom\" :\n\t\t\t\t\t\t/^e$/.test(i) ? \"Right\" : \"Left\" ].join(\"\");\n\n\t\t\t\t\ttarget.css(padPos, padWrapper);\n\n\t\t\t\t\tthis._proportionallyResize();\n\n\t\t\t\t}\n\n\t\t\t\t//TODO: What's that good for? There's not anything to be executed left\n\t\t\t\tif(!$(this.handles[i]).length) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t//TODO: make renderAxis a prototype function\n\t\tthis._renderAxis(this.element);\n\n\t\tthis._handles = $(\".ui-resizable-handle\", this.element)\n\t\t\t.disableSelection();\n\n\t\t//Matching axis name\n\t\tthis._handles.mouseover(function() {\n\t\t\tif (!that.resizing) {\n\t\t\t\tif (this.className) {\n\t\t\t\t\taxis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);\n\t\t\t\t}\n\t\t\t\t//Axis, default = se\n\t\t\t\tthat.axis = axis && axis[1] ? axis[1] : \"se\";\n\t\t\t}\n\t\t});\n\n\t\t//If we want to auto hide the elements\n\t\tif (o.autoHide) {\n\t\t\tthis._handles.hide();\n\t\t\t$(this.element)\n\t\t\t\t.addClass(\"ui-resizable-autohide\")\n\t\t\t\t.mouseenter(function() {\n\t\t\t\t\tif (o.disabled) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t$(this).removeClass(\"ui-resizable-autohide\");\n\t\t\t\t\tthat._handles.show();\n\t\t\t\t})\n\t\t\t\t.mouseleave(function(){\n\t\t\t\t\tif (o.disabled) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!that.resizing) {\n\t\t\t\t\t\t$(this).addClass(\"ui-resizable-autohide\");\n\t\t\t\t\t\tthat._handles.hide();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\t//Initialize the mouse interaction\n\t\tthis._mouseInit();\n\n\t},\n\n\t_destroy: function() {\n\n\t\tthis._mouseDestroy();\n\n\t\tvar wrapper,\n\t\t\t_destroy = function(exp) {\n\t\t\t\t$(exp).removeClass(\"ui-resizable ui-resizable-disabled ui-resizable-resizing\")\n\t\t\t\t\t.removeData(\"resizable\").removeData(\"ui-resizable\").unbind(\".resizable\").find(\".ui-resizable-handle\").remove();\n\t\t\t};\n\n\t\t//TODO: Unwrap at same DOM position\n\t\tif (this.elementIsWrapper) {\n\t\t\t_destroy(this.element);\n\t\t\twrapper = this.element;\n\t\t\tthis.originalElement.css({\n\t\t\t\tposition: wrapper.css(\"position\"),\n\t\t\t\twidth: wrapper.outerWidth(),\n\t\t\t\theight: wrapper.outerHeight(),\n\t\t\t\ttop: wrapper.css(\"top\"),\n\t\t\t\tleft: wrapper.css(\"left\")\n\t\t\t}).insertAfter( wrapper );\n\t\t\twrapper.remove();\n\t\t}\n\n\t\tthis.originalElement.css(\"resize\", this.originalResizeStyle);\n\t\t_destroy(this.originalElement);\n\n\t\treturn this;\n\t},\n\n\t_mouseCapture: function(event) {\n\t\tvar i, handle,\n\t\t\tcapture = false;\n\n\t\tfor (i in this.handles) {\n\t\t\thandle = $(this.handles[i])[0];\n\t\t\tif (handle === event.target || $.contains(handle, event.target)) {\n\t\t\t\tcapture = true;\n\t\t\t}\n\t\t}\n\n\t\treturn !this.options.disabled && capture;\n\t},\n\n\t_mouseStart: function(event) {\n\n\t\tvar curleft, curtop, cursor,\n\t\t\to = this.options,\n\t\t\tiniPos = this.element.position(),\n\t\t\tel = this.element;\n\n\t\tthis.resizing = true;\n\n\t\t// bugfix for http://dev.jquery.com/ticket/1749\n\t\tif ( (/absolute/).test( el.css(\"position\") ) ) {\n\t\t\tel.css({ position: \"absolute\", top: el.css(\"top\"), left: el.css(\"left\") });\n\t\t} else if (el.is(\".ui-draggable\")) {\n\t\t\tel.css({ position: \"absolute\", top: iniPos.top, left: iniPos.left });\n\t\t}\n\n\t\tthis._renderProxy();\n\n\t\tcurleft = num(this.helper.css(\"left\"));\n\t\tcurtop = num(this.helper.css(\"top\"));\n\n\t\tif (o.containment) {\n\t\t\tcurleft += $(o.containment).scrollLeft() || 0;\n\t\t\tcurtop += $(o.containment).scrollTop() || 0;\n\t\t}\n\n\t\t//Store needed variables\n\t\tthis.offset = this.helper.offset();\n\t\tthis.position = { left: curleft, top: curtop };\n\t\tthis.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };\n\t\tthis.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };\n\t\tthis.originalPosition = { left: curleft, top: curtop };\n\t\tthis.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };\n\t\tthis.originalMousePosition = { left: event.pageX, top: event.pageY };\n\n\t\t//Aspect Ratio\n\t\tthis.aspectRatio = (typeof o.aspectRatio === \"number\") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);\n\n\t\tcursor = $(\".ui-resizable-\" + this.axis).css(\"cursor\");\n\t\t$(\"body\").css(\"cursor\", cursor === \"auto\" ? this.axis + \"-resize\" : cursor);\n\n\t\tel.addClass(\"ui-resizable-resizing\");\n\t\tthis._propagate(\"start\", event);\n\t\treturn true;\n\t},\n\n\t_mouseDrag: function(event) {\n\n\t\t//Increase performance, avoid regex\n\t\tvar data,\n\t\t\tel = this.helper, props = {},\n\t\t\tsmp = this.originalMousePosition,\n\t\t\ta = this.axis,\n\t\t\tprevTop = this.position.top,\n\t\t\tprevLeft = this.position.left,\n\t\t\tprevWidth = this.size.width,\n\t\t\tprevHeight = this.size.height,\n\t\t\tdx = (event.pageX-smp.left)||0,\n\t\t\tdy = (event.pageY-smp.top)||0,\n\t\t\ttrigger = this._change[a];\n\n\t\tif (!trigger) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Calculate the attrs that will be change\n\t\tdata = trigger.apply(this, [event, dx, dy]);\n\n\t\t// Put this in the mouseDrag handler since the user can start pressing shift while resizing\n\t\tthis._updateVirtualBoundaries(event.shiftKey);\n\t\tif (this._aspectRatio || event.shiftKey) {\n\t\t\tdata = this._updateRatio(data, event);\n\t\t}\n\n\t\tdata = this._respectSize(data, event);\n\n\t\tthis._updateCache(data);\n\n\t\t// plugins callbacks need to be called first\n\t\tthis._propagate(\"resize\", event);\n\n\t\tif (this.position.top !== prevTop) {\n\t\t\tprops.top = this.position.top + \"px\";\n\t\t}\n\t\tif (this.position.left !== prevLeft) {\n\t\t\tprops.left = this.position.left + \"px\";\n\t\t}\n\t\tif (this.size.width !== prevWidth) {\n\t\t\tprops.width = this.size.width + \"px\";\n\t\t}\n\t\tif (this.size.height !== prevHeight) {\n\t\t\tprops.height = this.size.height + \"px\";\n\t\t}\n\t\tel.css(props);\n\n\t\tif (!this._helper && this._proportionallyResizeElements.length) {\n\t\t\tthis._proportionallyResize();\n\t\t}\n\n\t\t// Call the user callback if the element was resized\n\t\tif ( ! $.isEmptyObject(props) ) {\n\t\t\tthis._trigger(\"resize\", event, this.ui());\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function(event) {\n\n\t\tthis.resizing = false;\n\t\tvar pr, ista, soffseth, soffsetw, s, left, top,\n\t\t\to = this.options, that = this;\n\n\t\tif(this._helper) {\n\n\t\t\tpr = this._proportionallyResizeElements;\n\t\t\tista = pr.length && (/textarea/i).test(pr[0].nodeName);\n\t\t\tsoffseth = ista && $.ui.hasScroll(pr[0], \"left\") /* TODO - jump height */ ? 0 : that.sizeDiff.height;\n\t\t\tsoffsetw = ista ? 0 : that.sizeDiff.width;\n\n\t\t\ts = { width: (that.helper.width()  - soffsetw), height: (that.helper.height() - soffseth) };\n\t\t\tleft = (parseInt(that.element.css(\"left\"), 10) + (that.position.left - that.originalPosition.left)) || null;\n\t\t\ttop = (parseInt(that.element.css(\"top\"), 10) + (that.position.top - that.originalPosition.top)) || null;\n\n\t\t\tif (!o.animate) {\n\t\t\t\tthis.element.css($.extend(s, { top: top, left: left }));\n\t\t\t}\n\n\t\t\tthat.helper.height(that.size.height);\n\t\t\tthat.helper.width(that.size.width);\n\n\t\t\tif (this._helper && !o.animate) {\n\t\t\t\tthis._proportionallyResize();\n\t\t\t}\n\t\t}\n\n\t\t$(\"body\").css(\"cursor\", \"auto\");\n\n\t\tthis.element.removeClass(\"ui-resizable-resizing\");\n\n\t\tthis._propagate(\"stop\", event);\n\n\t\tif (this._helper) {\n\t\t\tthis.helper.remove();\n\t\t}\n\n\t\treturn false;\n\n\t},\n\n\t_updateVirtualBoundaries: function(forceAspectRatio) {\n\t\tvar pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,\n\t\t\to = this.options;\n\n\t\tb = {\n\t\t\tminWidth: isNumber(o.minWidth) ? o.minWidth : 0,\n\t\t\tmaxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,\n\t\t\tminHeight: isNumber(o.minHeight) ? o.minHeight : 0,\n\t\t\tmaxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity\n\t\t};\n\n\t\tif(this._aspectRatio || forceAspectRatio) {\n\t\t\t// We want to create an enclosing box whose aspect ration is the requested one\n\t\t\t// First, compute the \"projected\" size for each dimension based on the aspect ratio and other dimension\n\t\t\tpMinWidth = b.minHeight * this.aspectRatio;\n\t\t\tpMinHeight = b.minWidth / this.aspectRatio;\n\t\t\tpMaxWidth = b.maxHeight * this.aspectRatio;\n\t\t\tpMaxHeight = b.maxWidth / this.aspectRatio;\n\n\t\t\tif(pMinWidth > b.minWidth) {\n\t\t\t\tb.minWidth = pMinWidth;\n\t\t\t}\n\t\t\tif(pMinHeight > b.minHeight) {\n\t\t\t\tb.minHeight = pMinHeight;\n\t\t\t}\n\t\t\tif(pMaxWidth < b.maxWidth) {\n\t\t\t\tb.maxWidth = pMaxWidth;\n\t\t\t}\n\t\t\tif(pMaxHeight < b.maxHeight) {\n\t\t\t\tb.maxHeight = pMaxHeight;\n\t\t\t}\n\t\t}\n\t\tthis._vBoundaries = b;\n\t},\n\n\t_updateCache: function(data) {\n\t\tthis.offset = this.helper.offset();\n\t\tif (isNumber(data.left)) {\n\t\t\tthis.position.left = data.left;\n\t\t}\n\t\tif (isNumber(data.top)) {\n\t\t\tthis.position.top = data.top;\n\t\t}\n\t\tif (isNumber(data.height)) {\n\t\t\tthis.size.height = data.height;\n\t\t}\n\t\tif (isNumber(data.width)) {\n\t\t\tthis.size.width = data.width;\n\t\t}\n\t},\n\n\t_updateRatio: function( data ) {\n\n\t\tvar cpos = this.position,\n\t\t\tcsize = this.size,\n\t\t\ta = this.axis;\n\n\t\tif (isNumber(data.height)) {\n\t\t\tdata.width = (data.height * this.aspectRatio);\n\t\t} else if (isNumber(data.width)) {\n\t\t\tdata.height = (data.width / this.aspectRatio);\n\t\t}\n\n\t\tif (a === \"sw\") {\n\t\t\tdata.left = cpos.left + (csize.width - data.width);\n\t\t\tdata.top = null;\n\t\t}\n\t\tif (a === \"nw\") {\n\t\t\tdata.top = cpos.top + (csize.height - data.height);\n\t\t\tdata.left = cpos.left + (csize.width - data.width);\n\t\t}\n\n\t\treturn data;\n\t},\n\n\t_respectSize: function( data ) {\n\n\t\tvar o = this._vBoundaries,\n\t\t\ta = this.axis,\n\t\t\tismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),\n\t\t\tisminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),\n\t\t\tdw = this.originalPosition.left + this.originalSize.width,\n\t\t\tdh = this.position.top + this.size.height,\n\t\t\tcw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);\n\t\tif (isminw) {\n\t\t\tdata.width = o.minWidth;\n\t\t}\n\t\tif (isminh) {\n\t\t\tdata.height = o.minHeight;\n\t\t}\n\t\tif (ismaxw) {\n\t\t\tdata.width = o.maxWidth;\n\t\t}\n\t\tif (ismaxh) {\n\t\t\tdata.height = o.maxHeight;\n\t\t}\n\n\t\tif (isminw && cw) {\n\t\t\tdata.left = dw - o.minWidth;\n\t\t}\n\t\tif (ismaxw && cw) {\n\t\t\tdata.left = dw - o.maxWidth;\n\t\t}\n\t\tif (isminh && ch) {\n\t\t\tdata.top = dh - o.minHeight;\n\t\t}\n\t\tif (ismaxh && ch) {\n\t\t\tdata.top = dh - o.maxHeight;\n\t\t}\n\n\t\t// fixing jump error on top/left - bug #2330\n\t\tif (!data.width && !data.height && !data.left && data.top) {\n\t\t\tdata.top = null;\n\t\t} else if (!data.width && !data.height && !data.top && data.left) {\n\t\t\tdata.left = null;\n\t\t}\n\n\t\treturn data;\n\t},\n\n\t_proportionallyResize: function() {\n\n\t\tif (!this._proportionallyResizeElements.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar i, j, borders, paddings, prel,\n\t\t\telement = this.helper || this.element;\n\n\t\tfor ( i=0; i < this._proportionallyResizeElements.length; i++) {\n\n\t\t\tprel = this._proportionallyResizeElements[i];\n\n\t\t\tif (!this.borderDif) {\n\t\t\t\tthis.borderDif = [];\n\t\t\t\tborders = [prel.css(\"borderTopWidth\"), prel.css(\"borderRightWidth\"), prel.css(\"borderBottomWidth\"), prel.css(\"borderLeftWidth\")];\n\t\t\t\tpaddings = [prel.css(\"paddingTop\"), prel.css(\"paddingRight\"), prel.css(\"paddingBottom\"), prel.css(\"paddingLeft\")];\n\n\t\t\t\tfor ( j = 0; j < borders.length; j++ ) {\n\t\t\t\t\tthis.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprel.css({\n\t\t\t\theight: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,\n\t\t\t\twidth: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0\n\t\t\t});\n\n\t\t}\n\n\t},\n\n\t_renderProxy: function() {\n\n\t\tvar el = this.element, o = this.options;\n\t\tthis.elementOffset = el.offset();\n\n\t\tif(this._helper) {\n\n\t\t\tthis.helper = this.helper || $(\"<div style='overflow:hidden;'></div>\");\n\n\t\t\tthis.helper.addClass(this._helper).css({\n\t\t\t\twidth: this.element.outerWidth() - 1,\n\t\t\t\theight: this.element.outerHeight() - 1,\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tleft: this.elementOffset.left +\"px\",\n\t\t\t\ttop: this.elementOffset.top +\"px\",\n\t\t\t\tzIndex: ++o.zIndex //TODO: Don't modify option\n\t\t\t});\n\n\t\t\tthis.helper\n\t\t\t\t.appendTo(\"body\")\n\t\t\t\t.disableSelection();\n\n\t\t} else {\n\t\t\tthis.helper = this.element;\n\t\t}\n\n\t},\n\n\t_change: {\n\t\te: function(event, dx) {\n\t\t\treturn { width: this.originalSize.width + dx };\n\t\t},\n\t\tw: function(event, dx) {\n\t\t\tvar cs = this.originalSize, sp = this.originalPosition;\n\t\t\treturn { left: sp.left + dx, width: cs.width - dx };\n\t\t},\n\t\tn: function(event, dx, dy) {\n\t\t\tvar cs = this.originalSize, sp = this.originalPosition;\n\t\t\treturn { top: sp.top + dy, height: cs.height - dy };\n\t\t},\n\t\ts: function(event, dx, dy) {\n\t\t\treturn { height: this.originalSize.height + dy };\n\t\t},\n\t\tse: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));\n\t\t},\n\t\tsw: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));\n\t\t},\n\t\tne: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));\n\t\t},\n\t\tnw: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));\n\t\t}\n\t},\n\n\t_propagate: function(n, event) {\n\t\t$.ui.plugin.call(this, n, [event, this.ui()]);\n\t\t(n !== \"resize\" && this._trigger(n, event, this.ui()));\n\t},\n\n\tplugins: {},\n\n\tui: function() {\n\t\treturn {\n\t\t\toriginalElement: this.originalElement,\n\t\t\telement: this.element,\n\t\t\thelper: this.helper,\n\t\t\tposition: this.position,\n\t\t\tsize: this.size,\n\t\t\toriginalSize: this.originalSize,\n\t\t\toriginalPosition: this.originalPosition\n\t\t};\n\t}\n\n});\n\n/*\n * Resizable Extensions\n */\n\n$.ui.plugin.add(\"resizable\", \"animate\", {\n\n\tstop: function( event ) {\n\t\tvar that = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\tpr = that._proportionallyResizeElements,\n\t\t\tista = pr.length && (/textarea/i).test(pr[0].nodeName),\n\t\t\tsoffseth = ista && $.ui.hasScroll(pr[0], \"left\") /* TODO - jump height */ ? 0 : that.sizeDiff.height,\n\t\t\tsoffsetw = ista ? 0 : that.sizeDiff.width,\n\t\t\tstyle = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },\n\t\t\tleft = (parseInt(that.element.css(\"left\"), 10) + (that.position.left - that.originalPosition.left)) || null,\n\t\t\ttop = (parseInt(that.element.css(\"top\"), 10) + (that.position.top - that.originalPosition.top)) || null;\n\n\t\tthat.element.animate(\n\t\t\t$.extend(style, top && left ? { top: top, left: left } : {}), {\n\t\t\t\tduration: o.animateDuration,\n\t\t\t\teasing: o.animateEasing,\n\t\t\t\tstep: function() {\n\n\t\t\t\t\tvar data = {\n\t\t\t\t\t\twidth: parseInt(that.element.css(\"width\"), 10),\n\t\t\t\t\t\theight: parseInt(that.element.css(\"height\"), 10),\n\t\t\t\t\t\ttop: parseInt(that.element.css(\"top\"), 10),\n\t\t\t\t\t\tleft: parseInt(that.element.css(\"left\"), 10)\n\t\t\t\t\t};\n\n\t\t\t\t\tif (pr && pr.length) {\n\t\t\t\t\t\t$(pr[0]).css({ width: data.width, height: data.height });\n\t\t\t\t\t}\n\n\t\t\t\t\t// propagating resize, and updating values for each animation step\n\t\t\t\t\tthat._updateCache(data);\n\t\t\t\t\tthat._propagate(\"resize\", event);\n\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n});\n\n$.ui.plugin.add(\"resizable\", \"containment\", {\n\n\tstart: function() {\n\t\tvar element, p, co, ch, cw, width, height,\n\t\t\tthat = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\tel = that.element,\n\t\t\toc = o.containment,\n\t\t\tce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;\n\n\t\tif (!ce) {\n\t\t\treturn;\n\t\t}\n\n\t\tthat.containerElement = $(ce);\n\n\t\tif (/document/.test(oc) || oc === document) {\n\t\t\tthat.containerOffset = { left: 0, top: 0 };\n\t\t\tthat.containerPosition = { left: 0, top: 0 };\n\n\t\t\tthat.parentData = {\n\t\t\t\telement: $(document), left: 0, top: 0,\n\t\t\t\twidth: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight\n\t\t\t};\n\t\t}\n\n\t\t// i'm a node, so compute top, left, right, bottom\n\t\telse {\n\t\t\telement = $(ce);\n\t\t\tp = [];\n\t\t\t$([ \"Top\", \"Right\", \"Left\", \"Bottom\" ]).each(function(i, name) { p[i] = num(element.css(\"padding\" + name)); });\n\n\t\t\tthat.containerOffset = element.offset();\n\t\t\tthat.containerPosition = element.position();\n\t\t\tthat.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };\n\n\t\t\tco = that.containerOffset;\n\t\t\tch = that.containerSize.height;\n\t\t\tcw = that.containerSize.width;\n\t\t\twidth = ($.ui.hasScroll(ce, \"left\") ? ce.scrollWidth : cw );\n\t\t\theight = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);\n\n\t\t\tthat.parentData = {\n\t\t\t\telement: ce, left: co.left, top: co.top, width: width, height: height\n\t\t\t};\n\t\t}\n\t},\n\n\tresize: function( event ) {\n\t\tvar woset, hoset, isParent, isOffsetRelative,\n\t\t\tthat = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\tco = that.containerOffset, cp = that.position,\n\t\t\tpRatio = that._aspectRatio || event.shiftKey,\n\t\t\tcop = { top:0, left:0 }, ce = that.containerElement;\n\n\t\tif (ce[0] !== document && (/static/).test(ce.css(\"position\"))) {\n\t\t\tcop = co;\n\t\t}\n\n\t\tif (cp.left < (that._helper ? co.left : 0)) {\n\t\t\tthat.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));\n\t\t\tif (pRatio) {\n\t\t\t\tthat.size.height = that.size.width / that.aspectRatio;\n\t\t\t}\n\t\t\tthat.position.left = o.helper ? co.left : 0;\n\t\t}\n\n\t\tif (cp.top < (that._helper ? co.top : 0)) {\n\t\t\tthat.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);\n\t\t\tif (pRatio) {\n\t\t\t\tthat.size.width = that.size.height * that.aspectRatio;\n\t\t\t}\n\t\t\tthat.position.top = that._helper ? co.top : 0;\n\t\t}\n\n\t\tthat.offset.left = that.parentData.left+that.position.left;\n\t\tthat.offset.top = that.parentData.top+that.position.top;\n\n\t\twoset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );\n\t\thoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );\n\n\t\tisParent = that.containerElement.get(0) === that.element.parent().get(0);\n\t\tisOffsetRelative = /relative|absolute/.test(that.containerElement.css(\"position\"));\n\n\t\tif(isParent && isOffsetRelative) {\n\t\t\twoset -= that.parentData.left;\n\t\t}\n\n\t\tif (woset + that.size.width >= that.parentData.width) {\n\t\t\tthat.size.width = that.parentData.width - woset;\n\t\t\tif (pRatio) {\n\t\t\t\tthat.size.height = that.size.width / that.aspectRatio;\n\t\t\t}\n\t\t}\n\n\t\tif (hoset + that.size.height >= that.parentData.height) {\n\t\t\tthat.size.height = that.parentData.height - hoset;\n\t\t\tif (pRatio) {\n\t\t\t\tthat.size.width = that.size.height * that.aspectRatio;\n\t\t\t}\n\t\t}\n\t},\n\n\tstop: function(){\n\t\tvar that = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\tco = that.containerOffset,\n\t\t\tcop = that.containerPosition,\n\t\t\tce = that.containerElement,\n\t\t\thelper = $(that.helper),\n\t\t\tho = helper.offset(),\n\t\t\tw = helper.outerWidth() - that.sizeDiff.width,\n\t\t\th = helper.outerHeight() - that.sizeDiff.height;\n\n\t\tif (that._helper && !o.animate && (/relative/).test(ce.css(\"position\"))) {\n\t\t\t$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });\n\t\t}\n\n\t\tif (that._helper && !o.animate && (/static/).test(ce.css(\"position\"))) {\n\t\t\t$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });\n\t\t}\n\n\t}\n});\n\n$.ui.plugin.add(\"resizable\", \"alsoResize\", {\n\n\tstart: function () {\n\t\tvar that = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\t_store = function (exp) {\n\t\t\t\t$(exp).each(function() {\n\t\t\t\t\tvar el = $(this);\n\t\t\t\t\tel.data(\"ui-resizable-alsoresize\", {\n\t\t\t\t\t\twidth: parseInt(el.width(), 10), height: parseInt(el.height(), 10),\n\t\t\t\t\t\tleft: parseInt(el.css(\"left\"), 10), top: parseInt(el.css(\"top\"), 10)\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t};\n\n\t\tif (typeof(o.alsoResize) === \"object\" && !o.alsoResize.parentNode) {\n\t\t\tif (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }\n\t\t\telse { $.each(o.alsoResize, function (exp) { _store(exp); }); }\n\t\t}else{\n\t\t\t_store(o.alsoResize);\n\t\t}\n\t},\n\n\tresize: function (event, ui) {\n\t\tvar that = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\tos = that.originalSize,\n\t\t\top = that.originalPosition,\n\t\t\tdelta = {\n\t\t\t\theight: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,\n\t\t\t\ttop: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0\n\t\t\t},\n\n\t\t\t_alsoResize = function (exp, c) {\n\t\t\t\t$(exp).each(function() {\n\t\t\t\t\tvar el = $(this), start = $(this).data(\"ui-resizable-alsoresize\"), style = {},\n\t\t\t\t\t\tcss = c && c.length ? c : el.parents(ui.originalElement[0]).length ? [\"width\", \"height\"] : [\"width\", \"height\", \"top\", \"left\"];\n\n\t\t\t\t\t$.each(css, function (i, prop) {\n\t\t\t\t\t\tvar sum = (start[prop]||0) + (delta[prop]||0);\n\t\t\t\t\t\tif (sum && sum >= 0) {\n\t\t\t\t\t\t\tstyle[prop] = sum || null;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tel.css(style);\n\t\t\t\t});\n\t\t\t};\n\n\t\tif (typeof(o.alsoResize) === \"object\" && !o.alsoResize.nodeType) {\n\t\t\t$.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });\n\t\t}else{\n\t\t\t_alsoResize(o.alsoResize);\n\t\t}\n\t},\n\n\tstop: function () {\n\t\t$(this).removeData(\"resizable-alsoresize\");\n\t}\n});\n\n$.ui.plugin.add(\"resizable\", \"ghost\", {\n\n\tstart: function() {\n\n\t\tvar that = $(this).data(\"ui-resizable\"), o = that.options, cs = that.size;\n\n\t\tthat.ghost = that.originalElement.clone();\n\t\tthat.ghost\n\t\t\t.css({ opacity: 0.25, display: \"block\", position: \"relative\", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })\n\t\t\t.addClass(\"ui-resizable-ghost\")\n\t\t\t.addClass(typeof o.ghost === \"string\" ? o.ghost : \"\");\n\n\t\tthat.ghost.appendTo(that.helper);\n\n\t},\n\n\tresize: function(){\n\t\tvar that = $(this).data(\"ui-resizable\");\n\t\tif (that.ghost) {\n\t\t\tthat.ghost.css({ position: \"relative\", height: that.size.height, width: that.size.width });\n\t\t}\n\t},\n\n\tstop: function() {\n\t\tvar that = $(this).data(\"ui-resizable\");\n\t\tif (that.ghost && that.helper) {\n\t\t\tthat.helper.get(0).removeChild(that.ghost.get(0));\n\t\t}\n\t}\n\n});\n\n$.ui.plugin.add(\"resizable\", \"grid\", {\n\n\tresize: function() {\n\t\tvar that = $(this).data(\"ui-resizable\"),\n\t\t\to = that.options,\n\t\t\tcs = that.size,\n\t\t\tos = that.originalSize,\n\t\t\top = that.originalPosition,\n\t\t\ta = that.axis,\n\t\t\tgrid = typeof o.grid === \"number\" ? [o.grid, o.grid] : o.grid,\n\t\t\tgridX = (grid[0]||1),\n\t\t\tgridY = (grid[1]||1),\n\t\t\tox = Math.round((cs.width - os.width) / gridX) * gridX,\n\t\t\toy = Math.round((cs.height - os.height) / gridY) * gridY,\n\t\t\tnewWidth = os.width + ox,\n\t\t\tnewHeight = os.height + oy,\n\t\t\tisMaxWidth = o.maxWidth && (o.maxWidth < newWidth),\n\t\t\tisMaxHeight = o.maxHeight && (o.maxHeight < newHeight),\n\t\t\tisMinWidth = o.minWidth && (o.minWidth > newWidth),\n\t\t\tisMinHeight = o.minHeight && (o.minHeight > newHeight);\n\n\t\to.grid = grid;\n\n\t\tif (isMinWidth) {\n\t\t\tnewWidth = newWidth + gridX;\n\t\t}\n\t\tif (isMinHeight) {\n\t\t\tnewHeight = newHeight + gridY;\n\t\t}\n\t\tif (isMaxWidth) {\n\t\t\tnewWidth = newWidth - gridX;\n\t\t}\n\t\tif (isMaxHeight) {\n\t\t\tnewHeight = newHeight - gridY;\n\t\t}\n\n\t\tif (/^(se|s|e)$/.test(a)) {\n\t\t\tthat.size.width = newWidth;\n\t\t\tthat.size.height = newHeight;\n\t\t} else if (/^(ne)$/.test(a)) {\n\t\t\tthat.size.width = newWidth;\n\t\t\tthat.size.height = newHeight;\n\t\t\tthat.position.top = op.top - oy;\n\t\t} else if (/^(sw)$/.test(a)) {\n\t\t\tthat.size.width = newWidth;\n\t\t\tthat.size.height = newHeight;\n\t\t\tthat.position.left = op.left - ox;\n\t\t} else {\n\t\t\tthat.size.width = newWidth;\n\t\t\tthat.size.height = newHeight;\n\t\t\tthat.position.top = op.top - oy;\n\t\t\tthat.position.left = op.left - ox;\n\t\t}\n\t}\n\n});\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.widget(\"ui.selectable\", $.ui.mouse, {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\tappendTo: \"body\",\n\t\tautoRefresh: true,\n\t\tdistance: 0,\n\t\tfilter: \"*\",\n\t\ttolerance: \"touch\",\n\n\t\t// callbacks\n\t\tselected: null,\n\t\tselecting: null,\n\t\tstart: null,\n\t\tstop: null,\n\t\tunselected: null,\n\t\tunselecting: null\n\t},\n\t_create: function() {\n\t\tvar selectees,\n\t\t\tthat = this;\n\n\t\tthis.element.addClass(\"ui-selectable\");\n\n\t\tthis.dragged = false;\n\n\t\t// cache selectee children based on filter\n\t\tthis.refresh = function() {\n\t\t\tselectees = $(that.options.filter, that.element[0]);\n\t\t\tselectees.addClass(\"ui-selectee\");\n\t\t\tselectees.each(function() {\n\t\t\t\tvar $this = $(this),\n\t\t\t\t\tpos = $this.offset();\n\t\t\t\t$.data(this, \"selectable-item\", {\n\t\t\t\t\telement: this,\n\t\t\t\t\t$element: $this,\n\t\t\t\t\tleft: pos.left,\n\t\t\t\t\ttop: pos.top,\n\t\t\t\t\tright: pos.left + $this.outerWidth(),\n\t\t\t\t\tbottom: pos.top + $this.outerHeight(),\n\t\t\t\t\tstartselected: false,\n\t\t\t\t\tselected: $this.hasClass(\"ui-selected\"),\n\t\t\t\t\tselecting: $this.hasClass(\"ui-selecting\"),\n\t\t\t\t\tunselecting: $this.hasClass(\"ui-unselecting\")\n\t\t\t\t});\n\t\t\t});\n\t\t};\n\t\tthis.refresh();\n\n\t\tthis.selectees = selectees.addClass(\"ui-selectee\");\n\n\t\tthis._mouseInit();\n\n\t\tthis.helper = $(\"<div class='ui-selectable-helper'></div>\");\n\t},\n\n\t_destroy: function() {\n\t\tthis.selectees\n\t\t\t.removeClass(\"ui-selectee\")\n\t\t\t.removeData(\"selectable-item\");\n\t\tthis.element\n\t\t\t.removeClass(\"ui-selectable ui-selectable-disabled\");\n\t\tthis._mouseDestroy();\n\t},\n\n\t_mouseStart: function(event) {\n\t\tvar that = this,\n\t\t\toptions = this.options;\n\n\t\tthis.opos = [event.pageX, event.pageY];\n\n\t\tif (this.options.disabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.selectees = $(options.filter, this.element[0]);\n\n\t\tthis._trigger(\"start\", event);\n\n\t\t$(options.appendTo).append(this.helper);\n\t\t// position helper (lasso)\n\t\tthis.helper.css({\n\t\t\t\"left\": event.pageX,\n\t\t\t\"top\": event.pageY,\n\t\t\t\"width\": 0,\n\t\t\t\"height\": 0\n\t\t});\n\n\t\tif (options.autoRefresh) {\n\t\t\tthis.refresh();\n\t\t}\n\n\t\tthis.selectees.filter(\".ui-selected\").each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tselectee.startselected = true;\n\t\t\tif (!event.metaKey && !event.ctrlKey) {\n\t\t\t\tselectee.$element.removeClass(\"ui-selected\");\n\t\t\t\tselectee.selected = false;\n\t\t\t\tselectee.$element.addClass(\"ui-unselecting\");\n\t\t\t\tselectee.unselecting = true;\n\t\t\t\t// selectable UNSELECTING callback\n\t\t\t\tthat._trigger(\"unselecting\", event, {\n\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t$(event.target).parents().addBack().each(function() {\n\t\t\tvar doSelect,\n\t\t\t\tselectee = $.data(this, \"selectable-item\");\n\t\t\tif (selectee) {\n\t\t\t\tdoSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass(\"ui-selected\");\n\t\t\t\tselectee.$element\n\t\t\t\t\t.removeClass(doSelect ? \"ui-unselecting\" : \"ui-selected\")\n\t\t\t\t\t.addClass(doSelect ? \"ui-selecting\" : \"ui-unselecting\");\n\t\t\t\tselectee.unselecting = !doSelect;\n\t\t\t\tselectee.selecting = doSelect;\n\t\t\t\tselectee.selected = doSelect;\n\t\t\t\t// selectable (UN)SELECTING callback\n\t\t\t\tif (doSelect) {\n\t\t\t\t\tthat._trigger(\"selecting\", event, {\n\t\t\t\t\t\tselecting: selectee.element\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthat._trigger(\"unselecting\", event, {\n\t\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\n\t},\n\n\t_mouseDrag: function(event) {\n\n\t\tthis.dragged = true;\n\n\t\tif (this.options.disabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar tmp,\n\t\t\tthat = this,\n\t\t\toptions = this.options,\n\t\t\tx1 = this.opos[0],\n\t\t\ty1 = this.opos[1],\n\t\t\tx2 = event.pageX,\n\t\t\ty2 = event.pageY;\n\n\t\tif (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }\n\t\tif (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }\n\t\tthis.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});\n\n\t\tthis.selectees.each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\"),\n\t\t\t\thit = false;\n\n\t\t\t//prevent helper from being selected if appendTo: selectable\n\t\t\tif (!selectee || selectee.element === that.element[0]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (options.tolerance === \"touch\") {\n\t\t\t\thit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );\n\t\t\t} else if (options.tolerance === \"fit\") {\n\t\t\t\thit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);\n\t\t\t}\n\n\t\t\tif (hit) {\n\t\t\t\t// SELECT\n\t\t\t\tif (selectee.selected) {\n\t\t\t\t\tselectee.$element.removeClass(\"ui-selected\");\n\t\t\t\t\tselectee.selected = false;\n\t\t\t\t}\n\t\t\t\tif (selectee.unselecting) {\n\t\t\t\t\tselectee.$element.removeClass(\"ui-unselecting\");\n\t\t\t\t\tselectee.unselecting = false;\n\t\t\t\t}\n\t\t\t\tif (!selectee.selecting) {\n\t\t\t\t\tselectee.$element.addClass(\"ui-selecting\");\n\t\t\t\t\tselectee.selecting = true;\n\t\t\t\t\t// selectable SELECTING callback\n\t\t\t\t\tthat._trigger(\"selecting\", event, {\n\t\t\t\t\t\tselecting: selectee.element\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// UNSELECT\n\t\t\t\tif (selectee.selecting) {\n\t\t\t\t\tif ((event.metaKey || event.ctrlKey) && selectee.startselected) {\n\t\t\t\t\t\tselectee.$element.removeClass(\"ui-selecting\");\n\t\t\t\t\t\tselectee.selecting = false;\n\t\t\t\t\t\tselectee.$element.addClass(\"ui-selected\");\n\t\t\t\t\t\tselectee.selected = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tselectee.$element.removeClass(\"ui-selecting\");\n\t\t\t\t\t\tselectee.selecting = false;\n\t\t\t\t\t\tif (selectee.startselected) {\n\t\t\t\t\t\t\tselectee.$element.addClass(\"ui-unselecting\");\n\t\t\t\t\t\t\tselectee.unselecting = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// selectable UNSELECTING callback\n\t\t\t\t\t\tthat._trigger(\"unselecting\", event, {\n\t\t\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (selectee.selected) {\n\t\t\t\t\tif (!event.metaKey && !event.ctrlKey && !selectee.startselected) {\n\t\t\t\t\t\tselectee.$element.removeClass(\"ui-selected\");\n\t\t\t\t\t\tselectee.selected = false;\n\n\t\t\t\t\t\tselectee.$element.addClass(\"ui-unselecting\");\n\t\t\t\t\t\tselectee.unselecting = true;\n\t\t\t\t\t\t// selectable UNSELECTING callback\n\t\t\t\t\t\tthat._trigger(\"unselecting\", event, {\n\t\t\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function(event) {\n\t\tvar that = this;\n\n\t\tthis.dragged = false;\n\n\t\t$(\".ui-unselecting\", this.element[0]).each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tselectee.$element.removeClass(\"ui-unselecting\");\n\t\t\tselectee.unselecting = false;\n\t\t\tselectee.startselected = false;\n\t\t\tthat._trigger(\"unselected\", event, {\n\t\t\t\tunselected: selectee.element\n\t\t\t});\n\t\t});\n\t\t$(\".ui-selecting\", this.element[0]).each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tselectee.$element.removeClass(\"ui-selecting\").addClass(\"ui-selected\");\n\t\t\tselectee.selecting = false;\n\t\t\tselectee.selected = true;\n\t\t\tselectee.startselected = true;\n\t\t\tthat._trigger(\"selected\", event, {\n\t\t\t\tselected: selectee.element\n\t\t\t});\n\t\t});\n\t\tthis._trigger(\"stop\", event);\n\n\t\tthis.helper.remove();\n\n\t\treturn false;\n\t}\n\n});\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n/*jshint loopfunc: true */\n\nfunction isOverAxis( x, reference, size ) {\n\treturn ( x > reference ) && ( x < ( reference + size ) );\n}\n\n$.widget(\"ui.sortable\", $.ui.mouse, {\n\tversion: \"1.10.1\",\n\twidgetEventPrefix: \"sort\",\n\tready: false,\n\toptions: {\n\t\tappendTo: \"parent\",\n\t\taxis: false,\n\t\tconnectWith: false,\n\t\tcontainment: false,\n\t\tcursor: \"auto\",\n\t\tcursorAt: false,\n\t\tdropOnEmpty: true,\n\t\tforcePlaceholderSize: false,\n\t\tforceHelperSize: false,\n\t\tgrid: false,\n\t\thandle: false,\n\t\thelper: \"original\",\n\t\titems: \"> *\",\n\t\topacity: false,\n\t\tplaceholder: false,\n\t\trevert: false,\n\t\tscroll: true,\n\t\tscrollSensitivity: 20,\n\t\tscrollSpeed: 20,\n\t\tscope: \"default\",\n\t\ttolerance: \"intersect\",\n\t\tzIndex: 1000,\n\n\t\t// callbacks\n\t\tactivate: null,\n\t\tbeforeStop: null,\n\t\tchange: null,\n\t\tdeactivate: null,\n\t\tout: null,\n\t\tover: null,\n\t\treceive: null,\n\t\tremove: null,\n\t\tsort: null,\n\t\tstart: null,\n\t\tstop: null,\n\t\tupdate: null\n\t},\n\t_create: function() {\n\n\t\tvar o = this.options;\n\t\tthis.containerCache = {};\n\t\tthis.element.addClass(\"ui-sortable\");\n\n\t\t//Get the items\n\t\tthis.refresh();\n\n\t\t//Let's determine if the items are being displayed horizontally\n\t\tthis.floating = this.items.length ? o.axis === \"x\" || (/left|right/).test(this.items[0].item.css(\"float\")) || (/inline|table-cell/).test(this.items[0].item.css(\"display\")) : false;\n\n\t\t//Let's determine the parent's offset\n\t\tthis.offset = this.element.offset();\n\n\t\t//Initialize mouse events for interaction\n\t\tthis._mouseInit();\n\n\t\t//We're ready to go\n\t\tthis.ready = true;\n\n\t},\n\n\t_destroy: function() {\n\t\tthis.element\n\t\t\t.removeClass(\"ui-sortable ui-sortable-disabled\");\n\t\tthis._mouseDestroy();\n\n\t\tfor ( var i = this.items.length - 1; i >= 0; i-- ) {\n\t\t\tthis.items[i].item.removeData(this.widgetName + \"-item\");\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t_setOption: function(key, value){\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.options[ key ] = value;\n\n\t\t\tthis.widget().toggleClass( \"ui-sortable-disabled\", !!value );\n\t\t} else {\n\t\t\t// Don't call widget base _setOption for disable as it adds ui-state-disabled class\n\t\t\t$.Widget.prototype._setOption.apply(this, arguments);\n\t\t}\n\t},\n\n\t_mouseCapture: function(event, overrideHandle) {\n\t\tvar currentItem = null,\n\t\t\tvalidHandle = false,\n\t\t\tthat = this;\n\n\t\tif (this.reverting) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.options.disabled || this.options.type === \"static\") {\n\t\t\treturn false;\n\t\t}\n\n\t\t//We have to refresh the items data once first\n\t\tthis._refreshItems(event);\n\n\t\t//Find out if the clicked node (or one of its parents) is a actual item in this.items\n\t\t$(event.target).parents().each(function() {\n\t\t\tif($.data(this, that.widgetName + \"-item\") === that) {\n\t\t\t\tcurrentItem = $(this);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\tif($.data(event.target, that.widgetName + \"-item\") === that) {\n\t\t\tcurrentItem = $(event.target);\n\t\t}\n\n\t\tif(!currentItem) {\n\t\t\treturn false;\n\t\t}\n\t\tif(this.options.handle && !overrideHandle) {\n\t\t\t$(this.options.handle, currentItem).find(\"*\").addBack().each(function() {\n\t\t\t\tif(this === event.target) {\n\t\t\t\t\tvalidHandle = true;\n\t\t\t\t}\n\t\t\t});\n\t\t\tif(!validHandle) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis.currentItem = currentItem;\n\t\tthis._removeCurrentsFromItems();\n\t\treturn true;\n\n\t},\n\n\t_mouseStart: function(event, overrideHandle, noActivation) {\n\n\t\tvar i,\n\t\t\to = this.options;\n\n\t\tthis.currentContainer = this;\n\n\t\t//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture\n\t\tthis.refreshPositions();\n\n\t\t//Create and append the visible helper\n\t\tthis.helper = this._createHelper(event);\n\n\t\t//Cache the helper size\n\t\tthis._cacheHelperProportions();\n\n\t\t/*\n\t\t * - Position generation -\n\t\t * This block generates everything position related - it's the core of draggables.\n\t\t */\n\n\t\t//Cache the margins of the original element\n\t\tthis._cacheMargins();\n\n\t\t//Get the next scrolling parent\n\t\tthis.scrollParent = this.helper.scrollParent();\n\n\t\t//The element's absolute position on the page minus margins\n\t\tthis.offset = this.currentItem.offset();\n\t\tthis.offset = {\n\t\t\ttop: this.offset.top - this.margins.top,\n\t\t\tleft: this.offset.left - this.margins.left\n\t\t};\n\n\t\t$.extend(this.offset, {\n\t\t\tclick: { //Where the click happened, relative to the element\n\t\t\t\tleft: event.pageX - this.offset.left,\n\t\t\t\ttop: event.pageY - this.offset.top\n\t\t\t},\n\t\t\tparent: this._getParentOffset(),\n\t\t\trelative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper\n\t\t});\n\n\t\t// Only after we got the offset, we can change the helper's position to absolute\n\t\t// TODO: Still need to figure out a way to make relative sorting possible\n\t\tthis.helper.css(\"position\", \"absolute\");\n\t\tthis.cssPosition = this.helper.css(\"position\");\n\n\t\t//Generate the original position\n\t\tthis.originalPosition = this._generatePosition(event);\n\t\tthis.originalPageX = event.pageX;\n\t\tthis.originalPageY = event.pageY;\n\n\t\t//Adjust the mouse offset relative to the helper if \"cursorAt\" is supplied\n\t\t(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));\n\n\t\t//Cache the former DOM position\n\t\tthis.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };\n\n\t\t//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way\n\t\tif(this.helper[0] !== this.currentItem[0]) {\n\t\t\tthis.currentItem.hide();\n\t\t}\n\n\t\t//Create the placeholder\n\t\tthis._createPlaceholder();\n\n\t\t//Set a containment if given in the options\n\t\tif(o.containment) {\n\t\t\tthis._setContainment();\n\t\t}\n\n\t\tif(o.cursor) { // cursor option\n\t\t\tif ($(\"body\").css(\"cursor\")) {\n\t\t\t\tthis._storedCursor = $(\"body\").css(\"cursor\");\n\t\t\t}\n\t\t\t$(\"body\").css(\"cursor\", o.cursor);\n\t\t}\n\n\t\tif(o.opacity) { // opacity option\n\t\t\tif (this.helper.css(\"opacity\")) {\n\t\t\t\tthis._storedOpacity = this.helper.css(\"opacity\");\n\t\t\t}\n\t\t\tthis.helper.css(\"opacity\", o.opacity);\n\t\t}\n\n\t\tif(o.zIndex) { // zIndex option\n\t\t\tif (this.helper.css(\"zIndex\")) {\n\t\t\t\tthis._storedZIndex = this.helper.css(\"zIndex\");\n\t\t\t}\n\t\t\tthis.helper.css(\"zIndex\", o.zIndex);\n\t\t}\n\n\t\t//Prepare scrolling\n\t\tif(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== \"HTML\") {\n\t\t\tthis.overflowOffset = this.scrollParent.offset();\n\t\t}\n\n\t\t//Call callbacks\n\t\tthis._trigger(\"start\", event, this._uiHash());\n\n\t\t//Recache the helper size\n\t\tif(!this._preserveHelperProportions) {\n\t\t\tthis._cacheHelperProportions();\n\t\t}\n\n\n\t\t//Post \"activate\" events to possible containers\n\t\tif( !noActivation ) {\n\t\t\tfor ( i = this.containers.length - 1; i >= 0; i-- ) {\n\t\t\t\tthis.containers[ i ]._trigger( \"activate\", event, this._uiHash( this ) );\n\t\t\t}\n\t\t}\n\n\t\t//Prepare possible droppables\n\t\tif($.ui.ddmanager) {\n\t\t\t$.ui.ddmanager.current = this;\n\t\t}\n\n\t\tif ($.ui.ddmanager && !o.dropBehaviour) {\n\t\t\t$.ui.ddmanager.prepareOffsets(this, event);\n\t\t}\n\n\t\tthis.dragging = true;\n\n\t\tthis.helper.addClass(\"ui-sortable-helper\");\n\t\tthis._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position\n\t\treturn true;\n\n\t},\n\n\t_mouseDrag: function(event) {\n\t\tvar i, item, itemElement, intersection,\n\t\t\to = this.options,\n\t\t\tscrolled = false;\n\n\t\t//Compute the helpers position\n\t\tthis.position = this._generatePosition(event);\n\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\n\t\tif (!this.lastPositionAbs) {\n\t\t\tthis.lastPositionAbs = this.positionAbs;\n\t\t}\n\n\t\t//Do scrolling\n\t\tif(this.options.scroll) {\n\t\t\tif(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== \"HTML\") {\n\n\t\t\t\tif((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {\n\t\t\t\t\tthis.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;\n\t\t\t\t} else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {\n\t\t\t\t\tthis.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;\n\t\t\t\t}\n\n\t\t\t\tif((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {\n\t\t\t\t\tthis.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;\n\t\t\t\t} else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {\n\t\t\t\t\tthis.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);\n\t\t\t\t} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);\n\t\t\t\t}\n\n\t\t\t\tif(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);\n\t\t\t\t} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {\n\t\t\t\t$.ui.ddmanager.prepareOffsets(this, event);\n\t\t\t}\n\t\t}\n\n\t\t//Regenerate the absolute position used for position checks\n\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\n\t\t//Set the helper position\n\t\tif(!this.options.axis || this.options.axis !== \"y\") {\n\t\t\tthis.helper[0].style.left = this.position.left+\"px\";\n\t\t}\n\t\tif(!this.options.axis || this.options.axis !== \"x\") {\n\t\t\tthis.helper[0].style.top = this.position.top+\"px\";\n\t\t}\n\n\t\t//Rearrange\n\t\tfor (i = this.items.length - 1; i >= 0; i--) {\n\n\t\t\t//Cache variables and intersection, continue if no intersection\n\t\t\titem = this.items[i];\n\t\t\titemElement = item.item[0];\n\t\t\tintersection = this._intersectsWithPointer(item);\n\t\t\tif (!intersection) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Only put the placeholder inside the current Container, skip all\n\t\t\t// items form other containers. This works because when moving\n\t\t\t// an item from one container to another the\n\t\t\t// currentContainer is switched before the placeholder is moved.\n\t\t\t//\n\t\t\t// Without this moving items in \"sub-sortables\" can cause the placeholder to jitter\n\t\t\t// beetween the outer and inner container.\n\t\t\tif (item.instance !== this.currentContainer) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// cannot intersect with itself\n\t\t\t// no useless actions that have been done before\n\t\t\t// no action if the item moved is the parent of the item checked\n\t\t\tif (itemElement !== this.currentItem[0] &&\n\t\t\t\tthis.placeholder[intersection === 1 ? \"next\" : \"prev\"]()[0] !== itemElement &&\n\t\t\t\t!$.contains(this.placeholder[0], itemElement) &&\n\t\t\t\t(this.options.type === \"semi-dynamic\" ? !$.contains(this.element[0], itemElement) : true)\n\t\t\t) {\n\n\t\t\t\tthis.direction = intersection === 1 ? \"down\" : \"up\";\n\n\t\t\t\tif (this.options.tolerance === \"pointer\" || this._intersectsWithSides(item)) {\n\t\t\t\t\tthis._rearrange(event, item);\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tthis._trigger(\"change\", event, this._uiHash());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t//Post events to containers\n\t\tthis._contactContainers(event);\n\n\t\t//Interconnect with droppables\n\t\tif($.ui.ddmanager) {\n\t\t\t$.ui.ddmanager.drag(this, event);\n\t\t}\n\n\t\t//Call callbacks\n\t\tthis._trigger(\"sort\", event, this._uiHash());\n\n\t\tthis.lastPositionAbs = this.positionAbs;\n\t\treturn false;\n\n\t},\n\n\t_mouseStop: function(event, noPropagation) {\n\n\t\tif(!event) {\n\t\t\treturn;\n\t\t}\n\n\t\t//If we are using droppables, inform the manager about the drop\n\t\tif ($.ui.ddmanager && !this.options.dropBehaviour) {\n\t\t\t$.ui.ddmanager.drop(this, event);\n\t\t}\n\n\t\tif(this.options.revert) {\n\t\t\tvar that = this,\n\t\t\t\tcur = this.placeholder.offset();\n\n\t\t\tthis.reverting = true;\n\n\t\t\t$(this.helper).animate({\n\t\t\t\tleft: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft),\n\t\t\t\ttop: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop)\n\t\t\t}, parseInt(this.options.revert, 10) || 500, function() {\n\t\t\t\tthat._clear(event);\n\t\t\t});\n\t\t} else {\n\t\t\tthis._clear(event, noPropagation);\n\t\t}\n\n\t\treturn false;\n\n\t},\n\n\tcancel: function() {\n\n\t\tif(this.dragging) {\n\n\t\t\tthis._mouseUp({ target: null });\n\n\t\t\tif(this.options.helper === \"original\") {\n\t\t\t\tthis.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\");\n\t\t\t} else {\n\t\t\t\tthis.currentItem.show();\n\t\t\t}\n\n\t\t\t//Post deactivating events to containers\n\t\t\tfor (var i = this.containers.length - 1; i >= 0; i--){\n\t\t\t\tthis.containers[i]._trigger(\"deactivate\", null, this._uiHash(this));\n\t\t\t\tif(this.containers[i].containerCache.over) {\n\t\t\t\t\tthis.containers[i]._trigger(\"out\", null, this._uiHash(this));\n\t\t\t\t\tthis.containers[i].containerCache.over = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tif (this.placeholder) {\n\t\t\t//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!\n\t\t\tif(this.placeholder[0].parentNode) {\n\t\t\t\tthis.placeholder[0].parentNode.removeChild(this.placeholder[0]);\n\t\t\t}\n\t\t\tif(this.options.helper !== \"original\" && this.helper && this.helper[0].parentNode) {\n\t\t\t\tthis.helper.remove();\n\t\t\t}\n\n\t\t\t$.extend(this, {\n\t\t\t\thelper: null,\n\t\t\t\tdragging: false,\n\t\t\t\treverting: false,\n\t\t\t\t_noFinalSort: null\n\t\t\t});\n\n\t\t\tif(this.domPosition.prev) {\n\t\t\t\t$(this.domPosition.prev).after(this.currentItem);\n\t\t\t} else {\n\t\t\t\t$(this.domPosition.parent).prepend(this.currentItem);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tserialize: function(o) {\n\n\t\tvar items = this._getItemsAsjQuery(o && o.connected),\n\t\t\tstr = [];\n\t\to = o || {};\n\n\t\t$(items).each(function() {\n\t\t\tvar res = ($(o.item || this).attr(o.attribute || \"id\") || \"\").match(o.expression || (/(.+)[\\-=_](.+)/));\n\t\t\tif (res) {\n\t\t\t\tstr.push((o.key || res[1]+\"[]\")+\"=\"+(o.key && o.expression ? res[1] : res[2]));\n\t\t\t}\n\t\t});\n\n\t\tif(!str.length && o.key) {\n\t\t\tstr.push(o.key + \"=\");\n\t\t}\n\n\t\treturn str.join(\"&\");\n\n\t},\n\n\ttoArray: function(o) {\n\n\t\tvar items = this._getItemsAsjQuery(o && o.connected),\n\t\t\tret = [];\n\n\t\to = o || {};\n\n\t\titems.each(function() { ret.push($(o.item || this).attr(o.attribute || \"id\") || \"\"); });\n\t\treturn ret;\n\n\t},\n\n\t/* Be careful with the following core functions */\n\t_intersectsWith: function(item) {\n\n\t\tvar x1 = this.positionAbs.left,\n\t\t\tx2 = x1 + this.helperProportions.width,\n\t\t\ty1 = this.positionAbs.top,\n\t\t\ty2 = y1 + this.helperProportions.height,\n\t\t\tl = item.left,\n\t\t\tr = l + item.width,\n\t\t\tt = item.top,\n\t\t\tb = t + item.height,\n\t\t\tdyClick = this.offset.click.top,\n\t\t\tdxClick = this.offset.click.left,\n\t\t\tisOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;\n\n\t\tif ( this.options.tolerance === \"pointer\" ||\n\t\t\tthis.options.forcePointerForContainers ||\n\t\t\t(this.options.tolerance !== \"pointer\" && this.helperProportions[this.floating ? \"width\" : \"height\"] > item[this.floating ? \"width\" : \"height\"])\n\t\t) {\n\t\t\treturn isOverElement;\n\t\t} else {\n\n\t\t\treturn (l < x1 + (this.helperProportions.width / 2) && // Right Half\n\t\t\t\tx2 - (this.helperProportions.width / 2) < r && // Left Half\n\t\t\t\tt < y1 + (this.helperProportions.height / 2) && // Bottom Half\n\t\t\t\ty2 - (this.helperProportions.height / 2) < b ); // Top Half\n\n\t\t}\n\t},\n\n\t_intersectsWithPointer: function(item) {\n\n\t\tvar isOverElementHeight = (this.options.axis === \"x\") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),\n\t\t\tisOverElementWidth = (this.options.axis === \"y\") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),\n\t\t\tisOverElement = isOverElementHeight && isOverElementWidth,\n\t\t\tverticalDirection = this._getDragVerticalDirection(),\n\t\t\thorizontalDirection = this._getDragHorizontalDirection();\n\n\t\tif (!isOverElement) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.floating ?\n\t\t\t( ((horizontalDirection && horizontalDirection === \"right\") || verticalDirection === \"down\") ? 2 : 1 )\n\t\t\t: ( verticalDirection && (verticalDirection === \"down\" ? 2 : 1) );\n\n\t},\n\n\t_intersectsWithSides: function(item) {\n\n\t\tvar isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),\n\t\t\tisOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),\n\t\t\tverticalDirection = this._getDragVerticalDirection(),\n\t\t\thorizontalDirection = this._getDragHorizontalDirection();\n\n\t\tif (this.floating && horizontalDirection) {\n\t\t\treturn ((horizontalDirection === \"right\" && isOverRightHalf) || (horizontalDirection === \"left\" && !isOverRightHalf));\n\t\t} else {\n\t\t\treturn verticalDirection && ((verticalDirection === \"down\" && isOverBottomHalf) || (verticalDirection === \"up\" && !isOverBottomHalf));\n\t\t}\n\n\t},\n\n\t_getDragVerticalDirection: function() {\n\t\tvar delta = this.positionAbs.top - this.lastPositionAbs.top;\n\t\treturn delta !== 0 && (delta > 0 ? \"down\" : \"up\");\n\t},\n\n\t_getDragHorizontalDirection: function() {\n\t\tvar delta = this.positionAbs.left - this.lastPositionAbs.left;\n\t\treturn delta !== 0 && (delta > 0 ? \"right\" : \"left\");\n\t},\n\n\trefresh: function(event) {\n\t\tthis._refreshItems(event);\n\t\tthis.refreshPositions();\n\t\treturn this;\n\t},\n\n\t_connectWith: function() {\n\t\tvar options = this.options;\n\t\treturn options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;\n\t},\n\n\t_getItemsAsjQuery: function(connected) {\n\n\t\tvar i, j, cur, inst,\n\t\t\titems = [],\n\t\t\tqueries = [],\n\t\t\tconnectWith = this._connectWith();\n\n\t\tif(connectWith && connected) {\n\t\t\tfor (i = connectWith.length - 1; i >= 0; i--){\n\t\t\t\tcur = $(connectWith[i]);\n\t\t\t\tfor ( j = cur.length - 1; j >= 0; j--){\n\t\t\t\t\tinst = $.data(cur[j], this.widgetFullName);\n\t\t\t\t\tif(inst && inst !== this && !inst.options.disabled) {\n\t\t\t\t\t\tqueries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(\".ui-sortable-helper\").not(\".ui-sortable-placeholder\"), inst]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tqueries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(\".ui-sortable-helper\").not(\".ui-sortable-placeholder\"), this]);\n\n\t\tfor (i = queries.length - 1; i >= 0; i--){\n\t\t\tqueries[i][0].each(function() {\n\t\t\t\titems.push(this);\n\t\t\t});\n\t\t}\n\n\t\treturn $(items);\n\n\t},\n\n\t_removeCurrentsFromItems: function() {\n\n\t\tvar list = this.currentItem.find(\":data(\" + this.widgetName + \"-item)\");\n\n\t\tthis.items = $.grep(this.items, function (item) {\n\t\t\tfor (var j=0; j < list.length; j++) {\n\t\t\t\tif(list[j] === item.item[0]) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t},\n\n\t_refreshItems: function(event) {\n\n\t\tthis.items = [];\n\t\tthis.containers = [this];\n\n\t\tvar i, j, cur, inst, targetData, _queries, item, queriesLength,\n\t\t\titems = this.items,\n\t\t\tqueries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],\n\t\t\tconnectWith = this._connectWith();\n\n\t\tif(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down\n\t\t\tfor (i = connectWith.length - 1; i >= 0; i--){\n\t\t\t\tcur = $(connectWith[i]);\n\t\t\t\tfor (j = cur.length - 1; j >= 0; j--){\n\t\t\t\t\tinst = $.data(cur[j], this.widgetFullName);\n\t\t\t\t\tif(inst && inst !== this && !inst.options.disabled) {\n\t\t\t\t\t\tqueries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);\n\t\t\t\t\t\tthis.containers.push(inst);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (i = queries.length - 1; i >= 0; i--) {\n\t\t\ttargetData = queries[i][1];\n\t\t\t_queries = queries[i][0];\n\n\t\t\tfor (j=0, queriesLength = _queries.length; j < queriesLength; j++) {\n\t\t\t\titem = $(_queries[j]);\n\n\t\t\t\titem.data(this.widgetName + \"-item\", targetData); // Data for target checking (mouse manager)\n\n\t\t\t\titems.push({\n\t\t\t\t\titem: item,\n\t\t\t\t\tinstance: targetData,\n\t\t\t\t\twidth: 0, height: 0,\n\t\t\t\t\tleft: 0, top: 0\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t},\n\n\trefreshPositions: function(fast) {\n\n\t\t//This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change\n\t\tif(this.offsetParent && this.helper) {\n\t\t\tthis.offset.parent = this._getParentOffset();\n\t\t}\n\n\t\tvar i, item, t, p;\n\n\t\tfor (i = this.items.length - 1; i >= 0; i--){\n\t\t\titem = this.items[i];\n\n\t\t\t//We ignore calculating positions of all connected containers when we're not over them\n\t\t\tif(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tt = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;\n\n\t\t\tif (!fast) {\n\t\t\t\titem.width = t.outerWidth();\n\t\t\t\titem.height = t.outerHeight();\n\t\t\t}\n\n\t\t\tp = t.offset();\n\t\t\titem.left = p.left;\n\t\t\titem.top = p.top;\n\t\t}\n\n\t\tif(this.options.custom && this.options.custom.refreshContainers) {\n\t\t\tthis.options.custom.refreshContainers.call(this);\n\t\t} else {\n\t\t\tfor (i = this.containers.length - 1; i >= 0; i--){\n\t\t\t\tp = this.containers[i].element.offset();\n\t\t\t\tthis.containers[i].containerCache.left = p.left;\n\t\t\t\tthis.containers[i].containerCache.top = p.top;\n\t\t\t\tthis.containers[i].containerCache.width\t= this.containers[i].element.outerWidth();\n\t\t\t\tthis.containers[i].containerCache.height = this.containers[i].element.outerHeight();\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t_createPlaceholder: function(that) {\n\t\tthat = that || this;\n\t\tvar className,\n\t\t\to = that.options;\n\n\t\tif(!o.placeholder || o.placeholder.constructor === String) {\n\t\t\tclassName = o.placeholder;\n\t\t\to.placeholder = {\n\t\t\t\telement: function() {\n\n\t\t\t\t\tvar el = $(document.createElement(that.currentItem[0].nodeName))\n\t\t\t\t\t\t.addClass(className || that.currentItem[0].className+\" ui-sortable-placeholder\")\n\t\t\t\t\t\t.removeClass(\"ui-sortable-helper\")[0];\n\n\t\t\t\t\tif(!className) {\n\t\t\t\t\t\tel.style.visibility = \"hidden\";\n\t\t\t\t\t}\n\n\t\t\t\t\treturn el;\n\t\t\t\t},\n\t\t\t\tupdate: function(container, p) {\n\n\t\t\t\t\t// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that\n\t\t\t\t\t// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified\n\t\t\t\t\tif(className && !o.forcePlaceholderSize) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t//If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item\n\t\t\t\t\tif(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css(\"paddingTop\")||0, 10) - parseInt(that.currentItem.css(\"paddingBottom\")||0, 10)); }\n\t\t\t\t\tif(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css(\"paddingLeft\")||0, 10) - parseInt(that.currentItem.css(\"paddingRight\")||0, 10)); }\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t//Create the placeholder\n\t\tthat.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));\n\n\t\t//Append it after the actual current item\n\t\tthat.currentItem.after(that.placeholder);\n\n\t\t//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)\n\t\to.placeholder.update(that, that.placeholder);\n\n\t},\n\n\t_contactContainers: function(event) {\n\t\tvar i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom,\n\t\t\tinnermostContainer = null,\n\t\t\tinnermostIndex = null;\n\n\t\t// get innermost container that intersects with item\n\t\tfor (i = this.containers.length - 1; i >= 0; i--) {\n\n\t\t\t// never consider a container that's located within the item itself\n\t\t\tif($.contains(this.currentItem[0], this.containers[i].element[0])) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(this._intersectsWith(this.containers[i].containerCache)) {\n\n\t\t\t\t// if we've already found a container and it's more \"inner\" than this, then continue\n\t\t\t\tif(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tinnermostContainer = this.containers[i];\n\t\t\t\tinnermostIndex = i;\n\n\t\t\t} else {\n\t\t\t\t// container doesn't intersect. trigger \"out\" event if necessary\n\t\t\t\tif(this.containers[i].containerCache.over) {\n\t\t\t\t\tthis.containers[i]._trigger(\"out\", event, this._uiHash(this));\n\t\t\t\t\tthis.containers[i].containerCache.over = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\t// if no intersecting containers found, return\n\t\tif(!innermostContainer) {\n\t\t\treturn;\n\t\t}\n\n\t\t// move the item into the container if it's not there already\n\t\tif(this.containers.length === 1) {\n\t\t\tthis.containers[innermostIndex]._trigger(\"over\", event, this._uiHash(this));\n\t\t\tthis.containers[innermostIndex].containerCache.over = 1;\n\t\t} else {\n\n\t\t\t//When entering a new container, we will find the item with the least distance and append our item near it\n\t\t\tdist = 10000;\n\t\t\titemWithLeastDistance = null;\n\t\t\tposProperty = this.containers[innermostIndex].floating ? \"left\" : \"top\";\n\t\t\tsizeProperty = this.containers[innermostIndex].floating ? \"width\" : \"height\";\n\t\t\tbase = this.positionAbs[posProperty] + this.offset.click[posProperty];\n\t\t\tfor (j = this.items.length - 1; j >= 0; j--) {\n\t\t\t\tif(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(this.items[j].item[0] === this.currentItem[0]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcur = this.items[j].item.offset()[posProperty];\n\t\t\t\tnearBottom = false;\n\t\t\t\tif(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){\n\t\t\t\t\tnearBottom = true;\n\t\t\t\t\tcur += this.items[j][sizeProperty];\n\t\t\t\t}\n\n\t\t\t\tif(Math.abs(cur - base) < dist) {\n\t\t\t\t\tdist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];\n\t\t\t\t\tthis.direction = nearBottom ? \"up\": \"down\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//Check if dropOnEmpty is enabled\n\t\t\tif(!itemWithLeastDistance && !this.options.dropOnEmpty) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.currentContainer = this.containers[innermostIndex];\n\t\t\titemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);\n\t\t\tthis._trigger(\"change\", event, this._uiHash());\n\t\t\tthis.containers[innermostIndex]._trigger(\"change\", event, this._uiHash(this));\n\n\t\t\t//Update the placeholder\n\t\t\tthis.options.placeholder.update(this.currentContainer, this.placeholder);\n\n\t\t\tthis.containers[innermostIndex]._trigger(\"over\", event, this._uiHash(this));\n\t\t\tthis.containers[innermostIndex].containerCache.over = 1;\n\t\t}\n\n\n\t},\n\n\t_createHelper: function(event) {\n\n\t\tvar o = this.options,\n\t\t\thelper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === \"clone\" ? this.currentItem.clone() : this.currentItem);\n\n\t\t//Add the helper to the DOM if that didn't happen already\n\t\tif(!helper.parents(\"body\").length) {\n\t\t\t$(o.appendTo !== \"parent\" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);\n\t\t}\n\n\t\tif(helper[0] === this.currentItem[0]) {\n\t\t\tthis._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css(\"position\"), top: this.currentItem.css(\"top\"), left: this.currentItem.css(\"left\") };\n\t\t}\n\n\t\tif(!helper[0].style.width || o.forceHelperSize) {\n\t\t\thelper.width(this.currentItem.width());\n\t\t}\n\t\tif(!helper[0].style.height || o.forceHelperSize) {\n\t\t\thelper.height(this.currentItem.height());\n\t\t}\n\n\t\treturn helper;\n\n\t},\n\n\t_adjustOffsetFromHelper: function(obj) {\n\t\tif (typeof obj === \"string\") {\n\t\t\tobj = obj.split(\" \");\n\t\t}\n\t\tif ($.isArray(obj)) {\n\t\t\tobj = {left: +obj[0], top: +obj[1] || 0};\n\t\t}\n\t\tif (\"left\" in obj) {\n\t\t\tthis.offset.click.left = obj.left + this.margins.left;\n\t\t}\n\t\tif (\"right\" in obj) {\n\t\t\tthis.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;\n\t\t}\n\t\tif (\"top\" in obj) {\n\t\t\tthis.offset.click.top = obj.top + this.margins.top;\n\t\t}\n\t\tif (\"bottom\" in obj) {\n\t\t\tthis.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;\n\t\t}\n\t},\n\n\t_getParentOffset: function() {\n\n\n\t\t//Get the offsetParent and cache its position\n\t\tthis.offsetParent = this.helper.offsetParent();\n\t\tvar po = this.offsetParent.offset();\n\n\t\t// This is a special case where we need to modify a offset calculated on start, since the following happened:\n\t\t// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent\n\t\t// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that\n\t\t//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag\n\t\tif(this.cssPosition === \"absolute\" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {\n\t\t\tpo.left += this.scrollParent.scrollLeft();\n\t\t\tpo.top += this.scrollParent.scrollTop();\n\t\t}\n\n\t\t// This needs to be actually done for all browsers, since pageX/pageY includes this information\n\t\t// with an ugly IE fix\n\t\tif( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === \"html\" && $.ui.ie)) {\n\t\t\tpo = { top: 0, left: 0 };\n\t\t}\n\n\t\treturn {\n\t\t\ttop: po.top + (parseInt(this.offsetParent.css(\"borderTopWidth\"),10) || 0),\n\t\t\tleft: po.left + (parseInt(this.offsetParent.css(\"borderLeftWidth\"),10) || 0)\n\t\t};\n\n\t},\n\n\t_getRelativeOffset: function() {\n\n\t\tif(this.cssPosition === \"relative\") {\n\t\t\tvar p = this.currentItem.position();\n\t\t\treturn {\n\t\t\t\ttop: p.top - (parseInt(this.helper.css(\"top\"),10) || 0) + this.scrollParent.scrollTop(),\n\t\t\t\tleft: p.left - (parseInt(this.helper.css(\"left\"),10) || 0) + this.scrollParent.scrollLeft()\n\t\t\t};\n\t\t} else {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t},\n\n\t_cacheMargins: function() {\n\t\tthis.margins = {\n\t\t\tleft: (parseInt(this.currentItem.css(\"marginLeft\"),10) || 0),\n\t\t\ttop: (parseInt(this.currentItem.css(\"marginTop\"),10) || 0)\n\t\t};\n\t},\n\n\t_cacheHelperProportions: function() {\n\t\tthis.helperProportions = {\n\t\t\twidth: this.helper.outerWidth(),\n\t\t\theight: this.helper.outerHeight()\n\t\t};\n\t},\n\n\t_setContainment: function() {\n\n\t\tvar ce, co, over,\n\t\t\to = this.options;\n\t\tif(o.containment === \"parent\") {\n\t\t\to.containment = this.helper[0].parentNode;\n\t\t}\n\t\tif(o.containment === \"document\" || o.containment === \"window\") {\n\t\t\tthis.containment = [\n\t\t\t\t0 - this.offset.relative.left - this.offset.parent.left,\n\t\t\t\t0 - this.offset.relative.top - this.offset.parent.top,\n\t\t\t\t$(o.containment === \"document\" ? document : window).width() - this.helperProportions.width - this.margins.left,\n\t\t\t\t($(o.containment === \"document\" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top\n\t\t\t];\n\t\t}\n\n\t\tif(!(/^(document|window|parent)$/).test(o.containment)) {\n\t\t\tce = $(o.containment)[0];\n\t\t\tco = $(o.containment).offset();\n\t\t\tover = ($(ce).css(\"overflow\") !== \"hidden\");\n\n\t\t\tthis.containment = [\n\t\t\t\tco.left + (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingLeft\"),10) || 0) - this.margins.left,\n\t\t\t\tco.top + (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingTop\"),10) || 0) - this.margins.top,\n\t\t\t\tco.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingRight\"),10) || 0) - this.helperProportions.width - this.margins.left,\n\t\t\t\tco.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingBottom\"),10) || 0) - this.helperProportions.height - this.margins.top\n\t\t\t];\n\t\t}\n\n\t},\n\n\t_convertPositionTo: function(d, pos) {\n\n\t\tif(!pos) {\n\t\t\tpos = this.position;\n\t\t}\n\t\tvar mod = d === \"absolute\" ? 1 : -1,\n\t\t\tscroll = this.cssPosition === \"absolute\" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,\n\t\t\tscrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpos.top\t+\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.relative.top * mod +\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.top * mod -\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpos.left +\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.relative.left * mod +\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.left * mod\t-\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_generatePosition: function(event) {\n\n\t\tvar top, left,\n\t\t\to = this.options,\n\t\t\tpageX = event.pageX,\n\t\t\tpageY = event.pageY,\n\t\t\tscroll = this.cssPosition === \"absolute\" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\n\t\t// This is another very weird special case that only happens for relative elements:\n\t\t// 1. If the css position is relative\n\t\t// 2. and the scroll parent is the document or similar to the offset parent\n\t\t// we have to refresh the relative offset during the scroll so there are no jumps\n\t\tif(this.cssPosition === \"relative\" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {\n\t\t\tthis.offset.relative = this._getRelativeOffset();\n\t\t}\n\n\t\t/*\n\t\t * - Position constraining -\n\t\t * Constrain the position to a mix of grid, containment.\n\t\t */\n\n\t\tif(this.originalPosition) { //If we are not dragging yet, we won't check for options\n\n\t\t\tif(this.containment) {\n\t\t\t\tif(event.pageX - this.offset.click.left < this.containment[0]) {\n\t\t\t\t\tpageX = this.containment[0] + this.offset.click.left;\n\t\t\t\t}\n\t\t\t\tif(event.pageY - this.offset.click.top < this.containment[1]) {\n\t\t\t\t\tpageY = this.containment[1] + this.offset.click.top;\n\t\t\t\t}\n\t\t\t\tif(event.pageX - this.offset.click.left > this.containment[2]) {\n\t\t\t\t\tpageX = this.containment[2] + this.offset.click.left;\n\t\t\t\t}\n\t\t\t\tif(event.pageY - this.offset.click.top > this.containment[3]) {\n\t\t\t\t\tpageY = this.containment[3] + this.offset.click.top;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(o.grid) {\n\t\t\t\ttop = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];\n\t\t\t\tpageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;\n\n\t\t\t\tleft = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];\n\t\t\t\tpageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpageY -\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.click.top -\t\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\tthis.offset.relative.top\t-\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.top +\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpageX -\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\tthis.offset.click.left -\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\tthis.offset.relative.left\t-\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\tthis.offset.parent.left +\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t( ( this.cssPosition === \"fixed\" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_rearrange: function(event, i, a, hardRefresh) {\n\n\t\ta ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === \"down\" ? i.item[0] : i.item[0].nextSibling));\n\n\t\t//Various things done here to improve the performance:\n\t\t// 1. we create a setTimeout, that calls refreshPositions\n\t\t// 2. on the instance, we have a counter variable, that get's higher after every append\n\t\t// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same\n\t\t// 4. this lets only the last addition to the timeout stack through\n\t\tthis.counter = this.counter ? ++this.counter : 1;\n\t\tvar counter = this.counter;\n\n\t\tthis._delay(function() {\n\t\t\tif(counter === this.counter) {\n\t\t\t\tthis.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove\n\t\t\t}\n\t\t});\n\n\t},\n\n\t_clear: function(event, noPropagation) {\n\n\t\tthis.reverting = false;\n\t\t// We delay all events that have to be triggered to after the point where the placeholder has been removed and\n\t\t// everything else normalized again\n\t\tvar i,\n\t\t\tdelayedTriggers = [];\n\n\t\t// We first have to update the dom position of the actual currentItem\n\t\t// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)\n\t\tif(!this._noFinalSort && this.currentItem.parent().length) {\n\t\t\tthis.placeholder.before(this.currentItem);\n\t\t}\n\t\tthis._noFinalSort = null;\n\n\t\tif(this.helper[0] === this.currentItem[0]) {\n\t\t\tfor(i in this._storedCSS) {\n\t\t\t\tif(this._storedCSS[i] === \"auto\" || this._storedCSS[i] === \"static\") {\n\t\t\t\t\tthis._storedCSS[i] = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\");\n\t\t} else {\n\t\t\tthis.currentItem.show();\n\t\t}\n\n\t\tif(this.fromOutside && !noPropagation) {\n\t\t\tdelayedTriggers.push(function(event) { this._trigger(\"receive\", event, this._uiHash(this.fromOutside)); });\n\t\t}\n\t\tif((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(\".ui-sortable-helper\")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {\n\t\t\tdelayedTriggers.push(function(event) { this._trigger(\"update\", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed\n\t\t}\n\n\t\t// Check if the items Container has Changed and trigger appropriate\n\t\t// events.\n\t\tif (this !== this.currentContainer) {\n\t\t\tif(!noPropagation) {\n\t\t\t\tdelayedTriggers.push(function(event) { this._trigger(\"remove\", event, this._uiHash()); });\n\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"receive\", event, this._uiHash(this)); };  }).call(this, this.currentContainer));\n\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"update\", event, this._uiHash(this));  }; }).call(this, this.currentContainer));\n\t\t\t}\n\t\t}\n\n\n\t\t//Post events to containers\n\t\tfor (i = this.containers.length - 1; i >= 0; i--){\n\t\t\tif(!noPropagation) {\n\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"deactivate\", event, this._uiHash(this)); };  }).call(this, this.containers[i]));\n\t\t\t}\n\t\t\tif(this.containers[i].containerCache.over) {\n\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"out\", event, this._uiHash(this)); };  }).call(this, this.containers[i]));\n\t\t\t\tthis.containers[i].containerCache.over = 0;\n\t\t\t}\n\t\t}\n\n\t\t//Do what was originally in plugins\n\t\tif(this._storedCursor) {\n\t\t\t$(\"body\").css(\"cursor\", this._storedCursor);\n\t\t}\n\t\tif(this._storedOpacity) {\n\t\t\tthis.helper.css(\"opacity\", this._storedOpacity);\n\t\t}\n\t\tif(this._storedZIndex) {\n\t\t\tthis.helper.css(\"zIndex\", this._storedZIndex === \"auto\" ? \"\" : this._storedZIndex);\n\t\t}\n\n\t\tthis.dragging = false;\n\t\tif(this.cancelHelperRemoval) {\n\t\t\tif(!noPropagation) {\n\t\t\t\tthis._trigger(\"beforeStop\", event, this._uiHash());\n\t\t\t\tfor (i=0; i < delayedTriggers.length; i++) {\n\t\t\t\t\tdelayedTriggers[i].call(this, event);\n\t\t\t\t} //Trigger all delayed events\n\t\t\t\tthis._trigger(\"stop\", event, this._uiHash());\n\t\t\t}\n\n\t\t\tthis.fromOutside = false;\n\t\t\treturn false;\n\t\t}\n\n\t\tif(!noPropagation) {\n\t\t\tthis._trigger(\"beforeStop\", event, this._uiHash());\n\t\t}\n\n\t\t//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!\n\t\tthis.placeholder[0].parentNode.removeChild(this.placeholder[0]);\n\n\t\tif(this.helper[0] !== this.currentItem[0]) {\n\t\t\tthis.helper.remove();\n\t\t}\n\t\tthis.helper = null;\n\n\t\tif(!noPropagation) {\n\t\t\tfor (i=0; i < delayedTriggers.length; i++) {\n\t\t\t\tdelayedTriggers[i].call(this, event);\n\t\t\t} //Trigger all delayed events\n\t\t\tthis._trigger(\"stop\", event, this._uiHash());\n\t\t}\n\n\t\tthis.fromOutside = false;\n\t\treturn true;\n\n\t},\n\n\t_trigger: function() {\n\t\tif ($.Widget.prototype._trigger.apply(this, arguments) === false) {\n\t\t\tthis.cancel();\n\t\t}\n\t},\n\n\t_uiHash: function(_inst) {\n\t\tvar inst = _inst || this;\n\t\treturn {\n\t\t\thelper: inst.helper,\n\t\t\tplaceholder: inst.placeholder || $([]),\n\t\t\tposition: inst.position,\n\t\t\toriginalPosition: inst.originalPosition,\n\t\t\toffset: inst.positionAbs,\n\t\t\titem: inst.currentItem,\n\t\t\tsender: _inst ? _inst.element : null\n\t\t};\n\t}\n\n});\n\n})(jQuery);\n\n;(jQuery.effects || (function($, undefined) {\n\nvar dataSpace = \"ui-effects-\";\n\n$.effects = {\n\teffect: {}\n};\n\n/*!\n * jQuery Color Animations v2.1.2\n * https://github.com/jquery/jquery-color\n *\n * Copyright 2013 jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n *\n * Date: Wed Jan 16 08:47:09 2013 -0600\n */\n(function( jQuery, undefined ) {\n\n\tvar stepHooks = \"backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor\",\n\n\t// plusequals test for += 100 -= 100\n\trplusequals = /^([\\-+])=\\s*(\\d+\\.?\\d*)/,\n\t// a set of RE's that can match strings and generate color tuples.\n\tstringParsers = [{\n\t\t\tre: /rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d?(?:\\.\\d+)?)\\s*)?\\)/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\texecResult[ 1 ],\n\t\t\t\t\texecResult[ 2 ],\n\t\t\t\t\texecResult[ 3 ],\n\t\t\t\t\texecResult[ 4 ]\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\t\t\tre: /rgba?\\(\\s*(\\d+(?:\\.\\d+)?)\\%\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d?(?:\\.\\d+)?)\\s*)?\\)/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\texecResult[ 1 ] * 2.55,\n\t\t\t\t\texecResult[ 2 ] * 2.55,\n\t\t\t\t\texecResult[ 3 ] * 2.55,\n\t\t\t\t\texecResult[ 4 ]\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\t\t\t// this regex ignores A-F because it's compared against an already lowercased string\n\t\t\tre: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\tparseInt( execResult[ 1 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 2 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 3 ], 16 )\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\t\t\t// this regex ignores A-F because it's compared against an already lowercased string\n\t\t\tre: /#([a-f0-9])([a-f0-9])([a-f0-9])/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\tparseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 3 ] + execResult[ 3 ], 16 )\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\t\t\tre: /hsla?\\(\\s*(\\d+(?:\\.\\d+)?)\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d?(?:\\.\\d+)?)\\s*)?\\)/,\n\t\t\tspace: \"hsla\",\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\texecResult[ 1 ],\n\t\t\t\t\texecResult[ 2 ] / 100,\n\t\t\t\t\texecResult[ 3 ] / 100,\n\t\t\t\t\texecResult[ 4 ]\n\t\t\t\t];\n\t\t\t}\n\t\t}],\n\n\t// jQuery.Color( )\n\tcolor = jQuery.Color = function( color, green, blue, alpha ) {\n\t\treturn new jQuery.Color.fn.parse( color, green, blue, alpha );\n\t},\n\tspaces = {\n\t\trgba: {\n\t\t\tprops: {\n\t\t\t\tred: {\n\t\t\t\t\tidx: 0,\n\t\t\t\t\ttype: \"byte\"\n\t\t\t\t},\n\t\t\t\tgreen: {\n\t\t\t\t\tidx: 1,\n\t\t\t\t\ttype: \"byte\"\n\t\t\t\t},\n\t\t\t\tblue: {\n\t\t\t\t\tidx: 2,\n\t\t\t\t\ttype: \"byte\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\thsla: {\n\t\t\tprops: {\n\t\t\t\thue: {\n\t\t\t\t\tidx: 0,\n\t\t\t\t\ttype: \"degrees\"\n\t\t\t\t},\n\t\t\t\tsaturation: {\n\t\t\t\t\tidx: 1,\n\t\t\t\t\ttype: \"percent\"\n\t\t\t\t},\n\t\t\t\tlightness: {\n\t\t\t\t\tidx: 2,\n\t\t\t\t\ttype: \"percent\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\tpropTypes = {\n\t\t\"byte\": {\n\t\t\tfloor: true,\n\t\t\tmax: 255\n\t\t},\n\t\t\"percent\": {\n\t\t\tmax: 1\n\t\t},\n\t\t\"degrees\": {\n\t\t\tmod: 360,\n\t\t\tfloor: true\n\t\t}\n\t},\n\tsupport = color.support = {},\n\n\t// element for support tests\n\tsupportElem = jQuery( \"<p>\" )[ 0 ],\n\n\t// colors = jQuery.Color.names\n\tcolors,\n\n\t// local aliases of functions called often\n\teach = jQuery.each;\n\n// determine rgba support immediately\nsupportElem.style.cssText = \"background-color:rgba(1,1,1,.5)\";\nsupport.rgba = supportElem.style.backgroundColor.indexOf( \"rgba\" ) > -1;\n\n// define cache name and alpha properties\n// for rgba and hsla spaces\neach( spaces, function( spaceName, space ) {\n\tspace.cache = \"_\" + spaceName;\n\tspace.props.alpha = {\n\t\tidx: 3,\n\t\ttype: \"percent\",\n\t\tdef: 1\n\t};\n});\n\nfunction clamp( value, prop, allowEmpty ) {\n\tvar type = propTypes[ prop.type ] || {};\n\n\tif ( value == null ) {\n\t\treturn (allowEmpty || !prop.def) ? null : prop.def;\n\t}\n\n\t// ~~ is an short way of doing floor for positive numbers\n\tvalue = type.floor ? ~~value : parseFloat( value );\n\n\t// IE will pass in empty strings as value for alpha,\n\t// which will hit this case\n\tif ( isNaN( value ) ) {\n\t\treturn prop.def;\n\t}\n\n\tif ( type.mod ) {\n\t\t// we add mod before modding to make sure that negatives values\n\t\t// get converted properly: -10 -> 350\n\t\treturn (value + type.mod) % type.mod;\n\t}\n\n\t// for now all property types without mod have min and max\n\treturn 0 > value ? 0 : type.max < value ? type.max : value;\n}\n\nfunction stringParse( string ) {\n\tvar inst = color(),\n\t\trgba = inst._rgba = [];\n\n\tstring = string.toLowerCase();\n\n\teach( stringParsers, function( i, parser ) {\n\t\tvar parsed,\n\t\t\tmatch = parser.re.exec( string ),\n\t\t\tvalues = match && parser.parse( match ),\n\t\t\tspaceName = parser.space || \"rgba\";\n\n\t\tif ( values ) {\n\t\t\tparsed = inst[ spaceName ]( values );\n\n\t\t\t// if this was an rgba parse the assignment might happen twice\n\t\t\t// oh well....\n\t\t\tinst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];\n\t\t\trgba = inst._rgba = parsed._rgba;\n\n\t\t\t// exit each( stringParsers ) here because we matched\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t// Found a stringParser that handled it\n\tif ( rgba.length ) {\n\n\t\t// if this came from a parsed string, force \"transparent\" when alpha is 0\n\t\t// chrome, (and maybe others) return \"transparent\" as rgba(0,0,0,0)\n\t\tif ( rgba.join() === \"0,0,0,0\" ) {\n\t\t\tjQuery.extend( rgba, colors.transparent );\n\t\t}\n\t\treturn inst;\n\t}\n\n\t// named colors\n\treturn colors[ string ];\n}\n\ncolor.fn = jQuery.extend( color.prototype, {\n\tparse: function( red, green, blue, alpha ) {\n\t\tif ( red === undefined ) {\n\t\t\tthis._rgba = [ null, null, null, null ];\n\t\t\treturn this;\n\t\t}\n\t\tif ( red.jquery || red.nodeType ) {\n\t\t\tred = jQuery( red ).css( green );\n\t\t\tgreen = undefined;\n\t\t}\n\n\t\tvar inst = this,\n\t\t\ttype = jQuery.type( red ),\n\t\t\trgba = this._rgba = [];\n\n\t\t// more than 1 argument specified - assume ( red, green, blue, alpha )\n\t\tif ( green !== undefined ) {\n\t\t\tred = [ red, green, blue, alpha ];\n\t\t\ttype = \"array\";\n\t\t}\n\n\t\tif ( type === \"string\" ) {\n\t\t\treturn this.parse( stringParse( red ) || colors._default );\n\t\t}\n\n\t\tif ( type === \"array\" ) {\n\t\t\teach( spaces.rgba.props, function( key, prop ) {\n\t\t\t\trgba[ prop.idx ] = clamp( red[ prop.idx ], prop );\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( type === \"object\" ) {\n\t\t\tif ( red instanceof color ) {\n\t\t\t\teach( spaces, function( spaceName, space ) {\n\t\t\t\t\tif ( red[ space.cache ] ) {\n\t\t\t\t\t\tinst[ space.cache ] = red[ space.cache ].slice();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\teach( spaces, function( spaceName, space ) {\n\t\t\t\t\tvar cache = space.cache;\n\t\t\t\t\teach( space.props, function( key, prop ) {\n\n\t\t\t\t\t\t// if the cache doesn't exist, and we know how to convert\n\t\t\t\t\t\tif ( !inst[ cache ] && space.to ) {\n\n\t\t\t\t\t\t\t// if the value was null, we don't need to copy it\n\t\t\t\t\t\t\t// if the key was alpha, we don't need to copy it either\n\t\t\t\t\t\t\tif ( key === \"alpha\" || red[ key ] == null ) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinst[ cache ] = space.to( inst._rgba );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// this is the only case where we allow nulls for ALL properties.\n\t\t\t\t\t\t// call clamp with alwaysAllowEmpty\n\t\t\t\t\t\tinst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );\n\t\t\t\t\t});\n\n\t\t\t\t\t// everything defined but alpha?\n\t\t\t\t\tif ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {\n\t\t\t\t\t\t// use the default of 1\n\t\t\t\t\t\tinst[ cache ][ 3 ] = 1;\n\t\t\t\t\t\tif ( space.from ) {\n\t\t\t\t\t\t\tinst._rgba = space.from( inst[ cache ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t},\n\tis: function( compare ) {\n\t\tvar is = color( compare ),\n\t\t\tsame = true,\n\t\t\tinst = this;\n\n\t\teach( spaces, function( _, space ) {\n\t\t\tvar localCache,\n\t\t\t\tisCache = is[ space.cache ];\n\t\t\tif (isCache) {\n\t\t\t\tlocalCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];\n\t\t\t\teach( space.props, function( _, prop ) {\n\t\t\t\t\tif ( isCache[ prop.idx ] != null ) {\n\t\t\t\t\t\tsame = ( isCache[ prop.idx ] === localCache[ prop.idx ] );\n\t\t\t\t\t\treturn same;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn same;\n\t\t});\n\t\treturn same;\n\t},\n\t_space: function() {\n\t\tvar used = [],\n\t\t\tinst = this;\n\t\teach( spaces, function( spaceName, space ) {\n\t\t\tif ( inst[ space.cache ] ) {\n\t\t\t\tused.push( spaceName );\n\t\t\t}\n\t\t});\n\t\treturn used.pop();\n\t},\n\ttransition: function( other, distance ) {\n\t\tvar end = color( other ),\n\t\t\tspaceName = end._space(),\n\t\t\tspace = spaces[ spaceName ],\n\t\t\tstartColor = this.alpha() === 0 ? color( \"transparent\" ) : this,\n\t\t\tstart = startColor[ space.cache ] || space.to( startColor._rgba ),\n\t\t\tresult = start.slice();\n\n\t\tend = end[ space.cache ];\n\t\teach( space.props, function( key, prop ) {\n\t\t\tvar index = prop.idx,\n\t\t\t\tstartValue = start[ index ],\n\t\t\t\tendValue = end[ index ],\n\t\t\t\ttype = propTypes[ prop.type ] || {};\n\n\t\t\t// if null, don't override start value\n\t\t\tif ( endValue === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// if null - use end\n\t\t\tif ( startValue === null ) {\n\t\t\t\tresult[ index ] = endValue;\n\t\t\t} else {\n\t\t\t\tif ( type.mod ) {\n\t\t\t\t\tif ( endValue - startValue > type.mod / 2 ) {\n\t\t\t\t\t\tstartValue += type.mod;\n\t\t\t\t\t} else if ( startValue - endValue > type.mod / 2 ) {\n\t\t\t\t\t\tstartValue -= type.mod;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );\n\t\t\t}\n\t\t});\n\t\treturn this[ spaceName ]( result );\n\t},\n\tblend: function( opaque ) {\n\t\t// if we are already opaque - return ourself\n\t\tif ( this._rgba[ 3 ] === 1 ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar rgb = this._rgba.slice(),\n\t\t\ta = rgb.pop(),\n\t\t\tblend = color( opaque )._rgba;\n\n\t\treturn color( jQuery.map( rgb, function( v, i ) {\n\t\t\treturn ( 1 - a ) * blend[ i ] + a * v;\n\t\t}));\n\t},\n\ttoRgbaString: function() {\n\t\tvar prefix = \"rgba(\",\n\t\t\trgba = jQuery.map( this._rgba, function( v, i ) {\n\t\t\t\treturn v == null ? ( i > 2 ? 1 : 0 ) : v;\n\t\t\t});\n\n\t\tif ( rgba[ 3 ] === 1 ) {\n\t\t\trgba.pop();\n\t\t\tprefix = \"rgb(\";\n\t\t}\n\n\t\treturn prefix + rgba.join() + \")\";\n\t},\n\ttoHslaString: function() {\n\t\tvar prefix = \"hsla(\",\n\t\t\thsla = jQuery.map( this.hsla(), function( v, i ) {\n\t\t\t\tif ( v == null ) {\n\t\t\t\t\tv = i > 2 ? 1 : 0;\n\t\t\t\t}\n\n\t\t\t\t// catch 1 and 2\n\t\t\t\tif ( i && i < 3 ) {\n\t\t\t\t\tv = Math.round( v * 100 ) + \"%\";\n\t\t\t\t}\n\t\t\t\treturn v;\n\t\t\t});\n\n\t\tif ( hsla[ 3 ] === 1 ) {\n\t\t\thsla.pop();\n\t\t\tprefix = \"hsl(\";\n\t\t}\n\t\treturn prefix + hsla.join() + \")\";\n\t},\n\ttoHexString: function( includeAlpha ) {\n\t\tvar rgba = this._rgba.slice(),\n\t\t\talpha = rgba.pop();\n\n\t\tif ( includeAlpha ) {\n\t\t\trgba.push( ~~( alpha * 255 ) );\n\t\t}\n\n\t\treturn \"#\" + jQuery.map( rgba, function( v ) {\n\n\t\t\t// default to 0 when nulls exist\n\t\t\tv = ( v || 0 ).toString( 16 );\n\t\t\treturn v.length === 1 ? \"0\" + v : v;\n\t\t}).join(\"\");\n\t},\n\ttoString: function() {\n\t\treturn this._rgba[ 3 ] === 0 ? \"transparent\" : this.toRgbaString();\n\t}\n});\ncolor.fn.parse.prototype = color.fn;\n\n// hsla conversions adapted from:\n// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021\n\nfunction hue2rgb( p, q, h ) {\n\th = ( h + 1 ) % 1;\n\tif ( h * 6 < 1 ) {\n\t\treturn p + (q - p) * h * 6;\n\t}\n\tif ( h * 2 < 1) {\n\t\treturn q;\n\t}\n\tif ( h * 3 < 2 ) {\n\t\treturn p + (q - p) * ((2/3) - h) * 6;\n\t}\n\treturn p;\n}\n\nspaces.hsla.to = function ( rgba ) {\n\tif ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {\n\t\treturn [ null, null, null, rgba[ 3 ] ];\n\t}\n\tvar r = rgba[ 0 ] / 255,\n\t\tg = rgba[ 1 ] / 255,\n\t\tb = rgba[ 2 ] / 255,\n\t\ta = rgba[ 3 ],\n\t\tmax = Math.max( r, g, b ),\n\t\tmin = Math.min( r, g, b ),\n\t\tdiff = max - min,\n\t\tadd = max + min,\n\t\tl = add * 0.5,\n\t\th, s;\n\n\tif ( min === max ) {\n\t\th = 0;\n\t} else if ( r === max ) {\n\t\th = ( 60 * ( g - b ) / diff ) + 360;\n\t} else if ( g === max ) {\n\t\th = ( 60 * ( b - r ) / diff ) + 120;\n\t} else {\n\t\th = ( 60 * ( r - g ) / diff ) + 240;\n\t}\n\n\t// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%\n\t// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)\n\tif ( diff === 0 ) {\n\t\ts = 0;\n\t} else if ( l <= 0.5 ) {\n\t\ts = diff / add;\n\t} else {\n\t\ts = diff / ( 2 - add );\n\t}\n\treturn [ Math.round(h) % 360, s, l, a == null ? 1 : a ];\n};\n\nspaces.hsla.from = function ( hsla ) {\n\tif ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {\n\t\treturn [ null, null, null, hsla[ 3 ] ];\n\t}\n\tvar h = hsla[ 0 ] / 360,\n\t\ts = hsla[ 1 ],\n\t\tl = hsla[ 2 ],\n\t\ta = hsla[ 3 ],\n\t\tq = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,\n\t\tp = 2 * l - q;\n\n\treturn [\n\t\tMath.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),\n\t\tMath.round( hue2rgb( p, q, h ) * 255 ),\n\t\tMath.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),\n\t\ta\n\t];\n};\n\n\neach( spaces, function( spaceName, space ) {\n\tvar props = space.props,\n\t\tcache = space.cache,\n\t\tto = space.to,\n\t\tfrom = space.from;\n\n\t// makes rgba() and hsla()\n\tcolor.fn[ spaceName ] = function( value ) {\n\n\t\t// generate a cache for this space if it doesn't exist\n\t\tif ( to && !this[ cache ] ) {\n\t\t\tthis[ cache ] = to( this._rgba );\n\t\t}\n\t\tif ( value === undefined ) {\n\t\t\treturn this[ cache ].slice();\n\t\t}\n\n\t\tvar ret,\n\t\t\ttype = jQuery.type( value ),\n\t\t\tarr = ( type === \"array\" || type === \"object\" ) ? value : arguments,\n\t\t\tlocal = this[ cache ].slice();\n\n\t\teach( props, function( key, prop ) {\n\t\t\tvar val = arr[ type === \"object\" ? key : prop.idx ];\n\t\t\tif ( val == null ) {\n\t\t\t\tval = local[ prop.idx ];\n\t\t\t}\n\t\t\tlocal[ prop.idx ] = clamp( val, prop );\n\t\t});\n\n\t\tif ( from ) {\n\t\t\tret = color( from( local ) );\n\t\t\tret[ cache ] = local;\n\t\t\treturn ret;\n\t\t} else {\n\t\t\treturn color( local );\n\t\t}\n\t};\n\n\t// makes red() green() blue() alpha() hue() saturation() lightness()\n\teach( props, function( key, prop ) {\n\t\t// alpha is included in more than one space\n\t\tif ( color.fn[ key ] ) {\n\t\t\treturn;\n\t\t}\n\t\tcolor.fn[ key ] = function( value ) {\n\t\t\tvar vtype = jQuery.type( value ),\n\t\t\t\tfn = ( key === \"alpha\" ? ( this._hsla ? \"hsla\" : \"rgba\" ) : spaceName ),\n\t\t\t\tlocal = this[ fn ](),\n\t\t\t\tcur = local[ prop.idx ],\n\t\t\t\tmatch;\n\n\t\t\tif ( vtype === \"undefined\" ) {\n\t\t\t\treturn cur;\n\t\t\t}\n\n\t\t\tif ( vtype === \"function\" ) {\n\t\t\t\tvalue = value.call( this, cur );\n\t\t\t\tvtype = jQuery.type( value );\n\t\t\t}\n\t\t\tif ( value == null && prop.empty ) {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif ( vtype === \"string\" ) {\n\t\t\t\tmatch = rplusequals.exec( value );\n\t\t\t\tif ( match ) {\n\t\t\t\t\tvalue = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === \"+\" ? 1 : -1 );\n\t\t\t\t}\n\t\t\t}\n\t\t\tlocal[ prop.idx ] = value;\n\t\t\treturn this[ fn ]( local );\n\t\t};\n\t});\n});\n\n// add cssHook and .fx.step function for each named hook.\n// accept a space separated string of properties\ncolor.hook = function( hook ) {\n\tvar hooks = hook.split( \" \" );\n\teach( hooks, function( i, hook ) {\n\t\tjQuery.cssHooks[ hook ] = {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar parsed, curElem,\n\t\t\t\t\tbackgroundColor = \"\";\n\n\t\t\t\tif ( value !== \"transparent\" && ( jQuery.type( value ) !== \"string\" || ( parsed = stringParse( value ) ) ) ) {\n\t\t\t\t\tvalue = color( parsed || value );\n\t\t\t\t\tif ( !support.rgba && value._rgba[ 3 ] !== 1 ) {\n\t\t\t\t\t\tcurElem = hook === \"backgroundColor\" ? elem.parentNode : elem;\n\t\t\t\t\t\twhile (\n\t\t\t\t\t\t\t(backgroundColor === \"\" || backgroundColor === \"transparent\") &&\n\t\t\t\t\t\t\tcurElem && curElem.style\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tbackgroundColor = jQuery.css( curElem, \"backgroundColor\" );\n\t\t\t\t\t\t\t\tcurElem = curElem.parentNode;\n\t\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvalue = value.blend( backgroundColor && backgroundColor !== \"transparent\" ?\n\t\t\t\t\t\t\tbackgroundColor :\n\t\t\t\t\t\t\t\"_default\" );\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue = value.toRgbaString();\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\telem.style[ hook ] = value;\n\t\t\t\t} catch( e ) {\n\t\t\t\t\t// wrapped to prevent IE from throwing errors on \"invalid\" values like 'auto' or 'inherit'\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tjQuery.fx.step[ hook ] = function( fx ) {\n\t\t\tif ( !fx.colorInit ) {\n\t\t\t\tfx.start = color( fx.elem, hook );\n\t\t\t\tfx.end = color( fx.end );\n\t\t\t\tfx.colorInit = true;\n\t\t\t}\n\t\t\tjQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );\n\t\t};\n\t});\n\n};\n\ncolor.hook( stepHooks );\n\njQuery.cssHooks.borderColor = {\n\texpand: function( value ) {\n\t\tvar expanded = {};\n\n\t\teach( [ \"Top\", \"Right\", \"Bottom\", \"Left\" ], function( i, part ) {\n\t\t\texpanded[ \"border\" + part + \"Color\" ] = value;\n\t\t});\n\t\treturn expanded;\n\t}\n};\n\n// Basic color names only.\n// Usage of any of the other color names requires adding yourself or including\n// jquery.color.svg-names.js.\ncolors = jQuery.Color.names = {\n\t// 4.1. Basic color keywords\n\taqua: \"#00ffff\",\n\tblack: \"#000000\",\n\tblue: \"#0000ff\",\n\tfuchsia: \"#ff00ff\",\n\tgray: \"#808080\",\n\tgreen: \"#008000\",\n\tlime: \"#00ff00\",\n\tmaroon: \"#800000\",\n\tnavy: \"#000080\",\n\tolive: \"#808000\",\n\tpurple: \"#800080\",\n\tred: \"#ff0000\",\n\tsilver: \"#c0c0c0\",\n\tteal: \"#008080\",\n\twhite: \"#ffffff\",\n\tyellow: \"#ffff00\",\n\n\t// 4.2.3. \"transparent\" color keyword\n\ttransparent: [ null, null, null, 0 ],\n\n\t_default: \"#ffffff\"\n};\n\n})( jQuery );\n\n\n/******************************************************************************/\n/****************************** CLASS ANIMATIONS ******************************/\n/******************************************************************************/\n(function() {\n\nvar classAnimationActions = [ \"add\", \"remove\", \"toggle\" ],\n\tshorthandStyles = {\n\t\tborder: 1,\n\t\tborderBottom: 1,\n\t\tborderColor: 1,\n\t\tborderLeft: 1,\n\t\tborderRight: 1,\n\t\tborderTop: 1,\n\t\tborderWidth: 1,\n\t\tmargin: 1,\n\t\tpadding: 1\n\t};\n\n$.each([ \"borderLeftStyle\", \"borderRightStyle\", \"borderBottomStyle\", \"borderTopStyle\" ], function( _, prop ) {\n\t$.fx.step[ prop ] = function( fx ) {\n\t\tif ( fx.end !== \"none\" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {\n\t\t\tjQuery.style( fx.elem, prop, fx.end );\n\t\t\tfx.setAttr = true;\n\t\t}\n\t};\n});\n\nfunction getElementStyles( elem ) {\n\tvar key, len,\n\t\tstyle = elem.ownerDocument.defaultView ?\n\t\t\telem.ownerDocument.defaultView.getComputedStyle( elem, null ) :\n\t\t\telem.currentStyle,\n\t\tstyles = {};\n\n\tif ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {\n\t\tlen = style.length;\n\t\twhile ( len-- ) {\n\t\t\tkey = style[ len ];\n\t\t\tif ( typeof style[ key ] === \"string\" ) {\n\t\t\t\tstyles[ $.camelCase( key ) ] = style[ key ];\n\t\t\t}\n\t\t}\n\t// support: Opera, IE <9\n\t} else {\n\t\tfor ( key in style ) {\n\t\t\tif ( typeof style[ key ] === \"string\" ) {\n\t\t\t\tstyles[ key ] = style[ key ];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn styles;\n}\n\n\nfunction styleDifference( oldStyle, newStyle ) {\n\tvar diff = {},\n\t\tname, value;\n\n\tfor ( name in newStyle ) {\n\t\tvalue = newStyle[ name ];\n\t\tif ( oldStyle[ name ] !== value ) {\n\t\t\tif ( !shorthandStyles[ name ] ) {\n\t\t\t\tif ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {\n\t\t\t\t\tdiff[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn diff;\n}\n\n// support: jQuery <1.8\nif ( !$.fn.addBack ) {\n\t$.fn.addBack = function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t};\n}\n\n$.effects.animateClass = function( value, duration, easing, callback ) {\n\tvar o = $.speed( duration, easing, callback );\n\n\treturn this.queue( function() {\n\t\tvar animated = $( this ),\n\t\t\tbaseClass = animated.attr( \"class\" ) || \"\",\n\t\t\tapplyClassChange,\n\t\t\tallAnimations = o.children ? animated.find( \"*\" ).addBack() : animated;\n\n\t\t// map the animated objects to store the original styles.\n\t\tallAnimations = allAnimations.map(function() {\n\t\t\tvar el = $( this );\n\t\t\treturn {\n\t\t\t\tel: el,\n\t\t\t\tstart: getElementStyles( this )\n\t\t\t};\n\t\t});\n\n\t\t// apply class change\n\t\tapplyClassChange = function() {\n\t\t\t$.each( classAnimationActions, function(i, action) {\n\t\t\t\tif ( value[ action ] ) {\n\t\t\t\t\tanimated[ action + \"Class\" ]( value[ action ] );\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\t\tapplyClassChange();\n\n\t\t// map all animated objects again - calculate new styles and diff\n\t\tallAnimations = allAnimations.map(function() {\n\t\t\tthis.end = getElementStyles( this.el[ 0 ] );\n\t\t\tthis.diff = styleDifference( this.start, this.end );\n\t\t\treturn this;\n\t\t});\n\n\t\t// apply original class\n\t\tanimated.attr( \"class\", baseClass );\n\n\t\t// map all animated objects again - this time collecting a promise\n\t\tallAnimations = allAnimations.map(function() {\n\t\t\tvar styleInfo = this,\n\t\t\t\tdfd = $.Deferred(),\n\t\t\t\topts = $.extend({}, o, {\n\t\t\t\t\tqueue: false,\n\t\t\t\t\tcomplete: function() {\n\t\t\t\t\t\tdfd.resolve( styleInfo );\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\tthis.el.animate( this.diff, opts );\n\t\t\treturn dfd.promise();\n\t\t});\n\n\t\t// once all animations have completed:\n\t\t$.when.apply( $, allAnimations.get() ).done(function() {\n\n\t\t\t// set the final class\n\t\t\tapplyClassChange();\n\n\t\t\t// for each animated element,\n\t\t\t// clear all css properties that were animated\n\t\t\t$.each( arguments, function() {\n\t\t\t\tvar el = this.el;\n\t\t\t\t$.each( this.diff, function(key) {\n\t\t\t\t\tel.css( key, \"\" );\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t// this is guarnteed to be there if you use jQuery.speed()\n\t\t\t// it also handles dequeuing the next anim...\n\t\t\to.complete.call( animated[ 0 ] );\n\t\t});\n\t});\n};\n\n$.fn.extend({\n\t_addClass: $.fn.addClass,\n\taddClass: function( classNames, speed, easing, callback ) {\n\t\treturn speed ?\n\t\t\t$.effects.animateClass.call( this,\n\t\t\t\t{ add: classNames }, speed, easing, callback ) :\n\t\t\tthis._addClass( classNames );\n\t},\n\n\t_removeClass: $.fn.removeClass,\n\tremoveClass: function( classNames, speed, easing, callback ) {\n\t\treturn arguments.length > 1 ?\n\t\t\t$.effects.animateClass.call( this,\n\t\t\t\t{ remove: classNames }, speed, easing, callback ) :\n\t\t\tthis._removeClass.apply( this, arguments );\n\t},\n\n\t_toggleClass: $.fn.toggleClass,\n\ttoggleClass: function( classNames, force, speed, easing, callback ) {\n\t\tif ( typeof force === \"boolean\" || force === undefined ) {\n\t\t\tif ( !speed ) {\n\t\t\t\t// without speed parameter\n\t\t\t\treturn this._toggleClass( classNames, force );\n\t\t\t} else {\n\t\t\t\treturn $.effects.animateClass.call( this,\n\t\t\t\t\t(force ? { add: classNames } : { remove: classNames }),\n\t\t\t\t\tspeed, easing, callback );\n\t\t\t}\n\t\t} else {\n\t\t\t// without force parameter\n\t\t\treturn $.effects.animateClass.call( this,\n\t\t\t\t{ toggle: classNames }, force, speed, easing );\n\t\t}\n\t},\n\n\tswitchClass: function( remove, add, speed, easing, callback) {\n\t\treturn $.effects.animateClass.call( this, {\n\t\t\tadd: add,\n\t\t\tremove: remove\n\t\t}, speed, easing, callback );\n\t}\n});\n\n})();\n\n/******************************************************************************/\n/*********************************** EFFECTS **********************************/\n/******************************************************************************/\n\n(function() {\n\n$.extend( $.effects, {\n\tversion: \"1.10.1\",\n\n\t// Saves a set of properties in a data storage\n\tsave: function( element, set ) {\n\t\tfor( var i=0; i < set.length; i++ ) {\n\t\t\tif ( set[ i ] !== null ) {\n\t\t\t\telement.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Restores a set of previously saved properties from a data storage\n\trestore: function( element, set ) {\n\t\tvar val, i;\n\t\tfor( i=0; i < set.length; i++ ) {\n\t\t\tif ( set[ i ] !== null ) {\n\t\t\t\tval = element.data( dataSpace + set[ i ] );\n\t\t\t\t// support: jQuery 1.6.2\n\t\t\t\t// http://bugs.jquery.com/ticket/9917\n\t\t\t\t// jQuery 1.6.2 incorrectly returns undefined for any falsy value.\n\t\t\t\t// We can't differentiate between \"\" and 0 here, so we just assume\n\t\t\t\t// empty string since it's likely to be a more common value...\n\t\t\t\tif ( val === undefined ) {\n\t\t\t\t\tval = \"\";\n\t\t\t\t}\n\t\t\t\telement.css( set[ i ], val );\n\t\t\t}\n\t\t}\n\t},\n\n\tsetMode: function( el, mode ) {\n\t\tif (mode === \"toggle\") {\n\t\t\tmode = el.is( \":hidden\" ) ? \"show\" : \"hide\";\n\t\t}\n\t\treturn mode;\n\t},\n\n\t// Translates a [top,left] array into a baseline value\n\t// this should be a little more flexible in the future to handle a string & hash\n\tgetBaseline: function( origin, original ) {\n\t\tvar y, x;\n\t\tswitch ( origin[ 0 ] ) {\n\t\t\tcase \"top\": y = 0; break;\n\t\t\tcase \"middle\": y = 0.5; break;\n\t\t\tcase \"bottom\": y = 1; break;\n\t\t\tdefault: y = origin[ 0 ] / original.height;\n\t\t}\n\t\tswitch ( origin[ 1 ] ) {\n\t\t\tcase \"left\": x = 0; break;\n\t\t\tcase \"center\": x = 0.5; break;\n\t\t\tcase \"right\": x = 1; break;\n\t\t\tdefault: x = origin[ 1 ] / original.width;\n\t\t}\n\t\treturn {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t},\n\n\t// Wraps the element around a wrapper that copies position properties\n\tcreateWrapper: function( element ) {\n\n\t\t// if the element is already wrapped, return it\n\t\tif ( element.parent().is( \".ui-effects-wrapper\" )) {\n\t\t\treturn element.parent();\n\t\t}\n\n\t\t// wrap the element\n\t\tvar props = {\n\t\t\t\twidth: element.outerWidth(true),\n\t\t\t\theight: element.outerHeight(true),\n\t\t\t\t\"float\": element.css( \"float\" )\n\t\t\t},\n\t\t\twrapper = $( \"<div></div>\" )\n\t\t\t\t.addClass( \"ui-effects-wrapper\" )\n\t\t\t\t.css({\n\t\t\t\t\tfontSize: \"100%\",\n\t\t\t\t\tbackground: \"transparent\",\n\t\t\t\t\tborder: \"none\",\n\t\t\t\t\tmargin: 0,\n\t\t\t\t\tpadding: 0\n\t\t\t\t}),\n\t\t\t// Store the size in case width/height are defined in % - Fixes #5245\n\t\t\tsize = {\n\t\t\t\twidth: element.width(),\n\t\t\t\theight: element.height()\n\t\t\t},\n\t\t\tactive = document.activeElement;\n\n\t\t// support: Firefox\n\t\t// Firefox incorrectly exposes anonymous content\n\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=561664\n\t\ttry {\n\t\t\tactive.id;\n\t\t} catch( e ) {\n\t\t\tactive = document.body;\n\t\t}\n\n\t\telement.wrap( wrapper );\n\n\t\t// Fixes #7595 - Elements lose focus when wrapped.\n\t\tif ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {\n\t\t\t$( active ).focus();\n\t\t}\n\n\t\twrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element\n\n\t\t// transfer positioning properties to the wrapper\n\t\tif ( element.css( \"position\" ) === \"static\" ) {\n\t\t\twrapper.css({ position: \"relative\" });\n\t\t\telement.css({ position: \"relative\" });\n\t\t} else {\n\t\t\t$.extend( props, {\n\t\t\t\tposition: element.css( \"position\" ),\n\t\t\t\tzIndex: element.css( \"z-index\" )\n\t\t\t});\n\t\t\t$.each([ \"top\", \"left\", \"bottom\", \"right\" ], function(i, pos) {\n\t\t\t\tprops[ pos ] = element.css( pos );\n\t\t\t\tif ( isNaN( parseInt( props[ pos ], 10 ) ) ) {\n\t\t\t\t\tprops[ pos ] = \"auto\";\n\t\t\t\t}\n\t\t\t});\n\t\t\telement.css({\n\t\t\t\tposition: \"relative\",\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\tright: \"auto\",\n\t\t\t\tbottom: \"auto\"\n\t\t\t});\n\t\t}\n\t\telement.css(size);\n\n\t\treturn wrapper.css( props ).show();\n\t},\n\n\tremoveWrapper: function( element ) {\n\t\tvar active = document.activeElement;\n\n\t\tif ( element.parent().is( \".ui-effects-wrapper\" ) ) {\n\t\t\telement.parent().replaceWith( element );\n\n\t\t\t// Fixes #7595 - Elements lose focus when wrapped.\n\t\t\tif ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {\n\t\t\t\t$( active ).focus();\n\t\t\t}\n\t\t}\n\n\n\t\treturn element;\n\t},\n\n\tsetTransition: function( element, list, factor, value ) {\n\t\tvalue = value || {};\n\t\t$.each( list, function( i, x ) {\n\t\t\tvar unit = element.cssUnit( x );\n\t\t\tif ( unit[ 0 ] > 0 ) {\n\t\t\t\tvalue[ x ] = unit[ 0 ] * factor + unit[ 1 ];\n\t\t\t}\n\t\t});\n\t\treturn value;\n\t}\n});\n\n// return an effect options object for the given parameters:\nfunction _normalizeArguments( effect, options, speed, callback ) {\n\n\t// allow passing all options as the first parameter\n\tif ( $.isPlainObject( effect ) ) {\n\t\toptions = effect;\n\t\teffect = effect.effect;\n\t}\n\n\t// convert to an object\n\teffect = { effect: effect };\n\n\t// catch (effect, null, ...)\n\tif ( options == null ) {\n\t\toptions = {};\n\t}\n\n\t// catch (effect, callback)\n\tif ( $.isFunction( options ) ) {\n\t\tcallback = options;\n\t\tspeed = null;\n\t\toptions = {};\n\t}\n\n\t// catch (effect, speed, ?)\n\tif ( typeof options === \"number\" || $.fx.speeds[ options ] ) {\n\t\tcallback = speed;\n\t\tspeed = options;\n\t\toptions = {};\n\t}\n\n\t// catch (effect, options, callback)\n\tif ( $.isFunction( speed ) ) {\n\t\tcallback = speed;\n\t\tspeed = null;\n\t}\n\n\t// add options to effect\n\tif ( options ) {\n\t\t$.extend( effect, options );\n\t}\n\n\tspeed = speed || options.duration;\n\teffect.duration = $.fx.off ? 0 :\n\t\ttypeof speed === \"number\" ? speed :\n\t\tspeed in $.fx.speeds ? $.fx.speeds[ speed ] :\n\t\t$.fx.speeds._default;\n\n\teffect.complete = callback || options.complete;\n\n\treturn effect;\n}\n\nfunction standardSpeed( speed ) {\n\t// valid standard speeds\n\tif ( !speed || typeof speed === \"number\" || $.fx.speeds[ speed ] ) {\n\t\treturn true;\n\t}\n\n\t// invalid strings - treat as \"normal\" speed\n\treturn typeof speed === \"string\" && !$.effects.effect[ speed ];\n}\n\n$.fn.extend({\n\teffect: function( /* effect, options, speed, callback */ ) {\n\t\tvar args = _normalizeArguments.apply( this, arguments ),\n\t\t\tmode = args.mode,\n\t\t\tqueue = args.queue,\n\t\t\teffectMethod = $.effects.effect[ args.effect ];\n\n\t\tif ( $.fx.off || !effectMethod ) {\n\t\t\t// delegate to the original method (e.g., .show()) if possible\n\t\t\tif ( mode ) {\n\t\t\t\treturn this[ mode ]( args.duration, args.complete );\n\t\t\t} else {\n\t\t\t\treturn this.each( function() {\n\t\t\t\t\tif ( args.complete ) {\n\t\t\t\t\t\targs.complete.call( this );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfunction run( next ) {\n\t\t\tvar elem = $( this ),\n\t\t\t\tcomplete = args.complete,\n\t\t\t\tmode = args.mode;\n\n\t\t\tfunction done() {\n\t\t\t\tif ( $.isFunction( complete ) ) {\n\t\t\t\t\tcomplete.call( elem[0] );\n\t\t\t\t}\n\t\t\t\tif ( $.isFunction( next ) ) {\n\t\t\t\t\tnext();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if the element is hiddden and mode is hide,\n\t\t\t// or element is visible and mode is show\n\t\t\tif ( elem.is( \":hidden\" ) ? mode === \"hide\" : mode === \"show\" ) {\n\t\t\t\tdone();\n\t\t\t} else {\n\t\t\t\teffectMethod.call( elem[0], args, done );\n\t\t\t}\n\t\t}\n\n\t\treturn queue === false ? this.each( run ) : this.queue( queue || \"fx\", run );\n\t},\n\n\t_show: $.fn.show,\n\tshow: function( speed ) {\n\t\tif ( standardSpeed( speed ) ) {\n\t\t\treturn this._show.apply( this, arguments );\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply( this, arguments );\n\t\t\targs.mode = \"show\";\n\t\t\treturn this.effect.call( this, args );\n\t\t}\n\t},\n\n\t_hide: $.fn.hide,\n\thide: function( speed ) {\n\t\tif ( standardSpeed( speed ) ) {\n\t\t\treturn this._hide.apply( this, arguments );\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply( this, arguments );\n\t\t\targs.mode = \"hide\";\n\t\t\treturn this.effect.call( this, args );\n\t\t}\n\t},\n\n\t// jQuery core overloads toggle and creates _toggle\n\t__toggle: $.fn.toggle,\n\ttoggle: function( speed ) {\n\t\tif ( standardSpeed( speed ) || typeof speed === \"boolean\" || $.isFunction( speed ) ) {\n\t\t\treturn this.__toggle.apply( this, arguments );\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply( this, arguments );\n\t\t\targs.mode = \"toggle\";\n\t\t\treturn this.effect.call( this, args );\n\t\t}\n\t},\n\n\t// helper functions\n\tcssUnit: function(key) {\n\t\tvar style = this.css( key ),\n\t\t\tval = [];\n\n\t\t$.each( [ \"em\", \"px\", \"%\", \"pt\" ], function( i, unit ) {\n\t\t\tif ( style.indexOf( unit ) > 0 ) {\n\t\t\t\tval = [ parseFloat( style ), unit ];\n\t\t\t}\n\t\t});\n\t\treturn val;\n\t}\n});\n\n})();\n\n/******************************************************************************/\n/*********************************** EASING ***********************************/\n/******************************************************************************/\n\n(function() {\n\n// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)\n\nvar baseEasings = {};\n\n$.each( [ \"Quad\", \"Cubic\", \"Quart\", \"Quint\", \"Expo\" ], function( i, name ) {\n\tbaseEasings[ name ] = function( p ) {\n\t\treturn Math.pow( p, i + 2 );\n\t};\n});\n\n$.extend( baseEasings, {\n\tSine: function ( p ) {\n\t\treturn 1 - Math.cos( p * Math.PI / 2 );\n\t},\n\tCirc: function ( p ) {\n\t\treturn 1 - Math.sqrt( 1 - p * p );\n\t},\n\tElastic: function( p ) {\n\t\treturn p === 0 || p === 1 ? p :\n\t\t\t-Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );\n\t},\n\tBack: function( p ) {\n\t\treturn p * p * ( 3 * p - 2 );\n\t},\n\tBounce: function ( p ) {\n\t\tvar pow2,\n\t\t\tbounce = 4;\n\n\t\twhile ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}\n\t\treturn 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );\n\t}\n});\n\n$.each( baseEasings, function( name, easeIn ) {\n\t$.easing[ \"easeIn\" + name ] = easeIn;\n\t$.easing[ \"easeOut\" + name ] = function( p ) {\n\t\treturn 1 - easeIn( 1 - p );\n\t};\n\t$.easing[ \"easeInOut\" + name ] = function( p ) {\n\t\treturn p < 0.5 ?\n\t\t\teaseIn( p * 2 ) / 2 :\n\t\t\t1 - easeIn( p * -2 + 2 ) / 2;\n\t};\n});\n\n})();\n\n})(jQuery));\n\n(function( $, undefined ) {\n\nvar uid = 0,\n\thideProps = {},\n\tshowProps = {};\n\nhideProps.height = hideProps.paddingTop = hideProps.paddingBottom =\n\thideProps.borderTopWidth = hideProps.borderBottomWidth = \"hide\";\nshowProps.height = showProps.paddingTop = showProps.paddingBottom =\n\tshowProps.borderTopWidth = showProps.borderBottomWidth = \"show\";\n\n$.widget( \"ui.accordion\", {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\tactive: 0,\n\t\tanimate: {},\n\t\tcollapsible: false,\n\t\tevent: \"click\",\n\t\theader: \"> li > :first-child,> :not(li):even\",\n\t\theightStyle: \"auto\",\n\t\ticons: {\n\t\t\tactiveHeader: \"ui-icon-triangle-1-s\",\n\t\t\theader: \"ui-icon-triangle-1-e\"\n\t\t},\n\n\t\t// callbacks\n\t\tactivate: null,\n\t\tbeforeActivate: null\n\t},\n\n\t_create: function() {\n\t\tvar options = this.options;\n\t\tthis.prevShow = this.prevHide = $();\n\t\tthis.element.addClass( \"ui-accordion ui-widget ui-helper-reset\" )\n\t\t\t// ARIA\n\t\t\t.attr( \"role\", \"tablist\" );\n\n\t\t// don't allow collapsible: false and active: false / null\n\t\tif ( !options.collapsible && (options.active === false || options.active == null) ) {\n\t\t\toptions.active = 0;\n\t\t}\n\n\t\tthis._processPanels();\n\t\t// handle negative values\n\t\tif ( options.active < 0 ) {\n\t\t\toptions.active += this.headers.length;\n\t\t}\n\t\tthis._refresh();\n\t},\n\n\t_getCreateEventData: function() {\n\t\treturn {\n\t\t\theader: this.active,\n\t\t\tpanel: !this.active.length ? $() : this.active.next(),\n\t\t\tcontent: !this.active.length ? $() : this.active.next()\n\t\t};\n\t},\n\n\t_createIcons: function() {\n\t\tvar icons = this.options.icons;\n\t\tif ( icons ) {\n\t\t\t$( \"<span>\" )\n\t\t\t\t.addClass( \"ui-accordion-header-icon ui-icon \" + icons.header )\n\t\t\t\t.prependTo( this.headers );\n\t\t\tthis.active.children( \".ui-accordion-header-icon\" )\n\t\t\t\t.removeClass( icons.header )\n\t\t\t\t.addClass( icons.activeHeader );\n\t\t\tthis.headers.addClass( \"ui-accordion-icons\" );\n\t\t}\n\t},\n\n\t_destroyIcons: function() {\n\t\tthis.headers\n\t\t\t.removeClass( \"ui-accordion-icons\" )\n\t\t\t.children( \".ui-accordion-header-icon\" )\n\t\t\t\t.remove();\n\t},\n\n\t_destroy: function() {\n\t\tvar contents;\n\n\t\t// clean up main element\n\t\tthis.element\n\t\t\t.removeClass( \"ui-accordion ui-widget ui-helper-reset\" )\n\t\t\t.removeAttr( \"role\" );\n\n\t\t// clean up headers\n\t\tthis.headers\n\t\t\t.removeClass( \"ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-selected\" )\n\t\t\t.removeAttr( \"aria-controls\" )\n\t\t\t.removeAttr( \"tabIndex\" )\n\t\t\t.each(function() {\n\t\t\t\tif ( /^ui-accordion/.test( this.id ) ) {\n\t\t\t\t\tthis.removeAttribute( \"id\" );\n\t\t\t\t}\n\t\t\t});\n\t\tthis._destroyIcons();\n\n\t\t// clean up content panels\n\t\tcontents = this.headers.next()\n\t\t\t.css( \"display\", \"\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-expanded\" )\n\t\t\t.removeAttr( \"aria-hidden\" )\n\t\t\t.removeAttr( \"aria-labelledby\" )\n\t\t\t.removeClass( \"ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled\" )\n\t\t\t.each(function() {\n\t\t\t\tif ( /^ui-accordion/.test( this.id ) ) {\n\t\t\t\t\tthis.removeAttribute( \"id\" );\n\t\t\t\t}\n\t\t\t});\n\t\tif ( this.options.heightStyle !== \"content\" ) {\n\t\t\tcontents.css( \"height\", \"\" );\n\t\t}\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"active\" ) {\n\t\t\t// _activate() will handle invalid values and update this.options\n\t\t\tthis._activate( value );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key === \"event\" ) {\n\t\t\tif ( this.options.event ) {\n\t\t\t\tthis._off( this.headers, this.options.event );\n\t\t\t}\n\t\t\tthis._setupEvents( value );\n\t\t}\n\n\t\tthis._super( key, value );\n\n\t\t// setting collapsible: false while collapsed; open first panel\n\t\tif ( key === \"collapsible\" && !value && this.options.active === false ) {\n\t\t\tthis._activate( 0 );\n\t\t}\n\n\t\tif ( key === \"icons\" ) {\n\t\t\tthis._destroyIcons();\n\t\t\tif ( value ) {\n\t\t\t\tthis._createIcons();\n\t\t\t}\n\t\t}\n\n\t\t// #5332 - opacity doesn't cascade to positioned elements in IE\n\t\t// so we need to add the disabled class to the headers and panels\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.headers.add( this.headers.next() )\n\t\t\t\t.toggleClass( \"ui-state-disabled\", !!value );\n\t\t}\n\t},\n\n\t_keydown: function( event ) {\n\t\t/*jshint maxcomplexity:15*/\n\t\tif ( event.altKey || event.ctrlKey ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar keyCode = $.ui.keyCode,\n\t\t\tlength = this.headers.length,\n\t\t\tcurrentIndex = this.headers.index( event.target ),\n\t\t\ttoFocus = false;\n\n\t\tswitch ( event.keyCode ) {\n\t\t\tcase keyCode.RIGHT:\n\t\t\tcase keyCode.DOWN:\n\t\t\t\ttoFocus = this.headers[ ( currentIndex + 1 ) % length ];\n\t\t\t\tbreak;\n\t\t\tcase keyCode.LEFT:\n\t\t\tcase keyCode.UP:\n\t\t\t\ttoFocus = this.headers[ ( currentIndex - 1 + length ) % length ];\n\t\t\t\tbreak;\n\t\t\tcase keyCode.SPACE:\n\t\t\tcase keyCode.ENTER:\n\t\t\t\tthis._eventHandler( event );\n\t\t\t\tbreak;\n\t\t\tcase keyCode.HOME:\n\t\t\t\ttoFocus = this.headers[ 0 ];\n\t\t\t\tbreak;\n\t\t\tcase keyCode.END:\n\t\t\t\ttoFocus = this.headers[ length - 1 ];\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif ( toFocus ) {\n\t\t\t$( event.target ).attr( \"tabIndex\", -1 );\n\t\t\t$( toFocus ).attr( \"tabIndex\", 0 );\n\t\t\ttoFocus.focus();\n\t\t\tevent.preventDefault();\n\t\t}\n\t},\n\n\t_panelKeyDown : function( event ) {\n\t\tif ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {\n\t\t\t$( event.currentTarget ).prev().focus();\n\t\t}\n\t},\n\n\trefresh: function() {\n\t\tvar options = this.options;\n\t\tthis._processPanels();\n\n\t\t// was collapsed or no panel\n\t\tif ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {\n\t\t\toptions.active = false;\n\t\t\tthis.active = $();\n\t\t// active false only when collapsible is true\n\t\t} if ( options.active === false ) {\n\t\t\tthis._activate( 0 );\n\t\t// was active, but active panel is gone\n\t\t} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {\n\t\t\t// all remaining panel are disabled\n\t\t\tif ( this.headers.length === this.headers.find(\".ui-state-disabled\").length ) {\n\t\t\t\toptions.active = false;\n\t\t\t\tthis.active = $();\n\t\t\t// activate previous panel\n\t\t\t} else {\n\t\t\t\tthis._activate( Math.max( 0, options.active - 1 ) );\n\t\t\t}\n\t\t// was active, active panel still exists\n\t\t} else {\n\t\t\t// make sure active index is correct\n\t\t\toptions.active = this.headers.index( this.active );\n\t\t}\n\n\t\tthis._destroyIcons();\n\n\t\tthis._refresh();\n\t},\n\n\t_processPanels: function() {\n\t\tthis.headers = this.element.find( this.options.header )\n\t\t\t.addClass( \"ui-accordion-header ui-helper-reset ui-state-default ui-corner-all\" );\n\n\t\tthis.headers.next()\n\t\t\t.addClass( \"ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom\" )\n\t\t\t.filter(\":not(.ui-accordion-content-active)\")\n\t\t\t.hide();\n\t},\n\n\t_refresh: function() {\n\t\tvar maxHeight,\n\t\t\toptions = this.options,\n\t\t\theightStyle = options.heightStyle,\n\t\t\tparent = this.element.parent(),\n\t\t\taccordionId = this.accordionId = \"ui-accordion-\" +\n\t\t\t\t(this.element.attr( \"id\" ) || ++uid);\n\n\t\tthis.active = this._findActive( options.active )\n\t\t\t.addClass( \"ui-accordion-header-active ui-state-active ui-corner-top\" )\n\t\t\t.removeClass( \"ui-corner-all\" );\n\t\tthis.active.next()\n\t\t\t.addClass( \"ui-accordion-content-active\" )\n\t\t\t.show();\n\n\t\tthis.headers\n\t\t\t.attr( \"role\", \"tab\" )\n\t\t\t.each(function( i ) {\n\t\t\t\tvar header = $( this ),\n\t\t\t\t\theaderId = header.attr( \"id\" ),\n\t\t\t\t\tpanel = header.next(),\n\t\t\t\t\tpanelId = panel.attr( \"id\" );\n\t\t\t\tif ( !headerId ) {\n\t\t\t\t\theaderId = accordionId + \"-header-\" + i;\n\t\t\t\t\theader.attr( \"id\", headerId );\n\t\t\t\t}\n\t\t\t\tif ( !panelId ) {\n\t\t\t\t\tpanelId = accordionId + \"-panel-\" + i;\n\t\t\t\t\tpanel.attr( \"id\", panelId );\n\t\t\t\t}\n\t\t\t\theader.attr( \"aria-controls\", panelId );\n\t\t\t\tpanel.attr( \"aria-labelledby\", headerId );\n\t\t\t})\n\t\t\t.next()\n\t\t\t\t.attr( \"role\", \"tabpanel\" );\n\n\t\tthis.headers\n\t\t\t.not( this.active )\n\t\t\t.attr({\n\t\t\t\t\"aria-selected\": \"false\",\n\t\t\t\ttabIndex: -1\n\t\t\t})\n\t\t\t.next()\n\t\t\t\t.attr({\n\t\t\t\t\t\"aria-expanded\": \"false\",\n\t\t\t\t\t\"aria-hidden\": \"true\"\n\t\t\t\t})\n\t\t\t\t.hide();\n\n\t\t// make sure at least one header is in the tab order\n\t\tif ( !this.active.length ) {\n\t\t\tthis.headers.eq( 0 ).attr( \"tabIndex\", 0 );\n\t\t} else {\n\t\t\tthis.active.attr({\n\t\t\t\t\"aria-selected\": \"true\",\n\t\t\t\ttabIndex: 0\n\t\t\t})\n\t\t\t.next()\n\t\t\t\t.attr({\n\t\t\t\t\t\"aria-expanded\": \"true\",\n\t\t\t\t\t\"aria-hidden\": \"false\"\n\t\t\t\t});\n\t\t}\n\n\t\tthis._createIcons();\n\n\t\tthis._setupEvents( options.event );\n\n\t\tif ( heightStyle === \"fill\" ) {\n\t\t\tmaxHeight = parent.height();\n\t\t\tthis.element.siblings( \":visible\" ).each(function() {\n\t\t\t\tvar elem = $( this ),\n\t\t\t\t\tposition = elem.css( \"position\" );\n\n\t\t\t\tif ( position === \"absolute\" || position === \"fixed\" ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tmaxHeight -= elem.outerHeight( true );\n\t\t\t});\n\n\t\t\tthis.headers.each(function() {\n\t\t\t\tmaxHeight -= $( this ).outerHeight( true );\n\t\t\t});\n\n\t\t\tthis.headers.next()\n\t\t\t\t.each(function() {\n\t\t\t\t\t$( this ).height( Math.max( 0, maxHeight -\n\t\t\t\t\t\t$( this ).innerHeight() + $( this ).height() ) );\n\t\t\t\t})\n\t\t\t\t.css( \"overflow\", \"auto\" );\n\t\t} else if ( heightStyle === \"auto\" ) {\n\t\t\tmaxHeight = 0;\n\t\t\tthis.headers.next()\n\t\t\t\t.each(function() {\n\t\t\t\t\tmaxHeight = Math.max( maxHeight, $( this ).css( \"height\", \"\" ).height() );\n\t\t\t\t})\n\t\t\t\t.height( maxHeight );\n\t\t}\n\t},\n\n\t_activate: function( index ) {\n\t\tvar active = this._findActive( index )[ 0 ];\n\n\t\t// trying to activate the already active panel\n\t\tif ( active === this.active[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// trying to collapse, simulate a click on the currently active header\n\t\tactive = active || this.active[ 0 ];\n\n\t\tthis._eventHandler({\n\t\t\ttarget: active,\n\t\t\tcurrentTarget: active,\n\t\t\tpreventDefault: $.noop\n\t\t});\n\t},\n\n\t_findActive: function( selector ) {\n\t\treturn typeof selector === \"number\" ? this.headers.eq( selector ) : $();\n\t},\n\n\t_setupEvents: function( event ) {\n\t\tvar events = {\n\t\t\tkeydown: \"_keydown\"\n\t\t};\n\t\tif ( event ) {\n\t\t\t$.each( event.split(\" \"), function( index, eventName ) {\n\t\t\t\tevents[ eventName ] = \"_eventHandler\";\n\t\t\t});\n\t\t}\n\n\t\tthis._off( this.headers.add( this.headers.next() ) );\n\t\tthis._on( this.headers, events );\n\t\tthis._on( this.headers.next(), { keydown: \"_panelKeyDown\" });\n\t\tthis._hoverable( this.headers );\n\t\tthis._focusable( this.headers );\n\t},\n\n\t_eventHandler: function( event ) {\n\t\tvar options = this.options,\n\t\t\tactive = this.active,\n\t\t\tclicked = $( event.currentTarget ),\n\t\t\tclickedIsActive = clicked[ 0 ] === active[ 0 ],\n\t\t\tcollapsing = clickedIsActive && options.collapsible,\n\t\t\ttoShow = collapsing ? $() : clicked.next(),\n\t\t\ttoHide = active.next(),\n\t\t\teventData = {\n\t\t\t\toldHeader: active,\n\t\t\t\toldPanel: toHide,\n\t\t\t\tnewHeader: collapsing ? $() : clicked,\n\t\t\t\tnewPanel: toShow\n\t\t\t};\n\n\t\tevent.preventDefault();\n\n\t\tif (\n\t\t\t\t// click on active header, but not collapsible\n\t\t\t\t( clickedIsActive && !options.collapsible ) ||\n\t\t\t\t// allow canceling activation\n\t\t\t\t( this._trigger( \"beforeActivate\", event, eventData ) === false ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\toptions.active = collapsing ? false : this.headers.index( clicked );\n\n\t\t// when the call to ._toggle() comes after the class changes\n\t\t// it causes a very odd bug in IE 8 (see #6720)\n\t\tthis.active = clickedIsActive ? $() : clicked;\n\t\tthis._toggle( eventData );\n\n\t\t// switch classes\n\t\t// corner classes on the previously active header stay after the animation\n\t\tactive.removeClass( \"ui-accordion-header-active ui-state-active\" );\n\t\tif ( options.icons ) {\n\t\t\tactive.children( \".ui-accordion-header-icon\" )\n\t\t\t\t.removeClass( options.icons.activeHeader )\n\t\t\t\t.addClass( options.icons.header );\n\t\t}\n\n\t\tif ( !clickedIsActive ) {\n\t\t\tclicked\n\t\t\t\t.removeClass( \"ui-corner-all\" )\n\t\t\t\t.addClass( \"ui-accordion-header-active ui-state-active ui-corner-top\" );\n\t\t\tif ( options.icons ) {\n\t\t\t\tclicked.children( \".ui-accordion-header-icon\" )\n\t\t\t\t\t.removeClass( options.icons.header )\n\t\t\t\t\t.addClass( options.icons.activeHeader );\n\t\t\t}\n\n\t\t\tclicked\n\t\t\t\t.next()\n\t\t\t\t.addClass( \"ui-accordion-content-active\" );\n\t\t}\n\t},\n\n\t_toggle: function( data ) {\n\t\tvar toShow = data.newPanel,\n\t\t\ttoHide = this.prevShow.length ? this.prevShow : data.oldPanel;\n\n\t\t// handle activating a panel during the animation for another activation\n\t\tthis.prevShow.add( this.prevHide ).stop( true, true );\n\t\tthis.prevShow = toShow;\n\t\tthis.prevHide = toHide;\n\n\t\tif ( this.options.animate ) {\n\t\t\tthis._animate( toShow, toHide, data );\n\t\t} else {\n\t\t\ttoHide.hide();\n\t\t\ttoShow.show();\n\t\t\tthis._toggleComplete( data );\n\t\t}\n\n\t\ttoHide.attr({\n\t\t\t\"aria-expanded\": \"false\",\n\t\t\t\"aria-hidden\": \"true\"\n\t\t});\n\t\ttoHide.prev().attr( \"aria-selected\", \"false\" );\n\t\t// if we're switching panels, remove the old header from the tab order\n\t\t// if we're opening from collapsed state, remove the previous header from the tab order\n\t\t// if we're collapsing, then keep the collapsing header in the tab order\n\t\tif ( toShow.length && toHide.length ) {\n\t\t\ttoHide.prev().attr( \"tabIndex\", -1 );\n\t\t} else if ( toShow.length ) {\n\t\t\tthis.headers.filter(function() {\n\t\t\t\treturn $( this ).attr( \"tabIndex\" ) === 0;\n\t\t\t})\n\t\t\t.attr( \"tabIndex\", -1 );\n\t\t}\n\n\t\ttoShow\n\t\t\t.attr({\n\t\t\t\t\"aria-expanded\": \"true\",\n\t\t\t\t\"aria-hidden\": \"false\"\n\t\t\t})\n\t\t\t.prev()\n\t\t\t\t.attr({\n\t\t\t\t\t\"aria-selected\": \"true\",\n\t\t\t\t\ttabIndex: 0\n\t\t\t\t});\n\t},\n\n\t_animate: function( toShow, toHide, data ) {\n\t\tvar total, easing, duration,\n\t\t\tthat = this,\n\t\t\tadjust = 0,\n\t\t\tdown = toShow.length &&\n\t\t\t\t( !toHide.length || ( toShow.index() < toHide.index() ) ),\n\t\t\tanimate = this.options.animate || {},\n\t\t\toptions = down && animate.down || animate,\n\t\t\tcomplete = function() {\n\t\t\t\tthat._toggleComplete( data );\n\t\t\t};\n\n\t\tif ( typeof options === \"number\" ) {\n\t\t\tduration = options;\n\t\t}\n\t\tif ( typeof options === \"string\" ) {\n\t\t\teasing = options;\n\t\t}\n\t\t// fall back from options to animation in case of partial down settings\n\t\teasing = easing || options.easing || animate.easing;\n\t\tduration = duration || options.duration || animate.duration;\n\n\t\tif ( !toHide.length ) {\n\t\t\treturn toShow.animate( showProps, duration, easing, complete );\n\t\t}\n\t\tif ( !toShow.length ) {\n\t\t\treturn toHide.animate( hideProps, duration, easing, complete );\n\t\t}\n\n\t\ttotal = toShow.show().outerHeight();\n\t\ttoHide.animate( hideProps, {\n\t\t\tduration: duration,\n\t\t\teasing: easing,\n\t\t\tstep: function( now, fx ) {\n\t\t\t\tfx.now = Math.round( now );\n\t\t\t}\n\t\t});\n\t\ttoShow\n\t\t\t.hide()\n\t\t\t.animate( showProps, {\n\t\t\t\tduration: duration,\n\t\t\t\teasing: easing,\n\t\t\t\tcomplete: complete,\n\t\t\t\tstep: function( now, fx ) {\n\t\t\t\t\tfx.now = Math.round( now );\n\t\t\t\t\tif ( fx.prop !== \"height\" ) {\n\t\t\t\t\t\tadjust += fx.now;\n\t\t\t\t\t} else if ( that.options.heightStyle !== \"content\" ) {\n\t\t\t\t\t\tfx.now = Math.round( total - toHide.outerHeight() - adjust );\n\t\t\t\t\t\tadjust = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t},\n\n\t_toggleComplete: function( data ) {\n\t\tvar toHide = data.oldPanel;\n\n\t\ttoHide\n\t\t\t.removeClass( \"ui-accordion-content-active\" )\n\t\t\t.prev()\n\t\t\t\t.removeClass( \"ui-corner-top\" )\n\t\t\t\t.addClass( \"ui-corner-all\" );\n\n\t\t// Work around for rendering bug in IE (#5421)\n\t\tif ( toHide.length ) {\n\t\t\ttoHide.parent()[0].className = toHide.parent()[0].className;\n\t\t}\n\n\t\tthis._trigger( \"activate\", null, data );\n\t}\n});\n\n})( jQuery );\n\n(function( $, undefined ) {\n\n// used to prevent race conditions with remote data sources\nvar requestIndex = 0;\n\n$.widget( \"ui.autocomplete\", {\n\tversion: \"1.10.1\",\n\tdefaultElement: \"<input>\",\n\toptions: {\n\t\tappendTo: null,\n\t\tautoFocus: false,\n\t\tdelay: 300,\n\t\tminLength: 1,\n\t\tposition: {\n\t\t\tmy: \"left top\",\n\t\t\tat: \"left bottom\",\n\t\t\tcollision: \"none\"\n\t\t},\n\t\tsource: null,\n\n\t\t// callbacks\n\t\tchange: null,\n\t\tclose: null,\n\t\tfocus: null,\n\t\topen: null,\n\t\tresponse: null,\n\t\tsearch: null,\n\t\tselect: null\n\t},\n\n\tpending: 0,\n\n\t_create: function() {\n\t\t// Some browsers only repeat keydown events, not keypress events,\n\t\t// so we use the suppressKeyPress flag to determine if we've already\n\t\t// handled the keydown event. #7269\n\t\t// Unfortunately the code for & in keypress is the same as the up arrow,\n\t\t// so we use the suppressKeyPressRepeat flag to avoid handling keypress\n\t\t// events when we know the keydown event was used to modify the\n\t\t// search term. #7799\n\t\tvar suppressKeyPress, suppressKeyPressRepeat, suppressInput,\n\t\t\tnodeName = this.element[0].nodeName.toLowerCase(),\n\t\t\tisTextarea = nodeName === \"textarea\",\n\t\t\tisInput = nodeName === \"input\";\n\n\t\tthis.isMultiLine =\n\t\t\t// Textareas are always multi-line\n\t\t\tisTextarea ? true :\n\t\t\t// Inputs are always single-line, even if inside a contentEditable element\n\t\t\t// IE also treats inputs as contentEditable\n\t\t\tisInput ? false :\n\t\t\t// All other element types are determined by whether or not they're contentEditable\n\t\t\tthis.element.prop( \"isContentEditable\" );\n\n\t\tthis.valueMethod = this.element[ isTextarea || isInput ? \"val\" : \"text\" ];\n\t\tthis.isNewMenu = true;\n\n\t\tthis.element\n\t\t\t.addClass( \"ui-autocomplete-input\" )\n\t\t\t.attr( \"autocomplete\", \"off\" );\n\n\t\tthis._on( this.element, {\n\t\t\tkeydown: function( event ) {\n\t\t\t\t/*jshint maxcomplexity:15*/\n\t\t\t\tif ( this.element.prop( \"readOnly\" ) ) {\n\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\tsuppressInput = true;\n\t\t\t\t\tsuppressKeyPressRepeat = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tsuppressKeyPress = false;\n\t\t\t\tsuppressInput = false;\n\t\t\t\tsuppressKeyPressRepeat = false;\n\t\t\t\tvar keyCode = $.ui.keyCode;\n\t\t\t\tswitch( event.keyCode ) {\n\t\t\t\tcase keyCode.PAGE_UP:\n\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\tthis._move( \"previousPage\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.PAGE_DOWN:\n\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\tthis._move( \"nextPage\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.UP:\n\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\tthis._keyEvent( \"previous\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.DOWN:\n\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\tthis._keyEvent( \"next\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.ENTER:\n\t\t\t\tcase keyCode.NUMPAD_ENTER:\n\t\t\t\t\t// when menu is open and has focus\n\t\t\t\t\tif ( this.menu.active ) {\n\t\t\t\t\t\t// #6055 - Opera still allows the keypress to occur\n\t\t\t\t\t\t// which causes forms to submit\n\t\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tthis.menu.select( event );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.TAB:\n\t\t\t\t\tif ( this.menu.active ) {\n\t\t\t\t\t\tthis.menu.select( event );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.ESCAPE:\n\t\t\t\t\tif ( this.menu.element.is( \":visible\" ) ) {\n\t\t\t\t\t\tthis._value( this.term );\n\t\t\t\t\t\tthis.close( event );\n\t\t\t\t\t\t// Different browsers have different default behavior for escape\n\t\t\t\t\t\t// Single press can mean undo or clear\n\t\t\t\t\t\t// Double press in IE means clear the whole form\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tsuppressKeyPressRepeat = true;\n\t\t\t\t\t// search timeout should be triggered before the input value is changed\n\t\t\t\t\tthis._searchTimeout( event );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\tkeypress: function( event ) {\n\t\t\t\tif ( suppressKeyPress ) {\n\t\t\t\t\tsuppressKeyPress = false;\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif ( suppressKeyPressRepeat ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// replicate some key handlers to allow them to repeat in Firefox and Opera\n\t\t\t\tvar keyCode = $.ui.keyCode;\n\t\t\t\tswitch( event.keyCode ) {\n\t\t\t\tcase keyCode.PAGE_UP:\n\t\t\t\t\tthis._move( \"previousPage\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.PAGE_DOWN:\n\t\t\t\t\tthis._move( \"nextPage\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.UP:\n\t\t\t\t\tthis._keyEvent( \"previous\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.DOWN:\n\t\t\t\t\tthis._keyEvent( \"next\", event );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\tinput: function( event ) {\n\t\t\t\tif ( suppressInput ) {\n\t\t\t\t\tsuppressInput = false;\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._searchTimeout( event );\n\t\t\t},\n\t\t\tfocus: function() {\n\t\t\t\tthis.selectedItem = null;\n\t\t\t\tthis.previous = this._value();\n\t\t\t},\n\t\t\tblur: function( event ) {\n\t\t\t\tif ( this.cancelBlur ) {\n\t\t\t\t\tdelete this.cancelBlur;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tclearTimeout( this.searching );\n\t\t\t\tthis.close( event );\n\t\t\t\tthis._change( event );\n\t\t\t}\n\t\t});\n\n\t\tthis._initSource();\n\t\tthis.menu = $( \"<ul>\" )\n\t\t\t.addClass( \"ui-autocomplete ui-front\" )\n\t\t\t.appendTo( this._appendTo() )\n\t\t\t.menu({\n\t\t\t\t// custom key handling for now\n\t\t\t\tinput: $(),\n\t\t\t\t// disable ARIA support, the live region takes care of that\n\t\t\t\trole: null\n\t\t\t})\n\t\t\t.hide()\n\t\t\t.data( \"ui-menu\" );\n\n\t\tthis._on( this.menu.element, {\n\t\t\tmousedown: function( event ) {\n\t\t\t\t// prevent moving focus out of the text field\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\t// IE doesn't prevent moving focus even with event.preventDefault()\n\t\t\t\t// so we set a flag to know when we should ignore the blur event\n\t\t\t\tthis.cancelBlur = true;\n\t\t\t\tthis._delay(function() {\n\t\t\t\t\tdelete this.cancelBlur;\n\t\t\t\t});\n\n\t\t\t\t// clicking on the scrollbar causes focus to shift to the body\n\t\t\t\t// but we can't detect a mouseup or a click immediately afterward\n\t\t\t\t// so we have to track the next mousedown and close the menu if\n\t\t\t\t// the user clicks somewhere outside of the autocomplete\n\t\t\t\tvar menuElement = this.menu.element[ 0 ];\n\t\t\t\tif ( !$( event.target ).closest( \".ui-menu-item\" ).length ) {\n\t\t\t\t\tthis._delay(function() {\n\t\t\t\t\t\tvar that = this;\n\t\t\t\t\t\tthis.document.one( \"mousedown\", function( event ) {\n\t\t\t\t\t\t\tif ( event.target !== that.element[ 0 ] &&\n\t\t\t\t\t\t\t\t\tevent.target !== menuElement &&\n\t\t\t\t\t\t\t\t\t!$.contains( menuElement, event.target ) ) {\n\t\t\t\t\t\t\t\tthat.close();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\tmenufocus: function( event, ui ) {\n\t\t\t\t// #7024 - Prevent accidental activation of menu items in Firefox\n\t\t\t\tif ( this.isNewMenu ) {\n\t\t\t\t\tthis.isNewMenu = false;\n\t\t\t\t\tif ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {\n\t\t\t\t\t\tthis.menu.blur();\n\n\t\t\t\t\t\tthis.document.one( \"mousemove\", function() {\n\t\t\t\t\t\t\t$( event.target ).trigger( event.originalEvent );\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar item = ui.item.data( \"ui-autocomplete-item\" );\n\t\t\t\tif ( false !== this._trigger( \"focus\", event, { item: item } ) ) {\n\t\t\t\t\t// use value to match what will end up in the input, if it was a key event\n\t\t\t\t\tif ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {\n\t\t\t\t\t\tthis._value( item.value );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Normally the input is populated with the item's value as the\n\t\t\t\t\t// menu is navigated, causing screen readers to notice a change and\n\t\t\t\t\t// announce the item. Since the focus event was canceled, this doesn't\n\t\t\t\t\t// happen, so we update the live region so that screen readers can\n\t\t\t\t\t// still notice the change and announce it.\n\t\t\t\t\tthis.liveRegion.text( item.value );\n\t\t\t\t}\n\t\t\t},\n\t\t\tmenuselect: function( event, ui ) {\n\t\t\t\tvar item = ui.item.data( \"ui-autocomplete-item\" ),\n\t\t\t\t\tprevious = this.previous;\n\n\t\t\t\t// only trigger when focus was lost (click on menu)\n\t\t\t\tif ( this.element[0] !== this.document[0].activeElement ) {\n\t\t\t\t\tthis.element.focus();\n\t\t\t\t\tthis.previous = previous;\n\t\t\t\t\t// #6109 - IE triggers two focus events and the second\n\t\t\t\t\t// is asynchronous, so we need to reset the previous\n\t\t\t\t\t// term synchronously and asynchronously :-(\n\t\t\t\t\tthis._delay(function() {\n\t\t\t\t\t\tthis.previous = previous;\n\t\t\t\t\t\tthis.selectedItem = item;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif ( false !== this._trigger( \"select\", event, { item: item } ) ) {\n\t\t\t\t\tthis._value( item.value );\n\t\t\t\t}\n\t\t\t\t// reset the term after the select event\n\t\t\t\t// this allows custom select handling to work properly\n\t\t\t\tthis.term = this._value();\n\n\t\t\t\tthis.close( event );\n\t\t\t\tthis.selectedItem = item;\n\t\t\t}\n\t\t});\n\n\t\tthis.liveRegion = $( \"<span>\", {\n\t\t\t\trole: \"status\",\n\t\t\t\t\"aria-live\": \"polite\"\n\t\t\t})\n\t\t\t.addClass( \"ui-helper-hidden-accessible\" )\n\t\t\t.insertAfter( this.element );\n\n\t\t// turning off autocomplete prevents the browser from remembering the\n\t\t// value when navigating through history, so we re-enable autocomplete\n\t\t// if the page is unloaded before the widget is destroyed. #7790\n\t\tthis._on( this.window, {\n\t\t\tbeforeunload: function() {\n\t\t\t\tthis.element.removeAttr( \"autocomplete\" );\n\t\t\t}\n\t\t});\n\t},\n\n\t_destroy: function() {\n\t\tclearTimeout( this.searching );\n\t\tthis.element\n\t\t\t.removeClass( \"ui-autocomplete-input\" )\n\t\t\t.removeAttr( \"autocomplete\" );\n\t\tthis.menu.element.remove();\n\t\tthis.liveRegion.remove();\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tthis._super( key, value );\n\t\tif ( key === \"source\" ) {\n\t\t\tthis._initSource();\n\t\t}\n\t\tif ( key === \"appendTo\" ) {\n\t\t\tthis.menu.element.appendTo( this._appendTo() );\n\t\t}\n\t\tif ( key === \"disabled\" && value && this.xhr ) {\n\t\t\tthis.xhr.abort();\n\t\t}\n\t},\n\n\t_appendTo: function() {\n\t\tvar element = this.options.appendTo;\n\n\t\tif ( element ) {\n\t\t\telement = element.jquery || element.nodeType ?\n\t\t\t\t$( element ) :\n\t\t\t\tthis.document.find( element ).eq( 0 );\n\t\t}\n\n\t\tif ( !element ) {\n\t\t\telement = this.element.closest( \".ui-front\" );\n\t\t}\n\n\t\tif ( !element.length ) {\n\t\t\telement = this.document[0].body;\n\t\t}\n\n\t\treturn element;\n\t},\n\n\t_initSource: function() {\n\t\tvar array, url,\n\t\t\tthat = this;\n\t\tif ( $.isArray(this.options.source) ) {\n\t\t\tarray = this.options.source;\n\t\t\tthis.source = function( request, response ) {\n\t\t\t\tresponse( $.ui.autocomplete.filter( array, request.term ) );\n\t\t\t};\n\t\t} else if ( typeof this.options.source === \"string\" ) {\n\t\t\turl = this.options.source;\n\t\t\tthis.source = function( request, response ) {\n\t\t\t\tif ( that.xhr ) {\n\t\t\t\t\tthat.xhr.abort();\n\t\t\t\t}\n\t\t\t\tthat.xhr = $.ajax({\n\t\t\t\t\turl: url,\n\t\t\t\t\tdata: request,\n\t\t\t\t\tdataType: \"json\",\n\t\t\t\t\tsuccess: function( data ) {\n\t\t\t\t\t\tresponse( data );\n\t\t\t\t\t},\n\t\t\t\t\terror: function() {\n\t\t\t\t\t\tresponse( [] );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t};\n\t\t} else {\n\t\t\tthis.source = this.options.source;\n\t\t}\n\t},\n\n\t_searchTimeout: function( event ) {\n\t\tclearTimeout( this.searching );\n\t\tthis.searching = this._delay(function() {\n\t\t\t// only search if the value has changed\n\t\t\tif ( this.term !== this._value() ) {\n\t\t\t\tthis.selectedItem = null;\n\t\t\t\tthis.search( null, event );\n\t\t\t}\n\t\t}, this.options.delay );\n\t},\n\n\tsearch: function( value, event ) {\n\t\tvalue = value != null ? value : this._value();\n\n\t\t// always save the actual value, not the one passed as an argument\n\t\tthis.term = this._value();\n\n\t\tif ( value.length < this.options.minLength ) {\n\t\t\treturn this.close( event );\n\t\t}\n\n\t\tif ( this._trigger( \"search\", event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this._search( value );\n\t},\n\n\t_search: function( value ) {\n\t\tthis.pending++;\n\t\tthis.element.addClass( \"ui-autocomplete-loading\" );\n\t\tthis.cancelSearch = false;\n\n\t\tthis.source( { term: value }, this._response() );\n\t},\n\n\t_response: function() {\n\t\tvar that = this,\n\t\t\tindex = ++requestIndex;\n\n\t\treturn function( content ) {\n\t\t\tif ( index === requestIndex ) {\n\t\t\t\tthat.__response( content );\n\t\t\t}\n\n\t\t\tthat.pending--;\n\t\t\tif ( !that.pending ) {\n\t\t\t\tthat.element.removeClass( \"ui-autocomplete-loading\" );\n\t\t\t}\n\t\t};\n\t},\n\n\t__response: function( content ) {\n\t\tif ( content ) {\n\t\t\tcontent = this._normalize( content );\n\t\t}\n\t\tthis._trigger( \"response\", null, { content: content } );\n\t\tif ( !this.options.disabled && content && content.length && !this.cancelSearch ) {\n\t\t\tthis._suggest( content );\n\t\t\tthis._trigger( \"open\" );\n\t\t} else {\n\t\t\t// use ._close() instead of .close() so we don't cancel future searches\n\t\t\tthis._close();\n\t\t}\n\t},\n\n\tclose: function( event ) {\n\t\tthis.cancelSearch = true;\n\t\tthis._close( event );\n\t},\n\n\t_close: function( event ) {\n\t\tif ( this.menu.element.is( \":visible\" ) ) {\n\t\t\tthis.menu.element.hide();\n\t\t\tthis.menu.blur();\n\t\t\tthis.isNewMenu = true;\n\t\t\tthis._trigger( \"close\", event );\n\t\t}\n\t},\n\n\t_change: function( event ) {\n\t\tif ( this.previous !== this._value() ) {\n\t\t\tthis._trigger( \"change\", event, { item: this.selectedItem } );\n\t\t}\n\t},\n\n\t_normalize: function( items ) {\n\t\t// assume all items have the right format when the first item is complete\n\t\tif ( items.length && items[0].label && items[0].value ) {\n\t\t\treturn items;\n\t\t}\n\t\treturn $.map( items, function( item ) {\n\t\t\tif ( typeof item === \"string\" ) {\n\t\t\t\treturn {\n\t\t\t\t\tlabel: item,\n\t\t\t\t\tvalue: item\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn $.extend({\n\t\t\t\tlabel: item.label || item.value,\n\t\t\t\tvalue: item.value || item.label\n\t\t\t}, item );\n\t\t});\n\t},\n\n\t_suggest: function( items ) {\n\t\tvar ul = this.menu.element.empty();\n\t\tthis._renderMenu( ul, items );\n\t\tthis.menu.refresh();\n\n\t\t// size and position menu\n\t\tul.show();\n\t\tthis._resizeMenu();\n\t\tul.position( $.extend({\n\t\t\tof: this.element\n\t\t}, this.options.position ));\n\n\t\tif ( this.options.autoFocus ) {\n\t\t\tthis.menu.next();\n\t\t}\n\t},\n\n\t_resizeMenu: function() {\n\t\tvar ul = this.menu.element;\n\t\tul.outerWidth( Math.max(\n\t\t\t// Firefox wraps long text (possibly a rounding bug)\n\t\t\t// so we add 1px to avoid the wrapping (#7513)\n\t\t\tul.width( \"\" ).outerWidth() + 1,\n\t\t\tthis.element.outerWidth()\n\t\t) );\n\t},\n\n\t_renderMenu: function( ul, items ) {\n\t\tvar that = this;\n\t\t$.each( items, function( index, item ) {\n\t\t\tthat._renderItemData( ul, item );\n\t\t});\n\t},\n\n\t_renderItemData: function( ul, item ) {\n\t\treturn this._renderItem( ul, item ).data( \"ui-autocomplete-item\", item );\n\t},\n\n\t_renderItem: function( ul, item ) {\n\t\treturn $( \"<li>\" )\n\t\t\t.append( $( \"<a>\" ).text( item.label ) )\n\t\t\t.appendTo( ul );\n\t},\n\n\t_move: function( direction, event ) {\n\t\tif ( !this.menu.element.is( \":visible\" ) ) {\n\t\t\tthis.search( null, event );\n\t\t\treturn;\n\t\t}\n\t\tif ( this.menu.isFirstItem() && /^previous/.test( direction ) ||\n\t\t\t\tthis.menu.isLastItem() && /^next/.test( direction ) ) {\n\t\t\tthis._value( this.term );\n\t\t\tthis.menu.blur();\n\t\t\treturn;\n\t\t}\n\t\tthis.menu[ direction ]( event );\n\t},\n\n\twidget: function() {\n\t\treturn this.menu.element;\n\t},\n\n\t_value: function() {\n\t\treturn this.valueMethod.apply( this.element, arguments );\n\t},\n\n\t_keyEvent: function( keyEvent, event ) {\n\t\tif ( !this.isMultiLine || this.menu.element.is( \":visible\" ) ) {\n\t\t\tthis._move( keyEvent, event );\n\n\t\t\t// prevents moving cursor to beginning/end of the text field in some browsers\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n});\n\n$.extend( $.ui.autocomplete, {\n\tescapeRegex: function( value ) {\n\t\treturn value.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, \"\\\\$&\");\n\t},\n\tfilter: function(array, term) {\n\t\tvar matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), \"i\" );\n\t\treturn $.grep( array, function(value) {\n\t\t\treturn matcher.test( value.label || value.value || value );\n\t\t});\n\t}\n});\n\n\n// live region extension, adding a `messages` option\n// NOTE: This is an experimental API. We are still investigating\n// a full solution for string manipulation and internationalization.\n$.widget( \"ui.autocomplete\", $.ui.autocomplete, {\n\toptions: {\n\t\tmessages: {\n\t\t\tnoResults: \"No search results.\",\n\t\t\tresults: function( amount ) {\n\t\t\t\treturn amount + ( amount > 1 ? \" results are\" : \" result is\" ) +\n\t\t\t\t\t\" available, use up and down arrow keys to navigate.\";\n\t\t\t}\n\t\t}\n\t},\n\n\t__response: function( content ) {\n\t\tvar message;\n\t\tthis._superApply( arguments );\n\t\tif ( this.options.disabled || this.cancelSearch ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( content && content.length ) {\n\t\t\tmessage = this.options.messages.results( content.length );\n\t\t} else {\n\t\t\tmessage = this.options.messages.noResults;\n\t\t}\n\t\tthis.liveRegion.text( message );\n\t}\n});\n\n}( jQuery ));\n\n(function( $, undefined ) {\n\nvar lastActive, startXPos, startYPos, clickDragged,\n\tbaseClasses = \"ui-button ui-widget ui-state-default ui-corner-all\",\n\tstateClasses = \"ui-state-hover ui-state-active \",\n\ttypeClasses = \"ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only\",\n\tformResetHandler = function() {\n\t\tvar buttons = $( this ).find( \":ui-button\" );\n\t\tsetTimeout(function() {\n\t\t\tbuttons.button( \"refresh\" );\n\t\t}, 1 );\n\t},\n\tradioGroup = function( radio ) {\n\t\tvar name = radio.name,\n\t\t\tform = radio.form,\n\t\t\tradios = $( [] );\n\t\tif ( name ) {\n\t\t\tname = name.replace( /'/g, \"\\\\'\" );\n\t\t\tif ( form ) {\n\t\t\t\tradios = $( form ).find( \"[name='\" + name + \"']\" );\n\t\t\t} else {\n\t\t\t\tradios = $( \"[name='\" + name + \"']\", radio.ownerDocument )\n\t\t\t\t\t.filter(function() {\n\t\t\t\t\t\treturn !this.form;\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn radios;\n\t};\n\n$.widget( \"ui.button\", {\n\tversion: \"1.10.1\",\n\tdefaultElement: \"<button>\",\n\toptions: {\n\t\tdisabled: null,\n\t\ttext: true,\n\t\tlabel: null,\n\t\ticons: {\n\t\t\tprimary: null,\n\t\t\tsecondary: null\n\t\t}\n\t},\n\t_create: function() {\n\t\tthis.element.closest( \"form\" )\n\t\t\t.unbind( \"reset\" + this.eventNamespace )\n\t\t\t.bind( \"reset\" + this.eventNamespace, formResetHandler );\n\n\t\tif ( typeof this.options.disabled !== \"boolean\" ) {\n\t\t\tthis.options.disabled = !!this.element.prop( \"disabled\" );\n\t\t} else {\n\t\t\tthis.element.prop( \"disabled\", this.options.disabled );\n\t\t}\n\n\t\tthis._determineButtonType();\n\t\tthis.hasTitle = !!this.buttonElement.attr( \"title\" );\n\n\t\tvar that = this,\n\t\t\toptions = this.options,\n\t\t\ttoggleButton = this.type === \"checkbox\" || this.type === \"radio\",\n\t\t\tactiveClass = !toggleButton ? \"ui-state-active\" : \"\",\n\t\t\tfocusClass = \"ui-state-focus\";\n\n\t\tif ( options.label === null ) {\n\t\t\toptions.label = (this.type === \"input\" ? this.buttonElement.val() : this.buttonElement.html());\n\t\t}\n\n\t\tthis._hoverable( this.buttonElement );\n\n\t\tthis.buttonElement\n\t\t\t.addClass( baseClasses )\n\t\t\t.attr( \"role\", \"button\" )\n\t\t\t.bind( \"mouseenter\" + this.eventNamespace, function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif ( this === lastActive ) {\n\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t}\n\t\t\t})\n\t\t\t.bind( \"mouseleave\" + this.eventNamespace, function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).removeClass( activeClass );\n\t\t\t})\n\t\t\t.bind( \"click\" + this.eventNamespace, function( event ) {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t}\n\t\t\t});\n\n\t\tthis.element\n\t\t\t.bind( \"focus\" + this.eventNamespace, function() {\n\t\t\t\t// no need to check disabled, focus won't be triggered anyway\n\t\t\t\tthat.buttonElement.addClass( focusClass );\n\t\t\t})\n\t\t\t.bind( \"blur\" + this.eventNamespace, function() {\n\t\t\t\tthat.buttonElement.removeClass( focusClass );\n\t\t\t});\n\n\t\tif ( toggleButton ) {\n\t\t\tthis.element.bind( \"change\" + this.eventNamespace, function() {\n\t\t\t\tif ( clickDragged ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthat.refresh();\n\t\t\t});\n\t\t\t// if mouse moves between mousedown and mouseup (drag) set clickDragged flag\n\t\t\t// prevents issue where button state changes but checkbox/radio checked state\n\t\t\t// does not in Firefox (see ticket #6970)\n\t\t\tthis.buttonElement\n\t\t\t\t.bind( \"mousedown\" + this.eventNamespace, function( event ) {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tclickDragged = false;\n\t\t\t\t\tstartXPos = event.pageX;\n\t\t\t\t\tstartYPos = event.pageY;\n\t\t\t\t})\n\t\t\t\t.bind( \"mouseup\" + this.eventNamespace, function( event ) {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif ( startXPos !== event.pageX || startYPos !== event.pageY ) {\n\t\t\t\t\t\tclickDragged = true;\n\t\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tif ( this.type === \"checkbox\" ) {\n\t\t\tthis.buttonElement.bind( \"click\" + this.eventNamespace, function() {\n\t\t\t\tif ( options.disabled || clickDragged ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t} else if ( this.type === \"radio\" ) {\n\t\t\tthis.buttonElement.bind( \"click\" + this.eventNamespace, function() {\n\t\t\t\tif ( options.disabled || clickDragged ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\tthat.buttonElement.attr( \"aria-pressed\", \"true\" );\n\n\t\t\t\tvar radio = that.element[ 0 ];\n\t\t\t\tradioGroup( radio )\n\t\t\t\t\t.not( radio )\n\t\t\t\t\t.map(function() {\n\t\t\t\t\t\treturn $( this ).button( \"widget\" )[ 0 ];\n\t\t\t\t\t})\n\t\t\t\t\t.removeClass( \"ui-state-active\" )\n\t\t\t\t\t.attr( \"aria-pressed\", \"false\" );\n\t\t\t});\n\t\t} else {\n\t\t\tthis.buttonElement\n\t\t\t\t.bind( \"mousedown\" + this.eventNamespace, function() {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t\tlastActive = this;\n\t\t\t\t\tthat.document.one( \"mouseup\", function() {\n\t\t\t\t\t\tlastActive = null;\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.bind( \"mouseup\" + this.eventNamespace, function() {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t$( this ).removeClass( \"ui-state-active\" );\n\t\t\t\t})\n\t\t\t\t.bind( \"keydown\" + this.eventNamespace, function(event) {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {\n\t\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t// see #8559, we bind to blur here in case the button element loses\n\t\t\t\t// focus between keydown and keyup, it would be left in an \"active\" state\n\t\t\t\t.bind( \"keyup\" + this.eventNamespace + \" blur\" + this.eventNamespace, function() {\n\t\t\t\t\t$( this ).removeClass( \"ui-state-active\" );\n\t\t\t\t});\n\n\t\t\tif ( this.buttonElement.is(\"a\") ) {\n\t\t\t\tthis.buttonElement.keyup(function(event) {\n\t\t\t\t\tif ( event.keyCode === $.ui.keyCode.SPACE ) {\n\t\t\t\t\t\t// TODO pass through original event correctly (just as 2nd argument doesn't work)\n\t\t\t\t\t\t$( this ).click();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// TODO: pull out $.Widget's handling for the disabled option into\n\t\t// $.Widget.prototype._setOptionDisabled so it's easy to proxy and can\n\t\t// be overridden by individual plugins\n\t\tthis._setOption( \"disabled\", options.disabled );\n\t\tthis._resetButton();\n\t},\n\n\t_determineButtonType: function() {\n\t\tvar ancestor, labelSelector, checked;\n\n\t\tif ( this.element.is(\"[type=checkbox]\") ) {\n\t\t\tthis.type = \"checkbox\";\n\t\t} else if ( this.element.is(\"[type=radio]\") ) {\n\t\t\tthis.type = \"radio\";\n\t\t} else if ( this.element.is(\"input\") ) {\n\t\t\tthis.type = \"input\";\n\t\t} else {\n\t\t\tthis.type = \"button\";\n\t\t}\n\n\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t// we don't search against the document in case the element\n\t\t\t// is disconnected from the DOM\n\t\t\tancestor = this.element.parents().last();\n\t\t\tlabelSelector = \"label[for='\" + this.element.attr(\"id\") + \"']\";\n\t\t\tthis.buttonElement = ancestor.find( labelSelector );\n\t\t\tif ( !this.buttonElement.length ) {\n\t\t\t\tancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();\n\t\t\t\tthis.buttonElement = ancestor.filter( labelSelector );\n\t\t\t\tif ( !this.buttonElement.length ) {\n\t\t\t\t\tthis.buttonElement = ancestor.find( labelSelector );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.element.addClass( \"ui-helper-hidden-accessible\" );\n\n\t\t\tchecked = this.element.is( \":checked\" );\n\t\t\tif ( checked ) {\n\t\t\t\tthis.buttonElement.addClass( \"ui-state-active\" );\n\t\t\t}\n\t\t\tthis.buttonElement.prop( \"aria-pressed\", checked );\n\t\t} else {\n\t\t\tthis.buttonElement = this.element;\n\t\t}\n\t},\n\n\twidget: function() {\n\t\treturn this.buttonElement;\n\t},\n\n\t_destroy: function() {\n\t\tthis.element\n\t\t\t.removeClass( \"ui-helper-hidden-accessible\" );\n\t\tthis.buttonElement\n\t\t\t.removeClass( baseClasses + \" \" + stateClasses + \" \" + typeClasses )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-pressed\" )\n\t\t\t.html( this.buttonElement.find(\".ui-button-text\").html() );\n\n\t\tif ( !this.hasTitle ) {\n\t\t\tthis.buttonElement.removeAttr( \"title\" );\n\t\t}\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tthis._super( key, value );\n\t\tif ( key === \"disabled\" ) {\n\t\t\tif ( value ) {\n\t\t\t\tthis.element.prop( \"disabled\", true );\n\t\t\t} else {\n\t\t\t\tthis.element.prop( \"disabled\", false );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis._resetButton();\n\t},\n\n\trefresh: function() {\n\t\t//See #8237 & #8828\n\t\tvar isDisabled = this.element.is( \"input, button\" ) ? this.element.is( \":disabled\" ) : this.element.hasClass( \"ui-button-disabled\" );\n\n\t\tif ( isDisabled !== this.options.disabled ) {\n\t\t\tthis._setOption( \"disabled\", isDisabled );\n\t\t}\n\t\tif ( this.type === \"radio\" ) {\n\t\t\tradioGroup( this.element[0] ).each(function() {\n\t\t\t\tif ( $( this ).is( \":checked\" ) ) {\n\t\t\t\t\t$( this ).button( \"widget\" )\n\t\t\t\t\t\t.addClass( \"ui-state-active\" )\n\t\t\t\t\t\t.attr( \"aria-pressed\", \"true\" );\n\t\t\t\t} else {\n\t\t\t\t\t$( this ).button( \"widget\" )\n\t\t\t\t\t\t.removeClass( \"ui-state-active\" )\n\t\t\t\t\t\t.attr( \"aria-pressed\", \"false\" );\n\t\t\t\t}\n\t\t\t});\n\t\t} else if ( this.type === \"checkbox\" ) {\n\t\t\tif ( this.element.is( \":checked\" ) ) {\n\t\t\t\tthis.buttonElement\n\t\t\t\t\t.addClass( \"ui-state-active\" )\n\t\t\t\t\t.attr( \"aria-pressed\", \"true\" );\n\t\t\t} else {\n\t\t\t\tthis.buttonElement\n\t\t\t\t\t.removeClass( \"ui-state-active\" )\n\t\t\t\t\t.attr( \"aria-pressed\", \"false\" );\n\t\t\t}\n\t\t}\n\t},\n\n\t_resetButton: function() {\n\t\tif ( this.type === \"input\" ) {\n\t\t\tif ( this.options.label ) {\n\t\t\t\tthis.element.val( this.options.label );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tvar buttonElement = this.buttonElement.removeClass( typeClasses ),\n\t\t\tbuttonText = $( \"<span></span>\", this.document[0] )\n\t\t\t\t.addClass( \"ui-button-text\" )\n\t\t\t\t.html( this.options.label )\n\t\t\t\t.appendTo( buttonElement.empty() )\n\t\t\t\t.text(),\n\t\t\ticons = this.options.icons,\n\t\t\tmultipleIcons = icons.primary && icons.secondary,\n\t\t\tbuttonClasses = [];\n\n\t\tif ( icons.primary || icons.secondary ) {\n\t\t\tif ( this.options.text ) {\n\t\t\t\tbuttonClasses.push( \"ui-button-text-icon\" + ( multipleIcons ? \"s\" : ( icons.primary ? \"-primary\" : \"-secondary\" ) ) );\n\t\t\t}\n\n\t\t\tif ( icons.primary ) {\n\t\t\t\tbuttonElement.prepend( \"<span class='ui-button-icon-primary ui-icon \" + icons.primary + \"'></span>\" );\n\t\t\t}\n\n\t\t\tif ( icons.secondary ) {\n\t\t\t\tbuttonElement.append( \"<span class='ui-button-icon-secondary ui-icon \" + icons.secondary + \"'></span>\" );\n\t\t\t}\n\n\t\t\tif ( !this.options.text ) {\n\t\t\t\tbuttonClasses.push( multipleIcons ? \"ui-button-icons-only\" : \"ui-button-icon-only\" );\n\n\t\t\t\tif ( !this.hasTitle ) {\n\t\t\t\t\tbuttonElement.attr( \"title\", $.trim( buttonText ) );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tbuttonClasses.push( \"ui-button-text-only\" );\n\t\t}\n\t\tbuttonElement.addClass( buttonClasses.join( \" \" ) );\n\t}\n});\n\n$.widget( \"ui.buttonset\", {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\titems: \"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)\"\n\t},\n\n\t_create: function() {\n\t\tthis.element.addClass( \"ui-buttonset\" );\n\t},\n\n\t_init: function() {\n\t\tthis.refresh();\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.buttons.button( \"option\", key, value );\n\t\t}\n\n\t\tthis._super( key, value );\n\t},\n\n\trefresh: function() {\n\t\tvar rtl = this.element.css( \"direction\" ) === \"rtl\";\n\n\t\tthis.buttons = this.element.find( this.options.items )\n\t\t\t.filter( \":ui-button\" )\n\t\t\t\t.button( \"refresh\" )\n\t\t\t.end()\n\t\t\t.not( \":ui-button\" )\n\t\t\t\t.button()\n\t\t\t.end()\n\t\t\t.map(function() {\n\t\t\t\treturn $( this ).button( \"widget\" )[ 0 ];\n\t\t\t})\n\t\t\t\t.removeClass( \"ui-corner-all ui-corner-left ui-corner-right\" )\n\t\t\t\t.filter( \":first\" )\n\t\t\t\t\t.addClass( rtl ? \"ui-corner-right\" : \"ui-corner-left\" )\n\t\t\t\t.end()\n\t\t\t\t.filter( \":last\" )\n\t\t\t\t\t.addClass( rtl ? \"ui-corner-left\" : \"ui-corner-right\" )\n\t\t\t\t.end()\n\t\t\t.end();\n\t},\n\n\t_destroy: function() {\n\t\tthis.element.removeClass( \"ui-buttonset\" );\n\t\tthis.buttons\n\t\t\t.map(function() {\n\t\t\t\treturn $( this ).button( \"widget\" )[ 0 ];\n\t\t\t})\n\t\t\t\t.removeClass( \"ui-corner-left ui-corner-right\" )\n\t\t\t.end()\n\t\t\t.button( \"destroy\" );\n\t}\n});\n\n}( jQuery ) );\n\n(function( $, undefined ) {\n\n$.extend($.ui, { datepicker: { version: \"1.10.1\" } });\n\nvar PROP_NAME = \"datepicker\",\n\tdpuuid = new Date().getTime(),\n\tinstActive;\n\n/* Date picker manager.\n   Use the singleton instance of this class, $.datepicker, to interact with the date picker.\n   Settings for (groups of) date pickers are maintained in an instance object,\n   allowing multiple different settings on the same page. */\n\nfunction Datepicker() {\n\tthis._curInst = null; // The current instance in use\n\tthis._keyEvent = false; // If the last event was a key event\n\tthis._disabledInputs = []; // List of date picker inputs that have been disabled\n\tthis._datepickerShowing = false; // True if the popup picker is showing , false if not\n\tthis._inDialog = false; // True if showing within a \"dialog\", false if not\n\tthis._mainDivId = \"ui-datepicker-div\"; // The ID of the main datepicker division\n\tthis._inlineClass = \"ui-datepicker-inline\"; // The name of the inline marker class\n\tthis._appendClass = \"ui-datepicker-append\"; // The name of the append marker class\n\tthis._triggerClass = \"ui-datepicker-trigger\"; // The name of the trigger marker class\n\tthis._dialogClass = \"ui-datepicker-dialog\"; // The name of the dialog marker class\n\tthis._disableClass = \"ui-datepicker-disabled\"; // The name of the disabled covering marker class\n\tthis._unselectableClass = \"ui-datepicker-unselectable\"; // The name of the unselectable cell marker class\n\tthis._currentClass = \"ui-datepicker-current-day\"; // The name of the current day marker class\n\tthis._dayOverClass = \"ui-datepicker-days-cell-over\"; // The name of the day hover marker class\n\tthis.regional = []; // Available regional settings, indexed by language code\n\tthis.regional[\"\"] = { // Default regional settings\n\t\tcloseText: \"Done\", // Display text for close link\n\t\tprevText: \"Prev\", // Display text for previous month link\n\t\tnextText: \"Next\", // Display text for next month link\n\t\tcurrentText: \"Today\", // Display text for current month link\n\t\tmonthNames: [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\n\t\t\t\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"], // Names of months for drop-down and formatting\n\t\tmonthNamesShort: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"], // For formatting\n\t\tdayNames: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"], // For formatting\n\t\tdayNamesShort: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"], // For formatting\n\t\tdayNamesMin: [\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"], // Column headings for days starting at Sunday\n\t\tweekHeader: \"Wk\", // Column header for week of the year\n\t\tdateFormat: \"mm/dd/yy\", // See format options on parseDate\n\t\tfirstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...\n\t\tisRTL: false, // True if right-to-left language, false if left-to-right\n\t\tshowMonthAfterYear: false, // True if the year select precedes month, false for month then year\n\t\tyearSuffix: \"\" // Additional text to append to the year in the month headers\n\t};\n\tthis._defaults = { // Global defaults for all the date picker instances\n\t\tshowOn: \"focus\", // \"focus\" for popup on focus,\n\t\t\t// \"button\" for trigger button, or \"both\" for either\n\t\tshowAnim: \"fadeIn\", // Name of jQuery animation for popup\n\t\tshowOptions: {}, // Options for enhanced animations\n\t\tdefaultDate: null, // Used when field is blank: actual date,\n\t\t\t// +/-number for offset from today, null for today\n\t\tappendText: \"\", // Display text following the input box, e.g. showing the format\n\t\tbuttonText: \"...\", // Text for trigger button\n\t\tbuttonImage: \"\", // URL for trigger button image\n\t\tbuttonImageOnly: false, // True if the image appears alone, false if it appears on a button\n\t\thideIfNoPrevNext: false, // True to hide next/previous month links\n\t\t\t// if not applicable, false to just disable them\n\t\tnavigationAsDateFormat: false, // True if date formatting applied to prev/today/next links\n\t\tgotoCurrent: false, // True if today link goes back to current selection instead\n\t\tchangeMonth: false, // True if month can be selected directly, false if only prev/next\n\t\tchangeYear: false, // True if year can be selected directly, false if only prev/next\n\t\tyearRange: \"c-10:c+10\", // Range of years to display in drop-down,\n\t\t\t// either relative to today's year (-nn:+nn), relative to currently displayed year\n\t\t\t// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)\n\t\tshowOtherMonths: false, // True to show dates in other months, false to leave blank\n\t\tselectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable\n\t\tshowWeek: false, // True to show week of the year, false to not show it\n\t\tcalculateWeek: this.iso8601Week, // How to calculate the week of the year,\n\t\t\t// takes a Date and returns the number of the week for it\n\t\tshortYearCutoff: \"+10\", // Short year values < this are in the current century,\n\t\t\t// > this are in the previous century,\n\t\t\t// string value starting with \"+\" for current year + value\n\t\tminDate: null, // The earliest selectable date, or null for no limit\n\t\tmaxDate: null, // The latest selectable date, or null for no limit\n\t\tduration: \"fast\", // Duration of display/closure\n\t\tbeforeShowDay: null, // Function that takes a date and returns an array with\n\t\t\t// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or \"\",\n\t\t\t// [2] = cell title (optional), e.g. $.datepicker.noWeekends\n\t\tbeforeShow: null, // Function that takes an input field and\n\t\t\t// returns a set of custom settings for the date picker\n\t\tonSelect: null, // Define a callback function when a date is selected\n\t\tonChangeMonthYear: null, // Define a callback function when the month or year is changed\n\t\tonClose: null, // Define a callback function when the datepicker is closed\n\t\tnumberOfMonths: 1, // Number of months to show at a time\n\t\tshowCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)\n\t\tstepMonths: 1, // Number of months to step back/forward\n\t\tstepBigMonths: 12, // Number of months to step back/forward for the big links\n\t\taltField: \"\", // Selector for an alternate field to store selected dates into\n\t\taltFormat: \"\", // The date format to use for the alternate field\n\t\tconstrainInput: true, // The input is constrained by the current date format\n\t\tshowButtonPanel: false, // True to show button panel, false to not show it\n\t\tautoSize: false, // True to size the input for the date format, false to leave as is\n\t\tdisabled: false // The initial disabled state\n\t};\n\t$.extend(this._defaults, this.regional[\"\"]);\n\tthis.dpDiv = bindHover($(\"<div id='\" + this._mainDivId + \"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>\"));\n}\n\n$.extend(Datepicker.prototype, {\n\t/* Class name added to elements to indicate already configured with a date picker. */\n\tmarkerClassName: \"hasDatepicker\",\n\n\t//Keep track of the maximum number of rows displayed (see #7043)\n\tmaxRows: 4,\n\n\t// TODO rename to \"widget\" when switching to widget factory\n\t_widgetDatepicker: function() {\n\t\treturn this.dpDiv;\n\t},\n\n\t/* Override the default settings for all instances of the date picker.\n\t * @param  settings  object - the new settings to use as defaults (anonymous object)\n\t * @return the manager object\n\t */\n\tsetDefaults: function(settings) {\n\t\textendRemove(this._defaults, settings || {});\n\t\treturn this;\n\t},\n\n\t/* Attach the date picker to a jQuery selection.\n\t * @param  target\telement - the target input field or division or span\n\t * @param  settings  object - the new settings to use for this date picker instance (anonymous)\n\t */\n\t_attachDatepicker: function(target, settings) {\n\t\tvar nodeName, inline, inst;\n\t\tnodeName = target.nodeName.toLowerCase();\n\t\tinline = (nodeName === \"div\" || nodeName === \"span\");\n\t\tif (!target.id) {\n\t\t\tthis.uuid += 1;\n\t\t\ttarget.id = \"dp\" + this.uuid;\n\t\t}\n\t\tinst = this._newInst($(target), inline);\n\t\tinst.settings = $.extend({}, settings || {});\n\t\tif (nodeName === \"input\") {\n\t\t\tthis._connectDatepicker(target, inst);\n\t\t} else if (inline) {\n\t\t\tthis._inlineDatepicker(target, inst);\n\t\t}\n\t},\n\n\t/* Create a new instance object. */\n\t_newInst: function(target, inline) {\n\t\tvar id = target[0].id.replace(/([^A-Za-z0-9_\\-])/g, \"\\\\\\\\$1\"); // escape jQuery meta chars\n\t\treturn {id: id, input: target, // associated target\n\t\t\tselectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection\n\t\t\tdrawMonth: 0, drawYear: 0, // month being drawn\n\t\t\tinline: inline, // is datepicker inline or not\n\t\t\tdpDiv: (!inline ? this.dpDiv : // presentation div\n\t\t\tbindHover($(\"<div class='\" + this._inlineClass + \" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>\")))};\n\t},\n\n\t/* Attach the date picker to an input field. */\n\t_connectDatepicker: function(target, inst) {\n\t\tvar input = $(target);\n\t\tinst.append = $([]);\n\t\tinst.trigger = $([]);\n\t\tif (input.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\t\tthis._attachments(input, inst);\n\t\tinput.addClass(this.markerClassName).keydown(this._doKeyDown).\n\t\t\tkeypress(this._doKeyPress).keyup(this._doKeyUp);\n\t\tthis._autoSize(inst);\n\t\t$.data(target, PROP_NAME, inst);\n\t\t//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)\n\t\tif( inst.settings.disabled ) {\n\t\t\tthis._disableDatepicker( target );\n\t\t}\n\t},\n\n\t/* Make attachments based on settings. */\n\t_attachments: function(input, inst) {\n\t\tvar showOn, buttonText, buttonImage,\n\t\t\tappendText = this._get(inst, \"appendText\"),\n\t\t\tisRTL = this._get(inst, \"isRTL\");\n\n\t\tif (inst.append) {\n\t\t\tinst.append.remove();\n\t\t}\n\t\tif (appendText) {\n\t\t\tinst.append = $(\"<span class='\" + this._appendClass + \"'>\" + appendText + \"</span>\");\n\t\t\tinput[isRTL ? \"before\" : \"after\"](inst.append);\n\t\t}\n\n\t\tinput.unbind(\"focus\", this._showDatepicker);\n\n\t\tif (inst.trigger) {\n\t\t\tinst.trigger.remove();\n\t\t}\n\n\t\tshowOn = this._get(inst, \"showOn\");\n\t\tif (showOn === \"focus\" || showOn === \"both\") { // pop-up date picker when in the marked field\n\t\t\tinput.focus(this._showDatepicker);\n\t\t}\n\t\tif (showOn === \"button\" || showOn === \"both\") { // pop-up date picker when button clicked\n\t\t\tbuttonText = this._get(inst, \"buttonText\");\n\t\t\tbuttonImage = this._get(inst, \"buttonImage\");\n\t\t\tinst.trigger = $(this._get(inst, \"buttonImageOnly\") ?\n\t\t\t\t$(\"<img/>\").addClass(this._triggerClass).\n\t\t\t\t\tattr({ src: buttonImage, alt: buttonText, title: buttonText }) :\n\t\t\t\t$(\"<button type='button'></button>\").addClass(this._triggerClass).\n\t\t\t\t\thtml(!buttonImage ? buttonText : $(\"<img/>\").attr(\n\t\t\t\t\t{ src:buttonImage, alt:buttonText, title:buttonText })));\n\t\t\tinput[isRTL ? \"before\" : \"after\"](inst.trigger);\n\t\t\tinst.trigger.click(function() {\n\t\t\t\tif ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {\n\t\t\t\t\t$.datepicker._hideDatepicker();\n\t\t\t\t} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {\n\t\t\t\t\t$.datepicker._hideDatepicker();\n\t\t\t\t\t$.datepicker._showDatepicker(input[0]);\n\t\t\t\t} else {\n\t\t\t\t\t$.datepicker._showDatepicker(input[0]);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\t\t}\n\t},\n\n\t/* Apply the maximum length for the date format. */\n\t_autoSize: function(inst) {\n\t\tif (this._get(inst, \"autoSize\") && !inst.inline) {\n\t\t\tvar findMax, max, maxI, i,\n\t\t\t\tdate = new Date(2009, 12 - 1, 20), // Ensure double digits\n\t\t\t\tdateFormat = this._get(inst, \"dateFormat\");\n\n\t\t\tif (dateFormat.match(/[DM]/)) {\n\t\t\t\tfindMax = function(names) {\n\t\t\t\t\tmax = 0;\n\t\t\t\t\tmaxI = 0;\n\t\t\t\t\tfor (i = 0; i < names.length; i++) {\n\t\t\t\t\t\tif (names[i].length > max) {\n\t\t\t\t\t\t\tmax = names[i].length;\n\t\t\t\t\t\t\tmaxI = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn maxI;\n\t\t\t\t};\n\t\t\t\tdate.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?\n\t\t\t\t\t\"monthNames\" : \"monthNamesShort\"))));\n\t\t\t\tdate.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?\n\t\t\t\t\t\"dayNames\" : \"dayNamesShort\"))) + 20 - date.getDay());\n\t\t\t}\n\t\t\tinst.input.attr(\"size\", this._formatDate(inst, date).length);\n\t\t}\n\t},\n\n\t/* Attach an inline date picker to a div. */\n\t_inlineDatepicker: function(target, inst) {\n\t\tvar divSpan = $(target);\n\t\tif (divSpan.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\t\tdivSpan.addClass(this.markerClassName).append(inst.dpDiv);\n\t\t$.data(target, PROP_NAME, inst);\n\t\tthis._setDate(inst, this._getDefaultDate(inst), true);\n\t\tthis._updateDatepicker(inst);\n\t\tthis._updateAlternate(inst);\n\t\t//If disabled option is true, disable the datepicker before showing it (see ticket #5665)\n\t\tif( inst.settings.disabled ) {\n\t\t\tthis._disableDatepicker( target );\n\t\t}\n\t\t// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements\n\t\t// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height\n\t\tinst.dpDiv.css( \"display\", \"block\" );\n\t},\n\n\t/* Pop-up the date picker in a \"dialog\" box.\n\t * @param  input element - ignored\n\t * @param  date\tstring or Date - the initial date to display\n\t * @param  onSelect  function - the function to call when a date is selected\n\t * @param  settings  object - update the dialog date picker instance's settings (anonymous object)\n\t * @param  pos int[2] - coordinates for the dialog's position within the screen or\n\t *\t\t\t\t\tevent - with x/y coordinates or\n\t *\t\t\t\t\tleave empty for default (screen centre)\n\t * @return the manager object\n\t */\n\t_dialogDatepicker: function(input, date, onSelect, settings, pos) {\n\t\tvar id, browserWidth, browserHeight, scrollX, scrollY,\n\t\t\tinst = this._dialogInst; // internal instance\n\n\t\tif (!inst) {\n\t\t\tthis.uuid += 1;\n\t\t\tid = \"dp\" + this.uuid;\n\t\t\tthis._dialogInput = $(\"<input type='text' id='\" + id +\n\t\t\t\t\"' style='position: absolute; top: -100px; width: 0px;'/>\");\n\t\t\tthis._dialogInput.keydown(this._doKeyDown);\n\t\t\t$(\"body\").append(this._dialogInput);\n\t\t\tinst = this._dialogInst = this._newInst(this._dialogInput, false);\n\t\t\tinst.settings = {};\n\t\t\t$.data(this._dialogInput[0], PROP_NAME, inst);\n\t\t}\n\t\textendRemove(inst.settings, settings || {});\n\t\tdate = (date && date.constructor === Date ? this._formatDate(inst, date) : date);\n\t\tthis._dialogInput.val(date);\n\n\t\tthis._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);\n\t\tif (!this._pos) {\n\t\t\tbrowserWidth = document.documentElement.clientWidth;\n\t\t\tbrowserHeight = document.documentElement.clientHeight;\n\t\t\tscrollX = document.documentElement.scrollLeft || document.body.scrollLeft;\n\t\t\tscrollY = document.documentElement.scrollTop || document.body.scrollTop;\n\t\t\tthis._pos = // should use actual width/height below\n\t\t\t\t[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];\n\t\t}\n\n\t\t// move input on screen for focus, but hidden behind dialog\n\t\tthis._dialogInput.css(\"left\", (this._pos[0] + 20) + \"px\").css(\"top\", this._pos[1] + \"px\");\n\t\tinst.settings.onSelect = onSelect;\n\t\tthis._inDialog = true;\n\t\tthis.dpDiv.addClass(this._dialogClass);\n\t\tthis._showDatepicker(this._dialogInput[0]);\n\t\tif ($.blockUI) {\n\t\t\t$.blockUI(this.dpDiv);\n\t\t}\n\t\t$.data(this._dialogInput[0], PROP_NAME, inst);\n\t\treturn this;\n\t},\n\n\t/* Detach a datepicker from its control.\n\t * @param  target\telement - the target input field or division or span\n\t */\n\t_destroyDatepicker: function(target) {\n\t\tvar nodeName,\n\t\t\t$target = $(target),\n\t\t\tinst = $.data(target, PROP_NAME);\n\n\t\tif (!$target.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\n\t\tnodeName = target.nodeName.toLowerCase();\n\t\t$.removeData(target, PROP_NAME);\n\t\tif (nodeName === \"input\") {\n\t\t\tinst.append.remove();\n\t\t\tinst.trigger.remove();\n\t\t\t$target.removeClass(this.markerClassName).\n\t\t\t\tunbind(\"focus\", this._showDatepicker).\n\t\t\t\tunbind(\"keydown\", this._doKeyDown).\n\t\t\t\tunbind(\"keypress\", this._doKeyPress).\n\t\t\t\tunbind(\"keyup\", this._doKeyUp);\n\t\t} else if (nodeName === \"div\" || nodeName === \"span\") {\n\t\t\t$target.removeClass(this.markerClassName).empty();\n\t\t}\n\t},\n\n\t/* Enable the date picker to a jQuery selection.\n\t * @param  target\telement - the target input field or division or span\n\t */\n\t_enableDatepicker: function(target) {\n\t\tvar nodeName, inline,\n\t\t\t$target = $(target),\n\t\t\tinst = $.data(target, PROP_NAME);\n\n\t\tif (!$target.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\n\t\tnodeName = target.nodeName.toLowerCase();\n\t\tif (nodeName === \"input\") {\n\t\t\ttarget.disabled = false;\n\t\t\tinst.trigger.filter(\"button\").\n\t\t\t\teach(function() { this.disabled = false; }).end().\n\t\t\t\tfilter(\"img\").css({opacity: \"1.0\", cursor: \"\"});\n\t\t} else if (nodeName === \"div\" || nodeName === \"span\") {\n\t\t\tinline = $target.children(\".\" + this._inlineClass);\n\t\t\tinline.children().removeClass(\"ui-state-disabled\");\n\t\t\tinline.find(\"select.ui-datepicker-month, select.ui-datepicker-year\").\n\t\t\t\tprop(\"disabled\", false);\n\t\t}\n\t\tthis._disabledInputs = $.map(this._disabledInputs,\n\t\t\tfunction(value) { return (value === target ? null : value); }); // delete entry\n\t},\n\n\t/* Disable the date picker to a jQuery selection.\n\t * @param  target\telement - the target input field or division or span\n\t */\n\t_disableDatepicker: function(target) {\n\t\tvar nodeName, inline,\n\t\t\t$target = $(target),\n\t\t\tinst = $.data(target, PROP_NAME);\n\n\t\tif (!$target.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\n\t\tnodeName = target.nodeName.toLowerCase();\n\t\tif (nodeName === \"input\") {\n\t\t\ttarget.disabled = true;\n\t\t\tinst.trigger.filter(\"button\").\n\t\t\t\teach(function() { this.disabled = true; }).end().\n\t\t\t\tfilter(\"img\").css({opacity: \"0.5\", cursor: \"default\"});\n\t\t} else if (nodeName === \"div\" || nodeName === \"span\") {\n\t\t\tinline = $target.children(\".\" + this._inlineClass);\n\t\t\tinline.children().addClass(\"ui-state-disabled\");\n\t\t\tinline.find(\"select.ui-datepicker-month, select.ui-datepicker-year\").\n\t\t\t\tprop(\"disabled\", true);\n\t\t}\n\t\tthis._disabledInputs = $.map(this._disabledInputs,\n\t\t\tfunction(value) { return (value === target ? null : value); }); // delete entry\n\t\tthis._disabledInputs[this._disabledInputs.length] = target;\n\t},\n\n\t/* Is the first field in a jQuery collection disabled as a datepicker?\n\t * @param  target\telement - the target input field or division or span\n\t * @return boolean - true if disabled, false if enabled\n\t */\n\t_isDisabledDatepicker: function(target) {\n\t\tif (!target) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (var i = 0; i < this._disabledInputs.length; i++) {\n\t\t\tif (this._disabledInputs[i] === target) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t},\n\n\t/* Retrieve the instance data for the target control.\n\t * @param  target  element - the target input field or division or span\n\t * @return  object - the associated instance data\n\t * @throws  error if a jQuery problem getting data\n\t */\n\t_getInst: function(target) {\n\t\ttry {\n\t\t\treturn $.data(target, PROP_NAME);\n\t\t}\n\t\tcatch (err) {\n\t\t\tthrow \"Missing instance data for this datepicker\";\n\t\t}\n\t},\n\n\t/* Update or retrieve the settings for a date picker attached to an input field or division.\n\t * @param  target  element - the target input field or division or span\n\t * @param  name\tobject - the new settings to update or\n\t *\t\t\t\tstring - the name of the setting to change or retrieve,\n\t *\t\t\t\twhen retrieving also \"all\" for all instance settings or\n\t *\t\t\t\t\"defaults\" for all global defaults\n\t * @param  value   any - the new value for the setting\n\t *\t\t\t\t(omit if above is an object or to retrieve a value)\n\t */\n\t_optionDatepicker: function(target, name, value) {\n\t\tvar settings, date, minDate, maxDate,\n\t\t\tinst = this._getInst(target);\n\n\t\tif (arguments.length === 2 && typeof name === \"string\") {\n\t\t\treturn (name === \"defaults\" ? $.extend({}, $.datepicker._defaults) :\n\t\t\t\t(inst ? (name === \"all\" ? $.extend({}, inst.settings) :\n\t\t\t\tthis._get(inst, name)) : null));\n\t\t}\n\n\t\tsettings = name || {};\n\t\tif (typeof name === \"string\") {\n\t\t\tsettings = {};\n\t\t\tsettings[name] = value;\n\t\t}\n\n\t\tif (inst) {\n\t\t\tif (this._curInst === inst) {\n\t\t\t\tthis._hideDatepicker();\n\t\t\t}\n\n\t\t\tdate = this._getDateDatepicker(target, true);\n\t\t\tminDate = this._getMinMaxDate(inst, \"min\");\n\t\t\tmaxDate = this._getMinMaxDate(inst, \"max\");\n\t\t\textendRemove(inst.settings, settings);\n\t\t\t// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided\n\t\t\tif (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {\n\t\t\t\tinst.settings.minDate = this._formatDate(inst, minDate);\n\t\t\t}\n\t\t\tif (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {\n\t\t\t\tinst.settings.maxDate = this._formatDate(inst, maxDate);\n\t\t\t}\n\t\t\tif ( \"disabled\" in settings ) {\n\t\t\t\tif ( settings.disabled ) {\n\t\t\t\t\tthis._disableDatepicker(target);\n\t\t\t\t} else {\n\t\t\t\t\tthis._enableDatepicker(target);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._attachments($(target), inst);\n\t\t\tthis._autoSize(inst);\n\t\t\tthis._setDate(inst, date);\n\t\t\tthis._updateAlternate(inst);\n\t\t\tthis._updateDatepicker(inst);\n\t\t}\n\t},\n\n\t// change method deprecated\n\t_changeDatepicker: function(target, name, value) {\n\t\tthis._optionDatepicker(target, name, value);\n\t},\n\n\t/* Redraw the date picker attached to an input field or division.\n\t * @param  target  element - the target input field or division or span\n\t */\n\t_refreshDatepicker: function(target) {\n\t\tvar inst = this._getInst(target);\n\t\tif (inst) {\n\t\t\tthis._updateDatepicker(inst);\n\t\t}\n\t},\n\n\t/* Set the dates for a jQuery selection.\n\t * @param  target element - the target input field or division or span\n\t * @param  date\tDate - the new date\n\t */\n\t_setDateDatepicker: function(target, date) {\n\t\tvar inst = this._getInst(target);\n\t\tif (inst) {\n\t\t\tthis._setDate(inst, date);\n\t\t\tthis._updateDatepicker(inst);\n\t\t\tthis._updateAlternate(inst);\n\t\t}\n\t},\n\n\t/* Get the date(s) for the first entry in a jQuery selection.\n\t * @param  target element - the target input field or division or span\n\t * @param  noDefault boolean - true if no default date is to be used\n\t * @return Date - the current date\n\t */\n\t_getDateDatepicker: function(target, noDefault) {\n\t\tvar inst = this._getInst(target);\n\t\tif (inst && !inst.inline) {\n\t\t\tthis._setDateFromField(inst, noDefault);\n\t\t}\n\t\treturn (inst ? this._getDate(inst) : null);\n\t},\n\n\t/* Handle keystrokes. */\n\t_doKeyDown: function(event) {\n\t\tvar onSelect, dateStr, sel,\n\t\t\tinst = $.datepicker._getInst(event.target),\n\t\t\thandled = true,\n\t\t\tisRTL = inst.dpDiv.is(\".ui-datepicker-rtl\");\n\n\t\tinst._keyEvent = true;\n\t\tif ($.datepicker._datepickerShowing) {\n\t\t\tswitch (event.keyCode) {\n\t\t\t\tcase 9: $.datepicker._hideDatepicker();\n\t\t\t\t\t\thandled = false;\n\t\t\t\t\t\tbreak; // hide on tab out\n\t\t\t\tcase 13: sel = $(\"td.\" + $.datepicker._dayOverClass + \":not(.\" +\n\t\t\t\t\t\t\t\t\t$.datepicker._currentClass + \")\", inst.dpDiv);\n\t\t\t\t\t\tif (sel[0]) {\n\t\t\t\t\t\t\t$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tonSelect = $.datepicker._get(inst, \"onSelect\");\n\t\t\t\t\t\tif (onSelect) {\n\t\t\t\t\t\t\tdateStr = $.datepicker._formatDate(inst);\n\n\t\t\t\t\t\t\t// trigger custom callback\n\t\t\t\t\t\t\tonSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$.datepicker._hideDatepicker();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false; // don't submit the form\n\t\t\t\tcase 27: $.datepicker._hideDatepicker();\n\t\t\t\t\t\tbreak; // hide on escape\n\t\t\t\tcase 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t-$.datepicker._get(inst, \"stepBigMonths\") :\n\t\t\t\t\t\t\t-$.datepicker._get(inst, \"stepMonths\")), \"M\");\n\t\t\t\t\t\tbreak; // previous month/year on page up/+ ctrl\n\t\t\t\tcase 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t+$.datepicker._get(inst, \"stepBigMonths\") :\n\t\t\t\t\t\t\t+$.datepicker._get(inst, \"stepMonths\")), \"M\");\n\t\t\t\t\t\tbreak; // next month/year on page down/+ ctrl\n\t\t\t\tcase 35: if (event.ctrlKey || event.metaKey) {\n\t\t\t\t\t\t\t$.datepicker._clearDate(event.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // clear on ctrl or command +end\n\t\t\t\tcase 36: if (event.ctrlKey || event.metaKey) {\n\t\t\t\t\t\t\t$.datepicker._gotoToday(event.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // current on ctrl or command +home\n\t\t\t\tcase 37: if (event.ctrlKey || event.metaKey) {\n\t\t\t\t\t\t\t$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), \"D\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\t// -1 day on ctrl or command +left\n\t\t\t\t\t\tif (event.originalEvent.altKey) {\n\t\t\t\t\t\t\t$.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t\t-$.datepicker._get(inst, \"stepBigMonths\") :\n\t\t\t\t\t\t\t\t-$.datepicker._get(inst, \"stepMonths\")), \"M\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// next month/year on alt +left on Mac\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase 38: if (event.ctrlKey || event.metaKey) {\n\t\t\t\t\t\t\t$.datepicker._adjustDate(event.target, -7, \"D\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // -1 week on ctrl or command +up\n\t\t\t\tcase 39: if (event.ctrlKey || event.metaKey) {\n\t\t\t\t\t\t\t$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), \"D\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\t// +1 day on ctrl or command +right\n\t\t\t\t\t\tif (event.originalEvent.altKey) {\n\t\t\t\t\t\t\t$.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t\t+$.datepicker._get(inst, \"stepBigMonths\") :\n\t\t\t\t\t\t\t\t+$.datepicker._get(inst, \"stepMonths\")), \"M\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// next month/year on alt +right\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase 40: if (event.ctrlKey || event.metaKey) {\n\t\t\t\t\t\t\t$.datepicker._adjustDate(event.target, +7, \"D\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // +1 week on ctrl or command +down\n\t\t\t\tdefault: handled = false;\n\t\t\t}\n\t\t} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home\n\t\t\t$.datepicker._showDatepicker(this);\n\t\t} else {\n\t\t\thandled = false;\n\t\t}\n\n\t\tif (handled) {\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t}\n\t},\n\n\t/* Filter entered characters - based on date format. */\n\t_doKeyPress: function(event) {\n\t\tvar chars, chr,\n\t\t\tinst = $.datepicker._getInst(event.target);\n\n\t\tif ($.datepicker._get(inst, \"constrainInput\")) {\n\t\t\tchars = $.datepicker._possibleChars($.datepicker._get(inst, \"dateFormat\"));\n\t\t\tchr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);\n\t\t\treturn event.ctrlKey || event.metaKey || (chr < \" \" || !chars || chars.indexOf(chr) > -1);\n\t\t}\n\t},\n\n\t/* Synchronise manual entry and field/alternate field. */\n\t_doKeyUp: function(event) {\n\t\tvar date,\n\t\t\tinst = $.datepicker._getInst(event.target);\n\n\t\tif (inst.input.val() !== inst.lastVal) {\n\t\t\ttry {\n\t\t\t\tdate = $.datepicker.parseDate($.datepicker._get(inst, \"dateFormat\"),\n\t\t\t\t\t(inst.input ? inst.input.val() : null),\n\t\t\t\t\t$.datepicker._getFormatConfig(inst));\n\n\t\t\t\tif (date) { // only if valid\n\t\t\t\t\t$.datepicker._setDateFromField(inst);\n\t\t\t\t\t$.datepicker._updateAlternate(inst);\n\t\t\t\t\t$.datepicker._updateDatepicker(inst);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (err) {\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t},\n\n\t/* Pop-up the date picker for a given input field.\n\t * If false returned from beforeShow event handler do not show.\n\t * @param  input  element - the input field attached to the date picker or\n\t *\t\t\t\t\tevent - if triggered by focus\n\t */\n\t_showDatepicker: function(input) {\n\t\tinput = input.target || input;\n\t\tif (input.nodeName.toLowerCase() !== \"input\") { // find from button/image trigger\n\t\t\tinput = $(\"input\", input.parentNode)[0];\n\t\t}\n\n\t\tif ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here\n\t\t\treturn;\n\t\t}\n\n\t\tvar inst, beforeShow, beforeShowSettings, isFixed,\n\t\t\toffset, showAnim, duration;\n\n\t\tinst = $.datepicker._getInst(input);\n\t\tif ($.datepicker._curInst && $.datepicker._curInst !== inst) {\n\t\t\t$.datepicker._curInst.dpDiv.stop(true, true);\n\t\t\tif ( inst && $.datepicker._datepickerShowing ) {\n\t\t\t\t$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );\n\t\t\t}\n\t\t}\n\n\t\tbeforeShow = $.datepicker._get(inst, \"beforeShow\");\n\t\tbeforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};\n\t\tif(beforeShowSettings === false){\n\t\t\treturn;\n\t\t}\n\t\textendRemove(inst.settings, beforeShowSettings);\n\n\t\tinst.lastVal = null;\n\t\t$.datepicker._lastInput = input;\n\t\t$.datepicker._setDateFromField(inst);\n\n\t\tif ($.datepicker._inDialog) { // hide cursor\n\t\t\tinput.value = \"\";\n\t\t}\n\t\tif (!$.datepicker._pos) { // position below input\n\t\t\t$.datepicker._pos = $.datepicker._findPos(input);\n\t\t\t$.datepicker._pos[1] += input.offsetHeight; // add the height\n\t\t}\n\n\t\tisFixed = false;\n\t\t$(input).parents().each(function() {\n\t\t\tisFixed |= $(this).css(\"position\") === \"fixed\";\n\t\t\treturn !isFixed;\n\t\t});\n\n\t\toffset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};\n\t\t$.datepicker._pos = null;\n\t\t//to avoid flashes on Firefox\n\t\tinst.dpDiv.empty();\n\t\t// determine sizing offscreen\n\t\tinst.dpDiv.css({position: \"absolute\", display: \"block\", top: \"-1000px\"});\n\t\t$.datepicker._updateDatepicker(inst);\n\t\t// fix width for dynamic number of date pickers\n\t\t// and adjust position before showing\n\t\toffset = $.datepicker._checkOffset(inst, offset, isFixed);\n\t\tinst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?\n\t\t\t\"static\" : (isFixed ? \"fixed\" : \"absolute\")), display: \"none\",\n\t\t\tleft: offset.left + \"px\", top: offset.top + \"px\"});\n\n\t\tif (!inst.inline) {\n\t\t\tshowAnim = $.datepicker._get(inst, \"showAnim\");\n\t\t\tduration = $.datepicker._get(inst, \"duration\");\n\t\t\tinst.dpDiv.zIndex($(input).zIndex()+1);\n\t\t\t$.datepicker._datepickerShowing = true;\n\n\t\t\tif ( $.effects && $.effects.effect[ showAnim ] ) {\n\t\t\t\tinst.dpDiv.show(showAnim, $.datepicker._get(inst, \"showOptions\"), duration);\n\t\t\t} else {\n\t\t\t\tinst.dpDiv[showAnim || \"show\"](showAnim ? duration : null);\n\t\t\t}\n\n\t\t\tif (inst.input.is(\":visible\") && !inst.input.is(\":disabled\")) {\n\t\t\t\tinst.input.focus();\n\t\t\t}\n\t\t\t$.datepicker._curInst = inst;\n\t\t}\n\t},\n\n\t/* Generate the date picker content. */\n\t_updateDatepicker: function(inst) {\n\t\tthis.maxRows = 4; //Reset the max number of rows being displayed (see #7043)\n\t\tinstActive = inst; // for delegate hover events\n\t\tinst.dpDiv.empty().append(this._generateHTML(inst));\n\t\tthis._attachHandlers(inst);\n\t\tinst.dpDiv.find(\".\" + this._dayOverClass + \" a\").mouseover();\n\n\t\tvar origyearshtml,\n\t\t\tnumMonths = this._getNumberOfMonths(inst),\n\t\t\tcols = numMonths[1],\n\t\t\twidth = 17;\n\n\t\tinst.dpDiv.removeClass(\"ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4\").width(\"\");\n\t\tif (cols > 1) {\n\t\t\tinst.dpDiv.addClass(\"ui-datepicker-multi-\" + cols).css(\"width\", (width * cols) + \"em\");\n\t\t}\n\t\tinst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? \"add\" : \"remove\") +\n\t\t\t\"Class\"](\"ui-datepicker-multi\");\n\t\tinst.dpDiv[(this._get(inst, \"isRTL\") ? \"add\" : \"remove\") +\n\t\t\t\"Class\"](\"ui-datepicker-rtl\");\n\n\t\t// #6694 - don't focus the input if it's already focused\n\t\t// this breaks the change event in IE\n\t\tif (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&\n\t\t\tinst.input.is(\":visible\") && !inst.input.is(\":disabled\") && inst.input[0] !== document.activeElement) {\n\t\t\tinst.input.focus();\n\t\t}\n\n\t\t// deffered render of the years select (to avoid flashes on Firefox)\n\t\tif( inst.yearshtml ){\n\t\t\torigyearshtml = inst.yearshtml;\n\t\t\tsetTimeout(function(){\n\t\t\t\t//assure that inst.yearshtml didn't change.\n\t\t\t\tif( origyearshtml === inst.yearshtml && inst.yearshtml ){\n\t\t\t\t\tinst.dpDiv.find(\"select.ui-datepicker-year:first\").replaceWith(inst.yearshtml);\n\t\t\t\t}\n\t\t\t\torigyearshtml = inst.yearshtml = null;\n\t\t\t}, 0);\n\t\t}\n\t},\n\n\t/* Retrieve the size of left and top borders for an element.\n\t * @param  elem  (jQuery object) the element of interest\n\t * @return  (number[2]) the left and top borders\n\t */\n\t_getBorders: function(elem) {\n\t\tvar convert = function(value) {\n\t\t\treturn {thin: 1, medium: 2, thick: 3}[value] || value;\n\t\t};\n\t\treturn [parseFloat(convert(elem.css(\"border-left-width\"))),\n\t\t\tparseFloat(convert(elem.css(\"border-top-width\")))];\n\t},\n\n\t/* Check positioning to remain on screen. */\n\t_checkOffset: function(inst, offset, isFixed) {\n\t\tvar dpWidth = inst.dpDiv.outerWidth(),\n\t\t\tdpHeight = inst.dpDiv.outerHeight(),\n\t\t\tinputWidth = inst.input ? inst.input.outerWidth() : 0,\n\t\t\tinputHeight = inst.input ? inst.input.outerHeight() : 0,\n\t\t\tviewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),\n\t\t\tviewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());\n\n\t\toffset.left -= (this._get(inst, \"isRTL\") ? (dpWidth - inputWidth) : 0);\n\t\toffset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;\n\t\toffset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;\n\n\t\t// now check if datepicker is showing outside window viewport - move to a better place if so.\n\t\toffset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?\n\t\t\tMath.abs(offset.left + dpWidth - viewWidth) : 0);\n\t\toffset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?\n\t\t\tMath.abs(dpHeight + inputHeight) : 0);\n\n\t\treturn offset;\n\t},\n\n\t/* Find an object's position on the screen. */\n\t_findPos: function(obj) {\n\t\tvar position,\n\t\t\tinst = this._getInst(obj),\n\t\t\tisRTL = this._get(inst, \"isRTL\");\n\n\t\twhile (obj && (obj.type === \"hidden\" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {\n\t\t\tobj = obj[isRTL ? \"previousSibling\" : \"nextSibling\"];\n\t\t}\n\n\t\tposition = $(obj).offset();\n\t\treturn [position.left, position.top];\n\t},\n\n\t/* Hide the date picker from view.\n\t * @param  input  element - the input field attached to the date picker\n\t */\n\t_hideDatepicker: function(input) {\n\t\tvar showAnim, duration, postProcess, onClose,\n\t\t\tinst = this._curInst;\n\n\t\tif (!inst || (input && inst !== $.data(input, PROP_NAME))) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._datepickerShowing) {\n\t\t\tshowAnim = this._get(inst, \"showAnim\");\n\t\t\tduration = this._get(inst, \"duration\");\n\t\t\tpostProcess = function() {\n\t\t\t\t$.datepicker._tidyDialog(inst);\n\t\t\t};\n\n\t\t\t// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed\n\t\t\tif ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {\n\t\t\t\tinst.dpDiv.hide(showAnim, $.datepicker._get(inst, \"showOptions\"), duration, postProcess);\n\t\t\t} else {\n\t\t\t\tinst.dpDiv[(showAnim === \"slideDown\" ? \"slideUp\" :\n\t\t\t\t\t(showAnim === \"fadeIn\" ? \"fadeOut\" : \"hide\"))]((showAnim ? duration : null), postProcess);\n\t\t\t}\n\n\t\t\tif (!showAnim) {\n\t\t\t\tpostProcess();\n\t\t\t}\n\t\t\tthis._datepickerShowing = false;\n\n\t\t\tonClose = this._get(inst, \"onClose\");\n\t\t\tif (onClose) {\n\t\t\t\tonClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : \"\"), inst]);\n\t\t\t}\n\n\t\t\tthis._lastInput = null;\n\t\t\tif (this._inDialog) {\n\t\t\t\tthis._dialogInput.css({ position: \"absolute\", left: \"0\", top: \"-100px\" });\n\t\t\t\tif ($.blockUI) {\n\t\t\t\t\t$.unblockUI();\n\t\t\t\t\t$(\"body\").append(this.dpDiv);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._inDialog = false;\n\t\t}\n\t},\n\n\t/* Tidy up after a dialog display. */\n\t_tidyDialog: function(inst) {\n\t\tinst.dpDiv.removeClass(this._dialogClass).unbind(\".ui-datepicker-calendar\");\n\t},\n\n\t/* Close date picker if clicked elsewhere. */\n\t_checkExternalClick: function(event) {\n\t\tif (!$.datepicker._curInst) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar $target = $(event.target),\n\t\t\tinst = $.datepicker._getInst($target[0]);\n\n\t\tif ( ( ( $target[0].id !== $.datepicker._mainDivId &&\n\t\t\t\t$target.parents(\"#\" + $.datepicker._mainDivId).length === 0 &&\n\t\t\t\t!$target.hasClass($.datepicker.markerClassName) &&\n\t\t\t\t!$target.closest(\".\" + $.datepicker._triggerClass).length &&\n\t\t\t\t$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||\n\t\t\t( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {\n\t\t\t\t$.datepicker._hideDatepicker();\n\t\t}\n\t},\n\n\t/* Adjust one of the date sub-fields. */\n\t_adjustDate: function(id, offset, period) {\n\t\tvar target = $(id),\n\t\t\tinst = this._getInst(target[0]);\n\n\t\tif (this._isDisabledDatepicker(target[0])) {\n\t\t\treturn;\n\t\t}\n\t\tthis._adjustInstDate(inst, offset +\n\t\t\t(period === \"M\" ? this._get(inst, \"showCurrentAtPos\") : 0), // undo positioning\n\t\t\tperiod);\n\t\tthis._updateDatepicker(inst);\n\t},\n\n\t/* Action for current link. */\n\t_gotoToday: function(id) {\n\t\tvar date,\n\t\t\ttarget = $(id),\n\t\t\tinst = this._getInst(target[0]);\n\n\t\tif (this._get(inst, \"gotoCurrent\") && inst.currentDay) {\n\t\t\tinst.selectedDay = inst.currentDay;\n\t\t\tinst.drawMonth = inst.selectedMonth = inst.currentMonth;\n\t\t\tinst.drawYear = inst.selectedYear = inst.currentYear;\n\t\t} else {\n\t\t\tdate = new Date();\n\t\t\tinst.selectedDay = date.getDate();\n\t\t\tinst.drawMonth = inst.selectedMonth = date.getMonth();\n\t\t\tinst.drawYear = inst.selectedYear = date.getFullYear();\n\t\t}\n\t\tthis._notifyChange(inst);\n\t\tthis._adjustDate(target);\n\t},\n\n\t/* Action for selecting a new month/year. */\n\t_selectMonthYear: function(id, select, period) {\n\t\tvar target = $(id),\n\t\t\tinst = this._getInst(target[0]);\n\n\t\tinst[\"selected\" + (period === \"M\" ? \"Month\" : \"Year\")] =\n\t\tinst[\"draw\" + (period === \"M\" ? \"Month\" : \"Year\")] =\n\t\t\tparseInt(select.options[select.selectedIndex].value,10);\n\n\t\tthis._notifyChange(inst);\n\t\tthis._adjustDate(target);\n\t},\n\n\t/* Action for selecting a day. */\n\t_selectDay: function(id, month, year, td) {\n\t\tvar inst,\n\t\t\ttarget = $(id);\n\n\t\tif ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {\n\t\t\treturn;\n\t\t}\n\n\t\tinst = this._getInst(target[0]);\n\t\tinst.selectedDay = inst.currentDay = $(\"a\", td).html();\n\t\tinst.selectedMonth = inst.currentMonth = month;\n\t\tinst.selectedYear = inst.currentYear = year;\n\t\tthis._selectDate(id, this._formatDate(inst,\n\t\t\tinst.currentDay, inst.currentMonth, inst.currentYear));\n\t},\n\n\t/* Erase the input field and hide the date picker. */\n\t_clearDate: function(id) {\n\t\tvar target = $(id);\n\t\tthis._selectDate(target, \"\");\n\t},\n\n\t/* Update the input field with the selected date. */\n\t_selectDate: function(id, dateStr) {\n\t\tvar onSelect,\n\t\t\ttarget = $(id),\n\t\t\tinst = this._getInst(target[0]);\n\n\t\tdateStr = (dateStr != null ? dateStr : this._formatDate(inst));\n\t\tif (inst.input) {\n\t\t\tinst.input.val(dateStr);\n\t\t}\n\t\tthis._updateAlternate(inst);\n\n\t\tonSelect = this._get(inst, \"onSelect\");\n\t\tif (onSelect) {\n\t\t\tonSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback\n\t\t} else if (inst.input) {\n\t\t\tinst.input.trigger(\"change\"); // fire the change event\n\t\t}\n\n\t\tif (inst.inline){\n\t\t\tthis._updateDatepicker(inst);\n\t\t} else {\n\t\t\tthis._hideDatepicker();\n\t\t\tthis._lastInput = inst.input[0];\n\t\t\tif (typeof(inst.input[0]) !== \"object\") {\n\t\t\t\tinst.input.focus(); // restore focus\n\t\t\t}\n\t\t\tthis._lastInput = null;\n\t\t}\n\t},\n\n\t/* Update any alternate field to synchronise with the main field. */\n\t_updateAlternate: function(inst) {\n\t\tvar altFormat, date, dateStr,\n\t\t\taltField = this._get(inst, \"altField\");\n\n\t\tif (altField) { // update alternate field too\n\t\t\taltFormat = this._get(inst, \"altFormat\") || this._get(inst, \"dateFormat\");\n\t\t\tdate = this._getDate(inst);\n\t\t\tdateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));\n\t\t\t$(altField).each(function() { $(this).val(dateStr); });\n\t\t}\n\t},\n\n\t/* Set as beforeShowDay function to prevent selection of weekends.\n\t * @param  date  Date - the date to customise\n\t * @return [boolean, string] - is this date selectable?, what is its CSS class?\n\t */\n\tnoWeekends: function(date) {\n\t\tvar day = date.getDay();\n\t\treturn [(day > 0 && day < 6), \"\"];\n\t},\n\n\t/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.\n\t * @param  date  Date - the date to get the week for\n\t * @return  number - the number of the week within the year that contains this date\n\t */\n\tiso8601Week: function(date) {\n\t\tvar time,\n\t\t\tcheckDate = new Date(date.getTime());\n\n\t\t// Find Thursday of this week starting on Monday\n\t\tcheckDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));\n\n\t\ttime = checkDate.getTime();\n\t\tcheckDate.setMonth(0); // Compare with Jan 1\n\t\tcheckDate.setDate(1);\n\t\treturn Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;\n\t},\n\n\t/* Parse a string value into a date object.\n\t * See formatDate below for the possible formats.\n\t *\n\t * @param  format string - the expected format of the date\n\t * @param  value string - the date in the above format\n\t * @param  settings Object - attributes include:\n\t *\t\t\t\t\tshortYearCutoff  number - the cutoff year for determining the century (optional)\n\t *\t\t\t\t\tdayNamesShort\tstring[7] - abbreviated names of the days from Sunday (optional)\n\t *\t\t\t\t\tdayNames\t\tstring[7] - names of the days from Sunday (optional)\n\t *\t\t\t\t\tmonthNamesShort string[12] - abbreviated names of the months (optional)\n\t *\t\t\t\t\tmonthNames\t\tstring[12] - names of the months (optional)\n\t * @return  Date - the extracted date value or null if value is blank\n\t */\n\tparseDate: function (format, value, settings) {\n\t\tif (format == null || value == null) {\n\t\t\tthrow \"Invalid arguments\";\n\t\t}\n\n\t\tvalue = (typeof value === \"object\" ? value.toString() : value + \"\");\n\t\tif (value === \"\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar iFormat, dim, extra,\n\t\t\tiValue = 0,\n\t\t\tshortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,\n\t\t\tshortYearCutoff = (typeof shortYearCutoffTemp !== \"string\" ? shortYearCutoffTemp :\n\t\t\t\tnew Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),\n\t\t\tdayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,\n\t\t\tdayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,\n\t\t\tmonthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,\n\t\t\tmonthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,\n\t\t\tyear = -1,\n\t\t\tmonth = -1,\n\t\t\tday = -1,\n\t\t\tdoy = -1,\n\t\t\tliteral = false,\n\t\t\tdate,\n\t\t\t// Check whether a format character is doubled\n\t\t\tlookAhead = function(match) {\n\t\t\t\tvar matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);\n\t\t\t\tif (matches) {\n\t\t\t\t\tiFormat++;\n\t\t\t\t}\n\t\t\t\treturn matches;\n\t\t\t},\n\t\t\t// Extract a number from the string value\n\t\t\tgetNumber = function(match) {\n\t\t\t\tvar isDoubled = lookAhead(match),\n\t\t\t\t\tsize = (match === \"@\" ? 14 : (match === \"!\" ? 20 :\n\t\t\t\t\t(match === \"y\" && isDoubled ? 4 : (match === \"o\" ? 3 : 2)))),\n\t\t\t\t\tdigits = new RegExp(\"^\\\\d{1,\" + size + \"}\"),\n\t\t\t\t\tnum = value.substring(iValue).match(digits);\n\t\t\t\tif (!num) {\n\t\t\t\t\tthrow \"Missing number at position \" + iValue;\n\t\t\t\t}\n\t\t\t\tiValue += num[0].length;\n\t\t\t\treturn parseInt(num[0], 10);\n\t\t\t},\n\t\t\t// Extract a name from the string value and convert to an index\n\t\t\tgetName = function(match, shortNames, longNames) {\n\t\t\t\tvar index = -1,\n\t\t\t\t\tnames = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {\n\t\t\t\t\t\treturn [ [k, v] ];\n\t\t\t\t\t}).sort(function (a, b) {\n\t\t\t\t\t\treturn -(a[1].length - b[1].length);\n\t\t\t\t\t});\n\n\t\t\t\t$.each(names, function (i, pair) {\n\t\t\t\t\tvar name = pair[1];\n\t\t\t\t\tif (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {\n\t\t\t\t\t\tindex = pair[0];\n\t\t\t\t\t\tiValue += name.length;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\treturn index + 1;\n\t\t\t\t} else {\n\t\t\t\t\tthrow \"Unknown name at position \" + iValue;\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Confirm that a literal character matches the string value\n\t\t\tcheckLiteral = function() {\n\t\t\t\tif (value.charAt(iValue) !== format.charAt(iFormat)) {\n\t\t\t\t\tthrow \"Unexpected literal at position \" + iValue;\n\t\t\t\t}\n\t\t\t\tiValue++;\n\t\t\t};\n\n\t\tfor (iFormat = 0; iFormat < format.length; iFormat++) {\n\t\t\tif (literal) {\n\t\t\t\tif (format.charAt(iFormat) === \"'\" && !lookAhead(\"'\")) {\n\t\t\t\t\tliteral = false;\n\t\t\t\t} else {\n\t\t\t\t\tcheckLiteral();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tswitch (format.charAt(iFormat)) {\n\t\t\t\t\tcase \"d\":\n\t\t\t\t\t\tday = getNumber(\"d\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"D\":\n\t\t\t\t\t\tgetName(\"D\", dayNamesShort, dayNames);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"o\":\n\t\t\t\t\t\tdoy = getNumber(\"o\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"m\":\n\t\t\t\t\t\tmonth = getNumber(\"m\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"M\":\n\t\t\t\t\t\tmonth = getName(\"M\", monthNamesShort, monthNames);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"y\":\n\t\t\t\t\t\tyear = getNumber(\"y\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"@\":\n\t\t\t\t\t\tdate = new Date(getNumber(\"@\"));\n\t\t\t\t\t\tyear = date.getFullYear();\n\t\t\t\t\t\tmonth = date.getMonth() + 1;\n\t\t\t\t\t\tday = date.getDate();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"!\":\n\t\t\t\t\t\tdate = new Date((getNumber(\"!\") - this._ticksTo1970) / 10000);\n\t\t\t\t\t\tyear = date.getFullYear();\n\t\t\t\t\t\tmonth = date.getMonth() + 1;\n\t\t\t\t\t\tday = date.getDate();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\tif (lookAhead(\"'\")){\n\t\t\t\t\t\t\tcheckLiteral();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tliteral = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tcheckLiteral();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (iValue < value.length){\n\t\t\textra = value.substr(iValue);\n\t\t\tif (!/^\\s+/.test(extra)) {\n\t\t\t\tthrow \"Extra/unparsed characters found in date: \" + extra;\n\t\t\t}\n\t\t}\n\n\t\tif (year === -1) {\n\t\t\tyear = new Date().getFullYear();\n\t\t} else if (year < 100) {\n\t\t\tyear += new Date().getFullYear() - new Date().getFullYear() % 100 +\n\t\t\t\t(year <= shortYearCutoff ? 0 : -100);\n\t\t}\n\n\t\tif (doy > -1) {\n\t\t\tmonth = 1;\n\t\t\tday = doy;\n\t\t\tdo {\n\t\t\t\tdim = this._getDaysInMonth(year, month - 1);\n\t\t\t\tif (day <= dim) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmonth++;\n\t\t\t\tday -= dim;\n\t\t\t} while (true);\n\t\t}\n\n\t\tdate = this._daylightSavingAdjust(new Date(year, month - 1, day));\n\t\tif (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {\n\t\t\tthrow \"Invalid date\"; // E.g. 31/02/00\n\t\t}\n\t\treturn date;\n\t},\n\n\t/* Standard date formats. */\n\tATOM: \"yy-mm-dd\", // RFC 3339 (ISO 8601)\n\tCOOKIE: \"D, dd M yy\",\n\tISO_8601: \"yy-mm-dd\",\n\tRFC_822: \"D, d M y\",\n\tRFC_850: \"DD, dd-M-y\",\n\tRFC_1036: \"D, d M y\",\n\tRFC_1123: \"D, d M yy\",\n\tRFC_2822: \"D, d M yy\",\n\tRSS: \"D, d M y\", // RFC 822\n\tTICKS: \"!\",\n\tTIMESTAMP: \"@\",\n\tW3C: \"yy-mm-dd\", // ISO 8601\n\n\t_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +\n\t\tMath.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),\n\n\t/* Format a date object into a string value.\n\t * The format can be combinations of the following:\n\t * d  - day of month (no leading zero)\n\t * dd - day of month (two digit)\n\t * o  - day of year (no leading zeros)\n\t * oo - day of year (three digit)\n\t * D  - day name short\n\t * DD - day name long\n\t * m  - month of year (no leading zero)\n\t * mm - month of year (two digit)\n\t * M  - month name short\n\t * MM - month name long\n\t * y  - year (two digit)\n\t * yy - year (four digit)\n\t * @ - Unix timestamp (ms since 01/01/1970)\n\t * ! - Windows ticks (100ns since 01/01/0001)\n\t * \"...\" - literal text\n\t * '' - single quote\n\t *\n\t * @param  format string - the desired format of the date\n\t * @param  date Date - the date value to format\n\t * @param  settings Object - attributes include:\n\t *\t\t\t\t\tdayNamesShort\tstring[7] - abbreviated names of the days from Sunday (optional)\n\t *\t\t\t\t\tdayNames\t\tstring[7] - names of the days from Sunday (optional)\n\t *\t\t\t\t\tmonthNamesShort string[12] - abbreviated names of the months (optional)\n\t *\t\t\t\t\tmonthNames\t\tstring[12] - names of the months (optional)\n\t * @return  string - the date in the above format\n\t */\n\tformatDate: function (format, date, settings) {\n\t\tif (!date) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tvar iFormat,\n\t\t\tdayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,\n\t\t\tdayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,\n\t\t\tmonthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,\n\t\t\tmonthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,\n\t\t\t// Check whether a format character is doubled\n\t\t\tlookAhead = function(match) {\n\t\t\t\tvar matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);\n\t\t\t\tif (matches) {\n\t\t\t\t\tiFormat++;\n\t\t\t\t}\n\t\t\t\treturn matches;\n\t\t\t},\n\t\t\t// Format a number, with leading zero if necessary\n\t\t\tformatNumber = function(match, value, len) {\n\t\t\t\tvar num = \"\" + value;\n\t\t\t\tif (lookAhead(match)) {\n\t\t\t\t\twhile (num.length < len) {\n\t\t\t\t\t\tnum = \"0\" + num;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn num;\n\t\t\t},\n\t\t\t// Format a name, short or long as requested\n\t\t\tformatName = function(match, value, shortNames, longNames) {\n\t\t\t\treturn (lookAhead(match) ? longNames[value] : shortNames[value]);\n\t\t\t},\n\t\t\toutput = \"\",\n\t\t\tliteral = false;\n\n\t\tif (date) {\n\t\t\tfor (iFormat = 0; iFormat < format.length; iFormat++) {\n\t\t\t\tif (literal) {\n\t\t\t\t\tif (format.charAt(iFormat) === \"'\" && !lookAhead(\"'\")) {\n\t\t\t\t\t\tliteral = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\toutput += format.charAt(iFormat);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tswitch (format.charAt(iFormat)) {\n\t\t\t\t\t\tcase \"d\":\n\t\t\t\t\t\t\toutput += formatNumber(\"d\", date.getDate(), 2);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"D\":\n\t\t\t\t\t\t\toutput += formatName(\"D\", date.getDay(), dayNamesShort, dayNames);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"o\":\n\t\t\t\t\t\t\toutput += formatNumber(\"o\",\n\t\t\t\t\t\t\t\tMath.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"m\":\n\t\t\t\t\t\t\toutput += formatNumber(\"m\", date.getMonth() + 1, 2);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"M\":\n\t\t\t\t\t\t\toutput += formatName(\"M\", date.getMonth(), monthNamesShort, monthNames);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"y\":\n\t\t\t\t\t\t\toutput += (lookAhead(\"y\") ? date.getFullYear() :\n\t\t\t\t\t\t\t\t(date.getYear() % 100 < 10 ? \"0\" : \"\") + date.getYear() % 100);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"@\":\n\t\t\t\t\t\t\toutput += date.getTime();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"!\":\n\t\t\t\t\t\t\toutput += date.getTime() * 10000 + this._ticksTo1970;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (lookAhead(\"'\")) {\n\t\t\t\t\t\t\t\toutput += \"'\";\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tliteral = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\toutput += format.charAt(iFormat);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn output;\n\t},\n\n\t/* Extract all possible characters from the date format. */\n\t_possibleChars: function (format) {\n\t\tvar iFormat,\n\t\t\tchars = \"\",\n\t\t\tliteral = false,\n\t\t\t// Check whether a format character is doubled\n\t\t\tlookAhead = function(match) {\n\t\t\t\tvar matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);\n\t\t\t\tif (matches) {\n\t\t\t\t\tiFormat++;\n\t\t\t\t}\n\t\t\t\treturn matches;\n\t\t\t};\n\n\t\tfor (iFormat = 0; iFormat < format.length; iFormat++) {\n\t\t\tif (literal) {\n\t\t\t\tif (format.charAt(iFormat) === \"'\" && !lookAhead(\"'\")) {\n\t\t\t\t\tliteral = false;\n\t\t\t\t} else {\n\t\t\t\t\tchars += format.charAt(iFormat);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tswitch (format.charAt(iFormat)) {\n\t\t\t\t\tcase \"d\": case \"m\": case \"y\": case \"@\":\n\t\t\t\t\t\tchars += \"0123456789\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"D\": case \"M\":\n\t\t\t\t\t\treturn null; // Accept anything\n\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\tif (lookAhead(\"'\")) {\n\t\t\t\t\t\t\tchars += \"'\";\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tliteral = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tchars += format.charAt(iFormat);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn chars;\n\t},\n\n\t/* Get a setting value, defaulting if necessary. */\n\t_get: function(inst, name) {\n\t\treturn inst.settings[name] !== undefined ?\n\t\t\tinst.settings[name] : this._defaults[name];\n\t},\n\n\t/* Parse existing date and initialise date picker. */\n\t_setDateFromField: function(inst, noDefault) {\n\t\tif (inst.input.val() === inst.lastVal) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar dateFormat = this._get(inst, \"dateFormat\"),\n\t\t\tdates = inst.lastVal = inst.input ? inst.input.val() : null,\n\t\t\tdefaultDate = this._getDefaultDate(inst),\n\t\t\tdate = defaultDate,\n\t\t\tsettings = this._getFormatConfig(inst);\n\n\t\ttry {\n\t\t\tdate = this.parseDate(dateFormat, dates, settings) || defaultDate;\n\t\t} catch (event) {\n\t\t\tdates = (noDefault ? \"\" : dates);\n\t\t}\n\t\tinst.selectedDay = date.getDate();\n\t\tinst.drawMonth = inst.selectedMonth = date.getMonth();\n\t\tinst.drawYear = inst.selectedYear = date.getFullYear();\n\t\tinst.currentDay = (dates ? date.getDate() : 0);\n\t\tinst.currentMonth = (dates ? date.getMonth() : 0);\n\t\tinst.currentYear = (dates ? date.getFullYear() : 0);\n\t\tthis._adjustInstDate(inst);\n\t},\n\n\t/* Retrieve the default date shown on opening. */\n\t_getDefaultDate: function(inst) {\n\t\treturn this._restrictMinMax(inst,\n\t\t\tthis._determineDate(inst, this._get(inst, \"defaultDate\"), new Date()));\n\t},\n\n\t/* A date may be specified as an exact value or a relative one. */\n\t_determineDate: function(inst, date, defaultDate) {\n\t\tvar offsetNumeric = function(offset) {\n\t\t\t\tvar date = new Date();\n\t\t\t\tdate.setDate(date.getDate() + offset);\n\t\t\t\treturn date;\n\t\t\t},\n\t\t\toffsetString = function(offset) {\n\t\t\t\ttry {\n\t\t\t\t\treturn $.datepicker.parseDate($.datepicker._get(inst, \"dateFormat\"),\n\t\t\t\t\t\toffset, $.datepicker._getFormatConfig(inst));\n\t\t\t\t}\n\t\t\t\tcatch (e) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\n\t\t\t\tvar date = (offset.toLowerCase().match(/^c/) ?\n\t\t\t\t\t$.datepicker._getDate(inst) : null) || new Date(),\n\t\t\t\t\tyear = date.getFullYear(),\n\t\t\t\t\tmonth = date.getMonth(),\n\t\t\t\t\tday = date.getDate(),\n\t\t\t\t\tpattern = /([+\\-]?[0-9]+)\\s*(d|D|w|W|m|M|y|Y)?/g,\n\t\t\t\t\tmatches = pattern.exec(offset);\n\n\t\t\t\twhile (matches) {\n\t\t\t\t\tswitch (matches[2] || \"d\") {\n\t\t\t\t\t\tcase \"d\" : case \"D\" :\n\t\t\t\t\t\t\tday += parseInt(matches[1],10); break;\n\t\t\t\t\t\tcase \"w\" : case \"W\" :\n\t\t\t\t\t\t\tday += parseInt(matches[1],10) * 7; break;\n\t\t\t\t\t\tcase \"m\" : case \"M\" :\n\t\t\t\t\t\t\tmonth += parseInt(matches[1],10);\n\t\t\t\t\t\t\tday = Math.min(day, $.datepicker._getDaysInMonth(year, month));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"y\": case \"Y\" :\n\t\t\t\t\t\t\tyear += parseInt(matches[1],10);\n\t\t\t\t\t\t\tday = Math.min(day, $.datepicker._getDaysInMonth(year, month));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tmatches = pattern.exec(offset);\n\t\t\t\t}\n\t\t\t\treturn new Date(year, month, day);\n\t\t\t},\n\t\t\tnewDate = (date == null || date === \"\" ? defaultDate : (typeof date === \"string\" ? offsetString(date) :\n\t\t\t\t(typeof date === \"number\" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));\n\n\t\tnewDate = (newDate && newDate.toString() === \"Invalid Date\" ? defaultDate : newDate);\n\t\tif (newDate) {\n\t\t\tnewDate.setHours(0);\n\t\t\tnewDate.setMinutes(0);\n\t\t\tnewDate.setSeconds(0);\n\t\t\tnewDate.setMilliseconds(0);\n\t\t}\n\t\treturn this._daylightSavingAdjust(newDate);\n\t},\n\n\t/* Handle switch to/from daylight saving.\n\t * Hours may be non-zero on daylight saving cut-over:\n\t * > 12 when midnight changeover, but then cannot generate\n\t * midnight datetime, so jump to 1AM, otherwise reset.\n\t * @param  date  (Date) the date to check\n\t * @return  (Date) the corrected date\n\t */\n\t_daylightSavingAdjust: function(date) {\n\t\tif (!date) {\n\t\t\treturn null;\n\t\t}\n\t\tdate.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n\t\treturn date;\n\t},\n\n\t/* Set the date(s) directly. */\n\t_setDate: function(inst, date, noChange) {\n\t\tvar clear = !date,\n\t\t\torigMonth = inst.selectedMonth,\n\t\t\torigYear = inst.selectedYear,\n\t\t\tnewDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));\n\n\t\tinst.selectedDay = inst.currentDay = newDate.getDate();\n\t\tinst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();\n\t\tinst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();\n\t\tif ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {\n\t\t\tthis._notifyChange(inst);\n\t\t}\n\t\tthis._adjustInstDate(inst);\n\t\tif (inst.input) {\n\t\t\tinst.input.val(clear ? \"\" : this._formatDate(inst));\n\t\t}\n\t},\n\n\t/* Retrieve the date(s) directly. */\n\t_getDate: function(inst) {\n\t\tvar startDate = (!inst.currentYear || (inst.input && inst.input.val() === \"\") ? null :\n\t\t\tthis._daylightSavingAdjust(new Date(\n\t\t\tinst.currentYear, inst.currentMonth, inst.currentDay)));\n\t\t\treturn startDate;\n\t},\n\n\t/* Attach the onxxx handlers.  These are declared statically so\n\t * they work with static code transformers like Caja.\n\t */\n\t_attachHandlers: function(inst) {\n\t\tvar stepMonths = this._get(inst, \"stepMonths\"),\n\t\t\tid = \"#\" + inst.id.replace( /\\\\\\\\/g, \"\\\\\" );\n\t\tinst.dpDiv.find(\"[data-handler]\").map(function () {\n\t\t\tvar handler = {\n\t\t\t\tprev: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._adjustDate(id, -stepMonths, \"M\");\n\t\t\t\t},\n\t\t\t\tnext: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._adjustDate(id, +stepMonths, \"M\");\n\t\t\t\t},\n\t\t\t\thide: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._hideDatepicker();\n\t\t\t\t},\n\t\t\t\ttoday: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._gotoToday(id);\n\t\t\t\t},\n\t\t\t\tselectDay: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._selectDay(id, +this.getAttribute(\"data-month\"), +this.getAttribute(\"data-year\"), this);\n\t\t\t\t\treturn false;\n\t\t\t\t},\n\t\t\t\tselectMonth: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._selectMonthYear(id, this, \"M\");\n\t\t\t\t\treturn false;\n\t\t\t\t},\n\t\t\t\tselectYear: function () {\n\t\t\t\t\twindow[\"DP_jQuery_\" + dpuuid].datepicker._selectMonthYear(id, this, \"Y\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t};\n\t\t\t$(this).bind(this.getAttribute(\"data-event\"), handler[this.getAttribute(\"data-handler\")]);\n\t\t});\n\t},\n\n\t/* Generate the HTML for the current state of the date picker. */\n\t_generateHTML: function(inst) {\n\t\tvar maxDraw, prevText, prev, nextText, next, currentText, gotoDate,\n\t\t\tcontrols, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,\n\t\t\tmonthNames, monthNamesShort, beforeShowDay, showOtherMonths,\n\t\t\tselectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,\n\t\t\tcornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,\n\t\t\tprintDate, dRow, tbody, daySettings, otherMonth, unselectable,\n\t\t\ttempDate = new Date(),\n\t\t\ttoday = this._daylightSavingAdjust(\n\t\t\t\tnew Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time\n\t\t\tisRTL = this._get(inst, \"isRTL\"),\n\t\t\tshowButtonPanel = this._get(inst, \"showButtonPanel\"),\n\t\t\thideIfNoPrevNext = this._get(inst, \"hideIfNoPrevNext\"),\n\t\t\tnavigationAsDateFormat = this._get(inst, \"navigationAsDateFormat\"),\n\t\t\tnumMonths = this._getNumberOfMonths(inst),\n\t\t\tshowCurrentAtPos = this._get(inst, \"showCurrentAtPos\"),\n\t\t\tstepMonths = this._get(inst, \"stepMonths\"),\n\t\t\tisMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),\n\t\t\tcurrentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :\n\t\t\t\tnew Date(inst.currentYear, inst.currentMonth, inst.currentDay))),\n\t\t\tminDate = this._getMinMaxDate(inst, \"min\"),\n\t\t\tmaxDate = this._getMinMaxDate(inst, \"max\"),\n\t\t\tdrawMonth = inst.drawMonth - showCurrentAtPos,\n\t\t\tdrawYear = inst.drawYear;\n\n\t\tif (drawMonth < 0) {\n\t\t\tdrawMonth += 12;\n\t\t\tdrawYear--;\n\t\t}\n\t\tif (maxDate) {\n\t\t\tmaxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),\n\t\t\t\tmaxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));\n\t\t\tmaxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);\n\t\t\twhile (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {\n\t\t\t\tdrawMonth--;\n\t\t\t\tif (drawMonth < 0) {\n\t\t\t\t\tdrawMonth = 11;\n\t\t\t\t\tdrawYear--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tinst.drawMonth = drawMonth;\n\t\tinst.drawYear = drawYear;\n\n\t\tprevText = this._get(inst, \"prevText\");\n\t\tprevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,\n\t\t\tthis._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),\n\t\t\tthis._getFormatConfig(inst)));\n\n\t\tprev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?\n\t\t\t\"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'\" +\n\t\t\t\" title='\" + prevText + \"'><span class='ui-icon ui-icon-circle-triangle-\" + ( isRTL ? \"e\" : \"w\") + \"'>\" + prevText + \"</span></a>\" :\n\t\t\t(hideIfNoPrevNext ? \"\" : \"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='\"+ prevText +\"'><span class='ui-icon ui-icon-circle-triangle-\" + ( isRTL ? \"e\" : \"w\") + \"'>\" + prevText + \"</span></a>\"));\n\n\t\tnextText = this._get(inst, \"nextText\");\n\t\tnextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,\n\t\t\tthis._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),\n\t\t\tthis._getFormatConfig(inst)));\n\n\t\tnext = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?\n\t\t\t\"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'\" +\n\t\t\t\" title='\" + nextText + \"'><span class='ui-icon ui-icon-circle-triangle-\" + ( isRTL ? \"w\" : \"e\") + \"'>\" + nextText + \"</span></a>\" :\n\t\t\t(hideIfNoPrevNext ? \"\" : \"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='\"+ nextText + \"'><span class='ui-icon ui-icon-circle-triangle-\" + ( isRTL ? \"w\" : \"e\") + \"'>\" + nextText + \"</span></a>\"));\n\n\t\tcurrentText = this._get(inst, \"currentText\");\n\t\tgotoDate = (this._get(inst, \"gotoCurrent\") && inst.currentDay ? currentDate : today);\n\t\tcurrentText = (!navigationAsDateFormat ? currentText :\n\t\t\tthis.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));\n\n\t\tcontrols = (!inst.inline ? \"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>\" +\n\t\t\tthis._get(inst, \"closeText\") + \"</button>\" : \"\");\n\n\t\tbuttonPanel = (showButtonPanel) ? \"<div class='ui-datepicker-buttonpane ui-widget-content'>\" + (isRTL ? controls : \"\") +\n\t\t\t(this._isInRange(inst, gotoDate) ? \"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'\" +\n\t\t\t\">\" + currentText + \"</button>\" : \"\") + (isRTL ? \"\" : controls) + \"</div>\" : \"\";\n\n\t\tfirstDay = parseInt(this._get(inst, \"firstDay\"),10);\n\t\tfirstDay = (isNaN(firstDay) ? 0 : firstDay);\n\n\t\tshowWeek = this._get(inst, \"showWeek\");\n\t\tdayNames = this._get(inst, \"dayNames\");\n\t\tdayNamesMin = this._get(inst, \"dayNamesMin\");\n\t\tmonthNames = this._get(inst, \"monthNames\");\n\t\tmonthNamesShort = this._get(inst, \"monthNamesShort\");\n\t\tbeforeShowDay = this._get(inst, \"beforeShowDay\");\n\t\tshowOtherMonths = this._get(inst, \"showOtherMonths\");\n\t\tselectOtherMonths = this._get(inst, \"selectOtherMonths\");\n\t\tdefaultDate = this._getDefaultDate(inst);\n\t\thtml = \"\";\n\t\tdow;\n\t\tfor (row = 0; row < numMonths[0]; row++) {\n\t\t\tgroup = \"\";\n\t\t\tthis.maxRows = 4;\n\t\t\tfor (col = 0; col < numMonths[1]; col++) {\n\t\t\t\tselectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));\n\t\t\t\tcornerClass = \" ui-corner-all\";\n\t\t\t\tcalender = \"\";\n\t\t\t\tif (isMultiMonth) {\n\t\t\t\t\tcalender += \"<div class='ui-datepicker-group\";\n\t\t\t\t\tif (numMonths[1] > 1) {\n\t\t\t\t\t\tswitch (col) {\n\t\t\t\t\t\t\tcase 0: calender += \" ui-datepicker-group-first\";\n\t\t\t\t\t\t\t\tcornerClass = \" ui-corner-\" + (isRTL ? \"right\" : \"left\"); break;\n\t\t\t\t\t\t\tcase numMonths[1]-1: calender += \" ui-datepicker-group-last\";\n\t\t\t\t\t\t\t\tcornerClass = \" ui-corner-\" + (isRTL ? \"left\" : \"right\"); break;\n\t\t\t\t\t\t\tdefault: calender += \" ui-datepicker-group-middle\"; cornerClass = \"\"; break;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcalender += \"'>\";\n\t\t\t\t}\n\t\t\t\tcalender += \"<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix\" + cornerClass + \"'>\" +\n\t\t\t\t\t(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : \"\") +\n\t\t\t\t\t(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : \"\") +\n\t\t\t\t\tthis._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,\n\t\t\t\t\trow > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers\n\t\t\t\t\t\"</div><table class='ui-datepicker-calendar'><thead>\" +\n\t\t\t\t\t\"<tr>\";\n\t\t\t\tthead = (showWeek ? \"<th class='ui-datepicker-week-col'>\" + this._get(inst, \"weekHeader\") + \"</th>\" : \"\");\n\t\t\t\tfor (dow = 0; dow < 7; dow++) { // days of the week\n\t\t\t\t\tday = (dow + firstDay) % 7;\n\t\t\t\t\tthead += \"<th\" + ((dow + firstDay + 6) % 7 >= 5 ? \" class='ui-datepicker-week-end'\" : \"\") + \">\" +\n\t\t\t\t\t\t\"<span title='\" + dayNames[day] + \"'>\" + dayNamesMin[day] + \"</span></th>\";\n\t\t\t\t}\n\t\t\t\tcalender += thead + \"</tr></thead><tbody>\";\n\t\t\t\tdaysInMonth = this._getDaysInMonth(drawYear, drawMonth);\n\t\t\t\tif (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {\n\t\t\t\t\tinst.selectedDay = Math.min(inst.selectedDay, daysInMonth);\n\t\t\t\t}\n\t\t\t\tleadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;\n\t\t\t\tcurRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate\n\t\t\t\tnumRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)\n\t\t\t\tthis.maxRows = numRows;\n\t\t\t\tprintDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));\n\t\t\t\tfor (dRow = 0; dRow < numRows; dRow++) { // create date picker rows\n\t\t\t\t\tcalender += \"<tr>\";\n\t\t\t\t\ttbody = (!showWeek ? \"\" : \"<td class='ui-datepicker-week-col'>\" +\n\t\t\t\t\t\tthis._get(inst, \"calculateWeek\")(printDate) + \"</td>\");\n\t\t\t\t\tfor (dow = 0; dow < 7; dow++) { // create date picker days\n\t\t\t\t\t\tdaySettings = (beforeShowDay ?\n\t\t\t\t\t\t\tbeforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, \"\"]);\n\t\t\t\t\t\totherMonth = (printDate.getMonth() !== drawMonth);\n\t\t\t\t\t\tunselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||\n\t\t\t\t\t\t\t(minDate && printDate < minDate) || (maxDate && printDate > maxDate);\n\t\t\t\t\t\ttbody += \"<td class='\" +\n\t\t\t\t\t\t\t((dow + firstDay + 6) % 7 >= 5 ? \" ui-datepicker-week-end\" : \"\") + // highlight weekends\n\t\t\t\t\t\t\t(otherMonth ? \" ui-datepicker-other-month\" : \"\") + // highlight days from other months\n\t\t\t\t\t\t\t((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key\n\t\t\t\t\t\t\t(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?\n\t\t\t\t\t\t\t// or defaultDate is current printedDate and defaultDate is selectedDate\n\t\t\t\t\t\t\t\" \" + this._dayOverClass : \"\") + // highlight selected day\n\t\t\t\t\t\t\t(unselectable ? \" \" + this._unselectableClass + \" ui-state-disabled\": \"\") +  // highlight unselectable days\n\t\t\t\t\t\t\t(otherMonth && !showOtherMonths ? \"\" : \" \" + daySettings[1] + // highlight custom dates\n\t\t\t\t\t\t\t(printDate.getTime() === currentDate.getTime() ? \" \" + this._currentClass : \"\") + // highlight selected day\n\t\t\t\t\t\t\t(printDate.getTime() === today.getTime() ? \" ui-datepicker-today\" : \"\")) + \"'\" + // highlight today (if different)\n\t\t\t\t\t\t\t((!otherMonth || showOtherMonths) && daySettings[2] ? \" title='\" + daySettings[2].replace(/'/g, \"&#39;\") + \"'\" : \"\") + // cell title\n\t\t\t\t\t\t\t(unselectable ? \"\" : \" data-handler='selectDay' data-event='click' data-month='\" + printDate.getMonth() + \"' data-year='\" + printDate.getFullYear() + \"'\") + \">\" + // actions\n\t\t\t\t\t\t\t(otherMonth && !showOtherMonths ? \"&#xa0;\" : // display for other months\n\t\t\t\t\t\t\t(unselectable ? \"<span class='ui-state-default'>\" + printDate.getDate() + \"</span>\" : \"<a class='ui-state-default\" +\n\t\t\t\t\t\t\t(printDate.getTime() === today.getTime() ? \" ui-state-highlight\" : \"\") +\n\t\t\t\t\t\t\t(printDate.getTime() === currentDate.getTime() ? \" ui-state-active\" : \"\") + // highlight selected day\n\t\t\t\t\t\t\t(otherMonth ? \" ui-priority-secondary\" : \"\") + // distinguish dates from other months\n\t\t\t\t\t\t\t\"' href='#'>\" + printDate.getDate() + \"</a>\")) + \"</td>\"; // display selectable date\n\t\t\t\t\t\tprintDate.setDate(printDate.getDate() + 1);\n\t\t\t\t\t\tprintDate = this._daylightSavingAdjust(printDate);\n\t\t\t\t\t}\n\t\t\t\t\tcalender += tbody + \"</tr>\";\n\t\t\t\t}\n\t\t\t\tdrawMonth++;\n\t\t\t\tif (drawMonth > 11) {\n\t\t\t\t\tdrawMonth = 0;\n\t\t\t\t\tdrawYear++;\n\t\t\t\t}\n\t\t\t\tcalender += \"</tbody></table>\" + (isMultiMonth ? \"</div>\" +\n\t\t\t\t\t\t\t((numMonths[0] > 0 && col === numMonths[1]-1) ? \"<div class='ui-datepicker-row-break'></div>\" : \"\") : \"\");\n\t\t\t\tgroup += calender;\n\t\t\t}\n\t\t\thtml += group;\n\t\t}\n\t\thtml += buttonPanel;\n\t\tinst._keyEvent = false;\n\t\treturn html;\n\t},\n\n\t/* Generate the month and year header. */\n\t_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,\n\t\t\tsecondary, monthNames, monthNamesShort) {\n\n\t\tvar inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,\n\t\t\tchangeMonth = this._get(inst, \"changeMonth\"),\n\t\t\tchangeYear = this._get(inst, \"changeYear\"),\n\t\t\tshowMonthAfterYear = this._get(inst, \"showMonthAfterYear\"),\n\t\t\thtml = \"<div class='ui-datepicker-title'>\",\n\t\t\tmonthHtml = \"\";\n\n\t\t// month selection\n\t\tif (secondary || !changeMonth) {\n\t\t\tmonthHtml += \"<span class='ui-datepicker-month'>\" + monthNames[drawMonth] + \"</span>\";\n\t\t} else {\n\t\t\tinMinYear = (minDate && minDate.getFullYear() === drawYear);\n\t\t\tinMaxYear = (maxDate && maxDate.getFullYear() === drawYear);\n\t\t\tmonthHtml += \"<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>\";\n\t\t\tfor ( month = 0; month < 12; month++) {\n\t\t\t\tif ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {\n\t\t\t\t\tmonthHtml += \"<option value='\" + month + \"'\" +\n\t\t\t\t\t\t(month === drawMonth ? \" selected='selected'\" : \"\") +\n\t\t\t\t\t\t\">\" + monthNamesShort[month] + \"</option>\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tmonthHtml += \"</select>\";\n\t\t}\n\n\t\tif (!showMonthAfterYear) {\n\t\t\thtml += monthHtml + (secondary || !(changeMonth && changeYear) ? \"&#xa0;\" : \"\");\n\t\t}\n\n\t\t// year selection\n\t\tif ( !inst.yearshtml ) {\n\t\t\tinst.yearshtml = \"\";\n\t\t\tif (secondary || !changeYear) {\n\t\t\t\thtml += \"<span class='ui-datepicker-year'>\" + drawYear + \"</span>\";\n\t\t\t} else {\n\t\t\t\t// determine range of years to display\n\t\t\t\tyears = this._get(inst, \"yearRange\").split(\":\");\n\t\t\t\tthisYear = new Date().getFullYear();\n\t\t\t\tdetermineYear = function(value) {\n\t\t\t\t\tvar year = (value.match(/c[+\\-].*/) ? drawYear + parseInt(value.substring(1), 10) :\n\t\t\t\t\t\t(value.match(/[+\\-].*/) ? thisYear + parseInt(value, 10) :\n\t\t\t\t\t\tparseInt(value, 10)));\n\t\t\t\t\treturn (isNaN(year) ? thisYear : year);\n\t\t\t\t};\n\t\t\t\tyear = determineYear(years[0]);\n\t\t\t\tendYear = Math.max(year, determineYear(years[1] || \"\"));\n\t\t\t\tyear = (minDate ? Math.max(year, minDate.getFullYear()) : year);\n\t\t\t\tendYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);\n\t\t\t\tinst.yearshtml += \"<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>\";\n\t\t\t\tfor (; year <= endYear; year++) {\n\t\t\t\t\tinst.yearshtml += \"<option value='\" + year + \"'\" +\n\t\t\t\t\t\t(year === drawYear ? \" selected='selected'\" : \"\") +\n\t\t\t\t\t\t\">\" + year + \"</option>\";\n\t\t\t\t}\n\t\t\t\tinst.yearshtml += \"</select>\";\n\n\t\t\t\thtml += inst.yearshtml;\n\t\t\t\tinst.yearshtml = null;\n\t\t\t}\n\t\t}\n\n\t\thtml += this._get(inst, \"yearSuffix\");\n\t\tif (showMonthAfterYear) {\n\t\t\thtml += (secondary || !(changeMonth && changeYear) ? \"&#xa0;\" : \"\") + monthHtml;\n\t\t}\n\t\thtml += \"</div>\"; // Close datepicker_header\n\t\treturn html;\n\t},\n\n\t/* Adjust one of the date sub-fields. */\n\t_adjustInstDate: function(inst, offset, period) {\n\t\tvar year = inst.drawYear + (period === \"Y\" ? offset : 0),\n\t\t\tmonth = inst.drawMonth + (period === \"M\" ? offset : 0),\n\t\t\tday = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === \"D\" ? offset : 0),\n\t\t\tdate = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));\n\n\t\tinst.selectedDay = date.getDate();\n\t\tinst.drawMonth = inst.selectedMonth = date.getMonth();\n\t\tinst.drawYear = inst.selectedYear = date.getFullYear();\n\t\tif (period === \"M\" || period === \"Y\") {\n\t\t\tthis._notifyChange(inst);\n\t\t}\n\t},\n\n\t/* Ensure a date is within any min/max bounds. */\n\t_restrictMinMax: function(inst, date) {\n\t\tvar minDate = this._getMinMaxDate(inst, \"min\"),\n\t\t\tmaxDate = this._getMinMaxDate(inst, \"max\"),\n\t\t\tnewDate = (minDate && date < minDate ? minDate : date);\n\t\treturn (maxDate && newDate > maxDate ? maxDate : newDate);\n\t},\n\n\t/* Notify change of month/year. */\n\t_notifyChange: function(inst) {\n\t\tvar onChange = this._get(inst, \"onChangeMonthYear\");\n\t\tif (onChange) {\n\t\t\tonChange.apply((inst.input ? inst.input[0] : null),\n\t\t\t\t[inst.selectedYear, inst.selectedMonth + 1, inst]);\n\t\t}\n\t},\n\n\t/* Determine the number of months to show. */\n\t_getNumberOfMonths: function(inst) {\n\t\tvar numMonths = this._get(inst, \"numberOfMonths\");\n\t\treturn (numMonths == null ? [1, 1] : (typeof numMonths === \"number\" ? [1, numMonths] : numMonths));\n\t},\n\n\t/* Determine the current maximum date - ensure no time components are set. */\n\t_getMinMaxDate: function(inst, minMax) {\n\t\treturn this._determineDate(inst, this._get(inst, minMax + \"Date\"), null);\n\t},\n\n\t/* Find the number of days in a given month. */\n\t_getDaysInMonth: function(year, month) {\n\t\treturn 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();\n\t},\n\n\t/* Find the day of the week of the first of a month. */\n\t_getFirstDayOfMonth: function(year, month) {\n\t\treturn new Date(year, month, 1).getDay();\n\t},\n\n\t/* Determines if we should allow a \"next/prev\" month display change. */\n\t_canAdjustMonth: function(inst, offset, curYear, curMonth) {\n\t\tvar numMonths = this._getNumberOfMonths(inst),\n\t\t\tdate = this._daylightSavingAdjust(new Date(curYear,\n\t\t\tcurMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));\n\n\t\tif (offset < 0) {\n\t\t\tdate.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));\n\t\t}\n\t\treturn this._isInRange(inst, date);\n\t},\n\n\t/* Is the given date in the accepted range? */\n\t_isInRange: function(inst, date) {\n\t\tvar yearSplit, currentYear,\n\t\t\tminDate = this._getMinMaxDate(inst, \"min\"),\n\t\t\tmaxDate = this._getMinMaxDate(inst, \"max\"),\n\t\t\tminYear = null,\n\t\t\tmaxYear = null,\n\t\t\tyears = this._get(inst, \"yearRange\");\n\t\t\tif (years){\n\t\t\t\tyearSplit = years.split(\":\");\n\t\t\t\tcurrentYear = new Date().getFullYear();\n\t\t\t\tminYear = parseInt(yearSplit[0], 10);\n\t\t\t\tmaxYear = parseInt(yearSplit[1], 10);\n\t\t\t\tif ( yearSplit[0].match(/[+\\-].*/) ) {\n\t\t\t\t\tminYear += currentYear;\n\t\t\t\t}\n\t\t\t\tif ( yearSplit[1].match(/[+\\-].*/) ) {\n\t\t\t\t\tmaxYear += currentYear;\n\t\t\t\t}\n\t\t\t}\n\n\t\treturn ((!minDate || date.getTime() >= minDate.getTime()) &&\n\t\t\t(!maxDate || date.getTime() <= maxDate.getTime()) &&\n\t\t\t(!minYear || date.getFullYear() >= minYear) &&\n\t\t\t(!maxYear || date.getFullYear() <= maxYear));\n\t},\n\n\t/* Provide the configuration settings for formatting/parsing. */\n\t_getFormatConfig: function(inst) {\n\t\tvar shortYearCutoff = this._get(inst, \"shortYearCutoff\");\n\t\tshortYearCutoff = (typeof shortYearCutoff !== \"string\" ? shortYearCutoff :\n\t\t\tnew Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));\n\t\treturn {shortYearCutoff: shortYearCutoff,\n\t\t\tdayNamesShort: this._get(inst, \"dayNamesShort\"), dayNames: this._get(inst, \"dayNames\"),\n\t\t\tmonthNamesShort: this._get(inst, \"monthNamesShort\"), monthNames: this._get(inst, \"monthNames\")};\n\t},\n\n\t/* Format the given date for display. */\n\t_formatDate: function(inst, day, month, year) {\n\t\tif (!day) {\n\t\t\tinst.currentDay = inst.selectedDay;\n\t\t\tinst.currentMonth = inst.selectedMonth;\n\t\t\tinst.currentYear = inst.selectedYear;\n\t\t}\n\t\tvar date = (day ? (typeof day === \"object\" ? day :\n\t\t\tthis._daylightSavingAdjust(new Date(year, month, day))) :\n\t\t\tthis._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));\n\t\treturn this.formatDate(this._get(inst, \"dateFormat\"), date, this._getFormatConfig(inst));\n\t}\n});\n\n/*\n * Bind hover events for datepicker elements.\n * Done via delegate so the binding only occurs once in the lifetime of the parent div.\n * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.\n */\nfunction bindHover(dpDiv) {\n\tvar selector = \"button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a\";\n\treturn dpDiv.delegate(selector, \"mouseout\", function() {\n\t\t\t$(this).removeClass(\"ui-state-hover\");\n\t\t\tif (this.className.indexOf(\"ui-datepicker-prev\") !== -1) {\n\t\t\t\t$(this).removeClass(\"ui-datepicker-prev-hover\");\n\t\t\t}\n\t\t\tif (this.className.indexOf(\"ui-datepicker-next\") !== -1) {\n\t\t\t\t$(this).removeClass(\"ui-datepicker-next-hover\");\n\t\t\t}\n\t\t})\n\t\t.delegate(selector, \"mouseover\", function(){\n\t\t\tif (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {\n\t\t\t\t$(this).parents(\".ui-datepicker-calendar\").find(\"a\").removeClass(\"ui-state-hover\");\n\t\t\t\t$(this).addClass(\"ui-state-hover\");\n\t\t\t\tif (this.className.indexOf(\"ui-datepicker-prev\") !== -1) {\n\t\t\t\t\t$(this).addClass(\"ui-datepicker-prev-hover\");\n\t\t\t\t}\n\t\t\t\tif (this.className.indexOf(\"ui-datepicker-next\") !== -1) {\n\t\t\t\t\t$(this).addClass(\"ui-datepicker-next-hover\");\n\t\t\t\t}\n\t\t\t}\n\t\t});\n}\n\n/* jQuery extend now ignores nulls! */\nfunction extendRemove(target, props) {\n\t$.extend(target, props);\n\tfor (var name in props) {\n\t\tif (props[name] == null) {\n\t\t\ttarget[name] = props[name];\n\t\t}\n\t}\n\treturn target;\n}\n\n/* Invoke the datepicker functionality.\n   @param  options  string - a command, optionally followed by additional parameters or\n\t\t\t\t\tObject - settings for attaching new datepicker functionality\n   @return  jQuery object */\n$.fn.datepicker = function(options){\n\n\t/* Verify an empty collection wasn't passed - Fixes #6976 */\n\tif ( !this.length ) {\n\t\treturn this;\n\t}\n\n\t/* Initialise the date picker. */\n\tif (!$.datepicker.initialized) {\n\t\t$(document).mousedown($.datepicker._checkExternalClick);\n\t\t$.datepicker.initialized = true;\n\t}\n\n\t/* Append datepicker main container to body if not exist. */\n\tif ($(\"#\"+$.datepicker._mainDivId).length === 0) {\n\t\t$(\"body\").append($.datepicker.dpDiv);\n\t}\n\n\tvar otherArgs = Array.prototype.slice.call(arguments, 1);\n\tif (typeof options === \"string\" && (options === \"isDisabled\" || options === \"getDate\" || options === \"widget\")) {\n\t\treturn $.datepicker[\"_\" + options + \"Datepicker\"].\n\t\t\tapply($.datepicker, [this[0]].concat(otherArgs));\n\t}\n\tif (options === \"option\" && arguments.length === 2 && typeof arguments[1] === \"string\") {\n\t\treturn $.datepicker[\"_\" + options + \"Datepicker\"].\n\t\t\tapply($.datepicker, [this[0]].concat(otherArgs));\n\t}\n\treturn this.each(function() {\n\t\ttypeof options === \"string\" ?\n\t\t\t$.datepicker[\"_\" + options + \"Datepicker\"].\n\t\t\t\tapply($.datepicker, [this].concat(otherArgs)) :\n\t\t\t$.datepicker._attachDatepicker(this, options);\n\t});\n};\n\n$.datepicker = new Datepicker(); // singleton instance\n$.datepicker.initialized = false;\n$.datepicker.uuid = new Date().getTime();\n$.datepicker.version = \"1.10.1\";\n\n// Workaround for #4055\n// Add another global to avoid noConflict issues with inline event handlers\nwindow[\"DP_jQuery_\" + dpuuid] = $;\n\n})(jQuery);\n\n(function( $, undefined ) {\n\nvar sizeRelatedOptions = {\n\t\tbuttons: true,\n\t\theight: true,\n\t\tmaxHeight: true,\n\t\tmaxWidth: true,\n\t\tminHeight: true,\n\t\tminWidth: true,\n\t\twidth: true\n\t},\n\tresizableRelatedOptions = {\n\t\tmaxHeight: true,\n\t\tmaxWidth: true,\n\t\tminHeight: true,\n\t\tminWidth: true\n\t};\n\n$.widget( \"ui.dialog\", {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\tappendTo: \"body\",\n\t\tautoOpen: true,\n\t\tbuttons: [],\n\t\tcloseOnEscape: true,\n\t\tcloseText: \"close\",\n\t\tdialogClass: \"\",\n\t\tdraggable: true,\n\t\thide: null,\n\t\theight: \"auto\",\n\t\tmaxHeight: null,\n\t\tmaxWidth: null,\n\t\tminHeight: 150,\n\t\tminWidth: 150,\n\t\tmodal: false,\n\t\tposition: {\n\t\t\tmy: \"center\",\n\t\t\tat: \"center\",\n\t\t\tof: window,\n\t\t\tcollision: \"fit\",\n\t\t\t// Ensure the titlebar is always visible\n\t\t\tusing: function( pos ) {\n\t\t\t\tvar topOffset = $( this ).css( pos ).offset().top;\n\t\t\t\tif ( topOffset < 0 ) {\n\t\t\t\t\t$( this ).css( \"top\", pos.top - topOffset );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tresizable: true,\n\t\tshow: null,\n\t\ttitle: null,\n\t\twidth: 300,\n\n\t\t// callbacks\n\t\tbeforeClose: null,\n\t\tclose: null,\n\t\tdrag: null,\n\t\tdragStart: null,\n\t\tdragStop: null,\n\t\tfocus: null,\n\t\topen: null,\n\t\tresize: null,\n\t\tresizeStart: null,\n\t\tresizeStop: null\n\t},\n\n\t_create: function() {\n\t\tthis.originalCss = {\n\t\t\tdisplay: this.element[0].style.display,\n\t\t\twidth: this.element[0].style.width,\n\t\t\tminHeight: this.element[0].style.minHeight,\n\t\t\tmaxHeight: this.element[0].style.maxHeight,\n\t\t\theight: this.element[0].style.height\n\t\t};\n\t\tthis.originalPosition = {\n\t\t\tparent: this.element.parent(),\n\t\t\tindex: this.element.parent().children().index( this.element )\n\t\t};\n\t\tthis.originalTitle = this.element.attr(\"title\");\n\t\tthis.options.title = this.options.title || this.originalTitle;\n\n\t\tthis._createWrapper();\n\n\t\tthis.element\n\t\t\t.show()\n\t\t\t.removeAttr(\"title\")\n\t\t\t.addClass(\"ui-dialog-content ui-widget-content\")\n\t\t\t.appendTo( this.uiDialog );\n\n\t\tthis._createTitlebar();\n\t\tthis._createButtonPane();\n\n\t\tif ( this.options.draggable && $.fn.draggable ) {\n\t\t\tthis._makeDraggable();\n\t\t}\n\t\tif ( this.options.resizable && $.fn.resizable ) {\n\t\t\tthis._makeResizable();\n\t\t}\n\n\t\tthis._isOpen = false;\n\t},\n\n\t_init: function() {\n\t\tif ( this.options.autoOpen ) {\n\t\t\tthis.open();\n\t\t}\n\t},\n\n\t_appendTo: function() {\n\t\tvar element = this.options.appendTo;\n\t\tif ( element && (element.jquery || element.nodeType) ) {\n\t\t\treturn $( element );\n\t\t}\n\t\treturn this.document.find( element || \"body\" ).eq( 0 );\n\t},\n\n\t_destroy: function() {\n\t\tvar next,\n\t\t\toriginalPosition = this.originalPosition;\n\n\t\tthis._destroyOverlay();\n\n\t\tthis.element\n\t\t\t.removeUniqueId()\n\t\t\t.removeClass(\"ui-dialog-content ui-widget-content\")\n\t\t\t.css( this.originalCss )\n\t\t\t// Without detaching first, the following becomes really slow\n\t\t\t.detach();\n\n\t\tthis.uiDialog.stop( true, true ).remove();\n\n\t\tif ( this.originalTitle ) {\n\t\t\tthis.element.attr( \"title\", this.originalTitle );\n\t\t}\n\n\t\tnext = originalPosition.parent.children().eq( originalPosition.index );\n\t\t// Don't try to place the dialog next to itself (#8613)\n\t\tif ( next.length && next[0] !== this.element[0] ) {\n\t\t\tnext.before( this.element );\n\t\t} else {\n\t\t\toriginalPosition.parent.append( this.element );\n\t\t}\n\t},\n\n\twidget: function() {\n\t\treturn this.uiDialog;\n\t},\n\n\tdisable: $.noop,\n\tenable: $.noop,\n\n\tclose: function( event ) {\n\t\tvar that = this;\n\n\t\tif ( !this._isOpen || this._trigger( \"beforeClose\", event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._isOpen = false;\n\t\tthis._destroyOverlay();\n\n\t\tif ( !this.opener.filter(\":focusable\").focus().length ) {\n\t\t\t// Hiding a focused element doesn't trigger blur in WebKit\n\t\t\t// so in case we have nothing to focus on, explicitly blur the active element\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=47182\n\t\t\t$( this.document[0].activeElement ).blur();\n\t\t}\n\n\t\tthis._hide( this.uiDialog, this.options.hide, function() {\n\t\t\tthat._trigger( \"close\", event );\n\t\t});\n\t},\n\n\tisOpen: function() {\n\t\treturn this._isOpen;\n\t},\n\n\tmoveToTop: function() {\n\t\tthis._moveToTop();\n\t},\n\n\t_moveToTop: function( event, silent ) {\n\t\tvar moved = !!this.uiDialog.nextAll(\":visible\").insertBefore( this.uiDialog ).length;\n\t\tif ( moved && !silent ) {\n\t\t\tthis._trigger( \"focus\", event );\n\t\t}\n\t\treturn moved;\n\t},\n\n\topen: function() {\n\t\tvar that = this;\n\t\tif ( this._isOpen ) {\n\t\t\tif ( this._moveToTop() ) {\n\t\t\t\tthis._focusTabbable();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis._isOpen = true;\n\t\tthis.opener = $( this.document[0].activeElement );\n\n\t\tthis._size();\n\t\tthis._position();\n\t\tthis._createOverlay();\n\t\tthis._moveToTop( null, true );\n\t\tthis._show( this.uiDialog, this.options.show, function() {\n\t\t\tthat._focusTabbable();\n\t\t\tthat._trigger(\"focus\");\n\t\t});\n\n\t\tthis._trigger(\"open\");\n\t},\n\n\t_focusTabbable: function() {\n\t\t// Set focus to the first match:\n\t\t// 1. First element inside the dialog matching [autofocus]\n\t\t// 2. Tabbable element inside the content element\n\t\t// 3. Tabbable element inside the buttonpane\n\t\t// 4. The close button\n\t\t// 5. The dialog itself\n\t\tvar hasFocus = this.element.find(\"[autofocus]\");\n\t\tif ( !hasFocus.length ) {\n\t\t\thasFocus = this.element.find(\":tabbable\");\n\t\t}\n\t\tif ( !hasFocus.length ) {\n\t\t\thasFocus = this.uiDialogButtonPane.find(\":tabbable\");\n\t\t}\n\t\tif ( !hasFocus.length ) {\n\t\t\thasFocus = this.uiDialogTitlebarClose.filter(\":tabbable\");\n\t\t}\n\t\tif ( !hasFocus.length ) {\n\t\t\thasFocus = this.uiDialog;\n\t\t}\n\t\thasFocus.eq( 0 ).focus();\n\t},\n\n\t_keepFocus: function( event ) {\n\t\tfunction checkFocus() {\n\t\t\tvar activeElement = this.document[0].activeElement,\n\t\t\t\tisActive = this.uiDialog[0] === activeElement ||\n\t\t\t\t\t$.contains( this.uiDialog[0], activeElement );\n\t\t\tif ( !isActive ) {\n\t\t\t\tthis._focusTabbable();\n\t\t\t}\n\t\t}\n\t\tevent.preventDefault();\n\t\tcheckFocus.call( this );\n\t\t// support: IE\n\t\t// IE <= 8 doesn't prevent moving focus even with event.preventDefault()\n\t\t// so we check again later\n\t\tthis._delay( checkFocus );\n\t},\n\n\t_createWrapper: function() {\n\t\tthis.uiDialog = $(\"<div>\")\n\t\t\t.addClass( \"ui-dialog ui-widget ui-widget-content ui-corner-all ui-front \" +\n\t\t\t\tthis.options.dialogClass )\n\t\t\t.hide()\n\t\t\t.attr({\n\t\t\t\t// Setting tabIndex makes the div focusable\n\t\t\t\ttabIndex: -1,\n\t\t\t\trole: \"dialog\"\n\t\t\t})\n\t\t\t.appendTo( this._appendTo() );\n\n\t\tthis._on( this.uiDialog, {\n\t\t\tkeydown: function( event ) {\n\t\t\t\tif ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&\n\t\t\t\t\t\tevent.keyCode === $.ui.keyCode.ESCAPE ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tthis.close( event );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// prevent tabbing out of dialogs\n\t\t\t\tif ( event.keyCode !== $.ui.keyCode.TAB ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvar tabbables = this.uiDialog.find(\":tabbable\"),\n\t\t\t\t\tfirst = tabbables.filter(\":first\"),\n\t\t\t\t\tlast  = tabbables.filter(\":last\");\n\n\t\t\t\tif ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {\n\t\t\t\t\tfirst.focus( 1 );\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t} else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {\n\t\t\t\t\tlast.focus( 1 );\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t},\n\t\t\tmousedown: function( event ) {\n\t\t\t\tif ( this._moveToTop( event ) ) {\n\t\t\t\t\tthis._focusTabbable();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// We assume that any existing aria-describedby attribute means\n\t\t// that the dialog content is marked up properly\n\t\t// otherwise we brute force the content as the description\n\t\tif ( !this.element.find(\"[aria-describedby]\").length ) {\n\t\t\tthis.uiDialog.attr({\n\t\t\t\t\"aria-describedby\": this.element.uniqueId().attr(\"id\")\n\t\t\t});\n\t\t}\n\t},\n\n\t_createTitlebar: function() {\n\t\tvar uiDialogTitle;\n\n\t\tthis.uiDialogTitlebar = $(\"<div>\")\n\t\t\t.addClass(\"ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix\")\n\t\t\t.prependTo( this.uiDialog );\n\t\tthis._on( this.uiDialogTitlebar, {\n\t\t\tmousedown: function( event ) {\n\t\t\t\t// Don't prevent click on close button (#8838)\n\t\t\t\t// Focusing a dialog that is partially scrolled out of view\n\t\t\t\t// causes the browser to scroll it into view, preventing the click event\n\t\t\t\tif ( !$( event.target ).closest(\".ui-dialog-titlebar-close\") ) {\n\t\t\t\t\t// Dialog isn't getting focus when dragging (#8063)\n\t\t\t\t\tthis.uiDialog.focus();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.uiDialogTitlebarClose = $(\"<button></button>\")\n\t\t\t.button({\n\t\t\t\tlabel: this.options.closeText,\n\t\t\t\ticons: {\n\t\t\t\t\tprimary: \"ui-icon-closethick\"\n\t\t\t\t},\n\t\t\t\ttext: false\n\t\t\t})\n\t\t\t.addClass(\"ui-dialog-titlebar-close\")\n\t\t\t.appendTo( this.uiDialogTitlebar );\n\t\tthis._on( this.uiDialogTitlebarClose, {\n\t\t\tclick: function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.close( event );\n\t\t\t}\n\t\t});\n\n\t\tuiDialogTitle = $(\"<span>\")\n\t\t\t.uniqueId()\n\t\t\t.addClass(\"ui-dialog-title\")\n\t\t\t.prependTo( this.uiDialogTitlebar );\n\t\tthis._title( uiDialogTitle );\n\n\t\tthis.uiDialog.attr({\n\t\t\t\"aria-labelledby\": uiDialogTitle.attr(\"id\")\n\t\t});\n\t},\n\n\t_title: function( title ) {\n\t\tif ( !this.options.title ) {\n\t\t\ttitle.html(\"&#160;\");\n\t\t}\n\t\ttitle.text( this.options.title );\n\t},\n\n\t_createButtonPane: function() {\n\t\tthis.uiDialogButtonPane = $(\"<div>\")\n\t\t\t.addClass(\"ui-dialog-buttonpane ui-widget-content ui-helper-clearfix\");\n\n\t\tthis.uiButtonSet = $(\"<div>\")\n\t\t\t.addClass(\"ui-dialog-buttonset\")\n\t\t\t.appendTo( this.uiDialogButtonPane );\n\n\t\tthis._createButtons();\n\t},\n\n\t_createButtons: function() {\n\t\tvar that = this,\n\t\t\tbuttons = this.options.buttons;\n\n\t\t// if we already have a button pane, remove it\n\t\tthis.uiDialogButtonPane.remove();\n\t\tthis.uiButtonSet.empty();\n\n\t\tif ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {\n\t\t\tthis.uiDialog.removeClass(\"ui-dialog-buttons\");\n\t\t\treturn;\n\t\t}\n\n\t\t$.each( buttons, function( name, props ) {\n\t\t\tvar click, buttonOptions;\n\t\t\tprops = $.isFunction( props ) ?\n\t\t\t\t{ click: props, text: name } :\n\t\t\t\tprops;\n\t\t\t// Default to a non-submitting button\n\t\t\tprops = $.extend( { type: \"button\" }, props );\n\t\t\t// Change the context for the click callback to be the main element\n\t\t\tclick = props.click;\n\t\t\tprops.click = function() {\n\t\t\t\tclick.apply( that.element[0], arguments );\n\t\t\t};\n\t\t\tbuttonOptions = {\n\t\t\t\ticons: props.icons,\n\t\t\t\ttext: props.showText\n\t\t\t};\n\t\t\tdelete props.icons;\n\t\t\tdelete props.showText;\n\t\t\t$( \"<button></button>\", props )\n\t\t\t\t.button( buttonOptions )\n\t\t\t\t.appendTo( that.uiButtonSet );\n\t\t});\n\t\tthis.uiDialog.addClass(\"ui-dialog-buttons\");\n\t\tthis.uiDialogButtonPane.appendTo( this.uiDialog );\n\t},\n\n\t_makeDraggable: function() {\n\t\tvar that = this,\n\t\t\toptions = this.options;\n\n\t\tfunction filteredUi( ui ) {\n\t\t\treturn {\n\t\t\t\tposition: ui.position,\n\t\t\t\toffset: ui.offset\n\t\t\t};\n\t\t}\n\n\t\tthis.uiDialog.draggable({\n\t\t\tcancel: \".ui-dialog-content, .ui-dialog-titlebar-close\",\n\t\t\thandle: \".ui-dialog-titlebar\",\n\t\t\tcontainment: \"document\",\n\t\t\tstart: function( event, ui ) {\n\t\t\t\t$( this ).addClass(\"ui-dialog-dragging\");\n\t\t\t\tthat._blockFrames();\n\t\t\t\tthat._trigger( \"dragStart\", event, filteredUi( ui ) );\n\t\t\t},\n\t\t\tdrag: function( event, ui ) {\n\t\t\t\tthat._trigger( \"drag\", event, filteredUi( ui ) );\n\t\t\t},\n\t\t\tstop: function( event, ui ) {\n\t\t\t\toptions.position = [\n\t\t\t\t\tui.position.left - that.document.scrollLeft(),\n\t\t\t\t\tui.position.top - that.document.scrollTop()\n\t\t\t\t];\n\t\t\t\t$( this ).removeClass(\"ui-dialog-dragging\");\n\t\t\t\tthat._unblockFrames();\n\t\t\t\tthat._trigger( \"dragStop\", event, filteredUi( ui ) );\n\t\t\t}\n\t\t});\n\t},\n\n\t_makeResizable: function() {\n\t\tvar that = this,\n\t\t\toptions = this.options,\n\t\t\thandles = options.resizable,\n\t\t\t// .ui-resizable has position: relative defined in the stylesheet\n\t\t\t// but dialogs have to use absolute or fixed positioning\n\t\t\tposition = this.uiDialog.css(\"position\"),\n\t\t\tresizeHandles = typeof handles === \"string\" ?\n\t\t\t\thandles\t:\n\t\t\t\t\"n,e,s,w,se,sw,ne,nw\";\n\n\t\tfunction filteredUi( ui ) {\n\t\t\treturn {\n\t\t\t\toriginalPosition: ui.originalPosition,\n\t\t\t\toriginalSize: ui.originalSize,\n\t\t\t\tposition: ui.position,\n\t\t\t\tsize: ui.size\n\t\t\t};\n\t\t}\n\n\t\tthis.uiDialog.resizable({\n\t\t\tcancel: \".ui-dialog-content\",\n\t\t\tcontainment: \"document\",\n\t\t\talsoResize: this.element,\n\t\t\tmaxWidth: options.maxWidth,\n\t\t\tmaxHeight: options.maxHeight,\n\t\t\tminWidth: options.minWidth,\n\t\t\tminHeight: this._minHeight(),\n\t\t\thandles: resizeHandles,\n\t\t\tstart: function( event, ui ) {\n\t\t\t\t$( this ).addClass(\"ui-dialog-resizing\");\n\t\t\t\tthat._blockFrames();\n\t\t\t\tthat._trigger( \"resizeStart\", event, filteredUi( ui ) );\n\t\t\t},\n\t\t\tresize: function( event, ui ) {\n\t\t\t\tthat._trigger( \"resize\", event, filteredUi( ui ) );\n\t\t\t},\n\t\t\tstop: function( event, ui ) {\n\t\t\t\toptions.height = $( this ).height();\n\t\t\t\toptions.width = $( this ).width();\n\t\t\t\t$( this ).removeClass(\"ui-dialog-resizing\");\n\t\t\t\tthat._unblockFrames();\n\t\t\t\tthat._trigger( \"resizeStop\", event, filteredUi( ui ) );\n\t\t\t}\n\t\t})\n\t\t.css( \"position\", position );\n\t},\n\n\t_minHeight: function() {\n\t\tvar options = this.options;\n\n\t\treturn options.height === \"auto\" ?\n\t\t\toptions.minHeight :\n\t\t\tMath.min( options.minHeight, options.height );\n\t},\n\n\t_position: function() {\n\t\t// Need to show the dialog to get the actual offset in the position plugin\n\t\tvar isVisible = this.uiDialog.is(\":visible\");\n\t\tif ( !isVisible ) {\n\t\t\tthis.uiDialog.show();\n\t\t}\n\t\tthis.uiDialog.position( this.options.position );\n\t\tif ( !isVisible ) {\n\t\t\tthis.uiDialog.hide();\n\t\t}\n\t},\n\n\t_setOptions: function( options ) {\n\t\tvar that = this,\n\t\t\tresize = false,\n\t\t\tresizableOptions = {};\n\n\t\t$.each( options, function( key, value ) {\n\t\t\tthat._setOption( key, value );\n\n\t\t\tif ( key in sizeRelatedOptions ) {\n\t\t\t\tresize = true;\n\t\t\t}\n\t\t\tif ( key in resizableRelatedOptions ) {\n\t\t\t\tresizableOptions[ key ] = value;\n\t\t\t}\n\t\t});\n\n\t\tif ( resize ) {\n\t\t\tthis._size();\n\t\t\tthis._position();\n\t\t}\n\t\tif ( this.uiDialog.is(\":data(ui-resizable)\") ) {\n\t\t\tthis.uiDialog.resizable( \"option\", resizableOptions );\n\t\t}\n\t},\n\n\t_setOption: function( key, value ) {\n\t\t/*jshint maxcomplexity:15*/\n\t\tvar isDraggable, isResizable,\n\t\t\tuiDialog = this.uiDialog;\n\n\t\tif ( key === \"dialogClass\" ) {\n\t\t\tuiDialog\n\t\t\t\t.removeClass( this.options.dialogClass )\n\t\t\t\t.addClass( value );\n\t\t}\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._super( key, value );\n\n\t\tif ( key === \"appendTo\" ) {\n\t\t\tthis.uiDialog.appendTo( this._appendTo() );\n\t\t}\n\n\t\tif ( key === \"buttons\" ) {\n\t\t\tthis._createButtons();\n\t\t}\n\n\t\tif ( key === \"closeText\" ) {\n\t\t\tthis.uiDialogTitlebarClose.button({\n\t\t\t\t// Ensure that we always pass a string\n\t\t\t\tlabel: \"\" + value\n\t\t\t});\n\t\t}\n\n\t\tif ( key === \"draggable\" ) {\n\t\t\tisDraggable = uiDialog.is(\":data(ui-draggable)\");\n\t\t\tif ( isDraggable && !value ) {\n\t\t\t\tuiDialog.draggable(\"destroy\");\n\t\t\t}\n\n\t\t\tif ( !isDraggable && value ) {\n\t\t\t\tthis._makeDraggable();\n\t\t\t}\n\t\t}\n\n\t\tif ( key === \"position\" ) {\n\t\t\tthis._position();\n\t\t}\n\n\t\tif ( key === \"resizable\" ) {\n\t\t\t// currently resizable, becoming non-resizable\n\t\t\tisResizable = uiDialog.is(\":data(ui-resizable)\");\n\t\t\tif ( isResizable && !value ) {\n\t\t\t\tuiDialog.resizable(\"destroy\");\n\t\t\t}\n\n\t\t\t// currently resizable, changing handles\n\t\t\tif ( isResizable && typeof value === \"string\" ) {\n\t\t\t\tuiDialog.resizable( \"option\", \"handles\", value );\n\t\t\t}\n\n\t\t\t// currently non-resizable, becoming resizable\n\t\t\tif ( !isResizable && value !== false ) {\n\t\t\t\tthis._makeResizable();\n\t\t\t}\n\t\t}\n\n\t\tif ( key === \"title\" ) {\n\t\t\tthis._title( this.uiDialogTitlebar.find(\".ui-dialog-title\") );\n\t\t}\n\t},\n\n\t_size: function() {\n\t\t// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content\n\t\t// divs will both have width and height set, so we need to reset them\n\t\tvar nonContentHeight, minContentHeight, maxContentHeight,\n\t\t\toptions = this.options;\n\n\t\t// Reset content sizing\n\t\tthis.element.show().css({\n\t\t\twidth: \"auto\",\n\t\t\tminHeight: 0,\n\t\t\tmaxHeight: \"none\",\n\t\t\theight: 0\n\t\t});\n\n\t\tif ( options.minWidth > options.width ) {\n\t\t\toptions.width = options.minWidth;\n\t\t}\n\n\t\t// reset wrapper sizing\n\t\t// determine the height of all the non-content elements\n\t\tnonContentHeight = this.uiDialog.css({\n\t\t\t\theight: \"auto\",\n\t\t\t\twidth: options.width\n\t\t\t})\n\t\t\t.outerHeight();\n\t\tminContentHeight = Math.max( 0, options.minHeight - nonContentHeight );\n\t\tmaxContentHeight = typeof options.maxHeight === \"number\" ?\n\t\t\tMath.max( 0, options.maxHeight - nonContentHeight ) :\n\t\t\t\"none\";\n\n\t\tif ( options.height === \"auto\" ) {\n\t\t\tthis.element.css({\n\t\t\t\tminHeight: minContentHeight,\n\t\t\t\tmaxHeight: maxContentHeight,\n\t\t\t\theight: \"auto\"\n\t\t\t});\n\t\t} else {\n\t\t\tthis.element.height( Math.max( 0, options.height - nonContentHeight ) );\n\t\t}\n\n\t\tif (this.uiDialog.is(\":data(ui-resizable)\") ) {\n\t\t\tthis.uiDialog.resizable( \"option\", \"minHeight\", this._minHeight() );\n\t\t}\n\t},\n\n\t_blockFrames: function() {\n\t\tthis.iframeBlocks = this.document.find( \"iframe\" ).map(function() {\n\t\t\tvar iframe = $( this );\n\n\t\t\treturn $( \"<div>\" )\n\t\t\t\t.css({\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\twidth: iframe.outerWidth(),\n\t\t\t\t\theight: iframe.outerHeight()\n\t\t\t\t})\n\t\t\t\t.appendTo( iframe.parent() )\n\t\t\t\t.offset( iframe.offset() )[0];\n\t\t});\n\t},\n\n\t_unblockFrames: function() {\n\t\tif ( this.iframeBlocks ) {\n\t\t\tthis.iframeBlocks.remove();\n\t\t\tdelete this.iframeBlocks;\n\t\t}\n\t},\n\n\t_createOverlay: function() {\n\t\tif ( !this.options.modal ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !$.ui.dialog.overlayInstances ) {\n\t\t\t// Prevent use of anchors and inputs.\n\t\t\t// We use a delay in case the overlay is created from an\n\t\t\t// event that we're going to be cancelling. (#2804)\n\t\t\tthis._delay(function() {\n\t\t\t\t// Handle .dialog().dialog(\"close\") (#4065)\n\t\t\t\tif ( $.ui.dialog.overlayInstances ) {\n\t\t\t\t\tthis.document.bind( \"focusin.dialog\", function( event ) {\n\t\t\t\t\t\tif ( !$( event.target ).closest(\".ui-dialog\").length &&\n\t\t\t\t\t\t\t\t// TODO: Remove hack when datepicker implements\n\t\t\t\t\t\t\t\t// the .ui-front logic (#8989)\n\t\t\t\t\t\t\t\t!$( event.target ).closest(\".ui-datepicker\").length ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t$(\".ui-dialog:visible:last .ui-dialog-content\")\n\t\t\t\t\t\t\t\t.data(\"ui-dialog\")._focusTabbable();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tthis.overlay = $(\"<div>\")\n\t\t\t.addClass(\"ui-widget-overlay ui-front\")\n\t\t\t.appendTo( this._appendTo() );\n\t\tthis._on( this.overlay, {\n\t\t\tmousedown: \"_keepFocus\"\n\t\t});\n\t\t$.ui.dialog.overlayInstances++;\n\t},\n\n\t_destroyOverlay: function() {\n\t\tif ( !this.options.modal ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.overlay ) {\n\t\t\t$.ui.dialog.overlayInstances--;\n\n\t\t\tif ( !$.ui.dialog.overlayInstances ) {\n\t\t\t\tthis.document.unbind( \"focusin.dialog\" );\n\t\t\t}\n\t\t\tthis.overlay.remove();\n\t\t\tthis.overlay = null;\n\t\t}\n\t}\n});\n\n$.ui.dialog.overlayInstances = 0;\n\n// DEPRECATED\nif ( $.uiBackCompat !== false ) {\n\t// position option with array notation\n\t// just override with old implementation\n\t$.widget( \"ui.dialog\", $.ui.dialog, {\n\t\t_position: function() {\n\t\t\tvar position = this.options.position,\n\t\t\t\tmyAt = [],\n\t\t\t\toffset = [ 0, 0 ],\n\t\t\t\tisVisible;\n\n\t\t\tif ( position ) {\n\t\t\t\tif ( typeof position === \"string\" || (typeof position === \"object\" && \"0\" in position ) ) {\n\t\t\t\t\tmyAt = position.split ? position.split(\" \") : [ position[0], position[1] ];\n\t\t\t\t\tif ( myAt.length === 1 ) {\n\t\t\t\t\t\tmyAt[1] = myAt[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t$.each( [ \"left\", \"top\" ], function( i, offsetPosition ) {\n\t\t\t\t\t\tif ( +myAt[ i ] === myAt[ i ] ) {\n\t\t\t\t\t\t\toffset[ i ] = myAt[ i ];\n\t\t\t\t\t\t\tmyAt[ i ] = offsetPosition;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tposition = {\n\t\t\t\t\t\tmy: myAt[0] + (offset[0] < 0 ? offset[0] : \"+\" + offset[0]) + \" \" +\n\t\t\t\t\t\t\tmyAt[1] + (offset[1] < 0 ? offset[1] : \"+\" + offset[1]),\n\t\t\t\t\t\tat: myAt.join(\" \")\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tposition = $.extend( {}, $.ui.dialog.prototype.options.position, position );\n\t\t\t} else {\n\t\t\t\tposition = $.ui.dialog.prototype.options.position;\n\t\t\t}\n\n\t\t\t// need to show the dialog to get the actual offset in the position plugin\n\t\t\tisVisible = this.uiDialog.is(\":visible\");\n\t\t\tif ( !isVisible ) {\n\t\t\t\tthis.uiDialog.show();\n\t\t\t}\n\t\t\tthis.uiDialog.position( position );\n\t\t\tif ( !isVisible ) {\n\t\t\t\tthis.uiDialog.hide();\n\t\t\t}\n\t\t}\n\t});\n}\n\n}( jQuery ) );\n\n(function( $, undefined ) {\n\nvar rvertical = /up|down|vertical/,\n\trpositivemotion = /up|left|vertical|horizontal/;\n\n$.effects.effect.blind = function( o, done ) {\n\t// Create element\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"height\", \"width\" ],\n\t\tmode = $.effects.setMode( el, o.mode || \"hide\" ),\n\t\tdirection = o.direction || \"up\",\n\t\tvertical = rvertical.test( direction ),\n\t\tref = vertical ? \"height\" : \"width\",\n\t\tref2 = vertical ? \"top\" : \"left\",\n\t\tmotion = rpositivemotion.test( direction ),\n\t\tanimation = {},\n\t\tshow = mode === \"show\",\n\t\twrapper, distance, margin;\n\n\t// if already wrapped, the wrapper's properties are my property. #6245\n\tif ( el.parent().is( \".ui-effects-wrapper\" ) ) {\n\t\t$.effects.save( el.parent(), props );\n\t} else {\n\t\t$.effects.save( el, props );\n\t}\n\tel.show();\n\twrapper = $.effects.createWrapper( el ).css({\n\t\toverflow: \"hidden\"\n\t});\n\n\tdistance = wrapper[ ref ]();\n\tmargin = parseFloat( wrapper.css( ref2 ) ) || 0;\n\n\tanimation[ ref ] = show ? distance : 0;\n\tif ( !motion ) {\n\t\tel\n\t\t\t.css( vertical ? \"bottom\" : \"right\", 0 )\n\t\t\t.css( vertical ? \"top\" : \"left\", \"auto\" )\n\t\t\t.css({ position: \"absolute\" });\n\n\t\tanimation[ ref2 ] = show ? margin : distance + margin;\n\t}\n\n\t// start at 0 if we are showing\n\tif ( show ) {\n\t\twrapper.css( ref, 0 );\n\t\tif ( ! motion ) {\n\t\t\twrapper.css( ref2, margin + distance );\n\t\t}\n\t}\n\n\t// Animate\n\twrapper.animate( animation, {\n\t\tduration: o.duration,\n\t\teasing: o.easing,\n\t\tqueue: false,\n\t\tcomplete: function() {\n\t\t\tif ( mode === \"hide\" ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t}\n\t});\n\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.bounce = function( o, done ) {\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"height\", \"width\" ],\n\n\t\t// defaults:\n\t\tmode = $.effects.setMode( el, o.mode || \"effect\" ),\n\t\thide = mode === \"hide\",\n\t\tshow = mode === \"show\",\n\t\tdirection = o.direction || \"up\",\n\t\tdistance = o.distance,\n\t\ttimes = o.times || 5,\n\n\t\t// number of internal animations\n\t\tanims = times * 2 + ( show || hide ? 1 : 0 ),\n\t\tspeed = o.duration / anims,\n\t\teasing = o.easing,\n\n\t\t// utility:\n\t\tref = ( direction === \"up\" || direction === \"down\" ) ? \"top\" : \"left\",\n\t\tmotion = ( direction === \"up\" || direction === \"left\" ),\n\t\ti,\n\t\tupAnim,\n\t\tdownAnim,\n\n\t\t// we will need to re-assemble the queue to stack our animations in place\n\t\tqueue = el.queue(),\n\t\tqueuelen = queue.length;\n\n\t// Avoid touching opacity to prevent clearType and PNG issues in IE\n\tif ( show || hide ) {\n\t\tprops.push( \"opacity\" );\n\t}\n\n\t$.effects.save( el, props );\n\tel.show();\n\t$.effects.createWrapper( el ); // Create Wrapper\n\n\t// default distance for the BIGGEST bounce is the outer Distance / 3\n\tif ( !distance ) {\n\t\tdistance = el[ ref === \"top\" ? \"outerHeight\" : \"outerWidth\" ]() / 3;\n\t}\n\n\tif ( show ) {\n\t\tdownAnim = { opacity: 1 };\n\t\tdownAnim[ ref ] = 0;\n\n\t\t// if we are showing, force opacity 0 and set the initial position\n\t\t// then do the \"first\" animation\n\t\tel.css( \"opacity\", 0 )\n\t\t\t.css( ref, motion ? -distance * 2 : distance * 2 )\n\t\t\t.animate( downAnim, speed, easing );\n\t}\n\n\t// start at the smallest distance if we are hiding\n\tif ( hide ) {\n\t\tdistance = distance / Math.pow( 2, times - 1 );\n\t}\n\n\tdownAnim = {};\n\tdownAnim[ ref ] = 0;\n\t// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here\n\tfor ( i = 0; i < times; i++ ) {\n\t\tupAnim = {};\n\t\tupAnim[ ref ] = ( motion ? \"-=\" : \"+=\" ) + distance;\n\n\t\tel.animate( upAnim, speed, easing )\n\t\t\t.animate( downAnim, speed, easing );\n\n\t\tdistance = hide ? distance * 2 : distance / 2;\n\t}\n\n\t// Last Bounce when Hiding\n\tif ( hide ) {\n\t\tupAnim = { opacity: 0 };\n\t\tupAnim[ ref ] = ( motion ? \"-=\" : \"+=\" ) + distance;\n\n\t\tel.animate( upAnim, speed, easing );\n\t}\n\n\tel.queue(function() {\n\t\tif ( hide ) {\n\t\t\tel.hide();\n\t\t}\n\t\t$.effects.restore( el, props );\n\t\t$.effects.removeWrapper( el );\n\t\tdone();\n\t});\n\n\t// inject all the animations we just queued to be first in line (after \"inprogress\")\n\tif ( queuelen > 1) {\n\t\tqueue.splice.apply( queue,\n\t\t\t[ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );\n\t}\n\tel.dequeue();\n\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.clip = function( o, done ) {\n\t// Create element\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"height\", \"width\" ],\n\t\tmode = $.effects.setMode( el, o.mode || \"hide\" ),\n\t\tshow = mode === \"show\",\n\t\tdirection = o.direction || \"vertical\",\n\t\tvert = direction === \"vertical\",\n\t\tsize = vert ? \"height\" : \"width\",\n\t\tposition = vert ? \"top\" : \"left\",\n\t\tanimation = {},\n\t\twrapper, animate, distance;\n\n\t// Save & Show\n\t$.effects.save( el, props );\n\tel.show();\n\n\t// Create Wrapper\n\twrapper = $.effects.createWrapper( el ).css({\n\t\toverflow: \"hidden\"\n\t});\n\tanimate = ( el[0].tagName === \"IMG\" ) ? wrapper : el;\n\tdistance = animate[ size ]();\n\n\t// Shift\n\tif ( show ) {\n\t\tanimate.css( size, 0 );\n\t\tanimate.css( position, distance / 2 );\n\t}\n\n\t// Create Animation Object:\n\tanimation[ size ] = show ? distance : 0;\n\tanimation[ position ] = show ? 0 : distance / 2;\n\n\t// Animate\n\tanimate.animate( animation, {\n\t\tqueue: false,\n\t\tduration: o.duration,\n\t\teasing: o.easing,\n\t\tcomplete: function() {\n\t\t\tif ( !show ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t}\n\t});\n\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.drop = function( o, done ) {\n\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"opacity\", \"height\", \"width\" ],\n\t\tmode = $.effects.setMode( el, o.mode || \"hide\" ),\n\t\tshow = mode === \"show\",\n\t\tdirection = o.direction || \"left\",\n\t\tref = ( direction === \"up\" || direction === \"down\" ) ? \"top\" : \"left\",\n\t\tmotion = ( direction === \"up\" || direction === \"left\" ) ? \"pos\" : \"neg\",\n\t\tanimation = {\n\t\t\topacity: show ? 1 : 0\n\t\t},\n\t\tdistance;\n\n\t// Adjust\n\t$.effects.save( el, props );\n\tel.show();\n\t$.effects.createWrapper( el );\n\n\tdistance = o.distance || el[ ref === \"top\" ? \"outerHeight\": \"outerWidth\" ]( true ) / 2;\n\n\tif ( show ) {\n\t\tel\n\t\t\t.css( \"opacity\", 0 )\n\t\t\t.css( ref, motion === \"pos\" ? -distance : distance );\n\t}\n\n\t// Animation\n\tanimation[ ref ] = ( show ?\n\t\t( motion === \"pos\" ? \"+=\" : \"-=\" ) :\n\t\t( motion === \"pos\" ? \"-=\" : \"+=\" ) ) +\n\t\tdistance;\n\n\t// Animate\n\tel.animate( animation, {\n\t\tqueue: false,\n\t\tduration: o.duration,\n\t\teasing: o.easing,\n\t\tcomplete: function() {\n\t\t\tif ( mode === \"hide\" ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t}\n\t});\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.explode = function( o, done ) {\n\n\tvar rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,\n\t\tcells = rows,\n\t\tel = $( this ),\n\t\tmode = $.effects.setMode( el, o.mode || \"hide\" ),\n\t\tshow = mode === \"show\",\n\n\t\t// show and then visibility:hidden the element before calculating offset\n\t\toffset = el.show().css( \"visibility\", \"hidden\" ).offset(),\n\n\t\t// width and height of a piece\n\t\twidth = Math.ceil( el.outerWidth() / cells ),\n\t\theight = Math.ceil( el.outerHeight() / rows ),\n\t\tpieces = [],\n\n\t\t// loop\n\t\ti, j, left, top, mx, my;\n\n\t// children animate complete:\n\tfunction childComplete() {\n\t\tpieces.push( this );\n\t\tif ( pieces.length === rows * cells ) {\n\t\t\tanimComplete();\n\t\t}\n\t}\n\n\t// clone the element for each row and cell.\n\tfor( i = 0; i < rows ; i++ ) { // ===>\n\t\ttop = offset.top + i * height;\n\t\tmy = i - ( rows - 1 ) / 2 ;\n\n\t\tfor( j = 0; j < cells ; j++ ) { // |||\n\t\t\tleft = offset.left + j * width;\n\t\t\tmx = j - ( cells - 1 ) / 2 ;\n\n\t\t\t// Create a clone of the now hidden main element that will be absolute positioned\n\t\t\t// within a wrapper div off the -left and -top equal to size of our pieces\n\t\t\tel\n\t\t\t\t.clone()\n\t\t\t\t.appendTo( \"body\" )\n\t\t\t\t.wrap( \"<div></div>\" )\n\t\t\t\t.css({\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tvisibility: \"visible\",\n\t\t\t\t\tleft: -j * width,\n\t\t\t\t\ttop: -i * height\n\t\t\t\t})\n\n\t\t\t// select the wrapper - make it overflow: hidden and absolute positioned based on\n\t\t\t// where the original was located +left and +top equal to the size of pieces\n\t\t\t\t.parent()\n\t\t\t\t.addClass( \"ui-effects-explode\" )\n\t\t\t\t.css({\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\twidth: width,\n\t\t\t\t\theight: height,\n\t\t\t\t\tleft: left + ( show ? mx * width : 0 ),\n\t\t\t\t\ttop: top + ( show ? my * height : 0 ),\n\t\t\t\t\topacity: show ? 0 : 1\n\t\t\t\t}).animate({\n\t\t\t\t\tleft: left + ( show ? 0 : mx * width ),\n\t\t\t\t\ttop: top + ( show ? 0 : my * height ),\n\t\t\t\t\topacity: show ? 1 : 0\n\t\t\t\t}, o.duration || 500, o.easing, childComplete );\n\t\t}\n\t}\n\n\tfunction animComplete() {\n\t\tel.css({\n\t\t\tvisibility: \"visible\"\n\t\t});\n\t\t$( pieces ).remove();\n\t\tif ( !show ) {\n\t\t\tel.hide();\n\t\t}\n\t\tdone();\n\t}\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.fade = function( o, done ) {\n\tvar el = $( this ),\n\t\tmode = $.effects.setMode( el, o.mode || \"toggle\" );\n\n\tel.animate({\n\t\topacity: mode\n\t}, {\n\t\tqueue: false,\n\t\tduration: o.duration,\n\t\teasing: o.easing,\n\t\tcomplete: done\n\t});\n};\n\n})( jQuery );\n\n(function( $, undefined ) {\n\n$.effects.effect.fold = function( o, done ) {\n\n\t// Create element\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"height\", \"width\" ],\n\t\tmode = $.effects.setMode( el, o.mode || \"hide\" ),\n\t\tshow = mode === \"show\",\n\t\thide = mode === \"hide\",\n\t\tsize = o.size || 15,\n\t\tpercent = /([0-9]+)%/.exec( size ),\n\t\thorizFirst = !!o.horizFirst,\n\t\twidthFirst = show !== horizFirst,\n\t\tref = widthFirst ? [ \"width\", \"height\" ] : [ \"height\", \"width\" ],\n\t\tduration = o.duration / 2,\n\t\twrapper, distance,\n\t\tanimation1 = {},\n\t\tanimation2 = {};\n\n\t$.effects.save( el, props );\n\tel.show();\n\n\t// Create Wrapper\n\twrapper = $.effects.createWrapper( el ).css({\n\t\toverflow: \"hidden\"\n\t});\n\tdistance = widthFirst ?\n\t\t[ wrapper.width(), wrapper.height() ] :\n\t\t[ wrapper.height(), wrapper.width() ];\n\n\tif ( percent ) {\n\t\tsize = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];\n\t}\n\tif ( show ) {\n\t\twrapper.css( horizFirst ? {\n\t\t\theight: 0,\n\t\t\twidth: size\n\t\t} : {\n\t\t\theight: size,\n\t\t\twidth: 0\n\t\t});\n\t}\n\n\t// Animation\n\tanimation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;\n\tanimation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;\n\n\t// Animate\n\twrapper\n\t\t.animate( animation1, duration, o.easing )\n\t\t.animate( animation2, duration, o.easing, function() {\n\t\t\tif ( hide ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t});\n\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.highlight = function( o, done ) {\n\tvar elem = $( this ),\n\t\tprops = [ \"backgroundImage\", \"backgroundColor\", \"opacity\" ],\n\t\tmode = $.effects.setMode( elem, o.mode || \"show\" ),\n\t\tanimation = {\n\t\t\tbackgroundColor: elem.css( \"backgroundColor\" )\n\t\t};\n\n\tif (mode === \"hide\") {\n\t\tanimation.opacity = 0;\n\t}\n\n\t$.effects.save( elem, props );\n\n\telem\n\t\t.show()\n\t\t.css({\n\t\t\tbackgroundImage: \"none\",\n\t\t\tbackgroundColor: o.color || \"#ffff99\"\n\t\t})\n\t\t.animate( animation, {\n\t\t\tqueue: false,\n\t\t\tduration: o.duration,\n\t\t\teasing: o.easing,\n\t\t\tcomplete: function() {\n\t\t\t\tif ( mode === \"hide\" ) {\n\t\t\t\t\telem.hide();\n\t\t\t\t}\n\t\t\t\t$.effects.restore( elem, props );\n\t\t\t\tdone();\n\t\t\t}\n\t\t});\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.pulsate = function( o, done ) {\n\tvar elem = $( this ),\n\t\tmode = $.effects.setMode( elem, o.mode || \"show\" ),\n\t\tshow = mode === \"show\",\n\t\thide = mode === \"hide\",\n\t\tshowhide = ( show || mode === \"hide\" ),\n\n\t\t// showing or hiding leaves of the \"last\" animation\n\t\tanims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),\n\t\tduration = o.duration / anims,\n\t\tanimateTo = 0,\n\t\tqueue = elem.queue(),\n\t\tqueuelen = queue.length,\n\t\ti;\n\n\tif ( show || !elem.is(\":visible\")) {\n\t\telem.css( \"opacity\", 0 ).show();\n\t\tanimateTo = 1;\n\t}\n\n\t// anims - 1 opacity \"toggles\"\n\tfor ( i = 1; i < anims; i++ ) {\n\t\telem.animate({\n\t\t\topacity: animateTo\n\t\t}, duration, o.easing );\n\t\tanimateTo = 1 - animateTo;\n\t}\n\n\telem.animate({\n\t\topacity: animateTo\n\t}, duration, o.easing);\n\n\telem.queue(function() {\n\t\tif ( hide ) {\n\t\t\telem.hide();\n\t\t}\n\t\tdone();\n\t});\n\n\t// We just queued up \"anims\" animations, we need to put them next in the queue\n\tif ( queuelen > 1 ) {\n\t\tqueue.splice.apply( queue,\n\t\t\t[ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );\n\t}\n\telem.dequeue();\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.puff = function( o, done ) {\n\tvar elem = $( this ),\n\t\tmode = $.effects.setMode( elem, o.mode || \"hide\" ),\n\t\thide = mode === \"hide\",\n\t\tpercent = parseInt( o.percent, 10 ) || 150,\n\t\tfactor = percent / 100,\n\t\toriginal = {\n\t\t\theight: elem.height(),\n\t\t\twidth: elem.width(),\n\t\t\touterHeight: elem.outerHeight(),\n\t\t\touterWidth: elem.outerWidth()\n\t\t};\n\n\t$.extend( o, {\n\t\teffect: \"scale\",\n\t\tqueue: false,\n\t\tfade: true,\n\t\tmode: mode,\n\t\tcomplete: done,\n\t\tpercent: hide ? percent : 100,\n\t\tfrom: hide ?\n\t\t\toriginal :\n\t\t\t{\n\t\t\t\theight: original.height * factor,\n\t\t\t\twidth: original.width * factor,\n\t\t\t\touterHeight: original.outerHeight * factor,\n\t\t\t\touterWidth: original.outerWidth * factor\n\t\t\t}\n\t});\n\n\telem.effect( o );\n};\n\n$.effects.effect.scale = function( o, done ) {\n\n\t// Create element\n\tvar el = $( this ),\n\t\toptions = $.extend( true, {}, o ),\n\t\tmode = $.effects.setMode( el, o.mode || \"effect\" ),\n\t\tpercent = parseInt( o.percent, 10 ) ||\n\t\t\t( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === \"hide\" ? 0 : 100 ) ),\n\t\tdirection = o.direction || \"both\",\n\t\torigin = o.origin,\n\t\toriginal = {\n\t\t\theight: el.height(),\n\t\t\twidth: el.width(),\n\t\t\touterHeight: el.outerHeight(),\n\t\t\touterWidth: el.outerWidth()\n\t\t},\n\t\tfactor = {\n\t\t\ty: direction !== \"horizontal\" ? (percent / 100) : 1,\n\t\t\tx: direction !== \"vertical\" ? (percent / 100) : 1\n\t\t};\n\n\t// We are going to pass this effect to the size effect:\n\toptions.effect = \"size\";\n\toptions.queue = false;\n\toptions.complete = done;\n\n\t// Set default origin and restore for show/hide\n\tif ( mode !== \"effect\" ) {\n\t\toptions.origin = origin || [\"middle\",\"center\"];\n\t\toptions.restore = true;\n\t}\n\n\toptions.from = o.from || ( mode === \"show\" ? {\n\t\theight: 0,\n\t\twidth: 0,\n\t\touterHeight: 0,\n\t\touterWidth: 0\n\t} : original );\n\toptions.to = {\n\t\theight: original.height * factor.y,\n\t\twidth: original.width * factor.x,\n\t\touterHeight: original.outerHeight * factor.y,\n\t\touterWidth: original.outerWidth * factor.x\n\t};\n\n\t// Fade option to support puff\n\tif ( options.fade ) {\n\t\tif ( mode === \"show\" ) {\n\t\t\toptions.from.opacity = 0;\n\t\t\toptions.to.opacity = 1;\n\t\t}\n\t\tif ( mode === \"hide\" ) {\n\t\t\toptions.from.opacity = 1;\n\t\t\toptions.to.opacity = 0;\n\t\t}\n\t}\n\n\t// Animate\n\tel.effect( options );\n\n};\n\n$.effects.effect.size = function( o, done ) {\n\n\t// Create element\n\tvar original, baseline, factor,\n\t\tel = $( this ),\n\t\tprops0 = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"width\", \"height\", \"overflow\", \"opacity\" ],\n\n\t\t// Always restore\n\t\tprops1 = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"overflow\", \"opacity\" ],\n\n\t\t// Copy for children\n\t\tprops2 = [ \"width\", \"height\", \"overflow\" ],\n\t\tcProps = [ \"fontSize\" ],\n\t\tvProps = [ \"borderTopWidth\", \"borderBottomWidth\", \"paddingTop\", \"paddingBottom\" ],\n\t\thProps = [ \"borderLeftWidth\", \"borderRightWidth\", \"paddingLeft\", \"paddingRight\" ],\n\n\t\t// Set options\n\t\tmode = $.effects.setMode( el, o.mode || \"effect\" ),\n\t\trestore = o.restore || mode !== \"effect\",\n\t\tscale = o.scale || \"both\",\n\t\torigin = o.origin || [ \"middle\", \"center\" ],\n\t\tposition = el.css( \"position\" ),\n\t\tprops = restore ? props0 : props1,\n\t\tzero = {\n\t\t\theight: 0,\n\t\t\twidth: 0,\n\t\t\touterHeight: 0,\n\t\t\touterWidth: 0\n\t\t};\n\n\tif ( mode === \"show\" ) {\n\t\tel.show();\n\t}\n\toriginal = {\n\t\theight: el.height(),\n\t\twidth: el.width(),\n\t\touterHeight: el.outerHeight(),\n\t\touterWidth: el.outerWidth()\n\t};\n\n\tif ( o.mode === \"toggle\" && mode === \"show\" ) {\n\t\tel.from = o.to || zero;\n\t\tel.to = o.from || original;\n\t} else {\n\t\tel.from = o.from || ( mode === \"show\" ? zero : original );\n\t\tel.to = o.to || ( mode === \"hide\" ? zero : original );\n\t}\n\n\t// Set scaling factor\n\tfactor = {\n\t\tfrom: {\n\t\t\ty: el.from.height / original.height,\n\t\t\tx: el.from.width / original.width\n\t\t},\n\t\tto: {\n\t\t\ty: el.to.height / original.height,\n\t\t\tx: el.to.width / original.width\n\t\t}\n\t};\n\n\t// Scale the css box\n\tif ( scale === \"box\" || scale === \"both\" ) {\n\n\t\t// Vertical props scaling\n\t\tif ( factor.from.y !== factor.to.y ) {\n\t\t\tprops = props.concat( vProps );\n\t\t\tel.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );\n\t\t\tel.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );\n\t\t}\n\n\t\t// Horizontal props scaling\n\t\tif ( factor.from.x !== factor.to.x ) {\n\t\t\tprops = props.concat( hProps );\n\t\t\tel.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );\n\t\t\tel.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );\n\t\t}\n\t}\n\n\t// Scale the content\n\tif ( scale === \"content\" || scale === \"both\" ) {\n\n\t\t// Vertical props scaling\n\t\tif ( factor.from.y !== factor.to.y ) {\n\t\t\tprops = props.concat( cProps ).concat( props2 );\n\t\t\tel.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );\n\t\t\tel.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );\n\t\t}\n\t}\n\n\t$.effects.save( el, props );\n\tel.show();\n\t$.effects.createWrapper( el );\n\tel.css( \"overflow\", \"hidden\" ).css( el.from );\n\n\t// Adjust\n\tif (origin) { // Calculate baseline shifts\n\t\tbaseline = $.effects.getBaseline( origin, original );\n\t\tel.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;\n\t\tel.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;\n\t\tel.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;\n\t\tel.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;\n\t}\n\tel.css( el.from ); // set top & left\n\n\t// Animate\n\tif ( scale === \"content\" || scale === \"both\" ) { // Scale the children\n\n\t\t// Add margins/font-size\n\t\tvProps = vProps.concat([ \"marginTop\", \"marginBottom\" ]).concat(cProps);\n\t\thProps = hProps.concat([ \"marginLeft\", \"marginRight\" ]);\n\t\tprops2 = props0.concat(vProps).concat(hProps);\n\n\t\tel.find( \"*[width]\" ).each( function(){\n\t\t\tvar child = $( this ),\n\t\t\t\tc_original = {\n\t\t\t\t\theight: child.height(),\n\t\t\t\t\twidth: child.width(),\n\t\t\t\t\touterHeight: child.outerHeight(),\n\t\t\t\t\touterWidth: child.outerWidth()\n\t\t\t\t};\n\t\t\tif (restore) {\n\t\t\t\t$.effects.save(child, props2);\n\t\t\t}\n\n\t\t\tchild.from = {\n\t\t\t\theight: c_original.height * factor.from.y,\n\t\t\t\twidth: c_original.width * factor.from.x,\n\t\t\t\touterHeight: c_original.outerHeight * factor.from.y,\n\t\t\t\touterWidth: c_original.outerWidth * factor.from.x\n\t\t\t};\n\t\t\tchild.to = {\n\t\t\t\theight: c_original.height * factor.to.y,\n\t\t\t\twidth: c_original.width * factor.to.x,\n\t\t\t\touterHeight: c_original.height * factor.to.y,\n\t\t\t\touterWidth: c_original.width * factor.to.x\n\t\t\t};\n\n\t\t\t// Vertical props scaling\n\t\t\tif ( factor.from.y !== factor.to.y ) {\n\t\t\t\tchild.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );\n\t\t\t\tchild.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );\n\t\t\t}\n\n\t\t\t// Horizontal props scaling\n\t\t\tif ( factor.from.x !== factor.to.x ) {\n\t\t\t\tchild.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );\n\t\t\t\tchild.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );\n\t\t\t}\n\n\t\t\t// Animate children\n\t\t\tchild.css( child.from );\n\t\t\tchild.animate( child.to, o.duration, o.easing, function() {\n\n\t\t\t\t// Restore children\n\t\t\t\tif ( restore ) {\n\t\t\t\t\t$.effects.restore( child, props2 );\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// Animate\n\tel.animate( el.to, {\n\t\tqueue: false,\n\t\tduration: o.duration,\n\t\teasing: o.easing,\n\t\tcomplete: function() {\n\t\t\tif ( el.to.opacity === 0 ) {\n\t\t\t\tel.css( \"opacity\", el.from.opacity );\n\t\t\t}\n\t\t\tif( mode === \"hide\" ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\tif ( !restore ) {\n\n\t\t\t\t// we need to calculate our new positioning based on the scaling\n\t\t\t\tif ( position === \"static\" ) {\n\t\t\t\t\tel.css({\n\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t\ttop: el.to.top,\n\t\t\t\t\t\tleft: el.to.left\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t$.each([ \"top\", \"left\" ], function( idx, pos ) {\n\t\t\t\t\t\tel.css( pos, function( _, str ) {\n\t\t\t\t\t\t\tvar val = parseInt( str, 10 ),\n\t\t\t\t\t\t\t\ttoRef = idx ? el.to.left : el.to.top;\n\n\t\t\t\t\t\t\t// if original was \"auto\", recalculate the new value from wrapper\n\t\t\t\t\t\t\tif ( str === \"auto\" ) {\n\t\t\t\t\t\t\t\treturn toRef + \"px\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn val + toRef + \"px\";\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t}\n\t});\n\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.shake = function( o, done ) {\n\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"height\", \"width\" ],\n\t\tmode = $.effects.setMode( el, o.mode || \"effect\" ),\n\t\tdirection = o.direction || \"left\",\n\t\tdistance = o.distance || 20,\n\t\ttimes = o.times || 3,\n\t\tanims = times * 2 + 1,\n\t\tspeed = Math.round(o.duration/anims),\n\t\tref = (direction === \"up\" || direction === \"down\") ? \"top\" : \"left\",\n\t\tpositiveMotion = (direction === \"up\" || direction === \"left\"),\n\t\tanimation = {},\n\t\tanimation1 = {},\n\t\tanimation2 = {},\n\t\ti,\n\n\t\t// we will need to re-assemble the queue to stack our animations in place\n\t\tqueue = el.queue(),\n\t\tqueuelen = queue.length;\n\n\t$.effects.save( el, props );\n\tel.show();\n\t$.effects.createWrapper( el );\n\n\t// Animation\n\tanimation[ ref ] = ( positiveMotion ? \"-=\" : \"+=\" ) + distance;\n\tanimation1[ ref ] = ( positiveMotion ? \"+=\" : \"-=\" ) + distance * 2;\n\tanimation2[ ref ] = ( positiveMotion ? \"-=\" : \"+=\" ) + distance * 2;\n\n\t// Animate\n\tel.animate( animation, speed, o.easing );\n\n\t// Shakes\n\tfor ( i = 1; i < times; i++ ) {\n\t\tel.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );\n\t}\n\tel\n\t\t.animate( animation1, speed, o.easing )\n\t\t.animate( animation, speed / 2, o.easing )\n\t\t.queue(function() {\n\t\t\tif ( mode === \"hide\" ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t});\n\n\t// inject all the animations we just queued to be first in line (after \"inprogress\")\n\tif ( queuelen > 1) {\n\t\tqueue.splice.apply( queue,\n\t\t\t[ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );\n\t}\n\tel.dequeue();\n\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.slide = function( o, done ) {\n\n\t// Create element\n\tvar el = $( this ),\n\t\tprops = [ \"position\", \"top\", \"bottom\", \"left\", \"right\", \"width\", \"height\" ],\n\t\tmode = $.effects.setMode( el, o.mode || \"show\" ),\n\t\tshow = mode === \"show\",\n\t\tdirection = o.direction || \"left\",\n\t\tref = (direction === \"up\" || direction === \"down\") ? \"top\" : \"left\",\n\t\tpositiveMotion = (direction === \"up\" || direction === \"left\"),\n\t\tdistance,\n\t\tanimation = {};\n\n\t// Adjust\n\t$.effects.save( el, props );\n\tel.show();\n\tdistance = o.distance || el[ ref === \"top\" ? \"outerHeight\" : \"outerWidth\" ]( true );\n\n\t$.effects.createWrapper( el ).css({\n\t\toverflow: \"hidden\"\n\t});\n\n\tif ( show ) {\n\t\tel.css( ref, positiveMotion ? (isNaN(distance) ? \"-\" + distance : -distance) : distance );\n\t}\n\n\t// Animation\n\tanimation[ ref ] = ( show ?\n\t\t( positiveMotion ? \"+=\" : \"-=\") :\n\t\t( positiveMotion ? \"-=\" : \"+=\")) +\n\t\tdistance;\n\n\t// Animate\n\tel.animate( animation, {\n\t\tqueue: false,\n\t\tduration: o.duration,\n\t\teasing: o.easing,\n\t\tcomplete: function() {\n\t\t\tif ( mode === \"hide\" ) {\n\t\t\t\tel.hide();\n\t\t\t}\n\t\t\t$.effects.restore( el, props );\n\t\t\t$.effects.removeWrapper( el );\n\t\t\tdone();\n\t\t}\n\t});\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.effects.effect.transfer = function( o, done ) {\n\tvar elem = $( this ),\n\t\ttarget = $( o.to ),\n\t\ttargetFixed = target.css( \"position\" ) === \"fixed\",\n\t\tbody = $(\"body\"),\n\t\tfixTop = targetFixed ? body.scrollTop() : 0,\n\t\tfixLeft = targetFixed ? body.scrollLeft() : 0,\n\t\tendPosition = target.offset(),\n\t\tanimation = {\n\t\t\ttop: endPosition.top - fixTop ,\n\t\t\tleft: endPosition.left - fixLeft ,\n\t\t\theight: target.innerHeight(),\n\t\t\twidth: target.innerWidth()\n\t\t},\n\t\tstartPosition = elem.offset(),\n\t\ttransfer = $( \"<div class='ui-effects-transfer'></div>\" )\n\t\t\t.appendTo( document.body )\n\t\t\t.addClass( o.className )\n\t\t\t.css({\n\t\t\t\ttop: startPosition.top - fixTop ,\n\t\t\t\tleft: startPosition.left - fixLeft ,\n\t\t\t\theight: elem.innerHeight(),\n\t\t\t\twidth: elem.innerWidth(),\n\t\t\t\tposition: targetFixed ? \"fixed\" : \"absolute\"\n\t\t\t})\n\t\t\t.animate( animation, o.duration, o.easing, function() {\n\t\t\t\ttransfer.remove();\n\t\t\t\tdone();\n\t\t\t});\n};\n\n})(jQuery);\n\n(function( $, undefined ) {\n\n$.widget( \"ui.menu\", {\n\tversion: \"1.10.1\",\n\tdefaultElement: \"<ul>\",\n\tdelay: 300,\n\toptions: {\n\t\ticons: {\n\t\t\tsubmenu: \"ui-icon-carat-1-e\"\n\t\t},\n\t\tmenus: \"ul\",\n\t\tposition: {\n\t\t\tmy: \"left top\",\n\t\t\tat: \"right top\"\n\t\t},\n\t\trole: \"menu\",\n\n\t\t// callbacks\n\t\tblur: null,\n\t\tfocus: null,\n\t\tselect: null\n\t},\n\n\t_create: function() {\n\t\tthis.activeMenu = this.element;\n\t\t// flag used to prevent firing of the click handler\n\t\t// as the event bubbles up through nested menus\n\t\tthis.mouseHandled = false;\n\t\tthis.element\n\t\t\t.uniqueId()\n\t\t\t.addClass( \"ui-menu ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.toggleClass( \"ui-menu-icons\", !!this.element.find( \".ui-icon\" ).length )\n\t\t\t.attr({\n\t\t\t\trole: this.options.role,\n\t\t\t\ttabIndex: 0\n\t\t\t})\n\t\t\t// need to catch all clicks on disabled menu\n\t\t\t// not possible through _on\n\t\t\t.bind( \"click\" + this.eventNamespace, $.proxy(function( event ) {\n\t\t\t\tif ( this.options.disabled ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}, this ));\n\n\t\tif ( this.options.disabled ) {\n\t\t\tthis.element\n\t\t\t\t.addClass( \"ui-state-disabled\" )\n\t\t\t\t.attr( \"aria-disabled\", \"true\" );\n\t\t}\n\n\t\tthis._on({\n\t\t\t// Prevent focus from sticking to links inside menu after clicking\n\t\t\t// them (focus should always stay on UL during navigation).\n\t\t\t\"mousedown .ui-menu-item > a\": function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t},\n\t\t\t\"click .ui-state-disabled > a\": function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t},\n\t\t\t\"click .ui-menu-item:has(a)\": function( event ) {\n\t\t\t\tvar target = $( event.target ).closest( \".ui-menu-item\" );\n\t\t\t\tif ( !this.mouseHandled && target.not( \".ui-state-disabled\" ).length ) {\n\t\t\t\t\tthis.mouseHandled = true;\n\n\t\t\t\t\tthis.select( event );\n\t\t\t\t\t// Open submenu on click\n\t\t\t\t\tif ( target.has( \".ui-menu\" ).length ) {\n\t\t\t\t\t\tthis.expand( event );\n\t\t\t\t\t} else if ( !this.element.is( \":focus\" ) ) {\n\t\t\t\t\t\t// Redirect focus to the menu\n\t\t\t\t\t\tthis.element.trigger( \"focus\", [ true ] );\n\n\t\t\t\t\t\t// If the active item is on the top level, let it stay active.\n\t\t\t\t\t\t// Otherwise, blur the active item since it is no longer visible.\n\t\t\t\t\t\tif ( this.active && this.active.parents( \".ui-menu\" ).length === 1 ) {\n\t\t\t\t\t\t\tclearTimeout( this.timer );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"mouseenter .ui-menu-item\": function( event ) {\n\t\t\t\tvar target = $( event.currentTarget );\n\t\t\t\t// Remove ui-state-active class from siblings of the newly focused menu item\n\t\t\t\t// to avoid a jump caused by adjacent elements both having a class with a border\n\t\t\t\ttarget.siblings().children( \".ui-state-active\" ).removeClass( \"ui-state-active\" );\n\t\t\t\tthis.focus( event, target );\n\t\t\t},\n\t\t\tmouseleave: \"collapseAll\",\n\t\t\t\"mouseleave .ui-menu\": \"collapseAll\",\n\t\t\tfocus: function( event, keepActiveItem ) {\n\t\t\t\t// If there's already an active item, keep it active\n\t\t\t\t// If not, activate the first item\n\t\t\t\tvar item = this.active || this.element.children( \".ui-menu-item\" ).eq( 0 );\n\n\t\t\t\tif ( !keepActiveItem ) {\n\t\t\t\t\tthis.focus( event, item );\n\t\t\t\t}\n\t\t\t},\n\t\t\tblur: function( event ) {\n\t\t\t\tthis._delay(function() {\n\t\t\t\t\tif ( !$.contains( this.element[0], this.document[0].activeElement ) ) {\n\t\t\t\t\t\tthis.collapseAll( event );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\tkeydown: \"_keydown\"\n\t\t});\n\n\t\tthis.refresh();\n\n\t\t// Clicks outside of a menu collapse any open menus\n\t\tthis._on( this.document, {\n\t\t\tclick: function( event ) {\n\t\t\t\tif ( !$( event.target ).closest( \".ui-menu\" ).length ) {\n\t\t\t\t\tthis.collapseAll( event );\n\t\t\t\t}\n\n\t\t\t\t// Reset the mouseHandled flag\n\t\t\t\tthis.mouseHandled = false;\n\t\t\t}\n\t\t});\n\t},\n\n\t_destroy: function() {\n\t\t// Destroy (sub)menus\n\t\tthis.element\n\t\t\t.removeAttr( \"aria-activedescendant\" )\n\t\t\t.find( \".ui-menu\" ).addBack()\n\t\t\t\t.removeClass( \"ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons\" )\n\t\t\t\t.removeAttr( \"role\" )\n\t\t\t\t.removeAttr( \"tabIndex\" )\n\t\t\t\t.removeAttr( \"aria-labelledby\" )\n\t\t\t\t.removeAttr( \"aria-expanded\" )\n\t\t\t\t.removeAttr( \"aria-hidden\" )\n\t\t\t\t.removeAttr( \"aria-disabled\" )\n\t\t\t\t.removeUniqueId()\n\t\t\t\t.show();\n\n\t\t// Destroy menu items\n\t\tthis.element.find( \".ui-menu-item\" )\n\t\t\t.removeClass( \"ui-menu-item\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-disabled\" )\n\t\t\t.children( \"a\" )\n\t\t\t\t.removeUniqueId()\n\t\t\t\t.removeClass( \"ui-corner-all ui-state-hover\" )\n\t\t\t\t.removeAttr( \"tabIndex\" )\n\t\t\t\t.removeAttr( \"role\" )\n\t\t\t\t.removeAttr( \"aria-haspopup\" )\n\t\t\t\t.children().each( function() {\n\t\t\t\t\tvar elem = $( this );\n\t\t\t\t\tif ( elem.data( \"ui-menu-submenu-carat\" ) ) {\n\t\t\t\t\t\telem.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t// Destroy menu dividers\n\t\tthis.element.find( \".ui-menu-divider\" ).removeClass( \"ui-menu-divider ui-widget-content\" );\n\t},\n\n\t_keydown: function( event ) {\n\t\t/*jshint maxcomplexity:20*/\n\t\tvar match, prev, character, skip, regex,\n\t\t\tpreventDefault = true;\n\n\t\tfunction escape( value ) {\n\t\t\treturn value.replace( /[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, \"\\\\$&\" );\n\t\t}\n\n\t\tswitch ( event.keyCode ) {\n\t\tcase $.ui.keyCode.PAGE_UP:\n\t\t\tthis.previousPage( event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.PAGE_DOWN:\n\t\t\tthis.nextPage( event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.HOME:\n\t\t\tthis._move( \"first\", \"first\", event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.END:\n\t\t\tthis._move( \"last\", \"last\", event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.UP:\n\t\t\tthis.previous( event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.DOWN:\n\t\t\tthis.next( event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.LEFT:\n\t\t\tthis.collapse( event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.RIGHT:\n\t\t\tif ( this.active && !this.active.is( \".ui-state-disabled\" ) ) {\n\t\t\t\tthis.expand( event );\n\t\t\t}\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.ENTER:\n\t\tcase $.ui.keyCode.SPACE:\n\t\t\tthis._activate( event );\n\t\t\tbreak;\n\t\tcase $.ui.keyCode.ESCAPE:\n\t\t\tthis.collapse( event );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tpreventDefault = false;\n\t\t\tprev = this.previousFilter || \"\";\n\t\t\tcharacter = String.fromCharCode( event.keyCode );\n\t\t\tskip = false;\n\n\t\t\tclearTimeout( this.filterTimer );\n\n\t\t\tif ( character === prev ) {\n\t\t\t\tskip = true;\n\t\t\t} else {\n\t\t\t\tcharacter = prev + character;\n\t\t\t}\n\n\t\t\tregex = new RegExp( \"^\" + escape( character ), \"i\" );\n\t\t\tmatch = this.activeMenu.children( \".ui-menu-item\" ).filter(function() {\n\t\t\t\treturn regex.test( $( this ).children( \"a\" ).text() );\n\t\t\t});\n\t\t\tmatch = skip && match.index( this.active.next() ) !== -1 ?\n\t\t\t\tthis.active.nextAll( \".ui-menu-item\" ) :\n\t\t\t\tmatch;\n\n\t\t\t// If no matches on the current filter, reset to the last character pressed\n\t\t\t// to move down the menu to the first item that starts with that character\n\t\t\tif ( !match.length ) {\n\t\t\t\tcharacter = String.fromCharCode( event.keyCode );\n\t\t\t\tregex = new RegExp( \"^\" + escape( character ), \"i\" );\n\t\t\t\tmatch = this.activeMenu.children( \".ui-menu-item\" ).filter(function() {\n\t\t\t\t\treturn regex.test( $( this ).children( \"a\" ).text() );\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif ( match.length ) {\n\t\t\t\tthis.focus( event, match );\n\t\t\t\tif ( match.length > 1 ) {\n\t\t\t\t\tthis.previousFilter = character;\n\t\t\t\t\tthis.filterTimer = this._delay(function() {\n\t\t\t\t\t\tdelete this.previousFilter;\n\t\t\t\t\t}, 1000 );\n\t\t\t\t} else {\n\t\t\t\t\tdelete this.previousFilter;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdelete this.previousFilter;\n\t\t\t}\n\t\t}\n\n\t\tif ( preventDefault ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t},\n\n\t_activate: function( event ) {\n\t\tif ( !this.active.is( \".ui-state-disabled\" ) ) {\n\t\t\tif ( this.active.children( \"a[aria-haspopup='true']\" ).length ) {\n\t\t\t\tthis.expand( event );\n\t\t\t} else {\n\t\t\t\tthis.select( event );\n\t\t\t}\n\t\t}\n\t},\n\n\trefresh: function() {\n\t\tvar menus,\n\t\t\ticon = this.options.icons.submenu,\n\t\t\tsubmenus = this.element.find( this.options.menus );\n\n\t\t// Initialize nested menus\n\t\tsubmenus.filter( \":not(.ui-menu)\" )\n\t\t\t.addClass( \"ui-menu ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.hide()\n\t\t\t.attr({\n\t\t\t\trole: this.options.role,\n\t\t\t\t\"aria-hidden\": \"true\",\n\t\t\t\t\"aria-expanded\": \"false\"\n\t\t\t})\n\t\t\t.each(function() {\n\t\t\t\tvar menu = $( this ),\n\t\t\t\t\titem = menu.prev( \"a\" ),\n\t\t\t\t\tsubmenuCarat = $( \"<span>\" )\n\t\t\t\t\t\t.addClass( \"ui-menu-icon ui-icon \" + icon )\n\t\t\t\t\t\t.data( \"ui-menu-submenu-carat\", true );\n\n\t\t\t\titem\n\t\t\t\t\t.attr( \"aria-haspopup\", \"true\" )\n\t\t\t\t\t.prepend( submenuCarat );\n\t\t\t\tmenu.attr( \"aria-labelledby\", item.attr( \"id\" ) );\n\t\t\t});\n\n\t\tmenus = submenus.add( this.element );\n\n\t\t// Don't refresh list items that are already adapted\n\t\tmenus.children( \":not(.ui-menu-item):has(a)\" )\n\t\t\t.addClass( \"ui-menu-item\" )\n\t\t\t.attr( \"role\", \"presentation\" )\n\t\t\t.children( \"a\" )\n\t\t\t\t.uniqueId()\n\t\t\t\t.addClass( \"ui-corner-all\" )\n\t\t\t\t.attr({\n\t\t\t\t\ttabIndex: -1,\n\t\t\t\t\trole: this._itemRole()\n\t\t\t\t});\n\n\t\t// Initialize unlinked menu-items containing spaces and/or dashes only as dividers\n\t\tmenus.children( \":not(.ui-menu-item)\" ).each(function() {\n\t\t\tvar item = $( this );\n\t\t\t// hyphen, em dash, en dash\n\t\t\tif ( !/[^\\-\\u2014\\u2013\\s]/.test( item.text() ) ) {\n\t\t\t\titem.addClass( \"ui-widget-content ui-menu-divider\" );\n\t\t\t}\n\t\t});\n\n\t\t// Add aria-disabled attribute to any disabled menu item\n\t\tmenus.children( \".ui-state-disabled\" ).attr( \"aria-disabled\", \"true\" );\n\n\t\t// If the active item has been removed, blur the menu\n\t\tif ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {\n\t\t\tthis.blur();\n\t\t}\n\t},\n\n\t_itemRole: function() {\n\t\treturn {\n\t\t\tmenu: \"menuitem\",\n\t\t\tlistbox: \"option\"\n\t\t}[ this.options.role ];\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"icons\" ) {\n\t\t\tthis.element.find( \".ui-menu-icon\" )\n\t\t\t\t.removeClass( this.options.icons.submenu )\n\t\t\t\t.addClass( value.submenu );\n\t\t}\n\t\tthis._super( key, value );\n\t},\n\n\tfocus: function( event, item ) {\n\t\tvar nested, focused;\n\t\tthis.blur( event, event && event.type === \"focus\" );\n\n\t\tthis._scrollIntoView( item );\n\n\t\tthis.active = item.first();\n\t\tfocused = this.active.children( \"a\" ).addClass( \"ui-state-focus\" );\n\t\t// Only update aria-activedescendant if there's a role\n\t\t// otherwise we assume focus is managed elsewhere\n\t\tif ( this.options.role ) {\n\t\t\tthis.element.attr( \"aria-activedescendant\", focused.attr( \"id\" ) );\n\t\t}\n\n\t\t// Highlight active parent menu item, if any\n\t\tthis.active\n\t\t\t.parent()\n\t\t\t.closest( \".ui-menu-item\" )\n\t\t\t.children( \"a:first\" )\n\t\t\t.addClass( \"ui-state-active\" );\n\n\t\tif ( event && event.type === \"keydown\" ) {\n\t\t\tthis._close();\n\t\t} else {\n\t\t\tthis.timer = this._delay(function() {\n\t\t\t\tthis._close();\n\t\t\t}, this.delay );\n\t\t}\n\n\t\tnested = item.children( \".ui-menu\" );\n\t\tif ( nested.length && ( /^mouse/.test( event.type ) ) ) {\n\t\t\tthis._startOpening(nested);\n\t\t}\n\t\tthis.activeMenu = item.parent();\n\n\t\tthis._trigger( \"focus\", event, { item: item } );\n\t},\n\n\t_scrollIntoView: function( item ) {\n\t\tvar borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;\n\t\tif ( this._hasScroll() ) {\n\t\t\tborderTop = parseFloat( $.css( this.activeMenu[0], \"borderTopWidth\" ) ) || 0;\n\t\t\tpaddingTop = parseFloat( $.css( this.activeMenu[0], \"paddingTop\" ) ) || 0;\n\t\t\toffset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;\n\t\t\tscroll = this.activeMenu.scrollTop();\n\t\t\telementHeight = this.activeMenu.height();\n\t\t\titemHeight = item.height();\n\n\t\t\tif ( offset < 0 ) {\n\t\t\t\tthis.activeMenu.scrollTop( scroll + offset );\n\t\t\t} else if ( offset + itemHeight > elementHeight ) {\n\t\t\t\tthis.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );\n\t\t\t}\n\t\t}\n\t},\n\n\tblur: function( event, fromFocus ) {\n\t\tif ( !fromFocus ) {\n\t\t\tclearTimeout( this.timer );\n\t\t}\n\n\t\tif ( !this.active ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.active.children( \"a\" ).removeClass( \"ui-state-focus\" );\n\t\tthis.active = null;\n\n\t\tthis._trigger( \"blur\", event, { item: this.active } );\n\t},\n\n\t_startOpening: function( submenu ) {\n\t\tclearTimeout( this.timer );\n\n\t\t// Don't open if already open fixes a Firefox bug that caused a .5 pixel\n\t\t// shift in the submenu position when mousing over the carat icon\n\t\tif ( submenu.attr( \"aria-hidden\" ) !== \"true\" ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.timer = this._delay(function() {\n\t\t\tthis._close();\n\t\t\tthis._open( submenu );\n\t\t}, this.delay );\n\t},\n\n\t_open: function( submenu ) {\n\t\tvar position = $.extend({\n\t\t\tof: this.active\n\t\t}, this.options.position );\n\n\t\tclearTimeout( this.timer );\n\t\tthis.element.find( \".ui-menu\" ).not( submenu.parents( \".ui-menu\" ) )\n\t\t\t.hide()\n\t\t\t.attr( \"aria-hidden\", \"true\" );\n\n\t\tsubmenu\n\t\t\t.show()\n\t\t\t.removeAttr( \"aria-hidden\" )\n\t\t\t.attr( \"aria-expanded\", \"true\" )\n\t\t\t.position( position );\n\t},\n\n\tcollapseAll: function( event, all ) {\n\t\tclearTimeout( this.timer );\n\t\tthis.timer = this._delay(function() {\n\t\t\t// If we were passed an event, look for the submenu that contains the event\n\t\t\tvar currentMenu = all ? this.element :\n\t\t\t\t$( event && event.target ).closest( this.element.find( \".ui-menu\" ) );\n\n\t\t\t// If we found no valid submenu ancestor, use the main menu to close all sub menus anyway\n\t\t\tif ( !currentMenu.length ) {\n\t\t\t\tcurrentMenu = this.element;\n\t\t\t}\n\n\t\t\tthis._close( currentMenu );\n\n\t\t\tthis.blur( event );\n\t\t\tthis.activeMenu = currentMenu;\n\t\t}, this.delay );\n\t},\n\n\t// With no arguments, closes the currently active menu - if nothing is active\n\t// it closes all menus.  If passed an argument, it will search for menus BELOW\n\t_close: function( startMenu ) {\n\t\tif ( !startMenu ) {\n\t\t\tstartMenu = this.active ? this.active.parent() : this.element;\n\t\t}\n\n\t\tstartMenu\n\t\t\t.find( \".ui-menu\" )\n\t\t\t\t.hide()\n\t\t\t\t.attr( \"aria-hidden\", \"true\" )\n\t\t\t\t.attr( \"aria-expanded\", \"false\" )\n\t\t\t.end()\n\t\t\t.find( \"a.ui-state-active\" )\n\t\t\t\t.removeClass( \"ui-state-active\" );\n\t},\n\n\tcollapse: function( event ) {\n\t\tvar newItem = this.active &&\n\t\t\tthis.active.parent().closest( \".ui-menu-item\", this.element );\n\t\tif ( newItem && newItem.length ) {\n\t\t\tthis._close();\n\t\t\tthis.focus( event, newItem );\n\t\t}\n\t},\n\n\texpand: function( event ) {\n\t\tvar newItem = this.active &&\n\t\t\tthis.active\n\t\t\t\t.children( \".ui-menu \" )\n\t\t\t\t.children( \".ui-menu-item\" )\n\t\t\t\t.first();\n\n\t\tif ( newItem && newItem.length ) {\n\t\t\tthis._open( newItem.parent() );\n\n\t\t\t// Delay so Firefox will not hide activedescendant change in expanding submenu from AT\n\t\t\tthis._delay(function() {\n\t\t\t\tthis.focus( event, newItem );\n\t\t\t});\n\t\t}\n\t},\n\n\tnext: function( event ) {\n\t\tthis._move( \"next\", \"first\", event );\n\t},\n\n\tprevious: function( event ) {\n\t\tthis._move( \"prev\", \"last\", event );\n\t},\n\n\tisFirstItem: function() {\n\t\treturn this.active && !this.active.prevAll( \".ui-menu-item\" ).length;\n\t},\n\n\tisLastItem: function() {\n\t\treturn this.active && !this.active.nextAll( \".ui-menu-item\" ).length;\n\t},\n\n\t_move: function( direction, filter, event ) {\n\t\tvar next;\n\t\tif ( this.active ) {\n\t\t\tif ( direction === \"first\" || direction === \"last\" ) {\n\t\t\t\tnext = this.active\n\t\t\t\t\t[ direction === \"first\" ? \"prevAll\" : \"nextAll\" ]( \".ui-menu-item\" )\n\t\t\t\t\t.eq( -1 );\n\t\t\t} else {\n\t\t\t\tnext = this.active\n\t\t\t\t\t[ direction + \"All\" ]( \".ui-menu-item\" )\n\t\t\t\t\t.eq( 0 );\n\t\t\t}\n\t\t}\n\t\tif ( !next || !next.length || !this.active ) {\n\t\t\tnext = this.activeMenu.children( \".ui-menu-item\" )[ filter ]();\n\t\t}\n\n\t\tthis.focus( event, next );\n\t},\n\n\tnextPage: function( event ) {\n\t\tvar item, base, height;\n\n\t\tif ( !this.active ) {\n\t\t\tthis.next( event );\n\t\t\treturn;\n\t\t}\n\t\tif ( this.isLastItem() ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( this._hasScroll() ) {\n\t\t\tbase = this.active.offset().top;\n\t\t\theight = this.element.height();\n\t\t\tthis.active.nextAll( \".ui-menu-item\" ).each(function() {\n\t\t\t\titem = $( this );\n\t\t\t\treturn item.offset().top - base - height < 0;\n\t\t\t});\n\n\t\t\tthis.focus( event, item );\n\t\t} else {\n\t\t\tthis.focus( event, this.activeMenu.children( \".ui-menu-item\" )\n\t\t\t\t[ !this.active ? \"first\" : \"last\" ]() );\n\t\t}\n\t},\n\n\tpreviousPage: function( event ) {\n\t\tvar item, base, height;\n\t\tif ( !this.active ) {\n\t\t\tthis.next( event );\n\t\t\treturn;\n\t\t}\n\t\tif ( this.isFirstItem() ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( this._hasScroll() ) {\n\t\t\tbase = this.active.offset().top;\n\t\t\theight = this.element.height();\n\t\t\tthis.active.prevAll( \".ui-menu-item\" ).each(function() {\n\t\t\t\titem = $( this );\n\t\t\t\treturn item.offset().top - base + height > 0;\n\t\t\t});\n\n\t\t\tthis.focus( event, item );\n\t\t} else {\n\t\t\tthis.focus( event, this.activeMenu.children( \".ui-menu-item\" ).first() );\n\t\t}\n\t},\n\n\t_hasScroll: function() {\n\t\treturn this.element.outerHeight() < this.element.prop( \"scrollHeight\" );\n\t},\n\n\tselect: function( event ) {\n\t\t// TODO: It should never be possible to not have an active item at this\n\t\t// point, but the tests don't trigger mouseenter before click.\n\t\tthis.active = this.active || $( event.target ).closest( \".ui-menu-item\" );\n\t\tvar ui = { item: this.active };\n\t\tif ( !this.active.has( \".ui-menu\" ).length ) {\n\t\t\tthis.collapseAll( event, true );\n\t\t}\n\t\tthis._trigger( \"select\", event, ui );\n\t}\n});\n\n}( jQuery ));\n\n(function( $, undefined ) {\n\n$.ui = $.ui || {};\n\nvar cachedScrollbarWidth,\n\tmax = Math.max,\n\tabs = Math.abs,\n\tround = Math.round,\n\trhorizontal = /left|center|right/,\n\trvertical = /top|center|bottom/,\n\troffset = /[\\+\\-]\\d+(\\.[\\d]+)?%?/,\n\trposition = /^\\w+/,\n\trpercent = /%$/,\n\t_position = $.fn.position;\n\nfunction getOffsets( offsets, width, height ) {\n\treturn [\n\t\tparseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),\n\t\tparseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )\n\t];\n}\n\nfunction parseCss( element, property ) {\n\treturn parseInt( $.css( element, property ), 10 ) || 0;\n}\n\nfunction getDimensions( elem ) {\n\tvar raw = elem[0];\n\tif ( raw.nodeType === 9 ) {\n\t\treturn {\n\t\t\twidth: elem.width(),\n\t\t\theight: elem.height(),\n\t\t\toffset: { top: 0, left: 0 }\n\t\t};\n\t}\n\tif ( $.isWindow( raw ) ) {\n\t\treturn {\n\t\t\twidth: elem.width(),\n\t\t\theight: elem.height(),\n\t\t\toffset: { top: elem.scrollTop(), left: elem.scrollLeft() }\n\t\t};\n\t}\n\tif ( raw.preventDefault ) {\n\t\treturn {\n\t\t\twidth: 0,\n\t\t\theight: 0,\n\t\t\toffset: { top: raw.pageY, left: raw.pageX }\n\t\t};\n\t}\n\treturn {\n\t\twidth: elem.outerWidth(),\n\t\theight: elem.outerHeight(),\n\t\toffset: elem.offset()\n\t};\n}\n\n$.position = {\n\tscrollbarWidth: function() {\n\t\tif ( cachedScrollbarWidth !== undefined ) {\n\t\t\treturn cachedScrollbarWidth;\n\t\t}\n\t\tvar w1, w2,\n\t\t\tdiv = $( \"<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>\" ),\n\t\t\tinnerDiv = div.children()[0];\n\n\t\t$( \"body\" ).append( div );\n\t\tw1 = innerDiv.offsetWidth;\n\t\tdiv.css( \"overflow\", \"scroll\" );\n\n\t\tw2 = innerDiv.offsetWidth;\n\n\t\tif ( w1 === w2 ) {\n\t\t\tw2 = div[0].clientWidth;\n\t\t}\n\n\t\tdiv.remove();\n\n\t\treturn (cachedScrollbarWidth = w1 - w2);\n\t},\n\tgetScrollInfo: function( within ) {\n\t\tvar overflowX = within.isWindow ? \"\" : within.element.css( \"overflow-x\" ),\n\t\t\toverflowY = within.isWindow ? \"\" : within.element.css( \"overflow-y\" ),\n\t\t\thasOverflowX = overflowX === \"scroll\" ||\n\t\t\t\t( overflowX === \"auto\" && within.width < within.element[0].scrollWidth ),\n\t\t\thasOverflowY = overflowY === \"scroll\" ||\n\t\t\t\t( overflowY === \"auto\" && within.height < within.element[0].scrollHeight );\n\t\treturn {\n\t\t\twidth: hasOverflowX ? $.position.scrollbarWidth() : 0,\n\t\t\theight: hasOverflowY ? $.position.scrollbarWidth() : 0\n\t\t};\n\t},\n\tgetWithinInfo: function( element ) {\n\t\tvar withinElement = $( element || window ),\n\t\t\tisWindow = $.isWindow( withinElement[0] );\n\t\treturn {\n\t\t\telement: withinElement,\n\t\t\tisWindow: isWindow,\n\t\t\toffset: withinElement.offset() || { left: 0, top: 0 },\n\t\t\tscrollLeft: withinElement.scrollLeft(),\n\t\t\tscrollTop: withinElement.scrollTop(),\n\t\t\twidth: isWindow ? withinElement.width() : withinElement.outerWidth(),\n\t\t\theight: isWindow ? withinElement.height() : withinElement.outerHeight()\n\t\t};\n\t}\n};\n\n$.fn.position = function( options ) {\n\tif ( !options || !options.of ) {\n\t\treturn _position.apply( this, arguments );\n\t}\n\n\t// make a copy, we don't want to modify arguments\n\toptions = $.extend( {}, options );\n\n\tvar atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,\n\t\ttarget = $( options.of ),\n\t\twithin = $.position.getWithinInfo( options.within ),\n\t\tscrollInfo = $.position.getScrollInfo( within ),\n\t\tcollision = ( options.collision || \"flip\" ).split( \" \" ),\n\t\toffsets = {};\n\n\tdimensions = getDimensions( target );\n\tif ( target[0].preventDefault ) {\n\t\t// force left top to allow flipping\n\t\toptions.at = \"left top\";\n\t}\n\ttargetWidth = dimensions.width;\n\ttargetHeight = dimensions.height;\n\ttargetOffset = dimensions.offset;\n\t// clone to reuse original targetOffset later\n\tbasePosition = $.extend( {}, targetOffset );\n\n\t// force my and at to have valid horizontal and vertical positions\n\t// if a value is missing or invalid, it will be converted to center\n\t$.each( [ \"my\", \"at\" ], function() {\n\t\tvar pos = ( options[ this ] || \"\" ).split( \" \" ),\n\t\t\thorizontalOffset,\n\t\t\tverticalOffset;\n\n\t\tif ( pos.length === 1) {\n\t\t\tpos = rhorizontal.test( pos[ 0 ] ) ?\n\t\t\t\tpos.concat( [ \"center\" ] ) :\n\t\t\t\trvertical.test( pos[ 0 ] ) ?\n\t\t\t\t\t[ \"center\" ].concat( pos ) :\n\t\t\t\t\t[ \"center\", \"center\" ];\n\t\t}\n\t\tpos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : \"center\";\n\t\tpos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : \"center\";\n\n\t\t// calculate offsets\n\t\thorizontalOffset = roffset.exec( pos[ 0 ] );\n\t\tverticalOffset = roffset.exec( pos[ 1 ] );\n\t\toffsets[ this ] = [\n\t\t\thorizontalOffset ? horizontalOffset[ 0 ] : 0,\n\t\t\tverticalOffset ? verticalOffset[ 0 ] : 0\n\t\t];\n\n\t\t// reduce to just the positions without the offsets\n\t\toptions[ this ] = [\n\t\t\trposition.exec( pos[ 0 ] )[ 0 ],\n\t\t\trposition.exec( pos[ 1 ] )[ 0 ]\n\t\t];\n\t});\n\n\t// normalize collision option\n\tif ( collision.length === 1 ) {\n\t\tcollision[ 1 ] = collision[ 0 ];\n\t}\n\n\tif ( options.at[ 0 ] === \"right\" ) {\n\t\tbasePosition.left += targetWidth;\n\t} else if ( options.at[ 0 ] === \"center\" ) {\n\t\tbasePosition.left += targetWidth / 2;\n\t}\n\n\tif ( options.at[ 1 ] === \"bottom\" ) {\n\t\tbasePosition.top += targetHeight;\n\t} else if ( options.at[ 1 ] === \"center\" ) {\n\t\tbasePosition.top += targetHeight / 2;\n\t}\n\n\tatOffset = getOffsets( offsets.at, targetWidth, targetHeight );\n\tbasePosition.left += atOffset[ 0 ];\n\tbasePosition.top += atOffset[ 1 ];\n\n\treturn this.each(function() {\n\t\tvar collisionPosition, using,\n\t\t\telem = $( this ),\n\t\t\telemWidth = elem.outerWidth(),\n\t\t\telemHeight = elem.outerHeight(),\n\t\t\tmarginLeft = parseCss( this, \"marginLeft\" ),\n\t\t\tmarginTop = parseCss( this, \"marginTop\" ),\n\t\t\tcollisionWidth = elemWidth + marginLeft + parseCss( this, \"marginRight\" ) + scrollInfo.width,\n\t\t\tcollisionHeight = elemHeight + marginTop + parseCss( this, \"marginBottom\" ) + scrollInfo.height,\n\t\t\tposition = $.extend( {}, basePosition ),\n\t\t\tmyOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );\n\n\t\tif ( options.my[ 0 ] === \"right\" ) {\n\t\t\tposition.left -= elemWidth;\n\t\t} else if ( options.my[ 0 ] === \"center\" ) {\n\t\t\tposition.left -= elemWidth / 2;\n\t\t}\n\n\t\tif ( options.my[ 1 ] === \"bottom\" ) {\n\t\t\tposition.top -= elemHeight;\n\t\t} else if ( options.my[ 1 ] === \"center\" ) {\n\t\t\tposition.top -= elemHeight / 2;\n\t\t}\n\n\t\tposition.left += myOffset[ 0 ];\n\t\tposition.top += myOffset[ 1 ];\n\n\t\t// if the browser doesn't support fractions, then round for consistent results\n\t\tif ( !$.support.offsetFractions ) {\n\t\t\tposition.left = round( position.left );\n\t\t\tposition.top = round( position.top );\n\t\t}\n\n\t\tcollisionPosition = {\n\t\t\tmarginLeft: marginLeft,\n\t\t\tmarginTop: marginTop\n\t\t};\n\n\t\t$.each( [ \"left\", \"top\" ], function( i, dir ) {\n\t\t\tif ( $.ui.position[ collision[ i ] ] ) {\n\t\t\t\t$.ui.position[ collision[ i ] ][ dir ]( position, {\n\t\t\t\t\ttargetWidth: targetWidth,\n\t\t\t\t\ttargetHeight: targetHeight,\n\t\t\t\t\telemWidth: elemWidth,\n\t\t\t\t\telemHeight: elemHeight,\n\t\t\t\t\tcollisionPosition: collisionPosition,\n\t\t\t\t\tcollisionWidth: collisionWidth,\n\t\t\t\t\tcollisionHeight: collisionHeight,\n\t\t\t\t\toffset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],\n\t\t\t\t\tmy: options.my,\n\t\t\t\t\tat: options.at,\n\t\t\t\t\twithin: within,\n\t\t\t\t\telem : elem\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\tif ( options.using ) {\n\t\t\t// adds feedback as second argument to using callback, if present\n\t\t\tusing = function( props ) {\n\t\t\t\tvar left = targetOffset.left - position.left,\n\t\t\t\t\tright = left + targetWidth - elemWidth,\n\t\t\t\t\ttop = targetOffset.top - position.top,\n\t\t\t\t\tbottom = top + targetHeight - elemHeight,\n\t\t\t\t\tfeedback = {\n\t\t\t\t\t\ttarget: {\n\t\t\t\t\t\t\telement: target,\n\t\t\t\t\t\t\tleft: targetOffset.left,\n\t\t\t\t\t\t\ttop: targetOffset.top,\n\t\t\t\t\t\t\twidth: targetWidth,\n\t\t\t\t\t\t\theight: targetHeight\n\t\t\t\t\t\t},\n\t\t\t\t\t\telement: {\n\t\t\t\t\t\t\telement: elem,\n\t\t\t\t\t\t\tleft: position.left,\n\t\t\t\t\t\t\ttop: position.top,\n\t\t\t\t\t\t\twidth: elemWidth,\n\t\t\t\t\t\t\theight: elemHeight\n\t\t\t\t\t\t},\n\t\t\t\t\t\thorizontal: right < 0 ? \"left\" : left > 0 ? \"right\" : \"center\",\n\t\t\t\t\t\tvertical: bottom < 0 ? \"top\" : top > 0 ? \"bottom\" : \"middle\"\n\t\t\t\t\t};\n\t\t\t\tif ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {\n\t\t\t\t\tfeedback.horizontal = \"center\";\n\t\t\t\t}\n\t\t\t\tif ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {\n\t\t\t\t\tfeedback.vertical = \"middle\";\n\t\t\t\t}\n\t\t\t\tif ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {\n\t\t\t\t\tfeedback.important = \"horizontal\";\n\t\t\t\t} else {\n\t\t\t\t\tfeedback.important = \"vertical\";\n\t\t\t\t}\n\t\t\t\toptions.using.call( this, props, feedback );\n\t\t\t};\n\t\t}\n\n\t\telem.offset( $.extend( position, { using: using } ) );\n\t});\n};\n\n$.ui.position = {\n\tfit: {\n\t\tleft: function( position, data ) {\n\t\t\tvar within = data.within,\n\t\t\t\twithinOffset = within.isWindow ? within.scrollLeft : within.offset.left,\n\t\t\t\touterWidth = within.width,\n\t\t\t\tcollisionPosLeft = position.left - data.collisionPosition.marginLeft,\n\t\t\t\toverLeft = withinOffset - collisionPosLeft,\n\t\t\t\toverRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,\n\t\t\t\tnewOverRight;\n\n\t\t\t// element is wider than within\n\t\t\tif ( data.collisionWidth > outerWidth ) {\n\t\t\t\t// element is initially over the left side of within\n\t\t\t\tif ( overLeft > 0 && overRight <= 0 ) {\n\t\t\t\t\tnewOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;\n\t\t\t\t\tposition.left += overLeft - newOverRight;\n\t\t\t\t// element is initially over right side of within\n\t\t\t\t} else if ( overRight > 0 && overLeft <= 0 ) {\n\t\t\t\t\tposition.left = withinOffset;\n\t\t\t\t// element is initially over both left and right sides of within\n\t\t\t\t} else {\n\t\t\t\t\tif ( overLeft > overRight ) {\n\t\t\t\t\t\tposition.left = withinOffset + outerWidth - data.collisionWidth;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tposition.left = withinOffset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t// too far left -> align with left edge\n\t\t\t} else if ( overLeft > 0 ) {\n\t\t\t\tposition.left += overLeft;\n\t\t\t// too far right -> align with right edge\n\t\t\t} else if ( overRight > 0 ) {\n\t\t\t\tposition.left -= overRight;\n\t\t\t// adjust based on position and margin\n\t\t\t} else {\n\t\t\t\tposition.left = max( position.left - collisionPosLeft, position.left );\n\t\t\t}\n\t\t},\n\t\ttop: function( position, data ) {\n\t\t\tvar within = data.within,\n\t\t\t\twithinOffset = within.isWindow ? within.scrollTop : within.offset.top,\n\t\t\t\touterHeight = data.within.height,\n\t\t\t\tcollisionPosTop = position.top - data.collisionPosition.marginTop,\n\t\t\t\toverTop = withinOffset - collisionPosTop,\n\t\t\t\toverBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,\n\t\t\t\tnewOverBottom;\n\n\t\t\t// element is taller than within\n\t\t\tif ( data.collisionHeight > outerHeight ) {\n\t\t\t\t// element is initially over the top of within\n\t\t\t\tif ( overTop > 0 && overBottom <= 0 ) {\n\t\t\t\t\tnewOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;\n\t\t\t\t\tposition.top += overTop - newOverBottom;\n\t\t\t\t// element is initially over bottom of within\n\t\t\t\t} else if ( overBottom > 0 && overTop <= 0 ) {\n\t\t\t\t\tposition.top = withinOffset;\n\t\t\t\t// element is initially over both top and bottom of within\n\t\t\t\t} else {\n\t\t\t\t\tif ( overTop > overBottom ) {\n\t\t\t\t\t\tposition.top = withinOffset + outerHeight - data.collisionHeight;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tposition.top = withinOffset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t// too far up -> align with top\n\t\t\t} else if ( overTop > 0 ) {\n\t\t\t\tposition.top += overTop;\n\t\t\t// too far down -> align with bottom edge\n\t\t\t} else if ( overBottom > 0 ) {\n\t\t\t\tposition.top -= overBottom;\n\t\t\t// adjust based on position and margin\n\t\t\t} else {\n\t\t\t\tposition.top = max( position.top - collisionPosTop, position.top );\n\t\t\t}\n\t\t}\n\t},\n\tflip: {\n\t\tleft: function( position, data ) {\n\t\t\tvar within = data.within,\n\t\t\t\twithinOffset = within.offset.left + within.scrollLeft,\n\t\t\t\touterWidth = within.width,\n\t\t\t\toffsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,\n\t\t\t\tcollisionPosLeft = position.left - data.collisionPosition.marginLeft,\n\t\t\t\toverLeft = collisionPosLeft - offsetLeft,\n\t\t\t\toverRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,\n\t\t\t\tmyOffset = data.my[ 0 ] === \"left\" ?\n\t\t\t\t\t-data.elemWidth :\n\t\t\t\t\tdata.my[ 0 ] === \"right\" ?\n\t\t\t\t\t\tdata.elemWidth :\n\t\t\t\t\t\t0,\n\t\t\t\tatOffset = data.at[ 0 ] === \"left\" ?\n\t\t\t\t\tdata.targetWidth :\n\t\t\t\t\tdata.at[ 0 ] === \"right\" ?\n\t\t\t\t\t\t-data.targetWidth :\n\t\t\t\t\t\t0,\n\t\t\t\toffset = -2 * data.offset[ 0 ],\n\t\t\t\tnewOverRight,\n\t\t\t\tnewOverLeft;\n\n\t\t\tif ( overLeft < 0 ) {\n\t\t\t\tnewOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;\n\t\t\t\tif ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {\n\t\t\t\t\tposition.left += myOffset + atOffset + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( overRight > 0 ) {\n\t\t\t\tnewOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;\n\t\t\t\tif ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {\n\t\t\t\t\tposition.left += myOffset + atOffset + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\ttop: function( position, data ) {\n\t\t\tvar within = data.within,\n\t\t\t\twithinOffset = within.offset.top + within.scrollTop,\n\t\t\t\touterHeight = within.height,\n\t\t\t\toffsetTop = within.isWindow ? within.scrollTop : within.offset.top,\n\t\t\t\tcollisionPosTop = position.top - data.collisionPosition.marginTop,\n\t\t\t\toverTop = collisionPosTop - offsetTop,\n\t\t\t\toverBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,\n\t\t\t\ttop = data.my[ 1 ] === \"top\",\n\t\t\t\tmyOffset = top ?\n\t\t\t\t\t-data.elemHeight :\n\t\t\t\t\tdata.my[ 1 ] === \"bottom\" ?\n\t\t\t\t\t\tdata.elemHeight :\n\t\t\t\t\t\t0,\n\t\t\t\tatOffset = data.at[ 1 ] === \"top\" ?\n\t\t\t\t\tdata.targetHeight :\n\t\t\t\t\tdata.at[ 1 ] === \"bottom\" ?\n\t\t\t\t\t\t-data.targetHeight :\n\t\t\t\t\t\t0,\n\t\t\t\toffset = -2 * data.offset[ 1 ],\n\t\t\t\tnewOverTop,\n\t\t\t\tnewOverBottom;\n\t\t\tif ( overTop < 0 ) {\n\t\t\t\tnewOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;\n\t\t\t\tif ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {\n\t\t\t\t\tposition.top += myOffset + atOffset + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( overBottom > 0 ) {\n\t\t\t\tnewOverTop = position.top -  data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;\n\t\t\t\tif ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {\n\t\t\t\t\tposition.top += myOffset + atOffset + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\tflipfit: {\n\t\tleft: function() {\n\t\t\t$.ui.position.flip.left.apply( this, arguments );\n\t\t\t$.ui.position.fit.left.apply( this, arguments );\n\t\t},\n\t\ttop: function() {\n\t\t\t$.ui.position.flip.top.apply( this, arguments );\n\t\t\t$.ui.position.fit.top.apply( this, arguments );\n\t\t}\n\t}\n};\n\n// fraction support test\n(function () {\n\tvar testElement, testElementParent, testElementStyle, offsetLeft, i,\n\t\tbody = document.getElementsByTagName( \"body\" )[ 0 ],\n\t\tdiv = document.createElement( \"div\" );\n\n\t//Create a \"fake body\" for testing based on method used in jQuery.support\n\ttestElement = document.createElement( body ? \"div\" : \"body\" );\n\ttestElementStyle = {\n\t\tvisibility: \"hidden\",\n\t\twidth: 0,\n\t\theight: 0,\n\t\tborder: 0,\n\t\tmargin: 0,\n\t\tbackground: \"none\"\n\t};\n\tif ( body ) {\n\t\t$.extend( testElementStyle, {\n\t\t\tposition: \"absolute\",\n\t\t\tleft: \"-1000px\",\n\t\t\ttop: \"-1000px\"\n\t\t});\n\t}\n\tfor ( i in testElementStyle ) {\n\t\ttestElement.style[ i ] = testElementStyle[ i ];\n\t}\n\ttestElement.appendChild( div );\n\ttestElementParent = body || document.documentElement;\n\ttestElementParent.insertBefore( testElement, testElementParent.firstChild );\n\n\tdiv.style.cssText = \"position: absolute; left: 10.7432222px;\";\n\n\toffsetLeft = $( div ).offset().left;\n\t$.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;\n\n\ttestElement.innerHTML = \"\";\n\ttestElementParent.removeChild( testElement );\n})();\n\n}( jQuery ) );\n\n(function( $, undefined ) {\n\n$.widget( \"ui.progressbar\", {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\tmax: 100,\n\t\tvalue: 0,\n\n\t\tchange: null,\n\t\tcomplete: null\n\t},\n\n\tmin: 0,\n\n\t_create: function() {\n\t\t// Constrain initial value\n\t\tthis.oldValue = this.options.value = this._constrainedValue();\n\n\t\tthis.element\n\t\t\t.addClass( \"ui-progressbar ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.attr({\n\t\t\t\t// Only set static values, aria-valuenow and aria-valuemax are\n\t\t\t\t// set inside _refreshValue()\n\t\t\t\trole: \"progressbar\",\n\t\t\t\t\"aria-valuemin\": this.min\n\t\t\t});\n\n\t\tthis.valueDiv = $( \"<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>\" )\n\t\t\t.appendTo( this.element );\n\n\t\tthis._refreshValue();\n\t},\n\n\t_destroy: function() {\n\t\tthis.element\n\t\t\t.removeClass( \"ui-progressbar ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-valuemin\" )\n\t\t\t.removeAttr( \"aria-valuemax\" )\n\t\t\t.removeAttr( \"aria-valuenow\" );\n\n\t\tthis.valueDiv.remove();\n\t},\n\n\tvalue: function( newValue ) {\n\t\tif ( newValue === undefined ) {\n\t\t\treturn this.options.value;\n\t\t}\n\n\t\tthis.options.value = this._constrainedValue( newValue );\n\t\tthis._refreshValue();\n\t},\n\n\t_constrainedValue: function( newValue ) {\n\t\tif ( newValue === undefined ) {\n\t\t\tnewValue = this.options.value;\n\t\t}\n\n\t\tthis.indeterminate = newValue === false;\n\n\t\t// sanitize value\n\t\tif ( typeof newValue !== \"number\" ) {\n\t\t\tnewValue = 0;\n\t\t}\n\n\t\treturn this.indeterminate ? false :\n\t\t\tMath.min( this.options.max, Math.max( this.min, newValue ) );\n\t},\n\n\t_setOptions: function( options ) {\n\t\t// Ensure \"value\" option is set after other values (like max)\n\t\tvar value = options.value;\n\t\tdelete options.value;\n\n\t\tthis._super( options );\n\n\t\tthis.options.value = this._constrainedValue( value );\n\t\tthis._refreshValue();\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"max\" ) {\n\t\t\t// Don't allow a max less than min\n\t\t\tvalue = Math.max( this.min, value );\n\t\t}\n\n\t\tthis._super( key, value );\n\t},\n\n\t_percentage: function() {\n\t\treturn this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );\n\t},\n\n\t_refreshValue: function() {\n\t\tvar value = this.options.value,\n\t\t\tpercentage = this._percentage();\n\n\t\tthis.valueDiv\n\t\t\t.toggle( this.indeterminate || value > this.min )\n\t\t\t.toggleClass( \"ui-corner-right\", value === this.options.max )\n\t\t\t.width( percentage.toFixed(0) + \"%\" );\n\n\t\tthis.element.toggleClass( \"ui-progressbar-indeterminate\", this.indeterminate );\n\n\t\tif ( this.indeterminate ) {\n\t\t\tthis.element.removeAttr( \"aria-valuenow\" );\n\t\t\tif ( !this.overlayDiv ) {\n\t\t\t\tthis.overlayDiv = $( \"<div class='ui-progressbar-overlay'></div>\" ).appendTo( this.valueDiv );\n\t\t\t}\n\t\t} else {\n\t\t\tthis.element.attr({\n\t\t\t\t\"aria-valuemax\": this.options.max,\n\t\t\t\t\"aria-valuenow\": value\n\t\t\t});\n\t\t\tif ( this.overlayDiv ) {\n\t\t\t\tthis.overlayDiv.remove();\n\t\t\t\tthis.overlayDiv = null;\n\t\t\t}\n\t\t}\n\n\t\tif ( this.oldValue !== value ) {\n\t\t\tthis.oldValue = value;\n\t\t\tthis._trigger( \"change\" );\n\t\t}\n\t\tif ( value === this.options.max ) {\n\t\t\tthis._trigger( \"complete\" );\n\t\t}\n\t}\n});\n\n})( jQuery );\n\n(function( $, undefined ) {\n\n// number of pages in a slider\n// (how many times can you page up/down to go through the whole range)\nvar numPages = 5;\n\n$.widget( \"ui.slider\", $.ui.mouse, {\n\tversion: \"1.10.1\",\n\twidgetEventPrefix: \"slide\",\n\n\toptions: {\n\t\tanimate: false,\n\t\tdistance: 0,\n\t\tmax: 100,\n\t\tmin: 0,\n\t\torientation: \"horizontal\",\n\t\trange: false,\n\t\tstep: 1,\n\t\tvalue: 0,\n\t\tvalues: null,\n\n\t\t// callbacks\n\t\tchange: null,\n\t\tslide: null,\n\t\tstart: null,\n\t\tstop: null\n\t},\n\n\t_create: function() {\n\t\tthis._keySliding = false;\n\t\tthis._mouseSliding = false;\n\t\tthis._animateOff = true;\n\t\tthis._handleIndex = null;\n\t\tthis._detectOrientation();\n\t\tthis._mouseInit();\n\n\t\tthis.element\n\t\t\t.addClass( \"ui-slider\" +\n\t\t\t\t\" ui-slider-\" + this.orientation +\n\t\t\t\t\" ui-widget\" +\n\t\t\t\t\" ui-widget-content\" +\n\t\t\t\t\" ui-corner-all\");\n\n\t\tthis._refresh();\n\t\tthis._setOption( \"disabled\", this.options.disabled );\n\n\t\tthis._animateOff = false;\n\t},\n\n\t_refresh: function() {\n\t\tthis._createRange();\n\t\tthis._createHandles();\n\t\tthis._setupEvents();\n\t\tthis._refreshValue();\n\t},\n\n\t_createHandles: function() {\n\t\tvar i, handleCount,\n\t\t\toptions = this.options,\n\t\t\texistingHandles = this.element.find( \".ui-slider-handle\" ).addClass( \"ui-state-default ui-corner-all\" ),\n\t\t\thandle = \"<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>\",\n\t\t\thandles = [];\n\n\t\thandleCount = ( options.values && options.values.length ) || 1;\n\n\t\tif ( existingHandles.length > handleCount ) {\n\t\t\texistingHandles.slice( handleCount ).remove();\n\t\t\texistingHandles = existingHandles.slice( 0, handleCount );\n\t\t}\n\n\t\tfor ( i = existingHandles.length; i < handleCount; i++ ) {\n\t\t\thandles.push( handle );\n\t\t}\n\n\t\tthis.handles = existingHandles.add( $( handles.join( \"\" ) ).appendTo( this.element ) );\n\n\t\tthis.handle = this.handles.eq( 0 );\n\n\t\tthis.handles.each(function( i ) {\n\t\t\t$( this ).data( \"ui-slider-handle-index\", i );\n\t\t});\n\t},\n\n\t_createRange: function() {\n\t\tvar options = this.options,\n\t\t\tclasses = \"\";\n\n\t\tif ( options.range ) {\n\t\t\tif ( options.range === true ) {\n\t\t\t\tif ( !options.values ) {\n\t\t\t\t\toptions.values = [ this._valueMin(), this._valueMin() ];\n\t\t\t\t} else if ( options.values.length && options.values.length !== 2 ) {\n\t\t\t\t\toptions.values = [ options.values[0], options.values[0] ];\n\t\t\t\t} else if ( $.isArray( options.values ) ) {\n\t\t\t\t\toptions.values = options.values.slice(0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !this.range || !this.range.length ) {\n\t\t\t\tthis.range = $( \"<div></div>\" )\n\t\t\t\t\t.appendTo( this.element );\n\n\t\t\t\tclasses = \"ui-slider-range\" +\n\t\t\t\t// note: this isn't the most fittingly semantic framework class for this element,\n\t\t\t\t// but worked best visually with a variety of themes\n\t\t\t\t\" ui-widget-header ui-corner-all\";\n\t\t\t} else {\n\t\t\t\tthis.range.removeClass( \"ui-slider-range-min ui-slider-range-max\" )\n\t\t\t\t\t// Handle range switching from true to min/max\n\t\t\t\t\t.css({\n\t\t\t\t\t\t\"left\": \"\",\n\t\t\t\t\t\t\"bottom\": \"\"\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis.range.addClass( classes +\n\t\t\t\t( ( options.range === \"min\" || options.range === \"max\" ) ? \" ui-slider-range-\" + options.range : \"\" ) );\n\t\t} else {\n\t\t\tthis.range = $([]);\n\t\t}\n\t},\n\n\t_setupEvents: function() {\n\t\tvar elements = this.handles.add( this.range ).filter( \"a\" );\n\t\tthis._off( elements );\n\t\tthis._on( elements, this._handleEvents );\n\t\tthis._hoverable( elements );\n\t\tthis._focusable( elements );\n\t},\n\n\t_destroy: function() {\n\t\tthis.handles.remove();\n\t\tthis.range.remove();\n\n\t\tthis.element\n\t\t\t.removeClass( \"ui-slider\" +\n\t\t\t\t\" ui-slider-horizontal\" +\n\t\t\t\t\" ui-slider-vertical\" +\n\t\t\t\t\" ui-widget\" +\n\t\t\t\t\" ui-widget-content\" +\n\t\t\t\t\" ui-corner-all\" );\n\n\t\tthis._mouseDestroy();\n\t},\n\n\t_mouseCapture: function( event ) {\n\t\tvar position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,\n\t\t\tthat = this,\n\t\t\to = this.options;\n\n\t\tif ( o.disabled ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.elementSize = {\n\t\t\twidth: this.element.outerWidth(),\n\t\t\theight: this.element.outerHeight()\n\t\t};\n\t\tthis.elementOffset = this.element.offset();\n\n\t\tposition = { x: event.pageX, y: event.pageY };\n\t\tnormValue = this._normValueFromMouse( position );\n\t\tdistance = this._valueMax() - this._valueMin() + 1;\n\t\tthis.handles.each(function( i ) {\n\t\t\tvar thisDistance = Math.abs( normValue - that.values(i) );\n\t\t\tif (( distance > thisDistance ) ||\n\t\t\t\t( distance === thisDistance &&\n\t\t\t\t\t(i === that._lastChangedValue || that.values(i) === o.min ))) {\n\t\t\t\tdistance = thisDistance;\n\t\t\t\tclosestHandle = $( this );\n\t\t\t\tindex = i;\n\t\t\t}\n\t\t});\n\n\t\tallowed = this._start( event, index );\n\t\tif ( allowed === false ) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._mouseSliding = true;\n\n\t\tthis._handleIndex = index;\n\n\t\tclosestHandle\n\t\t\t.addClass( \"ui-state-active\" )\n\t\t\t.focus();\n\n\t\toffset = closestHandle.offset();\n\t\tmouseOverHandle = !$( event.target ).parents().addBack().is( \".ui-slider-handle\" );\n\t\tthis._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {\n\t\t\tleft: event.pageX - offset.left - ( closestHandle.width() / 2 ),\n\t\t\ttop: event.pageY - offset.top -\n\t\t\t\t( closestHandle.height() / 2 ) -\n\t\t\t\t( parseInt( closestHandle.css(\"borderTopWidth\"), 10 ) || 0 ) -\n\t\t\t\t( parseInt( closestHandle.css(\"borderBottomWidth\"), 10 ) || 0) +\n\t\t\t\t( parseInt( closestHandle.css(\"marginTop\"), 10 ) || 0)\n\t\t};\n\n\t\tif ( !this.handles.hasClass( \"ui-state-hover\" ) ) {\n\t\t\tthis._slide( event, index, normValue );\n\t\t}\n\t\tthis._animateOff = true;\n\t\treturn true;\n\t},\n\n\t_mouseStart: function() {\n\t\treturn true;\n\t},\n\n\t_mouseDrag: function( event ) {\n\t\tvar position = { x: event.pageX, y: event.pageY },\n\t\t\tnormValue = this._normValueFromMouse( position );\n\n\t\tthis._slide( event, this._handleIndex, normValue );\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function( event ) {\n\t\tthis.handles.removeClass( \"ui-state-active\" );\n\t\tthis._mouseSliding = false;\n\n\t\tthis._stop( event, this._handleIndex );\n\t\tthis._change( event, this._handleIndex );\n\n\t\tthis._handleIndex = null;\n\t\tthis._clickOffset = null;\n\t\tthis._animateOff = false;\n\n\t\treturn false;\n\t},\n\n\t_detectOrientation: function() {\n\t\tthis.orientation = ( this.options.orientation === \"vertical\" ) ? \"vertical\" : \"horizontal\";\n\t},\n\n\t_normValueFromMouse: function( position ) {\n\t\tvar pixelTotal,\n\t\t\tpixelMouse,\n\t\t\tpercentMouse,\n\t\t\tvalueTotal,\n\t\t\tvalueMouse;\n\n\t\tif ( this.orientation === \"horizontal\" ) {\n\t\t\tpixelTotal = this.elementSize.width;\n\t\t\tpixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );\n\t\t} else {\n\t\t\tpixelTotal = this.elementSize.height;\n\t\t\tpixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );\n\t\t}\n\n\t\tpercentMouse = ( pixelMouse / pixelTotal );\n\t\tif ( percentMouse > 1 ) {\n\t\t\tpercentMouse = 1;\n\t\t}\n\t\tif ( percentMouse < 0 ) {\n\t\t\tpercentMouse = 0;\n\t\t}\n\t\tif ( this.orientation === \"vertical\" ) {\n\t\t\tpercentMouse = 1 - percentMouse;\n\t\t}\n\n\t\tvalueTotal = this._valueMax() - this._valueMin();\n\t\tvalueMouse = this._valueMin() + percentMouse * valueTotal;\n\n\t\treturn this._trimAlignValue( valueMouse );\n\t},\n\n\t_start: function( event, index ) {\n\t\tvar uiHash = {\n\t\t\thandle: this.handles[ index ],\n\t\t\tvalue: this.value()\n\t\t};\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\tuiHash.value = this.values( index );\n\t\t\tuiHash.values = this.values();\n\t\t}\n\t\treturn this._trigger( \"start\", event, uiHash );\n\t},\n\n\t_slide: function( event, index, newVal ) {\n\t\tvar otherVal,\n\t\t\tnewValues,\n\t\t\tallowed;\n\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\totherVal = this.values( index ? 0 : 1 );\n\n\t\t\tif ( ( this.options.values.length === 2 && this.options.range === true ) &&\n\t\t\t\t\t( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )\n\t\t\t\t) {\n\t\t\t\tnewVal = otherVal;\n\t\t\t}\n\n\t\t\tif ( newVal !== this.values( index ) ) {\n\t\t\t\tnewValues = this.values();\n\t\t\t\tnewValues[ index ] = newVal;\n\t\t\t\t// A slide can be canceled by returning false from the slide callback\n\t\t\t\tallowed = this._trigger( \"slide\", event, {\n\t\t\t\t\thandle: this.handles[ index ],\n\t\t\t\t\tvalue: newVal,\n\t\t\t\t\tvalues: newValues\n\t\t\t\t} );\n\t\t\t\totherVal = this.values( index ? 0 : 1 );\n\t\t\t\tif ( allowed !== false ) {\n\t\t\t\t\tthis.values( index, newVal, true );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif ( newVal !== this.value() ) {\n\t\t\t\t// A slide can be canceled by returning false from the slide callback\n\t\t\t\tallowed = this._trigger( \"slide\", event, {\n\t\t\t\t\thandle: this.handles[ index ],\n\t\t\t\t\tvalue: newVal\n\t\t\t\t} );\n\t\t\t\tif ( allowed !== false ) {\n\t\t\t\t\tthis.value( newVal );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_stop: function( event, index ) {\n\t\tvar uiHash = {\n\t\t\thandle: this.handles[ index ],\n\t\t\tvalue: this.value()\n\t\t};\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\tuiHash.value = this.values( index );\n\t\t\tuiHash.values = this.values();\n\t\t}\n\n\t\tthis._trigger( \"stop\", event, uiHash );\n\t},\n\n\t_change: function( event, index ) {\n\t\tif ( !this._keySliding && !this._mouseSliding ) {\n\t\t\tvar uiHash = {\n\t\t\t\thandle: this.handles[ index ],\n\t\t\t\tvalue: this.value()\n\t\t\t};\n\t\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\t\tuiHash.value = this.values( index );\n\t\t\t\tuiHash.values = this.values();\n\t\t\t}\n\n\t\t\t//store the last changed value index for reference when handles overlap\n\t\t\tthis._lastChangedValue = index;\n\n\t\t\tthis._trigger( \"change\", event, uiHash );\n\t\t}\n\t},\n\n\tvalue: function( newValue ) {\n\t\tif ( arguments.length ) {\n\t\t\tthis.options.value = this._trimAlignValue( newValue );\n\t\t\tthis._refreshValue();\n\t\t\tthis._change( null, 0 );\n\t\t\treturn;\n\t\t}\n\n\t\treturn this._value();\n\t},\n\n\tvalues: function( index, newValue ) {\n\t\tvar vals,\n\t\t\tnewValues,\n\t\t\ti;\n\n\t\tif ( arguments.length > 1 ) {\n\t\t\tthis.options.values[ index ] = this._trimAlignValue( newValue );\n\t\t\tthis._refreshValue();\n\t\t\tthis._change( null, index );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( arguments.length ) {\n\t\t\tif ( $.isArray( arguments[ 0 ] ) ) {\n\t\t\t\tvals = this.options.values;\n\t\t\t\tnewValues = arguments[ 0 ];\n\t\t\t\tfor ( i = 0; i < vals.length; i += 1 ) {\n\t\t\t\t\tvals[ i ] = this._trimAlignValue( newValues[ i ] );\n\t\t\t\t\tthis._change( null, i );\n\t\t\t\t}\n\t\t\t\tthis._refreshValue();\n\t\t\t} else {\n\t\t\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\t\t\treturn this._values( index );\n\t\t\t\t} else {\n\t\t\t\t\treturn this.value();\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn this._values();\n\t\t}\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tvar i,\n\t\t\tvalsLength = 0;\n\n\t\tif ( key === \"range\" && this.options.range === true ) {\n\t\t\tif ( value === \"min\" ) {\n\t\t\t\tthis.options.value = this._values( 0 );\n\t\t\t\tthis.options.values = null;\n\t\t\t} else if ( value === \"max\" ) {\n\t\t\t\tthis.options.value = this._values( this.options.values.length-1 );\n\t\t\t\tthis.options.values = null;\n\t\t\t}\n\t\t}\n\n\t\tif ( $.isArray( this.options.values ) ) {\n\t\t\tvalsLength = this.options.values.length;\n\t\t}\n\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\n\t\tswitch ( key ) {\n\t\t\tcase \"orientation\":\n\t\t\t\tthis._detectOrientation();\n\t\t\t\tthis.element\n\t\t\t\t\t.removeClass( \"ui-slider-horizontal ui-slider-vertical\" )\n\t\t\t\t\t.addClass( \"ui-slider-\" + this.orientation );\n\t\t\t\tthis._refreshValue();\n\t\t\t\tbreak;\n\t\t\tcase \"value\":\n\t\t\t\tthis._animateOff = true;\n\t\t\t\tthis._refreshValue();\n\t\t\t\tthis._change( null, 0 );\n\t\t\t\tthis._animateOff = false;\n\t\t\t\tbreak;\n\t\t\tcase \"values\":\n\t\t\t\tthis._animateOff = true;\n\t\t\t\tthis._refreshValue();\n\t\t\t\tfor ( i = 0; i < valsLength; i += 1 ) {\n\t\t\t\t\tthis._change( null, i );\n\t\t\t\t}\n\t\t\t\tthis._animateOff = false;\n\t\t\t\tbreak;\n\t\t\tcase \"min\":\n\t\t\tcase \"max\":\n\t\t\t\tthis._animateOff = true;\n\t\t\t\tthis._refreshValue();\n\t\t\t\tthis._animateOff = false;\n\t\t\t\tbreak;\n\t\t\tcase \"range\":\n\t\t\t\tthis._animateOff = true;\n\t\t\t\tthis._refresh();\n\t\t\t\tthis._animateOff = false;\n\t\t\t\tbreak;\n\t\t}\n\t},\n\n\t//internal value getter\n\t// _value() returns value trimmed by min and max, aligned by step\n\t_value: function() {\n\t\tvar val = this.options.value;\n\t\tval = this._trimAlignValue( val );\n\n\t\treturn val;\n\t},\n\n\t//internal values getter\n\t// _values() returns array of values trimmed by min and max, aligned by step\n\t// _values( index ) returns single value trimmed by min and max, aligned by step\n\t_values: function( index ) {\n\t\tvar val,\n\t\t\tvals,\n\t\t\ti;\n\n\t\tif ( arguments.length ) {\n\t\t\tval = this.options.values[ index ];\n\t\t\tval = this._trimAlignValue( val );\n\n\t\t\treturn val;\n\t\t} else if ( this.options.values && this.options.values.length ) {\n\t\t\t// .slice() creates a copy of the array\n\t\t\t// this copy gets trimmed by min and max and then returned\n\t\t\tvals = this.options.values.slice();\n\t\t\tfor ( i = 0; i < vals.length; i+= 1) {\n\t\t\t\tvals[ i ] = this._trimAlignValue( vals[ i ] );\n\t\t\t}\n\n\t\t\treturn vals;\n\t\t} else {\n\t\t\treturn [];\n\t\t}\n\t},\n\n\t// returns the step-aligned value that val is closest to, between (inclusive) min and max\n\t_trimAlignValue: function( val ) {\n\t\tif ( val <= this._valueMin() ) {\n\t\t\treturn this._valueMin();\n\t\t}\n\t\tif ( val >= this._valueMax() ) {\n\t\t\treturn this._valueMax();\n\t\t}\n\t\tvar step = ( this.options.step > 0 ) ? this.options.step : 1,\n\t\t\tvalModStep = (val - this._valueMin()) % step,\n\t\t\talignValue = val - valModStep;\n\n\t\tif ( Math.abs(valModStep) * 2 >= step ) {\n\t\t\talignValue += ( valModStep > 0 ) ? step : ( -step );\n\t\t}\n\n\t\t// Since JavaScript has problems with large floats, round\n\t\t// the final value to 5 digits after the decimal point (see #4124)\n\t\treturn parseFloat( alignValue.toFixed(5) );\n\t},\n\n\t_valueMin: function() {\n\t\treturn this.options.min;\n\t},\n\n\t_valueMax: function() {\n\t\treturn this.options.max;\n\t},\n\n\t_refreshValue: function() {\n\t\tvar lastValPercent, valPercent, value, valueMin, valueMax,\n\t\t\toRange = this.options.range,\n\t\t\to = this.options,\n\t\t\tthat = this,\n\t\t\tanimate = ( !this._animateOff ) ? o.animate : false,\n\t\t\t_set = {};\n\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\tthis.handles.each(function( i ) {\n\t\t\t\tvalPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;\n\t\t\t\t_set[ that.orientation === \"horizontal\" ? \"left\" : \"bottom\" ] = valPercent + \"%\";\n\t\t\t\t$( this ).stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( _set, o.animate );\n\t\t\t\tif ( that.options.range === true ) {\n\t\t\t\t\tif ( that.orientation === \"horizontal\" ) {\n\t\t\t\t\t\tif ( i === 0 ) {\n\t\t\t\t\t\t\tthat.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { left: valPercent + \"%\" }, o.animate );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( i === 1 ) {\n\t\t\t\t\t\t\tthat.range[ animate ? \"animate\" : \"css\" ]( { width: ( valPercent - lastValPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( i === 0 ) {\n\t\t\t\t\t\t\tthat.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { bottom: ( valPercent ) + \"%\" }, o.animate );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( i === 1 ) {\n\t\t\t\t\t\t\tthat.range[ animate ? \"animate\" : \"css\" ]( { height: ( valPercent - lastValPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastValPercent = valPercent;\n\t\t\t});\n\t\t} else {\n\t\t\tvalue = this.value();\n\t\t\tvalueMin = this._valueMin();\n\t\t\tvalueMax = this._valueMax();\n\t\t\tvalPercent = ( valueMax !== valueMin ) ?\n\t\t\t\t\t( value - valueMin ) / ( valueMax - valueMin ) * 100 :\n\t\t\t\t\t0;\n\t\t\t_set[ this.orientation === \"horizontal\" ? \"left\" : \"bottom\" ] = valPercent + \"%\";\n\t\t\tthis.handle.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( _set, o.animate );\n\n\t\t\tif ( oRange === \"min\" && this.orientation === \"horizontal\" ) {\n\t\t\t\tthis.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { width: valPercent + \"%\" }, o.animate );\n\t\t\t}\n\t\t\tif ( oRange === \"max\" && this.orientation === \"horizontal\" ) {\n\t\t\t\tthis.range[ animate ? \"animate\" : \"css\" ]( { width: ( 100 - valPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t}\n\t\t\tif ( oRange === \"min\" && this.orientation === \"vertical\" ) {\n\t\t\t\tthis.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { height: valPercent + \"%\" }, o.animate );\n\t\t\t}\n\t\t\tif ( oRange === \"max\" && this.orientation === \"vertical\" ) {\n\t\t\t\tthis.range[ animate ? \"animate\" : \"css\" ]( { height: ( 100 - valPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t}\n\t\t}\n\t},\n\n\t_handleEvents: {\n\t\tkeydown: function( event ) {\n\t\t\t/*jshint maxcomplexity:25*/\n\t\t\tvar allowed, curVal, newVal, step,\n\t\t\t\tindex = $( event.target ).data( \"ui-slider-handle-index\" );\n\n\t\t\tswitch ( event.keyCode ) {\n\t\t\t\tcase $.ui.keyCode.HOME:\n\t\t\t\tcase $.ui.keyCode.END:\n\t\t\t\tcase $.ui.keyCode.PAGE_UP:\n\t\t\t\tcase $.ui.keyCode.PAGE_DOWN:\n\t\t\t\tcase $.ui.keyCode.UP:\n\t\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tif ( !this._keySliding ) {\n\t\t\t\t\t\tthis._keySliding = true;\n\t\t\t\t\t\t$( event.target ).addClass( \"ui-state-active\" );\n\t\t\t\t\t\tallowed = this._start( event, index );\n\t\t\t\t\t\tif ( allowed === false ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tstep = this.options.step;\n\t\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\t\tcurVal = newVal = this.values( index );\n\t\t\t} else {\n\t\t\t\tcurVal = newVal = this.value();\n\t\t\t}\n\n\t\t\tswitch ( event.keyCode ) {\n\t\t\t\tcase $.ui.keyCode.HOME:\n\t\t\t\t\tnewVal = this._valueMin();\n\t\t\t\t\tbreak;\n\t\t\t\tcase $.ui.keyCode.END:\n\t\t\t\t\tnewVal = this._valueMax();\n\t\t\t\t\tbreak;\n\t\t\t\tcase $.ui.keyCode.PAGE_UP:\n\t\t\t\t\tnewVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );\n\t\t\t\t\tbreak;\n\t\t\t\tcase $.ui.keyCode.PAGE_DOWN:\n\t\t\t\t\tnewVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );\n\t\t\t\t\tbreak;\n\t\t\t\tcase $.ui.keyCode.UP:\n\t\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\t\t\tif ( curVal === this._valueMax() ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tnewVal = this._trimAlignValue( curVal + step );\n\t\t\t\t\tbreak;\n\t\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\t\tif ( curVal === this._valueMin() ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tnewVal = this._trimAlignValue( curVal - step );\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthis._slide( event, index, newVal );\n\t\t},\n\t\tclick: function( event ) {\n\t\t\tevent.preventDefault();\n\t\t},\n\t\tkeyup: function( event ) {\n\t\t\tvar index = $( event.target ).data( \"ui-slider-handle-index\" );\n\n\t\t\tif ( this._keySliding ) {\n\t\t\t\tthis._keySliding = false;\n\t\t\t\tthis._stop( event, index );\n\t\t\t\tthis._change( event, index );\n\t\t\t\t$( event.target ).removeClass( \"ui-state-active\" );\n\t\t\t}\n\t\t}\n\t}\n\n});\n\n}(jQuery));\n\n(function( $ ) {\n\nfunction modifier( fn ) {\n\treturn function() {\n\t\tvar previous = this.element.val();\n\t\tfn.apply( this, arguments );\n\t\tthis._refresh();\n\t\tif ( previous !== this.element.val() ) {\n\t\t\tthis._trigger( \"change\" );\n\t\t}\n\t};\n}\n\n$.widget( \"ui.spinner\", {\n\tversion: \"1.10.1\",\n\tdefaultElement: \"<input>\",\n\twidgetEventPrefix: \"spin\",\n\toptions: {\n\t\tculture: null,\n\t\ticons: {\n\t\t\tdown: \"ui-icon-triangle-1-s\",\n\t\t\tup: \"ui-icon-triangle-1-n\"\n\t\t},\n\t\tincremental: true,\n\t\tmax: null,\n\t\tmin: null,\n\t\tnumberFormat: null,\n\t\tpage: 10,\n\t\tstep: 1,\n\n\t\tchange: null,\n\t\tspin: null,\n\t\tstart: null,\n\t\tstop: null\n\t},\n\n\t_create: function() {\n\t\t// handle string values that need to be parsed\n\t\tthis._setOption( \"max\", this.options.max );\n\t\tthis._setOption( \"min\", this.options.min );\n\t\tthis._setOption( \"step\", this.options.step );\n\n\t\t// format the value, but don't constrain\n\t\tthis._value( this.element.val(), true );\n\n\t\tthis._draw();\n\t\tthis._on( this._events );\n\t\tthis._refresh();\n\n\t\t// turning off autocomplete prevents the browser from remembering the\n\t\t// value when navigating through history, so we re-enable autocomplete\n\t\t// if the page is unloaded before the widget is destroyed. #7790\n\t\tthis._on( this.window, {\n\t\t\tbeforeunload: function() {\n\t\t\t\tthis.element.removeAttr( \"autocomplete\" );\n\t\t\t}\n\t\t});\n\t},\n\n\t_getCreateOptions: function() {\n\t\tvar options = {},\n\t\t\telement = this.element;\n\n\t\t$.each( [ \"min\", \"max\", \"step\" ], function( i, option ) {\n\t\t\tvar value = element.attr( option );\n\t\t\tif ( value !== undefined && value.length ) {\n\t\t\t\toptions[ option ] = value;\n\t\t\t}\n\t\t});\n\n\t\treturn options;\n\t},\n\n\t_events: {\n\t\tkeydown: function( event ) {\n\t\t\tif ( this._start( event ) && this._keydown( event ) ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t},\n\t\tkeyup: \"_stop\",\n\t\tfocus: function() {\n\t\t\tthis.previous = this.element.val();\n\t\t},\n\t\tblur: function( event ) {\n\t\t\tif ( this.cancelBlur ) {\n\t\t\t\tdelete this.cancelBlur;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._refresh();\n\t\t\tif ( this.previous !== this.element.val() ) {\n\t\t\t\tthis._trigger( \"change\", event );\n\t\t\t}\n\t\t},\n\t\tmousewheel: function( event, delta ) {\n\t\t\tif ( !delta ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( !this.spinning && !this._start( event ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._spin( (delta > 0 ? 1 : -1) * this.options.step, event );\n\t\t\tclearTimeout( this.mousewheelTimer );\n\t\t\tthis.mousewheelTimer = this._delay(function() {\n\t\t\t\tif ( this.spinning ) {\n\t\t\t\t\tthis._stop( event );\n\t\t\t\t}\n\t\t\t}, 100 );\n\t\t\tevent.preventDefault();\n\t\t},\n\t\t\"mousedown .ui-spinner-button\": function( event ) {\n\t\t\tvar previous;\n\n\t\t\t// We never want the buttons to have focus; whenever the user is\n\t\t\t// interacting with the spinner, the focus should be on the input.\n\t\t\t// If the input is focused then this.previous is properly set from\n\t\t\t// when the input first received focus. If the input is not focused\n\t\t\t// then we need to set this.previous based on the value before spinning.\n\t\t\tprevious = this.element[0] === this.document[0].activeElement ?\n\t\t\t\tthis.previous : this.element.val();\n\t\t\tfunction checkFocus() {\n\t\t\t\tvar isActive = this.element[0] === this.document[0].activeElement;\n\t\t\t\tif ( !isActive ) {\n\t\t\t\t\tthis.element.focus();\n\t\t\t\t\tthis.previous = previous;\n\t\t\t\t\t// support: IE\n\t\t\t\t\t// IE sets focus asynchronously, so we need to check if focus\n\t\t\t\t\t// moved off of the input because the user clicked on the button.\n\t\t\t\t\tthis._delay(function() {\n\t\t\t\t\t\tthis.previous = previous;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ensure focus is on (or stays on) the text field\n\t\t\tevent.preventDefault();\n\t\t\tcheckFocus.call( this );\n\n\t\t\t// support: IE\n\t\t\t// IE doesn't prevent moving focus even with event.preventDefault()\n\t\t\t// so we set a flag to know when we should ignore the blur event\n\t\t\t// and check (again) if focus moved off of the input.\n\t\t\tthis.cancelBlur = true;\n\t\t\tthis._delay(function() {\n\t\t\t\tdelete this.cancelBlur;\n\t\t\t\tcheckFocus.call( this );\n\t\t\t});\n\n\t\t\tif ( this._start( event ) === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._repeat( null, $( event.currentTarget ).hasClass( \"ui-spinner-up\" ) ? 1 : -1, event );\n\t\t},\n\t\t\"mouseup .ui-spinner-button\": \"_stop\",\n\t\t\"mouseenter .ui-spinner-button\": function( event ) {\n\t\t\t// button will add ui-state-active if mouse was down while mouseleave and kept down\n\t\t\tif ( !$( event.currentTarget ).hasClass( \"ui-state-active\" ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( this._start( event ) === false ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis._repeat( null, $( event.currentTarget ).hasClass( \"ui-spinner-up\" ) ? 1 : -1, event );\n\t\t},\n\t\t// TODO: do we really want to consider this a stop?\n\t\t// shouldn't we just stop the repeater and wait until mouseup before\n\t\t// we trigger the stop event?\n\t\t\"mouseleave .ui-spinner-button\": \"_stop\"\n\t},\n\n\t_draw: function() {\n\t\tvar uiSpinner = this.uiSpinner = this.element\n\t\t\t.addClass( \"ui-spinner-input\" )\n\t\t\t.attr( \"autocomplete\", \"off\" )\n\t\t\t.wrap( this._uiSpinnerHtml() )\n\t\t\t.parent()\n\t\t\t\t// add buttons\n\t\t\t\t.append( this._buttonHtml() );\n\n\t\tthis.element.attr( \"role\", \"spinbutton\" );\n\n\t\t// button bindings\n\t\tthis.buttons = uiSpinner.find( \".ui-spinner-button\" )\n\t\t\t.attr( \"tabIndex\", -1 )\n\t\t\t.button()\n\t\t\t.removeClass( \"ui-corner-all\" );\n\n\t\t// IE 6 doesn't understand height: 50% for the buttons\n\t\t// unless the wrapper has an explicit height\n\t\tif ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&\n\t\t\t\tuiSpinner.height() > 0 ) {\n\t\t\tuiSpinner.height( uiSpinner.height() );\n\t\t}\n\n\t\t// disable spinner if element was already disabled\n\t\tif ( this.options.disabled ) {\n\t\t\tthis.disable();\n\t\t}\n\t},\n\n\t_keydown: function( event ) {\n\t\tvar options = this.options,\n\t\t\tkeyCode = $.ui.keyCode;\n\n\t\tswitch ( event.keyCode ) {\n\t\tcase keyCode.UP:\n\t\t\tthis._repeat( null, 1, event );\n\t\t\treturn true;\n\t\tcase keyCode.DOWN:\n\t\t\tthis._repeat( null, -1, event );\n\t\t\treturn true;\n\t\tcase keyCode.PAGE_UP:\n\t\t\tthis._repeat( null, options.page, event );\n\t\t\treturn true;\n\t\tcase keyCode.PAGE_DOWN:\n\t\t\tthis._repeat( null, -options.page, event );\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_uiSpinnerHtml: function() {\n\t\treturn \"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>\";\n\t},\n\n\t_buttonHtml: function() {\n\t\treturn \"\" +\n\t\t\t\"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>\" +\n\t\t\t\t\"<span class='ui-icon \" + this.options.icons.up + \"'>&#9650;</span>\" +\n\t\t\t\"</a>\" +\n\t\t\t\"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>\" +\n\t\t\t\t\"<span class='ui-icon \" + this.options.icons.down + \"'>&#9660;</span>\" +\n\t\t\t\"</a>\";\n\t},\n\n\t_start: function( event ) {\n\t\tif ( !this.spinning && this._trigger( \"start\", event ) === false ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !this.counter ) {\n\t\t\tthis.counter = 1;\n\t\t}\n\t\tthis.spinning = true;\n\t\treturn true;\n\t},\n\n\t_repeat: function( i, steps, event ) {\n\t\ti = i || 500;\n\n\t\tclearTimeout( this.timer );\n\t\tthis.timer = this._delay(function() {\n\t\t\tthis._repeat( 40, steps, event );\n\t\t}, i );\n\n\t\tthis._spin( steps * this.options.step, event );\n\t},\n\n\t_spin: function( step, event ) {\n\t\tvar value = this.value() || 0;\n\n\t\tif ( !this.counter ) {\n\t\t\tthis.counter = 1;\n\t\t}\n\n\t\tvalue = this._adjustValue( value + step * this._increment( this.counter ) );\n\n\t\tif ( !this.spinning || this._trigger( \"spin\", event, { value: value } ) !== false) {\n\t\t\tthis._value( value );\n\t\t\tthis.counter++;\n\t\t}\n\t},\n\n\t_increment: function( i ) {\n\t\tvar incremental = this.options.incremental;\n\n\t\tif ( incremental ) {\n\t\t\treturn $.isFunction( incremental ) ?\n\t\t\t\tincremental( i ) :\n\t\t\t\tMath.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );\n\t\t}\n\n\t\treturn 1;\n\t},\n\n\t_precision: function() {\n\t\tvar precision = this._precisionOf( this.options.step );\n\t\tif ( this.options.min !== null ) {\n\t\t\tprecision = Math.max( precision, this._precisionOf( this.options.min ) );\n\t\t}\n\t\treturn precision;\n\t},\n\n\t_precisionOf: function( num ) {\n\t\tvar str = num.toString(),\n\t\t\tdecimal = str.indexOf( \".\" );\n\t\treturn decimal === -1 ? 0 : str.length - decimal - 1;\n\t},\n\n\t_adjustValue: function( value ) {\n\t\tvar base, aboveMin,\n\t\t\toptions = this.options;\n\n\t\t// make sure we're at a valid step\n\t\t// - find out where we are relative to the base (min or 0)\n\t\tbase = options.min !== null ? options.min : 0;\n\t\taboveMin = value - base;\n\t\t// - round to the nearest step\n\t\taboveMin = Math.round(aboveMin / options.step) * options.step;\n\t\t// - rounding is based on 0, so adjust back to our base\n\t\tvalue = base + aboveMin;\n\n\t\t// fix precision from bad JS floating point math\n\t\tvalue = parseFloat( value.toFixed( this._precision() ) );\n\n\t\t// clamp the value\n\t\tif ( options.max !== null && value > options.max) {\n\t\t\treturn options.max;\n\t\t}\n\t\tif ( options.min !== null && value < options.min ) {\n\t\t\treturn options.min;\n\t\t}\n\n\t\treturn value;\n\t},\n\n\t_stop: function( event ) {\n\t\tif ( !this.spinning ) {\n\t\t\treturn;\n\t\t}\n\n\t\tclearTimeout( this.timer );\n\t\tclearTimeout( this.mousewheelTimer );\n\t\tthis.counter = 0;\n\t\tthis.spinning = false;\n\t\tthis._trigger( \"stop\", event );\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"culture\" || key === \"numberFormat\" ) {\n\t\t\tvar prevValue = this._parse( this.element.val() );\n\t\t\tthis.options[ key ] = value;\n\t\t\tthis.element.val( this._format( prevValue ) );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key === \"max\" || key === \"min\" || key === \"step\" ) {\n\t\t\tif ( typeof value === \"string\" ) {\n\t\t\t\tvalue = this._parse( value );\n\t\t\t}\n\t\t}\n\t\tif ( key === \"icons\" ) {\n\t\t\tthis.buttons.first().find( \".ui-icon\" )\n\t\t\t\t.removeClass( this.options.icons.up )\n\t\t\t\t.addClass( value.up );\n\t\t\tthis.buttons.last().find( \".ui-icon\" )\n\t\t\t\t.removeClass( this.options.icons.down )\n\t\t\t\t.addClass( value.down );\n\t\t}\n\n\t\tthis._super( key, value );\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\tif ( value ) {\n\t\t\t\tthis.element.prop( \"disabled\", true );\n\t\t\t\tthis.buttons.button( \"disable\" );\n\t\t\t} else {\n\t\t\t\tthis.element.prop( \"disabled\", false );\n\t\t\t\tthis.buttons.button( \"enable\" );\n\t\t\t}\n\t\t}\n\t},\n\n\t_setOptions: modifier(function( options ) {\n\t\tthis._super( options );\n\t\tthis._value( this.element.val() );\n\t}),\n\n\t_parse: function( val ) {\n\t\tif ( typeof val === \"string\" && val !== \"\" ) {\n\t\t\tval = window.Globalize && this.options.numberFormat ?\n\t\t\t\tGlobalize.parseFloat( val, 10, this.options.culture ) : +val;\n\t\t}\n\t\treturn val === \"\" || isNaN( val ) ? null : val;\n\t},\n\n\t_format: function( value ) {\n\t\tif ( value === \"\" ) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn window.Globalize && this.options.numberFormat ?\n\t\t\tGlobalize.format( value, this.options.numberFormat, this.options.culture ) :\n\t\t\tvalue;\n\t},\n\n\t_refresh: function() {\n\t\tthis.element.attr({\n\t\t\t\"aria-valuemin\": this.options.min,\n\t\t\t\"aria-valuemax\": this.options.max,\n\t\t\t// TODO: what should we do with values that can't be parsed?\n\t\t\t\"aria-valuenow\": this._parse( this.element.val() )\n\t\t});\n\t},\n\n\t// update the value without triggering change\n\t_value: function( value, allowAny ) {\n\t\tvar parsed;\n\t\tif ( value !== \"\" ) {\n\t\t\tparsed = this._parse( value );\n\t\t\tif ( parsed !== null ) {\n\t\t\t\tif ( !allowAny ) {\n\t\t\t\t\tparsed = this._adjustValue( parsed );\n\t\t\t\t}\n\t\t\t\tvalue = this._format( parsed );\n\t\t\t}\n\t\t}\n\t\tthis.element.val( value );\n\t\tthis._refresh();\n\t},\n\n\t_destroy: function() {\n\t\tthis.element\n\t\t\t.removeClass( \"ui-spinner-input\" )\n\t\t\t.prop( \"disabled\", false )\n\t\t\t.removeAttr( \"autocomplete\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-valuemin\" )\n\t\t\t.removeAttr( \"aria-valuemax\" )\n\t\t\t.removeAttr( \"aria-valuenow\" );\n\t\tthis.uiSpinner.replaceWith( this.element );\n\t},\n\n\tstepUp: modifier(function( steps ) {\n\t\tthis._stepUp( steps );\n\t}),\n\t_stepUp: function( steps ) {\n\t\tif ( this._start() ) {\n\t\t\tthis._spin( (steps || 1) * this.options.step );\n\t\t\tthis._stop();\n\t\t}\n\t},\n\n\tstepDown: modifier(function( steps ) {\n\t\tthis._stepDown( steps );\n\t}),\n\t_stepDown: function( steps ) {\n\t\tif ( this._start() ) {\n\t\t\tthis._spin( (steps || 1) * -this.options.step );\n\t\t\tthis._stop();\n\t\t}\n\t},\n\n\tpageUp: modifier(function( pages ) {\n\t\tthis._stepUp( (pages || 1) * this.options.page );\n\t}),\n\n\tpageDown: modifier(function( pages ) {\n\t\tthis._stepDown( (pages || 1) * this.options.page );\n\t}),\n\n\tvalue: function( newVal ) {\n\t\tif ( !arguments.length ) {\n\t\t\treturn this._parse( this.element.val() );\n\t\t}\n\t\tmodifier( this._value ).call( this, newVal );\n\t},\n\n\twidget: function() {\n\t\treturn this.uiSpinner;\n\t}\n});\n\n}( jQuery ) );\n\n(function( $, undefined ) {\n\nvar tabId = 0,\n\trhash = /#.*$/;\n\nfunction getNextTabId() {\n\treturn ++tabId;\n}\n\nfunction isLocal( anchor ) {\n\treturn anchor.hash.length > 1 &&\n\t\tdecodeURIComponent( anchor.href.replace( rhash, \"\" ) ) ===\n\t\t\tdecodeURIComponent( location.href.replace( rhash, \"\" ) );\n}\n\n$.widget( \"ui.tabs\", {\n\tversion: \"1.10.1\",\n\tdelay: 300,\n\toptions: {\n\t\tactive: null,\n\t\tcollapsible: false,\n\t\tevent: \"click\",\n\t\theightStyle: \"content\",\n\t\thide: null,\n\t\tshow: null,\n\n\t\t// callbacks\n\t\tactivate: null,\n\t\tbeforeActivate: null,\n\t\tbeforeLoad: null,\n\t\tload: null\n\t},\n\n\t_create: function() {\n\t\tvar that = this,\n\t\t\toptions = this.options;\n\n\t\tthis.running = false;\n\n\t\tthis.element\n\t\t\t.addClass( \"ui-tabs ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.toggleClass( \"ui-tabs-collapsible\", options.collapsible )\n\t\t\t// Prevent users from focusing disabled tabs via click\n\t\t\t.delegate( \".ui-tabs-nav > li\", \"mousedown\" + this.eventNamespace, function( event ) {\n\t\t\t\tif ( $( this ).is( \".ui-state-disabled\" ) ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t})\n\t\t\t// support: IE <9\n\t\t\t// Preventing the default action in mousedown doesn't prevent IE\n\t\t\t// from focusing the element, so if the anchor gets focused, blur.\n\t\t\t// We don't have to worry about focusing the previously focused\n\t\t\t// element since clicking on a non-focusable element should focus\n\t\t\t// the body anyway.\n\t\t\t.delegate( \".ui-tabs-anchor\", \"focus\" + this.eventNamespace, function() {\n\t\t\t\tif ( $( this ).closest( \"li\" ).is( \".ui-state-disabled\" ) ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t}\n\t\t\t});\n\n\t\tthis._processTabs();\n\t\toptions.active = this._initialActive();\n\n\t\t// Take disabling tabs via class attribute from HTML\n\t\t// into account and update option properly.\n\t\tif ( $.isArray( options.disabled ) ) {\n\t\t\toptions.disabled = $.unique( options.disabled.concat(\n\t\t\t\t$.map( this.tabs.filter( \".ui-state-disabled\" ), function( li ) {\n\t\t\t\t\treturn that.tabs.index( li );\n\t\t\t\t})\n\t\t\t) ).sort();\n\t\t}\n\n\t\t// check for length avoids error when initializing empty list\n\t\tif ( this.options.active !== false && this.anchors.length ) {\n\t\t\tthis.active = this._findActive( options.active );\n\t\t} else {\n\t\t\tthis.active = $();\n\t\t}\n\n\t\tthis._refresh();\n\n\t\tif ( this.active.length ) {\n\t\t\tthis.load( options.active );\n\t\t}\n\t},\n\n\t_initialActive: function() {\n\t\tvar active = this.options.active,\n\t\t\tcollapsible = this.options.collapsible,\n\t\t\tlocationHash = location.hash.substring( 1 );\n\n\t\tif ( active === null ) {\n\t\t\t// check the fragment identifier in the URL\n\t\t\tif ( locationHash ) {\n\t\t\t\tthis.tabs.each(function( i, tab ) {\n\t\t\t\t\tif ( $( tab ).attr( \"aria-controls\" ) === locationHash ) {\n\t\t\t\t\t\tactive = i;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// check for a tab marked active via a class\n\t\t\tif ( active === null ) {\n\t\t\t\tactive = this.tabs.index( this.tabs.filter( \".ui-tabs-active\" ) );\n\t\t\t}\n\n\t\t\t// no active tab, set to false\n\t\t\tif ( active === null || active === -1 ) {\n\t\t\t\tactive = this.tabs.length ? 0 : false;\n\t\t\t}\n\t\t}\n\n\t\t// handle numbers: negative, out of range\n\t\tif ( active !== false ) {\n\t\t\tactive = this.tabs.index( this.tabs.eq( active ) );\n\t\t\tif ( active === -1 ) {\n\t\t\t\tactive = collapsible ? false : 0;\n\t\t\t}\n\t\t}\n\n\t\t// don't allow collapsible: false and active: false\n\t\tif ( !collapsible && active === false && this.anchors.length ) {\n\t\t\tactive = 0;\n\t\t}\n\n\t\treturn active;\n\t},\n\n\t_getCreateEventData: function() {\n\t\treturn {\n\t\t\ttab: this.active,\n\t\t\tpanel: !this.active.length ? $() : this._getPanelForTab( this.active )\n\t\t};\n\t},\n\n\t_tabKeydown: function( event ) {\n\t\t/*jshint maxcomplexity:15*/\n\t\tvar focusedTab = $( this.document[0].activeElement ).closest( \"li\" ),\n\t\t\tselectedIndex = this.tabs.index( focusedTab ),\n\t\t\tgoingForward = true;\n\n\t\tif ( this._handlePageNav( event ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch ( event.keyCode ) {\n\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\tselectedIndex++;\n\t\t\t\tbreak;\n\t\t\tcase $.ui.keyCode.UP:\n\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\tgoingForward = false;\n\t\t\t\tselectedIndex--;\n\t\t\t\tbreak;\n\t\t\tcase $.ui.keyCode.END:\n\t\t\t\tselectedIndex = this.anchors.length - 1;\n\t\t\t\tbreak;\n\t\t\tcase $.ui.keyCode.HOME:\n\t\t\t\tselectedIndex = 0;\n\t\t\t\tbreak;\n\t\t\tcase $.ui.keyCode.SPACE:\n\t\t\t\t// Activate only, no collapsing\n\t\t\t\tevent.preventDefault();\n\t\t\t\tclearTimeout( this.activating );\n\t\t\t\tthis._activate( selectedIndex );\n\t\t\t\treturn;\n\t\t\tcase $.ui.keyCode.ENTER:\n\t\t\t\t// Toggle (cancel delayed activation, allow collapsing)\n\t\t\t\tevent.preventDefault();\n\t\t\t\tclearTimeout( this.activating );\n\t\t\t\t// Determine if we should collapse or activate\n\t\t\t\tthis._activate( selectedIndex === this.options.active ? false : selectedIndex );\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\treturn;\n\t\t}\n\n\t\t// Focus the appropriate tab, based on which key was pressed\n\t\tevent.preventDefault();\n\t\tclearTimeout( this.activating );\n\t\tselectedIndex = this._focusNextTab( selectedIndex, goingForward );\n\n\t\t// Navigating with control key will prevent automatic activation\n\t\tif ( !event.ctrlKey ) {\n\t\t\t// Update aria-selected immediately so that AT think the tab is already selected.\n\t\t\t// Otherwise AT may confuse the user by stating that they need to activate the tab,\n\t\t\t// but the tab will already be activated by the time the announcement finishes.\n\t\t\tfocusedTab.attr( \"aria-selected\", \"false\" );\n\t\t\tthis.tabs.eq( selectedIndex ).attr( \"aria-selected\", \"true\" );\n\n\t\t\tthis.activating = this._delay(function() {\n\t\t\t\tthis.option( \"active\", selectedIndex );\n\t\t\t}, this.delay );\n\t\t}\n\t},\n\n\t_panelKeydown: function( event ) {\n\t\tif ( this._handlePageNav( event ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+up moves focus to the current tab\n\t\tif ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {\n\t\t\tevent.preventDefault();\n\t\t\tthis.active.focus();\n\t\t}\n\t},\n\n\t// Alt+page up/down moves focus to the previous/next tab (and activates)\n\t_handlePageNav: function( event ) {\n\t\tif ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {\n\t\t\tthis._activate( this._focusNextTab( this.options.active - 1, false ) );\n\t\t\treturn true;\n\t\t}\n\t\tif ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {\n\t\t\tthis._activate( this._focusNextTab( this.options.active + 1, true ) );\n\t\t\treturn true;\n\t\t}\n\t},\n\n\t_findNextTab: function( index, goingForward ) {\n\t\tvar lastTabIndex = this.tabs.length - 1;\n\n\t\tfunction constrain() {\n\t\t\tif ( index > lastTabIndex ) {\n\t\t\t\tindex = 0;\n\t\t\t}\n\t\t\tif ( index < 0 ) {\n\t\t\t\tindex = lastTabIndex;\n\t\t\t}\n\t\t\treturn index;\n\t\t}\n\n\t\twhile ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {\n\t\t\tindex = goingForward ? index + 1 : index - 1;\n\t\t}\n\n\t\treturn index;\n\t},\n\n\t_focusNextTab: function( index, goingForward ) {\n\t\tindex = this._findNextTab( index, goingForward );\n\t\tthis.tabs.eq( index ).focus();\n\t\treturn index;\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"active\" ) {\n\t\t\t// _activate() will handle invalid values and update this.options\n\t\t\tthis._activate( value );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\t// don't use the widget factory's disabled handling\n\t\t\tthis._setupDisabled( value );\n\t\t\treturn;\n\t\t}\n\n\t\tthis._super( key, value);\n\n\t\tif ( key === \"collapsible\" ) {\n\t\t\tthis.element.toggleClass( \"ui-tabs-collapsible\", value );\n\t\t\t// Setting collapsible: false while collapsed; open first panel\n\t\t\tif ( !value && this.options.active === false ) {\n\t\t\t\tthis._activate( 0 );\n\t\t\t}\n\t\t}\n\n\t\tif ( key === \"event\" ) {\n\t\t\tthis._setupEvents( value );\n\t\t}\n\n\t\tif ( key === \"heightStyle\" ) {\n\t\t\tthis._setupHeightStyle( value );\n\t\t}\n\t},\n\n\t_tabId: function( tab ) {\n\t\treturn tab.attr( \"aria-controls\" ) || \"ui-tabs-\" + getNextTabId();\n\t},\n\n\t_sanitizeSelector: function( hash ) {\n\t\treturn hash ? hash.replace( /[!\"$%&'()*+,.\\/:;<=>?@\\[\\]\\^`{|}~]/g, \"\\\\$&\" ) : \"\";\n\t},\n\n\trefresh: function() {\n\t\tvar options = this.options,\n\t\t\tlis = this.tablist.children( \":has(a[href])\" );\n\n\t\t// get disabled tabs from class attribute from HTML\n\t\t// this will get converted to a boolean if needed in _refresh()\n\t\toptions.disabled = $.map( lis.filter( \".ui-state-disabled\" ), function( tab ) {\n\t\t\treturn lis.index( tab );\n\t\t});\n\n\t\tthis._processTabs();\n\n\t\t// was collapsed or no tabs\n\t\tif ( options.active === false || !this.anchors.length ) {\n\t\t\toptions.active = false;\n\t\t\tthis.active = $();\n\t\t// was active, but active tab is gone\n\t\t} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {\n\t\t\t// all remaining tabs are disabled\n\t\t\tif ( this.tabs.length === options.disabled.length ) {\n\t\t\t\toptions.active = false;\n\t\t\t\tthis.active = $();\n\t\t\t// activate previous tab\n\t\t\t} else {\n\t\t\t\tthis._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );\n\t\t\t}\n\t\t// was active, active tab still exists\n\t\t} else {\n\t\t\t// make sure active index is correct\n\t\t\toptions.active = this.tabs.index( this.active );\n\t\t}\n\n\t\tthis._refresh();\n\t},\n\n\t_refresh: function() {\n\t\tthis._setupDisabled( this.options.disabled );\n\t\tthis._setupEvents( this.options.event );\n\t\tthis._setupHeightStyle( this.options.heightStyle );\n\n\t\tthis.tabs.not( this.active ).attr({\n\t\t\t\"aria-selected\": \"false\",\n\t\t\ttabIndex: -1\n\t\t});\n\t\tthis.panels.not( this._getPanelForTab( this.active ) )\n\t\t\t.hide()\n\t\t\t.attr({\n\t\t\t\t\"aria-expanded\": \"false\",\n\t\t\t\t\"aria-hidden\": \"true\"\n\t\t\t});\n\n\t\t// Make sure one tab is in the tab order\n\t\tif ( !this.active.length ) {\n\t\t\tthis.tabs.eq( 0 ).attr( \"tabIndex\", 0 );\n\t\t} else {\n\t\t\tthis.active\n\t\t\t\t.addClass( \"ui-tabs-active ui-state-active\" )\n\t\t\t\t.attr({\n\t\t\t\t\t\"aria-selected\": \"true\",\n\t\t\t\t\ttabIndex: 0\n\t\t\t\t});\n\t\t\tthis._getPanelForTab( this.active )\n\t\t\t\t.show()\n\t\t\t\t.attr({\n\t\t\t\t\t\"aria-expanded\": \"true\",\n\t\t\t\t\t\"aria-hidden\": \"false\"\n\t\t\t\t});\n\t\t}\n\t},\n\n\t_processTabs: function() {\n\t\tvar that = this;\n\n\t\tthis.tablist = this._getList()\n\t\t\t.addClass( \"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all\" )\n\t\t\t.attr( \"role\", \"tablist\" );\n\n\t\tthis.tabs = this.tablist.find( \"> li:has(a[href])\" )\n\t\t\t.addClass( \"ui-state-default ui-corner-top\" )\n\t\t\t.attr({\n\t\t\t\trole: \"tab\",\n\t\t\t\ttabIndex: -1\n\t\t\t});\n\n\t\tthis.anchors = this.tabs.map(function() {\n\t\t\t\treturn $( \"a\", this )[ 0 ];\n\t\t\t})\n\t\t\t.addClass( \"ui-tabs-anchor\" )\n\t\t\t.attr({\n\t\t\t\trole: \"presentation\",\n\t\t\t\ttabIndex: -1\n\t\t\t});\n\n\t\tthis.panels = $();\n\n\t\tthis.anchors.each(function( i, anchor ) {\n\t\t\tvar selector, panel, panelId,\n\t\t\t\tanchorId = $( anchor ).uniqueId().attr( \"id\" ),\n\t\t\t\ttab = $( anchor ).closest( \"li\" ),\n\t\t\t\toriginalAriaControls = tab.attr( \"aria-controls\" );\n\n\t\t\t// inline tab\n\t\t\tif ( isLocal( anchor ) ) {\n\t\t\t\tselector = anchor.hash;\n\t\t\t\tpanel = that.element.find( that._sanitizeSelector( selector ) );\n\t\t\t// remote tab\n\t\t\t} else {\n\t\t\t\tpanelId = that._tabId( tab );\n\t\t\t\tselector = \"#\" + panelId;\n\t\t\t\tpanel = that.element.find( selector );\n\t\t\t\tif ( !panel.length ) {\n\t\t\t\t\tpanel = that._createPanel( panelId );\n\t\t\t\t\tpanel.insertAfter( that.panels[ i - 1 ] || that.tablist );\n\t\t\t\t}\n\t\t\t\tpanel.attr( \"aria-live\", \"polite\" );\n\t\t\t}\n\n\t\t\tif ( panel.length) {\n\t\t\t\tthat.panels = that.panels.add( panel );\n\t\t\t}\n\t\t\tif ( originalAriaControls ) {\n\t\t\t\ttab.data( \"ui-tabs-aria-controls\", originalAriaControls );\n\t\t\t}\n\t\t\ttab.attr({\n\t\t\t\t\"aria-controls\": selector.substring( 1 ),\n\t\t\t\t\"aria-labelledby\": anchorId\n\t\t\t});\n\t\t\tpanel.attr( \"aria-labelledby\", anchorId );\n\t\t});\n\n\t\tthis.panels\n\t\t\t.addClass( \"ui-tabs-panel ui-widget-content ui-corner-bottom\" )\n\t\t\t.attr( \"role\", \"tabpanel\" );\n\t},\n\n\t// allow overriding how to find the list for rare usage scenarios (#7715)\n\t_getList: function() {\n\t\treturn this.element.find( \"ol,ul\" ).eq( 0 );\n\t},\n\n\t_createPanel: function( id ) {\n\t\treturn $( \"<div>\" )\n\t\t\t.attr( \"id\", id )\n\t\t\t.addClass( \"ui-tabs-panel ui-widget-content ui-corner-bottom\" )\n\t\t\t.data( \"ui-tabs-destroy\", true );\n\t},\n\n\t_setupDisabled: function( disabled ) {\n\t\tif ( $.isArray( disabled ) ) {\n\t\t\tif ( !disabled.length ) {\n\t\t\t\tdisabled = false;\n\t\t\t} else if ( disabled.length === this.anchors.length ) {\n\t\t\t\tdisabled = true;\n\t\t\t}\n\t\t}\n\n\t\t// disable tabs\n\t\tfor ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {\n\t\t\tif ( disabled === true || $.inArray( i, disabled ) !== -1 ) {\n\t\t\t\t$( li )\n\t\t\t\t\t.addClass( \"ui-state-disabled\" )\n\t\t\t\t\t.attr( \"aria-disabled\", \"true\" );\n\t\t\t} else {\n\t\t\t\t$( li )\n\t\t\t\t\t.removeClass( \"ui-state-disabled\" )\n\t\t\t\t\t.removeAttr( \"aria-disabled\" );\n\t\t\t}\n\t\t}\n\n\t\tthis.options.disabled = disabled;\n\t},\n\n\t_setupEvents: function( event ) {\n\t\tvar events = {\n\t\t\tclick: function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t};\n\t\tif ( event ) {\n\t\t\t$.each( event.split(\" \"), function( index, eventName ) {\n\t\t\t\tevents[ eventName ] = \"_eventHandler\";\n\t\t\t});\n\t\t}\n\n\t\tthis._off( this.anchors.add( this.tabs ).add( this.panels ) );\n\t\tthis._on( this.anchors, events );\n\t\tthis._on( this.tabs, { keydown: \"_tabKeydown\" } );\n\t\tthis._on( this.panels, { keydown: \"_panelKeydown\" } );\n\n\t\tthis._focusable( this.tabs );\n\t\tthis._hoverable( this.tabs );\n\t},\n\n\t_setupHeightStyle: function( heightStyle ) {\n\t\tvar maxHeight,\n\t\t\tparent = this.element.parent();\n\n\t\tif ( heightStyle === \"fill\" ) {\n\t\t\tmaxHeight = parent.height();\n\t\t\tmaxHeight -= this.element.outerHeight() - this.element.height();\n\n\t\t\tthis.element.siblings( \":visible\" ).each(function() {\n\t\t\t\tvar elem = $( this ),\n\t\t\t\t\tposition = elem.css( \"position\" );\n\n\t\t\t\tif ( position === \"absolute\" || position === \"fixed\" ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tmaxHeight -= elem.outerHeight( true );\n\t\t\t});\n\n\t\t\tthis.element.children().not( this.panels ).each(function() {\n\t\t\t\tmaxHeight -= $( this ).outerHeight( true );\n\t\t\t});\n\n\t\t\tthis.panels.each(function() {\n\t\t\t\t$( this ).height( Math.max( 0, maxHeight -\n\t\t\t\t\t$( this ).innerHeight() + $( this ).height() ) );\n\t\t\t})\n\t\t\t.css( \"overflow\", \"auto\" );\n\t\t} else if ( heightStyle === \"auto\" ) {\n\t\t\tmaxHeight = 0;\n\t\t\tthis.panels.each(function() {\n\t\t\t\tmaxHeight = Math.max( maxHeight, $( this ).height( \"\" ).height() );\n\t\t\t}).height( maxHeight );\n\t\t}\n\t},\n\n\t_eventHandler: function( event ) {\n\t\tvar options = this.options,\n\t\t\tactive = this.active,\n\t\t\tanchor = $( event.currentTarget ),\n\t\t\ttab = anchor.closest( \"li\" ),\n\t\t\tclickedIsActive = tab[ 0 ] === active[ 0 ],\n\t\t\tcollapsing = clickedIsActive && options.collapsible,\n\t\t\ttoShow = collapsing ? $() : this._getPanelForTab( tab ),\n\t\t\ttoHide = !active.length ? $() : this._getPanelForTab( active ),\n\t\t\teventData = {\n\t\t\t\toldTab: active,\n\t\t\t\toldPanel: toHide,\n\t\t\t\tnewTab: collapsing ? $() : tab,\n\t\t\t\tnewPanel: toShow\n\t\t\t};\n\n\t\tevent.preventDefault();\n\n\t\tif ( tab.hasClass( \"ui-state-disabled\" ) ||\n\t\t\t\t// tab is already loading\n\t\t\t\ttab.hasClass( \"ui-tabs-loading\" ) ||\n\t\t\t\t// can't switch durning an animation\n\t\t\t\tthis.running ||\n\t\t\t\t// click on active header, but not collapsible\n\t\t\t\t( clickedIsActive && !options.collapsible ) ||\n\t\t\t\t// allow canceling activation\n\t\t\t\t( this._trigger( \"beforeActivate\", event, eventData ) === false ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\toptions.active = collapsing ? false : this.tabs.index( tab );\n\n\t\tthis.active = clickedIsActive ? $() : tab;\n\t\tif ( this.xhr ) {\n\t\t\tthis.xhr.abort();\n\t\t}\n\n\t\tif ( !toHide.length && !toShow.length ) {\n\t\t\t$.error( \"jQuery UI Tabs: Mismatching fragment identifier.\" );\n\t\t}\n\n\t\tif ( toShow.length ) {\n\t\t\tthis.load( this.tabs.index( tab ), event );\n\t\t}\n\t\tthis._toggle( event, eventData );\n\t},\n\n\t// handles show/hide for selecting tabs\n\t_toggle: function( event, eventData ) {\n\t\tvar that = this,\n\t\t\ttoShow = eventData.newPanel,\n\t\t\ttoHide = eventData.oldPanel;\n\n\t\tthis.running = true;\n\n\t\tfunction complete() {\n\t\t\tthat.running = false;\n\t\t\tthat._trigger( \"activate\", event, eventData );\n\t\t}\n\n\t\tfunction show() {\n\t\t\teventData.newTab.closest( \"li\" ).addClass( \"ui-tabs-active ui-state-active\" );\n\n\t\t\tif ( toShow.length && that.options.show ) {\n\t\t\t\tthat._show( toShow, that.options.show, complete );\n\t\t\t} else {\n\t\t\t\ttoShow.show();\n\t\t\t\tcomplete();\n\t\t\t}\n\t\t}\n\n\t\t// start out by hiding, then showing, then completing\n\t\tif ( toHide.length && this.options.hide ) {\n\t\t\tthis._hide( toHide, this.options.hide, function() {\n\t\t\t\teventData.oldTab.closest( \"li\" ).removeClass( \"ui-tabs-active ui-state-active\" );\n\t\t\t\tshow();\n\t\t\t});\n\t\t} else {\n\t\t\teventData.oldTab.closest( \"li\" ).removeClass( \"ui-tabs-active ui-state-active\" );\n\t\t\ttoHide.hide();\n\t\t\tshow();\n\t\t}\n\n\t\ttoHide.attr({\n\t\t\t\"aria-expanded\": \"false\",\n\t\t\t\"aria-hidden\": \"true\"\n\t\t});\n\t\teventData.oldTab.attr( \"aria-selected\", \"false\" );\n\t\t// If we're switching tabs, remove the old tab from the tab order.\n\t\t// If we're opening from collapsed state, remove the previous tab from the tab order.\n\t\t// If we're collapsing, then keep the collapsing tab in the tab order.\n\t\tif ( toShow.length && toHide.length ) {\n\t\t\teventData.oldTab.attr( \"tabIndex\", -1 );\n\t\t} else if ( toShow.length ) {\n\t\t\tthis.tabs.filter(function() {\n\t\t\t\treturn $( this ).attr( \"tabIndex\" ) === 0;\n\t\t\t})\n\t\t\t.attr( \"tabIndex\", -1 );\n\t\t}\n\n\t\ttoShow.attr({\n\t\t\t\"aria-expanded\": \"true\",\n\t\t\t\"aria-hidden\": \"false\"\n\t\t});\n\t\teventData.newTab.attr({\n\t\t\t\"aria-selected\": \"true\",\n\t\t\ttabIndex: 0\n\t\t});\n\t},\n\n\t_activate: function( index ) {\n\t\tvar anchor,\n\t\t\tactive = this._findActive( index );\n\n\t\t// trying to activate the already active panel\n\t\tif ( active[ 0 ] === this.active[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// trying to collapse, simulate a click on the current active header\n\t\tif ( !active.length ) {\n\t\t\tactive = this.active;\n\t\t}\n\n\t\tanchor = active.find( \".ui-tabs-anchor\" )[ 0 ];\n\t\tthis._eventHandler({\n\t\t\ttarget: anchor,\n\t\t\tcurrentTarget: anchor,\n\t\t\tpreventDefault: $.noop\n\t\t});\n\t},\n\n\t_findActive: function( index ) {\n\t\treturn index === false ? $() : this.tabs.eq( index );\n\t},\n\n\t_getIndex: function( index ) {\n\t\t// meta-function to give users option to provide a href string instead of a numerical index.\n\t\tif ( typeof index === \"string\" ) {\n\t\t\tindex = this.anchors.index( this.anchors.filter( \"[href$='\" + index + \"']\" ) );\n\t\t}\n\n\t\treturn index;\n\t},\n\n\t_destroy: function() {\n\t\tif ( this.xhr ) {\n\t\t\tthis.xhr.abort();\n\t\t}\n\n\t\tthis.element.removeClass( \"ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible\" );\n\n\t\tthis.tablist\n\t\t\t.removeClass( \"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all\" )\n\t\t\t.removeAttr( \"role\" );\n\n\t\tthis.anchors\n\t\t\t.removeClass( \"ui-tabs-anchor\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"tabIndex\" )\n\t\t\t.removeUniqueId();\n\n\t\tthis.tabs.add( this.panels ).each(function() {\n\t\t\tif ( $.data( this, \"ui-tabs-destroy\" ) ) {\n\t\t\t\t$( this ).remove();\n\t\t\t} else {\n\t\t\t\t$( this )\n\t\t\t\t\t.removeClass( \"ui-state-default ui-state-active ui-state-disabled \" +\n\t\t\t\t\t\t\"ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel\" )\n\t\t\t\t\t.removeAttr( \"tabIndex\" )\n\t\t\t\t\t.removeAttr( \"aria-live\" )\n\t\t\t\t\t.removeAttr( \"aria-busy\" )\n\t\t\t\t\t.removeAttr( \"aria-selected\" )\n\t\t\t\t\t.removeAttr( \"aria-labelledby\" )\n\t\t\t\t\t.removeAttr( \"aria-hidden\" )\n\t\t\t\t\t.removeAttr( \"aria-expanded\" )\n\t\t\t\t\t.removeAttr( \"role\" );\n\t\t\t}\n\t\t});\n\n\t\tthis.tabs.each(function() {\n\t\t\tvar li = $( this ),\n\t\t\t\tprev = li.data( \"ui-tabs-aria-controls\" );\n\t\t\tif ( prev ) {\n\t\t\t\tli\n\t\t\t\t\t.attr( \"aria-controls\", prev )\n\t\t\t\t\t.removeData( \"ui-tabs-aria-controls\" );\n\t\t\t} else {\n\t\t\t\tli.removeAttr( \"aria-controls\" );\n\t\t\t}\n\t\t});\n\n\t\tthis.panels.show();\n\n\t\tif ( this.options.heightStyle !== \"content\" ) {\n\t\t\tthis.panels.css( \"height\", \"\" );\n\t\t}\n\t},\n\n\tenable: function( index ) {\n\t\tvar disabled = this.options.disabled;\n\t\tif ( disabled === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( index === undefined ) {\n\t\t\tdisabled = false;\n\t\t} else {\n\t\t\tindex = this._getIndex( index );\n\t\t\tif ( $.isArray( disabled ) ) {\n\t\t\t\tdisabled = $.map( disabled, function( num ) {\n\t\t\t\t\treturn num !== index ? num : null;\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tdisabled = $.map( this.tabs, function( li, num ) {\n\t\t\t\t\treturn num !== index ? num : null;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis._setupDisabled( disabled );\n\t},\n\n\tdisable: function( index ) {\n\t\tvar disabled = this.options.disabled;\n\t\tif ( disabled === true ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( index === undefined ) {\n\t\t\tdisabled = true;\n\t\t} else {\n\t\t\tindex = this._getIndex( index );\n\t\t\tif ( $.inArray( index, disabled ) !== -1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( $.isArray( disabled ) ) {\n\t\t\t\tdisabled = $.merge( [ index ], disabled ).sort();\n\t\t\t} else {\n\t\t\t\tdisabled = [ index ];\n\t\t\t}\n\t\t}\n\t\tthis._setupDisabled( disabled );\n\t},\n\n\tload: function( index, event ) {\n\t\tindex = this._getIndex( index );\n\t\tvar that = this,\n\t\t\ttab = this.tabs.eq( index ),\n\t\t\tanchor = tab.find( \".ui-tabs-anchor\" ),\n\t\t\tpanel = this._getPanelForTab( tab ),\n\t\t\teventData = {\n\t\t\t\ttab: tab,\n\t\t\t\tpanel: panel\n\t\t\t};\n\n\t\t// not remote\n\t\tif ( isLocal( anchor[ 0 ] ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );\n\n\t\t// support: jQuery <1.8\n\t\t// jQuery <1.8 returns false if the request is canceled in beforeSend,\n\t\t// but as of 1.8, $.ajax() always returns a jqXHR object.\n\t\tif ( this.xhr && this.xhr.statusText !== \"canceled\" ) {\n\t\t\ttab.addClass( \"ui-tabs-loading\" );\n\t\t\tpanel.attr( \"aria-busy\", \"true\" );\n\n\t\t\tthis.xhr\n\t\t\t\t.success(function( response ) {\n\t\t\t\t\t// support: jQuery <1.8\n\t\t\t\t\t// http://bugs.jquery.com/ticket/11778\n\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\tpanel.html( response );\n\t\t\t\t\t\tthat._trigger( \"load\", event, eventData );\n\t\t\t\t\t}, 1 );\n\t\t\t\t})\n\t\t\t\t.complete(function( jqXHR, status ) {\n\t\t\t\t\t// support: jQuery <1.8\n\t\t\t\t\t// http://bugs.jquery.com/ticket/11778\n\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\tif ( status === \"abort\" ) {\n\t\t\t\t\t\t\tthat.panels.stop( false, true );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttab.removeClass( \"ui-tabs-loading\" );\n\t\t\t\t\t\tpanel.removeAttr( \"aria-busy\" );\n\n\t\t\t\t\t\tif ( jqXHR === that.xhr ) {\n\t\t\t\t\t\t\tdelete that.xhr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 1 );\n\t\t\t\t});\n\t\t}\n\t},\n\n\t_ajaxSettings: function( anchor, event, eventData ) {\n\t\tvar that = this;\n\t\treturn {\n\t\t\turl: anchor.attr( \"href\" ),\n\t\t\tbeforeSend: function( jqXHR, settings ) {\n\t\t\t\treturn that._trigger( \"beforeLoad\", event,\n\t\t\t\t\t$.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );\n\t\t\t}\n\t\t};\n\t},\n\n\t_getPanelForTab: function( tab ) {\n\t\tvar id = $( tab ).attr( \"aria-controls\" );\n\t\treturn this.element.find( this._sanitizeSelector( \"#\" + id ) );\n\t}\n});\n\n})( jQuery );\n\n(function( $ ) {\n\nvar increments = 0;\n\nfunction addDescribedBy( elem, id ) {\n\tvar describedby = (elem.attr( \"aria-describedby\" ) || \"\").split( /\\s+/ );\n\tdescribedby.push( id );\n\telem\n\t\t.data( \"ui-tooltip-id\", id )\n\t\t.attr( \"aria-describedby\", $.trim( describedby.join( \" \" ) ) );\n}\n\nfunction removeDescribedBy( elem ) {\n\tvar id = elem.data( \"ui-tooltip-id\" ),\n\t\tdescribedby = (elem.attr( \"aria-describedby\" ) || \"\").split( /\\s+/ ),\n\t\tindex = $.inArray( id, describedby );\n\tif ( index !== -1 ) {\n\t\tdescribedby.splice( index, 1 );\n\t}\n\n\telem.removeData( \"ui-tooltip-id\" );\n\tdescribedby = $.trim( describedby.join( \" \" ) );\n\tif ( describedby ) {\n\t\telem.attr( \"aria-describedby\", describedby );\n\t} else {\n\t\telem.removeAttr( \"aria-describedby\" );\n\t}\n}\n\n$.widget( \"ui.tooltip\", {\n\tversion: \"1.10.1\",\n\toptions: {\n\t\tcontent: function() {\n\t\t\t// support: IE<9, Opera in jQuery <1.7\n\t\t\t// .text() can't accept undefined, so coerce to a string\n\t\t\tvar title = $( this ).attr( \"title\" ) || \"\";\n\t\t\t// Escape title, since we're going from an attribute to raw HTML\n\t\t\treturn $( \"<a>\" ).text( title ).html();\n\t\t},\n\t\thide: true,\n\t\t// Disabled elements have inconsistent behavior across browsers (#8661)\n\t\titems: \"[title]:not([disabled])\",\n\t\tposition: {\n\t\t\tmy: \"left top+15\",\n\t\t\tat: \"left bottom\",\n\t\t\tcollision: \"flipfit flip\"\n\t\t},\n\t\tshow: true,\n\t\ttooltipClass: null,\n\t\ttrack: false,\n\n\t\t// callbacks\n\t\tclose: null,\n\t\topen: null\n\t},\n\n\t_create: function() {\n\t\tthis._on({\n\t\t\tmouseover: \"open\",\n\t\t\tfocusin: \"open\"\n\t\t});\n\n\t\t// IDs of generated tooltips, needed for destroy\n\t\tthis.tooltips = {};\n\t\t// IDs of parent tooltips where we removed the title attribute\n\t\tthis.parents = {};\n\n\t\tif ( this.options.disabled ) {\n\t\t\tthis._disable();\n\t\t}\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tvar that = this;\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis[ value ? \"_disable\" : \"_enable\" ]();\n\t\t\tthis.options[ key ] = value;\n\t\t\t// disable element style changes\n\t\t\treturn;\n\t\t}\n\n\t\tthis._super( key, value );\n\n\t\tif ( key === \"content\" ) {\n\t\t\t$.each( this.tooltips, function( id, element ) {\n\t\t\t\tthat._updateContent( element );\n\t\t\t});\n\t\t}\n\t},\n\n\t_disable: function() {\n\t\tvar that = this;\n\n\t\t// close open tooltips\n\t\t$.each( this.tooltips, function( id, element ) {\n\t\t\tvar event = $.Event( \"blur\" );\n\t\t\tevent.target = event.currentTarget = element[0];\n\t\t\tthat.close( event, true );\n\t\t});\n\n\t\t// remove title attributes to prevent native tooltips\n\t\tthis.element.find( this.options.items ).addBack().each(function() {\n\t\t\tvar element = $( this );\n\t\t\tif ( element.is( \"[title]\" ) ) {\n\t\t\t\telement\n\t\t\t\t\t.data( \"ui-tooltip-title\", element.attr( \"title\" ) )\n\t\t\t\t\t.attr( \"title\", \"\" );\n\t\t\t}\n\t\t});\n\t},\n\n\t_enable: function() {\n\t\t// restore title attributes\n\t\tthis.element.find( this.options.items ).addBack().each(function() {\n\t\t\tvar element = $( this );\n\t\t\tif ( element.data( \"ui-tooltip-title\" ) ) {\n\t\t\t\telement.attr( \"title\", element.data( \"ui-tooltip-title\" ) );\n\t\t\t}\n\t\t});\n\t},\n\n\topen: function( event ) {\n\t\tvar that = this,\n\t\t\ttarget = $( event ? event.target : this.element )\n\t\t\t\t// we need closest here due to mouseover bubbling,\n\t\t\t\t// but always pointing at the same event target\n\t\t\t\t.closest( this.options.items );\n\n\t\t// No element to show a tooltip for or the tooltip is already open\n\t\tif ( !target.length || target.data( \"ui-tooltip-id\" ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( target.attr( \"title\" ) ) {\n\t\t\ttarget.data( \"ui-tooltip-title\", target.attr( \"title\" ) );\n\t\t}\n\n\t\ttarget.data( \"ui-tooltip-open\", true );\n\n\t\t// kill parent tooltips, custom or native, for hover\n\t\tif ( event && event.type === \"mouseover\" ) {\n\t\t\ttarget.parents().each(function() {\n\t\t\t\tvar parent = $( this ),\n\t\t\t\t\tblurEvent;\n\t\t\t\tif ( parent.data( \"ui-tooltip-open\" ) ) {\n\t\t\t\t\tblurEvent = $.Event( \"blur\" );\n\t\t\t\t\tblurEvent.target = blurEvent.currentTarget = this;\n\t\t\t\t\tthat.close( blurEvent, true );\n\t\t\t\t}\n\t\t\t\tif ( parent.attr( \"title\" ) ) {\n\t\t\t\t\tparent.uniqueId();\n\t\t\t\t\tthat.parents[ this.id ] = {\n\t\t\t\t\t\telement: this,\n\t\t\t\t\t\ttitle: parent.attr( \"title\" )\n\t\t\t\t\t};\n\t\t\t\t\tparent.attr( \"title\", \"\" );\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tthis._updateContent( target, event );\n\t},\n\n\t_updateContent: function( target, event ) {\n\t\tvar content,\n\t\t\tcontentOption = this.options.content,\n\t\t\tthat = this,\n\t\t\teventType = event ? event.type : null;\n\n\t\tif ( typeof contentOption === \"string\" ) {\n\t\t\treturn this._open( event, target, contentOption );\n\t\t}\n\n\t\tcontent = contentOption.call( target[0], function( response ) {\n\t\t\t// ignore async response if tooltip was closed already\n\t\t\tif ( !target.data( \"ui-tooltip-open\" ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// IE may instantly serve a cached response for ajax requests\n\t\t\t// delay this call to _open so the other call to _open runs first\n\t\t\tthat._delay(function() {\n\t\t\t\t// jQuery creates a special event for focusin when it doesn't\n\t\t\t\t// exist natively. To improve performance, the native event\n\t\t\t\t// object is reused and the type is changed. Therefore, we can't\n\t\t\t\t// rely on the type being correct after the event finished\n\t\t\t\t// bubbling, so we set it back to the previous value. (#8740)\n\t\t\t\tif ( event ) {\n\t\t\t\t\tevent.type = eventType;\n\t\t\t\t}\n\t\t\t\tthis._open( event, target, response );\n\t\t\t});\n\t\t});\n\t\tif ( content ) {\n\t\t\tthis._open( event, target, content );\n\t\t}\n\t},\n\n\t_open: function( event, target, content ) {\n\t\tvar tooltip, events, delayedShow,\n\t\t\tpositionOption = $.extend( {}, this.options.position );\n\n\t\tif ( !content ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Content can be updated multiple times. If the tooltip already\n\t\t// exists, then just update the content and bail.\n\t\ttooltip = this._find( target );\n\t\tif ( tooltip.length ) {\n\t\t\ttooltip.find( \".ui-tooltip-content\" ).html( content );\n\t\t\treturn;\n\t\t}\n\n\t\t// if we have a title, clear it to prevent the native tooltip\n\t\t// we have to check first to avoid defining a title if none exists\n\t\t// (we don't want to cause an element to start matching [title])\n\t\t//\n\t\t// We use removeAttr only for key events, to allow IE to export the correct\n\t\t// accessible attributes. For mouse events, set to empty string to avoid\n\t\t// native tooltip showing up (happens only when removing inside mouseover).\n\t\tif ( target.is( \"[title]\" ) ) {\n\t\t\tif ( event && event.type === \"mouseover\" ) {\n\t\t\t\ttarget.attr( \"title\", \"\" );\n\t\t\t} else {\n\t\t\t\ttarget.removeAttr( \"title\" );\n\t\t\t}\n\t\t}\n\n\t\ttooltip = this._tooltip( target );\n\t\taddDescribedBy( target, tooltip.attr( \"id\" ) );\n\t\ttooltip.find( \".ui-tooltip-content\" ).html( content );\n\n\t\tfunction position( event ) {\n\t\t\tpositionOption.of = event;\n\t\t\tif ( tooltip.is( \":hidden\" ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttooltip.position( positionOption );\n\t\t}\n\t\tif ( this.options.track && event && /^mouse/.test( event.type ) ) {\n\t\t\tthis._on( this.document, {\n\t\t\t\tmousemove: position\n\t\t\t});\n\t\t\t// trigger once to override element-relative positioning\n\t\t\tposition( event );\n\t\t} else {\n\t\t\ttooltip.position( $.extend({\n\t\t\t\tof: target\n\t\t\t}, this.options.position ) );\n\t\t}\n\n\t\ttooltip.hide();\n\n\t\tthis._show( tooltip, this.options.show );\n\t\t// Handle tracking tooltips that are shown with a delay (#8644). As soon\n\t\t// as the tooltip is visible, position the tooltip using the most recent\n\t\t// event.\n\t\tif ( this.options.show && this.options.show.delay ) {\n\t\t\tdelayedShow = this.delayedShow = setInterval(function() {\n\t\t\t\tif ( tooltip.is( \":visible\" ) ) {\n\t\t\t\t\tposition( positionOption.of );\n\t\t\t\t\tclearInterval( delayedShow );\n\t\t\t\t}\n\t\t\t}, $.fx.interval );\n\t\t}\n\n\t\tthis._trigger( \"open\", event, { tooltip: tooltip } );\n\n\t\tevents = {\n\t\t\tkeyup: function( event ) {\n\t\t\t\tif ( event.keyCode === $.ui.keyCode.ESCAPE ) {\n\t\t\t\t\tvar fakeEvent = $.Event(event);\n\t\t\t\t\tfakeEvent.currentTarget = target[0];\n\t\t\t\t\tthis.close( fakeEvent, true );\n\t\t\t\t}\n\t\t\t},\n\t\t\tremove: function() {\n\t\t\t\tthis._removeTooltip( tooltip );\n\t\t\t}\n\t\t};\n\t\tif ( !event || event.type === \"mouseover\" ) {\n\t\t\tevents.mouseleave = \"close\";\n\t\t}\n\t\tif ( !event || event.type === \"focusin\" ) {\n\t\t\tevents.focusout = \"close\";\n\t\t}\n\t\tthis._on( true, target, events );\n\t},\n\n\tclose: function( event ) {\n\t\tvar that = this,\n\t\t\ttarget = $( event ? event.currentTarget : this.element ),\n\t\t\ttooltip = this._find( target );\n\n\t\t// disabling closes the tooltip, so we need to track when we're closing\n\t\t// to avoid an infinite loop in case the tooltip becomes disabled on close\n\t\tif ( this.closing ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear the interval for delayed tracking tooltips\n\t\tclearInterval( this.delayedShow );\n\n\t\t// only set title if we had one before (see comment in _open())\n\t\tif ( target.data( \"ui-tooltip-title\" ) ) {\n\t\t\ttarget.attr( \"title\", target.data( \"ui-tooltip-title\" ) );\n\t\t}\n\n\t\tremoveDescribedBy( target );\n\n\t\ttooltip.stop( true );\n\t\tthis._hide( tooltip, this.options.hide, function() {\n\t\t\tthat._removeTooltip( $( this ) );\n\t\t});\n\n\t\ttarget.removeData( \"ui-tooltip-open\" );\n\t\tthis._off( target, \"mouseleave focusout keyup\" );\n\t\t// Remove 'remove' binding only on delegated targets\n\t\tif ( target[0] !== this.element[0] ) {\n\t\t\tthis._off( target, \"remove\" );\n\t\t}\n\t\tthis._off( this.document, \"mousemove\" );\n\n\t\tif ( event && event.type === \"mouseleave\" ) {\n\t\t\t$.each( this.parents, function( id, parent ) {\n\t\t\t\t$( parent.element ).attr( \"title\", parent.title );\n\t\t\t\tdelete that.parents[ id ];\n\t\t\t});\n\t\t}\n\n\t\tthis.closing = true;\n\t\tthis._trigger( \"close\", event, { tooltip: tooltip } );\n\t\tthis.closing = false;\n\t},\n\n\t_tooltip: function( element ) {\n\t\tvar id = \"ui-tooltip-\" + increments++,\n\t\t\ttooltip = $( \"<div>\" )\n\t\t\t\t.attr({\n\t\t\t\t\tid: id,\n\t\t\t\t\trole: \"tooltip\"\n\t\t\t\t})\n\t\t\t\t.addClass( \"ui-tooltip ui-widget ui-corner-all ui-widget-content \" +\n\t\t\t\t\t( this.options.tooltipClass || \"\" ) );\n\t\t$( \"<div>\" )\n\t\t\t.addClass( \"ui-tooltip-content\" )\n\t\t\t.appendTo( tooltip );\n\t\ttooltip.appendTo( this.document[0].body );\n\t\tthis.tooltips[ id ] = element;\n\t\treturn tooltip;\n\t},\n\n\t_find: function( target ) {\n\t\tvar id = target.data( \"ui-tooltip-id\" );\n\t\treturn id ? $( \"#\" + id ) : $();\n\t},\n\n\t_removeTooltip: function( tooltip ) {\n\t\ttooltip.remove();\n\t\tdelete this.tooltips[ tooltip.attr( \"id\" ) ];\n\t},\n\n\t_destroy: function() {\n\t\tvar that = this;\n\n\t\t// close open tooltips\n\t\t$.each( this.tooltips, function( id, element ) {\n\t\t\t// Delegate to close method to handle common cleanup\n\t\t\tvar event = $.Event( \"blur\" );\n\t\t\tevent.target = event.currentTarget = element[0];\n\t\t\tthat.close( event, true );\n\n\t\t\t// Remove immediately; destroying an open tooltip doesn't use the\n\t\t\t// hide animation\n\t\t\t$( \"#\" + id ).remove();\n\n\t\t\t// Restore the title\n\t\t\tif ( element.data( \"ui-tooltip-title\" ) ) {\n\t\t\t\telement.attr( \"title\", element.data( \"ui-tooltip-title\" ) );\n\t\t\t\telement.removeData( \"ui-tooltip-title\" );\n\t\t\t}\n\t\t});\n\t}\n});\n\n}( jQuery ) );\n"
  },
  {
    "path": "src/libs/jquery.base64.js",
    "content": "/*jslint adsafe: false, bitwise: true, browser: true, cap: false, css: false,\n  debug: false, devel: true, eqeqeq: true, es5: false, evil: false,\n  forin: false, fragment: false, immed: true, laxbreak: false, newcap: true,\n  nomen: false, on: false, onevar: true, passfail: false, plusplus: true,\n  regexp: false, rhino: true, safe: false, strict: false, sub: false,\n  undef: true, white: false, widget: false, windows: false */\n/*global jQuery: false, window: false */\n\"use strict\";\n\n/*\n * Original code (c) 2010 Nick Galbreath\n * http://code.google.com/p/stringencoders/source/browse/#svn/trunk/javascript\n *\n * jQuery port (c) 2010 Carlo Zottmann\n * http://github.com/carlo/jquery-base64\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\n/* base64 encode/decode compatible with window.btoa/atob\n *\n * window.atob/btoa is a Firefox extension to convert binary data (the \"b\")\n * to base64 (ascii, the \"a\").\n *\n * It is also found in Safari and Chrome.  It is not available in IE.\n *\n * if (!window.btoa) window.btoa = $.base64.encode\n * if (!window.atob) window.atob = $.base64.decode\n *\n * The original spec's for atob/btoa are a bit lacking\n * https://developer.mozilla.org/en/DOM/window.atob\n * https://developer.mozilla.org/en/DOM/window.btoa\n *\n * window.btoa and $.base64.encode takes a string where charCodeAt is [0,255]\n * If any character is not [0,255], then an exception is thrown.\n *\n * window.atob and $.base64.decode take a base64-encoded string\n * If the input length is not a multiple of 4, or contains invalid characters\n *   then an exception is thrown.\n */\n \njQuery.base64 = ( function( $ ) {\n  \n  var _PADCHAR = \"=\",\n    _ALPHA = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",\n    _VERSION = \"1.0\";\n\n\n  function _getbyte64( s, i ) {\n    // This is oddly fast, except on Chrome/V8.\n    // Minimal or no improvement in performance by using a\n    // object with properties mapping chars to value (eg. 'A': 0)\n\n    var idx = _ALPHA.indexOf( s.charAt( i ) );\n\n    if ( idx === -1 ) {\n      throw \"Cannot decode base64\";\n    }\n\n    return idx;\n  }\n  \n  \n  function _decode( s ) {\n    var pads = 0,\n      i,\n      b10,\n      imax = s.length,\n      x = [];\n\n    s = String( s );\n    \n    if ( imax === 0 ) {\n      return s;\n    }\n\n    if ( imax % 4 !== 0 ) {\n      throw \"Cannot decode base64\";\n    }\n\n    if ( s.charAt( imax - 1 ) === _PADCHAR ) {\n      pads = 1;\n\n      if ( s.charAt( imax - 2 ) === _PADCHAR ) {\n        pads = 2;\n      }\n\n      // either way, we want to ignore this last block\n      imax -= 4;\n    }\n\n    for ( i = 0; i < imax; i += 4 ) {\n      b10 = ( _getbyte64( s, i ) << 18 ) | ( _getbyte64( s, i + 1 ) << 12 ) | ( _getbyte64( s, i + 2 ) << 6 ) | _getbyte64( s, i + 3 );\n      x.push( String.fromCharCode( b10 >> 16, ( b10 >> 8 ) & 0xff, b10 & 0xff ) );\n    }\n\n    switch ( pads ) {\n      case 1:\n        b10 = ( _getbyte64( s, i ) << 18 ) | ( _getbyte64( s, i + 1 ) << 12 ) | ( _getbyte64( s, i + 2 ) << 6 );\n        x.push( String.fromCharCode( b10 >> 16, ( b10 >> 8 ) & 0xff ) );\n        break;\n\n      case 2:\n        b10 = ( _getbyte64( s, i ) << 18) | ( _getbyte64( s, i + 1 ) << 12 );\n        x.push( String.fromCharCode( b10 >> 16 ) );\n        break;\n    }\n\n    return x.join( \"\" );\n  }\n  \n  \n  function _getbyte( s, i ) {\n    var x = s.charCodeAt( i );\n\n    if ( x > 255 ) {\n      throw \"INVALID_CHARACTER_ERR: DOM Exception 5\";\n    }\n    \n    return x;\n  }\n\n\n  function _encode( s ) {\n    if ( arguments.length !== 1 ) {\n      throw \"SyntaxError: exactly one argument required\";\n    }\n\n    s = String( s );\n\n    var i,\n      b10,\n      x = [],\n      imax = s.length - s.length % 3;\n\n    if ( s.length === 0 ) {\n      return s;\n    }\n\n    for ( i = 0; i < imax; i += 3 ) {\n      b10 = ( _getbyte( s, i ) << 16 ) | ( _getbyte( s, i + 1 ) << 8 ) | _getbyte( s, i + 2 );\n      x.push( _ALPHA.charAt( b10 >> 18 ) );\n      x.push( _ALPHA.charAt( ( b10 >> 12 ) & 0x3F ) );\n      x.push( _ALPHA.charAt( ( b10 >> 6 ) & 0x3f ) );\n      x.push( _ALPHA.charAt( b10 & 0x3f ) );\n    }\n\n    switch ( s.length - imax ) {\n      case 1:\n        b10 = _getbyte( s, i ) << 16;\n        x.push( _ALPHA.charAt( b10 >> 18 ) + _ALPHA.charAt( ( b10 >> 12 ) & 0x3F ) + _PADCHAR + _PADCHAR );\n        break;\n\n      case 2:\n        b10 = ( _getbyte( s, i ) << 16 ) | ( _getbyte( s, i + 1 ) << 8 );\n        x.push( _ALPHA.charAt( b10 >> 18 ) + _ALPHA.charAt( ( b10 >> 12 ) & 0x3F ) + _ALPHA.charAt( ( b10 >> 6 ) & 0x3f ) + _PADCHAR );\n        break;\n    }\n\n    return x.join( \"\" );\n  }\n\n\n  return {\n    decode: _decode,\n    encode: _encode,\n    VERSION: _VERSION\n  };\n      \n}( jQuery ) );\n\n"
  },
  {
    "path": "src/libs/jquery.knob.min.js",
    "content": "(function(e){if(typeof define===\"function\"&&define.amd){define([\"jquery\"],e)}else{e(jQuery)}})(function(e){\"use strict\";var t={},n=Math.max,r=Math.min;t.c={};t.c.d=e(document);t.c.t=function(e){return e.originalEvent.touches.length-1};t.o=function(){var n=this;this.o=null;this.$=null;this.i=null;this.g=null;this.v=null;this.cv=null;this.x=0;this.y=0;this.w=0;this.h=0;this.$c=null;this.c=null;this.t=0;this.isInit=false;this.fgColor=null;this.pColor=null;this.dH=null;this.cH=null;this.eH=null;this.rH=null;this.scale=1;this.relative=false;this.relativeWidth=false;this.relativeHeight=false;this.$div=null;this.run=function(){var t=function(e,t){var r;for(r in t){n.o[r]=t[r]}n._carve().init();n._configure()._draw()};if(this.$.data(\"kontroled\"))return;this.$.data(\"kontroled\",true);this.extend();this.o=e.extend({min:this.$.data(\"min\")!==undefined?this.$.data(\"min\"):0,max:this.$.data(\"max\")!==undefined?this.$.data(\"max\"):100,stopper:true,readOnly:this.$.data(\"readonly\")||this.$.attr(\"readonly\")===\"readonly\",cursor:this.$.data(\"cursor\")===true&&30||this.$.data(\"cursor\")||0,thickness:this.$.data(\"thickness\")&&Math.max(Math.min(this.$.data(\"thickness\"),1),.01)||.35,lineCap:this.$.data(\"linecap\")||\"butt\",width:this.$.data(\"width\")||200,height:this.$.data(\"height\")||200,displayInput:this.$.data(\"displayinput\")==null||this.$.data(\"displayinput\"),displayPrevious:this.$.data(\"displayprevious\"),fgColor:this.$.data(\"fgcolor\")||\"#87CEEB\",inputColor:this.$.data(\"inputcolor\"),font:this.$.data(\"font\")||\"Arial\",fontWeight:this.$.data(\"font-weight\")||\"bold\",inline:false,step:this.$.data(\"step\")||1,rotation:this.$.data(\"rotation\"),draw:null,change:null,cancel:null,release:null,format:function(e){return e},parse:function(e){return parseFloat(e)}},this.o);this.o.flip=this.o.rotation===\"anticlockwise\"||this.o.rotation===\"acw\";if(!this.o.inputColor){this.o.inputColor=this.o.fgColor}if(this.$.is(\"fieldset\")){this.v={};this.i=this.$.find(\"input\");this.i.each(function(t){var r=e(this);n.i[t]=r;n.v[t]=n.o.parse(r.val());r.bind(\"change blur\",function(){var e={};e[t]=r.val();n.val(n._validate(e))})});this.$.find(\"legend\").remove()}else{this.i=this.$;this.v=this.o.parse(this.$.val());this.v===\"\"&&(this.v=this.o.min);this.$.bind(\"change blur\",function(){n.val(n._validate(n.o.parse(n.$.val())))})}!this.o.displayInput&&this.$.hide();this.$c=e(document.createElement(\"canvas\")).attr({width:this.o.width,height:this.o.height});this.$div=e('<div style=\"'+(this.o.inline?\"display:inline;\":\"\")+\"width:\"+this.o.width+\"px;height:\"+this.o.height+\"px;\"+'\"></div>');this.$.wrap(this.$div).before(this.$c);this.$div=this.$.parent();if(typeof G_vmlCanvasManager!==\"undefined\"){G_vmlCanvasManager.initElement(this.$c[0])}this.c=this.$c[0].getContext?this.$c[0].getContext(\"2d\"):null;if(!this.c){throw{name:\"CanvasNotSupportedException\",message:\"Canvas not supported. Please use excanvas on IE8.0.\",toString:function(){return this.name+\": \"+this.message}}}this.scale=(window.devicePixelRatio||1)/(this.c.webkitBackingStorePixelRatio||this.c.mozBackingStorePixelRatio||this.c.msBackingStorePixelRatio||this.c.oBackingStorePixelRatio||this.c.backingStorePixelRatio||1);this.relativeWidth=this.o.width%1!==0&&this.o.width.indexOf(\"%\");this.relativeHeight=this.o.height%1!==0&&this.o.height.indexOf(\"%\");this.relative=this.relativeWidth||this.relativeHeight;this._carve();if(this.v instanceof Object){this.cv={};this.copy(this.v,this.cv)}else{this.cv=this.v}this.$.bind(\"configure\",t).parent().bind(\"configure\",t);this._listen()._configure()._xy().init();this.isInit=true;this.$.val(this.o.format(this.v));this._draw();return this};this._carve=function(){if(this.relative){var e=this.relativeWidth?this.$div.parent().width()*parseInt(this.o.width)/100:this.$div.parent().width(),t=this.relativeHeight?this.$div.parent().height()*parseInt(this.o.height)/100:this.$div.parent().height();this.w=this.h=Math.min(e,t)}else{this.w=this.o.width;this.h=this.o.height}this.$div.css({width:this.w+\"px\",height:this.h+\"px\"});this.$c.attr({width:this.w,height:this.h});if(this.scale!==1){this.$c[0].width=this.$c[0].width*this.scale;this.$c[0].height=this.$c[0].height*this.scale;this.$c.width(this.w);this.$c.height(this.h)}return this};this._draw=function(){var e=true;n.g=n.c;n.clear();n.dH&&(e=n.dH());e!==false&&n.draw()};this._touch=function(e){var r=function(e){var t=n.xy2val(e.originalEvent.touches[n.t].pageX,e.originalEvent.touches[n.t].pageY);if(t==n.cv)return;if(n.cH&&n.cH(t)===false)return;n.change(n._validate(t));n._draw()};this.t=t.c.t(e);r(e);t.c.d.bind(\"touchmove.k\",r).bind(\"touchend.k\",function(){t.c.d.unbind(\"touchmove.k touchend.k\");n.val(n.cv)});return this};this._mouse=function(e){var r=function(e){var t=n.xy2val(e.pageX,e.pageY);if(t==n.cv)return;if(n.cH&&n.cH(t)===false)return;n.change(n._validate(t));n._draw()};r(e);t.c.d.bind(\"mousemove.k\",r).bind(\"keyup.k\",function(e){if(e.keyCode===27){t.c.d.unbind(\"mouseup.k mousemove.k keyup.k\");if(n.eH&&n.eH()===false)return;n.cancel()}}).bind(\"mouseup.k\",function(e){t.c.d.unbind(\"mousemove.k mouseup.k keyup.k\");n.val(n.cv)});return this};this._xy=function(){var e=this.$c.offset();this.x=e.left;this.y=e.top;return this};this._listen=function(){if(!this.o.readOnly){this.$c.bind(\"mousedown\",function(e){e.preventDefault();n._xy()._mouse(e)}).bind(\"touchstart\",function(e){e.preventDefault();n._xy()._touch(e)});this.listen()}else{this.$.attr(\"readonly\",\"readonly\")}if(this.relative){e(window).resize(function(){n._carve().init();n._draw()})}return this};this._configure=function(){if(this.o.draw)this.dH=this.o.draw;if(this.o.change)this.cH=this.o.change;if(this.o.cancel)this.eH=this.o.cancel;if(this.o.release)this.rH=this.o.release;if(this.o.displayPrevious){this.pColor=this.h2rgba(this.o.fgColor,\"0.4\");this.fgColor=this.h2rgba(this.o.fgColor,\"0.6\")}else{this.fgColor=this.o.fgColor}return this};this._clear=function(){this.$c[0].width=this.$c[0].width};this._validate=function(e){var t=~~((e<0?-.5:.5)+e/this.o.step)*this.o.step;return Math.round(t*100)/100};this.listen=function(){};this.extend=function(){};this.init=function(){};this.change=function(e){};this.val=function(e){};this.xy2val=function(e,t){};this.draw=function(){};this.clear=function(){this._clear()};this.h2rgba=function(e,t){var n;e=e.substring(1,7);n=[parseInt(e.substring(0,2),16),parseInt(e.substring(2,4),16),parseInt(e.substring(4,6),16)];return\"rgba(\"+n[0]+\",\"+n[1]+\",\"+n[2]+\",\"+t+\")\"};this.copy=function(e,t){for(var n in e){t[n]=e[n]}}};t.Dial=function(){t.o.call(this);this.startAngle=null;this.xy=null;this.radius=null;this.lineWidth=null;this.cursorExt=null;this.w2=null;this.PI2=2*Math.PI;this.extend=function(){this.o=e.extend({bgColor:this.$.data(\"bgcolor\")||\"#EEEEEE\",angleOffset:this.$.data(\"angleoffset\")||0,angleArc:this.$.data(\"anglearc\")||360,inline:true},this.o)};this.val=function(e,t){if(null!=e){e=this.o.parse(e);if(t!==false&&e!=this.v&&this.rH&&this.rH(e)===false){return}this.cv=this.o.stopper?n(r(e,this.o.max),this.o.min):e;this.v=this.cv;this.$.val(this.o.format(this.v));this._draw()}else{return this.v}};this.xy2val=function(e,t){var i,s;i=Math.atan2(e-(this.x+this.w2),-(t-this.y-this.w2))-this.angleOffset;if(this.o.flip){i=this.angleArc-i-this.PI2}if(this.angleArc!=this.PI2&&i<0&&i>-.5){i=0}else if(i<0){i+=this.PI2}s=i*(this.o.max-this.o.min)/this.angleArc+this.o.min;this.o.stopper&&(s=n(r(s,this.o.max),this.o.min));return s};this.listen=function(){var t=this,i,s,o=function(e){e.preventDefault();var o=e.originalEvent,u=o.detail||o.wheelDeltaX,a=o.detail||o.wheelDeltaY,f=t._validate(t.o.parse(t.$.val()))+(u>0||a>0?t.o.step:u<0||a<0?-t.o.step:0);f=n(r(f,t.o.max),t.o.min);t.val(f,false);if(t.rH){clearTimeout(i);i=setTimeout(function(){t.rH(f);i=null},100);if(!s){s=setTimeout(function(){if(i)t.rH(f);s=null},200)}}},u,a,f=1,l={37:-t.o.step,38:t.o.step,39:t.o.step,40:-t.o.step};this.$.bind(\"keydown\",function(i){var s=i.keyCode;if(s>=96&&s<=105){s=i.keyCode=s-48}u=parseInt(String.fromCharCode(s));if(isNaN(u)){s!==13&&s!==8&&s!==9&&s!==189&&(s!==190||t.$.val().match(/\\./))&&i.preventDefault();if(e.inArray(s,[37,38,39,40])>-1){i.preventDefault();var o=t.o.parse(t.$.val())+l[s]*f;t.o.stopper&&(o=n(r(o,t.o.max),t.o.min));t.change(t._validate(o));t._draw();a=window.setTimeout(function(){f*=2},30)}}}).bind(\"keyup\",function(e){if(isNaN(u)){if(a){window.clearTimeout(a);a=null;f=1;t.val(t.$.val())}}else{t.$.val()>t.o.max&&t.$.val(t.o.max)||t.$.val()<t.o.min&&t.$.val(t.o.min)}});this.$c.bind(\"mousewheel DOMMouseScroll\",o);this.$.bind(\"mousewheel DOMMouseScroll\",o)};this.init=function(){if(this.v<this.o.min||this.v>this.o.max){this.v=this.o.min}this.$.val(this.v);this.w2=this.w/2;this.cursorExt=this.o.cursor/100;this.xy=this.w2*this.scale;this.lineWidth=this.xy*this.o.thickness;this.lineCap=this.o.lineCap;this.radius=this.xy-this.lineWidth/2;this.o.angleOffset&&(this.o.angleOffset=isNaN(this.o.angleOffset)?0:this.o.angleOffset);this.o.angleArc&&(this.o.angleArc=isNaN(this.o.angleArc)?this.PI2:this.o.angleArc);this.angleOffset=this.o.angleOffset*Math.PI/180;this.angleArc=this.o.angleArc*Math.PI/180;this.startAngle=1.5*Math.PI+this.angleOffset;this.endAngle=1.5*Math.PI+this.angleOffset+this.angleArc;var e=n(String(Math.abs(this.o.max)).length,String(Math.abs(this.o.min)).length,2)+2;this.o.displayInput&&this.i.css({width:(this.w/2+4>>0)+\"px\",height:(this.w/3>>0)+\"px\",position:\"absolute\",\"vertical-align\":\"middle\",\"margin-top\":(this.w/3>>0)+\"px\",\"margin-left\":\"-\"+(this.w*3/4+2>>0)+\"px\",border:0,background:\"none\",font:this.o.fontWeight+\" \"+(this.w/e>>0)+\"px \"+this.o.font,\"text-align\":\"center\",color:this.o.inputColor||this.o.fgColor,padding:\"0px\",\"-webkit-appearance\":\"none\"})||this.i.css({width:\"0px\",visibility:\"hidden\"})};this.change=function(e){this.cv=e;this.$.val(this.o.format(e))};this.angle=function(e){return(e-this.o.min)*this.angleArc/(this.o.max-this.o.min)};this.arc=function(e){var t,n;e=this.angle(e);if(this.o.flip){t=this.endAngle+1e-5;n=t-e-1e-5}else{t=this.startAngle-1e-5;n=t+e+1e-5}this.o.cursor&&(t=n-this.cursorExt)&&(n=n+this.cursorExt);return{s:t,e:n,d:this.o.flip&&!this.o.cursor}};this.draw=function(){var e=this.g,t=this.arc(this.cv),n,r=1;e.lineWidth=this.lineWidth;e.lineCap=this.lineCap;if(this.o.bgColor!==\"none\"){e.beginPath();e.strokeStyle=this.o.bgColor;e.arc(this.xy,this.xy,this.radius,this.endAngle-1e-5,this.startAngle+1e-5,true);e.stroke()}if(this.o.displayPrevious){n=this.arc(this.v);e.beginPath();e.strokeStyle=this.pColor;e.arc(this.xy,this.xy,this.radius,n.s,n.e,n.d);e.stroke();r=this.cv==this.v}e.beginPath();e.strokeStyle=r?this.o.fgColor:this.fgColor;e.arc(this.xy,this.xy,this.radius,t.s,t.e,t.d);e.stroke()};this.cancel=function(){this.val(this.v)}};e.fn.dial=e.fn.knob=function(n){return this.each(function(){var r=new t.Dial;r.o=n;r.$=e(this);r.run()}).parent()}})"
  },
  {
    "path": "src/libs/jquery.timepicker/jquery.timepicker.min.js",
    "content": "/*!\n * jquery-timepicker v1.10.1 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.\n * Copyright (c) 2016 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/\n * License: MIT\n */\n\n!function(a){\"object\"==typeof exports&&exports&&\"object\"==typeof module&&module&&module.exports===exports?a(require(\"jquery\")):\"function\"==typeof define&&define.amd?define([\"jquery\"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=t(b.minTime)),b.maxTime&&(b.maxTime=t(b.maxTime)),b.durationTime&&\"function\"!=typeof b.durationTime&&(b.durationTime=t(b.durationTime)),\"now\"==b.scrollDefault)b.scrollDefault=function(){return b.roundingFunction(t(new Date),b)};else if(b.scrollDefault&&\"function\"!=typeof b.scrollDefault){var c=b.scrollDefault;b.scrollDefault=function(){return b.roundingFunction(t(c),b)}}else b.minTime&&(b.scrollDefault=function(){return b.roundingFunction(b.minTime,b)});if(\"string\"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.showOnFocus===!1&&-1!=b.showOn.indexOf(\"focus\")&&b.showOn.splice(b.showOn.indexOf(\"focus\"),1),b.disableTimeRanges.length>0){for(var d in b.disableTimeRanges)b.disableTimeRanges[d]=[t(b.disableTimeRanges[d][0]),t(b.disableTimeRanges[d][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var d=b.disableTimeRanges.length-1;d>0;d--)b.disableTimeRanges[d][0]<=b.disableTimeRanges[d-1][1]&&(b.disableTimeRanges[d-1]=[Math.min(b.disableTimeRanges[d][0],b.disableTimeRanges[d-1][0]),Math.max(b.disableTimeRanges[d][1],b.disableTimeRanges[d-1][1])],b.disableTimeRanges.splice(d,1))}return b}function d(b){var c=b.data(\"timepicker-settings\"),d=b.data(\"timepicker-list\");if(d&&d.length&&(d.remove(),b.data(\"timepicker-list\",!1)),c.useSelect){d=a(\"<select />\",{\"class\":\"ui-timepicker-select\"});var g=d}else{d=a(\"<ul />\",{\"class\":\"ui-timepicker-list\"});var g=a(\"<div />\",{\"class\":\"ui-timepicker-wrapper\",tabindex:-1});g.css({display:\"none\",position:\"absolute\"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?\"Time...\":\"None\"),a.isArray(c.noneOption)){for(var i in c.noneOption)if(parseInt(i,10)==i){var k=e(c.noneOption[i],c.useSelect);d.append(k)}}else{var k=e(c.noneOption,c.useSelect);d.append(k)}if(c.className&&g.addClass(c.className),(null!==c.minTime||null!==c.durationTime)&&c.showDuration){\"function\"==typeof c.step?\"function\":c.step;g.addClass(\"ui-timepicker-with-duration\"),g.addClass(\"ui-timepicker-step-\"+c.step)}var l=c.minTime;\"function\"==typeof c.durationTime?l=t(c.durationTime()):null!==c.durationTime&&(l=c.durationTime);var n=null!==c.minTime?c.minTime:0,o=null!==c.maxTime?c.maxTime:n+u-1;n>o&&(o+=u),o===u-1&&\"string\"===a.type(c.timeFormat)&&c.show2400&&(o=u);var p=c.disableTimeRanges,v=0,x=p.length,y=c.step;\"function\"!=typeof y&&(y=function(){return c.step});for(var i=n,z=0;o>=i;z++,i+=60*y(z)){var A=i,B=s(A,c);if(c.useSelect){var C=a(\"<option />\",{value:B});C.text(B)}else{var C=a(\"<li />\");C.addClass(43200>A%86400?\"ui-timepicker-am\":\"ui-timepicker-pm\"),C.data(\"time\",86400>=A?A:A%86400),C.text(B)}if((null!==c.minTime||null!==c.durationTime)&&c.showDuration){var D=r(i-l,c.step);if(c.useSelect)C.text(C.text()+\" (\"+D+\")\");else{var E=a(\"<span />\",{\"class\":\"ui-timepicker-duration\"});E.text(\" (\"+D+\")\"),C.append(E)}}x>v&&(A>=p[v][1]&&(v+=1),p[v]&&A>=p[v][0]&&A<p[v][1]&&(c.useSelect?C.prop(\"disabled\",!0):C.addClass(\"ui-timepicker-disabled\"))),d.append(C)}if(g.data(\"timepicker-input\",b),b.data(\"timepicker-list\",g),c.useSelect)b.val()&&d.val(f(t(b.val()),c)),d.on(\"focus\",function(){a(this).data(\"timepicker-input\").trigger(\"showTimepicker\")}),d.on(\"blur\",function(){a(this).data(\"timepicker-input\").trigger(\"hideTimepicker\")}),d.on(\"change\",function(){m(b,a(this).val(),\"select\")}),m(b,d.val(),\"initial\"),b.hide().after(d);else{var F=c.appendTo;\"string\"==typeof F?F=a(F):\"function\"==typeof F&&(F=F(b)),F.append(g),j(b,d),d.on(\"mousedown touchstart\",\"li\",function(c){b.off(\"focus.timepicker\"),b.on(\"focus.timepicker-ie-hack\",function(){b.off(\"focus.timepicker-ie-hack\"),b.on(\"focus.timepicker\",w.show)}),h(b)||b[0].focus(),d.find(\"li\").removeClass(\"ui-timepicker-selected\"),a(this).addClass(\"ui-timepicker-selected\"),q(b)&&(b.trigger(\"hideTimepicker\"),d.on(\"mouseup.timepicker touchend.timepicker\",\"li\",function(a){d.off(\"mouseup.timepicker touchend.timepicker\"),g.hide()}))})}}function e(b,c){var d,e,f;return\"object\"==typeof b?(d=b.label,e=b.className,f=b.value):\"string\"==typeof b?d=b:a.error(\"Invalid noneOption value\"),c?a(\"<option />\",{value:f,\"class\":e,text:d}):a(\"<li />\",{\"class\":e,text:d}).data(\"time\",String(f))}function f(a,b){return a=b.roundingFunction(a,b),null!==a?s(a,b):void 0}function g(b){var c=a(b.target),d=c.closest(\".ui-timepicker-input\");0===d.length&&0===c.closest(\".ui-timepicker-wrapper\").length&&(w.hide(),a(document).unbind(\".ui-timepicker\"),a(window).unbind(\".ui-timepicker\"))}function h(a){var b=a.data(\"timepicker-settings\");return(window.navigator.msMaxTouchPoints||\"ontouchstart\"in document)&&b.disableTouchKeyboard}function i(b,c,d){if(!d&&0!==d)return!1;var e=b.data(\"timepicker-settings\"),f=!1,d=e.roundingFunction(d,e);return c.find(\"li\").each(function(b,c){var e=a(c);if(\"number\"==typeof e.data(\"time\"))return e.data(\"time\")==d?(f=e,!1):void 0}),f}function j(a,b){b.find(\"li\").removeClass(\"ui-timepicker-selected\");var c=t(l(a),a.data(\"timepicker-settings\"));if(null!==c){var d=i(a,b,c);if(d){var e=d.offset().top-b.offset().top;(e+d.outerHeight()>b.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass(\"ui-timepicker-selected\")}}}function k(b,c){if(\"\"!==this.value&&\"timepicker\"!=c){var d=a(this);if(!d.is(\":focus\")||b&&\"change\"==b.type){var e=d.data(\"timepicker-settings\"),f=t(this.value,e);if(null===f)return void d.trigger(\"timeFormatError\");var g=!1;null!==e.minTime&&f<e.minTime&&null!==e.maxTime&&f>e.maxTime&&(g=!0),a.each(e.disableTimeRanges,function(){return f>=this[0]&&f<this[1]?(g=!0,!1):void 0}),e.forceRoundTime&&(f=e.roundingFunction(f,e));var h=s(f,e);g?m(d,h,\"error\")&&d.trigger(\"timeRangeError\"):m(d,h)}}}function l(a){return a.is(\"input\")?a.val():a.data(\"ui-timepicker-value\")}function m(a,b,c){if(a.is(\"input\")){a.val(b);var d=a.data(\"timepicker-settings\");d.useSelect&&\"select\"!=c&&\"initial\"!=c&&a.data(\"timepicker-list\").val(f(t(b),d))}return a.data(\"ui-timepicker-value\")!=b?(a.data(\"ui-timepicker-value\",b),\"select\"==c?a.trigger(\"selectTime\").trigger(\"changeTime\").trigger(\"change\",\"timepicker\"):\"error\"!=c&&a.trigger(\"changeTime\"),!0):(a.trigger(\"selectTime\"),!1)}function n(a){switch(a.keyCode){case 13:case 9:return;default:a.preventDefault()}}function o(c){var d=a(this),e=d.data(\"timepicker-list\");if(!e||!b(e)){if(40!=c.keyCode)return!0;w.show.call(d.get(0)),e=d.data(\"timepicker-list\"),h(d)||d.focus()}switch(c.keyCode){case 13:return q(d)&&w.hide.apply(this),c.preventDefault(),!1;case 38:var f=e.find(\".ui-timepicker-selected\");return f.length?f.is(\":first-child\")||(f.removeClass(\"ui-timepicker-selected\"),f.prev().addClass(\"ui-timepicker-selected\"),f.prev().position().top<f.outerHeight()&&e.scrollTop(e.scrollTop()-f.outerHeight())):(e.find(\"li\").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass(\"ui-timepicker-selected\")),!1;case 40:return f=e.find(\".ui-timepicker-selected\"),0===f.length?(e.find(\"li\").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass(\"ui-timepicker-selected\")):f.is(\":last-child\")||(f.removeClass(\"ui-timepicker-selected\"),f.next().addClass(\"ui-timepicker-selected\"),f.next().position().top+2*f.outerHeight()>e.outerHeight()&&e.scrollTop(e.scrollTop()+f.outerHeight())),!1;case 27:e.find(\"li\").removeClass(\"ui-timepicker-selected\"),w.hide();break;case 9:w.hide();break;default:return!0}}function p(c){var d=a(this),e=d.data(\"timepicker-list\"),f=d.data(\"timepicker-settings\");if(!e||!b(e)||f.disableTextInput)return!0;switch(c.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:f.typeaheadHighlight?j(d,e):e.hide()}}function q(a){var b=a.data(\"timepicker-settings\"),c=a.data(\"timepicker-list\"),d=null,e=c.find(\".ui-timepicker-selected\");return e.hasClass(\"ui-timepicker-disabled\")?!1:(e.length&&(d=e.data(\"time\")),null!==d&&(\"string\"!=typeof d&&(d=s(d,b)),m(a,d,\"select\")),!0)}function r(a,b){a=Math.abs(a);var c,d,e=Math.round(a/60),f=[];return 60>e?f=[e,v.mins]:(c=Math.floor(e/60),d=e%60,30==b&&30==d&&(c+=v.decimal+5),f.push(c),f.push(1==c?v.hr:v.hrs),30!=b&&d&&(f.push(d),f.push(v.mins))),f.join(\" \")}function s(b,c){if(\"number\"!=typeof b)return null;var d=parseInt(b%60),e=parseInt(b/60%60),f=parseInt(b/3600%24),g=new Date(1970,0,2,f,e,d,0);if(isNaN(g.getTime()))return null;if(\"function\"===a.type(c.timeFormat))return c.timeFormat(g);for(var h,i,j=\"\",k=0;k<c.timeFormat.length;k++)switch(i=c.timeFormat.charAt(k)){case\"a\":j+=g.getHours()>11?v.pm:v.am;break;case\"A\":j+=g.getHours()>11?v.PM:v.AM;break;case\"g\":h=g.getHours()%12,j+=0===h?\"12\":h;break;case\"G\":h=g.getHours(),b===u&&(h=c.show2400?24:0),j+=h;break;case\"h\":h=g.getHours()%12,0!==h&&10>h&&(h=\"0\"+h),j+=0===h?\"12\":h;break;case\"H\":h=g.getHours(),b===u&&(h=c.show2400?24:0),j+=h>9?h:\"0\"+h;break;case\"i\":var e=g.getMinutes();j+=e>9?e:\"0\"+e;break;case\"s\":d=g.getSeconds(),j+=d>9?d:\"0\"+d;break;case\"\\\\\":k++,j+=c.timeFormat.charAt(k);break;default:j+=i}return j}function t(a,b){if(\"\"===a||null===a)return null;if(\"object\"==typeof a)return 3600*a.getHours()+60*a.getMinutes()+a.getSeconds();if(\"string\"!=typeof a)return a;a=a.toLowerCase().replace(/[\\s\\.]/g,\"\"),(\"a\"==a.slice(-1)||\"p\"==a.slice(-1))&&(a+=\"m\");var c=\"(\"+v.am.replace(\".\",\"\")+\"|\"+v.pm.replace(\".\",\"\")+\"|\"+v.AM.replace(\".\",\"\")+\"|\"+v.PM.replace(\".\",\"\")+\")?\",d=new RegExp(\"^\"+c+\"([0-9]?[0-9])\\\\W?([0-5][0-9])?\\\\W?([0-5][0-9])?\"+c+\"$\"),e=a.match(d);if(!e)return null;var f=parseInt(1*e[2],10),g=f>24?f%24:f,h=e[1]||e[5],i=g;if(12>=g&&h){var j=h==v.pm||h==v.PM;i=12==g?j?12:0:g+(j?12:0)}var k=1*e[3]||0,l=1*e[4]||0,m=3600*i+60*k+l;if(12>g&&!h&&b&&b._twelveHourTime&&b.scrollDefault){var n=m-b.scrollDefault();0>n&&n>=u/-2&&(m=(m+u/2)%u)}return m}var u=86400,v={am:\"am\",pm:\"pm\",AM:\"AM\",PM:\"PM\",decimal:\".\",mins:\"mins\",hr:\"hr\",hrs:\"hrs\"},w={init:function(b){return this.each(function(){var e=a(this),f=[];for(var g in a.fn.timepicker.defaults)e.data(g)&&(f[g]=e.data(g));var h=a.extend({},a.fn.timepicker.defaults,f,b);if(h.lang&&(v=a.extend(v,h.lang)),h=c(h),e.data(\"timepicker-settings\",h),e.addClass(\"ui-timepicker-input\"),h.useSelect)d(e);else{if(e.prop(\"autocomplete\",\"off\"),h.showOn)for(var i in h.showOn)e.on(h.showOn[i]+\".timepicker\",w.show);e.on(\"change.timepicker\",k),e.on(\"keydown.timepicker\",o),e.on(\"keyup.timepicker\",p),h.disableTextInput&&e.on(\"keydown.timepicker\",n),k.call(e.get(0))}})},show:function(c){var e=a(this),f=e.data(\"timepicker-settings\");if(c&&c.preventDefault(),f.useSelect)return void e.data(\"timepicker-list\").focus();h(e)&&e.blur();var k=e.data(\"timepicker-list\");if(!e.prop(\"readonly\")&&(k&&0!==k.length&&\"function\"!=typeof f.durationTime||(d(e),k=e.data(\"timepicker-list\")),!b(k))){e.data(\"ui-timepicker-value\",e.val()),j(e,k),w.hide(),k.show();var m={};f.orientation.match(/r/)?m.left=e.offset().left+e.outerWidth()-k.outerWidth()+parseInt(k.css(\"marginLeft\").replace(\"px\",\"\"),10):m.left=e.offset().left+parseInt(k.css(\"marginLeft\").replace(\"px\",\"\"),10);var n;n=f.orientation.match(/t/)?\"t\":f.orientation.match(/b/)?\"b\":e.offset().top+e.outerHeight(!0)+k.outerHeight()>a(window).height()+a(window).scrollTop()?\"t\":\"b\",\"t\"==n?(k.addClass(\"ui-timepicker-positioned-top\"),m.top=e.offset().top-k.outerHeight()+parseInt(k.css(\"marginTop\").replace(\"px\",\"\"),10)):(k.removeClass(\"ui-timepicker-positioned-top\"),m.top=e.offset().top+e.outerHeight()+parseInt(k.css(\"marginTop\").replace(\"px\",\"\"),10)),k.offset(m);var o=k.find(\".ui-timepicker-selected\");if(!o.length){var p=t(l(e));null!==p?o=i(e,k,p):f.scrollDefault&&(o=i(e,k,f.scrollDefault()))}if(o&&o.length){var q=k.scrollTop()+o.position().top-o.outerHeight();k.scrollTop(q)}else k.scrollTop(0);return f.stopScrollPropagation&&a(document).on(\"wheel.ui-timepicker\",\".ui-timepicker-wrapper\",function(b){b.preventDefault();var c=a(this).scrollTop();a(this).scrollTop(c+b.originalEvent.deltaY)}),a(document).on(\"touchstart.ui-timepicker mousedown.ui-timepicker\",g),a(window).on(\"resize.ui-timepicker\",g),f.closeOnWindowScroll&&a(document).on(\"scroll.ui-timepicker\",g),e.trigger(\"showTimepicker\"),this}},hide:function(c){var d=a(this),e=d.data(\"timepicker-settings\");return e&&e.useSelect&&d.blur(),a(\".ui-timepicker-wrapper\").each(function(){var c=a(this);if(b(c)){var d=c.data(\"timepicker-input\"),e=d.data(\"timepicker-settings\");e&&e.selectOnBlur&&q(d),c.hide(),d.trigger(\"hideTimepicker\")}}),this},option:function(b,e){return\"string\"==typeof b&&\"undefined\"==typeof e?a(this).data(\"timepicker-settings\")[b]:this.each(function(){var f=a(this),g=f.data(\"timepicker-settings\"),h=f.data(\"timepicker-list\");\"object\"==typeof b?g=a.extend(g,b):\"string\"==typeof b&&(g[b]=e),g=c(g),f.data(\"timepicker-settings\",g),h&&(h.remove(),f.data(\"timepicker-list\",!1)),g.useSelect&&d(f)})},getSecondsFromMidnight:function(){return t(l(this))},getTime:function(a){var b=this,c=l(b);if(!c)return null;var d=t(c);if(null===d)return null;a||(a=new Date);var e=new Date(a);return e.setHours(d/3600),e.setMinutes(d%3600/60),e.setSeconds(d%60),e.setMilliseconds(0),e},isVisible:function(){var a=this,c=a.data(\"timepicker-list\");return!(!c||!b(c))},setTime:function(a){var b=this,c=b.data(\"timepicker-settings\");if(c.forceRoundTime)var d=f(t(a),c);else var d=s(t(a),c);return a&&null===d&&c.noneOption&&(d=a),m(b,d),b.data(\"timepicker-list\")&&j(b,b.data(\"timepicker-list\")),this},remove:function(){var a=this;if(a.hasClass(\"ui-timepicker-input\")){var b=a.data(\"timepicker-settings\");return a.removeAttr(\"autocomplete\",\"off\"),a.removeClass(\"ui-timepicker-input\"),a.removeData(\"timepicker-settings\"),a.off(\".timepicker\"),a.data(\"timepicker-list\")&&a.data(\"timepicker-list\").remove(),b.useSelect&&a.show(),a.removeData(\"timepicker-list\"),this}}};a.fn.timepicker=function(b){return this.length?w[b]?this.hasClass(\"ui-timepicker-input\")?w[b].apply(this,Array.prototype.slice.call(arguments,1)):this:\"object\"!=typeof b&&b?void a.error(\"Method \"+b+\" does not exist on jQuery.timepicker\"):w.init.apply(this,arguments):this},a.fn.timepicker.defaults={appendTo:\"body\",className:null,closeOnWindowScroll:!1,disableTextInput:!1,disableTimeRanges:[],disableTouchKeyboard:!1,durationTime:null,forceRoundTime:!1,maxTime:null,minTime:null,noneOption:!1,orientation:\"l\",roundingFunction:function(a,b){if(null===a)return null;if(\"number\"!=typeof b.step)return a;var c=a%(60*b.step);return c>=30*b.step?a+=60*b.step-c:a-=c,a==u&&b.show2400?a:a%u},scrollDefault:null,selectOnBlur:!1,show2400:!1,showDuration:!1,showOn:[\"click\",\"focus\"],showOnFocus:!0,step:30,stopScrollPropagation:!1,timeFormat:\"g:ia\",typeaheadHighlight:!0,useSelect:!1}});"
  },
  {
    "path": "src/libs/minicolors/jquery.minicolors.css",
    "content": ".minicolors {\n\tposition: relative;\n}\n\n.minicolors-swatch {\n\tposition: absolute;\n\tvertical-align: middle;\n\tbackground: url(\"jquery.minicolors.png\") -80px 0;\n\tborder: solid 1px #ccc;\n\tcursor: text;\n\tpadding: 0;\n\tmargin: 0;\n\tdisplay: inline-block;\n}\n\n.minicolors-swatch-color {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n}\n\n.minicolors input[type=hidden] + .minicolors-swatch {\n\twidth: 28px;\n\tposition: static;\n\tcursor: pointer;\n}\n\n/* Panel */\n.minicolors-panel {\n\tposition: absolute;\n\twidth: 173px;\n\theight: 152px;\n\tbackground: white;\n\tborder: solid 1px #CCC;\n\tbox-shadow: 0 0 20px rgba(0, 0, 0, .2);\n\tz-index: 99999;\n\t-moz-box-sizing: content-box;\n\t-webkit-box-sizing: content-box;\n\tbox-sizing: content-box;\n\tdisplay: none;\n}\n\n.minicolors-panel.minicolors-visible {\n\tdisplay: block;\n}\n\n/* Panel positioning */\n.minicolors-position-top .minicolors-panel {\n\ttop: -154px;\n}\n\n.minicolors-position-right .minicolors-panel {\n\tright: 0;\n}\n\n.minicolors-position-bottom .minicolors-panel {\n\ttop: auto;\n}\n\n.minicolors-position-left .minicolors-panel {\n\tleft: 0;\n}\n\n.minicolors-with-opacity .minicolors-panel {\n\twidth: 194px;\n}\n\n.minicolors .minicolors-grid {\n\tposition: absolute;\n\ttop: 1px;\n\tleft: 1px;\n\twidth: 150px;\n\theight: 150px;\n\tbackground: url(\"jquery.minicolors.png\") -120px 0;\n\tcursor: crosshair;\n}\n\n.minicolors .minicolors-grid-inner {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 150px;\n\theight: 150px;\n\tbackground: none;\n}\n\n.minicolors-slider-saturation .minicolors-grid {\n\tbackground-position: -420px 0;\n}\n\n.minicolors-slider-saturation .minicolors-grid-inner {\n\tbackground: url(\"jquery.minicolors.png\") -270px 0;\n}\n\n.minicolors-slider-brightness .minicolors-grid {\n\tbackground-position: -570px 0;\n}\n\n.minicolors-slider-brightness .minicolors-grid-inner {\n\tbackground: black;\n}\n\n.minicolors-slider-wheel .minicolors-grid {\n\tbackground-position: -720px 0;\n}\n\n.minicolors-slider,\n.minicolors-opacity-slider {\n\tposition: absolute;\n\ttop: 1px;\n\tleft: 152px;\n\twidth: 20px;\n\theight: 150px;\n\tbackground: white url(\"jquery.minicolors.png\") 0 0;\n\tcursor: row-resize;\n}\n\n.minicolors-slider-saturation .minicolors-slider {\n\tbackground-position: -60px 0;\n}\n\n.minicolors-slider-brightness .minicolors-slider {\n\tbackground-position: -20px 0;\n}\n\n.minicolors-slider-wheel .minicolors-slider {\n\tbackground-position: -20px 0;\n}\n\n.minicolors-opacity-slider {\n\tleft: 173px;\n\tbackground-position: -40px 0;\n\tdisplay: none;\n}\n\n.minicolors-with-opacity .minicolors-opacity-slider {\n\tdisplay: block;\n}\n\n/* Pickers */\n.minicolors-grid .minicolors-picker {\n\tposition: absolute;\n\ttop: 70px;\n\tleft: 70px;\n\twidth: 12px;\n\theight: 12px;\n\tborder: solid 1px black;\n\tborder-radius: 10px;\n\tmargin-top: -6px;\n\tmargin-left: -6px;\n\tbackground: none;\n}\n\n.minicolors-grid .minicolors-picker > div {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 8px;\n\tborder: solid 2px white;\n\t-moz-box-sizing: content-box;\n\t-webkit-box-sizing: content-box;\n\tbox-sizing: content-box;\n}\n\n.minicolors-picker {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 18px;\n\theight: 2px;\n\tbackground: white;\n\tborder: solid 1px black;\n\tmargin-top: -2px;\n\t-moz-box-sizing: content-box;\n\t-webkit-box-sizing: content-box;\n\tbox-sizing: content-box;\n}\n\n/* Inline controls */\n.minicolors-inline {\n\tdisplay: inline-block;\n}\n\n.minicolors-inline .minicolors-input {\n\tdisplay: none !important;\n}\n\n.minicolors-inline .minicolors-panel {\n\tposition: relative;\n\ttop: auto;\n\tleft: auto;\n\tbox-shadow: none;\n\tz-index: auto;\n\tdisplay: inline-block;\n}\n\n/* Default theme */\n.minicolors-theme-default .minicolors-swatch {\n\ttop: 5px;\n\tleft: 5px;\n\twidth: 18px;\n\theight: 18px;\t\n}\n.minicolors-theme-default.minicolors-position-right .minicolors-swatch {\n\tleft: auto;\n\tright: 5px;\n}\n.minicolors-theme-default.minicolors {\n\twidth: auto;\n\tdisplay: inline-block;\n}\n.minicolors-theme-default .minicolors-input {\n\theight: 20px;\n\twidth: auto;\n\tdisplay: inline-block;\n\tpadding-left: 26px;\n}\n.minicolors-theme-default.minicolors-position-right .minicolors-input {\n\tpadding-right: 26px;\n\tpadding-left: inherit;\n}\n\n/* Bootstrap theme */\n.minicolors-theme-bootstrap .minicolors-swatch {\n\ttop: 3px;\n\tleft: 3px;\n\twidth: 28px;\n\theight: 28px;\n\tborder-radius: 3px;\n}\n.minicolors-theme-bootstrap.minicolors-position-right .minicolors-swatch {\n\tleft: auto;\n\tright: 3px;\n}\n.minicolors-theme-bootstrap .minicolors-input {\n\tpadding-left: 44px;\n}\n.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input {\n\tpadding-right: 44px;\n\tpadding-left: 12px;\n}"
  },
  {
    "path": "src/libs/minicolors/jquery.minicolors.js",
    "content": "/*\n * jQuery MiniColors: A tiny color picker built on jQuery\n *\n * Copyright Cory LaViska for A Beautiful Site, LLC. (http://www.abeautifulsite.net/)\n *\n * Licensed under the MIT license: http://opensource.org/licenses/MIT\n *\n * Demo: http://www.digitalsignage.com/tmp/minicolors/jquery-minicolors-master/\n */\nif(jQuery) (function($) {\n\t\n\t// Defaults\n\t$.minicolors = {\n\t\tdefaults: {\n\t\t\tanimationSpeed: 50,\n\t\t\tanimationEasing: 'swing',\n\t\t\tchange: null,\n\t\t\tchangeDelay: 0,\n\t\t\tcontrol: 'hue',\n\t\t\tdefaultValue: '',\n\t\t\thide: null,\n\t\t\thideSpeed: 100,\n\t\t\tinline: false,\n\t\t\tletterCase: 'lowercase',\n\t\t\topacity: false,\n\t\t\tposition: 'bottom left',\n\t\t\tshow: null,\n\t\t\tshowSpeed: 100,\n\t\t\ttheme: 'default'\n\t\t}\n\t};\n\t\n\t// Public methods\n\t$.extend($.fn, {\n\t\tminicolors: function(method, data) {\n\t\t\t\n\t\t\tswitch(method) {\n\t\t\t\t\n\t\t\t\t// Destroy the control\n\t\t\t\tcase 'destroy':\n\t\t\t\t\t$(this).each( function() {\n\t\t\t\t\t\tdestroy($(this));\n\t\t\t\t\t});\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t\t// Hide the color picker\n\t\t\t\tcase 'hide':\n\t\t\t\t\thide();\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t\t// Get/set opacity\n\t\t\t\tcase 'opacity':\n\t\t\t\t\t// Getter\n\t\t\t\t\tif( data === undefined ) {\n\t\t\t\t\t\t// Getter\n\t\t\t\t\t\treturn $(this).attr('data-opacity');\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Setter\n\t\t\t\t\t\t$(this).each( function() {\n\t\t\t\t\t\t\tupdateFromInput($(this).attr('data-opacity', data));\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t\t// Get an RGB(A) object based on the current color/opacity\n\t\t\t\tcase 'rgbObject':\n\t\t\t\t\treturn rgbObject($(this), method === 'rgbaObject');\n\t\t\t\t\n\t\t\t\t// Get an RGB(A) string based on the current color/opacity\n\t\t\t\tcase 'rgbString':\n\t\t\t\tcase 'rgbaString':\n\t\t\t\t\treturn rgbString($(this), method === 'rgbaString');\n\t\t\t\t\n\t\t\t\t// Get/set settings on the fly\n\t\t\t\tcase 'settings':\n\t\t\t\t\tif( data === undefined ) {\n\t\t\t\t\t\treturn $(this).data('minicolors-settings');\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Setter\n\t\t\t\t\t\t$(this).each( function() {\n\t\t\t\t\t\t\tvar settings = $(this).data('minicolors-settings') || {};\n\t\t\t\t\t\t\tdestroy($(this));\n\t\t\t\t\t\t\t$(this).minicolors($.extend(true, settings, data));\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t\t// Show the color picker\n\t\t\t\tcase 'show':\n\t\t\t\t\tshow( $(this).eq(0) );\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t\t// Get/set the hex color value\n\t\t\t\tcase 'value':\n\t\t\t\t\tif( data === undefined ) {\n\t\t\t\t\t\t// Getter\n\t\t\t\t\t\treturn $(this).val();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Setter\n\t\t\t\t\t\t$(this).each( function() {\n\t\t\t\t\t\t\tupdateFromInput($(this).val(data));\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t\t// Initializes the control\n\t\t\t\tdefault:\n\t\t\t\t\tif( method !== 'create' ) data = method;\n\t\t\t\t\t$(this).each( function() {\n\t\t\t\t\t\tinit($(this), data);\n\t\t\t\t\t});\n\t\t\t\t\treturn $(this);\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t}\n\t});\n\t\n\t// Initialize input elements\n\tfunction init(input, settings) {\n\t\t\n\t\tvar minicolors = $('<div class=\"minicolors\" />'),\n\t\t\tdefaults = $.minicolors.defaults;\n\t\t\n\t\t// Do nothing if already initialized\n\t\tif( input.data('minicolors-initialized') ) return;\n\t\t\n\t\t// Handle settings\n\t\tsettings = $.extend(true, {}, defaults, settings);\n\t\t\n\t\t// The wrapper\n\t\tminicolors\n\t\t\t.addClass('minicolors-theme-' + settings.theme)\n\t\t\t.toggleClass('minicolors-with-opacity', settings.opacity);\n\t\t\n\t\t// Custom positioning\n\t\tif( settings.position !== undefined ) {\n\t\t\t$.each(settings.position.split(' '), function() {\n\t\t\t\tminicolors.addClass('minicolors-position-' + this);\n\t\t\t});\n\t\t}\n\t\t\n\t\t// The input\n\t\tinput\n\t\t\t.addClass('minicolors-input')\n\t\t\t.data('minicolors-initialized', false)\n\t\t\t.data('minicolors-settings', settings)\n\t\t\t.prop('size', 7)\n\t\t\t.wrap(minicolors)\n\t\t\t.after(\n\t\t\t\t'<div class=\"minicolors-panel minicolors-slider-' + settings.control + '\">' + \n\t\t\t\t\t'<div class=\"minicolors-slider\">' + \n\t\t\t\t\t\t'<div class=\"minicolors-picker\"></div>' +\n\t\t\t\t\t'</div>' + \n\t\t\t\t\t'<div class=\"minicolors-opacity-slider\">' + \n\t\t\t\t\t\t'<div class=\"minicolors-picker\"></div>' +\n\t\t\t\t\t'</div>' +\n\t\t\t\t\t'<div class=\"minicolors-grid\">' +\n\t\t\t\t\t\t'<div class=\"minicolors-grid-inner\"></div>' +\n\t\t\t\t\t\t'<div class=\"minicolors-picker\"><div></div></div>' +\n\t\t\t\t\t'</div>' +\n\t\t\t\t'</div>'\n\t\t\t);\n\t\t\n\t\t// The swatch\n\t\tif( !settings.inline ) {\n\t\t\tinput.after('<span class=\"minicolors-swatch\"><span class=\"minicolors-swatch-color\"></span></span>');\n\t\t\tinput.next('.minicolors-swatch').on('click', function(event) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tinput.focus();\n\t\t\t});\n\t\t}\n\t\t\n\t\t// Prevent text selection in IE\n\t\tinput.parent().find('.minicolors-panel').on('selectstart', function() { return false; }).end();\n\t\t\n\t\t// Inline controls\n\t\tif( settings.inline ) input.parent().addClass('minicolors-inline');\n\t\t\n\t\tupdateFromInput(input, false);\n\t\t\n\t\tinput.data('minicolors-initialized', true);\n\t\t\n\t}\n\t\n\t// Returns the input back to its original state\n\tfunction destroy(input) {\n\t\t\n\t\tvar minicolors = input.parent();\n\t\t\n\t\t// Revert the input element\n\t\tinput\n\t\t\t.removeData('minicolors-initialized')\n\t\t\t.removeData('minicolors-settings')\n\t\t\t.removeProp('size')\n\t\t\t.removeClass('minicolors-input');\n\t\t\n\t\t// Remove the wrap and destroy whatever remains\n\t\tminicolors.before(input).remove();\n\t\t\n\t}\n\t\n\t// Shows the specified dropdown panel\n\tfunction show(input) {\n\t\t\n\t\tvar minicolors = input.parent(),\n\t\t\tpanel = minicolors.find('.minicolors-panel'),\n\t\t\tsettings = input.data('minicolors-settings');\n\t\t\n\t\t// Do nothing if uninitialized, disabled, inline, or already open\n\t\tif( !input.data('minicolors-initialized') || \n\t\t\tinput.prop('disabled') || \n\t\t\tminicolors.hasClass('minicolors-inline') || \n\t\t\tminicolors.hasClass('minicolors-focus')\n\t\t) return;\n\t\t\n\t\thide();\n\t\t\n\t\tminicolors.addClass('minicolors-focus');\n\t\tpanel\n\t\t\t.stop(true, true)\n\t\t\t.fadeIn(settings.showSpeed, function() {\n\t\t\t\tif( settings.show ) settings.show.call(input.get(0));\n\t\t\t});\n\t\t\n\t}\n\t\n\t// Hides all dropdown panels\n\tfunction hide() {\n\t\t\n\t\t$('.minicolors-focus').each( function() {\n\t\t\t\n\t\t\tvar minicolors = $(this),\n\t\t\t\tinput = minicolors.find('.minicolors-input'),\n\t\t\t\tpanel = minicolors.find('.minicolors-panel'),\n\t\t\t\tsettings = input.data('minicolors-settings');\n\t\t\t\n\t\t\tpanel.fadeOut(settings.hideSpeed, function() {\n\t\t\t\tif( settings.hide ) settings.hide.call(input.get(0));\n\t\t\t\tminicolors.removeClass('minicolors-focus');\n\t\t\t});\t\t\t\n\t\t\t\t\t\t\n\t\t});\n\t}\n\t\n\t// Moves the selected picker\n\tfunction move(target, event, animate) {\n\t\t\n\t\tvar input = target.parents('.minicolors').find('.minicolors-input'),\n\t\t\tsettings = input.data('minicolors-settings'),\n\t\t\tpicker = target.find('[class$=-picker]'),\n\t\t\toffsetX = target.offset().left,\n\t\t\toffsetY = target.offset().top,\n\t\t\tx = Math.round(event.pageX - offsetX),\n\t\t\ty = Math.round(event.pageY - offsetY),\n\t\t\tduration = animate ? settings.animationSpeed : 0,\n\t\t\twx, wy, r, phi;\n\t\t\t\n\t\t// Touch support\n\t\tif( event.originalEvent.changedTouches ) {\n\t\t\tx = event.originalEvent.changedTouches[0].pageX - offsetX;\n\t\t\ty = event.originalEvent.changedTouches[0].pageY - offsetY;\n\t\t}\n\t\t\n\t\t// Constrain picker to its container\n\t\tif( x < 0 ) x = 0;\n\t\tif( y < 0 ) y = 0;\n\t\tif( x > target.width() ) x = target.width();\n\t\tif( y > target.height() ) y = target.height();\n\t\t\n\t\t// Constrain color wheel values to the wheel\n\t\tif( target.parent().is('.minicolors-slider-wheel') && picker.parent().is('.minicolors-grid') ) {\n\t\t\twx = 75 - x;\n\t\t\twy = 75 - y;\n\t\t\tr = Math.sqrt(wx * wx + wy * wy);\n\t\t\tphi = Math.atan2(wy, wx);\n\t\t\tif( phi < 0 ) phi += Math.PI * 2;\n\t\t\tif( r > 75 ) {\n\t\t\t\tr = 75;\n\t\t\t\tx = 75 - (75 * Math.cos(phi));\n\t\t\t\ty = 75 - (75 * Math.sin(phi));\n\t\t\t}\n\t\t\tx = Math.round(x);\n\t\t\ty = Math.round(y);\n\t\t}\n\t\t\n\t\t// Move the picker\n\t\tif( target.is('.minicolors-grid') ) {\n\t\t\tpicker\n\t\t\t\t.stop(true)\n\t\t\t\t.animate({\n\t\t\t\t\ttop: y + 'px',\n\t\t\t\t\tleft: x + 'px'\n\t\t\t\t}, duration, settings.animationEasing, function() {\n\t\t\t\t\tupdateFromControl(input, target);\n\t\t\t\t});\n\t\t} else {\n\t\t\tpicker\n\t\t\t\t.stop(true)\n\t\t\t\t.animate({\n\t\t\t\t\ttop: y + 'px'\n\t\t\t\t}, duration, settings.animationEasing, function() {\n\t\t\t\t\tupdateFromControl(input, target);\n\t\t\t\t});\n\t\t}\n\t\t\n\t}\n\t\n\t// Sets the input based on the color picker values\n\tfunction updateFromControl(input, target) {\n\t\t\n\t\tfunction getCoords(picker, container) {\n\t\t\t\n\t\t\tvar left, top;\n\t\t\tif( !picker.length || !container ) return null;\n\t\t\tleft = picker.offset().left;\n\t\t\ttop = picker.offset().top;\n\t\t\t\n\t\t\treturn {\n\t\t\t\tx: left - container.offset().left + (picker.outerWidth() / 2),\n\t\t\t\ty: top - container.offset().top + (picker.outerHeight() / 2)\n\t\t\t};\n\t\t\t\n\t\t}\n\t\t\n\t\tvar hue, saturation, brightness, x, y, r, phi,\n\t\t\t\n\t\t\thex = input.val(),\n\t\t\topacity = input.attr('data-opacity'),\n\t\t\t\n\t\t\t// Helpful references\n\t\t\tminicolors = input.parent(),\n\t\t\tsettings = input.data('minicolors-settings'),\n\t\t\tswatch = minicolors.find('.minicolors-swatch'),\n\t\t\t\n\t\t\t// Panel objects\n\t\t\tgrid = minicolors.find('.minicolors-grid'),\n\t\t\tslider = minicolors.find('.minicolors-slider'),\n\t\t\topacitySlider = minicolors.find('.minicolors-opacity-slider'),\n\t\t\t\n\t\t\t// Picker objects\n\t\t\tgridPicker = grid.find('[class$=-picker]'),\n\t\t\tsliderPicker = slider.find('[class$=-picker]'),\n\t\t\topacityPicker = opacitySlider.find('[class$=-picker]'),\n\t\t\t\n\t\t\t// Picker positions\n\t\t\tgridPos = getCoords(gridPicker, grid),\n\t\t\tsliderPos = getCoords(sliderPicker, slider),\n\t\t\topacityPos = getCoords(opacityPicker, opacitySlider);\n\t\t\n\t\t// Handle colors\n\t\tif( target.is('.minicolors-grid, .minicolors-slider') ) {\n\t\t\t\n\t\t\t// Determine HSB values\n\t\t\tswitch(settings.control) {\n\t\t\t\t\n\t\t\t\tcase 'wheel':\n\t\t\t\t\t// Calculate hue, saturation, and brightness\n\t\t\t\t\tx = (grid.width() / 2) - gridPos.x;\n\t\t\t\t\ty = (grid.height() / 2) - gridPos.y;\n\t\t\t\t\tr = Math.sqrt(x * x + y * y);\n\t\t\t\t\tphi = Math.atan2(y, x);\n\t\t\t\t\tif( phi < 0 ) phi += Math.PI * 2;\n\t\t\t\t\tif( r > 75 ) {\n\t\t\t\t\t\tr = 75;\n\t\t\t\t\t\tgridPos.x = 69 - (75 * Math.cos(phi));\n\t\t\t\t\t\tgridPos.y = 69 - (75 * Math.sin(phi));\n\t\t\t\t\t}\n\t\t\t\t\tsaturation = keepWithin(r / 0.75, 0, 100);\n\t\t\t\t\thue = keepWithin(phi * 180 / Math.PI, 0, 360);\n\t\t\t\t\tbrightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);\n\t\t\t\t\thex = hsb2hex({\n\t\t\t\t\t\th: hue,\n\t\t\t\t\t\ts: saturation,\n\t\t\t\t\t\tb: brightness\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\t// Update UI\n\t\t\t\t\tslider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 }));\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tcase 'saturation':\n\t\t\t\t\t// Calculate hue, saturation, and brightness\n\t\t\t\t\thue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360);\n\t\t\t\t\tsaturation = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);\n\t\t\t\t\tbrightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);\n\t\t\t\t\thex = hsb2hex({\n\t\t\t\t\t\th: hue,\n\t\t\t\t\t\ts: saturation,\n\t\t\t\t\t\tb: brightness\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\t// Update UI\n\t\t\t\t\tslider.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: brightness }));\n\t\t\t\t\tminicolors.find('.minicolors-grid-inner').css('opacity', saturation / 100);\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tcase 'brightness':\n\t\t\t\t\t// Calculate hue, saturation, and brightness\n\t\t\t\t\thue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360);\n\t\t\t\t\tsaturation = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);\n\t\t\t\t\tbrightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);\n\t\t\t\t\thex = hsb2hex({\n\t\t\t\t\t\th: hue,\n\t\t\t\t\t\ts: saturation,\n\t\t\t\t\t\tb: brightness\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\t// Update UI\n\t\t\t\t\tslider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 }));\n\t\t\t\t\tminicolors.find('.minicolors-grid-inner').css('opacity', 1 - (brightness / 100));\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tdefault:\n\t\t\t\t\t// Calculate hue, saturation, and brightness\n\t\t\t\t\thue = keepWithin(360 - parseInt(sliderPos.y * (360 / slider.height()), 10), 0, 360);\n\t\t\t\t\tsaturation = keepWithin(Math.floor(gridPos.x * (100 / grid.width())), 0, 100);\n\t\t\t\t\tbrightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);\n\t\t\t\t\thex = hsb2hex({\n\t\t\t\t\t\th: hue,\n\t\t\t\t\t\ts: saturation,\n\t\t\t\t\t\tb: brightness\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\t// Update UI\n\t\t\t\t\tgrid.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: 100 }));\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\t// Adjust case\n\t\t\tinput.val( convertCase(hex, settings.letterCase) );\n\t\t\t\n\t\t}\n\t\t\n\t\t// Handle opacity\n\t\tif( target.is('.minicolors-opacity-slider') ) {\n\t\t\tif( settings.opacity ) {\n\t\t\t\topacity = parseFloat(1 - (opacityPos.y / opacitySlider.height())).toFixed(2);\n\t\t\t} else {\n\t\t\t\topacity = 1;\n\t\t\t}\n\t\t\tif( settings.opacity ) input.attr('data-opacity', opacity);\n\t\t}\n\t\t\n\t\t// Set swatch color\n\t\tswatch.find('SPAN').css({\n\t\t\tbackgroundColor: hex,\n\t\t\topacity: opacity\n\t\t});\n\t\t\n\t\t// Handle change event\n\t\tdoChange(input, hex, opacity);\n\t\t\n\t}\n\t\n\t// Sets the color picker values from the input\n\tfunction updateFromInput(input, preserveInputValue) {\n\t\t\n\t\tvar hex,\n\t\t\thsb,\n\t\t\topacity,\n\t\t\tx, y, r, phi,\n\t\t\t\n\t\t\t// Helpful references\n\t\t\tminicolors = input.parent(),\n\t\t\tsettings = input.data('minicolors-settings'),\n\t\t\tswatch = minicolors.find('.minicolors-swatch'),\n\t\t\t\n\t\t\t// Panel objects\n\t\t\tgrid = minicolors.find('.minicolors-grid'),\n\t\t\tslider = minicolors.find('.minicolors-slider'),\n\t\t\topacitySlider = minicolors.find('.minicolors-opacity-slider'),\n\t\t\t\n\t\t\t// Picker objects\n\t\t\tgridPicker = grid.find('[class$=-picker]'),\n\t\t\tsliderPicker = slider.find('[class$=-picker]'),\n\t\t\topacityPicker = opacitySlider.find('[class$=-picker]');\n\t\t\n\t\t// Determine hex/HSB values\n\t\thex = convertCase(parseHex(input.val(), true), settings.letterCase);\n\t\tif( !hex ){\n\t\t\thex = convertCase(parseHex(settings.defaultValue, true), settings.letterCase);\n\t\t}\n\t\thsb = hex2hsb(hex);\n\t\t\n\t\t// Update input value\n\t\tif( !preserveInputValue ) input.val(hex);\n\t\t\n\t\t// Determine opacity value\n\t\tif( settings.opacity ) {\n\t\t\t// Get from data-opacity attribute and keep within 0-1 range\n\t\t\topacity = input.attr('data-opacity') === '' ? 1 : keepWithin(parseFloat(input.attr('data-opacity')).toFixed(2), 0, 1);\n\t\t\tif( isNaN(opacity) ) opacity = 1;\n\t\t\tinput.attr('data-opacity', opacity);\n\t\t\tswatch.find('SPAN').css('opacity', opacity);\n\t\t\t\n\t\t\t// Set opacity picker position\n\t\t\ty = keepWithin(opacitySlider.height() - (opacitySlider.height() * opacity), 0, opacitySlider.height());\n\t\t\topacityPicker.css('top', y + 'px');\n\t\t}\n\t\t\n\t\t// Update swatch\n\t\tswatch.find('SPAN').css('backgroundColor', hex);\n\t\t\n\t\t// Determine picker locations\n\t\tswitch(settings.control) {\n\t\t\t\n\t\t\tcase 'wheel':\n\t\t\t\t// Set grid position\n\t\t\t\tr = keepWithin(Math.ceil(hsb.s * 0.75), 0, grid.height() / 2);\n\t\t\t\tphi = hsb.h * Math.PI / 180;\n\t\t\t\tx = keepWithin(75 - Math.cos(phi) * r, 0, grid.width());\n\t\t\t\ty = keepWithin(75 - Math.sin(phi) * r, 0, grid.height());\n\t\t\t\tgridPicker.css({\n\t\t\t\t\ttop: y + 'px',\n\t\t\t\t\tleft: x + 'px'\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\t// Set slider position\n\t\t\t\ty = 150 - (hsb.b / (100 / grid.height()));\n\t\t\t\tif( hex === '' ) y = 0;\n\t\t\t\tsliderPicker.css('top', y + 'px');\n\t\t\t\t\n\t\t\t\t// Update panel color\n\t\t\t\tslider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 }));\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tcase 'saturation':\n\t\t\t\t// Set grid position\n\t\t\t\tx = keepWithin((5 * hsb.h) / 12, 0, 150);\n\t\t\t\ty = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height());\n\t\t\t\tgridPicker.css({\n\t\t\t\t\ttop: y + 'px',\n\t\t\t\t\tleft: x + 'px'\n\t\t\t\t});\t\t\t\t\n\t\t\t\t\n\t\t\t\t// Set slider position\n\t\t\t\ty = keepWithin(slider.height() - (hsb.s * (slider.height() / 100)), 0, slider.height());\n\t\t\t\tsliderPicker.css('top', y + 'px');\n\t\t\t\t\n\t\t\t\t// Update UI\n\t\t\t\tslider.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: hsb.b }));\n\t\t\t\tminicolors.find('.minicolors-grid-inner').css('opacity', hsb.s / 100);\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tcase 'brightness':\n\t\t\t\t// Set grid position\n\t\t\t\tx = keepWithin((5 * hsb.h) / 12, 0, 150);\n\t\t\t\ty = keepWithin(grid.height() - Math.ceil(hsb.s / (100 / grid.height())), 0, grid.height());\n\t\t\t\tgridPicker.css({\n\t\t\t\t\ttop: y + 'px',\n\t\t\t\t\tleft: x + 'px'\n\t\t\t\t});\t\t\t\t\n\t\t\t\t\n\t\t\t\t// Set slider position\n\t\t\t\ty = keepWithin(slider.height() - (hsb.b * (slider.height() / 100)), 0, slider.height());\n\t\t\t\tsliderPicker.css('top', y + 'px');\n\t\t\t\t\n\t\t\t\t// Update UI\n\t\t\t\tslider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 }));\n\t\t\t\tminicolors.find('.minicolors-grid-inner').css('opacity', 1 - (hsb.b / 100));\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tdefault:\n\t\t\t\t// Set grid position\n\t\t\t\tx = keepWithin(Math.ceil(hsb.s / (100 / grid.width())), 0, grid.width());\n\t\t\t\ty = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height());\n\t\t\t\tgridPicker.css({\n\t\t\t\t\ttop: y + 'px',\n\t\t\t\t\tleft: x + 'px'\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\t// Set slider position\n\t\t\t\ty = keepWithin(slider.height() - (hsb.h / (360 / slider.height())), 0, slider.height());\n\t\t\t\tsliderPicker.css('top', y + 'px');\n\t\t\t\t\n\t\t\t\t// Update panel color\n\t\t\t\tgrid.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: 100 }));\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t}\n\t\t\n\t\t// Fire change event, but only if minicolors is fully initialized\n\t\tif( input.data('minicolors-initialized') ) {\n\t\t\tdoChange(input, hex, opacity);\n\t\t}\n\t\t\n\t}\n\t\n\t// Runs the change and changeDelay callbacks\n\tfunction doChange(input, hex, opacity) {\n\t\t\n\t\tvar settings = input.data('minicolors-settings'),\n\t\t\tlastChange = input.data('minicolors-lastChange');\n\t\t\n\t\t// Only run if it actually changed\n\t\tif( !lastChange || lastChange.hex !== hex || lastChange.opacity !== opacity ) {\n\t\t\t\n\t\t\t// Remember last-changed value\n\t\t\tinput.data('minicolors-lastChange', {\n\t\t\t\thex: hex,\n\t\t\t\topacity: opacity\n\t\t\t});\n\t\t\t\n\t\t\t// Fire change event\n\t\t\tif( settings.change ) {\n\t\t\t\tif( settings.changeDelay ) {\n\t\t\t\t\t// Call after a delay\n\t\t\t\t\tclearTimeout(input.data('minicolors-changeTimeout'));\n\t\t\t\t\tinput.data('minicolors-changeTimeout', setTimeout( function() {\n\t\t\t\t\t\tsettings.change.call(input.get(0), hex, opacity);\n\t\t\t\t\t}, settings.changeDelay));\n\t\t\t\t} else {\n\t\t\t\t\t// Call immediately\n\t\t\t\t\tsettings.change.call(input.get(0), hex, opacity);\n\t\t\t\t}\n\t\t\t}\n\t\t\tinput.trigger('change').trigger('input');\n\t\t}\n\t\n\t}\n\t\n\t// Generates an RGB(A) object based on the input's value\n\tfunction rgbObject(input) {\n\t\tvar hex = parseHex($(input).val(), true),\n\t\t\trgb = hex2rgb(hex),\n\t\t\topacity = $(input).attr('data-opacity');\n\t\tif( !rgb ) return null;\n\t\tif( opacity !== undefined ) $.extend(rgb, { a: parseFloat(opacity) });\n\t\treturn rgb;\n\t}\n\t\n\t// Genearates an RGB(A) string based on the input's value\n\tfunction rgbString(input, alpha) {\n\t\tvar hex = parseHex($(input).val(), true),\n\t\t\trgb = hex2rgb(hex),\n\t\t\topacity = $(input).attr('data-opacity');\n\t\tif( !rgb ) return null;\n\t\tif( opacity === undefined ) opacity = 1;\n\t\tif( alpha ) {\n\t\t\treturn 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(opacity) + ')';\n\t\t} else {\n\t\t\treturn 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')';\n\t\t}\n\t}\n\t\n\t// Converts to the letter case specified in settings\n\tfunction convertCase(string, letterCase) {\n\t\treturn letterCase === 'uppercase' ? string.toUpperCase() : string.toLowerCase();\n\t}\n\t\n\t// Parses a string and returns a valid hex string when possible\n\tfunction parseHex(string, expand) {\n\t\tstring = string.replace(/[^A-F0-9]/ig, '');\n\t\tif( string.length !== 3 && string.length !== 6 ) return '';\n\t\tif( string.length === 3 && expand ) {\n\t\t\tstring = string[0] + string[0] + string[1] + string[1] + string[2] + string[2];\n\t\t}\n\t\treturn '#' + string;\n\t}\n\t\n\t// Keeps value within min and max\n\tfunction keepWithin(value, min, max) {\n\t\tif( value < min ) value = min;\n\t\tif( value > max ) value = max;\n\t\treturn value;\n\t}\n\t\n\t// Converts an HSB object to an RGB object\n\tfunction hsb2rgb(hsb) {\n\t\tvar rgb = {};\n\t\tvar h = Math.round(hsb.h);\n\t\tvar s = Math.round(hsb.s * 255 / 100);\n\t\tvar v = Math.round(hsb.b * 255 / 100);\n\t\tif(s === 0) {\n\t\t\trgb.r = rgb.g = rgb.b = v;\n\t\t} else {\n\t\t\tvar t1 = v;\n\t\t\tvar t2 = (255 - s) * v / 255;\n\t\t\tvar t3 = (t1 - t2) * (h % 60) / 60;\n\t\t\tif( h === 360 ) h = 0;\n\t\t\tif( h < 60 ) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3; }\n\t\t\telse if( h < 120 ) {rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3; }\n\t\t\telse if( h < 180 ) {rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3; }\n\t\t\telse if( h < 240 ) {rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3; }\n\t\t\telse if( h < 300 ) {rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3; }\n\t\t\telse if( h < 360 ) {rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3; }\n\t\t\telse { rgb.r = 0; rgb.g = 0; rgb.b = 0; }\n\t\t}\n\t\treturn {\n\t\t\tr: Math.round(rgb.r),\n\t\t\tg: Math.round(rgb.g),\n\t\t\tb: Math.round(rgb.b)\n\t\t};\n\t}\n\t\n\t// Converts an RGB object to a hex string\n\tfunction rgb2hex(rgb) {\n\t\tvar hex = [\n\t\t\trgb.r.toString(16),\n\t\t\trgb.g.toString(16),\n\t\t\trgb.b.toString(16)\n\t\t];\n\t\t$.each(hex, function(nr, val) {\n\t\t\tif (val.length === 1) hex[nr] = '0' + val;\n\t\t});\n\t\treturn '#' + hex.join('');\n\t}\n\t\n\t// Converts an HSB object to a hex string\n\tfunction hsb2hex(hsb) {\n\t\treturn rgb2hex(hsb2rgb(hsb));\n\t}\n\t\n\t// Converts a hex string to an HSB object\n\tfunction hex2hsb(hex) {\n\t\tvar hsb = rgb2hsb(hex2rgb(hex));\n\t\tif( hsb.s === 0 ) hsb.h = 360;\n\t\treturn hsb;\n\t}\n\t\n\t// Converts an RGB object to an HSB object\n\tfunction rgb2hsb(rgb) {\n\t\tvar hsb = { h: 0, s: 0, b: 0 };\n\t\tvar min = Math.min(rgb.r, rgb.g, rgb.b);\n\t\tvar max = Math.max(rgb.r, rgb.g, rgb.b);\n\t\tvar delta = max - min;\n\t\thsb.b = max;\n\t\thsb.s = max !== 0 ? 255 * delta / max : 0;\n\t\tif( hsb.s !== 0 ) {\n\t\t\tif( rgb.r === max ) {\n\t\t\t\thsb.h = (rgb.g - rgb.b) / delta;\n\t\t\t} else if( rgb.g === max ) {\n\t\t\t\thsb.h = 2 + (rgb.b - rgb.r) / delta;\n\t\t\t} else {\n\t\t\t\thsb.h = 4 + (rgb.r - rgb.g) / delta;\n\t\t\t}\n\t\t} else {\n\t\t\thsb.h = -1;\n\t\t}\n\t\thsb.h *= 60;\n\t\tif( hsb.h < 0 ) {\n\t\t\thsb.h += 360;\n\t\t}\n\t\thsb.s *= 100/255;\n\t\thsb.b *= 100/255;\n\t\treturn hsb;\n\t}\n\t\n\t// Converts a hex string to an RGB object\n\tfunction hex2rgb(hex) {\n\t\thex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);\n\t\treturn {\n\t\t\tr: hex >> 16,\n\t\t\tg: (hex & 0x00FF00) >> 8,\n\t\t\tb: (hex & 0x0000FF)\n\t\t};\n\t}\n\t\n\t// Handle events\n\t$(document)\n\t\t// Hide on clicks outside of the control\n\t\t.on('mousedown.minicolors touchstart.minicolors', function(event) {\n\t\t\tif( !$(event.target).parents().add(event.target).hasClass('minicolors') ) {\n\t\t\t\thide();\n\t\t\t}\n\t\t})\n\t\t// Start moving\n\t\t.on('mousedown.minicolors touchstart.minicolors', '.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider', function(event) {\n\t\t\tvar target = $(this);\n\t\t\tevent.preventDefault();\n\t\t\t$(document).data('minicolors-target', target);\n\t\t\tmove(target, event, true);\n\t\t})\n\t\t// Move pickers\n\t\t.on('mousemove.minicolors touchmove.minicolors', function(event) {\n\t\t\tvar target = $(document).data('minicolors-target');\n\t\t\tif( target ) move(target, event);\n\t\t})\n\t\t// Stop moving\n\t\t.on('mouseup.minicolors touchend.minicolors', function() {\n\t\t\t$(this).removeData('minicolors-target');\n\t\t})\n\t\t// Show panel when swatch is clicked\n\t\t.on('mousedown.minicolors touchstart.minicolors', '.minicolors-swatch', function(event) {\n\t\t\tvar input = $(this).parent().find('.minicolors-input');\n\t\t\tevent.preventDefault();\n\t\t\tshow(input);\n\t\t})\n\t\t// Show on focus\n\t\t.on('focus.minicolors', '.minicolors-input', function() {\n\t\t\tvar input = $(this);\n\t\t\tif( !input.data('minicolors-initialized') ) return;\n\t\t\tshow(input);\n\t\t})\n\t\t// Fix hex on blur\n\t\t.on('blur.minicolors', '.minicolors-input', function() {\n\t\t\tvar input = $(this),\n\t\t\t\tsettings = input.data('minicolors-settings');\n\t\t\tif( !input.data('minicolors-initialized') ) return;\n\t\t\t\n\t\t\t// Parse Hex\n\t\t\tinput.val(parseHex(input.val(), true));\n\t\t\t\n\t\t\t// Is it blank?\n\t\t\tif( input.val() === '' ) input.val(parseHex(settings.defaultValue, true));\n\t\t\t\n\t\t\t// Adjust case\n\t\t\tinput.val( convertCase(input.val(), settings.letterCase) );\n\t\t\t\n\t\t})\n\t\t// Handle keypresses\n\t\t.on('keydown.minicolors', '.minicolors-input', function(event) {\n\t\t\tvar input = $(this);\n\t\t\tif( !input.data('minicolors-initialized') ) return;\n\t\t\tswitch(event.keyCode) {\n\t\t\t\tcase 9: // tab\n\t\t\t\t\thide();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 13: // enter\n\t\t\t\tcase 27: // esc\n\t\t\t\t\thide();\n\t\t\t\t\tinput.blur();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t})\n\t\t// Update on keyup\n\t\t.on('keyup.minicolors', '.minicolors-input', function() {\n\t\t\tvar input = $(this);\n\t\t\tif( !input.data('minicolors-initialized') ) return;\n\t\t\tupdateFromInput(input, true);\n\t\t})\n\t\t// Update on paste\n\t\t.on('paste.minicolors', '.minicolors-input', function() {\n\t\t\tvar input = $(this);\n\t\t\tif( !input.data('minicolors-initialized') ) return;\n\t\t\tsetTimeout( function() {\n\t\t\t\tupdateFromInput(input, true);\n\t\t\t}, 1);\n\t\t});\n\t\n})(jQuery);"
  },
  {
    "path": "src/libs/qrcode/qrcode.js",
    "content": "/**\n * @fileoverview\n * - Using the 'QRCode for Javascript library'\n * - Fixed dataset of 'QRCode for Javascript library' for support full-spec.\n * - this library has no dependencies.\n * \n * @author davidshimjs\n * @see <a href=\"http://www.d-project.com/\" target=\"_blank\">http://www.d-project.com/</a>\n * @see <a href=\"http://jeromeetienne.github.com/jquery-qrcode/\" target=\"_blank\">http://jeromeetienne.github.com/jquery-qrcode/</a>\n */\nvar QRCode;\n\n(function () {\n\t//---------------------------------------------------------------------\n\t// QRCode for JavaScript\n\t//\n\t// Copyright (c) 2009 Kazuhiko Arase\n\t//\n\t// URL: http://www.d-project.com/\n\t//\n\t// Licensed under the MIT license:\n\t//   http://www.opensource.org/licenses/mit-license.php\n\t//\n\t// The word \"QR Code\" is registered trademark of \n\t// DENSO WAVE INCORPORATED\n\t//   http://www.denso-wave.com/qrcode/faqpatent-e.html\n\t//\n\t//---------------------------------------------------------------------\n\tfunction QR8bitByte(data) {\n\t\tthis.mode = QRMode.MODE_8BIT_BYTE;\n\t\tthis.data = data;\n\t\tthis.parsedData = [];\n\n\t\t// Added to support UTF-8 Characters\n\t\tfor (var i = 0, l = this.data.length; i < l; i++) {\n\t\t\tvar byteArray = [];\n\t\t\tvar code = this.data.charCodeAt(i);\n\n\t\t\tif (code > 0x10000) {\n\t\t\t\tbyteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);\n\t\t\t\tbyteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);\n\t\t\t\tbyteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);\n\t\t\t\tbyteArray[3] = 0x80 | (code & 0x3F);\n\t\t\t} else if (code > 0x800) {\n\t\t\t\tbyteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);\n\t\t\t\tbyteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);\n\t\t\t\tbyteArray[2] = 0x80 | (code & 0x3F);\n\t\t\t} else if (code > 0x80) {\n\t\t\t\tbyteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);\n\t\t\t\tbyteArray[1] = 0x80 | (code & 0x3F);\n\t\t\t} else {\n\t\t\t\tbyteArray[0] = code;\n\t\t\t}\n\n\t\t\tthis.parsedData.push(byteArray);\n\t\t}\n\n\t\tthis.parsedData = Array.prototype.concat.apply([], this.parsedData);\n\n\t\tif (this.parsedData.length != this.data.length) {\n\t\t\tthis.parsedData.unshift(191);\n\t\t\tthis.parsedData.unshift(187);\n\t\t\tthis.parsedData.unshift(239);\n\t\t}\n\t}\n\n\tQR8bitByte.prototype = {\n\t\tgetLength: function (buffer) {\n\t\t\treturn this.parsedData.length;\n\t\t},\n\t\twrite: function (buffer) {\n\t\t\tfor (var i = 0, l = this.parsedData.length; i < l; i++) {\n\t\t\t\tbuffer.put(this.parsedData[i], 8);\n\t\t\t}\n\t\t}\n\t};\n\n\tfunction QRCodeModel(typeNumber, errorCorrectLevel) {\n\t\tthis.typeNumber = typeNumber;\n\t\tthis.errorCorrectLevel = errorCorrectLevel;\n\t\tthis.modules = null;\n\t\tthis.moduleCount = 0;\n\t\tthis.dataCache = null;\n\t\tthis.dataList = [];\n\t}\n\n\tQRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+\",\"+col);}\n\treturn this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row<this.moduleCount;row++){this.modules[row]=new Array(this.moduleCount);for(var col=0;col<this.moduleCount;col++){this.modules[row][col]=null;}}\n\tthis.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(test,maskPattern);if(this.typeNumber>=7){this.setupTypeNumber(test);}\n\tif(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);}\n\tthis.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}\n\treturn pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row<this.modules.length;row++){var y=row*cs;for(var col=0;col<this.modules[row].length;col++){var x=col*cs;var dark=this.modules[row][col];if(dark){qr_mc.beginFill(0,100);qr_mc.moveTo(x,y);qr_mc.lineTo(x+cs,y);qr_mc.lineTo(x+cs,y+cs);qr_mc.lineTo(x,y+cs);qr_mc.endFill();}}}\n\treturn qr_mc;},setupTimingPattern:function(){for(var r=8;r<this.moduleCount-8;r++){if(this.modules[r][6]!=null){continue;}\n\tthis.modules[r][6]=(r%2==0);}\n\tfor(var c=8;c<this.moduleCount-8;c++){if(this.modules[6][c]!=null){continue;}\n\tthis.modules[6][c]=(c%2==0);}},setupPositionAdjustPattern:function(){var pos=QRUtil.getPatternPosition(this.typeNumber);for(var i=0;i<pos.length;i++){for(var j=0;j<pos.length;j++){var row=pos[i];var col=pos[j];if(this.modules[row][col]!=null){continue;}\n\tfor(var r=-2;r<=2;r++){for(var c=-2;c<=2;c++){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}}}},setupTypeNumber:function(test){var bits=QRUtil.getBCHTypeNumber(this.typeNumber);for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;}\n\tfor(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}}\n\tfor(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}}\n\tthis.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}\n\tvar mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;}\n\tthis.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}}\n\trow+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;i<dataList.length;i++){var data=dataList[i];buffer.put(data.mode,4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.mode,typeNumber));data.write(buffer);}\n\tvar totalDataCount=0;for(var i=0;i<rsBlocks.length;i++){totalDataCount+=rsBlocks[i].dataCount;}\n\tif(buffer.getLengthInBits()>totalDataCount*8){throw new Error(\"code length overflow. (\"\n\t+buffer.getLengthInBits()\n\t+\">\"\n\t+totalDataCount*8\n\t+\")\");}\n\tif(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}\n\twhile(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}\n\twhile(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}\n\tbuffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}\n\tbuffer.put(QRCodeModel.PAD1,8);}\n\treturn QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r++){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i++){dcdata[r][i]=0xff&buffer.buffer[i+offset];}\n\toffset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=new QRPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i++){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.get(modIndex):0;}}\n\tvar totalCodeCount=0;for(var i=0;i<rsBlocks.length;i++){totalCodeCount+=rsBlocks[i].totalCount;}\n\tvar data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<dcdata[r].length){data[index++]=dcdata[r][i];}}}\n\tfor(var i=0;i<maxEcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<ecdata[r].length){data[index++]=ecdata[r][i];}}}\n\treturn data;};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0),G18:(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0),G15_MASK:(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1),getBCHTypeInfo:function(data){var d=data<<10;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)>=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));}\n\treturn((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));}\n\treturn(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;}\n\treturn digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error(\"bad maskPattern:\"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i<errorCorrectLength;i++){a=a.multiply(new QRPolynomial([1,QRMath.gexp(i)],0));}\n\treturn a;},getLengthInBits:function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error(\"mode:\"+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error(\"mode:\"+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error(\"mode:\"+mode);}}else{throw new Error(\"type:\"+type);}},getLostPoint:function(qrCode){var moduleCount=qrCode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount;col++){var sameCount=0;var dark=qrCode.isDark(row,col);for(var r=-1;r<=1;r++){if(row+r<0||moduleCount<=row+r){continue;}\n\tfor(var c=-1;c<=1;c++){if(col+c<0||moduleCount<=col+c){continue;}\n\tif(r==0&&c==0){continue;}\n\tif(dark==qrCode.isDark(row+r,col+c)){sameCount++;}}}\n\tif(sameCount>5){lostPoint+=(3+sameCount-5);}}}\n\tfor(var row=0;row<moduleCount-1;row++){for(var col=0;col<moduleCount-1;col++){var count=0;if(qrCode.isDark(row,col))count++;if(qrCode.isDark(row+1,col))count++;if(qrCode.isDark(row,col+1))count++;if(qrCode.isDark(row+1,col+1))count++;if(count==0||count==4){lostPoint+=3;}}}\n\tfor(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount-6;col++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row,col+1)&&qrCode.isDark(row,col+2)&&qrCode.isDark(row,col+3)&&qrCode.isDark(row,col+4)&&!qrCode.isDark(row,col+5)&&qrCode.isDark(row,col+6)){lostPoint+=40;}}}\n\tfor(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount-6;row++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row+1,col)&&qrCode.isDark(row+2,col)&&qrCode.isDark(row+3,col)&&qrCode.isDark(row+4,col)&&!qrCode.isDark(row+5,col)&&qrCode.isDark(row+6,col)){lostPoint+=40;}}}\n\tvar darkCount=0;for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount;row++){if(qrCode.isDark(row,col)){darkCount++;}}}\n\tvar ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;}};var QRMath={glog:function(n){if(n<1){throw new Error(\"glog(\"+n+\")\");}\n\treturn QRMath.LOG_TABLE[n];},gexp:function(n){while(n<0){n+=255;}\n\twhile(n>=256){n-=255;}\n\treturn QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<<i;}\n\tfor(var i=8;i<256;i++){QRMath.EXP_TABLE[i]=QRMath.EXP_TABLE[i-4]^QRMath.EXP_TABLE[i-5]^QRMath.EXP_TABLE[i-6]^QRMath.EXP_TABLE[i-8];}\n\tfor(var i=0;i<255;i++){QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]]=i;}\n\tfunction QRPolynomial(num,shift){if(num.length==undefined){throw new Error(num.length+\"/\"+shift);}\n\tvar offset=0;while(offset<num.length&&num[offset]==0){offset++;}\n\tthis.num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i++){this.num[i]=num[i+offset];}}\n\tQRPolynomial.prototype={get:function(index){return this.num[index];},getLength:function(){return this.num.length;},multiply:function(e){var num=new Array(this.getLength()+e.getLength()-1);for(var i=0;i<this.getLength();i++){for(var j=0;j<e.getLength();j++){num[i+j]^=QRMath.gexp(QRMath.glog(this.get(i))+QRMath.glog(e.get(j)));}}\n\treturn new QRPolynomial(num,0);},mod:function(e){if(this.getLength()-e.getLength()<0){return this;}\n\tvar ratio=QRMath.glog(this.get(0))-QRMath.glog(e.get(0));var num=new Array(this.getLength());for(var i=0;i<this.getLength();i++){num[i]=this.get(i);}\n\tfor(var i=0;i<e.getLength();i++){num[i]^=QRMath.gexp(QRMath.glog(e.get(i))+ratio);}\n\treturn new QRPolynomial(num,0).mod(e);}};function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this.dataCount=dataCount;}\n\tQRRSBlock.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];QRRSBlock.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=QRRSBlock.getRsBlockTable(typeNumber,errorCorrectLevel);if(rsBlock==undefined){throw new Error(\"bad rs block @ typeNumber:\"+typeNumber+\"/errorCorrectLevel:\"+errorCorrectLevel);}\n\tvar length=rsBlock.length/3;var list=[];for(var i=0;i<length;i++){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j++){list.push(new QRRSBlock(totalCount,dataCount));}}\n\treturn list;};QRRSBlock.getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};function QRBitBuffer(){this.buffer=[];this.length=0;}\n\tQRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i<length;i++){this.putBit(((num>>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);}\n\tif(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));}\n\tthis.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];\n\t\n\tfunction _isSupportCanvas() {\n\t\treturn typeof CanvasRenderingContext2D != \"undefined\";\n\t}\n\t\n\t// android 2.x doesn't support Data-URI spec\n\tfunction _getAndroid() {\n\t\tvar android = false;\n\t\tvar sAgent = navigator.userAgent;\n\t\t\n\t\tif (/android/i.test(sAgent)) { // android\n\t\t\tandroid = true;\n\t\t\tvar aMat = sAgent.toString().match(/android ([0-9]\\.[0-9])/i);\n\t\t\t\n\t\t\tif (aMat && aMat[1]) {\n\t\t\t\tandroid = parseFloat(aMat[1]);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn android;\n\t}\n\t\n\tvar svgDrawer = (function() {\n\n\t\tvar Drawing = function (el, htOption) {\n\t\t\tthis._el = el;\n\t\t\tthis._htOption = htOption;\n\t\t};\n\n\t\tDrawing.prototype.draw = function (oQRCode) {\n\t\t\tvar _htOption = this._htOption;\n\t\t\tvar _el = this._el;\n\t\t\tvar nCount = oQRCode.getModuleCount();\n\t\t\tvar nWidth = Math.floor(_htOption.width / nCount);\n\t\t\tvar nHeight = Math.floor(_htOption.height / nCount);\n\n\t\t\tthis.clear();\n\n\t\t\tfunction makeSVG(tag, attrs) {\n\t\t\t\tvar el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n\t\t\t\tfor (var k in attrs)\n\t\t\t\t\tif (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);\n\t\t\t\treturn el;\n\t\t\t}\n\n\t\t\tvar svg = makeSVG(\"svg\" , {'viewBox': '0 0 ' + String(nCount) + \" \" + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight});\n\t\t\tsvg.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:xlink\", \"http://www.w3.org/1999/xlink\");\n\t\t\t_el.appendChild(svg);\n\n\t\t\tsvg.appendChild(makeSVG(\"rect\", {\"fill\": _htOption.colorLight, \"width\": \"100%\", \"height\": \"100%\"}));\n\t\t\tsvg.appendChild(makeSVG(\"rect\", {\"fill\": _htOption.colorDark, \"width\": \"1\", \"height\": \"1\", \"id\": \"template\"}));\n\n\t\t\tfor (var row = 0; row < nCount; row++) {\n\t\t\t\tfor (var col = 0; col < nCount; col++) {\n\t\t\t\t\tif (oQRCode.isDark(row, col)) {\n\t\t\t\t\t\tvar child = makeSVG(\"use\", {\"x\": String(row), \"y\": String(col)});\n\t\t\t\t\t\tchild.setAttributeNS(\"http://www.w3.org/1999/xlink\", \"href\", \"#template\")\n\t\t\t\t\t\tsvg.appendChild(child);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tDrawing.prototype.clear = function () {\n\t\t\twhile (this._el.hasChildNodes())\n\t\t\t\tthis._el.removeChild(this._el.lastChild);\n\t\t};\n\t\treturn Drawing;\n\t})();\n\n\tvar useSVG = document.documentElement.tagName.toLowerCase() === \"svg\";\n\n\t// Drawing in DOM by using Table tag\n\tvar Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {\n\t\tvar Drawing = function (el, htOption) {\n\t\t\tthis._el = el;\n\t\t\tthis._htOption = htOption;\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Draw the QRCode\n\t\t * \n\t\t * @param {QRCode} oQRCode\n\t\t */\n\t\tDrawing.prototype.draw = function (oQRCode) {\n            var _htOption = this._htOption;\n            var _el = this._el;\n\t\t\tvar nCount = oQRCode.getModuleCount();\n\t\t\tvar nWidth = Math.floor(_htOption.width / nCount);\n\t\t\tvar nHeight = Math.floor(_htOption.height / nCount);\n\t\t\tvar aHTML = ['<table style=\"border:0;border-collapse:collapse;\">'];\n\t\t\t\n\t\t\tfor (var row = 0; row < nCount; row++) {\n\t\t\t\taHTML.push('<tr>');\n\t\t\t\t\n\t\t\t\tfor (var col = 0; col < nCount; col++) {\n\t\t\t\t\taHTML.push('<td style=\"border:0;border-collapse:collapse;padding:0;margin:0;width:' + nWidth + 'px;height:' + nHeight + 'px;background-color:' + (oQRCode.isDark(row, col) ? _htOption.colorDark : _htOption.colorLight) + ';\"></td>');\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\taHTML.push('</tr>');\n\t\t\t}\n\t\t\t\n\t\t\taHTML.push('</table>');\n\t\t\t_el.innerHTML = aHTML.join('');\n\t\t\t\n\t\t\t// Fix the margin values as real size.\n\t\t\tvar elTable = _el.childNodes[0];\n\t\t\tvar nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;\n\t\t\tvar nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;\n\t\t\t\n\t\t\tif (nLeftMarginTable > 0 && nTopMarginTable > 0) {\n\t\t\t\telTable.style.margin = nTopMarginTable + \"px \" + nLeftMarginTable + \"px\";\t\n\t\t\t}\n\t\t};\n\t\t\n\t\t/**\n\t\t * Clear the QRCode\n\t\t */\n\t\tDrawing.prototype.clear = function () {\n\t\t\tthis._el.innerHTML = '';\n\t\t};\n\t\t\n\t\treturn Drawing;\n\t})() : (function () { // Drawing in Canvas\n\t\tfunction _onMakeImage() {\n\t\t\tthis._elImage.src = this._elCanvas.toDataURL(\"image/png\");\n\t\t\tthis._elImage.style.display = \"block\";\n\t\t\tthis._elCanvas.style.display = \"none\";\t\t\t\n\t\t}\n\t\t\n\t\t// Android 2.1 bug workaround\n\t\t// http://code.google.com/p/android/issues/detail?id=5141\n\t\tif (this._android && this._android <= 2.1) {\n\t    \tvar factor = 1 / window.devicePixelRatio;\n\t        var drawImage = CanvasRenderingContext2D.prototype.drawImage; \n\t    \tCanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) {\n\t    \t\tif ((\"nodeName\" in image) && /img/i.test(image.nodeName)) {\n\t\t        \tfor (var i = arguments.length - 1; i >= 1; i--) {\n\t\t            \targuments[i] = arguments[i] * factor;\n\t\t        \t}\n\t    \t\t} else if (typeof dw == \"undefined\") {\n\t    \t\t\targuments[1] *= factor;\n\t    \t\t\targuments[2] *= factor;\n\t    \t\t\targuments[3] *= factor;\n\t    \t\t\targuments[4] *= factor;\n\t    \t\t}\n\t    \t\t\n\t        \tdrawImage.apply(this, arguments); \n\t    \t};\n\t\t}\n\t\t\n\t\t/**\n\t\t * Check whether the user's browser supports Data URI or not\n\t\t * \n\t\t * @private\n\t\t * @param {Function} fSuccess Occurs if it supports Data URI\n\t\t * @param {Function} fFail Occurs if it doesn't support Data URI\n\t\t */\n\t\tfunction _safeSetDataURI(fSuccess, fFail) {\n            var self = this;\n            self._fFail = fFail;\n            self._fSuccess = fSuccess;\n\n            // Check it just once\n            if (self._bSupportDataURI === null) {\n                var el = document.createElement(\"img\");\n                var fOnError = function() {\n                    self._bSupportDataURI = false;\n\n                    if (self._fFail) {\n                        self._fFail.call(self);\n                    }\n                };\n                var fOnSuccess = function() {\n                    self._bSupportDataURI = true;\n\n                    if (self._fSuccess) {\n                        self._fSuccess.call(self);\n                    }\n                };\n\n                el.onabort = fOnError;\n                el.onerror = fOnError;\n                el.onload = fOnSuccess;\n                el.src = \"data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\"; // the Image contains 1px data.\n                return;\n            } else if (self._bSupportDataURI === true && self._fSuccess) {\n                self._fSuccess.call(self);\n            } else if (self._bSupportDataURI === false && self._fFail) {\n                self._fFail.call(self);\n            }\n\t\t};\n\t\t\n\t\t/**\n\t\t * Drawing QRCode by using canvas\n\t\t * \n\t\t * @constructor\n\t\t * @param {HTMLElement} el\n\t\t * @param {Object} htOption QRCode Options \n\t\t */\n\t\tvar Drawing = function (el, htOption) {\n    \t\tthis._bIsPainted = false;\n    \t\tthis._android = _getAndroid();\n\t\t\n\t\t\tthis._htOption = htOption;\n\t\t\tthis._elCanvas = document.createElement(\"canvas\");\n\t\t\tthis._elCanvas.width = htOption.width;\n\t\t\tthis._elCanvas.height = htOption.height;\n\t\t\tel.appendChild(this._elCanvas);\n\t\t\tthis._el = el;\n\t\t\tthis._oContext = this._elCanvas.getContext(\"2d\");\n\t\t\tthis._bIsPainted = false;\n\t\t\tthis._elImage = document.createElement(\"img\");\n\t\t\tthis._elImage.alt = \"Scan me!\";\n\t\t\tthis._elImage.style.display = \"none\";\n\t\t\tthis._el.appendChild(this._elImage);\n\t\t\tthis._bSupportDataURI = null;\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Draw the QRCode\n\t\t * \n\t\t * @param {QRCode} oQRCode \n\t\t */\n\t\tDrawing.prototype.draw = function (oQRCode) {\n            var _elImage = this._elImage;\n            var _oContext = this._oContext;\n            var _htOption = this._htOption;\n            \n\t\t\tvar nCount = oQRCode.getModuleCount();\n\t\t\tvar nWidth = _htOption.width / nCount;\n\t\t\tvar nHeight = _htOption.height / nCount;\n\t\t\tvar nRoundedWidth = Math.round(nWidth);\n\t\t\tvar nRoundedHeight = Math.round(nHeight);\n\n\t\t\t_elImage.style.display = \"none\";\n\t\t\tthis.clear();\n\t\t\t\n\t\t\tfor (var row = 0; row < nCount; row++) {\n\t\t\t\tfor (var col = 0; col < nCount; col++) {\n\t\t\t\t\tvar bIsDark = oQRCode.isDark(row, col);\n\t\t\t\t\tvar nLeft = col * nWidth;\n\t\t\t\t\tvar nTop = row * nHeight;\n\t\t\t\t\t_oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;\n\t\t\t\t\t_oContext.lineWidth = 1;\n\t\t\t\t\t_oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;\t\t\t\t\t\n\t\t\t\t\t_oContext.fillRect(nLeft, nTop, nWidth, nHeight);\n\t\t\t\t\t\n\t\t\t\t\t// 안티 앨리어싱 방지 처리\n\t\t\t\t\t_oContext.strokeRect(\n\t\t\t\t\t\tMath.floor(nLeft) + 0.5,\n\t\t\t\t\t\tMath.floor(nTop) + 0.5,\n\t\t\t\t\t\tnRoundedWidth,\n\t\t\t\t\t\tnRoundedHeight\n\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\t_oContext.strokeRect(\n\t\t\t\t\t\tMath.ceil(nLeft) - 0.5,\n\t\t\t\t\t\tMath.ceil(nTop) - 0.5,\n\t\t\t\t\t\tnRoundedWidth,\n\t\t\t\t\t\tnRoundedHeight\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tthis._bIsPainted = true;\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Make the image from Canvas if the browser supports Data URI.\n\t\t */\n\t\tDrawing.prototype.makeImage = function () {\n\t\t\tif (this._bIsPainted) {\n\t\t\t\t_safeSetDataURI.call(this, _onMakeImage);\n\t\t\t}\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Return whether the QRCode is painted or not\n\t\t * \n\t\t * @return {Boolean}\n\t\t */\n\t\tDrawing.prototype.isPainted = function () {\n\t\t\treturn this._bIsPainted;\n\t\t};\n\t\t\n\t\t/**\n\t\t * Clear the QRCode\n\t\t */\n\t\tDrawing.prototype.clear = function () {\n\t\t\tthis._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);\n\t\t\tthis._bIsPainted = false;\n\t\t};\n\t\t\n\t\t/**\n\t\t * @private\n\t\t * @param {Number} nNumber\n\t\t */\n\t\tDrawing.prototype.round = function (nNumber) {\n\t\t\tif (!nNumber) {\n\t\t\t\treturn nNumber;\n\t\t\t}\n\t\t\t\n\t\t\treturn Math.floor(nNumber * 1000) / 1000;\n\t\t};\n\t\t\n\t\treturn Drawing;\n\t})();\n\t\n\t/**\n\t * Get the type by string length\n\t * \n\t * @private\n\t * @param {String} sText\n\t * @param {Number} nCorrectLevel\n\t * @return {Number} type\n\t */\n\tfunction _getTypeNumber(sText, nCorrectLevel) {\t\t\t\n\t\tvar nType = 1;\n\t\tvar length = _getUTF8Length(sText);\n\t\t\n\t\tfor (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {\n\t\t\tvar nLimit = 0;\n\t\t\t\n\t\t\tswitch (nCorrectLevel) {\n\t\t\t\tcase QRErrorCorrectLevel.L :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][0];\n\t\t\t\t\tbreak;\n\t\t\t\tcase QRErrorCorrectLevel.M :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][1];\n\t\t\t\t\tbreak;\n\t\t\t\tcase QRErrorCorrectLevel.Q :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][2];\n\t\t\t\t\tbreak;\n\t\t\t\tcase QRErrorCorrectLevel.H :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][3];\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (length <= nLimit) {\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tnType++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (nType > QRCodeLimitLength.length) {\n\t\t\tthrow new Error(\"Too long data\");\n\t\t}\n\t\t\n\t\treturn nType;\n\t}\n\n\tfunction _getUTF8Length(sText) {\n\t\tvar replacedText = encodeURI(sText).toString().replace(/\\%[0-9a-fA-F]{2}/g, 'a');\n\t\treturn replacedText.length + (replacedText.length != sText ? 3 : 0);\n\t}\n\t\n\t/**\n\t * @class QRCode\n\t * @constructor\n\t * @example \n\t * new QRCode(document.getElementById(\"test\"), \"http://jindo.dev.naver.com/collie\");\n\t *\n\t * @example\n\t * var oQRCode = new QRCode(\"test\", {\n\t *    text : \"http://naver.com\",\n\t *    width : 128,\n\t *    height : 128\n\t * });\n\t * \n\t * oQRCode.clear(); // Clear the QRCode.\n\t * oQRCode.makeCode(\"http://map.naver.com\"); // Re-create the QRCode.\n\t *\n\t * @param {HTMLElement|String} el target element or 'id' attribute of element.\n\t * @param {Object|String} vOption\n\t * @param {String} vOption.text QRCode link data\n\t * @param {Number} [vOption.width=256]\n\t * @param {Number} [vOption.height=256]\n\t * @param {String} [vOption.colorDark=\"#000000\"]\n\t * @param {String} [vOption.colorLight=\"#ffffff\"]\n\t * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] \n\t */\n\tQRCode = function (el, vOption) {\n\t\tthis._htOption = {\n\t\t\twidth : 256, \n\t\t\theight : 256,\n\t\t\ttypeNumber : 4,\n\t\t\tcolorDark : \"#000000\",\n\t\t\tcolorLight : \"#ffffff\",\n\t\t\tcorrectLevel : QRErrorCorrectLevel.H\n\t\t};\n\t\t\n\t\tif (typeof vOption === 'string') {\n\t\t\tvOption\t= {\n\t\t\t\ttext : vOption\n\t\t\t};\n\t\t}\n\t\t\n\t\t// Overwrites options\n\t\tif (vOption) {\n\t\t\tfor (var i in vOption) {\n\t\t\t\tthis._htOption[i] = vOption[i];\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (typeof el == \"string\") {\n\t\t\tel = document.getElementById(el);\n\t\t}\n\n\t\tif (this._htOption.useSVG) {\n\t\t\tDrawing = svgDrawer;\n\t\t}\n\t\t\n\t\tthis._android = _getAndroid();\n\t\tthis._el = el;\n\t\tthis._oQRCode = null;\n\t\tthis._oDrawing = new Drawing(this._el, this._htOption);\n\t\t\n\t\tif (this._htOption.text) {\n\t\t\tthis.makeCode(this._htOption.text);\t\n\t\t}\n\t};\n\t\n\t/**\n\t * Make the QRCode\n\t * \n\t * @param {String} sText link data\n\t */\n\tQRCode.prototype.makeCode = function (sText) {\n\t\tthis._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);\n\t\tthis._oQRCode.addData(sText);\n\t\tthis._oQRCode.make();\n\t\tthis._el.title = sText;\n\t\tthis._oDrawing.draw(this._oQRCode);\t\t\t\n\t\tthis.makeImage();\n\t};\n\t\n\t/**\n\t * Make the Image from Canvas element\n\t * - It occurs automatically\n\t * - Android below 3 doesn't support Data-URI spec.\n\t * \n\t * @private\n\t */\n\tQRCode.prototype.makeImage = function () {\n\t\tif (typeof this._oDrawing.makeImage == \"function\" && (!this._android || this._android >= 3)) {\n\t\t\tthis._oDrawing.makeImage();\n\t\t}\n\t};\n\t\n\t/**\n\t * Clear the QRCode\n\t */\n\tQRCode.prototype.clear = function () {\n\t\tthis._oDrawing.clear();\n\t};\n\t\n\t/**\n\t * @name QRCode.CorrectLevel\n\t */\n\tQRCode.CorrectLevel = QRErrorCorrectLevel;\n})();\n"
  },
  {
    "path": "src/libs/rc4v1/rc4v1.js",
    "content": "/**\n RC4 encryption decryption library\n @class RC4\n @constructor\n @return {Object} instantiated RC4\n **/\nfunction RC4(i_passkey) {\n    this.m_passkey = i_passkey;\n};\n\nRC4.prototype = {\n    constructor: RC4,\n\n    /**\n     Arcfour_algorithm\n     @method _arcfour_crypt\n     @param {Object} i_data\n     @param {Object} i_key\n     @return {String} _arcfour_byte_string\n     **/\n    _arcfour_crypt: function (i_data, i_key) {\n        var self = this;\n        var STATE_LENGTH = 256;\n        var i, i1, i2, x, y, temp;\n        var secretKey = new Array(STATE_LENGTH);\n        var keyLen = i_key.length;\n        var dataLen = i_data.length;\n        var output = new Array(dataLen);\n\n        i1 = 0;\n        i2 = 0;\n        x = 0;\n        y = 0;\n        for (i = 0; i < STATE_LENGTH; i++)\n            secretKey[i] = i;\n\n\n        for (i = 0; i < STATE_LENGTH; i++) {\n            i2 = ((i_key.charCodeAt(i1) & 255) + secretKey[i] + i2) & 255;\n            // swap\n            temp = secretKey[i];\n            secretKey[i] = secretKey[i2];\n            secretKey[i2] = temp;\n            i1 = (i1 + 1) % keyLen;\n        }\n\n        for (i = 0; i < dataLen; i++) {\n            x = (x + 1) & 255;\n            y = (secretKey[x] + y) & 255;\n            // swap\n            temp = secretKey[x];\n            secretKey[x] = secretKey[y];\n            secretKey[y] = temp;\n            // xor\n            output[i] = i_data.charCodeAt(i) ^ secretKey[(secretKey[x] + secretKey[y]) & 255];\n        }\n        return self._arcfour_byte_string(output);\n    },\n\n    /**\n     Convert byte array into string.\n     @method _arcfour_byte_string\n     @param {Object} i_input\n     @return {Object} output\n     **/\n    _arcfour_byte_string: function (i_input) {\n        var self = this;\n        var output = new String();\n        for (var i = 0; i < i_input.length; i++) {\n            output += String.fromCharCode(i_input[i]);\n        }\n        return output;\n    },\n\n    /**\n     Get the hex representation of an array of bytes\n     @method _arcfour_hex_encode\n     @param {Object} i_input\n     @return {Object} output\n     **/\n    _arcfour_hex_encode: function (i_input) {\n        var self = this;\n        var hex_digits = \"0123456789abcdef\";\n        var output = new String();\n        for (var i = 0; i < i_input.length; i++) {\n            output += hex_digits.charAt((i_input.charCodeAt(i) >>> 4) & 15);\n            output += hex_digits.charAt(i_input.charCodeAt(i) & 15);\n        }\n        return output;\n    },\n\n    /**\n     Decode hex string\n     @method _arcfour_hex_decode\n     @param {Object} i_input\n     @return {Object} output\n     **/\n    _arcfour_hex_decode: function (i_input) {\n        var self = this;\n        var left, right, index;\n        var output = new Array(i_input.length / 2);\n        for (var i = 0; i < i_input.length; i += 2) {\n            left = i_input.charCodeAt(i);\n            right = i_input.charCodeAt(i + 1);\n            index = i / 2;\n            if (left < 97)  // left < 'a'\n                output[index] = ((left - 48) << 4);  // left - '0'\n            else\n                output[index] = ((left - 97 + 10) << 4);\n            if (right < 97)\n                output[index] += (right - 48);\n            else\n                output[index] += (right - 97 + 10);\n        }\n        return self._arcfour_byte_string(output);\n    },\n\n    /**\n     Generate a key in case we need a new one\n     @method _genKey\n     @return {Number} new ley\n     **/\n    _genKey: function () {\n        var self = this;\n        var key = new Array();\n        var i = 0;\n        var n;\n        while (i < 16) {\n            n = Math.ceil(Math.random() * 255);\n            key[i] = n;\n            i++;\n        }\n        return self._arcfour_hex_encode(self._arcfour_byte_string(key));\n    },\n\n    /**\n     Execute an encryption using pass\n     @method doEncrypt\n     @param {String} i_plaintext\n     @return {String} encrypted dtaa\n     **/\n    doEncrypt: function (i_plaintext) {\n        var self = this;\n        if (i_plaintext.length > 0) {\n            return self._arcfour_hex_encode(self._arcfour_crypt(i_plaintext, self._arcfour_hex_decode(self.m_passkey)));\n        }\n    },\n\n    /**\n     Execute an decryption using pass on i_value\n     @method doDecrypt\n     @param {String} plaintext\n     @return {String} decrypted i_value\n     **/\n    doDecrypt: function (i_value) {\n        var self = this;\n        var ciphertext = self._arcfour_hex_decode(i_value);\n        if (ciphertext.length > 0) {\n            return self._arcfour_crypt(ciphertext, self._arcfour_hex_decode(self.m_passkey));\n        }\n    }\n}\n\n\n\n"
  },
  {
    "path": "src/libs/rc4v2/rc4v2.js",
    "content": "(function(exports){\n\n    exports.RC4V2 = RC4;\n\n    function RC4() {\n        this.m_nBox = new Array(256);\n    }\n\n    RC4.prototype = {\n        constructor: RC4,\n        initialize: initialize,\n        encrypt: encrypt,\n        decrypt: decrypt,\n        calculate: calculate,\n    }\n\n    /**\n     * Implements Key-scheduling algorithm (KSA)\n     * @param pwd {string} The password used during the encrypting/decrypting process\n     * @return {void}\n     */\n    function initialize(pwd){\n        var asciiChars = new Array(256),\n            index2 = 0,\n            tempSwap,\n            intLength = pwd.length,\n            m_nBox = this.m_nBox;\n\n        for (var count=0; count<256; count++) {\n            asciiChars[count] = pwd[(count%intLength)];\n            m_nBox[count] = count;\n        }\n\n        for (count = 0; count<256; count++) {\n            index2 = (index2+m_nBox[count]+asciiChars[count]) % 256;\n            tempSwap = m_nBox[count];\n            m_nBox[count] = m_nBox[index2];\n            m_nBox[index2] = tempSwap;\n        }\n    }\n\n    /**\n     * Encrypts the given text with specified key\n     * @param src {string} The text to be encrypted\n     * @param key {string} The key for the encryption\n     * @return {string} The encrypted text\n     */\n    function encrypt(src, key) {\n        var srcChars= strToChars(src),\n            keyChars = strToChars(key),\n            result = this.calculate(srcChars, keyChars);\n\n        return charsToHex(result);\n    }\n\n    /**\n     * Decrypts the given text with specified key\n     * @param src {string} The text to be decrypted\n     * @param key {string} The key for decrypting\n     * @return {string} The decrypted text\n     */\n    function decrypt(src, key) {\n        var srcChars= hexToChars(src),\n            keyChars = strToChars(key),\n            result = this.calculate(srcChars, keyChars);\n\n        return charsToStr(result);\n    }\n\n    /**\n     * Implements Pseudo-random generation algorithm (PRGA)\n     * @param plaintxt {string} The text to be encrypted/decrypted\n     * @param psw {string} The key for decrypting/encrypting\n     * @return {string} The decrypted text\n     */\n    function calculate(plaintxt, psw){\n        var i = 0,\n            j = 0,\n            cipher = [],\n            k, temp, cipherby,\n            textLength = plaintxt.length,\n            m_nBox = this.m_nBox;\n\n        this.initialize(psw);\n\n        for (var a = 0; a<textLength; a++) {\n            i = (i+1) % 256;\n            j = (j+m_nBox[i])%256;\n            temp = m_nBox[i];\n            m_nBox[i] = m_nBox[j];\n            m_nBox[j] = temp;\n            var idx = (m_nBox[i]+m_nBox[j]) % 256;\n            k = m_nBox[idx];\n            cipherby = plaintxt[a]^k;\n            cipher.push(cipherby);\n        }\n        return cipher;\n    }\n\n    function charsToHex(chars) {\n        var result = '',\n            hexes = '0123456789abcdef'.split(''),\n            totalChars = chars.length;\n\n        for (var i = 0; i < totalChars; i++) {\n            result += hexes[chars[i] >> 4] + hexes[chars[i] & 0xf];\n        }\n        return result;\n    }\n\n    function hexToChars(hex) {\n        var codes = [],\n            totalChars = hex.length;\n        for (var i = (hex.substr(0, 2) == \"0x\") ? 2 : 0; i<totalChars; i+=2) {\n            codes.push(parseInt(hex.substr(i, 2), 16));\n        }\n        return codes;\n    }\n\n    function charsToStr(chars) {\n        var result = '',\n            totalChars = chars.length;\n        for (var i = 0; i<totalChars; i++) {\n            result += String.fromCharCode(chars[i]);\n        }\n        return result;\n    }\n\n    function strToChars(str) {\n        var codes = [],\n            totalChars = str.length;\n\n        for (var i = 0; i<totalChars; i++) {\n            codes.push(str.charCodeAt(i));\n        }\n\n        return codes;\n    }\n}(window));"
  },
  {
    "path": "src/libs/ruler/ruler.css",
    "content": "\n\n.rul_wrapper{\n    position: absolute;\n    height: 100%;\n    width: 783px;\n    overflow: hidden;\n    pointer-events: none;\n}\n\n.rul_wrapper *{\n    -webkit-user-select: none;  /* Chrome all / Safari all */\n    -moz-user-select: none;     /* Firefox all */\n    -ms-user-select: none;      /* IE 10+ */\n    /* No support for these yet, use at own risk */\n    -o-user-select: none;\n    user-select: none;\n}\n\n.rul_ruler{\n    display: block;\n    position: absolute;\n    border: 1px solid rgba(206, 219, 236, .5);\n    pointer-events: all;\n    filter: blur(0);\n    -webkit-filter: blur(0);\n    z-index: 1000;\n\n}\n\n.rul_corner{\n    pointer-events: all;\n    position: absolute;\n    background-color: white;\n    z-index: 1010;\n    cursor: pointer;\n}\n\n.rul_corner:hover{\n    background-color: lightgray;\n}\n\n.rul_cornerTL{\n    top:0;\n    left:0;\n    border-bottom: 1px solid rgba(206, 219, 236, .5);\n    border-right:  1px solid rgba(206, 219, 236, .5);\n}\n.rul_cornerTR{\n    top:1px;\n    right:1px;\n    border-bottom: 1px solid rgba(206, 219, 236, .5);\n    border-left:  1px solid rgba(206, 219, 236, .5);\n}\n.rul_cornerBL{\n    bottom:1px;\n    left:1px;\n    border-top: 1px solid rgba(206, 219, 236, .5);\n    border-right:  1px solid rgba(206, 219, 236, .5);\n}\n.rul_cornerBR{\n    bottom:1px;\n    right:1px;\n    border-top: 1px solid rgba(206, 219, 236, .5);\n    border-left:  1px solid rgba(206, 219, 236, .5);\n}\n.rul_ruler_Vertical{\n    cursor: ew-resize;\n    border-left: none;\n}\n\n.rul_ruler_Horizontal{\n    /*cursor: ns-resize;*/\n    border-top: none;\n}\n\n.rul_line{\n    position: absolute;\n    color: transparent;\n    background-color: transparent;\n    border-bottom: 1px solid #3BB7C7;\n    border-left: 1px solid #3BB7C7;\n    pointer-events: all;\n    z-index: 1000;\n}\n.rul_line_dragged{\n    border: 1px dotted #6B7587;\n}\n\n.rul_line:hover{\n    border-bottom: 1px solid #236E77;\n    border-left: 1px solid #236E77;\n}\n\n.rul_lineVer{\n    top: 0;\n    bottom: 0;\n}\n\n.rul_lineVer:hover{\n    cursor: ew-resize;\n}\n\n.rul_lineHor{\n    right: 0;\n    left: 0;\n}\n\n.rul_lineHor:hover{\n    cursor: ns-resize;\n}\n\n.rul_tooltip:after{\n    background: #fff;\n    color: black;\n    border: 1px solid gray;\n    font-size: 10px;\n    content: attr(data-tip);\n    top: 50%;\n    left: 50%;\n    margin-top: 1px;\n    margin-left: 1px;\n    padding: 2px 5px;\n    position: absolute;\n    z-index: 10001;\n    min-width: 45px;\n}\n\n.rul_tracker{\n    height: 1px;\n    width: 1px;\n    background: black;\n    position: absolute;\n    pointer-events: none;\n}\n"
  },
  {
    "path": "src/libs/ruler/ruler.js",
    "content": "\nvar ruler = function (options) {\n  this.api = this.builder();\n  this.api.constructRulers.call(this, options);\n};\nwindow['ruler'] = ruler;\n\n// ruler utils\n/**\n * Created by maor.frankel on 5/25/15.\n */\nruler.prototype.utils = {\n    extend: function extend(){\n        for(var i=1; i< arguments.length; i++)\n            for(var key in arguments[i])\n                if(arguments[i].hasOwnProperty(key))\n                    arguments[0][key] = arguments[i][key];\n        return arguments[0];\n    },\n    pixelize: function (val){\n        return val + 'px';\n    },\n    prependChild: function (container, element){\n        return container.insertBefore(element,container.firstChild);\n    },\n    addClasss: function (element, classNames){\n        if(!(classNames instanceof Array))\n        {\n            classNames = [classNames];\n        }\n\n        classNames.forEach(function (name){\n            element.className += ' ' + name;\n        });\n\n        return element;\n\n    },\n    removeClasss: function (element, classNames){\n        var curCalsss = element.className;\n        if(!(classNames instanceof Array))\n        {\n            classNames = [classNames];\n        }\n\n        classNames.forEach(function (name){\n            curCalsss = curCalsss.replace(name, '');\n        });\n        element.className = curCalsss;\n        return element;\n\n    }\n} ;\n\nruler.prototype.builder = function(){\n  var VERTICAL = 1,\n    HORIZONTAL = 2,\n    CUR_DELTA_X = 0,\n    CUR_DELTA_Y = 0,\n    CUR_SCALE = 1;\n\n  var options,\n    rulerz = {},\n    guides = [],\n    theRulerDOM = document.createElement('div'),\n    corners = [],\n    defaultOptions = {\n      rulerHeight: 15,\n      fontFamily: 'arial',\n      fontSize: '8px',\n      strokeStyle: 'gray',\n      sides: ['top', 'left'],\n      cornerSides: ['TL'],\n      lineWidth: 1,\n      enableMouseTracking: true,\n      enableToolTip: true\n    };\n\n  var rotateRuler = function (curRuler, angle) {\n    var rotation = 'rotate(' + angle + 'deg)';\n    var origin = ruler.prototype.utils.pixelize(Math.abs(parseInt(curRuler.canvas.style.left))) + ' 100%';\n    curRuler.canvas.style.webkitTransform = rotation;\n    curRuler.canvas.style.MozTransform = rotation;\n    curRuler.canvas.style.OTransform = rotation;\n    curRuler.canvas.style.msTransform = rotation;\n    curRuler.canvas.style.transform = rotation;\n    curRuler.canvas.style.webkitTransformOrigin = origin;\n    curRuler.canvas.style.MozTransformOrigin = origin;\n    curRuler.canvas.style.OTransformOrigin = origin;\n    curRuler.canvas.style.msTransformOrigin = origin;\n    curRuler.canvas.style.transformOrigin = origin;\n\n  };\n\n  var positionRuler = function (curRuler, alignment) {\n    curRuler.canvas.style.left = ruler.prototype.utils.pixelize(-((curRuler.canvas.width / 2) - curRuler.canvas.height));\n    switch (alignment) {\n      case 'top':\n        curRuler.orgPos = parseInt(curRuler.canvas.style.left);\n        break;\n      case 'left':\n        curRuler.canvas.style.top = ruler.prototype.utils.pixelize(-curRuler.canvas.height - 1);\n        curRuler.orgPos = parseInt(curRuler.canvas.style.top);\n        rotateRuler(curRuler, 90);\n        break;\n    }\n  };\n\n  var attachListeners = function (container, curRul) {\n    /*var mousedown = function (e) {\n      constructGuide(curRul.dimension, e.clientX, e.clientY, e);\n\n    };*/\n\n    /*curRul.canvas.addEventListener('mousedown', mousedown);\n    curRul.clearListeners = function () {\n      curRul.canvas.removeEventListener('mousedown', mousedown);\n    }*/\n  };\n\n  var constructGuide = function (dimension, x, y, e) {\n    var guideIndex;\n    var moveCB = function (line, x, y) {\n      var coor = line.dimension === VERTICAL ? x : y;\n      if (!line.assigned()) {\n        if (coor > options.rulerHeight) {\n          line.assigned(true);\n        }\n        return;\n      }\n\n      if (coor < options.rulerHeight) {\n        guides.some(function (guideLine, index) {\n          if (guideLine.line === line) {\n            guideIndex = index;\n            return true;\n          }\n        });\n        line.destroy();\n        guides.splice(guideIndex, 1);\n\n      }\n    };\n\n    var guide = document.createElement('div'),\n      guideStyle = dimension === VERTICAL ? 'rul_lineVer' : 'rul_lineHor',\n      curDelta = dimension === VERTICAL ? CUR_DELTA_X : CUR_DELTA_Y;\n    guide.title = 'Double click to delete';\n    ruler.prototype.utils.addClasss(guide, ['rul_line', guideStyle]);\n    guide = theRulerDOM.appendChild(guide);\n    if (dimension === VERTICAL) {\n      guide.style.left = ruler.prototype.utils.pixelize(x - options.container.getBoundingClientRect().left);\n    }\n    else {\n      guide.style.top = ruler.prototype.utils.pixelize(y - options.container.getBoundingClientRect().top);\n    }\n    guides.push({\n      dimension: dimension,\n      line: ruler.prototype.guideLine(guide, options.container.querySelector('.rul_wrapper'), dimension, options, curDelta, moveCB, e)\n    });\n  };\n\n\n  var constructRuler = function (container, alignment) {\n    var canvas,\n      dimension = alignment === 'left' || alignment === 'right' ? VERTICAL : HORIZONTAL,\n      rulerStyle = dimension === VERTICAL ? 'rul_ruler_Vertical' : 'rul_ruler_Horizontal',\n      element = document.createElement('canvas');\n\n\n    ruler.prototype.utils.addClasss(element, ['rul_ruler', rulerStyle, 'rul_align_' + alignment]);\n    canvas = container.appendChild(element);\n    rulerz[alignment] = ruler.prototype.rulerConstructor(canvas, options, dimension);\n    rulerz[alignment].drawRuler(container.offsetWidth, options.rulerHeight);\n    positionRuler(rulerz[alignment], alignment);\n    attachListeners(container, rulerz[alignment]);\n  };\n\n  var constructCorner = (function () {\n    function cornerDraw(container, side) {\n      var corner = document.createElement('div'),\n        cornerStyle = 'rul_corner' + side.toUpperCase();\n\n      corner.title = 'Clear Guide lines';\n      ruler.prototype.utils.addClasss(corner, ['rul_corner', cornerStyle]);\n      corner.style.width = ruler.prototype.utils.pixelize(options.rulerHeight + 1);\n      corner.style.height = ruler.prototype.utils.pixelize(options.rulerHeight);\n      return container.appendChild(corner);\n\n    }\n\n    function mousedown(e) {\n      e.stopPropagation();\n      clearGuides();\n    }\n\n    return function (container, cornerSides) {\n      cornerSides.forEach(function (side) {\n        var corner = cornerDraw(container, side);\n        corner.addEventListener('mousedown', mousedown);\n        corner.destroy = function () {\n          corner.removeEventListener('mousedown', mousedown);\n          corner.parentNode.removeChild(corner);\n        };\n\n        corners.push(corner);\n      })\n    }\n\n  })();\n\n  var mouseup = function (e) {\n    guides.forEach(function (guide) {\n      guide.line.stopDrag();\n    })\n  };\n\n  var constructRulers = function (curOptions) {\n    theRulerDOM = ruler.prototype.utils.addClasss(theRulerDOM, 'rul_wrapper');\n    options = ruler.prototype.utils.extend(defaultOptions, curOptions);\n    theRulerDOM = options.container.appendChild(theRulerDOM);\n    options.sides.forEach(function (side) {\n      constructRuler(theRulerDOM, side);\n    });\n    constructCorner(theRulerDOM, options.cornerSides);\n    options.container.addEventListener('mouseup', mouseup);\n\n\n  };\n\n  var forEachRuler = function (cb) {\n    var index = 0;\n    for (var rul in rulerz) {\n      if (rulerz.hasOwnProperty(rul)) {\n        cb(rulerz[rul], index++);\n      }\n    }\n  };\n\n\n  var setPos = function (values) {\n    var orgX = 0,\n      orgY,\n      deltaX = 0,\n      deltaY = 0;\n    forEachRuler(function (curRul) {\n      if (curRul.dimension === VERTICAL) {\n        orgY = curRul.canvas.style.top;\n        curRul.canvas.style.top = ruler.prototype.utils.pixelize(curRul.orgPos + (parseInt(values.y)));\n        deltaY = parseInt(orgY) - parseInt(curRul.canvas.style.top);\n      }\n      else {\n        orgX = curRul.canvas.style.left;\n        curRul.canvas.style.left = ruler.prototype.utils.pixelize(curRul.orgPos + (parseInt(values.x)));\n        deltaX = parseInt(orgX) - parseInt(curRul.canvas.style.left);\n      }\n    });\n    guides.forEach(function (guide) {\n      if (guide.dimension === HORIZONTAL) {\n        guide.line.guideLine.style.top = ruler.prototype.utils.pixelize(parseInt(guide.line.guideLine.style.top) - deltaY);\n        guide.line.curPosDelta(parseInt(values.y));\n      }\n      else {\n        guide.line.guideLine.style.left = ruler.prototype.utils.pixelize(parseInt(guide.line.guideLine.style.left) - deltaX);\n        guide.line.curPosDelta(parseInt(values.x));\n      }\n    });\n    CUR_DELTA_X = parseInt(values.x);\n    CUR_DELTA_Y = parseInt(values.y);\n\n  };\n\n  var setScale = function (newScale) {\n    var curPos, orgDelta, curScaleFac;\n    forEachRuler(function (rul) {\n      rul.context.clearRect(0, 0, rul.canvas.width, rul.canvas.height);\n      rul.context.beginPath();\n      rul.setScale(newScale);\n      rul.context.stroke();\n      CUR_SCALE = newScale;\n    });\n\n    guides.forEach(function (guide) {\n      if (guide.dimension === HORIZONTAL) {\n        curPos = parseInt(guide.line.guideLine.style.top);\n        orgDelta = options.rulerHeight + 1;\n        curScaleFac = (parseFloat(newScale) / guide.line.curScale());\n        guide.line.guideLine.style.top = ruler.prototype.utils.pixelize(((curPos - orgDelta - CUR_DELTA_Y ) / curScaleFac) + orgDelta + CUR_DELTA_Y);\n        guide.line.curScale(newScale);\n      }\n      else {\n        curPos = parseInt(guide.line.guideLine.style.left);\n        orgDelta = options.rulerHeight + 1;\n        curScaleFac = (parseFloat(newScale) / guide.line.curScale());\n        guide.line.guideLine.style.left = ruler.prototype.utils.pixelize(((curPos - orgDelta - CUR_DELTA_X) / curScaleFac) + orgDelta + CUR_DELTA_X);\n        guide.line.curScale(newScale);\n      }\n    });\n  };\n\n\n  var clearGuides = function () {\n    guides.forEach(function (guide) {\n      guide.line.destroy();\n    });\n    guides = [];\n  };\n\n  var toggleGuideVisibility = function (val) {\n    var func = val ? 'show' : 'hide';\n    guides.forEach(function (guide) {\n      guide.line[func]();\n    });\n  };\n\n  var toggleRulerVisibility = function (val) {\n    var state = val ? 'block' : 'none';\n    theRulerDOM.style.display = state;\n    var trackers = options.container.querySelectorAll('.rul_tracker');\n    if (trackers.length > 0) {\n      trackers[0].style.display = state;\n      trackers[1].style.display = state;\n    }\n\n  };\n\n  var getGuides = function () {\n    return guides.map(function (guide) {\n      return {\n        posX: Math.round((parseInt(guide.line.guideLine.style.left) - CUR_DELTA_X - options.rulerHeight) * CUR_SCALE),\n        posY: Math.round((parseInt(guide.line.guideLine.style.top) - CUR_DELTA_Y - options.rulerHeight) * CUR_SCALE),\n        dimension: guide.dimension\n      }\n    });\n  };\n\n  var setGuides = function (_guides) {\n    if(!_guides){return}\n    _guides.forEach(function (guide) {\n      constructGuide(guide.dimension, guide.posX, guide.posY)\n    })\n\n  };\n\n  var destroy = function () {\n    clearGuides();\n    forEachRuler(function (ruler) {\n      ruler.destroy();\n    });\n    corners.forEach(function (corner) {\n      corner.destroy();\n    });\n    options.container.removeEventListener('mouseup', mouseup);\n    theRulerDOM.parentNode.removeChild(theRulerDOM);\n  };\n\n  return {\n    VERTICAL: VERTICAL,\n    HORIZONTAL: HORIZONTAL,\n    setPos: setPos,\n    setScale: setScale,\n    clearGuides: clearGuides,\n    getGuides: getGuides,\n    setGuides: setGuides,\n    constructRulers: constructRulers,\n    toggleRulerVisibility: toggleRulerVisibility,\n    toggleGuideVisibility: toggleGuideVisibility,\n    destroy: destroy\n  }\n};\n\n// ruler constructor\n\nruler.prototype.rulerConstructor =  function(_canvas, options, rulDimension)\n{\n\n    var canvas = _canvas,\n        context = canvas.getContext('2d'),\n        rulThickness = 0,\n        rulLength = 0,\n        rulScale = 1,\n        dimension = rulDimension || 2,\n        orgPos = 0,\n        tracker = document.createElement('div');\n\n    var getLength = function (){\n        return rulLength;\n    };\n\n    var getThickness = function(){\n        return rulThickness;\n    };\n\n    var getScale = function(){\n        return rulScale;\n    };\n\n    var setScale = function(newScale){\n        rulScale = parseFloat(newScale);\n        drawPoints();\n        return rulScale;\n    };\n\n    var drawRuler = function (_rulerLength, _rulerThickness, _rulerScale){\n        rulLength = canvas.width = _rulerLength * 4;\n        rulThickness = canvas.height = _rulerThickness;\n        rulScale = _rulerScale || rulScale;\n        context.strokeStyle = options.strokeStyle;\n        context.font = options.fontSize + ' ' + options.fontFamily;\n        context.lineWidth = options.lineWidth;\n        context.beginPath();\n        drawPoints();\n        context.stroke();\n    };\n\n\n\n    var drawPoints = function () {\n        var  pointLength = 0,\n            label = '',\n            delta = 0,\n            draw = false,\n            lineLengthMax = 0,\n            lineLengthMed = rulThickness / 2,\n            lineLengthMin = rulThickness / 2;\n\n        for (var pos = 0; pos <= rulLength; pos += 1) {\n            delta = ((rulLength / 2) - pos);\n            draw = false;\n            label = '';\n\n            if (delta % 50 === 0) {\n                pointLength = lineLengthMax;\n                label = Math.round(Math.abs(delta)*rulScale);\n                draw = true;\n            }\n            else if (delta % 25 === 0) {\n                pointLength = lineLengthMed;\n                draw = true;\n            }\n            else if (delta % 5 === 0) {\n                pointLength = lineLengthMin;\n                draw = true;\n            }\n            if (draw) {\n                context.moveTo(pos + 0.5, rulThickness + 0.5);\n                context.lineTo(pos + 0.5, pointLength +  0.5);\n                context.fillText(label, pos + 1.5, (rulThickness / 2) + 1);\n            }\n        }\n    };\n\n    var mousemove = function(e) {\n      var posX = e.clientX;\n      var posY = e.clientY;\n      if(dimension === 2){\n        tracker.style.left = ruler.prototype.utils.pixelize(posX - parseInt(options.container.getBoundingClientRect().left));\n      }\n      else{\n        tracker.style.top = ruler.prototype.utils.pixelize(posY - parseInt(options.container.getBoundingClientRect().top)) ;\n      }\n    };\n\n    var destroy = function(){\n      options.container.removeEventListener('mousemove', mousemove);\n      tracker.parentNode.removeChild(tracker);\n      this.clearListeners && this.clearListeners();\n\n    };\n\n    var initTracker = function(){\n        tracker = options.container.appendChild(tracker);\n        ruler.prototype.utils.addClasss(tracker, 'rul_tracker');\n        var height = ruler.prototype.utils.pixelize(options.rulerHeight);\n        if(dimension === 2){\n            tracker.style.height = height;\n        }\n        else{\n            tracker.style.width = height;\n        }\n\n        options.container.addEventListener('mousemove', mousemove);\n    };\n\n    if(options.enableMouseTracking){\n        initTracker();\n    }\n\n\n    return{\n        getLength: getLength,\n        getThickness: getThickness,\n        getScale: getScale,\n        setScale: setScale,\n        dimension: dimension,\n        orgPos: orgPos,\n        canvas: canvas,\n        context: context,\n        drawRuler: drawRuler,\n        drawPoints: drawPoints,\n        destroy: destroy\n    }\n};\n\n// ruler guideline\n\n/**\n * Created by maor.frankel on 5/23/15.\n */\nruler.prototype.guideLine = function (line, _dragContainer, lineDimension, options, curDelta, moveCB, event) {\n\n  var self,\n    guideLine = line,\n    _curScale = 1,\n    _assigned = false,\n    _curPosDelta = curDelta || 0,\n    dragContainer = _dragContainer,\n    dimension = lineDimension || 2,\n    moveCB = moveCB || function () {\n      };\n\n\n  var curPosDelta = function (val) {\n    if (typeof val === 'undefined') {\n      return _curPosDelta;\n    }\n    return (_curPosDelta = val);\n  };\n\n  var assigned = function (val) {\n    if (typeof val === 'undefined') {\n      return _assigned;\n    }\n    return (_assigned = val);\n  };\n\n  var curScale = function (val) {\n    if (typeof val === 'undefined') {\n      return _curScale;\n    }\n    return (_curScale = val);\n  };\n\n\n  var draggable = (function () {\n    return {\n      move: function (xpos, ypos) {\n        guideLine.style.left = ruler.prototype.utils.pixelize(xpos);\n        guideLine.style.top = ruler.prototype.utils.pixelize(ypos);\n        updateToolTip(xpos, ypos);\n        moveCB(self, xpos, ypos);\n      },\n      startMoving: function (evt) {\n        ruler.prototype.utils.addClasss(guideLine, ['rul_line_dragged']);\n        evt = evt || window.event;\n        var posX = evt ? evt.clientX : 0,\n          posY = evt ? evt.clientY : 0,\n          divTop = parseInt(guideLine.style.top || 0),\n          divLeft = parseInt(guideLine.style.left || 0),\n          eWi = parseInt(guideLine.offsetWidth),\n          eHe = parseInt(guideLine.offsetHeight),\n          cWi = parseInt(dragContainer.offsetWidth),\n          cHe = parseInt(dragContainer.offsetHeight),\n          cursor = dimension === 2 ? 'ns-resize' : 'ew-resize';\n\n        options.container.style.cursor = cursor;\n        guideLine.style.cursor = cursor;\n        var diffX = posX - divLeft,\n          diffY = posY - divTop;\n        document.onmousemove = function moving(evt) {\n          evt = evt || window.event;\n          var posX = evt.clientX,\n            posY = evt.clientY,\n            aX = posX - diffX,\n            aY = posY - diffY;\n\n          if (aX < 0) {\n            aX = 0;\n          }\n          if (aY < 0) {\n            aY = 0;\n          }\n\n          if (aX + eWi > cWi) {\n            aX = cWi - eWi;\n          }\n          if (aY + eHe > cHe) {\n            aY = cHe - eHe;\n          }\n\n          draggable.move(aX, aY);\n        };\n        showToolTip();\n      },\n      stopMoving: function () {\n        options.container.style.cursor = null;\n        guideLine.style.cursor = null;\n        document.onmousemove = function () {\n        };\n        hideToolTip();\n        ruler.prototype.utils.removeClasss(guideLine, ['rul_line_dragged']);\n      }\n    }\n  })();\n\n  var showToolTip = function (e) {\n    if (!options.enableToolTip) {\n      return;\n    }\n    ruler.prototype.utils.addClasss(guideLine, 'rul_tooltip');\n  };\n\n  var updateToolTip = function (x, y) {\n    if (y) {\n      guideLine.dataset.tip = 'Y: ' + Math.round((y - options.rulerHeight - 1 - _curPosDelta) * _curScale) + ' px';\n    }\n    else {\n      guideLine.dataset.tip = 'X: ' + Math.round((x - options.rulerHeight - 1 - _curPosDelta) * _curScale) + ' px';\n    }\n  };\n\n  var hideToolTip = function (e) {\n    ruler.prototype.utils.removeClasss(guideLine, 'rul_tooltip');\n  };\n\n  var destroy = function () {\n    draggable.stopMoving();\n    moveCB = null;\n    guideLine.removeEventListener('mousedown', mousedown);\n    guideLine.removeEventListener('mouseup', mouseup);\n    guideLine.removeEventListener('dblclick', dblclick);\n    guideLine.parentNode && guideLine.parentNode.removeChild(guideLine);\n  };\n\n  var hide = function () {\n    guideLine.style.display = 'none';\n  };\n\n  var show = function () {\n    guideLine.style.display = 'block';\n  };\n\n  var mousedown = function (e) {\n    e.stopPropagation();\n    draggable.startMoving();\n  };\n\n  var mouseup = function (e) {\n    draggable.stopMoving();\n  };\n\n  var dblclick = function (e) {\n    e.stopPropagation();\n    destroy();\n  };\n\n  guideLine.addEventListener('mousedown', mousedown);\n\n  guideLine.addEventListener('mouseup', mouseup);\n\n  guideLine.addEventListener('dblclick', dblclick);\n  if(event) draggable.startMoving(event);\n\n  self = {\n    setAsDraggable: draggable,\n    startDrag: draggable.startMoving,\n    stopDrag: draggable.stopMoving,\n    destroy: destroy,\n    curScale: curScale,\n    assigned: assigned,\n    curPosDelta: curPosDelta,\n    guideLine: guideLine,\n    dimension: dimension,\n    hide: hide,\n    show: show\n  };\n  return self;\n\n};\n"
  },
  {
    "path": "src/libs/ruler/rulerConstructor.js",
    "content": "\nruler.prototype.rulerConstructor =  function(_canvas, options, rulDimension)\n{\n\n    var canvas = _canvas,\n        context = canvas.getContext('2d'),\n        rulThickness = 0,\n        rulLength = 0,\n        rulScale = 1,\n        dimension = rulDimension || 2,\n        orgPos = 0,\n        tracker = document.createElement('div');\n\n    var getLength = function (){\n        return rulLength;\n    };\n\n    var getThickness = function(){\n        return rulThickness;\n    };\n\n    var getScale = function(){\n        return rulScale;\n    };\n\n    var setScale = function(newScale){\n        rulScale = parseFloat(newScale);\n        drawPoints();\n        return rulScale;\n    };\n\n    var drawRuler = function (_rulerLength, _rulerThickness, _rulerScale){\n        rulLength = canvas.width = _rulerLength * 4;\n        rulThickness = canvas.height = _rulerThickness;\n        rulScale = _rulerScale || rulScale;\n        context.strokeStyle = options.strokeStyle;\n        context.font = options.fontSize + ' ' + options.fontFamily;\n        context.lineWidth = options.lineWidth;\n        context.beginPath();\n        drawPoints();\n        context.stroke();\n    };\n\n\n\n    var drawPoints = function () {\n        var  pointLength = 0,\n            label = '',\n            delta = 0,\n            draw = false,\n            lineLengthMax = 0,\n            lineLengthMed = rulThickness / 2,\n            lineLengthMin = rulThickness / 2;\n\n        for (var pos = 0; pos <= rulLength; pos += 1) {\n            delta = ((rulLength / 2) - pos);\n            draw = false;\n            label = '';\n\n            if (delta % 50 === 0) {\n                pointLength = lineLengthMax;\n                label = Math.round(Math.abs(delta)*rulScale);\n                draw = true;\n            }\n            else if (delta % 25 === 0) {\n                pointLength = lineLengthMed;\n                draw = true;\n            }\n            else if (delta % 5 === 0) {\n                pointLength = lineLengthMin;\n                draw = true;\n            }\n            if (draw) {\n                context.moveTo(pos + 0.5, rulThickness + 0.5);\n                context.lineTo(pos + 0.5, pointLength +  0.5);\n                context.fillText(label, pos + 1.5, (rulThickness / 2) + 1);\n            }\n        }\n    };\n\n    var mousemove = function(e) {\n      var posX = e.clientX;\n      var posY = e.clientY;\n      if(dimension === 2){\n        tracker.style.left = ruler.prototype.utils.pixelize(posX - parseInt(options.container.getBoundingClientRect().left));\n      }\n      else{\n        tracker.style.top = ruler.prototype.utils.pixelize(posY - parseInt(options.container.getBoundingClientRect().top)) ;\n      }\n    };\n\n    var destroy = function(){\n      options.container.removeEventListener('mousemove', mousemove);\n      tracker.parentNode.removeChild(tracker);\n      this.clearListeners && this.clearListeners();\n\n    };\n\n    var initTracker = function(){\n        tracker = options.container.appendChild(tracker);\n        ruler.prototype.utils.addClasss(tracker, 'rul_tracker');\n        var height = ruler.prototype.utils.pixelize(options.rulerHeight);\n        if(dimension === 2){\n            tracker.style.height = height;\n        }\n        else{\n            tracker.style.width = height;\n        }\n\n        options.container.addEventListener('mousemove', mousemove);\n    };\n\n    if(options.enableMouseTracking){\n        initTracker();\n    }\n\n\n    return{\n        getLength: getLength,\n        getThickness: getThickness,\n        getScale: getScale,\n        setScale: setScale,\n        dimension: dimension,\n        orgPos: orgPos,\n        canvas: canvas,\n        context: context,\n        drawRuler: drawRuler,\n        drawPoints: drawPoints,\n        destroy: destroy\n    }\n};\n\n"
  },
  {
    "path": "src/libs/ruler/rulerGuideLine.js",
    "content": "/**\n * Created by maor.frankel on 5/23/15.\n */\nruler.prototype.guideLine = function (line, _dragContainer, lineDimension, options, curDelta, moveCB, event) {\n\n  var self,\n    guideLine = line,\n    _curScale = 1,\n    _assigned = false,\n    _curPosDelta = curDelta || 0,\n    dragContainer = _dragContainer,\n    dimension = lineDimension || 2,\n    moveCB = moveCB || function () {\n      };\n\n\n  var curPosDelta = function (val) {\n    if (typeof val === 'undefined') {\n      return _curPosDelta;\n    }\n    return (_curPosDelta = val);\n  };\n\n  var assigned = function (val) {\n    if (typeof val === 'undefined') {\n      return _assigned;\n    }\n    return (_assigned = val);\n  };\n\n  var curScale = function (val) {\n    if (typeof val === 'undefined') {\n      return _curScale;\n    }\n    return (_curScale = val);\n  };\n\n\n  var draggable = (function () {\n    return {\n      move: function (xpos, ypos) {\n        guideLine.style.left = ruler.prototype.utils.pixelize(xpos);\n        guideLine.style.top = ruler.prototype.utils.pixelize(ypos);\n        updateToolTip(xpos, ypos);\n        moveCB(self, xpos, ypos);\n      },\n      startMoving: function (evt) {\n        ruler.prototype.utils.addClasss(guideLine, ['rul_line_dragged']);\n        evt = evt || window.event;\n        var posX = evt ? evt.clientX : 0,\n          posY = evt ? evt.clientY : 0,\n          divTop = parseInt(guideLine.style.top || 0),\n          divLeft = parseInt(guideLine.style.left || 0),\n          eWi = parseInt(guideLine.offsetWidth),\n          eHe = parseInt(guideLine.offsetHeight),\n          cWi = parseInt(dragContainer.offsetWidth),\n          cHe = parseInt(dragContainer.offsetHeight),\n          cursor = dimension === 2 ? 'ns-resize' : 'ew-resize';\n\n        options.container.style.cursor = cursor;\n        guideLine.style.cursor = cursor;\n        var diffX = posX - divLeft,\n          diffY = posY - divTop;\n        document.onmousemove = function moving(evt) {\n          evt = evt || window.event;\n          var posX = evt.clientX,\n            posY = evt.clientY,\n            aX = posX - diffX,\n            aY = posY - diffY;\n\n          if (aX < 0) {\n            aX = 0;\n          }\n          if (aY < 0) {\n            aY = 0;\n          }\n\n          if (aX + eWi > cWi) {\n            aX = cWi - eWi;\n          }\n          if (aY + eHe > cHe) {\n            aY = cHe - eHe;\n          }\n\n          draggable.move(aX, aY);\n        };\n        showToolTip();\n      },\n      stopMoving: function () {\n        options.container.style.cursor = null;\n        guideLine.style.cursor = null;\n        document.onmousemove = function () {\n        };\n        hideToolTip();\n        ruler.prototype.utils.removeClasss(guideLine, ['rul_line_dragged']);\n      }\n    }\n  })();\n\n  var showToolTip = function (e) {\n    if (!options.enableToolTip) {\n      return;\n    }\n    ruler.prototype.utils.addClasss(guideLine, 'rul_tooltip');\n  };\n\n  var updateToolTip = function (x, y) {\n    if (y) {\n      guideLine.dataset.tip = 'Y: ' + Math.round((y - options.rulerHeight - 1 - _curPosDelta) * _curScale) + ' px';\n    }\n    else {\n      guideLine.dataset.tip = 'X: ' + Math.round((x - options.rulerHeight - 1 - _curPosDelta) * _curScale) + ' px';\n    }\n  };\n\n  var hideToolTip = function (e) {\n    ruler.prototype.utils.removeClasss(guideLine, 'rul_tooltip');\n  };\n\n  var destroy = function () {\n    draggable.stopMoving();\n    moveCB = null;\n    guideLine.removeEventListener('mousedown', mousedown);\n    guideLine.removeEventListener('mouseup', mouseup);\n    guideLine.removeEventListener('dblclick', dblclick);\n    guideLine.parentNode && guideLine.parentNode.removeChild(guideLine);\n  };\n\n  var hide = function () {\n    guideLine.style.display = 'none';\n  };\n\n  var show = function () {\n    guideLine.style.display = 'block';\n  };\n\n  var mousedown = function (e) {\n    e.stopPropagation();\n    draggable.startMoving();\n  };\n\n  var mouseup = function (e) {\n    draggable.stopMoving();\n  };\n\n  var dblclick = function (e) {\n    e.stopPropagation();\n    destroy();\n  };\n\n  guideLine.addEventListener('mousedown', mousedown);\n\n  guideLine.addEventListener('mouseup', mouseup);\n\n  guideLine.addEventListener('dblclick', dblclick);\n  if(event) draggable.startMoving(event);\n\n  self = {\n    setAsDraggable: draggable,\n    startDrag: draggable.startMoving,\n    stopDrag: draggable.stopMoving,\n    destroy: destroy,\n    curScale: curScale,\n    assigned: assigned,\n    curPosDelta: curPosDelta,\n    guideLine: guideLine,\n    dimension: dimension,\n    hide: hide,\n    show: show\n  };\n  return self;\n\n};"
  },
  {
    "path": "src/libs/ruler/utils.js",
    "content": "/**\n * Created by maor.frankel on 5/25/15.\n */\nruler.prototype.utils = {\n    extend: function extend(){\n        for(var i=1; i< arguments.length; i++)\n            for(var key in arguments[i])\n                if(arguments[i].hasOwnProperty(key))\n                    arguments[0][key] = arguments[i][key];\n        return arguments[0];\n    },\n    pixelize: function (val){\n        return val + 'px';\n    },\n    prependChild: function (container, element){\n        return container.insertBefore(element,container.firstChild);\n    },\n    addClasss: function (element, classNames){\n        if(!(classNames instanceof Array))\n        {\n            classNames = [classNames];\n        }\n\n        classNames.forEach(function (name){\n            element.className += ' ' + name;\n        });\n\n        return element;\n\n    },\n    removeClasss: function (element, classNames){\n        var curCalsss = element.className;\n        if(!(classNames instanceof Array))\n        {\n            classNames = [classNames];\n        }\n\n        classNames.forEach(function (name){\n            curCalsss = curCalsss.replace(name, '');\n        });\n        element.className = curCalsss;\n        return element;\n\n    }\n} ;\n"
  },
  {
    "path": "src/libs/screen-templates.json",
    "content": "{\n  \"0\": {\n    \"1920x1080\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 1080\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 880\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1920,\n          \"h\": 880\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType3_sd1\",\n          \"x\": 420,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 1080\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType4_sd1\",\n          \"x\": 1500,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1080\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 880\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType5_sd1\",\n          \"x\": 1500,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 880\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType6_sd1\",\n          \"x\": 420,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 880\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType7_sd1\",\n          \"x\": 960,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 540\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 540,\n          \"w\": 1500,\n          \"h\": 540\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType8_sd2\",\n          \"x\": 1500,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1080\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType9_sd1\",\n          \"x\": 420,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 540\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType9_sd2\",\n          \"x\": 420,\n          \"y\": 540,\n          \"w\": 1500,\n          \"h\": 540\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 360\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 360,\n          \"w\": 1920,\n          \"h\": 360\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 1920,\n          \"h\": 360\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType11_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 1320,\n          \"h\": 540\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType11_sd2\",\n          \"x\": 600,\n          \"y\": 540,\n          \"w\": 1320,\n          \"h\": 540\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType11_sd3\",\n          \"x\": 1620,\n          \"y\": 780,\n          \"w\": 300,\n          \"h\": 300\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType12_sd1\",\n          \"x\": 500,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType12_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 500,\n          \"h\": 380\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType12_sd3\",\n          \"x\": 500,\n          \"y\": 700,\n          \"w\": 500,\n          \"h\": 380\n        },\n        \"sd4\": {\n          \"id\": \"horizontal_1920x1080_screenType12_sd4\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 920,\n          \"h\": 1080\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType13_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 920,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType13_sd2\",\n          \"x\": 1000,\n          \"y\": 700,\n          \"w\": 920,\n          \"h\": 380\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 540\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 540,\n          \"w\": 960,\n          \"h\": 540\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType14_sd2\",\n          \"x\": 960,\n          \"y\": 540,\n          \"w\": 960,\n          \"h\": 540\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType15_sd1\",\n          \"x\": 960,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType15_sd2\",\n          \"x\": 560,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 400\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType16_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType16_sd2\",\n          \"x\": 1280,\n          \"y\": 540,\n          \"w\": 640,\n          \"h\": 540\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType16_sd3\",\n          \"x\": 1280,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 540\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 540\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType17_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 540\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType17_sd2\",\n          \"x\": 1280,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 540\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType17_sd3\",\n          \"x\": 0,\n          \"y\": 540,\n          \"w\": 1920,\n          \"h\": 540\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType18_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType8_sd2\",\n          \"x\": 0,\n          \"y\": 400,\n          \"w\": 960,\n          \"h\": 680\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType18_sd3\",\n          \"x\": 960,\n          \"y\": 400,\n          \"w\": 960,\n          \"h\": 680\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1080_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1080_screenType19_sd1\",\n          \"x\": 900,\n          \"y\": 0,\n          \"w\": 1020,\n          \"h\": 540\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1080_screenType19_sd2\",\n          \"x\": 900,\n          \"y\": 540,\n          \"w\": 1020,\n          \"h\": 540\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType19_sd3\",\n          \"x\": 500,\n          \"y\": 680,\n          \"w\": 400,\n          \"h\": 400\n        }\n      }\n    },\n    \"1366x768\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1366,\n          \"h\": 768\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1366,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1366,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1366,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1366,\n          \"h\": 568\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType3_sd1\",\n          \"x\": 366,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 768\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType4_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 768\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType5_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1366,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType6_sd1\",\n          \"x\": 366,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1366,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 683,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType7_sd1\",\n          \"x\": 683,\n          \"y\": 0,\n          \"w\": 683,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1366,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType8_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 768\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType8_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType8_sd3\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 341,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType9_sd1\",\n          \"x\": 341,\n          \"y\": 0,\n          \"w\": 341,\n          \"h\": 768\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType9_sd2\",\n          \"x\": 682,\n          \"y\": 0,\n          \"w\": 341,\n          \"h\": 768\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType9_sd3\",\n          \"x\": 1023,\n          \"y\": 0,\n          \"w\": 343,\n          \"h\": 768\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1366,\n          \"h\": 192\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 192,\n          \"w\": 1366,\n          \"h\": 192\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 384,\n          \"w\": 1366,\n          \"h\": 192\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1080_screenType10_sd3\",\n          \"x\": 0,\n          \"y\": 576,\n          \"w\": 1366,\n          \"h\": 192\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 683,\n          \"h\": 384\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType11_sd1\",\n          \"x\": 683,\n          \"y\": 0,\n          \"w\": 683,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType11_sd2\",\n          \"x\": 200,\n          \"y\": 384,\n          \"w\": 1166,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 384,\n          \"w\": 200,\n          \"h\": 384\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 256\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 256,\n          \"w\": 366,\n          \"h\": 256\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType12_sd2\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 366,\n          \"h\": 256\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType12_sd3\",\n          \"x\": 366,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 768\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1366,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType13_sd2\",\n          \"x\": 1166,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1366,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType14_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 568\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 683,\n          \"h\": 384\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType15_sd1\",\n          \"x\": 683,\n          \"y\": 0,\n          \"w\": 683,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 384,\n          \"w\": 683,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType15_sd3\",\n          \"x\": 683,\n          \"y\": 384,\n          \"w\": 683,\n          \"h\": 384\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType16_sd1\",\n          \"x\": 366,\n          \"y\": 100,\n          \"w\": 1000,\n          \"h\": 668\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType16_sd2\",\n          \"x\": 366,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 100\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType16_sd3\",\n          \"x\": 366,\n          \"y\": 668,\n          \"w\": 100,\n          \"h\": 100\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType17_sd1\",\n          \"x\": 366,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 256\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType17_sd2\",\n          \"x\": 366,\n          \"y\": 256,\n          \"w\": 1000,\n          \"h\": 256\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType17_sd3\",\n          \"x\": 366,\n          \"y\": 512,\n          \"w\": 1000,\n          \"h\": 256\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType18_sd1\",\n          \"x\": 366,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 768\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType18_sd2\",\n          \"x\": 1266,\n          \"y\": 0,\n          \"w\": 100,\n          \"h\": 100\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType18_sd3\",\n          \"x\": 1266,\n          \"y\": 668,\n          \"w\": 100,\n          \"h\": 100\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1366x768_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1366x768_screenType19_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 366,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1366x768_screenType19_sd2\",\n          \"x\": 1000,\n          \"y\": 384,\n          \"w\": 366,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1366x768_screenType19_sd3\",\n          \"x\": 700,\n          \"y\": 468,\n          \"w\": 300,\n          \"h\": 300\n        }\n      }\n    },\n    \"1440x900\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 900\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1440,\n          \"h\": 700\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType3_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 900\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType4_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 900\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType5_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType6_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType7_sd1\",\n          \"x\": 720,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 1000,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType8_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 900\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 300\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 300,\n          \"w\": 480,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType9_sd2\",\n          \"x\": 480,\n          \"y\": 300,\n          \"w\": 480,\n          \"h\": 600\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType9_sd3\",\n          \"x\": 960,\n          \"y\": 300,\n          \"w\": 480,\n          \"h\": 600\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 300\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 300,\n          \"w\": 1000,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType10_sd2\",\n          \"x\": 1000,\n          \"y\": 300,\n          \"w\": 440,\n          \"h\": 600\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType11_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType11_sd2\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 440,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType11_sd3\",\n          \"x\": 440,\n          \"y\": 450,\n          \"w\": 1000,\n          \"h\": 450\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 1000,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType12_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 220,\n          \"h\": 900\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType12_sd3\",\n          \"x\": 1220,\n          \"y\": 0,\n          \"w\": 220,\n          \"h\": 900\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType13_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType13_sd2\",\n          \"x\": 440,\n          \"y\": 600,\n          \"w\": 1000,\n          \"h\": 300\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType13_sd3\",\n          \"x\": 440,\n          \"y\": 300,\n          \"w\": 300,\n          \"h\": 300\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1000,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType14_sd1\",\n          \"x\": 1000,\n          \"y\": 200,\n          \"w\": 440,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 250,\n          \"h\": 250\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 470,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType15_sd2\",\n          \"x\": 470,\n          \"y\": 200,\n          \"w\": 500,\n          \"h\": 700\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType15_sd3\",\n          \"x\": 970,\n          \"y\": 200,\n          \"w\": 470,\n          \"h\": 700\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1000,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType16_sd1\",\n          \"x\": 1000,\n          \"y\": 200,\n          \"w\": 440,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType16_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType16_sd3\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 300,\n          \"h\": 300\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType17_sd1\",\n          \"x\": 720,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 720,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType17_sd3\",\n          \"x\": 720,\n          \"y\": 450,\n          \"w\": 720,\n          \"h\": 450\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 300\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType18_sd1\",\n          \"x\": 0,\n          \"y\": 300,\n          \"w\": 1440,\n          \"h\": 300\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1440,\n          \"h\": 300\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x900_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1440x900_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 440,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1440x900_screenType19_sd2\",\n          \"x\": 440,\n          \"y\": 200,\n          \"w\": 1000,\n          \"h\": 700\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1440x900_screenType19_sd3\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 200\n        }\n      }\n    },\n    \"1280x800\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 800\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 600\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType3_sd1\",\n          \"x\": 280,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 800\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType4_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 800\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType5_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType6_sd1\",\n          \"x\": 280,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType7_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 400\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 400,\n          \"w\": 800,\n          \"h\": 400\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType8_sd2\",\n          \"x\": 800,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 800\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType9_sd1\",\n          \"x\": 480,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 400\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType9_sd2\",\n          \"x\": 480,\n          \"y\": 400,\n          \"w\": 800,\n          \"h\": 400\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 300\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 300,\n          \"w\": 1280,\n          \"h\": 300\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 400\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType11_sd2\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 400\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType12_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType12_sd2\",\n          \"x\": 800,\n          \"y\": 600,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType13_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType13_sd3\",\n          \"x\": 1080,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType14_sd1\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 400\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 400,\n          \"w\": 1000,\n          \"h\": 400\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType15_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 400\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType15_sd3\",\n          \"x\": 1000,\n          \"y\": 400,\n          \"w\": 280,\n          \"h\": 400\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 400\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 400,\n          \"w\": 280,\n          \"h\": 400\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType16_sd2\",\n          \"x\": 280,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 400\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType16_sd3\",\n          \"x\": 280,\n          \"y\": 400,\n          \"w\": 1000,\n          \"h\": 400\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType17_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType17_sd3\",\n          \"x\": 800,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType18_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x800_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x800_screenType19_sd1\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x800_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x800_screenType19_sd3\",\n          \"x\": 1080,\n          \"y\": 600,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1280x1024\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 1024\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 824\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 380,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType3_sd1\",\n          \"x\": 380,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1024\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType4_sd1\",\n          \"x\": 900,\n          \"y\": 0,\n          \"w\": 380,\n          \"h\": 1024\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType5_sd1\",\n          \"x\": 900,\n          \"y\": 0,\n          \"w\": 380,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 380,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType6_sd1\",\n          \"x\": 380,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType7_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 1000,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType8_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 1024\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType9_sd1\",\n          \"x\": 280,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType9_sd2\",\n          \"x\": 280,\n          \"y\": 512,\n          \"w\": 1000,\n          \"h\": 512\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 300\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 300,\n          \"w\": 1280,\n          \"h\": 300\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1280,\n          \"h\": 424\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 624\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType11_sd2\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 624\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType12_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 1024\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType12_sd2\",\n          \"x\": 800,\n          \"y\": 824,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType13_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 1024\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType13_sd3\",\n          \"x\": 1080,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType14_sd1\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 1000,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType15_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 512\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType15_sd3\",\n          \"x\": 1000,\n          \"y\": 512,\n          \"w\": 280,\n          \"h\": 512\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 280,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 280,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType16_sd2\",\n          \"x\": 280,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 512\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType16_sd3\",\n          \"x\": 280,\n          \"y\": 512,\n          \"w\": 1000,\n          \"h\": 512\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType17_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 640,\n          \"h\": 512\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType17_sd3\",\n          \"x\": 640,\n          \"y\": 512,\n          \"w\": 640,\n          \"h\": 512\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1000,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType18_sd1\",\n          \"x\": 1000,\n          \"y\": 200,\n          \"w\": 280,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x1024_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x1024_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x1024_screenType19_sd2\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 824\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x1024_screenType19_sd3\",\n          \"x\": 1080,\n          \"y\": 824,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1680x1050\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 1050\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1680,\n          \"h\": 850\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 1050\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType3_sd1\",\n          \"x\": 480,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 1050\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 1050\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType4_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 1050\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType5_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType6_sd1\",\n          \"x\": 680,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 840,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType7_sd1\",\n          \"x\": 840,\n          \"y\": 0,\n          \"w\": 840,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 525\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 525,\n          \"w\": 1200,\n          \"h\": 525\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType8_sd2\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 1050\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 1050\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType9_sd1\",\n          \"x\": 480,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 525\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType9_sd2\",\n          \"x\": 480,\n          \"y\": 525,\n          \"w\": 1200,\n          \"h\": 525\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 350\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 350,\n          \"w\": 1680,\n          \"h\": 350\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1680,\n          \"h\": 350\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 840,\n          \"h\": 650\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType11_sd2\",\n          \"x\": 840,\n          \"y\": 200,\n          \"w\": 840,\n          \"h\": 650\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 1050\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType12_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 1050\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType12_sd2\",\n          \"x\": 1000,\n          \"y\": 850,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 840,\n          \"h\": 1050\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType13_sd1\",\n          \"x\": 840,\n          \"y\": 0,\n          \"w\": 840,\n          \"h\": 1050\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType13_sd3\",\n          \"x\": 1480,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 840,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType14_sd1\",\n          \"x\": 840,\n          \"y\": 200,\n          \"w\": 840,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 525\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 525,\n          \"w\": 1000,\n          \"h\": 525\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType15_sd2\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 525\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType15_sd3\",\n          \"x\": 1000,\n          \"y\": 525,\n          \"w\": 680,\n          \"h\": 525\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 525\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 525,\n          \"w\": 480,\n          \"h\": 525\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType16_sd2\",\n          \"x\": 480,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 525\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType16_sd3\",\n          \"x\": 480,\n          \"y\": 525,\n          \"w\": 1200,\n          \"h\": 525\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType17_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType17_sd3\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 850\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType18_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 850,\n          \"w\": 1680,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1680x1050_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1680,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1680x1050_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 840,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1680x1050_screenType19_sd2\",\n          \"x\": 840,\n          \"y\": 200,\n          \"w\": 840,\n          \"h\": 850\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1680x1050_screenType19_sd3\",\n          \"x\": 1480,\n          \"y\": 850,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1600x900\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 900\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1600,\n          \"h\": 700\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType3_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 900\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType4_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 900\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType5_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType6_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType7_sd1\",\n          \"x\": 800,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 1200,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType8_sd2\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 900\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType9_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType9_sd2\",\n          \"x\": 400,\n          \"y\": 450,\n          \"w\": 1200,\n          \"h\": 450\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 300\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 300,\n          \"w\": 1600,\n          \"h\": 300\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1600,\n          \"h\": 300\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 500\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType11_sd2\",\n          \"x\": 800,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 500\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType12_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 900\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType12_sd2\",\n          \"x\": 1000,\n          \"y\": 700,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 900\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType13_sd1\",\n          \"x\": 800,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 900\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType13_sd3\",\n          \"x\": 1400,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1200,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType14_sd1\",\n          \"x\": 1200,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1100,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 1100,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType15_sd2\",\n          \"x\": 1100,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType15_sd3\",\n          \"x\": 1100,\n          \"y\": 450,\n          \"w\": 500,\n          \"h\": 450\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 450\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 450,\n          \"w\": 400,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType16_sd2\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType16_sd3\",\n          \"x\": 400,\n          \"y\": 450,\n          \"w\": 1200,\n          \"h\": 450\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType17_sd1\",\n          \"x\": 1200,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType17_sd3\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 700\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType18_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 700,\n          \"w\": 1600,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1600x900_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1600,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1600x900_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 700\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1600x900_screenType19_sd2\",\n          \"x\": 800,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 700\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1600x900_screenType19_sd3\",\n          \"x\": 1400,\n          \"y\": 700,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1920x1200\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 1200\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1920,\n          \"h\": 1000\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType3_sd1\",\n          \"x\": 500,\n          \"y\": 0,\n          \"w\": 1420,\n          \"h\": 1200\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 1200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType4_sd1\",\n          \"x\": 1500,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1200\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType5_sd1\",\n          \"x\": 1520,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType6_sd1\",\n          \"x\": 420,\n          \"y\": 0,\n          \"w\": 1500,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType7_sd1\",\n          \"x\": 960,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1520,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType8_sd2\",\n          \"x\": 1520,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1200\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType9_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType9_sd2\",\n          \"x\": 400,\n          \"y\": 600,\n          \"w\": 1520,\n          \"h\": 600\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 400\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 400,\n          \"w\": 1920,\n          \"h\": 400\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 800,\n          \"w\": 1920,\n          \"h\": 400\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 960,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType11_sd2\",\n          \"x\": 960,\n          \"y\": 200,\n          \"w\": 960,\n          \"h\": 800\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 1200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType12_sd1\",\n          \"x\": 1520,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1200\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType12_sd2\",\n          \"x\": 1320,\n          \"y\": 1000,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 1200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType13_sd1\",\n          \"x\": 960,\n          \"y\": 0,\n          \"w\": 960,\n          \"h\": 1200\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType13_sd3\",\n          \"x\": 1720,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 960,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType14_sd1\",\n          \"x\": 960,\n          \"y\": 200,\n          \"w\": 960,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 1520,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType15_sd2\",\n          \"x\": 1520,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 600\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType15_sd3\",\n          \"x\": 1520,\n          \"y\": 600,\n          \"w\": 400,\n          \"h\": 600\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 600\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 600,\n          \"w\": 400,\n          \"h\": 600\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType16_sd2\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 600\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType16_sd3\",\n          \"x\": 400,\n          \"y\": 600,\n          \"w\": 1520,\n          \"h\": 600\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType17_sd1\",\n          \"x\": 1520,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType17_sd3\",\n          \"x\": 1320,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1520,\n          \"h\": 1000\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType18_sd1\",\n          \"x\": 1520,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 1000,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1920x1200_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1920,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1920x1200_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 960,\n          \"h\": 1000\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1920x1200_screenType19_sd2\",\n          \"x\": 960,\n          \"y\": 200,\n          \"w\": 960,\n          \"h\": 1000\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1920x1200_screenType19_sd3\",\n          \"x\": 1720,\n          \"y\": 1000,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1024x768\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 768\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1024,\n          \"h\": 568\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 724,\n          \"h\": 768\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 724,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType4_sd1\",\n          \"x\": 724,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 768\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType5_sd1\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType6_sd1\",\n          \"x\": 324,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType7_sd1\",\n          \"x\": 512,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 384\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 384,\n          \"w\": 700,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType8_sd2\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 768\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType9_sd1\",\n          \"x\": 324,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType9_sd2\",\n          \"x\": 324,\n          \"y\": 384,\n          \"w\": 700,\n          \"h\": 384\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 256\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 256,\n          \"w\": 1024,\n          \"h\": 256\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 1024,\n          \"h\": 256\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 512,\n          \"h\": 368\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType11_sd2\",\n          \"x\": 512,\n          \"y\": 200,\n          \"w\": 512,\n          \"h\": 368\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 624,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType12_sd1\",\n          \"x\": 624,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 768\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType12_sd2\",\n          \"x\": 424,\n          \"y\": 568,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 768\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType13_sd1\",\n          \"x\": 512,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 768\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType13_sd3\",\n          \"x\": 824,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 700,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType14_sd1\",\n          \"x\": 700,\n          \"y\": 200,\n          \"w\": 324,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 384\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 384,\n          \"w\": 700,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType15_sd2\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType15_sd3\",\n          \"x\": 700,\n          \"y\": 384,\n          \"w\": 324,\n          \"h\": 384\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 384\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 384,\n          \"w\": 324,\n          \"h\": 384\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType16_sd2\",\n          \"x\": 324,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType16_sd3\",\n          \"x\": 324,\n          \"y\": 384,\n          \"w\": 700,\n          \"h\": 384\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType17_sd1\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType17_sd3\",\n          \"x\": 500,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 700,\n          \"h\": 568\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType18_sd1\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 324,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 568,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x768_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1024x768_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 512,\n          \"h\": 568\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1024x768_screenType19_sd2\",\n          \"x\": 512,\n          \"y\": 200,\n          \"w\": 512,\n          \"h\": 568\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1024x768_screenType19_sd3\",\n          \"x\": 824,\n          \"y\": 568,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1280x720\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 720\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 520\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 520\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 980,\n          \"h\": 720\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 980,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType4_sd1\",\n          \"x\": 980,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 720\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 520\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType5_sd1\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 520\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType6_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 520\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType7_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 360\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 360,\n          \"w\": 880,\n          \"h\": 360\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType8_sd2\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 720\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType9_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 360\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType9_sd2\",\n          \"x\": 400,\n          \"y\": 360,\n          \"w\": 880,\n          \"h\": 360\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 240,\n          \"w\": 1280,\n          \"h\": 240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 480,\n          \"w\": 1280,\n          \"h\": 240\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 320\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType11_sd2\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 320\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType12_sd1\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType12_sd2\",\n          \"x\": 680,\n          \"y\": 520,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType13_sd1\",\n          \"x\": 640,\n          \"y\": 0,\n          \"w\": 640,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType13_sd3\",\n          \"x\": 1080,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 520\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType14_sd1\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 360\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 360,\n          \"w\": 880,\n          \"h\": 360\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType15_sd2\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 360\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_11280x720_screenType15_sd3\",\n          \"x\": 880,\n          \"y\": 360,\n          \"w\": 400,\n          \"h\": 360\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 360\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 360,\n          \"w\": 400,\n          \"h\": 360\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType16_sd2\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 360\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType16_sd3\",\n          \"x\": 400,\n          \"y\": 360,\n          \"w\": 880,\n          \"h\": 360\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 560\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType17_sd1\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType17_sd3\",\n          \"x\": 680,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 880,\n          \"h\": 520\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType18_sd1\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 520,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1280x720_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_1280x720_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 520\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_1280x720_screenType19_sd2\",\n          \"x\": 640,\n          \"y\": 200,\n          \"w\": 640,\n          \"h\": 520\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_1280x720_screenType19_sd3\",\n          \"x\": 1080,\n          \"y\": 520,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"2560x1440\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 1440\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 2560,\n          \"h\": 1240\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType3_sd1\",\n          \"x\": 560,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1440\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType4_sd1\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1440\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType5_sd1\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType5_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440screenType6_sd1\",\n          \"x\": 560,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType7_sd1\",\n          \"x\": 1280,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 2000,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType8_sd2\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1440\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType9_sd1\",\n          \"x\": 560,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType9_sd2\",\n          \"x\": 560,\n          \"y\": 720,\n          \"w\": 2000,\n          \"h\": 720\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 480\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType10_sd1\",\n          \"x\": 0,\n          \"y\": 480,\n          \"w\": 2560,\n          \"h\": 480\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType10_sd2\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 2560,\n          \"h\": 480\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 1040\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType11_sd2\",\n          \"x\": 1280,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 1040\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType11_sd3\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType12_sd1\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1440\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType12_sd2\",\n          \"x\": 1800,\n          \"y\": 1240,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType13_sd1\",\n          \"x\": 1280,\n          \"y\": 0,\n          \"w\": 1280,\n          \"h\": 1440\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType13_sd3\",\n          \"x\": 2360,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType14_sd1\",\n          \"x\": 1280,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType15_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 2000,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType15_sd2\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 720\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType15_sd3\",\n          \"x\": 2000,\n          \"y\": 720,\n          \"w\": 560,\n          \"h\": 720\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 560,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType16_sd2\",\n          \"x\": 560,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 720\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType16_sd3\",\n          \"x\": 560,\n          \"y\": 720,\n          \"w\": 2000,\n          \"h\": 720\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType17_sd1\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType17_sd3\",\n          \"x\": 1800,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2000,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType18_sd1\",\n          \"x\": 2000,\n          \"y\": 0,\n          \"w\": 560,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType18_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 2560,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType18_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"horizontal_2560x1440_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 2560,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"horizontal_2560x1440_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"horizontal_2560x1440_screenType19_sd2\",\n          \"x\": 1280,\n          \"y\": 200,\n          \"w\": 1280,\n          \"h\": 1240\n        },\n        \"sd3\": {\n          \"id\": \"horizontal_2560x1440_screenType19_sd3\",\n          \"x\": 2360,\n          \"y\": 1240,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    }\n  },\n  \"1\": {\n    \"1080x1920\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 1920\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 1720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1080,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1080,\n          \"h\": 1720\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType3_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 1920\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType4_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 480,\n          \"h\": 1920\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 1080,\n          \"h\": 960\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 1720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType6_sd1\",\n          \"x\": 680,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1080,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType7_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1080,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 680,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType8_sd2\",\n          \"x\": 680,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 1720\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType9_sd2\",\n          \"x\": 400,\n          \"y\": 200,\n          \"w\": 680,\n          \"h\": 1720\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType10_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType10_sd2\",\n          \"x\": 400,\n          \"y\": 960,\n          \"w\": 680,\n          \"h\": 960\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 540,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType11_sd2\",\n          \"x\": 540,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 1920\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 540,\n          \"h\": 1520\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType12_sd2\",\n          \"x\": 540,\n          \"y\": 200,\n          \"w\": 540,\n          \"h\": 1520\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1080,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1080,\n          \"h\": 1520\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType13_sd3\",\n          \"x\": 880,\n          \"y\": 1520,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1080,\n          \"h\": 1520\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1080,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 1520,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType15_sd1\",\n          \"x\": 540,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 1080,\n          \"h\": 960\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType15_sd3\",\n          \"x\": 880,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 540,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType16_sd2\",\n          \"x\": 540,\n          \"y\": 960,\n          \"w\": 540,\n          \"h\": 960\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType16_sd3\",\n          \"x\": 880,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType17_sd1\",\n          \"x\": 540,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 1920\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType17_sd2\",\n          \"x\": 880,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType17_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType18_sd1\",\n          \"x\": 540,\n          \"y\": 0,\n          \"w\": 540,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType18_sd2\",\n          \"x\": 540,\n          \"y\": 640,\n          \"w\": 540,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType18_sd3\",\n          \"x\": 540,\n          \"y\": 1280,\n          \"w\": 540,\n          \"h\": 640\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_1080x1920_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1080,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1080x1920_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 1080,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1080x1920_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1080x1920_screenType19_sd3\",\n          \"x\": 880,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"768x1366\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_768x1366_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 1366\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 1166\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 768,\n          \"h\": 1166\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1366\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 1366\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 1366\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType4_sd1\",\n          \"x\": 468,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1366\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 683\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 683,\n          \"w\": 768,\n          \"h\": 683\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1166\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType6_sd1\",\n          \"x\": 500,\n          \"y\": 0,\n          \"w\": 268,\n          \"h\": 1166\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 268,\n          \"h\": 1166\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType7_sd1\",\n          \"x\": 268,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1166\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 500,\n          \"h\": 1166\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType8_sd2\",\n          \"x\": 500,\n          \"y\": 200,\n          \"w\": 268,\n          \"h\": 1166\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 268,\n          \"h\": 1166\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType9_sd2\",\n          \"x\": 268,\n          \"y\": 200,\n          \"w\": 500,\n          \"h\": 1166\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1366\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType10_sd1\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType10_sd2\",\n          \"x\": 384,\n          \"y\": 683,\n          \"w\": 384,\n          \"h\": 683\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 683,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType11_sd2\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1366\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 683,\n          \"h\": 966\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType12_sd2\",\n          \"x\": 384,\n          \"y\": 200,\n          \"w\": 384,\n          \"h\": 966\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 768,\n          \"h\": 966\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType13_sd3\",\n          \"x\": 568,\n          \"y\": 966,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 768,\n          \"h\": 966\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 966,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType15_sd1\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 683,\n          \"w\": 768,\n          \"h\": 683\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType15_sd3\",\n          \"x\": 568,\n          \"y\": 1166,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 683\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 683,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType16_sd2\",\n          \"x\": 384,\n          \"y\": 683,\n          \"w\": 384,\n          \"h\": 683\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType16_sd3\",\n          \"x\": 568,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1366\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType17_sd1\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1366\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType17_sd2\",\n          \"x\": 384,\n          \"y\": 982,\n          \"w\": 384,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType17_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 384\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1366\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType18_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 450\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType18_sd2\",\n          \"x\": 300,\n          \"y\": 450,\n          \"w\": 468,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType18_sd3\",\n          \"x\": 300,\n          \"y\": 900,\n          \"w\": 468,\n          \"h\": 466\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1366_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 683\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1366_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 683,\n          \"w\": 768,\n          \"h\": 683\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1366_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1166,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1366_screenType19_sd3\",\n          \"x\": 568,\n          \"y\": 1166,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"900x1440\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_900x1440_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1440\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 900,\n          \"h\": 1240\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1440\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType4_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1440\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 900,\n          \"h\": 720\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType6_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1240\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType7_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType8_sd2\",\n          \"x\": 600,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1240\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1240\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType9_sd2\",\n          \"x\": 300,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1240\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType10_sd1\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType10_sd2\",\n          \"x\": 450,\n          \"y\": 720,\n          \"w\": 450,\n          \"h\": 720\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType11_sd2\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1440\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 450,\n          \"h\": 1040\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType12_sd2\",\n          \"x\": 450,\n          \"y\": 200,\n          \"w\": 450,\n          \"h\": 1040\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 900,\n          \"h\": 1040\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType13_sd3\",\n          \"x\": 700,\n          \"y\": 1040,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 900,\n          \"h\": 1040\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 1040,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType15_sd1\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 900,\n          \"h\": 720\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType14_sd3\",\n          \"x\": 700,\n          \"y\": 1240,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType16_sd2\",\n          \"x\": 450,\n          \"y\": 720,\n          \"w\": 450,\n          \"h\": 720\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType14_sd3\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType17_sd1\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1440\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType14_sd3\",\n          \"x\": 450,\n          \"y\": 990,\n          \"w\": 450,\n          \"h\": 450\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1440\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType18_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 480\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType18_sd2\",\n          \"x\": 300,\n          \"y\": 480,\n          \"w\": 600,\n          \"h\": 480\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType14_sd3\",\n          \"x\": 300,\n          \"y\": 960,\n          \"w\": 600,\n          \"h\": 480\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1440_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1440_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 720,\n          \"w\": 900,\n          \"h\": 720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1440_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1240,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1440_screenType19_sd3\",\n          \"x\": 700,\n          \"y\": 1240,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"800x1280\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_800x1280_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 1280\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 800,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 1080\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1280\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType4_sd1\",\n          \"x\": 500,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1280\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 800,\n          \"h\": 640\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType6_sd1\",\n          \"x\": 500,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 800,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType7_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 800,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 500,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType8_sd2\",\n          \"x\": 500,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1080\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType9_sd2\",\n          \"x\": 300,\n          \"y\": 200,\n          \"w\": 500,\n          \"h\": 1080\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType10_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType10_sd2\",\n          \"x\": 400,\n          \"y\": 640,\n          \"w\": 400,\n          \"h\": 640\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType11_sd2\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType12_sd2\",\n          \"x\": 400,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 880\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 800,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType13_sd3\",\n          \"x\": 600,\n          \"y\": 880,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 800,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType15_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 800,\n          \"h\": 640\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType16_sd2\",\n          \"x\": 400,\n          \"y\": 640,\n          \"w\": 400,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType16_sd3\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType17_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 400\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType17_sd3\",\n          \"x\": 400,\n          \"y\": 880,\n          \"w\": 400,\n          \"h\": 400\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType18_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 500,\n          \"h\": 420\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType18_sd2\",\n          \"x\": 300,\n          \"y\": 420,\n          \"w\": 500,\n          \"h\": 420\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType18_sd3\",\n          \"x\": 300,\n          \"y\": 840,\n          \"w\": 500,\n          \"h\": 440\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_800x1280_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_800x1280_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 800,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_800x1280_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_800x1280_screenType19_sd3\",\n          \"x\": 600,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1024x1280\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1024x1280_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 1280\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1024,\n          \"h\": 1080\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType3_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 624,\n          \"h\": 1280\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 624,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType4_sd1\",\n          \"x\": 624,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 1024,\n          \"h\": 640\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType6_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 424,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 424,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType7_sd1\",\n          \"x\": 424,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 624,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType8_sd2\",\n          \"x\": 624,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 1080\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType9_sd2\",\n          \"x\": 400,\n          \"y\": 200,\n          \"w\": 624,\n          \"h\": 1080\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType10_sd1\",\n          \"x\": 512,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType10_sd2\",\n          \"x\": 512,\n          \"y\": 640,\n          \"w\": 512,\n          \"h\": 640\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType11_sd2\",\n          \"x\": 512,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 1280\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 512,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType12_sd2\",\n          \"x\": 512,\n          \"y\": 200,\n          \"w\": 512,\n          \"h\": 880\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 1024,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1024,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType13_sd3\",\n          \"x\": 824,\n          \"y\": 880,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1024,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 1024,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType15_sd1\",\n          \"x\": 512,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 1024,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType15_sd3\",\n          \"x\": 824,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType16_sd2\",\n          \"x\": 512,\n          \"y\": 640,\n          \"w\": 512,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType16_sd3\",\n          \"x\": 824,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType17_sd1\",\n          \"x\": 512,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType17_sd2\",\n          \"x\": 512,\n          \"y\": 768,\n          \"w\": 512,\n          \"h\": 512\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType17_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 512,\n          \"h\": 512\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType18_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 680,\n          \"h\": 420\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType18_sd2\",\n          \"x\": 400,\n          \"y\": 420,\n          \"w\": 680,\n          \"h\": 420\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType18_sd3\",\n          \"x\": 400,\n          \"y\": 840,\n          \"w\": 680,\n          \"h\": 440\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_1024x1280_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1024,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1024x1280_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 1024,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1024x1280_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1024x1280_screenType19_sd3\",\n          \"x\": 824,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1050x1680\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1050x1680_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 1680\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 1480\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 1050,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1050,\n          \"h\": 1480\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1680\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType3_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 650,\n          \"h\": 1680\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 650,\n          \"h\": 1680\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType4_sd1\",\n          \"x\": 650,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1680\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 840\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 840,\n          \"w\": 1050,\n          \"h\": 840\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 650,\n          \"h\": 1480\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType6_sd1\",\n          \"x\": 650,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1480\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 1050,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1480\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType7_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 650,\n          \"h\": 1480\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 1050,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1480\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType8_sd2\",\n          \"x\": 600,\n          \"y\": 200,\n          \"w\": 450,\n          \"h\": 1480\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 450,\n          \"h\": 1480\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType9_sd2\",\n          \"x\": 450,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1480\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 1680\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType10_sd1\",\n          \"x\": 525,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType10_sd2\",\n          \"x\": 525,\n          \"y\": 840,\n          \"w\": 525,\n          \"h\": 840\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 840,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType11_sd2\",\n          \"x\": 525,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 1680\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 525,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType12_sd2\",\n          \"x\": 525,\n          \"y\": 200,\n          \"w\": 525,\n          \"h\": 1280\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 1050,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1050,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType13_sd3\",\n          \"x\": 850,\n          \"y\": 1280,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1050,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 1050,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 1280,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType15_sd1\",\n          \"x\": 525,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 840,\n          \"w\": 1050,\n          \"h\": 840\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType15_sd3\",\n          \"x\": 850,\n          \"y\": 1480,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 840\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 840,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType16_sd2\",\n          \"x\": 525,\n          \"y\": 840,\n          \"w\": 525,\n          \"h\": 840\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType16_sd3\",\n          \"x\": 850,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 1680\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType17_sd1\",\n          \"x\": 525,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 1680\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType17_sd2\",\n          \"x\": 525,\n          \"y\": 1155,\n          \"w\": 525,\n          \"h\": 525\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType17_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 525\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 1680\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType18_sd1\",\n          \"x\": 525,\n          \"y\": 0,\n          \"w\": 525,\n          \"h\": 560\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType18_sd2\",\n          \"x\": 525,\n          \"y\": 560,\n          \"w\": 525,\n          \"h\": 560\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType18_sd3\",\n          \"x\": 525,\n          \"y\": 1120,\n          \"w\": 525,\n          \"h\": 560\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_1050x1680_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1050,\n          \"h\": 840\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1050x1680_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 840,\n          \"w\": 1050,\n          \"h\": 840\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1050x1680_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1480,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1050x1680_screenType19_sd3\",\n          \"x\": 850,\n          \"y\": 1480,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"900x1600\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_900x1600_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1600\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1400\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 1400\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 900,\n          \"h\": 1400\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1600\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1600\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1600\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType4_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1600\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 800,\n          \"w\": 900,\n          \"h\": 800\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1400\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType6_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1400\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1400\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType7_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1400\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1400\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType8_sd2\",\n          \"x\": 600,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1400\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1400\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType9_sd2\",\n          \"x\": 300,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1400\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1600\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType10_sd1\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType10_sd2\",\n          \"x\": 450,\n          \"y\": 800,\n          \"w\": 450,\n          \"h\": 800\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 800,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType11_sd2\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1600\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 450,\n          \"h\": 1200\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType12_sd2\",\n          \"x\": 450,\n          \"y\": 200,\n          \"w\": 450,\n          \"h\": 1200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 900,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 900,\n          \"h\": 1200\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType13_sd3\",\n          \"x\": 700,\n          \"y\": 1200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 900,\n          \"h\": 1200\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 900,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType13_sd3\",\n          \"x\": 0,\n          \"y\": 1200,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType15_sd1\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 800,\n          \"w\": 900,\n          \"h\": 800\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType15_sd3\",\n          \"x\": 700,\n          \"y\": 1400,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 800,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType16_sd2\",\n          \"x\": 450,\n          \"y\": 800,\n          \"w\": 450,\n          \"h\": 800\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType16_sd3\",\n          \"x\": 700,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1600\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType17_sd1\",\n          \"x\": 450,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 1600\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType17_sd2\",\n          \"x\": 450,\n          \"y\": 1150,\n          \"w\": 450,\n          \"h\": 450\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType17_sd3\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 450,\n          \"h\": 450\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1600\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType18_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 530\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType18_sd2\",\n          \"x\": 300,\n          \"y\": 530,\n          \"w\": 600,\n          \"h\": 530\n        },\n        \"sd3\": {\n          \"id\": \"vertical_900x1600_screenType18_sd3\",\n          \"x\": 300,\n          \"y\": 1060,\n          \"w\": 600,\n          \"h\": 540\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_900x1600_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 900,\n          \"h\": 800\n        },\n        \"sd1\": {\n          \"id\": \"vertical_900x1600_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 800,\n          \"w\": 900,\n          \"h\": 800\n        },\n        \"sd2\": {\n          \"id\": \"vertical_900x1600_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1400,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1200x1920\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1200x1920_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 1920\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 1720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1200,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1200,\n          \"h\": 1720\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType3_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 1920\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType4_sd1\",\n          \"x\": 800,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1920\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 1200,\n          \"h\": 960\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 1720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType6_sd1\",\n          \"x\": 800,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1200,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1720\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType7_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1200,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 1720\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType8_sd2\",\n          \"x\": 800,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 1720\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 400,\n          \"h\": 1720\n        },\n        \"sd12\": {\n          \"id\": \"vertical_1200x1920_screenType9_sd2\",\n          \"x\": 400,\n          \"y\": 200,\n          \"w\": 800,\n          \"h\": 1720\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType10_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType10_sd2\",\n          \"x\": 600,\n          \"y\": 960,\n          \"w\": 600,\n          \"h\": 960\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType11_sd2\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1920\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1520\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType12_sd2\",\n          \"x\": 600,\n          \"y\": 200,\n          \"w\": 600,\n          \"h\": 1520\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1200,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1200,\n          \"h\": 1520\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType13_sd3\",\n          \"x\": 1000,\n          \"y\": 1520,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1200,\n          \"h\": 1520\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 1200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 1520,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType15_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 1200,\n          \"h\": 960\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType15_sd3\",\n          \"x\": 1000,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType16_sd2\",\n          \"x\": 600,\n          \"y\": 960,\n          \"w\": 600,\n          \"h\": 960\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType16_sd3\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType17_sd1\",\n          \"x\": 600,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 1920\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 600,\n          \"h\": 600\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType17_sd3\",\n          \"x\": 600,\n          \"y\": 1320,\n          \"w\": 600,\n          \"h\": 600\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 400,\n          \"h\": 1920\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType18_sd1\",\n          \"x\": 400,\n          \"y\": 0,\n          \"w\": 800,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType18_sd2\",\n          \"x\": 400,\n          \"y\": 640,\n          \"w\": 800,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType18_sd3\",\n          \"x\": 400,\n          \"y\": 1280,\n          \"w\": 800,\n          \"h\": 640\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_1200x1920_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1200,\n          \"h\": 960\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1200x1920_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 960,\n          \"w\": 1200,\n          \"h\": 960\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1200x1920_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1200x1920_screenType19_sd3\",\n          \"x\": 1000,\n          \"y\": 1720,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"768x1024\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_768x1024_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 1024\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 768,\n          \"h\": 824\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 1024\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType4_sd1\",\n          \"x\": 468,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1024\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 768,\n          \"h\": 512\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType6_sd1\",\n          \"x\": 468,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 824\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType7_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 468,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType8_sd2\",\n          \"x\": 468,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 824\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 824\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType9_sd2\",\n          \"x\": 300,\n          \"y\": 200,\n          \"w\": 468,\n          \"h\": 824\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType10_sd1\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType10_sd2\",\n          \"x\": 384,\n          \"y\": 512,\n          \"w\": 384,\n          \"h\": 512\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType11_sd2\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1024\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 384,\n          \"h\": 624\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType12_sd2\",\n          \"x\": 384,\n          \"y\": 200,\n          \"w\": 384,\n          \"h\": 624\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 768,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 768,\n          \"h\": 624\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType13_sd3\",\n          \"x\": 568,\n          \"y\": 624,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 768,\n          \"h\": 624\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 768,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 624,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType15_sd1\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 768,\n          \"h\": 512\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType15_sd3\",\n          \"x\": 568,\n          \"y\": 824,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType16_sd2\",\n          \"x\": 384,\n          \"y\": 512,\n          \"w\": 384,\n          \"h\": 512\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType16_sd3\",\n          \"x\": 568,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType17_sd1\",\n          \"x\": 384,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 1024\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 384,\n          \"h\": 384\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType17_sd3\",\n          \"x\": 384,\n          \"y\": 640,\n          \"w\": 384,\n          \"h\": 384\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1024\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType18_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 468,\n          \"h\": 340\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType18_sd2\",\n          \"x\": 300,\n          \"y\": 340,\n          \"w\": 468,\n          \"h\": 340\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType18_sd3\",\n          \"x\": 300,\n          \"y\": 680,\n          \"w\": 468,\n          \"h\": 344\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_768x1024_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 768,\n          \"h\": 512\n        },\n        \"sd1\": {\n          \"id\": \"vertical_768x1024_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 512,\n          \"w\": 768,\n          \"h\": 512\n        },\n        \"sd2\": {\n          \"id\": \"vertical_768x1024_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 824,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_768x1024_screenType19_sd2\",\n          \"x\": 568,\n          \"y\": 824,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"720x1280\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_720x1280_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 1280\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 720,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 720,\n          \"h\": 1080\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType3_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1280\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType4_sd1\",\n          \"x\": 420,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1280\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 720,\n          \"h\": 640\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType6_sd1\",\n          \"x\": 420,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 720,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1080\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType7_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 720,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 420,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType8_sd2\",\n          \"x\": 420,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1080\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 300,\n          \"h\": 1080\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType9_sd2\",\n          \"x\": 300,\n          \"y\": 200,\n          \"w\": 420,\n          \"h\": 1080\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType10_sd1\",\n          \"x\": 360,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType10_sd2\",\n          \"x\": 360,\n          \"y\": 640,\n          \"w\": 360,\n          \"h\": 640\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType11_sd2\",\n          \"x\": 360,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 1280\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 360,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType12_sd2\",\n          \"x\": 360,\n          \"y\": 200,\n          \"w\": 360,\n          \"h\": 880\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 720,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 720,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType13_sd3\",\n          \"x\": 520,\n          \"y\": 880,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 720,\n          \"h\": 880\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 720,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 880,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType15_sd1\",\n          \"x\": 360,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 720,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType15_sd3\",\n          \"x\": 520,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType16_sd2\",\n          \"x\": 360,\n          \"y\": 640,\n          \"w\": 360,\n          \"h\": 640\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType16_sd3\",\n          \"x\": 520,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType17_sd1\",\n          \"x\": 360,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 360,\n          \"h\": 360\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType17_sd3\",\n          \"x\": 360,\n          \"y\": 920,\n          \"w\": 360,\n          \"h\": 360\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 300,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType18_sd1\",\n          \"x\": 300,\n          \"y\": 0,\n          \"w\": 420,\n          \"h\": 420\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType18_sd2\",\n          \"x\": 300,\n          \"y\": 420,\n          \"w\": 420,\n          \"h\": 420\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType18_sd3\",\n          \"x\": 300,\n          \"y\": 840,\n          \"w\": 420,\n          \"h\": 440\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_720x1280_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 640\n        },\n        \"sd1\": {\n          \"id\": \"vertical_720x1280_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 640,\n          \"w\": 720,\n          \"h\": 640\n        },\n        \"sd2\": {\n          \"id\": \"vertical_720x1280_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_720x1280_screenType19_sd3\",\n          \"x\": 520,\n          \"y\": 1080,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    },\n    \"1440x2560\": {\n      \"screenType0\": {\n        \"sd0\": {\n          \"id\": \"horizontal_1440x2560_screenType0_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 2560\n        }\n      },\n      \"screenType1\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType1_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 2360\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType1_sd1\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType2\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType2_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType2_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1440,\n          \"h\": 2360\n        }\n      },\n      \"screenType3\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType3_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 2560\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType3_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 2560\n        }\n      },\n      \"screenType4\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType4_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 2560\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType4_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 2560\n        }\n      },\n      \"screenType5\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType5_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType5_sd1\",\n          \"x\": 0,\n          \"y\": 1280,\n          \"w\": 1440,\n          \"h\": 1280\n        }\n      },\n      \"screenType6\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType6_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 2360\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType6_sd1\",\n          \"x\": 1000,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 2360\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType6_sd2\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType7\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType7_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 2360\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType7_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 2360\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType7_sd2\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType8\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType8_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType8_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1000,\n          \"h\": 2360\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType8_sd2\",\n          \"x\": 1000,\n          \"y\": 200,\n          \"w\": 440,\n          \"h\": 2360\n        }\n      },\n      \"screenType9\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType9_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType9_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 440,\n          \"h\": 2360\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType9_sd2\",\n          \"x\": 440,\n          \"y\": 200,\n          \"w\": 1000,\n          \"h\": 2360\n        }\n      },\n      \"screenType10\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType10_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 2560\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType10_sd1\",\n          \"x\": 720,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType10_sd2\",\n          \"x\": 720,\n          \"y\": 1280,\n          \"w\": 720,\n          \"h\": 1280\n        }\n      },\n      \"screenType11\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType11_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType11_sd1\",\n          \"x\": 0,\n          \"y\": 1280,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType11_sd2\",\n          \"x\": 720,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 2560\n        }\n      },\n      \"screenType12\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType12_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType12_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 720,\n          \"h\": 2160\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType12_sd2\",\n          \"x\": 720,\n          \"y\": 200,\n          \"w\": 720,\n          \"h\": 2160\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType12_sd3\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 1440,\n          \"h\": 200\n        }\n      },\n      \"screenType13\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType13_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType13_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1440,\n          \"h\": 2160\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType13_sd2\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType13_sd3\",\n          \"x\": 1240,\n          \"y\": 2160,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType14\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType14_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType14_sd1\",\n          \"x\": 0,\n          \"y\": 200,\n          \"w\": 1440,\n          \"h\": 2160\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType14_sd2\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 1440,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType14_sd3\",\n          \"x\": 0,\n          \"y\": 2160,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType15\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType15_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType15_sd1\",\n          \"x\": 720,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType15_sd2\",\n          \"x\": 0,\n          \"y\": 1280,\n          \"w\": 1440,\n          \"h\": 1280\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType15_sd3\",\n          \"x\": 1240,\n          \"y\": 2360,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType16\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType16_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType16_sd1\",\n          \"x\": 0,\n          \"y\": 1280,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType16_sd2\",\n          \"x\": 720,\n          \"y\": 1280,\n          \"w\": 720,\n          \"h\": 1280\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType16_sd3\",\n          \"x\": 1240,\n          \"y\": 0,\n          \"w\": 200,\n          \"h\": 200\n        }\n      },\n      \"screenType17\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType17_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 2560\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType17_sd1\",\n          \"x\": 720,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 2560\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType17_sd2\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 720,\n          \"h\": 720\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType17_sd3\",\n          \"x\": 720,\n          \"y\": 1840,\n          \"w\": 720,\n          \"h\": 720\n        }\n      },\n      \"screenType18\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType18_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 440,\n          \"h\": 2560\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType18_sd1\",\n          \"x\": 440,\n          \"y\": 0,\n          \"w\": 1000,\n          \"h\": 850\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType18_sd2\",\n          \"x\": 440,\n          \"y\": 850,\n          \"w\": 1000,\n          \"h\": 850\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType18_sd3\",\n          \"x\": 440,\n          \"y\": 1700,\n          \"w\": 1000,\n          \"h\": 860\n        }\n      },\n      \"screenType19\": {\n        \"sd0\": {\n          \"id\": \"vertical_1440x2560_screenType19_sd0\",\n          \"x\": 0,\n          \"y\": 0,\n          \"w\": 1440,\n          \"h\": 1280\n        },\n        \"sd1\": {\n          \"id\": \"vertical_1440x2560_screenType19_sd1\",\n          \"x\": 0,\n          \"y\": 1280,\n          \"w\": 1440,\n          \"h\": 1280\n        },\n        \"sd2\": {\n          \"id\": \"vertical_1440x2560_screenType19_sd2\",\n          \"x\": 0,\n          \"y\": 2360,\n          \"w\": 200,\n          \"h\": 200\n        },\n        \"sd3\": {\n          \"id\": \"vertical_1440x2560_screenType19_sd3\",\n          \"x\": 1240,\n          \"y\": 2360,\n          \"w\": 200,\n          \"h\": 200\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "src/libs/stop-watch/stop-watch.js",
    "content": "/*\n * Javascript Stopwatch class\n * http://www.seph.dk\n * http://www.seph.dk/blog/projects/javascript-stopwatch-class/\n *\n * Copyright 2009 Seph soliman\n * Released under the MIT license (do whatever you want - just leave my name on it)\n * http://opensource.org/licenses/MIT\n */\n\n// * Stopwatch class {{{\nStopwatch = function(listener, resolution) {\n    this.startTime = 0;\n    this.stopTime = 0;\n    this.totalElapsed = 0; // * elapsed number of ms in total\n    this.started = false;\n    this.listener = (listener != undefined ? listener : null); // * function to receive onTick events\n    this.tickResolution = (resolution != undefined ? resolution : 500); // * how long between each tick in milliseconds\n    this.tickInterval = null;\n\n    // * pretty static vars\n    this.onehour = 1000 * 60 * 60;\n    this.onemin  = 1000 * 60;\n    this.onesec  = 1000;\n}\nStopwatch.prototype.start = function() {\n    var delegate = function(that, method) { return function() { return method.call(that) } };\n    if(!this.started) {\n        this.startTime = new Date().getTime();\n        this.stopTime = 0;\n        this.started = true;\n        this.tickInterval = setInterval(delegate(this, this.onTick), this.tickResolution);\n    }\n}\nStopwatch.prototype.stop = function() {\n    if(this.started) {\n        this.stopTime = new Date().getTime();\n        this.started = false;\n        var elapsed = this.stopTime - this.startTime;\n        this.totalElapsed += elapsed;\n        if(this.tickInterval != null)\n            clearInterval(this.tickInterval);\n    }\n    return this.getElapsed();\n}\nStopwatch.prototype.reset = function() {\n    this.totalElapsed = 0;\n    // * if watch is running, reset it to current time\n    this.startTime = new Date().getTime();\n    this.stopTime = this.startTime;\n}\nStopwatch.prototype.restart = function() {\n    this.stop();\n    this.reset();\n    this.start();\n}\nStopwatch.prototype.getElapsed = function() {\n    // * if watch is stopped, use that date, else use now\n    var elapsed = 0;\n    if(this.started)\n        elapsed = new Date().getTime() - this.startTime;\n    elapsed += this.totalElapsed;\n\n    var hours = parseInt(elapsed / this.onehour);\n    elapsed %= this.onehour;\n    var mins = parseInt(elapsed / this.onemin);\n    elapsed %= this.onemin;\n    var secs = parseInt(elapsed / this.onesec);\n    var ms = elapsed % this.onesec;\n\n    return {\n        hours: hours,\n        minutes: mins,\n        seconds: secs,\n        milliseconds: ms\n    };\n}\nStopwatch.prototype.setElapsed = function(hours, mins, secs) {\n    this.reset();\n    this.totalElapsed = 0;\n    this.totalElapsed += hours * this.onehour;\n    this.totalElapsed += mins  * this.onemin;\n    this.totalElapsed += secs  * this.onesec;\n    this.totalElapsed = Math.max(this.totalElapsed, 0); // * No negative numbers\n}\nStopwatch.prototype.toString = function() {\n    var zpad = function(no, digits) {\n        no = no.toString();\n        while(no.length < digits)\n            no = '0' + no;\n        return no;\n    }\n    var e = this.getElapsed();\n    return zpad(e.hours,2) + \":\" + zpad(e.minutes,2) + \":\" + zpad(e.seconds,2);\n}\nStopwatch.prototype.setListener = function(listener) {\n    this.listener = listener;\n}\n// * triggered every <resolution> ms\nStopwatch.prototype.onTick = function() {\n    if(this.listener != null) {\n        this.listener(this);\n    }\n}\n// }}}"
  },
  {
    "path": "src/libs/xml2js/xml2js.js",
    "content": "/*\n Copyright 2011-2013 Abdulla Abdurakhmanov\n Original sources are available at https://code.google.com/p/x2js/\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n */\n\nfunction X2JS(config) {\n    'use strict';\n\n    var VERSION = \"1.1.3\";\n\n    config = config || {};\n    initConfigDefaults();\n\n    function initConfigDefaults() {\n        if(config.escapeMode === undefined) {\n            config.escapeMode = true;\n        }\n        config.attributePrefix = config.attributePrefix || \"_\";\n        config.arrayAccessForm = config.arrayAccessForm || \"none\";\n        config.emptyNodeForm = config.emptyNodeForm || \"text\";\n        if(config.enableToStringFunc === undefined) {\n            config.enableToStringFunc = true;\n        }\n        config.arrayAccessFormPaths = config.arrayAccessFormPaths || [];\n        if(config.skipEmptyTextNodesForObj === undefined) {\n            config.skipEmptyTextNodesForObj = true;\n        }\n    }\n\n    var DOMNodeTypes = {\n        ELEMENT_NODE \t   : 1,\n        TEXT_NODE    \t   : 3,\n        CDATA_SECTION_NODE : 4,\n        COMMENT_NODE\t   : 8,\n        DOCUMENT_NODE \t   : 9\n    };\n\n    function getNodeLocalName( node ) {\n        var nodeLocalName = node.localName;\n        if(nodeLocalName == null) // Yeah, this is IE!!\n            nodeLocalName = node.baseName;\n        if(nodeLocalName == null || nodeLocalName==\"\") // ==\"\" is IE too\n            nodeLocalName = node.nodeName;\n        return nodeLocalName;\n    }\n\n    function getNodePrefix(node) {\n        return node.prefix;\n    }\n\n    function escapeXmlChars(str) {\n        if(typeof(str) == \"string\")\n            return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\\//g, '&#x2F;');\n        else\n            return str;\n    }\n\n    function unescapeXmlChars(str) {\n        return str.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '\"').replace(/&#x27;/g, \"'\").replace(/&#x2F;/g, '\\/');\n    }\n\n    function toArrayAccessForm(obj, childName, path) {\n        switch(config.arrayAccessForm) {\n            case \"property\":\n                if(!(obj[childName] instanceof Array))\n                    obj[childName+\"_asArray\"] = [obj[childName]];\n                else\n                    obj[childName+\"_asArray\"] = obj[childName];\n                break;\n            /*case \"none\":\n                break;*/\n        }\n\n        if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) {\n            var idx = 0;\n            for(; idx < config.arrayAccessFormPaths.length; idx++) {\n                var arrayPath = config.arrayAccessFormPaths[idx];\n                if( typeof arrayPath === \"string\" ) {\n                    if(arrayPath == path)\n                        break;\n                }\n                else\n                if( arrayPath instanceof RegExp) {\n                    if(arrayPath.test(path))\n                        break;\n                }\n                else\n                if( typeof arrayPath === \"function\") {\n                    if(arrayPath(obj, childName, path))\n                        break;\n                }\n            }\n            if(idx!=config.arrayAccessFormPaths.length) {\n                obj[childName] = [obj[childName]];\n            }\n        }\n    }\n\n    function parseDOMChildren( node, path ) {\n        if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) {\n            var result = new Object;\n            var nodeChildren = node.childNodes;\n            // Alternative for firstElementChild which is not supported in some environments\n            for(var cidx=0; cidx <nodeChildren.length; cidx++) {\n                var child = nodeChildren.item(cidx);\n                if(child.nodeType == DOMNodeTypes.ELEMENT_NODE) {\n                    var childName = getNodeLocalName(child);\n                    result[childName] = parseDOMChildren(child, childName);\n                }\n            }\n            return result;\n        }\n        else\n        if(node.nodeType == DOMNodeTypes.ELEMENT_NODE) {\n            var result = new Object;\n            result.__cnt=0;\n\n            var nodeChildren = node.childNodes;\n\n            // Children nodes\n            for(var cidx=0; cidx <nodeChildren.length; cidx++) {\n                var child = nodeChildren.item(cidx); // nodeChildren[cidx];\n                var childName = getNodeLocalName(child);\n\n                if(child.nodeType!= DOMNodeTypes.COMMENT_NODE) {\n                    result.__cnt++;\n                    if(result[childName] == null) {\n                        result[childName] = parseDOMChildren(child, path+\".\"+childName);\n                        toArrayAccessForm(result, childName, path+\".\"+childName);\n                    }\n                    else {\n                        if(result[childName] != null) {\n                            if( !(result[childName] instanceof Array)) {\n                                result[childName] = [result[childName]];\n                                toArrayAccessForm(result, childName, path+\".\"+childName);\n                            }\n                        }\n                        (result[childName])[result[childName].length] = parseDOMChildren(child, path+\".\"+childName);\n                    }\n                }\n            }\n\n            // Attributes\n            for(var aidx=0; aidx <node.attributes.length; aidx++) {\n                var attr = node.attributes.item(aidx); // [aidx];\n                result.__cnt++;\n                result[config.attributePrefix+attr.name]=attr.value;\n            }\n\n            // Node namespace prefix\n            var nodePrefix = getNodePrefix(node);\n            if(nodePrefix!=null && nodePrefix!=\"\") {\n                result.__cnt++;\n                result.__prefix=nodePrefix;\n            }\n\n            if(result[\"#text\"]!=null) {\n                result.__text = result[\"#text\"];\n                if(result.__text instanceof Array) {\n                    result.__text = result.__text.join(\"\\n\");\n                }\n                if(config.escapeMode)\n                    result.__text = unescapeXmlChars(result.__text);\n                delete result[\"#text\"];\n                if(config.arrayAccessForm==\"property\")\n                    delete result[\"#text_asArray\"];\n            }\n            if(result[\"#cdata-section\"]!=null) {\n                result.__cdata = result[\"#cdata-section\"];\n                delete result[\"#cdata-section\"];\n                if(config.arrayAccessForm==\"property\")\n                    delete result[\"#cdata-section_asArray\"];\n            }\n\n            if( result.__cnt == 1 && result.__text!=null  ) {\n                result = result.__text;\n            }\n            else\n            if( result.__cnt == 0 && config.emptyNodeForm==\"text\" ) {\n                result = '';\n            }\n            else\n            if ( result.__cnt > 1 && result.__text!=null && config.skipEmptyTextNodesForObj) {\n                if(result.__text.trim()==\"\") {\n                    delete result.__text;\n                }\n            }\n            delete result.__cnt;\n\n            if( config.enableToStringFunc && result.__text!=null || result.__cdata!=null ) {\n                result.toString = function() {\n                    return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:'');\n                };\n            }\n            return result;\n        }\n        else\n        if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) {\n            return node.nodeValue;\n        }\n    }\n\n    function startTag(jsonObj, element, attrList, closed) {\n        var resultStr = \"<\"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+\":\"):\"\") + element;\n        if(attrList!=null) {\n            for(var aidx = 0; aidx < attrList.length; aidx++) {\n                var attrName = attrList[aidx];\n                var attrVal = jsonObj[attrName];\n                resultStr+=\" \"+attrName.substr(config.attributePrefix.length)+\"='\"+attrVal+\"'\";\n            }\n        }\n        if(!closed)\n            resultStr+=\">\";\n        else\n            resultStr+=\"/>\";\n        return resultStr;\n    }\n\n    function endTag(jsonObj,elementName) {\n        return \"</\"+ (jsonObj.__prefix!=null? (jsonObj.__prefix+\":\"):\"\")+elementName+\">\";\n    }\n\n    function endsWith(str, suffix) {\n        return str.indexOf(suffix, str.length - suffix.length) !== -1;\n    }\n\n    function jsonXmlSpecialElem ( jsonObj, jsonObjField ) {\n        if((config.arrayAccessForm==\"property\" && endsWith(jsonObjField.toString(),(\"_asArray\")))\n            || jsonObjField.toString().indexOf(config.attributePrefix)==0\n            || jsonObjField.toString().indexOf(\"__\")==0\n            || (jsonObj[jsonObjField] instanceof Function) )\n            return true;\n        else\n            return false;\n    }\n\n    function jsonXmlElemCount ( jsonObj ) {\n        var elementsCnt = 0;\n        if(jsonObj instanceof Object ) {\n            for( var it in jsonObj  ) {\n                if(jsonXmlSpecialElem ( jsonObj, it) )\n                    continue;\n                elementsCnt++;\n            }\n        }\n        return elementsCnt;\n    }\n\n    function parseJSONAttributes ( jsonObj ) {\n        var attrList = [];\n        if(jsonObj instanceof Object ) {\n            for( var ait in jsonObj  ) {\n                if(ait.toString().indexOf(\"__\")== -1 && ait.toString().indexOf(config.attributePrefix)==0) {\n                    attrList.push(ait);\n                }\n            }\n        }\n        return attrList;\n    }\n\n    function parseJSONTextAttrs ( jsonTxtObj ) {\n        var result =\"\";\n\n        if(jsonTxtObj.__cdata!=null) {\n            result+=\"<![CDATA[\"+jsonTxtObj.__cdata+\"]]>\";\n        }\n\n        if(jsonTxtObj.__text!=null) {\n            if(config.escapeMode)\n                result+=escapeXmlChars(jsonTxtObj.__text);\n            else\n                result+=jsonTxtObj.__text;\n        }\n        return result;\n    }\n\n    function parseJSONTextObject ( jsonTxtObj ) {\n        var result =\"\";\n\n        if( jsonTxtObj instanceof Object ) {\n            result+=parseJSONTextAttrs ( jsonTxtObj );\n        }\n        else\n        if(jsonTxtObj!=null) {\n            if(config.escapeMode)\n                result+=escapeXmlChars(jsonTxtObj);\n            else\n                result+=jsonTxtObj;\n        }\n\n        return result;\n    }\n\n    function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList ) {\n        var result = \"\";\n        if(jsonArrRoot.length == 0) {\n            result+=startTag(jsonArrRoot, jsonArrObj, attrList, true);\n        }\n        else {\n            for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) {\n                result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false);\n                result+=parseJSONObject(jsonArrRoot[arIdx]);\n                result+=endTag(jsonArrRoot[arIdx],jsonArrObj);\n            }\n        }\n        return result;\n    }\n\n    function parseJSONObject ( jsonObj ) {\n        var result = \"\";\n\n        var elementsCnt = jsonXmlElemCount ( jsonObj );\n\n        if(elementsCnt > 0) {\n            for( var it in jsonObj ) {\n\n                if(jsonXmlSpecialElem ( jsonObj, it) )\n                    continue;\n\n                var subObj = jsonObj[it];\n\n                var attrList = parseJSONAttributes( subObj )\n\n                if(subObj == null || subObj == undefined) {\n                    result+=startTag(subObj, it, attrList, true);\n                }\n                else\n                if(subObj instanceof Object) {\n\n                    if(subObj instanceof Array) {\n                        result+=parseJSONArray( subObj, it, attrList );\n                    }\n                    else {\n                        var subObjElementsCnt = jsonXmlElemCount ( subObj );\n                        if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) {\n                            result+=startTag(subObj, it, attrList, false);\n                            result+=parseJSONObject(subObj);\n                            result+=endTag(subObj,it);\n                        }\n                        else {\n                            result+=startTag(subObj, it, attrList, true);\n                        }\n                    }\n                }\n                else {\n                    result+=startTag(subObj, it, attrList, false);\n                    result+=parseJSONTextObject(subObj);\n                    result+=endTag(subObj,it);\n                }\n            }\n        }\n        result+=parseJSONTextObject(jsonObj);\n\n        return result;\n    }\n\n    this.parseXmlString = function(xmlDocStr) {\n        if (xmlDocStr === undefined) {\n            return null;\n        }\n        var xmlDoc;\n        if (window.DOMParser) {\n            var parser=new window.DOMParser();\n            xmlDoc = parser.parseFromString( xmlDocStr, \"text/xml\" );\n        }\n        else {\n            // IE :(\n            if(xmlDocStr.indexOf(\"<?\")==0) {\n                xmlDocStr = xmlDocStr.substr( xmlDocStr.indexOf(\"?>\") + 2 );\n            }\n            xmlDoc=new ActiveXObject(\"Microsoft.XMLDOM\");\n            xmlDoc.async=\"false\";\n            xmlDoc.loadXML(xmlDocStr);\n        }\n        return xmlDoc;\n    };\n\n    this.asArray = function(prop) {\n        if(prop instanceof Array)\n            return prop;\n        else\n            return [prop];\n    }\n\n    this.xml2json = function (xmlDoc) {\n        return parseDOMChildren ( xmlDoc );\n    };\n\n    this.xml_str2json = function (xmlDocStr) {\n        var xmlDoc = this.parseXmlString(xmlDocStr);\n        return this.xml2json(xmlDoc);\n    };\n\n    this.json2xml_str = function (jsonObj) {\n        return parseJSONObject ( jsonObj );\n    };\n\n    this.json2xml = function (jsonObj) {\n        var xmlDocStr = this.json2xml_str (jsonObj);\n        return this.parseXmlString(xmlDocStr);\n    };\n\n    this.getVersion = function () {\n        return VERSION;\n    };\n\n}"
  },
  {
    "path": "src/locale/ar.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"ar\">\n\t<translation id=\"9198441993514322349\">اتجاه الشاشة</translation>\n\t<translation id=\"2838690440296896849\">الوضع عن بعد</translation>\n\t<translation id=\"2849064100927111571\">جار التحميل...</translation>\n\t<translation id=\"7309719557896597512\">أتمنى لك نهارا سعيد</translation>\n\t<translation id=\"5805758016483237261\">الترقية إلى المؤسسة - 99،00 $ شهريا</translation>\n\t<translation id=\"7212624462478696127\">التحقق من وصول ...</translation>\n\t<translation id=\"1156206314346372426\">لوحة حساب</translation>\n\t<translation id=\"892759319569190037\">لون خلفية المشهد</translation>\n\t<translation id=\"463077023711449502\">لون الحدود</translation>\n\t<translation id=\"7844431484369877777\">رابط</translation>\n\t<translation id=\"6727478076005438064\">اختيار شكل</translation>\n\t<translation id=\"8932917860978648376\">وحدة</translation>\n\t<translation id=\"6447113917741810043\">فهرنهايت</translation>\n\t<translation id=\"1546647220090341106\">درجة مئوية</translation>\n\t<translation id=\"6977749640368501596\">الأنماط</translation>\n\t<translation id=\"30300572504753589\">أسود</translation>\n\t<translation id=\"7850674593676755019\">أبيض</translation>\n\t<translation id=\"9011959596901584887\">اللون</translation>\n\t<translation id=\"5667922561719642173\">الحمل مع المشهد</translation>\n\t<translation id=\"5466334165625502718\">فترة</translation>\n\t<translation id=\"1128028236258747485\">تشغيل الفيديو على الانتهاء</translation>\n\t<translation id=\"3372777815572567783\">تشغيل عشوائي</translation>\n\t<translation id=\"6757770085960264448\">عرض الشرائح</translation>\n\t<translation id=\"6659445582099947212\">رمز</translation>\n\t<translation id=\"6262368721870308838\">إنشاء رمز وصول الانستقرام</translation>\n\t<translation id=\"6358635099770142731\">إنشاء رمز</translation>\n\t<translation id=\"7499211462525828161\">الحمل مع تقويم</translation>\n\t<translation id=\"3128474301651540051\">تعويض وضع مجموعة</translation>\n\t<translation id=\"5645011507444946232\">قبل أيام اليوم</translation>\n\t<translation id=\"472347571959391022\">بعد أيام اليوم</translation>\n\t<translation id=\"7382546590159708114\">تاريخ البدء</translation>\n\t<translation id=\"8615958092383580706\">تاريخ الانتهاء</translation>\n\t<translation id=\"7824071976623180870\">الحمل مع ورقة</translation>\n\t<translation id=\"4370305429271412983\">الاسم الذي سيظهر</translation>\n\t<translation id=\"7641098557273120361\">إنشاء رمز وصول</translation>\n\t<translation id=\"361150460746746781\">الحفاظ على نسبة الارتفاع</translation>\n\t<translation id=\"3046991000485970172\">RSS تحديث (دقيقة)</translation>\n\t<translation id=\"2303401327609002516\">RSS الاتجاه التمرير</translation>\n\t<translation id=\"8382375758916799432\">أفقي</translation>\n\t<translation id=\"160958144287367985\">عمودي</translation>\n\t<translation id=\"5576694760844259892\">RSS سرعة التمرير</translation>\n\t<translation id=\"3801245379625272309\">بطيء</translation>\n\t<translation id=\"4688460977394283086\">متوسط</translation>\n\t<translation id=\"9161614188045173336\">بسرعة</translation>\n\t<translation id=\"6107231410782382609\">على الحدث اتخاذ الإجراءات التالية</translation>\n\t<translation id=\"8875363048655701399\">وضع كشك</translation>\n\t<translation id=\"6880124786888445040\">تلعب مجموعة في تسلسل</translation>\n\t<translation id=\"2166463051767640100\">إضافة محتوى لمجموعة</translation>\n\t<translation id=\"7365517136074263312\">رمز الاستجابة السريعة</translation>\n\t<translation id=\"810733191089543608\">الصوت</translation>\n\t<translation id=\"4815249204085613710\">جودة الفيديو</translation>\n\t<translation id=\"5082095396043563283\">منطقة</translation>\n\t<translation id=\"396267502411280310\">الأكثر مشاهدة</translation>\n\t<translation id=\"2441920677226386245\">قائمة مخصصة</translation>\n\t<translation id=\"1223194855937061908\">معرفات فيديو</translation>\n\t<translation id=\"4103549354606724944\">خطوط العملاء</translation>\n\t<translation id=\"7262144878230347914\">لون الخلفية</translation>\n\t<translation id=\"1435085881129646880\">قائمة التشغيل متتابعة افتراضي</translation>\n\t<translation id=\"1587536276491357593\">إجمالي الموقع بناء:></translation>\n\t<translation id=\"3325180562659478330\">اسم</translation>\n\t<translation id=\"3051480550159545291\">خط العرض</translation>\n\t<translation id=\"2703718513716530782\">خط الطول</translation>\n\t<translation id=\"5602245631444655788\">المدة الزمنية</translation>\n\t<translation id=\"118487254857410201\">مجموعة دائرة نصف قطرها</translation>\n\t<translation id=\"9178543898761255307\">كم</translation>\n\t<translation id=\"7866202877490561957\">أولوية الصراع</translation>\n\t<translation id=\"720146333131008909\">إضافة محتوى إلى موقع الحادث</translation>\n\t<translation id=\"8729372534532732068\">اسم المشهد</translation>\n\t<translation id=\"2224690894219674949\">وضع المحاكاة</translation>\n\t<translation id=\"7220335122322620944\">معرفة المزيد عن المؤسسة</translation>\n\t<translation id=\"8444323300278462770\">أعلى</translation>\n\t<translation id=\"7449548947549758066\">اليسار</translation>\n\t<translation id=\"9172672254266086971\">عرض</translation>\n\t<translation id=\"4093381701787958997\">ارتفاع</translation>\n\t<translation id=\"2062170564010556149\">دوران</translation>\n\t<translation id=\"9088937454320275395\">تطبيق التغييرات</translation>\n\t<translation id=\"1870560040946711505\">مقفل</translation>\n\t<translation id=\"6108618462851148193\">محرر الحملة</translation>\n\t<translation id=\"2741646832903808697\">تخطيط الشاشة</translation>\n\t<translation id=\"6454444033973204385\">اختيار حملة</translation>\n\t<translation id=\"6028894272398949430\">حملة جديدة</translation>\n\t<translation id=\"3008329758802399315\">الحصول على معالج مساعدة</translation>\n\t<translation id=\"4145364267099301397\">اختر اسم حملتك</translation>\n\t<translation id=\"3843469504048287640\">أدخل اسم الحملة الجديدة</translation>\n\t<translation id=\"4895430942430831092\">معرف الحملة:</translation>\n\t<translation id=\"1901427837939428954\">وضع كشك</translation>\n\t<translation id=\"8329228391349300722\">حملة وضع تشغيل الموسيقى:</translation>\n\t<translation id=\"8793145092368811184\">التسلسل (الوضع البسيط):</translation>\n\t<translation id=\"4691632839818550461\">لعب الجداول الزمنية لهذه الحملة في حلقة مستمرة. فمن السهل أن الإعداد وسهل الاستخدام</translation>\n\t<translation id=\"6075423017399759230\">جدولة (الوضع المتقدم):</translation>\n\t<translation id=\"750837672459228230\">لعب الجداول الزمنية لهذه الحملة فقط على أوقات محددة. على سبيل المثال، تلعب الجدول الزمني (أ) في الصباح والجدول الزمني B في الليل.</translation>\n\t<translation id=\"1167977099462453641\">دقة الشاشة</translation>\n\t<translation id=\"7626905534069326448\">أولوية الصراع:</translation>\n\t<translation id=\"4220765745195024064\">المدة الزمنية:</translation>\n\t<translation id=\"4049333306580215724\">لعب مرة واحدة</translation>\n\t<translation id=\"7249155645987524413\">لعب يوميا</translation>\n\t<translation id=\"8568181330490588741\">لعب أسبوعيا</translation>\n\t<translation id=\"3408786538616090951\">حدد يوما:</translation>\n\t<translation id=\"6324587259626414962\">تكرار لتناسب</translation>\n\t<translation id=\"2012264763266897754\">ترتيب عشوائي</translation>\n\t<translation id=\"4324819244706823449\">تحرير تخطيط</translation>\n\t<translation id=\"5755245564638965488\">قناة المقبل</translation>\n\t<translation id=\"2925036210758384238\">الخط المحدد</translation>\n\t<translation id=\"3601209751322374737\">تذكير قبل الناس</translation>\n\t<translation id=\"1790884679999452685\">محطة المفتوحة</translation>\n\t<translation id=\"4878432943521432749\">خط إعادة تعيين</translation>\n\t<translation id=\"3728601907282119753\">خصائص قائمة الانتظار</translation>\n\t<translation id=\"2536017892630886700\">العملاء المختارة:</translation>\n\t<translation id=\"6228967158577655533\">التحقق:</translation>\n\t<translation id=\"6435015929996679472\">ودعا من قبل:</translation>\n\t<translation id=\"8711852116268389728\">اختيار المشهد</translation>\n\t<translation id=\"5053705054681686956\">خط جديد</translation>\n\t<translation id=\"5225640858395745699\">إزالة خط</translation>\n\t<translation id=\"3116266439138367996\">الروابط</translation>\n\t<translation id=\"4159874591284333337\">مدعوم من إطار الزاوي جوجل</translation>\n\t<translation id=\"3008186756887926107\">تحميل الملفات</translation>\n\t<translation id=\"2123171795960509943\">إزالة</translation>\n\t<translation id=\"7246196759043272468\">قائمة</translation>\n\t<translation id=\"946077791002604877\">شبكة</translation>\n\t<translation id=\"5936943188558553659\">الملفات المدعومة: flv، mp4، JPG، PNG، فرنك سويسري و SVG</translation>\n\t<translation id=\"8054250976557949996\">مشهد جديد</translation>\n\t<translation id=\"6133338617402043535\">مكرر</translation>\n\t<translation id=\"1576591662761177526\">قالب استيراد</translation>\n\t<translation id=\"2225048990372533999\">إعادة تحميل</translation>\n\t<translation id=\"987425828725037788\">عنوان بروتوكول الإنترنت</translation>\n\t<translation id=\"1646067470190508925\">ميناء</translation>\n\n\t<translation id=\"8097415329769247281\">اختر الباقة التي تناسبك</translation>\n\n\t<translation id=\"6570363013146073520\">لوحة القيادة</translation>\n\t<translation id=\"8864658120410603626\">حملات</translation>\n\t<translation id=\"2446117790692479672\">موارد</translation>\n\t<translation id=\"794120057687191331\">مشاهد</translation>\n\t<translation id=\"4846792506513649213\">محطات</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">مساعدة</translation>\n\t<translation id=\"6082171864197428613\">التثبت</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">الخروج</translation>\n\t<translation id=\"7746065369460476808\">اسم المستخدم أو البريد الالكتروني</translation>\n\t<translation id=\"4809196861118879526\">كلمه السر</translation>\n\t<translation id=\"9162857816822524614\">إدخال اثنين مفتاح عامل</translation>\n\t<translation id=\"24227595514967590\">مع أداة مصادقة Google</translation>\n\t<translation id=\"2001940299854753031\">تذكرنى</translation>\n\t<translation id=\"5872337092278414963\">هل نسيت كلمة المرور</translation>\n\t<translation id=\"8246600873004586882\">تغيير كلمة السر</translation>\n\t<translation id=\"5289326240092186479\">اسم الشركة تغيير</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">كلمة المرور القديمة</translation>\n\t<translation id=\"48285893667252664\">كلمة السر الجديدة</translation>\n\t<translation id=\"6917932917401642982\">كلمة مرور جديدة تكرار</translation>\n\t<translation id=\"5666893431176348635\">اسم الشركة الجديد</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">تطوير</translation>\n\t<translation id=\"8894542476475088437\">حساب-S</translation>\n\t<translation id=\"2347724151568473592\">لغة</translation>\n\t<translation id=\"4376434433661751094\">دردشة مباشرة</translation>\n\t<translation id=\"5344752701442428839\">موقع الكتروني</translation>\n\t<translation id=\"7108535247064136881\">اختر لغتك</translation>\n\t<translation id=\"4137049537431219133\">تسجيل الدخول إلى حسابك مع مصادقة جوجل</translation>\n\t<translation id=\"4785021168351486737\">حفظ و الخروج</translation>\n\t<translation id=\"6524180701596149125\">مجرد تسجيل الخروج</translation>\n\n\t<translation id=\"2503331336991669578\">تسجيل الدخول إلى حسابك</translation>\n\t<translation id=\"8359621426539146583\">ليس لديك حساب</translation>\n\t<translation id=\"569785428576811345\">المدة الزمنية:</translation>\n\t<translation id=\"9043806075514219833\">وقت البدء:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/be.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"be\">\n\t<translation id=\"9198441993514322349\">арыентацыя экрана</translation>\n\t<translation id=\"2838690440296896849\">аддалены статус</translation>\n\t<translation id=\"2849064100927111571\">загрузка ...</translation>\n\t<translation id=\"7309719557896597512\">добрага дня</translation>\n\t<translation id=\"5805758016483237261\">Абнаўленне да Enterprise - $ 99,00 у месяц</translation>\n\t<translation id=\"7212624462478696127\">Праверка доступу ...</translation>\n\t<translation id=\"1156206314346372426\">кошт прыборнай панэлі</translation>\n\t<translation id=\"892759319569190037\">колер сцэны фон</translation>\n\t<translation id=\"463077023711449502\">які вылучае колер</translation>\n\t<translation id=\"7844431484369877777\">URL</translation>\n\t<translation id=\"6727478076005438064\">выберыце фармат</translation>\n\t<translation id=\"8932917860978648376\">блок</translation>\n\t<translation id=\"6447113917741810043\">Фарэнгейт</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">стылі</translation>\n\t<translation id=\"30300572504753589\">чорны</translation>\n\t<translation id=\"7850674593676755019\">белы</translation>\n\t<translation id=\"9011959596901584887\">колер</translation>\n\t<translation id=\"5667922561719642173\">Нагрузка на сцэне</translation>\n\t<translation id=\"5466334165625502718\">інтэрвал</translation>\n\t<translation id=\"1128028236258747485\">прайгравання відэа да завяршэння</translation>\n\t<translation id=\"3372777815572567783\">прайграванне ў выпадковым парадку</translation>\n\t<translation id=\"6757770085960264448\">слайд-шоў</translation>\n\t<translation id=\"6659445582099947212\">знак</translation>\n\t<translation id=\"6262368721870308838\">стварыць маркер доступу Instagram</translation>\n\t<translation id=\"6358635099770142731\">стварыць маркер</translation>\n\t<translation id=\"7499211462525828161\">Нагрузка з календаром</translation>\n\t<translation id=\"3128474301651540051\">Зрушэнне рэжыму дыяпазону</translation>\n\t<translation id=\"5645011507444946232\">дзён да сённяшняга дня</translation>\n\t<translation id=\"472347571959391022\">дзён пасля таго, як сёння</translation>\n\t<translation id=\"7382546590159708114\">дата пачатку</translation>\n\t<translation id=\"8615958092383580706\">дата заканчэння</translation>\n\t<translation id=\"7824071976623180870\">Нагрузка з лістом</translation>\n\t<translation id=\"4370305429271412983\">імя экрана</translation>\n\t<translation id=\"7641098557273120361\">стварыць маркер доступу</translation>\n\t<translation id=\"361150460746746781\">падтрымліваць суадносіны бакоў</translation>\n\t<translation id=\"3046991000485970172\">RSS абнаўлення (у хвілінах)</translation>\n\t<translation id=\"2303401327609002516\">RSS кірунак пракруткі</translation>\n\t<translation id=\"8382375758916799432\">гарызантальны</translation>\n\t<translation id=\"160958144287367985\">вертыкальны</translation>\n\t<translation id=\"5576694760844259892\">RSS хуткасць прагорткі</translation>\n\t<translation id=\"3801245379625272309\">павольна</translation>\n\t<translation id=\"4688460977394283086\">серада</translation>\n\t<translation id=\"9161614188045173336\">хутка</translation>\n\t<translation id=\"6107231410782382609\">У выпадку прыняць наступныя меры</translation>\n\t<translation id=\"8875363048655701399\">рэжым кіёска</translation>\n\t<translation id=\"6880124786888445040\">Гуляць калекцыю ў паслядоўнасці</translation>\n\t<translation id=\"2166463051767640100\">дадаць змесціва ў калекцыю</translation>\n\t<translation id=\"7365517136074263312\">QR-код</translation>\n\t<translation id=\"810733191089543608\">аб'ём</translation>\n\t<translation id=\"4815249204085613710\">якасць відэа</translation>\n\t<translation id=\"5082095396043563283\">вобласць</translation>\n\t<translation id=\"396267502411280310\">найбольш прагледжваемыя</translation>\n\t<translation id=\"2441920677226386245\">карыстацкі спіс</translation>\n\t<translation id=\"1223194855937061908\">ідэнтыфікатары відэа</translation>\n\t<translation id=\"4103549354606724944\">лініі кліентаў</translation>\n\t<translation id=\"7262144878230347914\">колер фону</translation>\n\t<translation id=\"1435085881129646880\">Па змаўчанні паслядоўны плэйліст</translation>\n\t<translation id=\"1587536276491357593\">Агульнае размяшчэнне на аснове:></translation>\n\t<translation id=\"3325180562659478330\">імя</translation>\n\t<translation id=\"3051480550159545291\">шырата</translation>\n\t<translation id=\"2703718513716530782\">даўгата</translation>\n\t<translation id=\"5602245631444655788\">працягласць</translation>\n\t<translation id=\"118487254857410201\">дыяпазон радыус</translation>\n\t<translation id=\"9178543898761255307\">кіламетраў</translation>\n\t<translation id=\"7866202877490561957\">калізія прыярытэтаў</translation>\n\t<translation id=\"720146333131008909\">дадаць змесціва ў сцэне</translation>\n\t<translation id=\"8729372534532732068\">назву сцэны</translation>\n\t<translation id=\"2224690894219674949\">рэжым мадэлявання</translation>\n\t<translation id=\"7220335122322620944\">Больш падрабязна аб прадпрыемстве</translation>\n\t<translation id=\"8444323300278462770\">топ</translation>\n\t<translation id=\"7449548947549758066\">злева</translation>\n\t<translation id=\"9172672254266086971\">шырыня</translation>\n\t<translation id=\"4093381701787958997\">вышыня</translation>\n\t<translation id=\"2062170564010556149\">кручэнне</translation>\n\t<translation id=\"9088937454320275395\">прымяніць змены</translation>\n\t<translation id=\"1870560040946711505\">зачынены</translation>\n\t<translation id=\"6108618462851148193\">рэдактар ​​кампаніі</translation>\n\t<translation id=\"2741646832903808697\">размяшчэнне экрана</translation>\n\t<translation id=\"6454444033973204385\">выбар кампаніі</translation>\n\t<translation id=\"6028894272398949430\">новая кампанія</translation>\n\t<translation id=\"3008329758802399315\">Атрымаць майстар дапамогу</translation>\n\t<translation id=\"4145364267099301397\">Выберыце назву кампаніі</translation>\n\t<translation id=\"3843469504048287640\">Калі ласка, увядзіце новую назву кампаніі</translation>\n\t<translation id=\"4895430942430831092\">Ідэнтыфікатар кампаніі:</translation>\n\t<translation id=\"1901427837939428954\">рэжым кіёска</translation>\n\t<translation id=\"8329228391349300722\">Кампанія рэжыму прайгравання:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (просты рэжым):</translation>\n\t<translation id=\"4691632839818550461\">Гуляць часовыя рамкі для гэтай кампаніі ў бесперапынным цыкле. Ён просты ва ўсталёўцы і просты ў выкарыстанні</translation>\n\t<translation id=\"6075423017399759230\">Планавальнік (дасведчаным):</translation>\n\t<translation id=\"750837672459228230\">Гуляць часовыя рамкі для гэтай кампаніі толькі ў пэўныя моманты часу. Напрыклад, гуляць Timeline А раніцай і Timeline B ў начны час.</translation>\n\t<translation id=\"1167977099462453641\">дазвол экрана</translation>\n\t<translation id=\"7626905534069326448\">Прыярытэт Conflict:</translation>\n\t<translation id=\"4220765745195024064\">працягласць:</translation>\n\t<translation id=\"4049333306580215724\">гуляць адзін раз</translation>\n\t<translation id=\"7249155645987524413\">гуляць штодня</translation>\n\t<translation id=\"8568181330490588741\">гуляць у тыдзень</translation>\n\t<translation id=\"3408786538616090951\">Выберыце дні:</translation>\n\t<translation id=\"6324587259626414962\">Паўтараю, каб адпавядаць</translation>\n\t<translation id=\"2012264763266897754\">ў выпадковым парадку</translation>\n\t<translation id=\"4324819244706823449\">рэдагаваць макет</translation>\n\t<translation id=\"5755245564638965488\">наступны канал</translation>\n\t<translation id=\"2925036210758384238\">абраная лінія</translation>\n\t<translation id=\"3601209751322374737\">напамін перад людзьмі</translation>\n\t<translation id=\"1790884679999452685\">адкрыты тэрмінал</translation>\n\t<translation id=\"4878432943521432749\">скід лініі</translation>\n\t<translation id=\"3728601907282119753\">ўласцівасці чарзе</translation>\n\t<translation id=\"2536017892630886700\">абраны кліентам:</translation>\n\t<translation id=\"6228967158577655533\">праверка:</translation>\n\t<translation id=\"6435015929996679472\">завуць:</translation>\n\t<translation id=\"8711852116268389728\">выбар сцэны</translation>\n\t<translation id=\"5053705054681686956\">новая радок</translation>\n\t<translation id=\"5225640858395745699\">выдаліць радок</translation>\n\t<translation id=\"3116266439138367996\">сувязі</translation>\n\t<translation id=\"4159874591284333337\">Працуе на вуглавымі рамках кампаніі Google</translation>\n\t<translation id=\"3008186756887926107\">загружаць файлы</translation>\n\t<translation id=\"2123171795960509943\">выдаленне</translation>\n\t<translation id=\"7246196759043272468\">спіс</translation>\n\t<translation id=\"946077791002604877\">сетка</translation>\n\t<translation id=\"5936943188558553659\">Падтрымліваюцца файлы: FLV, MP4, JPG, PNG, SWF і SVG</translation>\n\t<translation id=\"8054250976557949996\">новая сцэна</translation>\n\t<translation id=\"6133338617402043535\">дубляваць</translation>\n\t<translation id=\"1576591662761177526\">шаблон імпарту</translation>\n\t<translation id=\"2225048990372533999\">перазагружаць</translation>\n\t<translation id=\"987425828725037788\">IP-адрас</translation>\n\t<translation id=\"1646067470190508925\">порт</translation>\n\n\t<translation id=\"8097415329769247281\">Абярыце пакет, які падыходзіць для вас</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/bn.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"bn\">\n\t<translation id=\"9198441993514322349\">পর্দা স্থিতিবিন্যাস</translation>\n\t<translation id=\"2838690440296896849\">দূরবর্তী অবস্থা</translation>\n\t<translation id=\"2849064100927111571\">লোড হচ্ছে ...</translation>\n\t<translation id=\"7309719557896597512\">আপনার দিনটি শুভ হোক</translation>\n\t<translation id=\"5805758016483237261\">এন্টারপ্রাইজ এ আপগ্রেড করুন - $ 99.00 প্রতি মাসে</translation>\n\t<translation id=\"7212624462478696127\">এক্সেস যাচাই করা হচ্ছে ...</translation>\n\t<translation id=\"1156206314346372426\">অ্যাকাউন্ট ড্যাশবোর্ড</translation>\n\t<translation id=\"892759319569190037\">দৃশ্য পটভূমির রঙ</translation>\n\t<translation id=\"463077023711449502\">সীমান্ত রঙ</translation>\n\t<translation id=\"7844431484369877777\">URL</translation>\n\t<translation id=\"6727478076005438064\">ফর্ম্যাট চয়ন করুন</translation>\n\t<translation id=\"8932917860978648376\">একক</translation>\n\t<translation id=\"6447113917741810043\">তাপমান যন্ত্রবিশেষ</translation>\n\t<translation id=\"1546647220090341106\">তাপমাপক যন্ত্র</translation>\n\t<translation id=\"6977749640368501596\">শৈলী</translation>\n\t<translation id=\"30300572504753589\">কালো</translation>\n\t<translation id=\"7850674593676755019\">সাদা</translation>\n\t<translation id=\"9011959596901584887\">রঙ</translation>\n\t<translation id=\"5667922561719642173\">দৃশ্য সঙ্গে লোড</translation>\n\t<translation id=\"5466334165625502718\">অন্তর</translation>\n\t<translation id=\"1128028236258747485\">সমাপ্তির ভিডিও প্লে</translation>\n\t<translation id=\"3372777815572567783\">র্যান্ডম প্লেব্যাক</translation>\n\t<translation id=\"6757770085960264448\">স্লাইডশো</translation>\n\t<translation id=\"6659445582099947212\">টোকেন</translation>\n\t<translation id=\"6262368721870308838\">Instagram অ্যাক্সেস টোকেন তৈরি</translation>\n\t<translation id=\"6358635099770142731\">টোকেন তৈরি</translation>\n\t<translation id=\"7499211462525828161\">ক্যালেন্ডারের সাথে লোড</translation>\n\t<translation id=\"3128474301651540051\">পরিসর মোড অফসেট</translation>\n\t<translation id=\"5645011507444946232\">দিন পূর্বে আজকের</translation>\n\t<translation id=\"472347571959391022\">দিন পরে আজ</translation>\n\t<translation id=\"7382546590159708114\">শুরুর তারিখ</translation>\n\t<translation id=\"8615958092383580706\">শেষ তারিখ</translation>\n\t<translation id=\"7824071976623180870\">চাদর দিয়ে লোড</translation>\n\t<translation id=\"4370305429271412983\">স্ক্রীনের নাম</translation>\n\t<translation id=\"7641098557273120361\">অ্যাক্সেস টোকেন তৈরি</translation>\n\t<translation id=\"361150460746746781\">অনুপাত বজায় রাখা</translation>\n\t<translation id=\"3046991000485970172\">আরএসএস রিফ্রেশ (মিনিট)</translation>\n\t<translation id=\"2303401327609002516\">আরএসএস স্ক্রল দিক</translation>\n\t<translation id=\"8382375758916799432\">অনুভূমিক</translation>\n\t<translation id=\"160958144287367985\">উল্লম্ব</translation>\n\t<translation id=\"5576694760844259892\">আরএসএস স্ক্রল গতি</translation>\n\t<translation id=\"3801245379625272309\">ধীর</translation>\n\t<translation id=\"4688460977394283086\">মধ্যম</translation>\n\t<translation id=\"9161614188045173336\">দ্রুত</translation>\n\t<translation id=\"6107231410782382609\">ঘটনা নিম্নলিখিত ব্যবস্থা গ্রহণ</translation>\n\t<translation id=\"8875363048655701399\">কিয়স্ক মোড</translation>\n\t<translation id=\"6880124786888445040\">ক্রমানুসারে সংগ্রহ খেলুন</translation>\n\t<translation id=\"2166463051767640100\">সংগ্রহে বিষয়বস্তু যোগ</translation>\n\t<translation id=\"7365517136074263312\">QR কোড</translation>\n\t<translation id=\"810733191089543608\">আয়তন</translation>\n\t<translation id=\"4815249204085613710\">ভিডিও এর ধরন</translation>\n\t<translation id=\"5082095396043563283\">এলাকা</translation>\n\t<translation id=\"396267502411280310\">সর্বাধিক দেখা</translation>\n\t<translation id=\"2441920677226386245\">কাস্টম তালিকা</translation>\n\t<translation id=\"1223194855937061908\">ভিডিও আইডির</translation>\n\t<translation id=\"4103549354606724944\">গ্রাহকের লাইন</translation>\n\t<translation id=\"7262144878230347914\">পেছনের রং</translation>\n\t<translation id=\"1435085881129646880\">ডিফল্ট অনুক্রমিক প্লেলিস্ট</translation>\n\t<translation id=\"1587536276491357593\">মোট অবস্থান ভিত্তিক:></translation>\n\t<translation id=\"3325180562659478330\">নাম</translation>\n\t<translation id=\"3051480550159545291\">অক্ষাংশ</translation>\n\t<translation id=\"2703718513716530782\">দ্রাঘিমা</translation>\n\t<translation id=\"5602245631444655788\">স্থিতিকাল</translation>\n\t<translation id=\"118487254857410201\">ব্যাসার্ধ পরিসীমা</translation>\n\t<translation id=\"9178543898761255307\">কিলোমিটার</translation>\n\t<translation id=\"7866202877490561957\">দ্বন্দ্ব অগ্রাধিকার</translation>\n\t<translation id=\"720146333131008909\">ঘটনাস্থলে বিষয়বস্তু যোগ</translation>\n\t<translation id=\"8729372534532732068\">দৃশ্য নাম</translation>\n\t<translation id=\"2224690894219674949\">সিমুলেশন মোড</translation>\n\t<translation id=\"7220335122322620944\">এন্টারপ্রাইজ সম্পর্কে আরো জানুন</translation>\n\t<translation id=\"8444323300278462770\">শীর্ষ</translation>\n\t<translation id=\"7449548947549758066\">বাম</translation>\n\t<translation id=\"9172672254266086971\">প্রস্থ</translation>\n\t<translation id=\"4093381701787958997\">উচ্চতা</translation>\n\t<translation id=\"2062170564010556149\">ঘূর্ণন</translation>\n\t<translation id=\"9088937454320275395\">পরিবর্তনগুলি প্রয়োগ</translation>\n\t<translation id=\"1870560040946711505\">লক</translation>\n\t<translation id=\"6108618462851148193\">প্রচারণা সম্পাদক</translation>\n\t<translation id=\"2741646832903808697\">স্ক্রীন লেআউট</translation>\n\t<translation id=\"6454444033973204385\">প্রচারণা নির্বাচন</translation>\n\t<translation id=\"6028894272398949430\">নতুন প্রচারাভিযান</translation>\n\t<translation id=\"3008329758802399315\">উইজার্ড সহায়তা পান</translation>\n\t<translation id=\"4145364267099301397\">আপনার প্রচারাভিযান নাম নির্বাচন করুন</translation>\n\t<translation id=\"3843469504048287640\">নতুন প্রচারাভিযান নাম লিখুন</translation>\n\t<translation id=\"4895430942430831092\">প্রচারণা আইডি:</translation>\n\t<translation id=\"1901427837939428954\">কিয়স্ক মোডে</translation>\n\t<translation id=\"8329228391349300722\">প্রচারাভিযানের প্লেব্যাক মোড:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (সাধারণ মোড):</translation>\n\t<translation id=\"4691632839818550461\">টাইমলাইন খেলুন একটি ক্রমাগত লুপ এই প্রচারণা জন্য। এটা তোলে সেটআপ করা সহজ এবং ব্যবহার করা সহজ হয়</translation>\n\t<translation id=\"6075423017399759230\">নির্ধারণকারী (উন্নত মোড):</translation>\n\t<translation id=\"750837672459228230\">টাইমলাইন খেলুন শুধুমাত্র নির্দিষ্ট সময়ের উপর এই প্রচারণার জন্য। উদাহরণ হিসেবে বলা যায়, রাতে সকালে সময়রেখা A এবং সময়রেখা বি খেলা এবং খেলার।</translation>\n\t<translation id=\"1167977099462453641\">পর্দা রেজল্যুশন</translation>\n\t<translation id=\"7626905534069326448\">সংঘর্ষ অগ্রাধিকার:</translation>\n\t<translation id=\"4220765745195024064\">স্থিতিকাল:</translation>\n\t<translation id=\"4049333306580215724\">একবার খেলতে</translation>\n\t<translation id=\"7249155645987524413\">দৈনন্দিন খেলা</translation>\n\t<translation id=\"8568181330490588741\">সাপ্তাহিক খেলা</translation>\n\t<translation id=\"3408786538616090951\">দিন নির্বাচন করুন:</translation>\n\t<translation id=\"6324587259626414962\">মাপসই পুনরাবৃত্তি</translation>\n\t<translation id=\"2012264763266897754\">বিক্ষিপ্ত আদেশ</translation>\n\t<translation id=\"4324819244706823449\">সম্পাদন করা বিন্যাস</translation>\n\t<translation id=\"5755245564638965488\">পরবর্তী চ্যানেল</translation>\n\t<translation id=\"2925036210758384238\">নির্বাচিত লাইন</translation>\n\t<translation id=\"3601209751322374737\">লোকদের আগে আগে হাঁটতে অনুস্মারক</translation>\n\t<translation id=\"1790884679999452685\">খোলা টার্মিনাল</translation>\n\t<translation id=\"4878432943521432749\">রিসেট লাইন</translation>\n\t<translation id=\"3728601907282119753\">সারি বৈশিষ্ট্য</translation>\n\t<translation id=\"2536017892630886700\">নির্বাচিত গ্রাহক:</translation>\n\t<translation id=\"6228967158577655533\">প্রতিপাদন:</translation>\n\t<translation id=\"6435015929996679472\">ডাকা:</translation>\n\t<translation id=\"8711852116268389728\">দৃশ্য নির্বাচন</translation>\n\t<translation id=\"5053705054681686956\">নতুন লাইন</translation>\n\t<translation id=\"5225640858395745699\">লাইন অপসারণ</translation>\n\t<translation id=\"3116266439138367996\">লিংক</translation>\n\t<translation id=\"4159874591284333337\">Google এর কৌণিক ফ্রেমওয়ার্ক দ্বারা চালিত</translation>\n\t<translation id=\"3008186756887926107\">ফাইল আপলোড</translation>\n\t<translation id=\"2123171795960509943\">অপসারণ</translation>\n\t<translation id=\"7246196759043272468\">তালিকা</translation>\n\t<translation id=\"946077791002604877\">গ্রিড</translation>\n\t<translation id=\"5936943188558553659\">সমর্থিত ফাইলগুলি: FLV, MP4, JPG, PNG, SWF এবং SVG</translation>\n\t<translation id=\"8054250976557949996\">নতুন দৃশ্য</translation>\n\t<translation id=\"6133338617402043535\">নকল</translation>\n\t<translation id=\"1576591662761177526\">আমদানি টেমপ্লেট</translation>\n\t<translation id=\"2225048990372533999\">পুনরায় বোঝাই করা</translation>\n\t<translation id=\"987425828725037788\">আইপি ঠিকানা</translation>\n\t<translation id=\"1646067470190508925\">বন্দর</translation>\n\n\t<translation id=\"8097415329769247281\">প্যাকেজ আপনার জন্য সঠিক চয়ন করুন</translation>\n\n\t<translation id=\"6570363013146073520\">ড্যাশবোর্ড</translation>\n\t<translation id=\"8864658120410603626\">প্রচারাভিযান</translation>\n\t<translation id=\"2446117790692479672\">সম্পদ</translation>\n\t<translation id=\"794120057687191331\">দৃশ্য</translation>\n\t<translation id=\"4846792506513649213\">স্টেশন</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">সাহায্য করুন</translation>\n\t<translation id=\"6082171864197428613\">ইনস্টল করুন</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">প্রস্থান</translation>\n\t<translation id=\"7746065369460476808\">ব্যবহারকারী নাম বা ইমেল</translation>\n\t<translation id=\"4809196861118879526\">পাসওয়ার্ড</translation>\n\t<translation id=\"9162857816822524614\">দুই ফ্যাক্টর কী লিখুন</translation>\n\t<translation id=\"24227595514967590\">Google প্রমাণকারী সঙ্গে</translation>\n\t<translation id=\"2001940299854753031\">আমাকে মনে কর</translation>\n\t<translation id=\"5872337092278414963\">পাসওয়ার্ড ভুলে গেছেন</translation>\n\t<translation id=\"8246600873004586882\">পাসওয়ার্ড পরিবর্তন</translation>\n\t<translation id=\"5289326240092186479\">পরিবর্তন ব্যবসার নাম</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">পুরানো পাসওয়ার্ড</translation>\n\t<translation id=\"48285893667252664\">নতুন পাসওয়ার্ড</translation>\n\t<translation id=\"6917932917401642982\">পুনরাবৃত্তি নতুন পাসওয়ার্ড</translation>\n\t<translation id=\"5666893431176348635\">নতুন ব্যবসার নাম</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">আপগ্রেড</translation>\n\t<translation id=\"8894542476475088437\">অ্যাকাউন্ট-এস</translation>\n\t<translation id=\"2347724151568473592\">ভাষা</translation>\n\t<translation id=\"4376434433661751094\">সরাসরি কথোপকথন</translation>\n\t<translation id=\"5344752701442428839\">ওয়েব সাইট</translation>\n\t<translation id=\"7108535247064136881\">আপনার ভাষা চয়ন করুন</translation>\n\t<translation id=\"4137049537431219133\">Google প্রমাণকারী সঙ্গে আপনার অ্যাকাউন্টে লগইন</translation>\n\t<translation id=\"4785021168351486737\">সংরক্ষণ করুন & লগআউট</translation>\n\t<translation id=\"6524180701596149125\">শুধু লগআউট</translation>\n\n\t<translation id=\"2503331336991669578\">আপনার অ্যাকাউন্টে লগ ইন করুন</translation>\n\t<translation id=\"8359621426539146583\">কোনো একাউন্ট না</translation>\n\t<translation id=\"569785428576811345\">স্থিতিকাল:</translation>\n\t<translation id=\"9043806075514219833\">সময় শুরু:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/cs.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"cs\">\n\t<translation id=\"9198441993514322349\">orientace obrazovky</translation>\n\t<translation id=\"2838690440296896849\">vzdálená status</translation>\n\t<translation id=\"2849064100927111571\">načítání...</translation>\n\t<translation id=\"7309719557896597512\">hezký den</translation>\n\t<translation id=\"5805758016483237261\">Upgradovat na Enterprise - 99,00 $ za měsíc</translation>\n\t<translation id=\"7212624462478696127\">ověření přístupu ...</translation>\n\t<translation id=\"1156206314346372426\">účet dashboard</translation>\n\t<translation id=\"892759319569190037\">barvu pozadí scény</translation>\n\t<translation id=\"463077023711449502\">barva ohraničení</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">zvolit formát</translation>\n\t<translation id=\"8932917860978648376\">Jednotka</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheita</translation>\n\t<translation id=\"1546647220090341106\">Celsia</translation>\n\t<translation id=\"6977749640368501596\">styly</translation>\n\t<translation id=\"30300572504753589\">Černá</translation>\n\t<translation id=\"7850674593676755019\">Bílý</translation>\n\t<translation id=\"9011959596901584887\">Barva</translation>\n\t<translation id=\"5667922561719642173\">Zatížení se scénou</translation>\n\t<translation id=\"5466334165625502718\">interval</translation>\n\t<translation id=\"1128028236258747485\">přehrávat video až do konce</translation>\n\t<translation id=\"3372777815572567783\">náhodné přehrávání</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">žeton</translation>\n\t<translation id=\"6262368721870308838\">Vytvoření Instagram přístupový token</translation>\n\t<translation id=\"6358635099770142731\">vytvoření tokenu</translation>\n\t<translation id=\"7499211462525828161\">Zatížení s kalendářem</translation>\n\t<translation id=\"3128474301651540051\">ofsetový režim rozsah</translation>\n\t<translation id=\"5645011507444946232\">dní před dnes</translation>\n\t<translation id=\"472347571959391022\">dní po dnešku</translation>\n\t<translation id=\"7382546590159708114\">Datum zahájení</translation>\n\t<translation id=\"8615958092383580706\">datum ukončení</translation>\n\t<translation id=\"7824071976623180870\">Zatížení se list</translation>\n\t<translation id=\"4370305429271412983\">přezdívka</translation>\n\t<translation id=\"7641098557273120361\">vytvořit přístupový token</translation>\n\t<translation id=\"361150460746746781\">udržuje poměr stran</translation>\n\t<translation id=\"3046991000485970172\">RSS refresh (minuty)</translation>\n\t<translation id=\"2303401327609002516\">RSS scroll směr</translation>\n\t<translation id=\"8382375758916799432\">Horizontální</translation>\n\t<translation id=\"160958144287367985\">Vertikální</translation>\n\t<translation id=\"5576694760844259892\">RSS rychlost procházení</translation>\n\t<translation id=\"3801245379625272309\">pomalý</translation>\n\t<translation id=\"4688460977394283086\">střední</translation>\n\t<translation id=\"9161614188045173336\">rychle</translation>\n\t<translation id=\"6107231410782382609\">Na akci tyto kroky</translation>\n\t<translation id=\"8875363048655701399\">režim Kiosk</translation>\n\t<translation id=\"6880124786888445040\">Hrají sbírku v pořadí</translation>\n\t<translation id=\"2166463051767640100\">přidávat obsah do sbírky</translation>\n\t<translation id=\"7365517136074263312\">QR kód</translation>\n\t<translation id=\"810733191089543608\">hlasitost</translation>\n\t<translation id=\"4815249204085613710\">kvalita videa</translation>\n\t<translation id=\"5082095396043563283\">kraj</translation>\n\t<translation id=\"396267502411280310\">nejsledovanější</translation>\n\t<translation id=\"2441920677226386245\">vlastní seznam</translation>\n\t<translation id=\"1223194855937061908\">ID videí</translation>\n\t<translation id=\"4103549354606724944\">linky zákazníků</translation>\n\t<translation id=\"7262144878230347914\">barva pozadí</translation>\n\t<translation id=\"1435085881129646880\">Výchozí sekvenční playlist</translation>\n\t<translation id=\"1587536276491357593\">Celkové umístění založen:></translation>\n\t<translation id=\"3325180562659478330\">název</translation>\n\t<translation id=\"3051480550159545291\">zeměpisná šířka</translation>\n\t<translation id=\"2703718513716530782\">zeměpisná délka</translation>\n\t<translation id=\"5602245631444655788\">doba trvání</translation>\n\t<translation id=\"118487254857410201\">rozsah poloměr</translation>\n\t<translation id=\"9178543898761255307\">kilometry</translation>\n\t<translation id=\"7866202877490561957\">priority konflikt</translation>\n\t<translation id=\"720146333131008909\">přidávat obsah na scéně</translation>\n\t<translation id=\"8729372534532732068\">název scény</translation>\n\t<translation id=\"2224690894219674949\">režim simulace</translation>\n\t<translation id=\"7220335122322620944\">Dozvědět se více o podnikání</translation>\n\t<translation id=\"8444323300278462770\">horní</translation>\n\t<translation id=\"7449548947549758066\">vlevo, odjet</translation>\n\t<translation id=\"9172672254266086971\">šířka</translation>\n\t<translation id=\"4093381701787958997\">výška</translation>\n\t<translation id=\"2062170564010556149\">otáčení</translation>\n\t<translation id=\"9088937454320275395\">aplikuj změny</translation>\n\t<translation id=\"1870560040946711505\">zamčený</translation>\n\t<translation id=\"6108618462851148193\">editor kampaně</translation>\n\t<translation id=\"2741646832903808697\">rozložení obrazovky</translation>\n\t<translation id=\"6454444033973204385\">Volba kampaň</translation>\n\t<translation id=\"6028894272398949430\">nová kampaň</translation>\n\t<translation id=\"3008329758802399315\">Získat Wizard pomoc</translation>\n\t<translation id=\"4145364267099301397\">Vyberte si název kampaně</translation>\n\t<translation id=\"3843469504048287640\">Zadejte nový název kampaně</translation>\n\t<translation id=\"4895430942430831092\">Kampaň id:</translation>\n\t<translation id=\"1901427837939428954\">režim kiosk</translation>\n\t<translation id=\"8329228391349300722\">Kampani režimu přehrávání:</translation>\n\t<translation id=\"8793145092368811184\">Sekvencer (jednoduchý režim):</translation>\n\t<translation id=\"4691632839818550461\">Hrát časový plán pro tuto kampaň v nekonečné smyčce. Je snadné nastavení a snadné použití</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (rozšířený režim):</translation>\n\t<translation id=\"750837672459228230\">Hrát časový plán pro tuto kampaň pouze v určitých časech. Například, hrát časové osy A v ranních hodinách a na časové ose B v noci.</translation>\n\t<translation id=\"1167977099462453641\">Rozlišení obrazovky</translation>\n\t<translation id=\"7626905534069326448\">priority konflikt:</translation>\n\t<translation id=\"4220765745195024064\">Doba trvání:</translation>\n\t<translation id=\"4049333306580215724\">jednou přehrála</translation>\n\t<translation id=\"7249155645987524413\">hrát denně</translation>\n\t<translation id=\"8568181330490588741\">hrají týdenní</translation>\n\t<translation id=\"3408786538616090951\">Zvolte dny:</translation>\n\t<translation id=\"6324587259626414962\">opakovat, aby se vešly</translation>\n\t<translation id=\"2012264763266897754\">náhodná objednávka</translation>\n\t<translation id=\"4324819244706823449\">editovat rozvržení</translation>\n\t<translation id=\"5755245564638965488\">další kanál</translation>\n\t<translation id=\"2925036210758384238\">vybraný řádek</translation>\n\t<translation id=\"3601209751322374737\">připomínka před lidmi</translation>\n\t<translation id=\"1790884679999452685\">otevřený terminál</translation>\n\t<translation id=\"4878432943521432749\">resetovací linka</translation>\n\t<translation id=\"3728601907282119753\">vlastnosti fronty</translation>\n\t<translation id=\"2536017892630886700\">vybrán zákazník:</translation>\n\t<translation id=\"6228967158577655533\">ověření:</translation>\n\t<translation id=\"6435015929996679472\">nazvaný:</translation>\n\t<translation id=\"8711852116268389728\">Volba scény</translation>\n\t<translation id=\"5053705054681686956\">nový řádek</translation>\n\t<translation id=\"5225640858395745699\">odstranit řádek</translation>\n\t<translation id=\"3116266439138367996\">odkazy</translation>\n\t<translation id=\"4159874591284333337\">Běží na úhlové rámci Google</translation>\n\t<translation id=\"3008186756887926107\">nahrát soubory</translation>\n\t<translation id=\"2123171795960509943\">odstranit</translation>\n\t<translation id=\"7246196759043272468\">seznam</translation>\n\t<translation id=\"946077791002604877\">mřížka</translation>\n\t<translation id=\"5936943188558553659\">podporované soubory: flv, mp4, jpg, png, swf a SVG</translation>\n\t<translation id=\"8054250976557949996\">nová scéna</translation>\n\t<translation id=\"6133338617402043535\">duplikát</translation>\n\t<translation id=\"1576591662761177526\">import šablony</translation>\n\t<translation id=\"2225048990372533999\">Znovu načíst</translation>\n\t<translation id=\"987425828725037788\">IP adresa</translation>\n\t<translation id=\"1646067470190508925\">přístav</translation>\n\n\t<translation id=\"8097415329769247281\">Vyberte si balíček, který je pro vás to pravé</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/da.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"da\">\n\t<translation id=\"9198441993514322349\">skærmretningen</translation>\n\t<translation id=\"2838690440296896849\">fjernbetjening status</translation>\n\t<translation id=\"2849064100927111571\">Indlæser...</translation>\n\t<translation id=\"7309719557896597512\">hav en god dag</translation>\n\t<translation id=\"5805758016483237261\">Opgrader til Enterprise - $ 99,00 per måned</translation>\n\t<translation id=\"7212624462478696127\">verificere adgang ...</translation>\n\t<translation id=\"1156206314346372426\">instrumentbræt konto</translation>\n\t<translation id=\"892759319569190037\">farve scene baggrund</translation>\n\t<translation id=\"463077023711449502\">farve grænse</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Vælg format</translation>\n\t<translation id=\"8932917860978648376\">Enhed</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">styles</translation>\n\t<translation id=\"30300572504753589\">Sort</translation>\n\t<translation id=\"7850674593676755019\">hvid</translation>\n\t<translation id=\"9011959596901584887\">Farve</translation>\n\t<translation id=\"5667922561719642173\">belastning med scene</translation>\n\t<translation id=\"5466334165625502718\">interval</translation>\n\t<translation id=\"1128028236258747485\">afspille video til færdiggørelse</translation>\n\t<translation id=\"3372777815572567783\">tilfældig afspilning</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">polet</translation>\n\t<translation id=\"6262368721870308838\">skabe instagram adgang token</translation>\n\t<translation id=\"6358635099770142731\">skabe token</translation>\n\t<translation id=\"7499211462525828161\">Belastning med kalender</translation>\n\t<translation id=\"3128474301651540051\">offset rækkevidde tilstand</translation>\n\t<translation id=\"5645011507444946232\">dage før i dag</translation>\n\t<translation id=\"472347571959391022\">dage efter dag</translation>\n\t<translation id=\"7382546590159708114\">start dato</translation>\n\t<translation id=\"8615958092383580706\">slutdato</translation>\n\t<translation id=\"7824071976623180870\">Belastning med ark</translation>\n\t<translation id=\"4370305429271412983\">skærm navn</translation>\n\t<translation id=\"7641098557273120361\">skabe adgang token</translation>\n\t<translation id=\"361150460746746781\">beholde proportionerne</translation>\n\t<translation id=\"3046991000485970172\">RSS opdateringshastighed (minutter)</translation>\n\t<translation id=\"2303401327609002516\">RSS scroll retning</translation>\n\t<translation id=\"8382375758916799432\">Vandret</translation>\n\t<translation id=\"160958144287367985\">Lodret</translation>\n\t<translation id=\"5576694760844259892\">RSS scroll hastighed</translation>\n\t<translation id=\"3801245379625272309\">langsom</translation>\n\t<translation id=\"4688460977394283086\">medium</translation>\n\t<translation id=\"9161614188045173336\">hurtig</translation>\n\t<translation id=\"6107231410782382609\">På begivenhed træffe følgende foranstaltninger</translation>\n\t<translation id=\"8875363048655701399\">Kiosk-tilstand</translation>\n\t<translation id=\"6880124786888445040\">Spille samling i rækkefølge</translation>\n\t<translation id=\"2166463051767640100\">tilføje indhold til samling</translation>\n\t<translation id=\"7365517136074263312\">QR kode</translation>\n\t<translation id=\"810733191089543608\">bind</translation>\n\t<translation id=\"4815249204085613710\">videokvalitet</translation>\n\t<translation id=\"5082095396043563283\">område</translation>\n\t<translation id=\"396267502411280310\">mest sete</translation>\n\t<translation id=\"2441920677226386245\">brugerdefineret liste</translation>\n\t<translation id=\"1223194855937061908\">video-id'er</translation>\n\t<translation id=\"4103549354606724944\">kundelinjer</translation>\n\t<translation id=\"7262144878230347914\">baggrundsfarve</translation>\n\t<translation id=\"1435085881129646880\">Standard sekventiel spilleliste</translation>\n\t<translation id=\"1587536276491357593\">Samlet placering baseret:></translation>\n\t<translation id=\"3325180562659478330\">navn</translation>\n\t<translation id=\"3051480550159545291\">Breddegrad</translation>\n\t<translation id=\"2703718513716530782\">længde</translation>\n\t<translation id=\"5602245631444655788\">varighed</translation>\n\t<translation id=\"118487254857410201\">radius rækkevidde</translation>\n\t<translation id=\"9178543898761255307\">kilometer</translation>\n\t<translation id=\"7866202877490561957\">prioritet konflikt</translation>\n\t<translation id=\"720146333131008909\">tilføje indhold til scene</translation>\n\t<translation id=\"8729372534532732068\">scene navn</translation>\n\t<translation id=\"2224690894219674949\">simulationsmodus</translation>\n\t<translation id=\"7220335122322620944\">Læs mere om Enterprise</translation>\n\t<translation id=\"8444323300278462770\">top</translation>\n\t<translation id=\"7449548947549758066\">venstre</translation>\n\t<translation id=\"9172672254266086971\">bredde</translation>\n\t<translation id=\"4093381701787958997\">højde</translation>\n\t<translation id=\"2062170564010556149\">rotation</translation>\n\t<translation id=\"9088937454320275395\">anvende ændringerne</translation>\n\t<translation id=\"1870560040946711505\">Låst</translation>\n\t<translation id=\"6108618462851148193\">kampagne redaktør</translation>\n\t<translation id=\"2741646832903808697\">skærm layout</translation>\n\t<translation id=\"6454444033973204385\">udvælgelse kampagne</translation>\n\t<translation id=\"6028894272398949430\">ny kampagne</translation>\n\t<translation id=\"3008329758802399315\">Få guiden hjælp</translation>\n\t<translation id=\"4145364267099301397\">Vælg din kampagne navn</translation>\n\t<translation id=\"3843469504048287640\">Indtast ny kampagne navn</translation>\n\t<translation id=\"4895430942430831092\">kampagne-id:</translation>\n\t<translation id=\"1901427837939428954\">kiosk-tilstand</translation>\n\t<translation id=\"8329228391349300722\">I kampagne afspilningstilstand:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (enkel tilstand):</translation>\n\t<translation id=\"4691632839818550461\">Spil tidslinjer for denne kampagne i en kontinuerlig løkke. Det er let at installere og enkel at bruge</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (avanceret tilstand):</translation>\n\t<translation id=\"750837672459228230\">Spil tidslinjer for denne kampagne kun på bestemte tidspunkter. For eksempel spiller Tidslinje A om morgenen og Timeline B natten.</translation>\n\t<translation id=\"1167977099462453641\">skærmopløsning</translation>\n\t<translation id=\"7626905534069326448\">Konflikt prioritet:</translation>\n\t<translation id=\"4220765745195024064\">Varighed:</translation>\n\t<translation id=\"4049333306580215724\">spille en gang</translation>\n\t<translation id=\"7249155645987524413\">spille dagligt</translation>\n\t<translation id=\"8568181330490588741\">spille ugentlige</translation>\n\t<translation id=\"3408786538616090951\">Vælg de dage:</translation>\n\t<translation id=\"6324587259626414962\">gentag til at passe</translation>\n\t<translation id=\"2012264763266897754\">tilfældig rækkefølge</translation>\n\t<translation id=\"4324819244706823449\">redigere layout</translation>\n\t<translation id=\"5755245564638965488\">næste kanal</translation>\n\t<translation id=\"2925036210758384238\">valgte linje</translation>\n\t<translation id=\"3601209751322374737\">påmindelse forud for mennesker</translation>\n\t<translation id=\"1790884679999452685\">åben terminal</translation>\n\t<translation id=\"4878432943521432749\">reset linje</translation>\n\t<translation id=\"3728601907282119753\">kø egenskaber</translation>\n\t<translation id=\"2536017892630886700\">valgte kunde:</translation>\n\t<translation id=\"6228967158577655533\">verifikation:</translation>\n\t<translation id=\"6435015929996679472\">kaldt af:</translation>\n\t<translation id=\"8711852116268389728\">udvælgelse scene</translation>\n\t<translation id=\"5053705054681686956\">ny linje</translation>\n\t<translation id=\"5225640858395745699\">fjerne linje</translation>\n\t<translation id=\"3116266439138367996\">links</translation>\n\t<translation id=\"4159874591284333337\">Drevet af Googles Kantet ramme</translation>\n\t<translation id=\"3008186756887926107\">uploade filer</translation>\n\t<translation id=\"2123171795960509943\">fjerne</translation>\n\t<translation id=\"7246196759043272468\">liste</translation>\n\t<translation id=\"946077791002604877\">gitter</translation>\n\t<translation id=\"5936943188558553659\">understøttede filer: flv, mp4, jpg, png, swf og SVG</translation>\n\t<translation id=\"8054250976557949996\">ny scene</translation>\n\t<translation id=\"6133338617402043535\">duplikere</translation>\n\t<translation id=\"1576591662761177526\">import skabelon</translation>\n\t<translation id=\"2225048990372533999\">reload</translation>\n\t<translation id=\"987425828725037788\">IP-adresse</translation>\n\t<translation id=\"1646067470190508925\">Havn</translation>\n\n\t<translation id=\"8097415329769247281\">Vælg den pakke, der passer til dig</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/de.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"de\">\n\t<translation id=\"9198441993514322349\">Bildschirmausrichtung</translation>\n\t<translation id=\"2838690440296896849\">Remote Status</translation>\n\t<translation id=\"2849064100927111571\">Laden...</translation>\n\t<translation id=\"7309719557896597512\">Einen schönen Tag noch</translation>\n\t<translation id=\"5805758016483237261\">Upgrade auf Enterprise - $ 99.00 pro Monat</translation>\n\t<translation id=\"7212624462478696127\">Zugriff überprüfen ...</translation>\n\t<translation id=\"1156206314346372426\">Benutzerkonto Übersicht</translation>\n\t<translation id=\"892759319569190037\">Szene Hintergrundfarbe</translation>\n\t<translation id=\"463077023711449502\">Randfarbe</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Format wählen</translation>\n\t<translation id=\"8932917860978648376\">Einheit</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">Styles</translation>\n\t<translation id=\"30300572504753589\">Schwarz</translation>\n\t<translation id=\"7850674593676755019\">Weiß</translation>\n\t<translation id=\"9011959596901584887\">Farbe</translation>\n\t<translation id=\"5667922561719642173\">Last mit Szene</translation>\n\t<translation id=\"5466334165625502718\">Intervall</translation>\n\t<translation id=\"1128028236258747485\">Video abspielen zu Abschluss</translation>\n\t<translation id=\"3372777815572567783\">Zufallswiedergabe</translation>\n\t<translation id=\"6757770085960264448\">Diashow</translation>\n\t<translation id=\"6659445582099947212\">Zeichen</translation>\n\t<translation id=\"6262368721870308838\">erstellen instagram Zugriffstoken</translation>\n\t<translation id=\"6358635099770142731\">erstellen Token</translation>\n\t<translation id=\"7499211462525828161\">Last mit Kalender</translation>\n\t<translation id=\"3128474301651540051\">Offset-Bereich-Modus</translation>\n\t<translation id=\"5645011507444946232\">Tage vor heute</translation>\n\t<translation id=\"472347571959391022\">Tage nach dem heutigen Tag</translation>\n\t<translation id=\"7382546590159708114\">Anfangsdatum</translation>\n\t<translation id=\"8615958092383580706\">Enddatum</translation>\n\t<translation id=\"7824071976623180870\">Belastung mit Blatt</translation>\n\t<translation id=\"4370305429271412983\">Künstlername</translation>\n\t<translation id=\"7641098557273120361\">erstellen Zugriffstoken</translation>\n\t<translation id=\"361150460746746781\">Seitenverhältnis beibehalten</translation>\n\t<translation id=\"3046991000485970172\">RSS refresh (Minuten)</translation>\n\t<translation id=\"2303401327609002516\">RSS Scroll-Richtung</translation>\n\t<translation id=\"8382375758916799432\">Horizontal</translation>\n\t<translation id=\"160958144287367985\">Vertikal</translation>\n\t<translation id=\"5576694760844259892\">RSS Scroll-Geschwindigkeit</translation>\n\t<translation id=\"3801245379625272309\">langsam</translation>\n\t<translation id=\"4688460977394283086\">Mittel</translation>\n\t<translation id=\"9161614188045173336\">schnell</translation>\n\t<translation id=\"6107231410782382609\">Auf Veranstaltung nehmen Sie die folgende Aktion</translation>\n\t<translation id=\"8875363048655701399\">Kiosk-Modus</translation>\n\t<translation id=\"6880124786888445040\">Spiele Sammlung in Folge</translation>\n\t<translation id=\"2166463051767640100\">Inhalte hinzufügen Sammlung</translation>\n\t<translation id=\"7365517136074263312\">QR-Code</translation>\n\t<translation id=\"810733191089543608\">Volumen</translation>\n\t<translation id=\"4815249204085613710\">Videoqualität</translation>\n\t<translation id=\"5082095396043563283\">Region</translation>\n\t<translation id=\"396267502411280310\">am häufigsten gesehen</translation>\n\t<translation id=\"2441920677226386245\">benutzerdefinierte Liste</translation>\n\t<translation id=\"1223194855937061908\">Video-IDs</translation>\n\t<translation id=\"4103549354606724944\">Kundenanschaltungen</translation>\n\t<translation id=\"7262144878230347914\">Hintergrundfarbe</translation>\n\t<translation id=\"1435085881129646880\">Standard sequenzielle Playlist</translation>\n\t<translation id=\"1587536276491357593\">Insgesamt Location Based:></translation>\n\t<translation id=\"3325180562659478330\">Name</translation>\n\t<translation id=\"3051480550159545291\">Breite</translation>\n\t<translation id=\"2703718513716530782\">Länge</translation>\n\t<translation id=\"5602245631444655788\">Dauer</translation>\n\t<translation id=\"118487254857410201\">radius</translation>\n\t<translation id=\"9178543898761255307\">Kilometer</translation>\n\t<translation id=\"7866202877490561957\">Konflikt Priorität</translation>\n\t<translation id=\"720146333131008909\">Inhalte hinzufügen Szene</translation>\n\t<translation id=\"8729372534532732068\">Szenennamen</translation>\n\t<translation id=\"2224690894219674949\">Simulationsmodus</translation>\n\t<translation id=\"7220335122322620944\">Weitere Informationen zum Unternehmen</translation>\n\t<translation id=\"8444323300278462770\">oben</translation>\n\t<translation id=\"7449548947549758066\">links</translation>\n\t<translation id=\"9172672254266086971\">Breite</translation>\n\t<translation id=\"4093381701787958997\">Höhe</translation>\n\t<translation id=\"2062170564010556149\">Drehung</translation>\n\t<translation id=\"9088937454320275395\">Änderungen übernehmen</translation>\n\t<translation id=\"1870560040946711505\">eingesperrt</translation>\n\t<translation id=\"6108618462851148193\">Kampagnen-Editor</translation>\n\t<translation id=\"2741646832903808697\">Bildschirmgestaltung</translation>\n\t<translation id=\"6454444033973204385\">Kampagne Auswahl</translation>\n\t<translation id=\"6028894272398949430\">neue Kampagne</translation>\n\t<translation id=\"3008329758802399315\">Get-Assistent Hilfe</translation>\n\t<translation id=\"4145364267099301397\">Wählen Sie den Kampagnennamen</translation>\n\t<translation id=\"3843469504048287640\">Geben Sie den neuen Kampagnennamen</translation>\n\t<translation id=\"4895430942430831092\">Kampagnen-ID:</translation>\n\t<translation id=\"1901427837939428954\">Kiosk-Modus</translation>\n\t<translation id=\"8329228391349300722\">Kampagne Wiedergabemodus:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (Einfach-Modus):</translation>\n\t<translation id=\"4691632839818550461\">Spielen Sie einen Zeitplan für diese Kampagne in einer Endlosschleife. Es ist einfach zu installieren und einfach zu bedienen</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (erweiterter Modus):</translation>\n\t<translation id=\"750837672459228230\">Spiele Frist für diese Kampagne nur zu bestimmten Zeiten. Zum Beispiel spielt Timeline A am Morgen und Timeline-B in der Nacht.</translation>\n\t<translation id=\"1167977099462453641\">Bildschirmauflösung</translation>\n\t<translation id=\"7626905534069326448\">Konflikt Priorität:</translation>\n\t<translation id=\"4220765745195024064\">Dauer:</translation>\n\t<translation id=\"4049333306580215724\">spielen einmal</translation>\n\t<translation id=\"7249155645987524413\">spielen täglich</translation>\n\t<translation id=\"8568181330490588741\">spielen wöchentlich</translation>\n\t<translation id=\"3408786538616090951\">Wählen Sie die Tage:</translation>\n\t<translation id=\"6324587259626414962\">wiederholen, um fit</translation>\n\t<translation id=\"2012264763266897754\">zufällige Reihenfolge</translation>\n\t<translation id=\"4324819244706823449\">Layout bearbeiten</translation>\n\t<translation id=\"5755245564638965488\">nächster Kanal</translation>\n\t<translation id=\"2925036210758384238\">ausgewählte Leitung</translation>\n\t<translation id=\"3601209751322374737\">Erinnerung vor Menschen</translation>\n\t<translation id=\"1790884679999452685\">offene Klemmen</translation>\n\t<translation id=\"4878432943521432749\">Reset-Leitung</translation>\n\t<translation id=\"3728601907282119753\">Queue-Eigenschaften</translation>\n\t<translation id=\"2536017892630886700\">ausgewählte Kunden:</translation>\n\t<translation id=\"6228967158577655533\">Überprüfung:</translation>\n\t<translation id=\"6435015929996679472\">angerufen von:</translation>\n\t<translation id=\"8711852116268389728\">Szenenauswahl</translation>\n\t<translation id=\"5053705054681686956\">Neue Zeile</translation>\n\t<translation id=\"5225640858395745699\">entfernen Linie</translation>\n\t<translation id=\"3116266439138367996\">Links</translation>\n\t<translation id=\"4159874591284333337\">Angetrieben durch Google Angular Rahmen</translation>\n\t<translation id=\"3008186756887926107\">Daten hochladen</translation>\n\t<translation id=\"2123171795960509943\">entfernen</translation>\n\t<translation id=\"7246196759043272468\">Liste</translation>\n\t<translation id=\"946077791002604877\">Gitter</translation>\n\t<translation id=\"5936943188558553659\">unterstützt Dateien: flv, mp4, jpg, png, swf und svg</translation>\n\t<translation id=\"8054250976557949996\">neue Szene</translation>\n\t<translation id=\"6133338617402043535\">Duplikat</translation>\n\t<translation id=\"1576591662761177526\">Importvorlage</translation>\n\t<translation id=\"2225048990372533999\">neu laden</translation>\n\t<translation id=\"987425828725037788\">IP Adresse</translation>\n\t<translation id=\"1646067470190508925\">Hafen</translation>\n\n\t<translation id=\"8097415329769247281\">Wählen Sie das Paket, das Richtige für Sie</translation>\n\n\t<translation id=\"6570363013146073520\">Instrumententafel</translation>\n\t<translation id=\"8864658120410603626\">Kampagnen</translation>\n\t<translation id=\"2446117790692479672\">Ressourcen</translation>\n\t<translation id=\"794120057687191331\">Szenen</translation>\n\t<translation id=\"4846792506513649213\">Stationen</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Hilfe</translation>\n\t<translation id=\"6082171864197428613\">Installieren</translation>\n\t<translation id=\"3476206505271758484\">studiopro</translation>\n\t<translation id=\"3797778920049399855\">Ausloggen</translation>\n\t<translation id=\"7746065369460476808\">Benutzername oder E-Mail-Adresse</translation>\n\t<translation id=\"4809196861118879526\">Passwort</translation>\n\t<translation id=\"9162857816822524614\">Geben Sie Zwei-Faktor-Schlüssel</translation>\n\t<translation id=\"24227595514967590\">mit Google Authenticator</translation>\n\t<translation id=\"2001940299854753031\">Erinnere dich an mich</translation>\n\t<translation id=\"5872337092278414963\">Passwort vergessen</translation>\n\t<translation id=\"8246600873004586882\">Passwort ändern</translation>\n\t<translation id=\"5289326240092186479\">Änderung Firmenname</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">Altes Passwort</translation>\n\t<translation id=\"48285893667252664\">Neues Kennwort</translation>\n\t<translation id=\"6917932917401642982\">Wiederhole das neue Passwort</translation>\n\t<translation id=\"5666893431176348635\">neuer Firmenname</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">Aktualisierung</translation>\n\t<translation id=\"8894542476475088437\">Konto-S</translation>\n\t<translation id=\"2347724151568473592\">Sprache</translation>\n\t<translation id=\"4376434433661751094\">Live-Chat</translation>\n\t<translation id=\"5344752701442428839\">Website</translation>\n\t<translation id=\"7108535247064136881\">Wählen Sie Ihre Sprache</translation>\n\t<translation id=\"4137049537431219133\">Melden Sie sich mit Ihrem Google-Authentifizierer an</translation>\n\t<translation id=\"4785021168351486737\">Speichern & Abmelden</translation>\n\t<translation id=\"6524180701596149125\">Nur abmelden</translation>\n\n\t<translation id=\"2503331336991669578\">Melde dich in deinem Konto an</translation>\n\t<translation id=\"8359621426539146583\">Haben Sie kein Konto</translation>\n\t<translation id=\"569785428576811345\">Dauer:</translation>\n\t<translation id=\"9043806075514219833\">Startzeit:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/el.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"el\">\n\t<translation id=\"9198441993514322349\">προσανατολισμό της οθόνης</translation>\n\t<translation id=\"2838690440296896849\">απομακρυσμένη κατάσταση</translation>\n\t<translation id=\"2849064100927111571\">φόρτωση...</translation>\n\t<translation id=\"7309719557896597512\">να εχεις μια ωραια μερα</translation>\n\t<translation id=\"5805758016483237261\">Αναβάθμιση σε Επιχειρήσεις - $ 99,00 ανά μήνα</translation>\n\t<translation id=\"7212624462478696127\">τον έλεγχο της πρόσβασης ...</translation>\n\t<translation id=\"1156206314346372426\">πίνακα ελέγχου του λογαριασμού</translation>\n\t<translation id=\"892759319569190037\">χρώμα του φόντου σκηνή</translation>\n\t<translation id=\"463077023711449502\">χρώμα περιγράμματος</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Επιλέξτε τη μορφή</translation>\n\t<translation id=\"8932917860978648376\">Μονάδα</translation>\n\t<translation id=\"6447113917741810043\">θερμόμετρο Φαρενάιτ</translation>\n\t<translation id=\"1546647220090341106\">Κελσίου</translation>\n\t<translation id=\"6977749640368501596\">στυλ</translation>\n\t<translation id=\"30300572504753589\">Μαύρος</translation>\n\t<translation id=\"7850674593676755019\">άσπρο</translation>\n\t<translation id=\"9011959596901584887\">Χρώμα</translation>\n\t<translation id=\"5667922561719642173\">φορτίο με σκηνή</translation>\n\t<translation id=\"5466334165625502718\">διάστημα</translation>\n\t<translation id=\"1128028236258747485\">αναπαραγωγή βίντεο με την ολοκλήρωση</translation>\n\t<translation id=\"3372777815572567783\">τυχαία αναπαραγωγή</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">ένδειξη</translation>\n\t<translation id=\"6262368721870308838\">δημιουργούν διακριτικό πρόσβασης Instagram</translation>\n\t<translation id=\"6358635099770142731\">δημιουργούν διακριτικό</translation>\n\t<translation id=\"7499211462525828161\">Φορτίο με το ημερολόγιο</translation>\n\t<translation id=\"3128474301651540051\">offset λειτουργία εύρος</translation>\n\t<translation id=\"5645011507444946232\">ημέρες πριν από σήμερα</translation>\n\t<translation id=\"472347571959391022\">ημέρες μετά τη σημερινή</translation>\n\t<translation id=\"7382546590159708114\">ημερομηνία έναρξης</translation>\n\t<translation id=\"8615958092383580706\">ημερομηνία λήξης</translation>\n\t<translation id=\"7824071976623180870\">Φορτίο με φύλλο</translation>\n\t<translation id=\"4370305429271412983\">Όνομα οθόνης</translation>\n\t<translation id=\"7641098557273120361\">δημιουργούν διακριτικό πρόσβασης</translation>\n\t<translation id=\"361150460746746781\">διατηρήσουν αναλογία</translation>\n\t<translation id=\"3046991000485970172\">RSS ανανέωσης (λεπτά)</translation>\n\t<translation id=\"2303401327609002516\">RSS κύλισης κατεύθυνση</translation>\n\t<translation id=\"8382375758916799432\">Οριζόντιος</translation>\n\t<translation id=\"160958144287367985\">Κατακόρυφος</translation>\n\t<translation id=\"5576694760844259892\">RSS ταχύτητα κύλισης</translation>\n\t<translation id=\"3801245379625272309\">αργός</translation>\n\t<translation id=\"4688460977394283086\">Μεσαίο</translation>\n\t<translation id=\"9161614188045173336\">γρήγορα</translation>\n\t<translation id=\"6107231410782382609\">Σε περίπτωση προβεί στις ακόλουθες ενέργειες</translation>\n\t<translation id=\"8875363048655701399\">λειτουργία Kiosk</translation>\n\t<translation id=\"6880124786888445040\">Παίξτε συλλογής στη σειρά</translation>\n\t<translation id=\"2166463051767640100\">προσθέστε περιεχόμενο σε συλλογή</translation>\n\t<translation id=\"7365517136074263312\">κώδικα QR</translation>\n\t<translation id=\"810733191089543608\">Ενταση ΗΧΟΥ</translation>\n\t<translation id=\"4815249204085613710\">ποιότητα βίντεο</translation>\n\t<translation id=\"5082095396043563283\">περιοχή</translation>\n\t<translation id=\"396267502411280310\">περισσότερες εμφανίσεις</translation>\n\t<translation id=\"2441920677226386245\">προσαρμοσμένη λίστα</translation>\n\t<translation id=\"1223194855937061908\">αναγνωριστικά βίντεο</translation>\n\t<translation id=\"4103549354606724944\">γραμμές των πελατών</translation>\n\t<translation id=\"7262144878230347914\">χρώμα του φόντου</translation>\n\t<translation id=\"1435085881129646880\">Προεπιλεγμένη διαδοχική playlist</translation>\n\t<translation id=\"1587536276491357593\">Σύνολο με βάση την τοποθεσία:></translation>\n\t<translation id=\"3325180562659478330\">όνομα</translation>\n\t<translation id=\"3051480550159545291\">γεωγραφικό πλάτος</translation>\n\t<translation id=\"2703718513716530782\">γεωγραφικό μήκος</translation>\n\t<translation id=\"5602245631444655788\">διάρκεια</translation>\n\t<translation id=\"118487254857410201\">εύρος ακτίνας</translation>\n\t<translation id=\"9178543898761255307\">χιλιόμετρα</translation>\n\t<translation id=\"7866202877490561957\">προτεραιότητας των συγκρούσεων</translation>\n\t<translation id=\"720146333131008909\">προσθέστε περιεχόμενο σκηνή</translation>\n\t<translation id=\"8729372534532732068\">Το όνομά σκηνή</translation>\n\t<translation id=\"2224690894219674949\">λειτουργία προσομοίωσης</translation>\n\t<translation id=\"7220335122322620944\">Μάθετε περισσότερα για την Επιχείρηση</translation>\n\t<translation id=\"8444323300278462770\">μπλουζα</translation>\n\t<translation id=\"7449548947549758066\">αριστερά</translation>\n\t<translation id=\"9172672254266086971\">πλάτος</translation>\n\t<translation id=\"4093381701787958997\">ύψος</translation>\n\t<translation id=\"2062170564010556149\">περιστροφή</translation>\n\t<translation id=\"9088937454320275395\">εφαρμογή των αλλαγών</translation>\n\t<translation id=\"1870560040946711505\">κλειδωμένο</translation>\n\t<translation id=\"6108618462851148193\">συντάκτης εκστρατεία</translation>\n\t<translation id=\"2741646832903808697\">διάταξη της οθόνης</translation>\n\t<translation id=\"6454444033973204385\">επιλογή καμπάνιας</translation>\n\t<translation id=\"6028894272398949430\">νέα καμπάνια</translation>\n\t<translation id=\"3008329758802399315\">Πάρτε Οδηγός βοήθεια</translation>\n\t<translation id=\"4145364267099301397\">Επιλέξτε το όνομα της καμπάνιας σας</translation>\n\t<translation id=\"3843469504048287640\">Πληκτρολογήστε το νέο όνομα της καμπάνιας</translation>\n\t<translation id=\"4895430942430831092\">id καμπάνια:</translation>\n\t<translation id=\"1901427837939428954\">λειτουργία περιπτέρου</translation>\n\t<translation id=\"8329228391349300722\">Καμπάνια λειτουργία αναπαραγωγής:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (απλή λειτουργία):</translation>\n\t<translation id=\"4691632839818550461\">Παιχνίδι χρονοδιαγράμματα για αυτή την εκστρατεία σε μια συνεχή ροή. Είναι εύκολο στην εγκατάσταση και απλό στη χρήση</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (Προχωρημένος τρόπος λειτουργίας):</translation>\n\t<translation id=\"750837672459228230\">Παιχνίδι χρονοδιαγράμματα για την εκστρατεία αυτή μόνο σε συγκεκριμένες ώρες. Για παράδειγμα, παίξετε Timeline Ένα το πρωί και το Timeline Β βράδυ.</translation>\n\t<translation id=\"1167977099462453641\">ανάλυση της οθόνης</translation>\n\t<translation id=\"7626905534069326448\">προτεραιότητας Σύγκρουση:</translation>\n\t<translation id=\"4220765745195024064\">Διάρκεια:</translation>\n\t<translation id=\"4049333306580215724\">παίξουν μία φορά</translation>\n\t<translation id=\"7249155645987524413\">παίζουν καθημερινά</translation>\n\t<translation id=\"8568181330490588741\">παίζουν κάθε εβδομάδα</translation>\n\t<translation id=\"3408786538616090951\">Επιλέξτε τις ημέρες:</translation>\n\t<translation id=\"6324587259626414962\">Επαναλαμβάνω για να χωρέσει</translation>\n\t<translation id=\"2012264763266897754\">τυχαία σειρά</translation>\n\t<translation id=\"4324819244706823449\">διάταξη επεξεργασίας</translation>\n\t<translation id=\"5755245564638965488\">επόμενο κανάλι</translation>\n\t<translation id=\"2925036210758384238\">επιλεγμένη γραμμή</translation>\n\t<translation id=\"3601209751322374737\">υπενθύμιση μπροστά από τους ανθρώπους</translation>\n\t<translation id=\"1790884679999452685\">ανοικτό τερματικό</translation>\n\t<translation id=\"4878432943521432749\">επαναφορά της γραμμής</translation>\n\t<translation id=\"3728601907282119753\">ιδιότητες ουρά</translation>\n\t<translation id=\"2536017892630886700\">επιλεγμένο πελάτη:</translation>\n\t<translation id=\"6228967158577655533\">επαλήθευση:</translation>\n\t<translation id=\"6435015929996679472\">καλείται από:</translation>\n\t<translation id=\"8711852116268389728\">επιλογή σκηνής</translation>\n\t<translation id=\"5053705054681686956\">νέα γραμμή</translation>\n\t<translation id=\"5225640858395745699\">αφαιρέστε γραμμή</translation>\n\t<translation id=\"3116266439138367996\">συνδέσεις</translation>\n\t<translation id=\"4159874591284333337\">Powered by γωνιακή πλαίσιο της Google</translation>\n\t<translation id=\"3008186756887926107\">φορτώσουν αρχεία</translation>\n\t<translation id=\"2123171795960509943\">αφαιρώ</translation>\n\t<translation id=\"7246196759043272468\">λίστα</translation>\n\t<translation id=\"946077791002604877\">πλέγμα</translation>\n\t<translation id=\"5936943188558553659\">υποστηριζόμενα αρχεία: flv, mp4, jpg, png, swf και SVG</translation>\n\t<translation id=\"8054250976557949996\">νέα σκηνή</translation>\n\t<translation id=\"6133338617402043535\">αντίγραφο</translation>\n\t<translation id=\"1576591662761177526\">πρότυπο εισαγωγής</translation>\n\t<translation id=\"2225048990372533999\">φορτώνω πάλι</translation>\n\t<translation id=\"987425828725037788\">διεύθυνση IP</translation>\n\t<translation id=\"1646067470190508925\">Λιμάνι</translation>\n\n\t<translation id=\"8097415329769247281\">Επιλέξτε το πακέτο που είναι κατάλληλη για σας</translation>\n\n\t<translation id=\"6570363013146073520\">Ταμπλό</translation>\n\t<translation id=\"8864658120410603626\">εκστρατείες</translation>\n\t<translation id=\"2446117790692479672\">Πόροι</translation>\n\t<translation id=\"794120057687191331\">σκηνές</translation>\n\t<translation id=\"4846792506513649213\">σταθμοί</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Βοήθεια</translation>\n\t<translation id=\"6082171864197428613\">Εγκαθιστώ</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">Αποσυνδέση</translation>\n\t<translation id=\"7746065369460476808\">όνομα χρήστη ή διεύθυνση ηλεκτρονικού ταχυδρομίου</translation>\n\t<translation id=\"4809196861118879526\">Κωδικός πρόσβασης</translation>\n\t<translation id=\"9162857816822524614\">εισάγετε δύο βασικά παράγοντα</translation>\n\t<translation id=\"24227595514967590\">με το Google ελέγχου ταυτότητας</translation>\n\t<translation id=\"2001940299854753031\">Θυμήσου με</translation>\n\t<translation id=\"5872337092278414963\">Ξεχάσατε τον κωδικό</translation>\n\t<translation id=\"8246600873004586882\">άλλαξε κωδικό</translation>\n\t<translation id=\"5289326240092186479\">Η αλλαγή του ονόματος των επιχειρήσεων</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">ΠΑΛΙΟΣ ΚΩΔΙΚΟΣ</translation>\n\t<translation id=\"48285893667252664\">Νέος Κωδικός</translation>\n\t<translation id=\"6917932917401642982\">επανάληψη νέο κωδικό πρόσβασης</translation>\n\t<translation id=\"5666893431176348635\">νέα επωνυμία της επιχείρησης</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">αναβαθμίζω</translation>\n\t<translation id=\"8894542476475088437\">Ο λογαριασμός-S</translation>\n\t<translation id=\"2347724151568473592\">Γλώσσα</translation>\n\t<translation id=\"4376434433661751094\">ζωντανή συζήτηση</translation>\n\t<translation id=\"5344752701442428839\">Ιστοσελίδα</translation>\n\t<translation id=\"7108535247064136881\">Επιλέξτε τη γλώσσα σας</translation>\n\t<translation id=\"4137049537431219133\">Συνδεθείτε στο λογαριασμό σας με το εργαλείο ελέγχου ταυτότητας Google</translation>\n\t<translation id=\"4785021168351486737\">Αποθήκευση & Αποσύνδεση</translation>\n\t<translation id=\"6524180701596149125\">Απλά αποσυνδεθείτε</translation>\n\n\t<translation id=\"2503331336991669578\">Συνδεθείτε στο λογαριασμό σας</translation>\n\t<translation id=\"8359621426539146583\">Δεν έχετε λογαριασμό</translation>\n\t<translation id=\"569785428576811345\">Διάρκεια:</translation>\n\t<translation id=\"9043806075514219833\">Ωρα έναρξης:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/en.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"en\">\n\t<translation id=\"9198441993514322349\">screen orientation</translation>\n\t<translation id=\"2838690440296896849\">remote status</translation>\n\t<translation id=\"2849064100927111571\">loading...</translation>\n\t<translation id=\"7309719557896597512\">have a nice day</translation>\n\t<translation id=\"5805758016483237261\">Upgrade to Enterprise</translation>\n\t<translation id=\"7212624462478696127\">verifying access...</translation>\n\t<translation id=\"1156206314346372426\">account dashboard</translation>\n\t<translation id=\"892759319569190037\">scene background color</translation>\n\t<translation id=\"463077023711449502\">border color</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Choose format</translation>\n\t<translation id=\"8932917860978648376\">Unit</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">Styles</translation>\n\t<translation id=\"30300572504753589\">Black</translation>\n\t<translation id=\"7850674593676755019\">White</translation>\n\t<translation id=\"9011959596901584887\">Color</translation>\n\t<translation id=\"5667922561719642173\">load with scene</translation>\n\t<translation id=\"5466334165625502718\">interval</translation>\n\t<translation id=\"1128028236258747485\">play video to completion</translation>\n\t<translation id=\"3372777815572567783\">random playback</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">token</translation>\n\t<translation id=\"6262368721870308838\">create instagram access token</translation>\n\t<translation id=\"6358635099770142731\">create token</translation>\n\t<translation id=\"7499211462525828161\">Load with calendar</translation>\n\t<translation id=\"3128474301651540051\">offset range mode</translation>\n\t<translation id=\"5645011507444946232\">days before today</translation>\n\t<translation id=\"472347571959391022\">days after today</translation>\n\t<translation id=\"7382546590159708114\">start date</translation>\n\t<translation id=\"8615958092383580706\">end date</translation>\n\t<translation id=\"7824071976623180870\">Load with sheet</translation>\n\t<translation id=\"4370305429271412983\">screen name</translation>\n\t<translation id=\"7641098557273120361\">create access token</translation>\n\t<translation id=\"361150460746746781\">maintain aspect ratio</translation>\n\t<translation id=\"3046991000485970172\">RSS refresh (minutes)</translation>\n\t<translation id=\"2303401327609002516\">RSS scroll direction</translation>\n\t<translation id=\"8382375758916799432\">Horizontal</translation>\n\t<translation id=\"160958144287367985\">Vertical</translation>\n\t<translation id=\"5576694760844259892\">RSS scroll speed</translation>\n\t<translation id=\"3801245379625272309\">slow</translation>\n\t<translation id=\"4688460977394283086\">medium</translation>\n\t<translation id=\"9161614188045173336\">fast</translation>\n\t<translation id=\"6107231410782382609\">On event take the following action</translation>\n\t<translation id=\"8875363048655701399\">Kiosk mode</translation>\n\t<translation id=\"6880124786888445040\">Play collection in sequence</translation>\n\t<translation id=\"2166463051767640100\">add content to collection</translation>\n\t<translation id=\"7365517136074263312\">QR code</translation>\n\t<translation id=\"810733191089543608\">volume</translation>\n\t<translation id=\"4815249204085613710\">video quality</translation>\n\t<translation id=\"5082095396043563283\">region</translation>\n\t<translation id=\"396267502411280310\">most viewed</translation>\n\t<translation id=\"2441920677226386245\">custom list</translation>\n\t<translation id=\"1223194855937061908\">video ids</translation>\n\t<translation id=\"4103549354606724944\">customer lines</translation>\n\t<translation id=\"7262144878230347914\">background color</translation>\n\t<translation id=\"1435085881129646880\">Default sequential playlist</translation>\n\t<translation id=\"1587536276491357593\">Total location based: ></translation>\n\t<translation id=\"3325180562659478330\">name</translation>\n\t<translation id=\"3051480550159545291\">latitude</translation>\n\t<translation id=\"2703718513716530782\">longitude</translation>\n\t<translation id=\"5602245631444655788\">duration</translation>\n\t<translation id=\"118487254857410201\">radius range</translation>\n\t<translation id=\"9178543898761255307\"> kilometers</translation>\n\t<translation id=\"7866202877490561957\">conflict priority</translation>\n\t<translation id=\"720146333131008909\">add content to scene</translation>\n\t<translation id=\"8729372534532732068\">scene name</translation>\n\t<translation id=\"2224690894219674949\">simulation mode</translation>\n\t<translation id=\"7220335122322620944\">\n                Learn more about Enterprise</translation>\n\t<translation id=\"8444323300278462770\">top</translation>\n\t<translation id=\"7449548947549758066\">left</translation>\n\t<translation id=\"9172672254266086971\">width</translation>\n\t<translation id=\"4093381701787958997\">height</translation>\n\t<translation id=\"2062170564010556149\">rotation</translation>\n\t<translation id=\"9088937454320275395\">apply changes</translation>\n\t<translation id=\"1870560040946711505\">locked</translation>\n\t<translation id=\"6108618462851148193\">campaign editor</translation>\n\t<translation id=\"2741646832903808697\">screen layout</translation>\n\t<translation id=\"6454444033973204385\">campaign selection</translation>\n\t<translation id=\"6028894272398949430\">new campaign</translation>\n\t<translation id=\"3008329758802399315\">Get Wizard help</translation>\n\t<translation id=\"4145364267099301397\">Select your campaign name</translation>\n\t<translation id=\"3843469504048287640\">Enter new campaign name</translation>\n\t<translation id=\"4895430942430831092\">campaign id:</translation>\n\t<translation id=\"1901427837939428954\">kiosk mode</translation>\n\t<translation id=\"8329228391349300722\">Campaign playback mode:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (simple mode):</translation>\n\t<translation id=\"4691632839818550461\">Play timelines for this campaign in a continuous loop. It is easy to setup and simple to use</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (advanced mode):</translation>\n\t<translation id=\"750837672459228230\">Play timelines for this campaign only on specific times. For example, play Timeline A in the morning and Timeline B at night.</translation>\n\t<translation id=\"1167977099462453641\">screen resolution</translation>\n\t<translation id=\"7626905534069326448\">Conflict priority:</translation>\n\t<translation id=\"4220765745195024064\">Duration:</translation>\n\t<translation id=\"4049333306580215724\">play once</translation>\n\t<translation id=\"7249155645987524413\">play daily</translation>\n\t<translation id=\"8568181330490588741\">play weekly</translation>\n\t<translation id=\"3408786538616090951\">Select the days:</translation>\n\t<translation id=\"6324587259626414962\">repeat to fit</translation>\n\t<translation id=\"2012264763266897754\"> random order</translation>\n\t<translation id=\"4324819244706823449\">edit layout</translation>\n\t<translation id=\"5755245564638965488\">next channel</translation>\n\t<translation id=\"2925036210758384238\">selected line</translation>\n\t<translation id=\"3601209751322374737\">reminder ahead of people</translation>\n\t<translation id=\"1790884679999452685\">open terminal</translation>\n\t<translation id=\"4878432943521432749\">reset line</translation>\n\t<translation id=\"3728601907282119753\">Queue properties</translation>\n\t<translation id=\"2536017892630886700\">selected customer:</translation>\n\t<translation id=\"6228967158577655533\">verification:</translation>\n\t<translation id=\"6435015929996679472\">called by:</translation>\n\t<translation id=\"8711852116268389728\">scene selection</translation>\n\t<translation id=\"5053705054681686956\">new line</translation>\n\t<translation id=\"5225640858395745699\">remove line</translation>\n\t<translation id=\"3116266439138367996\"> links</translation>\n\t<translation id=\"4159874591284333337\">Powered by Google's Angular framework</translation>\n\t<translation id=\"3008186756887926107\">upload files</translation>\n\t<translation id=\"2123171795960509943\">remove</translation>\n\t<translation id=\"7246196759043272468\">list</translation>\n\t<translation id=\"946077791002604877\">grid</translation>\n\t<translation id=\"5936943188558553659\">supported files: flv, mp4, jpg, png, swf and svg</translation>\n\t<translation id=\"8054250976557949996\">new scene</translation>\n\t<translation id=\"6133338617402043535\">duplicate</translation>\n\t<translation id=\"1576591662761177526\">import template</translation>\n\t<translation id=\"2225048990372533999\">reload</translation>\n\t<translation id=\"987425828725037788\">ip address</translation>\n\t<translation id=\"1646067470190508925\">port</translation>\n\t<translation id=\"8097415329769247281\">Choose the package that's right for you</translation>\n\n\t<translation id=\"6570363013146073520\">Dashboard</translation>\n\t<translation id=\"8864658120410603626\">Campaigns</translation>\n\t<translation id=\"2446117790692479672\">Resources</translation>\n\t<translation id=\"794120057687191331\">Scenes</translation>\n\t<translation id=\"4846792506513649213\">Stations</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Help</translation>\n\t<translation id=\"6082171864197428613\">Install</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">Logout</translation>\n\t<translation id=\"7746065369460476808\">user name or email</translation>\n\t<translation id=\"4809196861118879526\">password</translation>\n\t<translation id=\"9162857816822524614\">enter two factor key</translation>\n\t<translation id=\"24227595514967590\">with Google authenticator</translation>\n\t<translation id=\"2001940299854753031\"> remember me</translation>\n\t<translation id=\"5872337092278414963\">forgot password</translation>\n\t<translation id=\"8246600873004586882\">change password</translation>\n\t<translation id=\"5289326240092186479\">change business name</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">old password</translation>\n\t<translation id=\"48285893667252664\">new password</translation>\n\t<translation id=\"6917932917401642982\">repeat new password</translation>\n\t<translation id=\"5666893431176348635\">new business name</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">upgrade</translation>\n\t<translation id=\"8894542476475088437\">Account-S</translation>\n\t<translation id=\"2347724151568473592\">language</translation>\n\t<translation id=\"4376434433661751094\">live chat</translation>\n\t<translation id=\"5344752701442428839\">web site</translation>\n\t<translation id=\"7108535247064136881\">Pick your language</translation>\n\t<translation id=\"4137049537431219133\"> login to your account\n                            with Google authenticator</translation>\n\t<translation id=\"4785021168351486737\">Save & Logout</translation>\n\t<translation id=\"6524180701596149125\">Just Logout</translation>\n\n\t<translation id=\"2503331336991669578\"> login to your account</translation>\n\t<translation id=\"8359621426539146583\">Don't have an account</translation>\n\t<translation id=\"569785428576811345\">Duration:</translation>\n\t<translation id=\"9043806075514219833\">Start time:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/eo.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"eo\">\n\t<translation id=\"9198441993514322349\">ekrano orientiĝo</translation>\n\t<translation id=\"2838690440296896849\">fora statuso</translation>\n\t<translation id=\"2849064100927111571\">loading ...</translation>\n\t<translation id=\"7309719557896597512\">havu bonan tagon</translation>\n\t<translation id=\"5805758016483237261\">Ĝisdatigi al Enterprise - $ 99.00 por monato</translation>\n\t<translation id=\"7212624462478696127\">kontroli aliro ...</translation>\n\t<translation id=\"1156206314346372426\">konton panelo</translation>\n\t<translation id=\"892759319569190037\">sceno fonkoloro</translation>\n\t<translation id=\"463077023711449502\">limo koloro</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Elektu formato</translation>\n\t<translation id=\"8932917860978648376\">Unueco</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">stiloj</translation>\n\t<translation id=\"30300572504753589\">Nigra</translation>\n\t<translation id=\"7850674593676755019\">Blanka</translation>\n\t<translation id=\"9011959596901584887\">koloro</translation>\n\t<translation id=\"5667922561719642173\">ŝarĝon kun sceno</translation>\n\t<translation id=\"5466334165625502718\">intervalo</translation>\n\t<translation id=\"1128028236258747485\">ludi video por kompletigo</translation>\n\t<translation id=\"3372777815572567783\">hazardaj reprodukto</translation>\n\t<translation id=\"6757770085960264448\">bildoprezento</translation>\n\t<translation id=\"6659445582099947212\">signo</translation>\n\t<translation id=\"6262368721870308838\">krei Instagram aliro ĵetono</translation>\n\t<translation id=\"6358635099770142731\">krei signo</translation>\n\t<translation id=\"7499211462525828161\">Ŝarĝon kun kalendaro</translation>\n\t<translation id=\"3128474301651540051\">ofseto gamo modon</translation>\n\t<translation id=\"5645011507444946232\">tagojn antaŭ hodiaŭ</translation>\n\t<translation id=\"472347571959391022\">tagoj post hodiaŭ</translation>\n\t<translation id=\"7382546590159708114\">komenca dato</translation>\n\t<translation id=\"8615958092383580706\">fino dato</translation>\n\t<translation id=\"7824071976623180870\">Ŝarĝon kun folio</translation>\n\t<translation id=\"4370305429271412983\">ekrano nomo</translation>\n\t<translation id=\"7641098557273120361\">krei aliro signo</translation>\n\t<translation id=\"361150460746746781\">subteni bildformato</translation>\n\t<translation id=\"3046991000485970172\">RSS refresh (minutoj)</translation>\n\t<translation id=\"2303401327609002516\">RSS ruluman direkton</translation>\n\t<translation id=\"8382375758916799432\">Horizontala</translation>\n\t<translation id=\"160958144287367985\">vertikala</translation>\n\t<translation id=\"5576694760844259892\">RSS skribrulajxon rapido</translation>\n\t<translation id=\"3801245379625272309\">malrapida</translation>\n\t<translation id=\"4688460977394283086\">meza</translation>\n\t<translation id=\"9161614188045173336\">rapida</translation>\n\t<translation id=\"6107231410782382609\">La okazaĵo prenas la sekvajn agojn</translation>\n\t<translation id=\"8875363048655701399\">kiosko modon</translation>\n\t<translation id=\"6880124786888445040\">Ludu kolekto en sinsekvo</translation>\n\t<translation id=\"2166463051767640100\">aldoni enhavon al kolekto</translation>\n\t<translation id=\"7365517136074263312\">QR kodo</translation>\n\t<translation id=\"810733191089543608\">volumo</translation>\n\t<translation id=\"4815249204085613710\">video kvalito</translation>\n\t<translation id=\"5082095396043563283\">regiono</translation>\n\t<translation id=\"396267502411280310\">pli viditaj</translation>\n\t<translation id=\"2441920677226386245\">kutimo listo</translation>\n\t<translation id=\"1223194855937061908\">video ids</translation>\n\t<translation id=\"4103549354606724944\">kliento linioj</translation>\n\t<translation id=\"7262144878230347914\">fonkoloro</translation>\n\t<translation id=\"1435085881129646880\">Defaŭlta secuencial playlist</translation>\n\t<translation id=\"1587536276491357593\">Tuta loko bazita:></translation>\n\t<translation id=\"3325180562659478330\">nomo</translation>\n\t<translation id=\"3051480550159545291\">latitudo</translation>\n\t<translation id=\"2703718513716530782\">longitudo</translation>\n\t<translation id=\"5602245631444655788\">daŭro</translation>\n\t<translation id=\"118487254857410201\">radiuso gamo</translation>\n\t<translation id=\"9178543898761255307\">kilometroj</translation>\n\t<translation id=\"7866202877490561957\">konflikto prioritato</translation>\n\t<translation id=\"720146333131008909\">aldoni enhavon al sceno</translation>\n\t<translation id=\"8729372534532732068\">sceno nomon</translation>\n\t<translation id=\"2224690894219674949\">simulado modon</translation>\n\t<translation id=\"7220335122322620944\">Lernu pli pri Enterprise</translation>\n\t<translation id=\"8444323300278462770\">supro</translation>\n\t<translation id=\"7449548947549758066\">forlasis</translation>\n\t<translation id=\"9172672254266086971\">larĝo</translation>\n\t<translation id=\"4093381701787958997\">alteco</translation>\n\t<translation id=\"2062170564010556149\">turnado</translation>\n\t<translation id=\"9088937454320275395\">apliki ŝanĝojn</translation>\n\t<translation id=\"1870560040946711505\">ŝlosita</translation>\n\t<translation id=\"6108618462851148193\">kampanjo redaktilo</translation>\n\t<translation id=\"2741646832903808697\">ekrano aranĝo</translation>\n\t<translation id=\"6454444033973204385\">kampanjo elekto</translation>\n\t<translation id=\"6028894272398949430\">nova kampanjo</translation>\n\t<translation id=\"3008329758802399315\">Akiri Sorĉisto helpo</translation>\n\t<translation id=\"4145364267099301397\">Elektu vian kampanjon nomon</translation>\n\t<translation id=\"3843469504048287640\">Entajpu novan kampanjon nomon</translation>\n\t<translation id=\"4895430942430831092\">kampanjo id:</translation>\n\t<translation id=\"1901427837939428954\">kiosko modon</translation>\n\t<translation id=\"8329228391349300722\">Kampanjo reprodukto modon:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (simpla maniero):</translation>\n\t<translation id=\"4691632839818550461\">Ludu Timelines por ĉi tiu kampanjo en kontinua ciklo. Ĝi estas facila al instalinstrukciojn kaj simpla por uzi</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (altnivela reĝimo):</translation>\n\t<translation id=\"750837672459228230\">Ludu Timelines por tiu kampanjo nur en specifaj tempoj. Ekzemple, ludi Kronologio A matene kaj Kronologio B nokto.</translation>\n\t<translation id=\"1167977099462453641\">rezolucio</translation>\n\t<translation id=\"7626905534069326448\">Konflikto prioritato:</translation>\n\t<translation id=\"4220765745195024064\">daŭro:</translation>\n\t<translation id=\"4049333306580215724\">ludi samtempe</translation>\n\t<translation id=\"7249155645987524413\">ludi ĉiutage</translation>\n\t<translation id=\"8568181330490588741\">ludi ĉiusemajne</translation>\n\t<translation id=\"3408786538616090951\">Elektu la tagoj:</translation>\n\t<translation id=\"6324587259626414962\">ripeti konveni</translation>\n\t<translation id=\"2012264763266897754\">hazarda ordo</translation>\n\t<translation id=\"4324819244706823449\">redakti aranĝo</translation>\n\t<translation id=\"5755245564638965488\">sekva kanalo</translation>\n\t<translation id=\"2925036210758384238\">elektitaj linio</translation>\n\t<translation id=\"3601209751322374737\">memorigilo antaŭ homoj</translation>\n\t<translation id=\"1790884679999452685\">malfermita terminalo</translation>\n\t<translation id=\"4878432943521432749\">reset linio</translation>\n\t<translation id=\"3728601907282119753\">atendovico ecoj</translation>\n\t<translation id=\"2536017892630886700\">elektitaj kliento:</translation>\n\t<translation id=\"6228967158577655533\">konfirmo:</translation>\n\t<translation id=\"6435015929996679472\">nomita de:</translation>\n\t<translation id=\"8711852116268389728\">sceno elekto</translation>\n\t<translation id=\"5053705054681686956\">nova linio</translation>\n\t<translation id=\"5225640858395745699\">forigi linio</translation>\n\t<translation id=\"3116266439138367996\">ligoj</translation>\n\t<translation id=\"4159874591284333337\">Funkciigita de Google Angula kadron</translation>\n\t<translation id=\"3008186756887926107\">alŝuti dosierojn</translation>\n\t<translation id=\"2123171795960509943\">forigu</translation>\n\t<translation id=\"7246196759043272468\">listo</translation>\n\t<translation id=\"946077791002604877\">krado</translation>\n\t<translation id=\"5936943188558553659\">subtenataj dosieroj: flv, mp4, jpg, png, SWF kaj svg</translation>\n\t<translation id=\"8054250976557949996\">nova sceno</translation>\n\t<translation id=\"6133338617402043535\">duobligi</translation>\n\t<translation id=\"1576591662761177526\">importado ŝablono</translation>\n\t<translation id=\"2225048990372533999\">reŝargi</translation>\n\t<translation id=\"987425828725037788\">IP-adreso</translation>\n\t<translation id=\"1646067470190508925\">haveno</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/es.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"es\">\n\t<translation id=\"9198441993514322349\">orientación de la pantalla</translation>\n\t<translation id=\"2838690440296896849\">estado remoto</translation>\n\t<translation id=\"2849064100927111571\">cargando...</translation>\n\t<translation id=\"7309719557896597512\">que tengas un buen día</translation>\n\t<translation id=\"5805758016483237261\">Actualizar a Enterprise - $ 99.00 por mes</translation>\n\t<translation id=\"7212624462478696127\">verificar el acceso ...</translation>\n\t<translation id=\"1156206314346372426\">cuenta salpicadero</translation>\n\t<translation id=\"892759319569190037\">color de fondo de escena</translation>\n\t<translation id=\"463077023711449502\">color del borde</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">elegir el formato</translation>\n\t<translation id=\"8932917860978648376\">Unidad</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">estilos</translation>\n\t<translation id=\"30300572504753589\">Negro</translation>\n\t<translation id=\"7850674593676755019\">Blanco</translation>\n\t<translation id=\"9011959596901584887\">Color</translation>\n\t<translation id=\"5667922561719642173\">carga con la escena</translation>\n\t<translation id=\"5466334165625502718\">intervalo</translation>\n\t<translation id=\"1128028236258747485\">reproducir vídeo hasta su finalización</translation>\n\t<translation id=\"3372777815572567783\">reproducción aleatoria</translation>\n\t<translation id=\"6757770085960264448\">diapositivas</translation>\n\t<translation id=\"6659445582099947212\">simbólico</translation>\n\t<translation id=\"6262368721870308838\">crear token de acceso instagram</translation>\n\t<translation id=\"6358635099770142731\">crear símbolo</translation>\n\t<translation id=\"7499211462525828161\">Cargar con el calendario</translation>\n\t<translation id=\"3128474301651540051\">compensado modo de rango</translation>\n\t<translation id=\"5645011507444946232\">días antes de hoy</translation>\n\t<translation id=\"472347571959391022\">días a partir de hoy</translation>\n\t<translation id=\"7382546590159708114\">fecha de inicio</translation>\n\t<translation id=\"8615958092383580706\">fecha final</translation>\n\t<translation id=\"7824071976623180870\">Cargar con la hoja</translation>\n\t<translation id=\"4370305429271412983\">Nombre de pantalla</translation>\n\t<translation id=\"7641098557273120361\">crear token de acceso</translation>\n\t<translation id=\"361150460746746781\">mantener la relación de aspecto</translation>\n\t<translation id=\"3046991000485970172\">RSS de actualización (minutos)</translation>\n\t<translation id=\"2303401327609002516\">RSS dirección de desplazamiento</translation>\n\t<translation id=\"8382375758916799432\">Horizontal</translation>\n\t<translation id=\"160958144287367985\">Vertical</translation>\n\t<translation id=\"5576694760844259892\">velocidad de desplazamiento RSS</translation>\n\t<translation id=\"3801245379625272309\">lento</translation>\n\t<translation id=\"4688460977394283086\">medio</translation>\n\t<translation id=\"9161614188045173336\">rápido</translation>\n\t<translation id=\"6107231410782382609\">En caso de tomar las siguientes medidas</translation>\n\t<translation id=\"8875363048655701399\">modo de pantalla completa</translation>\n\t<translation id=\"6880124786888445040\">Jugar la colección en secuencia</translation>\n\t<translation id=\"2166463051767640100\">añadir contenido a la colección</translation>\n\t<translation id=\"7365517136074263312\">Código QR</translation>\n\t<translation id=\"810733191089543608\">volumen</translation>\n\t<translation id=\"4815249204085613710\">calidad de video</translation>\n\t<translation id=\"5082095396043563283\">región</translation>\n\t<translation id=\"396267502411280310\">mas visto</translation>\n\t<translation id=\"2441920677226386245\">lista personalizada</translation>\n\t<translation id=\"1223194855937061908\">ID de vídeo</translation>\n\t<translation id=\"4103549354606724944\">líneas de clientes</translation>\n\t<translation id=\"7262144878230347914\">color de fondo</translation>\n\t<translation id=\"1435085881129646880\">lista de reproducción secuencial predeterminado</translation>\n\t<translation id=\"1587536276491357593\">Total basado ubicación:></translation>\n\t<translation id=\"3325180562659478330\">nombre</translation>\n\t<translation id=\"3051480550159545291\">latitud</translation>\n\t<translation id=\"2703718513716530782\">longitud</translation>\n\t<translation id=\"5602245631444655788\">duración</translation>\n\t<translation id=\"118487254857410201\">intervalo de radios</translation>\n\t<translation id=\"9178543898761255307\">kilómetros</translation>\n\t<translation id=\"7866202877490561957\">prioridad conflicto</translation>\n\t<translation id=\"720146333131008909\">añadir contenido a escena</translation>\n\t<translation id=\"8729372534532732068\">nombre de la escena</translation>\n\t<translation id=\"2224690894219674949\">el modo de simulación</translation>\n\t<translation id=\"7220335122322620944\">Más información sobre la empresa</translation>\n\t<translation id=\"8444323300278462770\">parte superior</translation>\n\t<translation id=\"7449548947549758066\">izquierda</translation>\n\t<translation id=\"9172672254266086971\">anchura</translation>\n\t<translation id=\"4093381701787958997\">altura</translation>\n\t<translation id=\"2062170564010556149\">rotación</translation>\n\t<translation id=\"9088937454320275395\">aplicar cambios</translation>\n\t<translation id=\"1870560040946711505\">bloqueada</translation>\n\t<translation id=\"6108618462851148193\">editor de campañas</translation>\n\t<translation id=\"2741646832903808697\">diseño de pantalla</translation>\n\t<translation id=\"6454444033973204385\">la selección de campaña</translation>\n\t<translation id=\"6028894272398949430\">nueva campaña</translation>\n\t<translation id=\"3008329758802399315\">Asistente para obtener ayuda</translation>\n\t<translation id=\"4145364267099301397\">Seleccione el nombre de la campaña</translation>\n\t<translation id=\"3843469504048287640\">Introducir nuevo nombre de la campaña</translation>\n\t<translation id=\"4895430942430831092\">ID de la campaña:</translation>\n\t<translation id=\"1901427837939428954\">modo de pantalla completa</translation>\n\t<translation id=\"8329228391349300722\">Campaña modo de reproducción:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (modo simple):</translation>\n\t<translation id=\"4691632839818550461\">Juega líneas de tiempo para esta campaña en un bucle continuo. Es fácil de configurar y fácil de usar</translation>\n\t<translation id=\"6075423017399759230\">Programador (modo avanzado):</translation>\n\t<translation id=\"750837672459228230\">Juega líneas de tiempo para esta campaña sólo en momentos específicos. Por ejemplo, jugar Cronología A en la mañana y en la noche Cronograma B.</translation>\n\t<translation id=\"1167977099462453641\">resolución de la pantalla</translation>\n\t<translation id=\"7626905534069326448\">Conflicto de prioridad:</translation>\n\t<translation id=\"4220765745195024064\">Duración:</translation>\n\t<translation id=\"4049333306580215724\">jugar una vez</translation>\n\t<translation id=\"7249155645987524413\">jugar a diario</translation>\n\t<translation id=\"8568181330490588741\">jugar semanal</translation>\n\t<translation id=\"3408786538616090951\">Seleccione los días:</translation>\n\t<translation id=\"6324587259626414962\">repetir para encajar</translation>\n\t<translation id=\"2012264763266897754\">Orden aleatorio</translation>\n\t<translation id=\"4324819244706823449\">Editar diseño</translation>\n\t<translation id=\"5755245564638965488\">siguiente canal</translation>\n\t<translation id=\"2925036210758384238\">línea seleccionada</translation>\n\t<translation id=\"3601209751322374737\">recordatorio delante de la gente</translation>\n\t<translation id=\"1790884679999452685\">terminal abierto</translation>\n\t<translation id=\"4878432943521432749\">línea de reset</translation>\n\t<translation id=\"3728601907282119753\">propiedades de la cola</translation>\n\t<translation id=\"2536017892630886700\">seleccionada por el cliente:</translation>\n\t<translation id=\"6228967158577655533\">verificación:</translation>\n\t<translation id=\"6435015929996679472\">llamado por:</translation>\n\t<translation id=\"8711852116268389728\">selección de escena</translation>\n\t<translation id=\"5053705054681686956\">nueva línea</translation>\n\t<translation id=\"5225640858395745699\">quite la línea de</translation>\n\t<translation id=\"3116266439138367996\">campo de golf</translation>\n\t<translation id=\"4159874591284333337\">Con tecnología de marco angular de Google</translation>\n\t<translation id=\"3008186756887926107\">subir archivos</translation>\n\t<translation id=\"2123171795960509943\">retirar</translation>\n\t<translation id=\"7246196759043272468\">lista</translation>\n\t<translation id=\"946077791002604877\">cuadrícula</translation>\n\t<translation id=\"5936943188558553659\">archivos soportados: FLV, MP4, JPG, PNG, SVG y SWF</translation>\n\t<translation id=\"8054250976557949996\">nueva escena</translation>\n\t<translation id=\"6133338617402043535\">duplicar</translation>\n\t<translation id=\"1576591662761177526\">plantilla de importación</translation>\n\t<translation id=\"2225048990372533999\">recargar</translation>\n\t<translation id=\"987425828725037788\">dirección IP</translation>\n\t<translation id=\"1646067470190508925\">Puerto</translation>\n\n\t<translation id=\"8097415329769247281\">Elija el paquete que sea adecuado para usted</translation>\n\n\t<translation id=\"6570363013146073520\">Tablero</translation>\n\t<translation id=\"8864658120410603626\">campañas</translation>\n\t<translation id=\"2446117790692479672\">recursos</translation>\n\t<translation id=\"794120057687191331\">escenas</translation>\n\t<translation id=\"4846792506513649213\">estaciones</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Ayuda</translation>\n\t<translation id=\"6082171864197428613\">Instalar</translation>\n\t<translation id=\"3476206505271758484\">studiopro</translation>\n\t<translation id=\"3797778920049399855\">Cerrar sesión</translation>\n\t<translation id=\"7746065369460476808\">Nombre de usuario o correo electrónico</translation>\n\t<translation id=\"4809196861118879526\">contraseña</translation>\n\t<translation id=\"9162857816822524614\">introducir dos factores clave</translation>\n\t<translation id=\"24227595514967590\">con Google autenticador</translation>\n\t<translation id=\"2001940299854753031\">Recuérdame</translation>\n\t<translation id=\"5872337092278414963\">Se te olvidó tu contraseña</translation>\n\t<translation id=\"8246600873004586882\">Cambia la contraseña</translation>\n\t<translation id=\"5289326240092186479\">cambio de nombre de la empresa</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">Contraseña anterior</translation>\n\t<translation id=\"48285893667252664\">nueva contraseña</translation>\n\t<translation id=\"6917932917401642982\">repita la nueva contraseña</translation>\n\t<translation id=\"5666893431176348635\">nuevo nombre de la empresa</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">mejorar</translation>\n\t<translation id=\"8894542476475088437\">Cuenta-S</translation>\n\t<translation id=\"2347724151568473592\">idioma</translation>\n\t<translation id=\"4376434433661751094\">chat en vivo</translation>\n\t<translation id=\"5344752701442428839\">Sitio web</translation>\n\t<translation id=\"7108535247064136881\">Escoja su idioma</translation>\n\t<translation id=\"4137049537431219133\">Inicie sesión en su cuenta con Google authenticator</translation>\n\t<translation id=\"4785021168351486737\">Guardar y cerrar sesión</translation>\n\t<translation id=\"6524180701596149125\">Solo desconectarse</translation>\n\n\t<translation id=\"2503331336991669578\">Ingrese a su cuenta</translation>\n\t<translation id=\"8359621426539146583\">No tiene una cuenta</translation>\n\t<translation id=\"569785428576811345\">Duración:</translation>\n\t<translation id=\"9043806075514219833\">Hora de inicio:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/fr.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"fr\">\n\t<translation id=\"9198441993514322349\">orientation de l'écran</translation>\n\t<translation id=\"2838690440296896849\">état à distance</translation>\n\t<translation id=\"2849064100927111571\">chargement...</translation>\n\t<translation id=\"7309719557896597512\">bonne journée</translation>\n\t<translation id=\"5805758016483237261\">Mise à niveau vers Enterprise - 99,00 $ par mois</translation>\n\t<translation id=\"7212624462478696127\">Vérification de l'accès ...</translation>\n\t<translation id=\"1156206314346372426\">tableau de bord compte</translation>\n\t<translation id=\"892759319569190037\">couleur de fond de scène</translation>\n\t<translation id=\"463077023711449502\">couleur de la bordure</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Choisissez le format</translation>\n\t<translation id=\"8932917860978648376\">Unité</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">modes</translation>\n\t<translation id=\"30300572504753589\">Noir</translation>\n\t<translation id=\"7850674593676755019\">blanc</translation>\n\t<translation id=\"9011959596901584887\">Couleur</translation>\n\t<translation id=\"5667922561719642173\">charge avec scène</translation>\n\t<translation id=\"5466334165625502718\">intervalle</translation>\n\t<translation id=\"1128028236258747485\">lire la vidéo à la fin</translation>\n\t<translation id=\"3372777815572567783\">lecture aléatoire</translation>\n\t<translation id=\"6757770085960264448\">diaporama</translation>\n\t<translation id=\"6659445582099947212\">jeton</translation>\n\t<translation id=\"6262368721870308838\">créer jeton d'accès instagram</translation>\n\t<translation id=\"6358635099770142731\">créer jeton</translation>\n\t<translation id=\"7499211462525828161\">Charge avec calendrier</translation>\n\t<translation id=\"3128474301651540051\">décalage de mode large</translation>\n\t<translation id=\"5645011507444946232\">jours avant aujourd'hui</translation>\n\t<translation id=\"472347571959391022\">jours à partir d'aujourd'hui</translation>\n\t<translation id=\"7382546590159708114\">date de début</translation>\n\t<translation id=\"8615958092383580706\">date de fin</translation>\n\t<translation id=\"7824071976623180870\">Charge avec feuille</translation>\n\t<translation id=\"4370305429271412983\">Nom de l'écran</translation>\n\t<translation id=\"7641098557273120361\">créer un jeton d'accès</translation>\n\t<translation id=\"361150460746746781\">maintenir rapport d'aspect</translation>\n\t<translation id=\"3046991000485970172\">refresh RSS (minutes)</translation>\n\t<translation id=\"2303401327609002516\">RSS Sens de défilement</translation>\n\t<translation id=\"8382375758916799432\">Horizontal</translation>\n\t<translation id=\"160958144287367985\">Verticale</translation>\n\t<translation id=\"5576694760844259892\">RSS vitesse de défilement</translation>\n\t<translation id=\"3801245379625272309\">lent</translation>\n\t<translation id=\"4688460977394283086\">moyen</translation>\n\t<translation id=\"9161614188045173336\">vite</translation>\n\t<translation id=\"6107231410782382609\">En cas prendre les mesures suivantes</translation>\n\t<translation id=\"8875363048655701399\">mode kiosque</translation>\n\t<translation id=\"6880124786888445040\">Jouer à la collection en séquence</translation>\n\t<translation id=\"2166463051767640100\">ajouter du contenu à la collection</translation>\n\t<translation id=\"7365517136074263312\">QR Code</translation>\n\t<translation id=\"810733191089543608\">le volume</translation>\n\t<translation id=\"4815249204085613710\">qualité vidéo</translation>\n\t<translation id=\"5082095396043563283\">Région</translation>\n\t<translation id=\"396267502411280310\">le plus regardé</translation>\n\t<translation id=\"2441920677226386245\">liste personnalisée</translation>\n\t<translation id=\"1223194855937061908\">ids vidéo</translation>\n\t<translation id=\"4103549354606724944\">lignes de clients</translation>\n\t<translation id=\"7262144878230347914\">Couleur de fond</translation>\n\t<translation id=\"1435085881129646880\">playlist séquentielle défaut</translation>\n\t<translation id=\"1587536276491357593\">emplacement total en fonction:></translation>\n\t<translation id=\"3325180562659478330\">prénom</translation>\n\t<translation id=\"3051480550159545291\">latitude</translation>\n\t<translation id=\"2703718513716530782\">longitude</translation>\n\t<translation id=\"5602245631444655788\">durée</translation>\n\t<translation id=\"118487254857410201\">gamme rayon</translation>\n\t<translation id=\"9178543898761255307\">kilomètres</translation>\n\t<translation id=\"7866202877490561957\">priorité des conflits</translation>\n\t<translation id=\"720146333131008909\">ajouter du contenu à la scène</translation>\n\t<translation id=\"8729372534532732068\">Nom de scène</translation>\n\t<translation id=\"2224690894219674949\">mode de simulation</translation>\n\t<translation id=\"7220335122322620944\">En savoir plus sur l'entreprise</translation>\n\t<translation id=\"8444323300278462770\">Haut</translation>\n\t<translation id=\"7449548947549758066\">la gauche</translation>\n\t<translation id=\"9172672254266086971\">largeur</translation>\n\t<translation id=\"4093381701787958997\">la taille</translation>\n\t<translation id=\"2062170564010556149\">rotation</translation>\n\t<translation id=\"9088937454320275395\">appliquer les modifications</translation>\n\t<translation id=\"1870560040946711505\">fermé à clef</translation>\n\t<translation id=\"6108618462851148193\">éditeur de campagne</translation>\n\t<translation id=\"2741646832903808697\">mise en page de l'écran</translation>\n\t<translation id=\"6454444033973204385\">sélection de la campagne</translation>\n\t<translation id=\"6028894272398949430\">nouvelle campagne</translation>\n\t<translation id=\"3008329758802399315\">Obtenez Assistant aide</translation>\n\t<translation id=\"4145364267099301397\">Sélectionnez le nom de la campagne</translation>\n\t<translation id=\"3843469504048287640\">Entrez le nouveau nom de la campagne</translation>\n\t<translation id=\"4895430942430831092\">id de la campagne:</translation>\n\t<translation id=\"1901427837939428954\">mode kiosque</translation>\n\t<translation id=\"8329228391349300722\">Campagne en mode lecture:</translation>\n\t<translation id=\"8793145092368811184\">Séquenceur (en mode simple):</translation>\n\t<translation id=\"4691632839818550461\">Jouez les délais pour cette campagne dans une boucle continue. Il est facile à installer et simple à utiliser</translation>\n\t<translation id=\"6075423017399759230\">Planificateur (mode avancé):</translation>\n\t<translation id=\"750837672459228230\">Jouez les délais pour cette campagne seulement sur des moments précis. Par exemple, jouer Timeline A le matin et Timeline B la nuit.</translation>\n\t<translation id=\"1167977099462453641\">résolution d'écran</translation>\n\t<translation id=\"7626905534069326448\">priorité des conflits:</translation>\n\t<translation id=\"4220765745195024064\">Durée:</translation>\n\t<translation id=\"4049333306580215724\">jouer une fois</translation>\n\t<translation id=\"7249155645987524413\">jouer tous les jours</translation>\n\t<translation id=\"8568181330490588741\">jouer hebdomadaire</translation>\n\t<translation id=\"3408786538616090951\">Sélectionnez les jours:</translation>\n\t<translation id=\"6324587259626414962\">répéter pour s'adapter</translation>\n\t<translation id=\"2012264763266897754\">ordre aléatoire</translation>\n\t<translation id=\"4324819244706823449\">modifier la mise en page</translation>\n\t<translation id=\"5755245564638965488\">canal suivant</translation>\n\t<translation id=\"2925036210758384238\">ligne sélectionnée</translation>\n\t<translation id=\"3601209751322374737\">rappel à l'avance les personnes</translation>\n\t<translation id=\"1790884679999452685\">borne ouverte</translation>\n\t<translation id=\"4878432943521432749\">ligne reset</translation>\n\t<translation id=\"3728601907282119753\">Propriétés de la file d'attente</translation>\n\t<translation id=\"2536017892630886700\">client sélectionné:</translation>\n\t<translation id=\"6228967158577655533\">vérification:</translation>\n\t<translation id=\"6435015929996679472\">appelé par:</translation>\n\t<translation id=\"8711852116268389728\">sélection de scène</translation>\n\t<translation id=\"5053705054681686956\">nouvelle ligne</translation>\n\t<translation id=\"5225640858395745699\">supprimer la ligne</translation>\n\t<translation id=\"3116266439138367996\">des liens</translation>\n\t<translation id=\"4159874591284333337\">Propulsé par le cadre angulaire de Google</translation>\n\t<translation id=\"3008186756887926107\">télécharger des fichiers</translation>\n\t<translation id=\"2123171795960509943\">retirer</translation>\n\t<translation id=\"7246196759043272468\">liste</translation>\n\t<translation id=\"946077791002604877\">la grille</translation>\n\t<translation id=\"5936943188558553659\">fichiers pris en charge: flv, mp4, jpg, png, swf et svg</translation>\n\t<translation id=\"8054250976557949996\">nouvelle scène</translation>\n\t<translation id=\"6133338617402043535\">dupliquer</translation>\n\t<translation id=\"1576591662761177526\">modèle d'importation</translation>\n\t<translation id=\"2225048990372533999\">recharger</translation>\n\t<translation id=\"987425828725037788\">adresse IP</translation>\n\t<translation id=\"1646067470190508925\">Port</translation>\n\n\t<translation id=\"8097415329769247281\">Choisissez le forfait qui vous convient</translation>\n\n\t<translation id=\"6570363013146073520\">Tableau de bord</translation>\n\t<translation id=\"8864658120410603626\">campagnes</translation>\n\t<translation id=\"2446117790692479672\">Ressources</translation>\n\t<translation id=\"794120057687191331\">scènes</translation>\n\t<translation id=\"4846792506513649213\">stations</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Aidez-moi</translation>\n\t<translation id=\"6082171864197428613\">Installer</translation>\n\t<translation id=\"3476206505271758484\">studiopro</translation>\n\t<translation id=\"3797778920049399855\">Connectez - Out</translation>\n\t<translation id=\"7746065369460476808\">nom d'utilisateur ou email</translation>\n\t<translation id=\"4809196861118879526\">mot de passe</translation>\n\t<translation id=\"9162857816822524614\">entrer deux facteur clé</translation>\n\t<translation id=\"24227595514967590\">avec Google Authenticator</translation>\n\t<translation id=\"2001940299854753031\">souviens-toi de moi</translation>\n\t<translation id=\"5872337092278414963\">mot de passe oublié</translation>\n\t<translation id=\"8246600873004586882\">changer le mot de passe</translation>\n\t<translation id=\"5289326240092186479\">Changer le nom de l'entreprise</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">ancien mot de passe</translation>\n\t<translation id=\"48285893667252664\">nouveau mot de passe</translation>\n\t<translation id=\"6917932917401642982\">Répété le nouveau mot de passe</translation>\n\t<translation id=\"5666893431176348635\">nouveau nom d'entreprise</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">surclassement</translation>\n\t<translation id=\"8894542476475088437\">Compte-S</translation>\n\t<translation id=\"2347724151568473592\">la langue</translation>\n\t<translation id=\"4376434433661751094\">Discussion en temps réel</translation>\n\t<translation id=\"5344752701442428839\">site Internet</translation>\n\t<translation id=\"7108535247064136881\">Choisissez votre langue</translation>\n\t<translation id=\"4137049537431219133\">Connectez-vous à votre compte avec l'authentificateur Google</translation>\n\t<translation id=\"4785021168351486737\">Enregistrer et se déconnecter</translation>\n\t<translation id=\"6524180701596149125\">Déconnexion juste</translation>\n\n\t<translation id=\"2503331336991669578\">Connectez-vous à votre compte</translation>\n\t<translation id=\"8359621426539146583\">Pas de compte</translation>\n\t<translation id=\"569785428576811345\">Durée:</translation>\n\t<translation id=\"9043806075514219833\">Heure de début:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/hi.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"hi\">\n\t<translation id=\"9198441993514322349\">स्क्रीन दिशानिर्देश</translation>\n\t<translation id=\"2838690440296896849\">दूरस्थ स्थिति</translation>\n\t<translation id=\"2849064100927111571\">लोड हो रहा है...</translation>\n\t<translation id=\"7309719557896597512\">आपका दिन शुभ हो</translation>\n\t<translation id=\"5805758016483237261\">उद्यम में अपग्रेड करें - $ 99.00 प्रति माह</translation>\n\t<translation id=\"7212624462478696127\">पहुँच की पुष्टि करने के ...</translation>\n\t<translation id=\"1156206314346372426\">खाता डैशबोर्ड</translation>\n\t<translation id=\"892759319569190037\">दृश्य पृष्ठभूमि रंग</translation>\n\t<translation id=\"463077023711449502\">किनारे का रंग</translation>\n\t<translation id=\"7844431484369877777\">यूआरएल</translation>\n\t<translation id=\"6727478076005438064\">प्रारूप चुनें</translation>\n\t<translation id=\"8932917860978648376\">इकाई</translation>\n\t<translation id=\"6447113917741810043\">फारेनहाइट</translation>\n\t<translation id=\"1546647220090341106\">सेल्सीयस</translation>\n\t<translation id=\"6977749640368501596\">शैलियाँ</translation>\n\t<translation id=\"30300572504753589\">काली</translation>\n\t<translation id=\"7850674593676755019\">सफेद</translation>\n\t<translation id=\"9011959596901584887\">रंग</translation>\n\t<translation id=\"5667922561719642173\">दृश्य के साथ लोड</translation>\n\t<translation id=\"5466334165625502718\">मध्यान्तर</translation>\n\t<translation id=\"1128028236258747485\">पूरा होने के लिए वीडियो चलाने</translation>\n\t<translation id=\"3372777815572567783\">यादृच्छिक प्लेबैक</translation>\n\t<translation id=\"6757770085960264448\">स्लाइड शो</translation>\n\t<translation id=\"6659445582099947212\">टोकन</translation>\n\t<translation id=\"6262368721870308838\">instagram पहुँच टोकन बनाने</translation>\n\t<translation id=\"6358635099770142731\">टोकन बनाने</translation>\n\t<translation id=\"7499211462525828161\">कैलेंडर के साथ लोड</translation>\n\t<translation id=\"3128474301651540051\">रेंज मोड ऑफसेट</translation>\n\t<translation id=\"5645011507444946232\">दिन पहले आज</translation>\n\t<translation id=\"472347571959391022\">दिनों के बाद आज</translation>\n\t<translation id=\"7382546590159708114\">आरंभ करने की तिथि</translation>\n\t<translation id=\"8615958092383580706\">अंतिम तिथि</translation>\n\t<translation id=\"7824071976623180870\">शीट के साथ लोड</translation>\n\t<translation id=\"4370305429271412983\">स्क्रीन नाम</translation>\n\t<translation id=\"7641098557273120361\">पहुँच टोकन बनाने</translation>\n\t<translation id=\"361150460746746781\">स्वरुप अनुपात बनायें रखें</translation>\n\t<translation id=\"3046991000485970172\">आरएसएस ताज़ा (मिनट)</translation>\n\t<translation id=\"2303401327609002516\">आरएसएस स्क्रॉल दिशा</translation>\n\t<translation id=\"8382375758916799432\">क्षैतिज</translation>\n\t<translation id=\"160958144287367985\">खड़ा</translation>\n\t<translation id=\"5576694760844259892\">आरएसएस स्क्रॉल गति</translation>\n\t<translation id=\"3801245379625272309\">धीमा</translation>\n\t<translation id=\"4688460977394283086\">मध्यम</translation>\n\t<translation id=\"9161614188045173336\">उपवास</translation>\n\t<translation id=\"6107231410782382609\">घटना पर निम्न कदम उठा</translation>\n\t<translation id=\"8875363048655701399\">किओस्क मोड</translation>\n\t<translation id=\"6880124786888445040\">अनुक्रम में संग्रह खेलते हैं</translation>\n\t<translation id=\"2166463051767640100\">समूह में सामग्री जोड़ने</translation>\n\t<translation id=\"7365517136074263312\">क्यूआर कोड</translation>\n\t<translation id=\"810733191089543608\">आयतन</translation>\n\t<translation id=\"4815249204085613710\">वीडियो की गुणवत्ता</translation>\n\t<translation id=\"5082095396043563283\">क्षेत्र</translation>\n\t<translation id=\"396267502411280310\">सबसे ज्यादा देखा गया</translation>\n\t<translation id=\"2441920677226386245\">कस्टम सूची</translation>\n\t<translation id=\"1223194855937061908\">वीडियो आईडी</translation>\n\t<translation id=\"4103549354606724944\">ग्राहक लाइनों</translation>\n\t<translation id=\"7262144878230347914\">पीछे का रंग</translation>\n\t<translation id=\"1435085881129646880\">डिफ़ॉल्ट अनुक्रमिक प्लेलिस्ट</translation>\n\t<translation id=\"1587536276491357593\">कुल स्थान आधारित:></translation>\n\t<translation id=\"3325180562659478330\">नाम</translation>\n\t<translation id=\"3051480550159545291\">अक्षांश</translation>\n\t<translation id=\"2703718513716530782\">देशान्तर</translation>\n\t<translation id=\"5602245631444655788\">अवधि</translation>\n\t<translation id=\"118487254857410201\">त्रिज्या रेंज</translation>\n\t<translation id=\"9178543898761255307\">किलोमीटर की दूरी पर</translation>\n\t<translation id=\"7866202877490561957\">संघर्ष प्राथमिकता</translation>\n\t<translation id=\"720146333131008909\">दृश्य पर सामग्री जोड़ने</translation>\n\t<translation id=\"8729372534532732068\">दृश्य नाम</translation>\n\t<translation id=\"2224690894219674949\">अनुकरण मोड</translation>\n\t<translation id=\"7220335122322620944\">Enterprise बारे में और जानें</translation>\n\t<translation id=\"8444323300278462770\">चोटी</translation>\n\t<translation id=\"7449548947549758066\">बाएं</translation>\n\t<translation id=\"9172672254266086971\">चौड़ाई</translation>\n\t<translation id=\"4093381701787958997\">ऊंचाई</translation>\n\t<translation id=\"2062170564010556149\">रोटेशन</translation>\n\t<translation id=\"9088937454320275395\">परिवर्तन लागू करें</translation>\n\t<translation id=\"1870560040946711505\">बंद</translation>\n\t<translation id=\"6108618462851148193\">अभियान संपादक</translation>\n\t<translation id=\"2741646832903808697\">स्क्रीन लेआउट</translation>\n\t<translation id=\"6454444033973204385\">अभियान चयन</translation>\n\t<translation id=\"6028894272398949430\">नया अभियान</translation>\n\t<translation id=\"3008329758802399315\">जादूगर सहायता प्राप्त करें</translation>\n\t<translation id=\"4145364267099301397\">अपने अभियान का नाम का चयन करें</translation>\n\t<translation id=\"3843469504048287640\">नए अभियान का नाम डालें</translation>\n\t<translation id=\"4895430942430831092\">अभियान आईडी:</translation>\n\t<translation id=\"1901427837939428954\">कियोस्क मोड</translation>\n\t<translation id=\"8329228391349300722\">अभियान प्लेबैक मोड:</translation>\n\t<translation id=\"8793145092368811184\">अनुक्रमक (सरल मोड):</translation>\n\t<translation id=\"4691632839818550461\">समय खेलते हैं एक सतत पाश में इस अभियान के लिए। यह सेटअप करने के लिए आसान है और उपयोग करने के लिए आसान है</translation>\n\t<translation id=\"6075423017399759230\">समयबद्धक (उन्नत मोड):</translation>\n\t<translation id=\"750837672459228230\">समय खेलते हैं केवल विशिष्ट समय पर इस अभियान के लिए। उदाहरण के लिए, रात में सुबह समय एक और समय बी खेलते हैं।</translation>\n\t<translation id=\"1167977099462453641\">स्क्रीन संकल्प</translation>\n\t<translation id=\"7626905534069326448\">संघर्ष प्राथमिकता:</translation>\n\t<translation id=\"4220765745195024064\">अवधि:</translation>\n\t<translation id=\"4049333306580215724\">एक बार खेलने</translation>\n\t<translation id=\"7249155645987524413\">दैनिक खेलने</translation>\n\t<translation id=\"8568181330490588741\">साप्ताहिक खेलने</translation>\n\t<translation id=\"3408786538616090951\">दिन का चयन करें:</translation>\n\t<translation id=\"6324587259626414962\">फिट करने के लिए दोहराने</translation>\n\t<translation id=\"2012264763266897754\">अनियमित क्रम</translation>\n\t<translation id=\"4324819244706823449\">संपादित लेआउट</translation>\n\t<translation id=\"5755245564638965488\">अगले चैनल</translation>\n\t<translation id=\"2925036210758384238\">चयनित लाइन</translation>\n\t<translation id=\"3601209751322374737\">लोगों से आगे अनुस्मारक</translation>\n\t<translation id=\"1790884679999452685\">खुला टर्मिनल</translation>\n\t<translation id=\"4878432943521432749\">रीसेट लाइन</translation>\n\t<translation id=\"3728601907282119753\">कतार गुण</translation>\n\t<translation id=\"2536017892630886700\">चयनित ग्राहक:</translation>\n\t<translation id=\"6228967158577655533\">सत्यापन:</translation>\n\t<translation id=\"6435015929996679472\">से बुलाया:</translation>\n\t<translation id=\"8711852116268389728\">दृश्य का चुनाव</translation>\n\t<translation id=\"5053705054681686956\">नई पंक्ति</translation>\n\t<translation id=\"5225640858395745699\">लाइन को दूर</translation>\n\t<translation id=\"3116266439138367996\">लिंक</translation>\n\t<translation id=\"4159874591284333337\">गूगल के कोणीय ढांचे द्वारा संचालित</translation>\n\t<translation id=\"3008186756887926107\">फाइल अपलोड करो</translation>\n\t<translation id=\"2123171795960509943\">हटाना</translation>\n\t<translation id=\"7246196759043272468\">सूची</translation>\n\t<translation id=\"946077791002604877\">जाल</translation>\n\t<translation id=\"5936943188558553659\">समर्थित फ़ाइलें: FLV, MP4, jpg, png, swf और svg</translation>\n\t<translation id=\"8054250976557949996\">नया दृश्य</translation>\n\t<translation id=\"6133338617402043535\">प्रतिलिपि</translation>\n\t<translation id=\"1576591662761177526\">आयात टेम्पलेट</translation>\n\t<translation id=\"2225048990372533999\">सीमा से अधिक लादना</translation>\n\t<translation id=\"987425828725037788\">आईपी ​​पता</translation>\n\t<translation id=\"1646067470190508925\">बंदरगाह</translation>\n\n\t<translation id=\"8097415329769247281\">पैकेज आपके लिए सही है कि चुनें</translation>\n\n\t<translation id=\"6570363013146073520\">डैशबोर्ड</translation>\n\t<translation id=\"8864658120410603626\">अभियान</translation>\n\t<translation id=\"2446117790692479672\">साधन</translation>\n\t<translation id=\"794120057687191331\">पर्दे</translation>\n\t<translation id=\"4846792506513649213\">स्टेशनों</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">मदद</translation>\n\t<translation id=\"6082171864197428613\">इंस्टॉल करें</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">लोग आउट</translation>\n\t<translation id=\"7746065369460476808\">उपयोगकर्ता का नाम या ईमेल</translation>\n\t<translation id=\"4809196861118879526\">पासवर्ड</translation>\n\t<translation id=\"9162857816822524614\">दो कारक कुंजी दर्ज करें</translation>\n\t<translation id=\"24227595514967590\">Google प्रमाणक के साथ</translation>\n\t<translation id=\"2001940299854753031\">मुझे याद रखना</translation>\n\t<translation id=\"5872337092278414963\">पासवर्ड भूल गए</translation>\n\t<translation id=\"8246600873004586882\">पासवर्ड बदलें</translation>\n\t<translation id=\"5289326240092186479\">परिवर्तन व्यवसाय के नाम</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">पुराना पासवर्ड</translation>\n\t<translation id=\"48285893667252664\">नया पासवर्ड</translation>\n\t<translation id=\"6917932917401642982\">नया पासवर्ड दोहराएँ</translation>\n\t<translation id=\"5666893431176348635\">नए व्यवसाय के नाम</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">उन्नयन</translation>\n\t<translation id=\"8894542476475088437\">खाता-एस</translation>\n\t<translation id=\"2347724151568473592\">भाषा</translation>\n\t<translation id=\"4376434433661751094\">सीधी बातचीत</translation>\n\t<translation id=\"5344752701442428839\">वेबसाइट</translation>\n\t<translation id=\"7108535247064136881\">अपनी भाषा चुनें</translation>\n\t<translation id=\"4137049537431219133\">Google authenticator के साथ अपने खाते में लॉगिन करें</translation>\n\t<translation id=\"4785021168351486737\">सहेजें और लॉगआउट</translation>\n\t<translation id=\"6524180701596149125\">बस लॉगआउट</translation>\n\n\t<translation id=\"2503331336991669578\">अपने खाते में प्रवेश करें</translation>\n\t<translation id=\"8359621426539146583\">कोई खाता नहीं है</translation>\n\t<translation id=\"569785428576811345\">अवधि:</translation>\n\t<translation id=\"9043806075514219833\">समय शुरू:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/it.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"it\">\n\t<translation id=\"9198441993514322349\">orientamento schermo</translation>\n\t<translation id=\"2838690440296896849\">stato a distanza</translation>\n\t<translation id=\"2849064100927111571\">Caricamento in corso...</translation>\n\t<translation id=\"7309719557896597512\">buona giornata</translation>\n\t<translation id=\"5805758016483237261\">Aggiornamento a Enterprise - $ 99.00 per mese</translation>\n\t<translation id=\"7212624462478696127\">verifica dell'accesso ...</translation>\n\t<translation id=\"1156206314346372426\">conto cruscotto</translation>\n\t<translation id=\"892759319569190037\">colore di scena di sfondo</translation>\n\t<translation id=\"463077023711449502\">colore del bordo</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Scegli il formato</translation>\n\t<translation id=\"8932917860978648376\">Unità</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Centigrado</translation>\n\t<translation id=\"6977749640368501596\">stili</translation>\n\t<translation id=\"30300572504753589\">Nero</translation>\n\t<translation id=\"7850674593676755019\">bianca</translation>\n\t<translation id=\"9011959596901584887\">Colore</translation>\n\t<translation id=\"5667922561719642173\">carico con scena</translation>\n\t<translation id=\"5466334165625502718\">intervallo</translation>\n\t<translation id=\"1128028236258747485\">riprodurre video fino al completamento</translation>\n\t<translation id=\"3372777815572567783\">la riproduzione casuale</translation>\n\t<translation id=\"6757770085960264448\">Presentazione</translation>\n\t<translation id=\"6659445582099947212\">gettone</translation>\n\t<translation id=\"6262368721870308838\">creare l'accesso instagram gettone</translation>\n\t<translation id=\"6358635099770142731\">creare Token</translation>\n\t<translation id=\"7499211462525828161\">Carico con il calendario</translation>\n\t<translation id=\"3128474301651540051\">Offset modo range</translation>\n\t<translation id=\"5645011507444946232\">giorni prima di oggi</translation>\n\t<translation id=\"472347571959391022\">giorni dopo oggi</translation>\n\t<translation id=\"7382546590159708114\">data d'inizio</translation>\n\t<translation id=\"8615958092383580706\">data di fine</translation>\n\t<translation id=\"7824071976623180870\">Carico con lamiera</translation>\n\t<translation id=\"4370305429271412983\">Nome della schermata</translation>\n\t<translation id=\"7641098557273120361\">creare token di accesso</translation>\n\t<translation id=\"361150460746746781\">mantenere le proporzioni</translation>\n\t<translation id=\"3046991000485970172\">RSS refresh (minuti)</translation>\n\t<translation id=\"2303401327609002516\">RSS direzione di scorrimento</translation>\n\t<translation id=\"8382375758916799432\">Orizzontale</translation>\n\t<translation id=\"160958144287367985\">Verticale</translation>\n\t<translation id=\"5576694760844259892\">velocità di scorrimento RSS</translation>\n\t<translation id=\"3801245379625272309\">lento</translation>\n\t<translation id=\"4688460977394283086\">medio</translation>\n\t<translation id=\"9161614188045173336\">veloce</translation>\n\t<translation id=\"6107231410782382609\">Sul evento intraprendere le seguenti azioni</translation>\n\t<translation id=\"8875363048655701399\">modalità Kiosk</translation>\n\t<translation id=\"6880124786888445040\">Gioca collezione in sequenza</translation>\n\t<translation id=\"2166463051767640100\">aggiungere il contenuto alla raccolta</translation>\n\t<translation id=\"7365517136074263312\">QR Code</translation>\n\t<translation id=\"810733191089543608\">volume</translation>\n\t<translation id=\"4815249204085613710\">qualità video</translation>\n\t<translation id=\"5082095396043563283\">regione</translation>\n\t<translation id=\"396267502411280310\">I più visti</translation>\n\t<translation id=\"2441920677226386245\">elenco personalizzato</translation>\n\t<translation id=\"1223194855937061908\">iD video</translation>\n\t<translation id=\"4103549354606724944\">linee dei clienti</translation>\n\t<translation id=\"7262144878230347914\">colore di sfondo</translation>\n\t<translation id=\"1435085881129646880\">playlist sequenziale predefinito</translation>\n\t<translation id=\"1587536276491357593\">Totale basato posizione:></translation>\n\t<translation id=\"3325180562659478330\">nome</translation>\n\t<translation id=\"3051480550159545291\">latitudine</translation>\n\t<translation id=\"2703718513716530782\">longitudine</translation>\n\t<translation id=\"5602245631444655788\">durata</translation>\n\t<translation id=\"118487254857410201\">gamma raggio</translation>\n\t<translation id=\"9178543898761255307\">chilometri</translation>\n\t<translation id=\"7866202877490561957\">la priorità dei conflitti</translation>\n\t<translation id=\"720146333131008909\">aggiungere il contenuto di scena</translation>\n\t<translation id=\"8729372534532732068\">nome della scena</translation>\n\t<translation id=\"2224690894219674949\">modalità di simulazione</translation>\n\t<translation id=\"7220335122322620944\">Ulteriori informazioni su Enterprise</translation>\n\t<translation id=\"8444323300278462770\">superiore</translation>\n\t<translation id=\"7449548947549758066\">sinistra</translation>\n\t<translation id=\"9172672254266086971\">larghezza</translation>\n\t<translation id=\"4093381701787958997\">altezza</translation>\n\t<translation id=\"2062170564010556149\">rotazione</translation>\n\t<translation id=\"9088937454320275395\">applica i cambiamenti</translation>\n\t<translation id=\"1870560040946711505\">bloccato</translation>\n\t<translation id=\"6108618462851148193\">editor di campagna</translation>\n\t<translation id=\"2741646832903808697\">layout dello schermo</translation>\n\t<translation id=\"6454444033973204385\">selezione della campagna</translation>\n\t<translation id=\"6028894272398949430\">nuova campagna</translation>\n\t<translation id=\"3008329758802399315\">Get guidata aiuto</translation>\n\t<translation id=\"4145364267099301397\">Selezionare il nome della campagna</translation>\n\t<translation id=\"3843469504048287640\">Inserire il nuovo nome della campagna</translation>\n\t<translation id=\"4895430942430831092\">ID campagna:</translation>\n\t<translation id=\"1901427837939428954\">modalità kiosk</translation>\n\t<translation id=\"8329228391349300722\">Campagna modalità di riproduzione:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (modalità semplice):</translation>\n\t<translation id=\"4691632839818550461\">Gioca scadenze per questa campagna in un ciclo continuo. E 'facile da installare e semplice da usare</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (modalità avanzata):</translation>\n\t<translation id=\"750837672459228230\">Gioca scadenze per questa campagna solo in orari specifici. Ad esempio, giocare Timeline Una al mattino e Timeline B durante la notte.</translation>\n\t<translation id=\"1167977099462453641\">risoluzione dello schermo</translation>\n\t<translation id=\"7626905534069326448\">priorità Conflict:</translation>\n\t<translation id=\"4220765745195024064\">Durata:</translation>\n\t<translation id=\"4049333306580215724\">giocare una volta</translation>\n\t<translation id=\"7249155645987524413\">giocare tutti i giorni</translation>\n\t<translation id=\"8568181330490588741\">gioca settimanale</translation>\n\t<translation id=\"3408786538616090951\">Selezionare i giorni:</translation>\n\t<translation id=\"6324587259626414962\">ripetere per adattarsi</translation>\n\t<translation id=\"2012264763266897754\">ordine casuale</translation>\n\t<translation id=\"4324819244706823449\">il layout di modifica</translation>\n\t<translation id=\"5755245564638965488\">canale successivo</translation>\n\t<translation id=\"2925036210758384238\">linea selezionata</translation>\n\t<translation id=\"3601209751322374737\">ricordo davanti a persone</translation>\n\t<translation id=\"1790884679999452685\">terminale aperto</translation>\n\t<translation id=\"4878432943521432749\">linea di reset</translation>\n\t<translation id=\"3728601907282119753\">proprietà della coda</translation>\n\t<translation id=\"2536017892630886700\">cliente selezionato:</translation>\n\t<translation id=\"6228967158577655533\">verifica:</translation>\n\t<translation id=\"6435015929996679472\">chiamato da:</translation>\n\t<translation id=\"8711852116268389728\">selezione scena</translation>\n\t<translation id=\"5053705054681686956\">nuova linea</translation>\n\t<translation id=\"5225640858395745699\">rimuovere la linea</translation>\n\t<translation id=\"3116266439138367996\">link</translation>\n\t<translation id=\"4159874591284333337\">Realizzato da quadro angolare di Google</translation>\n\t<translation id=\"3008186756887926107\">caricare files</translation>\n\t<translation id=\"2123171795960509943\">rimuovere</translation>\n\t<translation id=\"7246196759043272468\">elenco</translation>\n\t<translation id=\"946077791002604877\">griglia</translation>\n\t<translation id=\"5936943188558553659\">file supportati: flv, mp4, jpg, png, swf e SVG</translation>\n\t<translation id=\"8054250976557949996\">nuova scena</translation>\n\t<translation id=\"6133338617402043535\">duplicare</translation>\n\t<translation id=\"1576591662761177526\">modello di importazione</translation>\n\t<translation id=\"2225048990372533999\">ricaricare</translation>\n\t<translation id=\"987425828725037788\">indirizzo IP</translation>\n\t<translation id=\"1646067470190508925\">porta</translation>\n\n\t<translation id=\"8097415329769247281\">Scegliete il pacchetto che fa per te</translation>\n\n\t<translation id=\"6570363013146073520\">Cruscotto</translation>\n\t<translation id=\"8864658120410603626\">campagne</translation>\n\t<translation id=\"2446117790692479672\">risorse</translation>\n\t<translation id=\"794120057687191331\">scene</translation>\n\t<translation id=\"4846792506513649213\">Stazioni</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Aiuto</translation>\n\t<translation id=\"6082171864197428613\">Installare</translation>\n\t<translation id=\"3476206505271758484\">StudioPro</translation>\n\t<translation id=\"3797778920049399855\">Logout</translation>\n\t<translation id=\"7746065369460476808\">nome utente o email</translation>\n\t<translation id=\"4809196861118879526\">parola d'ordine</translation>\n\t<translation id=\"9162857816822524614\">inserire due fattore chiave</translation>\n\t<translation id=\"24227595514967590\">con Google Authenticator</translation>\n\t<translation id=\"2001940299854753031\">Ricordati di me</translation>\n\t<translation id=\"5872337092278414963\">Ha dimenticato la password</translation>\n\t<translation id=\"8246600873004586882\">cambia la password</translation>\n\t<translation id=\"5289326240092186479\">cambiamento di ragione sociale</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">vecchia password</translation>\n\t<translation id=\"48285893667252664\">nuova password</translation>\n\t<translation id=\"6917932917401642982\">ripetere la nuova password</translation>\n\t<translation id=\"5666893431176348635\">nuova ragione sociale</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">aggiornamento</translation>\n\t<translation id=\"8894542476475088437\">Account-S</translation>\n\t<translation id=\"2347724151568473592\">Lingua</translation>\n\t<translation id=\"4376434433661751094\">chat dal vivo</translation>\n\t<translation id=\"5344752701442428839\">Sito web</translation>\n\t<translation id=\"7108535247064136881\">Scegli la tua lingua</translation>\n\t<translation id=\"4137049537431219133\">Accedi al tuo account con l'autenticatore di Google</translation>\n\t<translation id=\"4785021168351486737\">Salva & disconnetti</translation>\n\t<translation id=\"6524180701596149125\">Appena uscire</translation>\n\n\t<translation id=\"2503331336991669578\">Accedi al tuo account</translation>\n\t<translation id=\"8359621426539146583\">Non hai un account</translation>\n\t<translation id=\"569785428576811345\">Durata:</translation>\n\t<translation id=\"9043806075514219833\">Ora di inizio:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/iw.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"iw\">\n\t<translation id=\"9198441993514322349\">כיוון המסך</translation>\n\t<translation id=\"2838690440296896849\">מצב מרחוק</translation>\n\t<translation id=\"7309719557896597512\">שֶׁיִּהְיֶה לְךָ יוֹם טוֹב</translation>\n\t<translation id=\"5805758016483237261\">שדרג Enterprise - 99.00 $ לחודש</translation>\n\t<translation id=\"1156206314346372426\">שליטה של ​​חשבון</translation>\n\t<translation id=\"892759319569190037\">צבע רקע הסצנה</translation>\n\t<translation id=\"463077023711449502\">צבע גבול</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">בחר בפורמט</translation>\n\t<translation id=\"8932917860978648376\">יחידה</translation>\n\t<translation id=\"6447113917741810043\">פרנהייט</translation>\n\t<translation id=\"1546647220090341106\">צֶלסִיוּס</translation>\n\t<translation id=\"6977749640368501596\">סגנונות</translation>\n\t<translation id=\"30300572504753589\">שָׁחוֹר</translation>\n\t<translation id=\"7850674593676755019\">לבן</translation>\n\t<translation id=\"9011959596901584887\">צֶבַע</translation>\n\t<translation id=\"5667922561719642173\">עומס עם סצנה</translation>\n\t<translation id=\"5466334165625502718\">הַפסָקָה</translation>\n\t<translation id=\"1128028236258747485\">לנגן וידאו להשלמה</translation>\n\t<translation id=\"3372777815572567783\">השמעה אקראית</translation>\n\t<translation id=\"6757770085960264448\">מצגת</translation>\n\t<translation id=\"6659445582099947212\">אֲסִימוֹן</translation>\n\t<translation id=\"6262368721870308838\">ליצור אסימון גישה אינסטגרם</translation>\n\t<translation id=\"6358635099770142731\">ליצור אסימון</translation>\n\t<translation id=\"7499211462525828161\">טענתי עם לוח שנה</translation>\n\t<translation id=\"3128474301651540051\">לקזז מצב טווח</translation>\n\t<translation id=\"5645011507444946232\">ימים לפני היום</translation>\n\t<translation id=\"472347571959391022\">ימים לאחר היום</translation>\n\t<translation id=\"7382546590159708114\">תאריך התחלה</translation>\n\t<translation id=\"8615958092383580706\">תאריך סיום</translation>\n\t<translation id=\"7824071976623180870\">טען גיליון</translation>\n\t<translation id=\"4370305429271412983\">שם מסך</translation>\n\t<translation id=\"7641098557273120361\">ליצור אסימון גישה</translation>\n\t<translation id=\"361150460746746781\">לשמור על פרופורציות</translation>\n\t<translation id=\"3046991000485970172\">רענון RSS (דקות)</translation>\n\t<translation id=\"2303401327609002516\">כיוון הגלילה RSS</translation>\n\t<translation id=\"8382375758916799432\">אופקי</translation>\n\t<translation id=\"160958144287367985\">אֲנָכִי</translation>\n\t<translation id=\"5576694760844259892\">מהירות הגלילה RSS</translation>\n\t<translation id=\"3801245379625272309\">לְהַאֵט</translation>\n\t<translation id=\"4688460977394283086\">בינוני</translation>\n\t<translation id=\"9161614188045173336\">מָהִיר</translation>\n\t<translation id=\"6107231410782382609\">ביום האירוע את הפעולה הבאה</translation>\n\t<translation id=\"8875363048655701399\">מצב קיוסק</translation>\n\t<translation id=\"6880124786888445040\">שחק אוסף ברצף</translation>\n\t<translation id=\"2166463051767640100\">להוסיף תוכן לאוסף</translation>\n\t<translation id=\"7365517136074263312\">קוד QR</translation>\n\t<translation id=\"810733191089543608\">כֶּרֶך</translation>\n\t<translation id=\"4815249204085613710\">איכות וידאו</translation>\n\t<translation id=\"5082095396043563283\">אזור</translation>\n\t<translation id=\"396267502411280310\">הכי נצפה</translation>\n\t<translation id=\"2441920677226386245\">רשימה מותאמת אישית</translation>\n\t<translation id=\"1223194855937061908\">מזהי וידאו</translation>\n\t<translation id=\"4103549354606724944\">קווי לקוחות</translation>\n\t<translation id=\"7262144878230347914\">צבע רקע</translation>\n\t<translation id=\"1435085881129646880\">רשימת השמעה רציפה ברירה</translation>\n\t<translation id=\"1587536276491357593\">סה\"כ מיקום מבוסס:></translation>\n\t<translation id=\"3325180562659478330\">שֵׁם</translation>\n\t<translation id=\"3051480550159545291\">קו רוחב</translation>\n\t<translation id=\"2703718513716530782\">האורך</translation>\n\t<translation id=\"5602245631444655788\">מֶשֶׁך</translation>\n\t<translation id=\"118487254857410201\">טווח רדיוס</translation>\n\t<translation id=\"9178543898761255307\">קילומטרים</translation>\n\t<translation id=\"7866202877490561957\">עדיפות הסכסוך</translation>\n\t<translation id=\"720146333131008909\">להוסיף תוכן הסצנה</translation>\n\t<translation id=\"8729372534532732068\">שם סצנה</translation>\n\t<translation id=\"2224690894219674949\">מצב סימולציה</translation>\n\t<translation id=\"7220335122322620944\">למידע נוסף על החברה</translation>\n\t<translation id=\"8444323300278462770\">חלק עליון</translation>\n\t<translation id=\"7449548947549758066\">שמאלה</translation>\n\t<translation id=\"9172672254266086971\">רוֹחַב</translation>\n\t<translation id=\"4093381701787958997\">גוֹבַה</translation>\n\t<translation id=\"2062170564010556149\">רוֹטַציָה</translation>\n\t<translation id=\"9088937454320275395\">החל שינויים</translation>\n\t<translation id=\"1870560040946711505\">נָעוּל</translation>\n\t<translation id=\"6108618462851148193\">עורך מסע פרסום</translation>\n\t<translation id=\"2741646832903808697\">פריסת מסך</translation>\n\t<translation id=\"6454444033973204385\">בחירה בקמפיין</translation>\n\t<translation id=\"6028894272398949430\">קמפיין חדש</translation>\n\t<translation id=\"3008329758802399315\">קבל עזרה אשפית</translation>\n\t<translation id=\"4145364267099301397\">בחר את שם מסע הפרסום</translation>\n\t<translation id=\"3843469504048287640\">הזן את שם מסע חדש</translation>\n\t<translation id=\"4895430942430831092\">id הקמפיין:</translation>\n\t<translation id=\"1901427837939428954\">מצב קיוסק</translation>\n\t<translation id=\"8329228391349300722\">קמפיין מצב השמעה:</translation>\n\t<translation id=\"8793145092368811184\">ברצף (מצב פשוט):</translation>\n\t<translation id=\"4691632839818550461\">שחק צירי זמן לקמפיין זה בלולאה רציפה. זה קל להתקנה וקל לשימוש</translation>\n\t<translation id=\"6075423017399759230\">מתזמן (מצב מתקדם):</translation>\n\t<translation id=\"750837672459228230\">שחק צירי זמן עבור הקמפיין הזה רק על פי המבוקש. לדוגמה, לשחק Timeline א 'בבוקר Timeline B בלילה.</translation>\n\t<translation id=\"1167977099462453641\">רזולוציית מסך</translation>\n\t<translation id=\"7626905534069326448\">עדיפות הסכסוך:</translation>\n\t<translation id=\"4220765745195024064\">מֶשֶׁך:</translation>\n\t<translation id=\"4049333306580215724\">לשחק פעם</translation>\n\t<translation id=\"7249155645987524413\">לשחק יומי</translation>\n\t<translation id=\"8568181330490588741\">לשחק שבועי</translation>\n\t<translation id=\"3408786538616090951\">בחר את הימים:</translation>\n\t<translation id=\"6324587259626414962\">לחזור על כך שיתאים</translation>\n\t<translation id=\"2012264763266897754\">סדר אקראי</translation>\n\t<translation id=\"4324819244706823449\">ערוך פריסה</translation>\n\t<translation id=\"5755245564638965488\">לערוץ הבא</translation>\n\t<translation id=\"2925036210758384238\">קו נבחר</translation>\n\t<translation id=\"3601209751322374737\">תזכורת והקדים</translation>\n\t<translation id=\"1790884679999452685\">מסוף פתוח</translation>\n\t<translation id=\"4878432943521432749\">קו איפוס</translation>\n\t<translation id=\"3728601907282119753\">מאפייני תור</translation>\n\t<translation id=\"2536017892630886700\">לקוחות נבחרים:</translation>\n\t<translation id=\"6228967158577655533\">אימות:</translation>\n\t<translation id=\"6435015929996679472\">נקרא על ידי:</translation>\n\t<translation id=\"8711852116268389728\">זירת בחירה</translation>\n\t<translation id=\"5053705054681686956\">שורה חדשה</translation>\n\t<translation id=\"5225640858395745699\">להסרת קו</translation>\n\t<translation id=\"3116266439138367996\">קישורים</translation>\n\t<translation id=\"4159874591284333337\">Powered by מסגרת זוויתית של גוגל</translation>\n\t<translation id=\"3008186756887926107\">להעלות קבצים</translation>\n\t<translation id=\"2123171795960509943\">לְהַסִיר</translation>\n\t<translation id=\"7246196759043272468\">רשימה</translation>\n\t<translation id=\"946077791002604877\">רֶשֶׁת</translation>\n\t<translation id=\"5936943188558553659\">קבצים נתמכים: FLV, MP4, JPG, PNG, SWF ו- SVG</translation>\n\t<translation id=\"8054250976557949996\">סצנה חדשה</translation>\n\t<translation id=\"6133338617402043535\">לְשַׁכְפֵּל</translation>\n\t<translation id=\"1576591662761177526\">תבנית יבוא</translation>\n\t<translation id=\"2225048990372533999\">לִטעוֹן מִחָדָשׁ</translation>\n\t<translation id=\"987425828725037788\">כתובת ה - IP</translation>\n\t<translation id=\"1646067470190508925\">נָמָל</translation>\n\n\t<translation id=\"8097415329769247281\">בחר את החבילה המתאימה לך</translation>\n\n\t<translation id=\"4809196861118879526\">סיסמה</translation>\n\t<translation id=\"9162857816822524614\">יש להזין שני מפתח גורם</translation>\n\t<translation id=\"24227595514967590\">עם מאמת Google</translation>\n\t<translation id=\"2001940299854753031\">זכור אותי</translation>\n\t<translation id=\"5872337092278414963\">שכחת את הסיסמא</translation>\n\t<translation id=\"8246600873004586882\">שנה סיסמא</translation>\n\t<translation id=\"5289326240092186479\">שם עסק שינוי</translation>\n\t<translation id=\"867339644855996577\">סיסמה ישנה</translation>\n\t<translation id=\"48285893667252664\">סיסמה חדשה</translation>\n\t<translation id=\"6917932917401642982\">חזור על סיסמה חדשה</translation>\n\t<translation id=\"5666893431176348635\">שם עסק חדש</translation>\n\n\t<translation id=\"2446117790692479672\">אֶמְצָעִי</translation>\n\t<translation id=\"2849064100927111571\">טוען...</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"7212624462478696127\">אימות גישה ...</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"6570363013146073520\">לוּחַ מַחווָנִים</translation>\n\t<translation id=\"8864658120410603626\">קמפיינים</translation>\n\t<translation id=\"794120057687191331\">קלעים</translation>\n\t<translation id=\"4846792506513649213\">תחנות</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">עֶזרָה</translation>\n\t<translation id=\"6082171864197428613\">להתקין</translation>\n\t<translation id=\"3476206505271758484\">StudioPro</translation>\n\t<translation id=\"3797778920049399855\">להתנתק</translation>\n\t<translation id=\"7746065369460476808\">שם משתמש או דוא\"ל</translation>\n\n\t<translation id=\"4010072142461558046\">לשדרג</translation>\n\t<translation id=\"8894542476475088437\">חשבון-S</translation>\n\t<translation id=\"2347724151568473592\">שפה</translation>\n\t<translation id=\"4376434433661751094\">צ'אט חי</translation>\n\t<translation id=\"5344752701442428839\">אתר אינטרנט</translation>\n\t<translation id=\"7108535247064136881\">בחר את השפה שלך</translation>\n\t<translation id=\"4137049537431219133\">היכנס לחשבון שלך באמצעות Google authenticator</translation>\n\t<translation id=\"4785021168351486737\">שמור & התנתקות</translation>\n\t<translation id=\"6524180701596149125\">רק התנתקות</translation>\n\n\t<translation id=\"2503331336991669578\">התחבר לחשבון שלך</translation>\n\t<translation id=\"8359621426539146583\">אין לך חשבון</translation>\n\t<translation id=\"569785428576811345\">מֶשֶׁך:</translation>\n\t<translation id=\"9043806075514219833\">שעת התחלה:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/ja.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"ja\">\n\t<translation id=\"9198441993514322349\">画面の向き</translation>\n\t<translation id=\"2838690440296896849\">リモート状態</translation>\n\t<translation id=\"2849064100927111571\">読み込んでいます...</translation>\n\t<translation id=\"7309719557896597512\">良い一日を</translation>\n\t<translation id=\"5805758016483237261\">Enterpriseへのアップグレード - 月額$ 99.00</translation>\n\t<translation id=\"7212624462478696127\">アクセスを確認しています...</translation>\n\t<translation id=\"1156206314346372426\">アカウントのダッシュボード</translation>\n\t<translation id=\"892759319569190037\">シーンの背景色</translation>\n\t<translation id=\"463077023711449502\">境界線の色</translation>\n\t<translation id=\"7844431484369877777\">URL</translation>\n\t<translation id=\"6727478076005438064\">形式を選択してください</translation>\n\t<translation id=\"8932917860978648376\">単位</translation>\n\t<translation id=\"6447113917741810043\">華氏</translation>\n\t<translation id=\"1546647220090341106\">摂氏</translation>\n\t<translation id=\"6977749640368501596\">スタイル</translation>\n\t<translation id=\"30300572504753589\">ブラック</translation>\n\t<translation id=\"7850674593676755019\">白</translation>\n\t<translation id=\"9011959596901584887\">色</translation>\n\t<translation id=\"5667922561719642173\">シーンにロード</translation>\n\t<translation id=\"5466334165625502718\">間隔</translation>\n\t<translation id=\"1128028236258747485\">完了までのビデオを再生</translation>\n\t<translation id=\"3372777815572567783\">ランダム再生</translation>\n\t<translation id=\"6757770085960264448\">スライドショー</translation>\n\t<translation id=\"6659445582099947212\">トークン</translation>\n\t<translation id=\"6262368721870308838\">Instagramのアクセストークンを作成します</translation>\n\t<translation id=\"6358635099770142731\">トークンを作成します</translation>\n\t<translation id=\"7499211462525828161\">カレンダー付きロード</translation>\n\t<translation id=\"3128474301651540051\">オフセットレンジモード</translation>\n\t<translation id=\"5645011507444946232\">今日の前の日</translation>\n\t<translation id=\"472347571959391022\">日後の今日</translation>\n\t<translation id=\"7382546590159708114\">開始日</translation>\n\t<translation id=\"8615958092383580706\">終了日</translation>\n\t<translation id=\"7824071976623180870\">シートとロード</translation>\n\t<translation id=\"4370305429271412983\">ハンドルネーム</translation>\n\t<translation id=\"7641098557273120361\">アクセストークンを作成します</translation>\n\t<translation id=\"361150460746746781\">アスペクト比を維持</translation>\n\t<translation id=\"3046991000485970172\">RSSの更新（分）</translation>\n\t<translation id=\"2303401327609002516\">RSSスクロール方向</translation>\n\t<translation id=\"8382375758916799432\">水平な</translation>\n\t<translation id=\"160958144287367985\">垂直</translation>\n\t<translation id=\"5576694760844259892\">RSSスクロール速度</translation>\n\t<translation id=\"3801245379625272309\">スロー</translation>\n\t<translation id=\"4688460977394283086\">中</translation>\n\t<translation id=\"9161614188045173336\">速いです</translation>\n\t<translation id=\"6107231410782382609\">イベントには、次の行動を取ります</translation>\n\t<translation id=\"8875363048655701399\">キオスクモード</translation>\n\t<translation id=\"6880124786888445040\">順序でコレクションを再生します</translation>\n\t<translation id=\"2166463051767640100\">コレクションにコンテンツを追加</translation>\n\t<translation id=\"7365517136074263312\">QRコード</translation>\n\t<translation id=\"810733191089543608\">ボリューム</translation>\n\t<translation id=\"4815249204085613710\">ビデオ品質</translation>\n\t<translation id=\"5082095396043563283\">領域</translation>\n\t<translation id=\"396267502411280310\">最も見られました</translation>\n\t<translation id=\"2441920677226386245\">カスタムリスト</translation>\n\t<translation id=\"1223194855937061908\">動画ID</translation>\n\t<translation id=\"4103549354606724944\">顧客回線</translation>\n\t<translation id=\"7262144878230347914\">背景色</translation>\n\t<translation id=\"1435085881129646880\">デフォルトのシーケンシャルプレイリスト</translation>\n\t<translation id=\"1587536276491357593\">総ロケーションベース：></translation>\n\t<translation id=\"3325180562659478330\">名</translation>\n\t<translation id=\"3051480550159545291\">緯度</translation>\n\t<translation id=\"2703718513716530782\">経度</translation>\n\t<translation id=\"5602245631444655788\">期間</translation>\n\t<translation id=\"118487254857410201\">半径範囲</translation>\n\t<translation id=\"9178543898761255307\">キロメートル</translation>\n\t<translation id=\"7866202877490561957\">競合の優先順位</translation>\n\t<translation id=\"720146333131008909\">シーンにコンテンツを追加</translation>\n\t<translation id=\"8729372534532732068\">シーン名</translation>\n\t<translation id=\"2224690894219674949\">シミュレーションモード</translation>\n\t<translation id=\"7220335122322620944\">エンタープライズ詳細については、こちらをご覧ください</translation>\n\t<translation id=\"8444323300278462770\">上</translation>\n\t<translation id=\"7449548947549758066\">左</translation>\n\t<translation id=\"9172672254266086971\">幅</translation>\n\t<translation id=\"4093381701787958997\">高さ</translation>\n\t<translation id=\"2062170564010556149\">回転</translation>\n\t<translation id=\"9088937454320275395\">変更を適用</translation>\n\t<translation id=\"1870560040946711505\">ロック</translation>\n\t<translation id=\"6108618462851148193\">キャンペーンエディタ</translation>\n\t<translation id=\"2741646832903808697\">画面レイアウト</translation>\n\t<translation id=\"6454444033973204385\">キャンペーンの選択</translation>\n\t<translation id=\"6028894272398949430\">新しいキャンペーン</translation>\n\t<translation id=\"3008329758802399315\">ウィザードのヘルプを表示</translation>\n\t<translation id=\"4145364267099301397\">キャンペーン名を選択</translation>\n\t<translation id=\"3843469504048287640\">新しいキャンペーン名を入力してください</translation>\n\t<translation id=\"4895430942430831092\">キャンペーンID：</translation>\n\t<translation id=\"1901427837939428954\">キオスクモード</translation>\n\t<translation id=\"8329228391349300722\">キャンペーンの再生モード：</translation>\n\t<translation id=\"8793145092368811184\">シーケンサー（シンプルモード）：</translation>\n\t<translation id=\"4691632839818550461\">連続ループでこのキャンペーンのためのタイムラインを再生します。これは、セットアップが簡単で、使用するのは簡単です</translation>\n\t<translation id=\"6075423017399759230\">スケジューラ（アドバンストモード）：</translation>\n\t<translation id=\"750837672459228230\">唯一の特定の時間に、このキャンペーンのためのタイムラインを再生します。例えば、夜に朝のタイムラインAとBのタイムラインを再生します。</translation>\n\t<translation id=\"1167977099462453641\">画面の解像度</translation>\n\t<translation id=\"7626905534069326448\">紛争の優先順位：</translation>\n\t<translation id=\"4220765745195024064\">所要時間：</translation>\n\t<translation id=\"4049333306580215724\">一度遊びます</translation>\n\t<translation id=\"7249155645987524413\">毎日遊びます</translation>\n\t<translation id=\"8568181330490588741\">毎週プレー</translation>\n\t<translation id=\"3408786538616090951\">日を選択：</translation>\n\t<translation id=\"6324587259626414962\">合わせて繰り返し</translation>\n\t<translation id=\"2012264763266897754\">順不同</translation>\n\t<translation id=\"4324819244706823449\">編集レイアウト</translation>\n\t<translation id=\"5755245564638965488\">次のチャンネル</translation>\n\t<translation id=\"2925036210758384238\">選択された行</translation>\n\t<translation id=\"3601209751322374737\">先に人のリマインダー</translation>\n\t<translation id=\"1790884679999452685\">開放端子</translation>\n\t<translation id=\"4878432943521432749\">リセットライン</translation>\n\t<translation id=\"3728601907282119753\">キューのプロパティ</translation>\n\t<translation id=\"2536017892630886700\">選択した顧客：</translation>\n\t<translation id=\"6228967158577655533\">検証：</translation>\n\t<translation id=\"6435015929996679472\">によって呼び出さ：</translation>\n\t<translation id=\"8711852116268389728\">シーン選択</translation>\n\t<translation id=\"5053705054681686956\">改行</translation>\n\t<translation id=\"5225640858395745699\">行を削除</translation>\n\t<translation id=\"3116266439138367996\">リンク</translation>\n\t<translation id=\"4159874591284333337\">Googleの角度フレームワークを搭載</translation>\n\t<translation id=\"3008186756887926107\">ファイルをアップロード</translation>\n\t<translation id=\"2123171795960509943\">取り除きます</translation>\n\t<translation id=\"7246196759043272468\">リスト</translation>\n\t<translation id=\"946077791002604877\">グリッド</translation>\n\t<translation id=\"5936943188558553659\">サポートファイル：FLV、MP4、JPG、PNG、SWFおよびSVG</translation>\n\t<translation id=\"8054250976557949996\">新しいシーン</translation>\n\t<translation id=\"6133338617402043535\">複写</translation>\n\t<translation id=\"1576591662761177526\">インポートテンプレート</translation>\n\t<translation id=\"2225048990372533999\">リロード</translation>\n\t<translation id=\"987425828725037788\">IPアドレス</translation>\n\t<translation id=\"1646067470190508925\">ポート</translation>\n\n\t<translation id=\"8097415329769247281\">あなたにぴったりのパッケージを選択します。</translation>\n\n\t<translation id=\"6570363013146073520\">計器盤</translation>\n\t<translation id=\"8864658120410603626\">キャンペーン</translation>\n\t<translation id=\"2446117790692479672\">リソース</translation>\n\t<translation id=\"794120057687191331\">シーン</translation>\n\t<translation id=\"4846792506513649213\">駅</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">助けて</translation>\n\t<translation id=\"6082171864197428613\">インストール</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">ログアウト</translation>\n\t<translation id=\"7746065369460476808\">ユーザー名または電子メール</translation>\n\t<translation id=\"4809196861118879526\">パスワード</translation>\n\t<translation id=\"9162857816822524614\">2つのファクタキーを入力してください</translation>\n\t<translation id=\"24227595514967590\">Google認証付き</translation>\n\t<translation id=\"2001940299854753031\">私を覚えてますか</translation>\n\t<translation id=\"5872337092278414963\">パスワードをお忘れですか</translation>\n\t<translation id=\"8246600873004586882\">パスワードを変更する</translation>\n\t<translation id=\"5289326240092186479\">変更の事業名</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">以前のパスワード</translation>\n\t<translation id=\"48285893667252664\">新しいパスワード</translation>\n\t<translation id=\"6917932917401642982\">新しいパスワードを繰り返して</translation>\n\t<translation id=\"5666893431176348635\">新規事業名</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">アップグレード</translation>\n\t<translation id=\"8894542476475088437\">アカウント-S</translation>\n\t<translation id=\"2347724151568473592\">言語</translation>\n\t<translation id=\"4376434433661751094\">ライブチャット</translation>\n\t<translation id=\"5344752701442428839\">ウェブサイト</translation>\n\t<translation id=\"7108535247064136881\">あなたの言語を選んでください</translation>\n\t<translation id=\"4137049537431219133\">Google認証ツールでアカウントにログインする</translation>\n\t<translation id=\"4785021168351486737\">セーブ＆ログアウト</translation>\n\t<translation id=\"6524180701596149125\">ちょうどログアウト</translation>\n\n\t<translation id=\"2503331336991669578\">あなたのアカウントにログイン</translation>\n\t<translation id=\"8359621426539146583\">アカウントを持っていない</translation>\n\t<translation id=\"569785428576811345\">期間：</translation>\n\t<translation id=\"9043806075514219833\">始まる時間：</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/ko.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"ko\">\n\t<translation id=\"9198441993514322349\">화면 방향</translation>\n\t<translation id=\"2838690440296896849\">원격 상태</translation>\n\t<translation id=\"2849064100927111571\">로드 중 ...</translation>\n\t<translation id=\"7309719557896597512\">좋은 하루 되세요</translation>\n\t<translation id=\"5805758016483237261\">엔터프라이즈 업그레이드 - 한달에 $ 99.00</translation>\n\t<translation id=\"7212624462478696127\">액세스를 확인 ...</translation>\n\t<translation id=\"1156206314346372426\">계정 대시 보드</translation>\n\t<translation id=\"892759319569190037\">장면의 배경 색상</translation>\n\t<translation id=\"463077023711449502\">테두리 색상</translation>\n\t<translation id=\"7844431484369877777\">URL</translation>\n\t<translation id=\"6727478076005438064\">형식을 선택합니다</translation>\n\t<translation id=\"8932917860978648376\">단위</translation>\n\t<translation id=\"6447113917741810043\">화씨</translation>\n\t<translation id=\"1546647220090341106\">섭씨</translation>\n\t<translation id=\"6977749640368501596\">스타일</translation>\n\t<translation id=\"30300572504753589\">검은</translation>\n\t<translation id=\"7850674593676755019\">화이트</translation>\n\t<translation id=\"9011959596901584887\">색깔</translation>\n\t<translation id=\"5667922561719642173\">장면로드</translation>\n\t<translation id=\"5466334165625502718\">간격</translation>\n\t<translation id=\"1128028236258747485\">완료 비디오를 재생</translation>\n\t<translation id=\"3372777815572567783\">임의 재생</translation>\n\t<translation id=\"6757770085960264448\">슬라이드 쇼</translation>\n\t<translation id=\"6659445582099947212\">토큰</translation>\n\t<translation id=\"6262368721870308838\">인스 타 그램 액세스 토큰을 생성</translation>\n\t<translation id=\"6358635099770142731\">토큰 생성</translation>\n\t<translation id=\"7499211462525828161\">달력로드</translation>\n\t<translation id=\"3128474301651540051\">다양한 모드를 오프셋</translation>\n\t<translation id=\"5645011507444946232\">일전 오늘</translation>\n\t<translation id=\"472347571959391022\">일 후 오늘</translation>\n\t<translation id=\"7382546590159708114\">시작 날짜</translation>\n\t<translation id=\"8615958092383580706\">종료 날짜</translation>\n\t<translation id=\"7824071976623180870\">시트와로드</translation>\n\t<translation id=\"4370305429271412983\">화면 이름</translation>\n\t<translation id=\"7641098557273120361\">액세스 토큰을 생성</translation>\n\t<translation id=\"361150460746746781\">종횡비를 유지</translation>\n\t<translation id=\"3046991000485970172\">RSS 새로 고침 (분)</translation>\n\t<translation id=\"2303401327609002516\">RSS 스크롤 방향</translation>\n\t<translation id=\"8382375758916799432\">수평</translation>\n\t<translation id=\"160958144287367985\">수직선</translation>\n\t<translation id=\"5576694760844259892\">RSS 스크롤 속도</translation>\n\t<translation id=\"3801245379625272309\">느린</translation>\n\t<translation id=\"4688460977394283086\">매질</translation>\n\t<translation id=\"9161614188045173336\">빠른</translation>\n\t<translation id=\"6107231410782382609\">이벤트에 다음과 같은 조치를 취할</translation>\n\t<translation id=\"8875363048655701399\">키오스크 모드</translation>\n\t<translation id=\"6880124786888445040\">순서에 따라 수집 플레이</translation>\n\t<translation id=\"2166463051767640100\">컬렉션에 내용을 추가</translation>\n\t<translation id=\"7365517136074263312\">QR 코드</translation>\n\t<translation id=\"810733191089543608\">음량</translation>\n\t<translation id=\"4815249204085613710\">비디오 품질</translation>\n\t<translation id=\"5082095396043563283\">부위</translation>\n\t<translation id=\"396267502411280310\">가장 많이 본</translation>\n\t<translation id=\"2441920677226386245\">사용자 지정 목록</translation>\n\t<translation id=\"1223194855937061908\">동영상 ID</translation>\n\t<translation id=\"4103549354606724944\">고객의 라인</translation>\n\t<translation id=\"7262144878230347914\">배경색</translation>\n\t<translation id=\"1435085881129646880\">기본 연속 재생 목록</translation>\n\t<translation id=\"1587536276491357593\">총 위치 기반 :></translation>\n\t<translation id=\"3325180562659478330\">이름</translation>\n\t<translation id=\"3051480550159545291\">위도</translation>\n\t<translation id=\"2703718513716530782\">경도</translation>\n\t<translation id=\"5602245631444655788\">지속</translation>\n\t<translation id=\"118487254857410201\">반경 범위</translation>\n\t<translation id=\"9178543898761255307\">km</translation>\n\t<translation id=\"7866202877490561957\">충돌 우선 순위</translation>\n\t<translation id=\"720146333131008909\">현장에 내용을 추가</translation>\n\t<translation id=\"8729372534532732068\">장면 이름</translation>\n\t<translation id=\"2224690894219674949\">시뮬레이션 모드</translation>\n\t<translation id=\"7220335122322620944\">기업에 대해 자세히 알아보기</translation>\n\t<translation id=\"8444323300278462770\">상단</translation>\n\t<translation id=\"7449548947549758066\">왼쪽</translation>\n\t<translation id=\"9172672254266086971\">폭</translation>\n\t<translation id=\"4093381701787958997\">신장</translation>\n\t<translation id=\"2062170564010556149\">회전</translation>\n\t<translation id=\"9088937454320275395\">변경 승인</translation>\n\t<translation id=\"1870560040946711505\">고정</translation>\n\t<translation id=\"6108618462851148193\">캠페인 편집기</translation>\n\t<translation id=\"2741646832903808697\">화면 레이아웃</translation>\n\t<translation id=\"6454444033973204385\">캠페인 선택</translation>\n\t<translation id=\"6028894272398949430\">새로운 캠페인</translation>\n\t<translation id=\"3008329758802399315\">마법사의 도움 받기</translation>\n\t<translation id=\"4145364267099301397\">캠페인 이름을 선택</translation>\n\t<translation id=\"3843469504048287640\">새 캠페인 이름을 입력합니다</translation>\n\t<translation id=\"4895430942430831092\">캠페인 ID :</translation>\n\t<translation id=\"1901427837939428954\">키오스크 모드</translation>\n\t<translation id=\"8329228391349300722\">재생 모드 캠페인 :</translation>\n\t<translation id=\"8793145092368811184\">시퀀서 (단순 모드) :</translation>\n\t<translation id=\"4691632839818550461\">연속 루프에서이 캠페인 타임 라인을 재생합니다. 그것은 쉽게 설치 및 사용이 간편하다</translation>\n\t<translation id=\"6075423017399759230\">스케줄러 (고급 모드) :</translation>\n\t<translation id=\"750837672459228230\">특정 시간에이 캠페인 타임 라인을 재생합니다. 예를 들어, 밤에 아침에 타임 라인 A와 타임 라인 B를 재생할 수 있습니다.</translation>\n\t<translation id=\"1167977099462453641\">화면 해상도</translation>\n\t<translation id=\"7626905534069326448\">충돌 우선 순위 :</translation>\n\t<translation id=\"4220765745195024064\">지속:</translation>\n\t<translation id=\"4049333306580215724\">한 번 연주</translation>\n\t<translation id=\"7249155645987524413\">매일 플레이</translation>\n\t<translation id=\"8568181330490588741\">매주 재생</translation>\n\t<translation id=\"3408786538616090951\">일 선택 :</translation>\n\t<translation id=\"6324587259626414962\">에 맞게 반복</translation>\n\t<translation id=\"2012264763266897754\">임의의 순서로</translation>\n\t<translation id=\"4324819244706823449\">편집 레이아웃</translation>\n\t<translation id=\"5755245564638965488\">다음 채널</translation>\n\t<translation id=\"2925036210758384238\">선택한 선</translation>\n\t<translation id=\"3601209751322374737\">앞서 사람들의 알림</translation>\n\t<translation id=\"1790884679999452685\">터미널 열기</translation>\n\t<translation id=\"4878432943521432749\">리셋 라인</translation>\n\t<translation id=\"3728601907282119753\">큐 속성</translation>\n\t<translation id=\"2536017892630886700\">선택한 고객 :</translation>\n\t<translation id=\"6228967158577655533\">확인:</translation>\n\t<translation id=\"6435015929996679472\">에 의해 호출 :</translation>\n\t<translation id=\"8711852116268389728\">장면 선택</translation>\n\t<translation id=\"5053705054681686956\">새로운 라인</translation>\n\t<translation id=\"5225640858395745699\">줄을 제거</translation>\n\t<translation id=\"3116266439138367996\">모래밭</translation>\n\t<translation id=\"4159874591284333337\">구글의 각도 프레임 워크에 의해 구동</translation>\n\t<translation id=\"3008186756887926107\">파일 업로드하다</translation>\n\t<translation id=\"2123171795960509943\">풀다</translation>\n\t<translation id=\"7246196759043272468\">명부</translation>\n\t<translation id=\"946077791002604877\">그리드</translation>\n\t<translation id=\"5936943188558553659\">지원 파일 : FLV, MP4, JPG, PNG, SWF 및 SVG</translation>\n\t<translation id=\"8054250976557949996\">새로운 장면</translation>\n\t<translation id=\"6133338617402043535\">복제</translation>\n\t<translation id=\"1576591662761177526\">가져 오기 템플릿</translation>\n\t<translation id=\"2225048990372533999\">다시로드</translation>\n\t<translation id=\"987425828725037788\">IP 주소</translation>\n\t<translation id=\"1646067470190508925\">포트</translation>\n\n\t<translation id=\"8097415329769247281\">당신에게 적합한 패키지를 선택</translation>\n\n\t<translation id=\"6570363013146073520\">계기반</translation>\n\t<translation id=\"8864658120410603626\">캠페인</translation>\n\t<translation id=\"2446117790692479672\">자원</translation>\n\t<translation id=\"794120057687191331\">장면</translation>\n\t<translation id=\"4846792506513649213\">역</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">도움</translation>\n\t<translation id=\"6082171864197428613\">설치</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">로그 아웃</translation>\n\t<translation id=\"7746065369460476808\">아이디 또는 이메일</translation>\n\t<translation id=\"4809196861118879526\">암호</translation>\n\t<translation id=\"9162857816822524614\">두 요소 키를 입력</translation>\n\t<translation id=\"24227595514967590\">구글 인증과</translation>\n\t<translation id=\"2001940299854753031\">날 기억해</translation>\n\t<translation id=\"5872337092278414963\">비밀번호를 잊으 셨나요</translation>\n\t<translation id=\"8246600873004586882\">암호 변경</translation>\n\t<translation id=\"5289326240092186479\">변화의 비즈니스 이름</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">기존 비밀번호</translation>\n\t<translation id=\"48285893667252664\">새 비밀번호</translation>\n\t<translation id=\"6917932917401642982\">반복 새 비밀번호</translation>\n\t<translation id=\"5666893431176348635\">새로운 비즈니스 이름</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">업그레이드</translation>\n\t<translation id=\"8894542476475088437\">계정-S</translation>\n\t<translation id=\"2347724151568473592\">언어</translation>\n\t<translation id=\"4376434433661751094\">라이브 채팅</translation>\n\t<translation id=\"5344752701442428839\">웹 사이트</translation>\n\t<translation id=\"7108535247064136881\">언어 선택</translation>\n\t<translation id=\"4137049537431219133\">Google 인증 자로 귀하의 계정에 로그인하십시오.</translation>\n\t<translation id=\"4785021168351486737\">저장 및 로그 아웃</translation>\n\t<translation id=\"6524180701596149125\">그냥 로그 아웃</translation>\n\n\t<translation id=\"2503331336991669578\">귀하의 계정에 로그인하십시오.</translation>\n\t<translation id=\"8359621426539146583\">계정이 없다.</translation>\n\t<translation id=\"569785428576811345\">지속:</translation>\n\t<translation id=\"9043806075514219833\">시작 시간:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/la.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"la\">\n\t<translation id=\"9198441993514322349\">screen sexualis</translation>\n\t<translation id=\"2838690440296896849\">status remote</translation>\n\t<translation id=\"2849064100927111571\">... loading</translation>\n\t<translation id=\"7309719557896597512\">bonum diem habeas</translation>\n\t<translation id=\"5805758016483237261\">Phasellus ut Enterprise - $ 99.00 per month</translation>\n\t<translation id=\"7212624462478696127\">probari possit aditus ...</translation>\n\t<translation id=\"1156206314346372426\">propter ashboardday</translation>\n\t<translation id=\"892759319569190037\">SCENA background color</translation>\n\t<translation id=\"463077023711449502\">terminus color</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Elige forma</translation>\n\t<translation id=\"8932917860978648376\">Unit</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit IX</translation>\n\t<translation id=\"1546647220090341106\">celsius</translation>\n\t<translation id=\"6977749640368501596\">styli</translation>\n\t<translation id=\"30300572504753589\">nigrum</translation>\n\t<translation id=\"7850674593676755019\">alba</translation>\n\t<translation id=\"9011959596901584887\">color</translation>\n\t<translation id=\"5667922561719642173\">onus in scena</translation>\n\t<translation id=\"5466334165625502718\">spatium</translation>\n\t<translation id=\"1128028236258747485\">video ludere ad completionem</translation>\n\t<translation id=\"3372777815572567783\">temere playback</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">firmitatis indicium</translation>\n\t<translation id=\"6262368721870308838\">aditus tesseram creare instagram</translation>\n\t<translation id=\"6358635099770142731\">partum firmitatis indicium</translation>\n\t<translation id=\"7499211462525828161\">Onus in fastis</translation>\n\t<translation id=\"3128474301651540051\">offset range modus</translation>\n\t<translation id=\"5645011507444946232\">antequam dies est hodie</translation>\n\t<translation id=\"472347571959391022\">post dies est hodie</translation>\n\t<translation id=\"7382546590159708114\">satus date</translation>\n\t<translation id=\"8615958092383580706\">ultimum diem</translation>\n\t<translation id=\"7824071976623180870\">Et onus sheet</translation>\n\t<translation id=\"4370305429271412983\">screen nomen,</translation>\n\t<translation id=\"7641098557273120361\">partum aditus tesseram</translation>\n\t<translation id=\"361150460746746781\">ponere rationem ratio</translation>\n\t<translation id=\"3046991000485970172\">RSS reficite (minuta)</translation>\n\t<translation id=\"2303401327609002516\">Liber via RSS</translation>\n\t<translation id=\"8382375758916799432\">vestibulum</translation>\n\t<translation id=\"160958144287367985\">vertical</translation>\n\t<translation id=\"5576694760844259892\">Celeritate volumen RSS</translation>\n\t<translation id=\"3801245379625272309\">tarda</translation>\n\t<translation id=\"4688460977394283086\">medium</translation>\n\t<translation id=\"9161614188045173336\">celer</translation>\n\t<translation id=\"6107231410782382609\">In rem actione accipe</translation>\n\t<translation id=\"8875363048655701399\">ac ante modus</translation>\n\t<translation id=\"6880124786888445040\">Ludere in tempore collectione</translation>\n\t<translation id=\"2166463051767640100\">addere in contentus collectio</translation>\n\t<translation id=\"7365517136074263312\">QR code</translation>\n\t<translation id=\"810733191089543608\">magnitudo</translation>\n\t<translation id=\"4815249204085613710\">qualis video</translation>\n\t<translation id=\"5082095396043563283\">regionem</translation>\n\t<translation id=\"396267502411280310\">maxime spectantur</translation>\n\t<translation id=\"2441920677226386245\">more album</translation>\n\t<translation id=\"1223194855937061908\">video ids</translation>\n\t<translation id=\"4103549354606724944\">Lorem lineae</translation>\n\t<translation id=\"7262144878230347914\">background color</translation>\n\t<translation id=\"1435085881129646880\">Default sequentem playlist</translation>\n\t<translation id=\"1587536276491357593\">Totalis secundum locum:></translation>\n\t<translation id=\"3325180562659478330\">nomine</translation>\n\t<translation id=\"3051480550159545291\">latitudo</translation>\n\t<translation id=\"2703718513716530782\">longitudo</translation>\n\t<translation id=\"5602245631444655788\">tempus</translation>\n\t<translation id=\"118487254857410201\">radii range</translation>\n\t<translation id=\"9178543898761255307\">chiliometrorum</translation>\n\t<translation id=\"7866202877490561957\">prius conflictu</translation>\n\t<translation id=\"720146333131008909\">addere in contentus scena</translation>\n\t<translation id=\"8729372534532732068\">SCENA nomen eius</translation>\n\t<translation id=\"2224690894219674949\">modus simulation</translation>\n\t<translation id=\"7220335122322620944\">Disce magis de Enterprise</translation>\n\t<translation id=\"8444323300278462770\">summitatem</translation>\n\t<translation id=\"7449548947549758066\">reliquit</translation>\n\t<translation id=\"9172672254266086971\">width</translation>\n\t<translation id=\"4093381701787958997\">altitudo</translation>\n\t<translation id=\"2062170564010556149\">rotatione</translation>\n\t<translation id=\"9088937454320275395\">mutationes adhibere</translation>\n\t<translation id=\"1870560040946711505\">clausa</translation>\n\t<translation id=\"6108618462851148193\">expeditionem Editor</translation>\n\t<translation id=\"2741646832903808697\">screen layout</translation>\n\t<translation id=\"6454444033973204385\">expeditionem delectu</translation>\n\t<translation id=\"6028894272398949430\">novam expeditionem</translation>\n\t<translation id=\"3008329758802399315\">Carmina Get Auxilium</translation>\n\t<translation id=\"4145364267099301397\">Select expeditionem nomen tuum</translation>\n\t<translation id=\"3843469504048287640\">Intra expeditionem nomen novum,</translation>\n\t<translation id=\"4895430942430831092\">id expeditionem,</translation>\n\t<translation id=\"1901427837939428954\">ac ante modus</translation>\n\t<translation id=\"8329228391349300722\">Bella gerere playback modus:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (simplex modus)</translation>\n\t<translation id=\"4691632839818550461\">Ludere hanc expeditionem in continua timelines pro loop. Hoc est simplex quod securus utor setup</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (provectus modus)</translation>\n\t<translation id=\"750837672459228230\">Ludere hanc expeditionem timelines tantum in certis temporibus. Eg ludere Quintus Quintus A et B mane in nocte.</translation>\n\t<translation id=\"1167977099462453641\">screen resolutio</translation>\n\t<translation id=\"7626905534069326448\">Conflictus prius:</translation>\n\t<translation id=\"4220765745195024064\">Duration:</translation>\n\t<translation id=\"4049333306580215724\">ludere semel,</translation>\n\t<translation id=\"7249155645987524413\">cotidie ludere</translation>\n\t<translation id=\"8568181330490588741\">ludere weekly</translation>\n\t<translation id=\"3408786538616090951\">Select a diebus:</translation>\n\t<translation id=\"6324587259626414962\">ut fit iterare</translation>\n\t<translation id=\"2012264763266897754\">ut temere</translation>\n\t<translation id=\"4324819244706823449\">recensere layout</translation>\n\t<translation id=\"5755245564638965488\">deinde channel</translation>\n\t<translation id=\"2925036210758384238\">delectis recta</translation>\n\t<translation id=\"3601209751322374737\">praemisit in memoriam vos in populos</translation>\n\t<translation id=\"1790884679999452685\">terminalibus patentibus</translation>\n\t<translation id=\"4878432943521432749\">reset recta</translation>\n\t<translation id=\"3728601907282119753\">Queue possessiones</translation>\n\t<translation id=\"2536017892630886700\">lectus elit;</translation>\n\t<translation id=\"6228967158577655533\">solvas:</translation>\n\t<translation id=\"6435015929996679472\">per dicitur:</translation>\n\t<translation id=\"8711852116268389728\">SCENA delectu</translation>\n\t<translation id=\"5053705054681686956\">novam lineam</translation>\n\t<translation id=\"5225640858395745699\">acie remove</translation>\n\t<translation id=\"3116266439138367996\">Nexus</translation>\n\t<translation id=\"4159874591284333337\">Potentia a Google data est Versio compage</translation>\n\t<translation id=\"3008186756887926107\">fasciculos oneres</translation>\n\t<translation id=\"2123171795960509943\">remove</translation>\n\t<translation id=\"7246196759043272468\">album</translation>\n\t<translation id=\"946077791002604877\">euismod</translation>\n\t<translation id=\"5936943188558553659\">files nititur, rar, mp4, jpg, png, et swf Chinne</translation>\n\t<translation id=\"8054250976557949996\">new scene</translation>\n\t<translation id=\"6133338617402043535\">duplicare</translation>\n\t<translation id=\"1576591662761177526\">import template</translation>\n\t<translation id=\"2225048990372533999\">reload</translation>\n\t<translation id=\"987425828725037788\">Disputatio</translation>\n\t<translation id=\"1646067470190508925\">portum</translation>\n\n\t<translation id=\"8097415329769247281\">Elige tibi in sarcina quod iustum est</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/messages.xmb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE messagebundle [\n<!ELEMENT messagebundle (msg)*>\n<!ATTLIST messagebundle class CDATA #IMPLIED>\n\n<!ELEMENT msg (#PCDATA|ph|source)*>\n<!ATTLIST msg id CDATA #IMPLIED>\n<!ATTLIST msg seq CDATA #IMPLIED>\n<!ATTLIST msg name CDATA #IMPLIED>\n<!ATTLIST msg desc CDATA #IMPLIED>\n<!ATTLIST msg meaning CDATA #IMPLIED>\n<!ATTLIST msg obsolete (obsolete) #IMPLIED>\n<!ATTLIST msg xml:space (default|preserve) \"default\">\n<!ATTLIST msg is_hidden CDATA #IMPLIED>\n\n<!ELEMENT source (#PCDATA)>\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<messagebundle>\n  <msg id=\"9198441993514322349\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-orientation.ts:3</source>screen orientation</msg>\n  <msg id=\"2838690440296896849\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-editor.ts:3</source>remote status</msg>\n  <msg id=\"6570363013146073520\"><source>C:/msweb/studiolite/src/app/app-component.ts:27</source><source>C:/msweb/studiolite/src/app/appwrap.ts:4</source>Dashboard</msg>\n  <msg id=\"8864658120410603626\"><source>C:/msweb/studiolite/src/app/app-component.ts:28</source><source>C:/msweb/studiolite/src/app/appwrap.ts:5</source>Campaigns</msg>\n  <msg id=\"2446117790692479672\"><source>C:/msweb/studiolite/src/app/app-component.ts:29</source><source>C:/msweb/studiolite/src/app/appwrap.ts:6</source>Resources</msg>\n  <msg id=\"794120057687191331\"><source>C:/msweb/studiolite/src/app/app-component.ts:30</source><source>C:/msweb/studiolite/src/app/appwrap.ts:7</source>Scenes</msg>\n  <msg id=\"4846792506513649213\"><source>C:/msweb/studiolite/src/app/app-component.ts:31</source><source>C:/msweb/studiolite/src/app/appwrap.ts:8</source>Stations</msg>\n  <msg id=\"5686918033652531723\"><source>C:/msweb/studiolite/src/app/app-component.ts:32</source><source>C:/msweb/studiolite/src/app/appwrap.ts:9</source>Fasterq</msg>\n  <msg id=\"7911416166208830577\"><source>C:/msweb/studiolite/src/app/app-component.ts:33</source><source>C:/msweb/studiolite/src/app/appwrap.ts:12</source>Help</msg>\n  <msg id=\"6082171864197428613\"><source>C:/msweb/studiolite/src/app/app-component.ts:34</source><source>C:/msweb/studiolite/src/app/appwrap.ts:13</source>Install</msg>\n  <msg id=\"3476206505271758484\"><source>C:/msweb/studiolite/src/app/app-component.ts:36</source><source>C:/msweb/studiolite/src/app/appwrap.ts:11</source>Studiopro</msg>\n  <msg id=\"3797778920049399855\"><source>C:/msweb/studiolite/src/app/app-component.ts:37</source><source>C:/msweb/studiolite/src/app/appwrap.ts:14</source>Logout</msg>\n  <msg id=\"4010072142461558046\"><source>C:/msweb/studiolite/src/app/app-component.ts:42</source>upgrade</msg>\n  <msg id=\"8894542476475088437\"><source>C:/msweb/studiolite/src/app/app-component.ts:45</source>Cont-S</msg>\n  <msg id=\"2347724151568473592\"><source>C:/msweb/studiolite/src/app/app-component.ts:48</source>language</msg>\n  <msg id=\"4376434433661751094\"><source>C:/msweb/studiolite/src/app/app-component.ts:51</source>live chat</msg>\n  <msg id=\"5344752701442428839\"><source>C:/msweb/studiolite/src/app/app-component.ts:54</source>web site</msg>\n  <msg id=\"2849064100927111571\"><source>C:/msweb/studiolite/src/app/app-component.ts:91</source>loading...</msg>\n  <msg id=\"7309719557896597512\"><source>C:/msweb/studiolite/src/app/app-component.ts:94</source>have a nice day </msg>\n  <msg id=\"5805758016483237261\"><source>C:/msweb/studiolite/src/app/app-component.ts:102</source><source>C:/msweb/studiolite/src/app/studiopro/studiopro-navigation.ts:175</source>Upgrade to Enterprise</msg>\n  <msg id=\"7108535247064136881\"><source>C:/msweb/studiolite/src/app/app-component.ts:112</source>Pick your language</msg>\n  <msg id=\"7746065369460476808\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:14</source>user name or email</msg>\n  <msg id=\"4809196861118879526\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:15</source><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:81</source>password</msg>\n  <msg id=\"9162857816822524614\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:20</source>enter two factor key</msg>\n  <msg id=\"2503331336991669578\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:25,27</source> login to your account\n                            \n                        </msg>\n  <msg id=\"2001940299854753031\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:34</source> remember me </msg>\n  <msg id=\"5872337092278414963\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:38</source>forgot password</msg>\n  <msg id=\"8246600873004586882\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:40</source>change password</msg>\n  <msg id=\"5289326240092186479\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:42</source>change business name</msg>\n  <msg id=\"8359621426539146583\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:49</source>Don&apos;t have an account? create one</msg>\n  <msg id=\"8732769503581158362\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:54</source><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:69</source><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:80</source>user name / email</msg>\n  <msg id=\"867339644855996577\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:55</source>old password</msg>\n  <msg id=\"48285893667252664\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:56</source>new password</msg>\n  <msg id=\"6917932917401642982\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:57</source>repeat new password</msg>\n  <msg id=\"5666893431176348635\"><source>C:/msweb/studiolite/src/comps/entry/LoginPanel.ts:82</source>new business name</msg>\n  <msg id=\"4785021168351486737\"><source>C:/msweb/studiolite/src/comps/logout/Logout.ts:4</source>Save &amp; Logout</msg>\n  <msg id=\"6524180701596149125\"><source>C:/msweb/studiolite/src/comps/logout/Logout.ts:5</source>Just Logout</msg>\n  <msg id=\"7212624462478696127\"><source>C:/msweb/studiolite/src/comps/entry/AutoLogin.ts:2</source>verifying access...</msg>\n  <msg id=\"1156206314346372426\"><source>C:/msweb/studiolite/src/app/dashboard/dashboard-navigation.ts:2</source>account dashboard</msg>\n  <msg id=\"892759319569190037\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-common.ts:25</source>scene background color</msg>\n  <msg id=\"463077023711449502\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-common.ts:45</source>border color</msg>\n  <msg id=\"7844431484369877777\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-html.ts:8</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-video.ts:7</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-image.ts:7</source>url</msg>\n  <msg id=\"6727478076005438064\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-clock.ts:9</source>Choose format</msg>\n  <msg id=\"8932917860978648376\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:8</source>Unit</msg>\n  <msg id=\"6447113917741810043\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:11</source>Fahrenheit</msg>\n  <msg id=\"1546647220090341106\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:14</source>Celsius</msg>\n  <msg id=\"6977749640368501596\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:17</source>Styles</msg>\n  <msg id=\"30300572504753589\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:20</source>Black</msg>\n  <msg id=\"7850674593676755019\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:23</source>White</msg>\n  <msg id=\"9011959596901584887\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-weather.ts:26</source>Color</msg>\n  <msg id=\"5667922561719642173\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-json-player.ts:19</source>load with scene</msg>\n  <msg id=\"5466334165625502718\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-json-player.ts:26</source>interval</msg>\n  <msg id=\"1128028236258747485\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-json-player.ts:30</source>play video to completion</msg>\n  <msg id=\"3372777815572567783\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-json-player.ts:40</source>random playback</msg>\n  <msg id=\"6757770085960264448\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-json-player.ts:50</source>slideshow</msg>\n  <msg id=\"6659445582099947212\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-instagram.ts:8</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:8</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-sheets.ts:8</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-twitter.ts:12</source>token</msg>\n  <msg id=\"6262368721870308838\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-instagram.ts:12</source>create instagram access token</msg>\n  <msg id=\"6358635099770142731\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:12</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-sheets.ts:12</source>create token</msg>\n  <msg id=\"7499211462525828161\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:15</source>Load with calendar</msg>\n  <msg id=\"3128474301651540051\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:25</source>offset range mode</msg>\n  <msg id=\"5645011507444946232\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:36</source>days before today</msg>\n  <msg id=\"472347571959391022\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:41</source>days after today</msg>\n  <msg id=\"7382546590159708114\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:46</source>start date</msg>\n  <msg id=\"8615958092383580706\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-calendar.ts:53</source>end date</msg>\n  <msg id=\"7824071976623180870\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-sheets.ts:15</source>Load with sheet</msg>\n  <msg id=\"4370305429271412983\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-twitter.ts:8</source>screen name</msg>\n  <msg id=\"7641098557273120361\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-twitter.ts:16</source>create access token</msg>\n  <msg id=\"361150460746746781\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-video.ts:11</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-image.ts:11</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-mrss.ts:7</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-json-item.ts:51</source>maintain aspect ratio</msg>\n  <msg id=\"3046991000485970172\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:15</source>RSS refresh (minutes)</msg>\n  <msg id=\"2303401327609002516\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:19</source>RSS scroll direction</msg>\n  <msg id=\"8382375758916799432\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:22</source>Horizontal</msg>\n  <msg id=\"160958144287367985\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:25</source>Vertical</msg>\n  <msg id=\"5576694760844259892\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:28</source>RSS scroll speed</msg>\n  <msg id=\"3801245379625272309\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:31</source>slow</msg>\n  <msg id=\"4688460977394283086\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:34</source>medium</msg>\n  <msg id=\"9161614188045173336\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-rss.ts:37</source>fast</msg>\n  <msg id=\"6107231410782382609\"><source>C:/msweb/studiolite/src/app/blocks/json-event-grid.ts:3</source>On event take the following action</msg>\n  <msg id=\"8875363048655701399\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-collection.ts:7</source>Kiosk mode</msg>\n  <msg id=\"6880124786888445040\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-collection.ts:23</source>Play collection in sequence</msg>\n  <msg id=\"2166463051767640100\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-collection.ts:51</source><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:92</source>add content to collection</msg>\n  <msg id=\"7365517136074263312\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-qr.ts:7</source>QR code</msg>\n  <msg id=\"810733191089543608\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-youtube.ts:7</source>volume</msg>\n  <msg id=\"4815249204085613710\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-youtube.ts:11</source>video quality</msg>\n  <msg id=\"5082095396043563283\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-youtube.ts:21</source>region</msg>\n  <msg id=\"396267502411280310\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-youtube.ts:28</source>most viewed</msg>\n  <msg id=\"2441920677226386245\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-youtube.ts:31</source>custom list</msg>\n  <msg id=\"1223194855937061908\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-youtube.ts:34</source>video ids</msg>\n  <msg id=\"4103549354606724944\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-fasterq.ts:5</source>customer lines</msg>\n  <msg id=\"7262144878230347914\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-fasterq.ts:8</source>background color</msg>\n  <msg id=\"1435085881129646880\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:15</source>Default sequential playlist</msg>\n  <msg id=\"1587536276491357593\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:58</source>Total location based: &gt;</msg>\n  <msg id=\"3325180562659478330\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:64</source>name</msg>\n  <msg id=\"3051480550159545291\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:68</source>latitude</msg>\n  <msg id=\"2703718513716530782\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:72</source>longitude</msg>\n  <msg id=\"5602245631444655788\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:76</source>duration</msg>\n  <msg id=\"118487254857410201\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:80</source>radius range </msg>\n  <msg id=\"9178543898761255307\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:80</source> kilometers</msg>\n  <msg id=\"7866202877490561957\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-location.ts:84</source>conflict priority</msg>\n  <msg id=\"720146333131008909\"><source>C:/msweb/studiolite/src/app/scenes/scene-editor.ts:27</source>add content to scene</msg>\n  <msg id=\"8729372534532732068\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-scene.ts:8</source>scene name</msg>\n  <msg id=\"2224690894219674949\"><source>C:/msweb/studiolite/src/app/location/location-map.ts:15</source>simulation mode</msg>\n  <msg id=\"7220335122322620944\"><source>C:/msweb/studiolite/src/app/studiopro/pro-upgrade.ts:10,12</source>\n                Learn more about Enterprise\n            </msg>\n  <msg id=\"8444323300278462770\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:10</source>top</msg>\n  <msg id=\"7449548947549758066\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:14</source>left</msg>\n  <msg id=\"9172672254266086971\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:18</source>width</msg>\n  <msg id=\"4093381701787958997\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:22</source>height</msg>\n  <msg id=\"2062170564010556149\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:26</source>rotation</msg>\n  <msg id=\"9088937454320275395\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:30</source>apply changes</msg>\n  <msg id=\"1870560040946711505\"><source>C:/msweb/studiolite/src/app/blocks/block-prop-position.ts:35</source>locked</msg>\n  <msg id=\"6108618462851148193\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-editor.ts:2</source>campaign editor</msg>\n  <msg id=\"2741646832903808697\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-layout.ts:3</source>screen layout</msg>\n  <msg id=\"6454444033973204385\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-manager.ts:4</source>campaign selection</msg>\n  <msg id=\"6028894272398949430\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-manager.ts:10</source>new campaign</msg>\n  <msg id=\"3008329758802399315\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-manager.ts:15</source>Get Wizard help</msg>\n  <msg id=\"4145364267099301397\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-name.ts:3</source>Select your campaign name</msg>\n  <msg id=\"3843469504048287640\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-name.ts:6</source>Enter new campaign name</msg>\n  <msg id=\"4895430942430831092\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:15</source>campaign id: </msg>\n  <msg id=\"1901427837939428954\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:19</source>kiosk mode</msg>\n  <msg id=\"8329228391349300722\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:37</source>Campaign playback mode:</msg>\n  <msg id=\"8793145092368811184\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:53</source>Sequencer (simple mode):</msg>\n  <msg id=\"4691632839818550461\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:54</source>Play timelines for this campaign in a continuous loop. It is easy to setup and simple to use</msg>\n  <msg id=\"6075423017399759230\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:57</source>Scheduler (advanced mode): </msg>\n  <msg id=\"750837672459228230\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-props.ts:58</source>Play timelines for this campaign only on specific times. For example, play Timeline A in the morning and Timeline B at night.</msg>\n  <msg id=\"1167977099462453641\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-resolution.ts:3</source>screen resolution</msg>\n  <msg id=\"7626905534069326448\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:15</source>Conflict priority:</msg>\n  <msg id=\"569785428576811345\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:23</source>Duration: </msg>\n  <msg id=\"9043806075514219833\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:33</source>Start time:</msg>\n  <msg id=\"4049333306580215724\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:50</source>play once</msg>\n  <msg id=\"7249155645987524413\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:61</source>play daily</msg>\n  <msg id=\"8568181330490588741\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:78</source>play weekly</msg>\n  <msg id=\"3408786538616090951\"><source>C:/msweb/studiolite/src/app/campaigns/campaign-sched-props.ts:95</source>Select the days:</msg>\n  <msg id=\"4039555836273676912\"><source>C:/msweb/studiolite/src/app/campaigns/channel-block-props.ts:4</source>hours / minutes /seconds</msg>\n  <msg id=\"6324587259626414962\"><source>C:/msweb/studiolite/src/app/campaigns/channel-props.ts:27</source>repeat to fit</msg>\n  <msg id=\"2012264763266897754\"><source>C:/msweb/studiolite/src/app/campaigns/channel-props.ts:37</source> random order</msg>\n  <msg id=\"4324819244706823449\"><source>C:/msweb/studiolite/src/app/campaigns/sequencer.ts:20</source>edit layout</msg>\n  <msg id=\"5755245564638965488\"><source>C:/msweb/studiolite/src/app/campaigns/sequencer.ts:21</source>next channel</msg>\n  <msg id=\"2925036210758384238\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:14</source>selected line</msg>\n  <msg id=\"3601209751322374737\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:23</source>reminder ahead of people</msg>\n  <msg id=\"1790884679999452685\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:32</source>open terminal</msg>\n  <msg id=\"4878432943521432749\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:35</source>reset line</msg>\n  <msg id=\"3728601907282119753\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:47</source>Queue properties</msg>\n  <msg id=\"2536017892630886700\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:50</source>selected customer: </msg>\n  <msg id=\"6228967158577655533\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:53</source>verification: </msg>\n  <msg id=\"6435015929996679472\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-line-props.ts:56</source>called by: </msg>\n  <msg id=\"8711852116268389728\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-manager.ts:4</source><source>C:/msweb/studiolite/src/app/scenes/scene-manager.ts:4</source>scene selection</msg>\n  <msg id=\"5053705054681686956\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-manager.ts:10</source>new line</msg>\n  <msg id=\"5225640858395745699\"><source>C:/msweb/studiolite/src/app/fasterq/fasterq-manager.ts:14</source>remove line</msg>\n  <msg id=\"3116266439138367996\"><source>C:/msweb/studiolite/src/app/help/help-navigation.ts:31</source> links</msg>\n  <msg id=\"4159874591284333337\"><source>C:/msweb/studiolite/src/app/help/help-navigation.ts:57</source>Powered by Google&apos;s Angular framework</msg>\n  <msg id=\"3008186756887926107\"><source>C:/msweb/studiolite/src/app/resources/resources.ts:7</source>upload files</msg>\n  <msg id=\"2123171795960509943\"><source>C:/msweb/studiolite/src/app/resources/resources.ts:15</source><source>C:/msweb/studiolite/src/app/scenes/scene-manager.ts:14</source><source>C:/msweb/studiolite/src/app/stations/stations.ts:11</source>remove</msg>\n  <msg id=\"7246196759043272468\"><source>C:/msweb/studiolite/src/app/resources/resources.ts:19</source>list</msg>\n  <msg id=\"946077791002604877\"><source>C:/msweb/studiolite/src/app/resources/resources.ts:23</source>grid</msg>\n  <msg id=\"5936943188558553659\"><source>C:/msweb/studiolite/src/app/resources/resources.ts:27</source>supported files: flv, mp4, jpg, png, swf and svg</msg>\n  <msg id=\"8054250976557949996\"><source>C:/msweb/studiolite/src/app/scenes/scene-manager.ts:10</source>new scene</msg>\n  <msg id=\"6133338617402043535\"><source>C:/msweb/studiolite/src/app/scenes/scene-manager.ts:18</source>duplicate</msg>\n  <msg id=\"1576591662761177526\"><source>C:/msweb/studiolite/src/app/scenes/scene-creator.ts:31</source>import template</msg>\n  <msg id=\"2225048990372533999\"><source>C:/msweb/studiolite/src/app/stations/stations.ts:7</source>reload</msg>\n  <msg id=\"987425828725037788\"><source>C:/msweb/studiolite/src/app/stations/stations-props-manager.ts:115</source>ip address</msg>\n  <msg id=\"1646067470190508925\"><source>C:/msweb/studiolite/src/app/stations/stations-props-manager.ts:119</source>port</msg>\n  <msg id=\"8097415329769247281\"><source>C:/msweb/studiolite/src/app/studiopro/studiopro-navigation.ts:3</source>Choose the package that&apos;s right for you</msg>\n</messagebundle>\n"
  },
  {
    "path": "src/locale/pt.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"pt\">\n\t<translation id=\"9198441993514322349\">orientação da tela</translation>\n\t<translation id=\"2838690440296896849\">o status remoto</translation>\n\t<translation id=\"2849064100927111571\">Carregando...</translation>\n\t<translation id=\"7309719557896597512\">tenha um bom dia</translation>\n\t<translation id=\"5805758016483237261\">Upgrade para Empresa - $ 99,00 por mês</translation>\n\t<translation id=\"7212624462478696127\">verificação de acesso ...</translation>\n\t<translation id=\"1156206314346372426\">conta dashboard</translation>\n\t<translation id=\"892759319569190037\">cor de fundo cena</translation>\n\t<translation id=\"463077023711449502\">Cor da borda</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Escolha o formato</translation>\n\t<translation id=\"8932917860978648376\">Unidade</translation>\n\t<translation id=\"6447113917741810043\">Fahrenheit</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">Styles</translation>\n\t<translation id=\"30300572504753589\">Preto</translation>\n\t<translation id=\"7850674593676755019\">Branco</translation>\n\t<translation id=\"9011959596901584887\">Cor</translation>\n\t<translation id=\"5667922561719642173\">carga com a cena</translation>\n\t<translation id=\"5466334165625502718\">intervalo</translation>\n\t<translation id=\"1128028236258747485\">reproduzir vídeo para conclusão</translation>\n\t<translation id=\"3372777815572567783\">reprodução aleatória</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">símbolo</translation>\n\t<translation id=\"6262368721870308838\">criar token de acesso instagram</translation>\n\t<translation id=\"6358635099770142731\">criar símbolo</translation>\n\t<translation id=\"7499211462525828161\">Carga com calendário</translation>\n\t<translation id=\"3128474301651540051\">Modo de deslocamento intervalo</translation>\n\t<translation id=\"5645011507444946232\">dias antes de hoje</translation>\n\t<translation id=\"472347571959391022\">dias depois de hoje</translation>\n\t<translation id=\"7382546590159708114\">data de início</translation>\n\t<translation id=\"8615958092383580706\">data final</translation>\n\t<translation id=\"7824071976623180870\">Carga com folha</translation>\n\t<translation id=\"4370305429271412983\">Nome do ecrã</translation>\n\t<translation id=\"7641098557273120361\">criar token de acesso</translation>\n\t<translation id=\"361150460746746781\">manter a relação de aspecto</translation>\n\t<translation id=\"3046991000485970172\">RSS atualização (minutos)</translation>\n\t<translation id=\"2303401327609002516\">RSS direção de rolagem</translation>\n\t<translation id=\"8382375758916799432\">Horizontal</translation>\n\t<translation id=\"160958144287367985\">Vertical</translation>\n\t<translation id=\"5576694760844259892\">velocidade de deslocamento RSS</translation>\n\t<translation id=\"3801245379625272309\">lento</translation>\n\t<translation id=\"4688460977394283086\">médio</translation>\n\t<translation id=\"9161614188045173336\">velozes</translation>\n\t<translation id=\"6107231410782382609\">No evento de tomar as seguintes providências</translation>\n\t<translation id=\"8875363048655701399\">modo quiosque</translation>\n\t<translation id=\"6880124786888445040\">Jogar a coleção em sequência</translation>\n\t<translation id=\"2166463051767640100\">adicionar conteúdo de coleção</translation>\n\t<translation id=\"7365517136074263312\">Código QR</translation>\n\t<translation id=\"810733191089543608\">volume</translation>\n\t<translation id=\"4815249204085613710\">qualidade de vídeo</translation>\n\t<translation id=\"5082095396043563283\">região</translation>\n\t<translation id=\"396267502411280310\">mais visto</translation>\n\t<translation id=\"2441920677226386245\">lista personalizada</translation>\n\t<translation id=\"1223194855937061908\">ids de vídeo</translation>\n\t<translation id=\"4103549354606724944\">linhas de cliente</translation>\n\t<translation id=\"7262144878230347914\">cor de fundo</translation>\n\t<translation id=\"1435085881129646880\">lista sequencial padrão</translation>\n\t<translation id=\"1587536276491357593\">localização Total base:></translation>\n\t<translation id=\"3325180562659478330\">nome</translation>\n\t<translation id=\"3051480550159545291\">latitude</translation>\n\t<translation id=\"2703718513716530782\">longitude</translation>\n\t<translation id=\"5602245631444655788\">duração</translation>\n\t<translation id=\"118487254857410201\">raio de alcance</translation>\n\t<translation id=\"9178543898761255307\">quilômetros</translation>\n\t<translation id=\"7866202877490561957\">prioridade conflito</translation>\n\t<translation id=\"720146333131008909\">adicionar conteúdo de cena</translation>\n\t<translation id=\"8729372534532732068\">nome da cena</translation>\n\t<translation id=\"2224690894219674949\">modo de simulação</translation>\n\t<translation id=\"7220335122322620944\">Saiba mais sobre Enterprise</translation>\n\t<translation id=\"8444323300278462770\">topo</translation>\n\t<translation id=\"7449548947549758066\">esquerda</translation>\n\t<translation id=\"9172672254266086971\">largura</translation>\n\t<translation id=\"4093381701787958997\">altura</translation>\n\t<translation id=\"2062170564010556149\">rotação</translation>\n\t<translation id=\"9088937454320275395\">Aplicar mudanças</translation>\n\t<translation id=\"1870560040946711505\">trancado</translation>\n\t<translation id=\"6108618462851148193\">editor de campanha</translation>\n\t<translation id=\"2741646832903808697\">layout da tela</translation>\n\t<translation id=\"6454444033973204385\">selecção campanha</translation>\n\t<translation id=\"6028894272398949430\">nova campanha</translation>\n\t<translation id=\"3008329758802399315\">Obtenha ajuda Assistente</translation>\n\t<translation id=\"4145364267099301397\">Selecione o nome da campanha</translation>\n\t<translation id=\"3843469504048287640\">Introduza o novo nome da campanha</translation>\n\t<translation id=\"4895430942430831092\">ID de campanha:</translation>\n\t<translation id=\"1901427837939428954\">modo de quiosque</translation>\n\t<translation id=\"8329228391349300722\">Campanha modo de reprodução:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (modo simples):</translation>\n\t<translation id=\"4691632839818550461\">Jogar prazos para esta campanha em um loop contínuo. É fácil de configurar e simples de usar</translation>\n\t<translation id=\"6075423017399759230\">Programador (Modo Avançado):</translation>\n\t<translation id=\"750837672459228230\">Jogar prazos para esta campanha apenas em horários específicos. Por exemplo, jogar Timeline Um de manhã e Timeline B à noite.</translation>\n\t<translation id=\"1167977099462453641\">resolução da tela</translation>\n\t<translation id=\"7626905534069326448\">prioridade conflito:</translation>\n\t<translation id=\"4220765745195024064\">Duração:</translation>\n\t<translation id=\"4049333306580215724\">jogar uma vez</translation>\n\t<translation id=\"7249155645987524413\">jogar diária</translation>\n\t<translation id=\"8568181330490588741\">jogar semanal</translation>\n\t<translation id=\"3408786538616090951\">Selecione os dias:</translation>\n\t<translation id=\"6324587259626414962\">repetir para caber</translation>\n\t<translation id=\"2012264763266897754\">ordem aleatória</translation>\n\t<translation id=\"4324819244706823449\">layout de edição</translation>\n\t<translation id=\"5755245564638965488\">próximo canal</translation>\n\t<translation id=\"2925036210758384238\">A linha seleccionada</translation>\n\t<translation id=\"3601209751322374737\">lembrete frente de pessoas</translation>\n\t<translation id=\"1790884679999452685\">terminal aberto</translation>\n\t<translation id=\"4878432943521432749\">linha de reset</translation>\n\t<translation id=\"3728601907282119753\">propriedades da fila</translation>\n\t<translation id=\"2536017892630886700\">cliente selecionado:</translation>\n\t<translation id=\"6228967158577655533\">verificação:</translation>\n\t<translation id=\"6435015929996679472\">chamado por:</translation>\n\t<translation id=\"8711852116268389728\">seleção de cena</translation>\n\t<translation id=\"5053705054681686956\">nova linha</translation>\n\t<translation id=\"5225640858395745699\">remover linha</translation>\n\t<translation id=\"3116266439138367996\">ligações</translation>\n\t<translation id=\"4159874591284333337\">Equipada com quadro angular do Google</translation>\n\t<translation id=\"3008186756887926107\">fazer upload de arquivos</translation>\n\t<translation id=\"2123171795960509943\">remover</translation>\n\t<translation id=\"7246196759043272468\">Lista</translation>\n\t<translation id=\"946077791002604877\">grade</translation>\n\t<translation id=\"5936943188558553659\">arquivos suportados: flv, mp4, jpg, png, swf e SVG</translation>\n\t<translation id=\"8054250976557949996\">nova cena</translation>\n\t<translation id=\"6133338617402043535\">duplicado</translation>\n\t<translation id=\"1576591662761177526\">modelo de importação</translation>\n\t<translation id=\"2225048990372533999\">recarregar</translation>\n\t<translation id=\"987425828725037788\">endereço de IP</translation>\n\t<translation id=\"1646067470190508925\">porta</translation>\n\n\t<translation id=\"8097415329769247281\">Escolha o pacote que é certo para você</translation>\n\n\t<translation id=\"6570363013146073520\">painel de controle</translation>\n\t<translation id=\"8864658120410603626\">campanhas</translation>\n\t<translation id=\"2446117790692479672\">Recursos</translation>\n\t<translation id=\"794120057687191331\">cenas</translation>\n\t<translation id=\"4846792506513649213\">estações</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Socorro</translation>\n\t<translation id=\"6082171864197428613\">Instalar</translation>\n\t<translation id=\"3476206505271758484\">studiopro</translation>\n\t<translation id=\"3797778920049399855\">Sair</translation>\n\t<translation id=\"7746065369460476808\">nome de usuário ou email</translation>\n\t<translation id=\"4809196861118879526\">senha</translation>\n\t<translation id=\"9162857816822524614\">ENTER duas fator chave</translation>\n\t<translation id=\"24227595514967590\">Google autenticador</translation>\n\t<translation id=\"2001940299854753031\">lembre de mim</translation>\n\t<translation id=\"5872337092278414963\">Esqueceu a senha</translation>\n\t<translation id=\"8246600873004586882\">mudar senha</translation>\n\t<translation id=\"5289326240092186479\">nome mudança negócio</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">Senha Antiga</translation>\n\t<translation id=\"48285893667252664\">Nova senha</translation>\n\t<translation id=\"6917932917401642982\">Repita a nova senha</translation>\n\t<translation id=\"5666893431176348635\">novo nome de negócios</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">atualizar</translation>\n\t<translation id=\"8894542476475088437\">Conta-S</translation>\n\t<translation id=\"2347724151568473592\">língua</translation>\n\t<translation id=\"4376434433661751094\">Bate-papo ao vivo</translation>\n\t<translation id=\"5344752701442428839\">local na rede Internet</translation>\n\t<translation id=\"7108535247064136881\">Escolha seu idioma</translation>\n\t<translation id=\"4137049537431219133\">Inicie sessão na sua conta com o autenticador do Google</translation>\n\t<translation id=\"4785021168351486737\">Salvar e sair</translation>\n\t<translation id=\"6524180701596149125\">Apenas Sair</translation>\n\n\t<translation id=\"2503331336991669578\">Faça login na sua conta</translation>\n\t<translation id=\"8359621426539146583\">Não tem uma conta</translation>\n\t<translation id=\"569785428576811345\">Duração:</translation>\n\t<translation id=\"9043806075514219833\">Hora de início:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/ru.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"ru\">\n\t<translation id=\"9198441993514322349\">ориентация экрана</translation>\n\t<translation id=\"2838690440296896849\">удаленный статус</translation>\n\t<translation id=\"2849064100927111571\">загрузка ...</translation>\n\t<translation id=\"7309719557896597512\">хорошего дня</translation>\n\t<translation id=\"5805758016483237261\">Обновление до Enterprise - $ 99,00 в месяц</translation>\n\t<translation id=\"7212624462478696127\">Проверка доступа ...</translation>\n\t<translation id=\"1156206314346372426\">счет приборной панели</translation>\n\t<translation id=\"892759319569190037\">цвет сцены фон</translation>\n\t<translation id=\"463077023711449502\">цвет границы</translation>\n\t<translation id=\"7844431484369877777\">URL</translation>\n\t<translation id=\"6727478076005438064\">Выберите формат</translation>\n\t<translation id=\"8932917860978648376\">Ед. изм</translation>\n\t<translation id=\"6447113917741810043\">Фаренгейт</translation>\n\t<translation id=\"1546647220090341106\">Celsius</translation>\n\t<translation id=\"6977749640368501596\">Стили</translation>\n\t<translation id=\"30300572504753589\">черный</translation>\n\t<translation id=\"7850674593676755019\">белый</translation>\n\t<translation id=\"9011959596901584887\">цвет</translation>\n\t<translation id=\"5667922561719642173\">Нагрузка на сцене</translation>\n\t<translation id=\"5466334165625502718\">интервал</translation>\n\t<translation id=\"1128028236258747485\">воспроизведения видео до завершения</translation>\n\t<translation id=\"3372777815572567783\">воспроизведение в случайном порядке</translation>\n\t<translation id=\"6757770085960264448\">слайд-шоу</translation>\n\t<translation id=\"6659445582099947212\">знак</translation>\n\t<translation id=\"6262368721870308838\">создать маркер доступа Instagram</translation>\n\t<translation id=\"6358635099770142731\">создать маркер</translation>\n\t<translation id=\"7499211462525828161\">Нагрузка с календарем</translation>\n\t<translation id=\"3128474301651540051\">Смещение режима диапазона</translation>\n\t<translation id=\"5645011507444946232\">дней до сегодняшнего дня</translation>\n\t<translation id=\"472347571959391022\">дней после того, как сегодня</translation>\n\t<translation id=\"7382546590159708114\">Дата начала</translation>\n\t<translation id=\"8615958092383580706\">Дата окончания</translation>\n\t<translation id=\"7824071976623180870\">Нагрузка с листом</translation>\n\t<translation id=\"4370305429271412983\">Ник</translation>\n\t<translation id=\"7641098557273120361\">создать маркер доступа</translation>\n\t<translation id=\"361150460746746781\">сохранять пропорции</translation>\n\t<translation id=\"3046991000485970172\">RSS обновления (в минутах)</translation>\n\t<translation id=\"2303401327609002516\">RSS направление прокрутки</translation>\n\t<translation id=\"8382375758916799432\">горизонтальный</translation>\n\t<translation id=\"160958144287367985\">вертикальный</translation>\n\t<translation id=\"5576694760844259892\">RSS скорость прокрутки</translation>\n\t<translation id=\"3801245379625272309\">медленный</translation>\n\t<translation id=\"4688460977394283086\">средний</translation>\n\t<translation id=\"9161614188045173336\">быстро</translation>\n\t<translation id=\"6107231410782382609\">В случае принять следующие меры</translation>\n\t<translation id=\"8875363048655701399\">режим киоска</translation>\n\t<translation id=\"6880124786888445040\">Играть коллекцию в последовательности</translation>\n\t<translation id=\"2166463051767640100\">добавить содержимое в коллекцию</translation>\n\t<translation id=\"7365517136074263312\">QR код</translation>\n\t<translation id=\"810733191089543608\">объем</translation>\n\t<translation id=\"4815249204085613710\">качество видео</translation>\n\t<translation id=\"5082095396043563283\">область</translation>\n\t<translation id=\"396267502411280310\">наиболее просматриваемые</translation>\n\t<translation id=\"2441920677226386245\">пользовательский список</translation>\n\t<translation id=\"1223194855937061908\">идентификаторы видео</translation>\n\t<translation id=\"4103549354606724944\">линии клиентов</translation>\n\t<translation id=\"7262144878230347914\">фоновый цвет</translation>\n\t<translation id=\"1435085881129646880\">По умолчанию последовательный плейлист</translation>\n\t<translation id=\"1587536276491357593\">Общее расположение на основе:></translation>\n\t<translation id=\"3325180562659478330\">имя</translation>\n\t<translation id=\"3051480550159545291\">широта</translation>\n\t<translation id=\"2703718513716530782\">долгота</translation>\n\t<translation id=\"5602245631444655788\">продолжительность</translation>\n\t<translation id=\"118487254857410201\">диапазон радиус</translation>\n\t<translation id=\"9178543898761255307\">километров</translation>\n\t<translation id=\"7866202877490561957\">коллизия приоритетов</translation>\n\t<translation id=\"720146333131008909\">добавить содержимое в сцене</translation>\n\t<translation id=\"8729372534532732068\">название сцены</translation>\n\t<translation id=\"2224690894219674949\">режим моделирования</translation>\n\t<translation id=\"7220335122322620944\">Подробнее о предприятии</translation>\n\t<translation id=\"8444323300278462770\">Вверх</translation>\n\t<translation id=\"7449548947549758066\">оставил</translation>\n\t<translation id=\"9172672254266086971\">ширина</translation>\n\t<translation id=\"4093381701787958997\">высота</translation>\n\t<translation id=\"2062170564010556149\">вращение</translation>\n\t<translation id=\"9088937454320275395\">применить изменения</translation>\n\t<translation id=\"1870560040946711505\">запертый</translation>\n\t<translation id=\"6108618462851148193\">редактор кампании</translation>\n\t<translation id=\"2741646832903808697\">расположение экрана</translation>\n\t<translation id=\"6454444033973204385\">выбор кампании</translation>\n\t<translation id=\"6028894272398949430\">новая кампания</translation>\n\t<translation id=\"3008329758802399315\">Получить мастер помощь</translation>\n\t<translation id=\"4145364267099301397\">Выберите название кампании</translation>\n\t<translation id=\"3843469504048287640\">Введите новое название кампании</translation>\n\t<translation id=\"4895430942430831092\">Идентификатор кампании:</translation>\n\t<translation id=\"1901427837939428954\">режим киоска</translation>\n\t<translation id=\"8329228391349300722\">Кампания режима воспроизведения:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (простой режим):</translation>\n\t<translation id=\"4691632839818550461\">Играть временные рамки для этой кампании в непрерывном цикле. Он прост в установке и прост в использовании</translation>\n\t<translation id=\"6075423017399759230\">Планировщик (расширенный режим):</translation>\n\t<translation id=\"750837672459228230\">Играть временные рамки для этой кампании только в определенные моменты времени. Например, играть Timeline А утром и Timeline B в ночное время.</translation>\n\t<translation id=\"1167977099462453641\">разрешение экрана</translation>\n\t<translation id=\"7626905534069326448\">Приоритет Conflict:</translation>\n\t<translation id=\"4220765745195024064\">Продолжительность:</translation>\n\t<translation id=\"4049333306580215724\">играть один раз</translation>\n\t<translation id=\"7249155645987524413\">играть ежедневно</translation>\n\t<translation id=\"8568181330490588741\">играть в неделю</translation>\n\t<translation id=\"3408786538616090951\">Выберите дни:</translation>\n\t<translation id=\"6324587259626414962\">Повторяю, чтобы соответствовать</translation>\n\t<translation id=\"2012264763266897754\">случайный порядок</translation>\n\t<translation id=\"4324819244706823449\">редактировать макет</translation>\n\t<translation id=\"5755245564638965488\">следующий канал</translation>\n\t<translation id=\"2925036210758384238\">Выбранная линия</translation>\n\t<translation id=\"3601209751322374737\">напоминание перед людьми</translation>\n\t<translation id=\"1790884679999452685\">открыт терминал</translation>\n\t<translation id=\"4878432943521432749\">сброс линии</translation>\n\t<translation id=\"3728601907282119753\">свойства очереди</translation>\n\t<translation id=\"2536017892630886700\">выбранный клиентом:</translation>\n\t<translation id=\"6228967158577655533\">проверка:</translation>\n\t<translation id=\"6435015929996679472\">называют:</translation>\n\t<translation id=\"8711852116268389728\">выбор сцены</translation>\n\t<translation id=\"5053705054681686956\">новая линия</translation>\n\t<translation id=\"5225640858395745699\">удалить строку</translation>\n\t<translation id=\"3116266439138367996\">связи</translation>\n\t<translation id=\"4159874591284333337\">Работает на угловыми рамках компании Google</translation>\n\t<translation id=\"3008186756887926107\">загрузить файлы</translation>\n\t<translation id=\"2123171795960509943\">Удалить</translation>\n\t<translation id=\"7246196759043272468\">список</translation>\n\t<translation id=\"946077791002604877\">сетка</translation>\n\t<translation id=\"5936943188558553659\">Поддерживаемые файлы: FLV, MP4, JPG, PNG, SWF и SVG</translation>\n\t<translation id=\"8054250976557949996\">новая сцена</translation>\n\t<translation id=\"6133338617402043535\">дублировать</translation>\n\t<translation id=\"1576591662761177526\">шаблон импорта</translation>\n\t<translation id=\"2225048990372533999\">перезагружать</translation>\n\t<translation id=\"987425828725037788\">айпи адрес</translation>\n\t<translation id=\"1646067470190508925\">порт</translation>\n\t<translation id=\"8097415329769247281\">Выберите пакет, который подходит для вас</translation>\n\n\t<translation id=\"6570363013146073520\">Панель приборов</translation>\n\t<translation id=\"8864658120410603626\">Кампании</translation>\n\t<translation id=\"2446117790692479672\">Ресурсы</translation>\n\t<translation id=\"794120057687191331\">Сцены</translation>\n\t<translation id=\"4846792506513649213\">станций</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Помогите</translation>\n\t<translation id=\"6082171864197428613\">устанавливать</translation>\n\t<translation id=\"3476206505271758484\">StudioPRO</translation>\n\t<translation id=\"3797778920049399855\">Выйти</translation>\n\t<translation id=\"7746065369460476808\">Имя пользователя или адрес электронной почты</translation>\n\t<translation id=\"4809196861118879526\">пароль</translation>\n\t<translation id=\"9162857816822524614\">введите два ключа фактора</translation>\n\t<translation id=\"24227595514967590\">с Google идентифицирующей</translation>\n\t<translation id=\"2001940299854753031\">Запомни меня</translation>\n\t<translation id=\"5872337092278414963\">Забыли пароль</translation>\n\t<translation id=\"8246600873004586882\">изменить пароль</translation>\n\t<translation id=\"5289326240092186479\">наименование изменение</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">Старый пароль</translation>\n\t<translation id=\"48285893667252664\">новый пароль</translation>\n\t<translation id=\"6917932917401642982\">повторите новый пароль</translation>\n\t<translation id=\"5666893431176348635\">новое название компании</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">Обновить</translation>\n\t<translation id=\"8894542476475088437\">Счет-S</translation>\n\t<translation id=\"2347724151568473592\">язык</translation>\n\t<translation id=\"4376434433661751094\">Живой чат</translation>\n\t<translation id=\"5344752701442428839\">Веб-сайт</translation>\n\t<translation id=\"7108535247064136881\">Выберите свой язык</translation>\n\t<translation id=\"4137049537431219133\">Войдите в свою учетную запись с помощью аутентификатора Google</translation>\n\t<translation id=\"4785021168351486737\">Сохранить и выйти из системы</translation>\n\t<translation id=\"6524180701596149125\">Только выход</translation>\n\n\t<translation id=\"2503331336991669578\">Войдите в свой аккаунт</translation>\n\t<translation id=\"8359621426539146583\">У вас нет учетной записи?</translation>\n\t<translation id=\"569785428576811345\">Продолжительность:</translation>\n\t<translation id=\"9043806075514219833\">Время начала:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/template.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\":LANG:\">\n</translationbundle>\n"
  },
  {
    "path": "src/locale/th.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"th\">\n\t<translation id=\"9198441993514322349\">วางหน้าจอ</translation>\n\t<translation id=\"2838690440296896849\">สถานะระยะไกล</translation>\n\t<translation id=\"2849064100927111571\">loading ...</translation>\n\t<translation id=\"7309719557896597512\">ขอให้มีความสุขมาก ๆ ในวันนี้นะ</translation>\n\t<translation id=\"5805758016483237261\">อัพเกรดเป็นองค์กร - $ 99.00 ต่อเดือน</translation>\n\t<translation id=\"7212624462478696127\">การตรวจสอบการเข้าถึง ...</translation>\n\t<translation id=\"1156206314346372426\">แดชบอร์ดบัญชี</translation>\n\t<translation id=\"892759319569190037\">สีพื้นหลังที่เกิดเหตุ</translation>\n\t<translation id=\"463077023711449502\">สีของเส้นขอบ</translation>\n\t<translation id=\"7844431484369877777\">URL</translation>\n\t<translation id=\"6727478076005438064\">เลือกรูปแบบ</translation>\n\t<translation id=\"8932917860978648376\">หน่วย</translation>\n\t<translation id=\"6447113917741810043\">ฟาเรนไฮต์</translation>\n\t<translation id=\"1546647220090341106\">เซลเซียส</translation>\n\t<translation id=\"6977749640368501596\">รูปแบบ</translation>\n\t<translation id=\"30300572504753589\">สีดำ</translation>\n\t<translation id=\"7850674593676755019\">ขาว</translation>\n\t<translation id=\"9011959596901584887\">สี</translation>\n\t<translation id=\"5667922561719642173\">โหลดฉาก</translation>\n\t<translation id=\"5466334165625502718\">ระยะห่าง</translation>\n\t<translation id=\"1128028236258747485\">เล่นวิดีโอที่จะเสร็จสิ้น</translation>\n\t<translation id=\"3372777815572567783\">การเล่นแบบสุ่ม</translation>\n\t<translation id=\"6757770085960264448\">สไลด์โชว์</translation>\n\t<translation id=\"6659445582099947212\">เหรียญ</translation>\n\t<translation id=\"6262368721870308838\">สร้างโทเค็นการเข้าถึง Instagram</translation>\n\t<translation id=\"6358635099770142731\">สร้างโทเค็น</translation>\n\t<translation id=\"7499211462525828161\">โหลดกับปฏิทิน</translation>\n\t<translation id=\"3128474301651540051\">ชดเชยโหมดช่วง</translation>\n\t<translation id=\"5645011507444946232\">วันก่อนวันนี้</translation>\n\t<translation id=\"472347571959391022\">วันหลังจากวันนี้</translation>\n\t<translation id=\"7382546590159708114\">วันที่เริ่มต้น</translation>\n\t<translation id=\"8615958092383580706\">วันที่สิ้นสุด</translation>\n\t<translation id=\"7824071976623180870\">โหลดด้วยแผ่น</translation>\n\t<translation id=\"4370305429271412983\">ชื่อหน้าจอ</translation>\n\t<translation id=\"7641098557273120361\">สร้างโทเค็นการเข้าถึง</translation>\n\t<translation id=\"361150460746746781\">รักษาอัตราส่วน</translation>\n\t<translation id=\"3046991000485970172\">รีเฟรช RSS (นาที)</translation>\n\t<translation id=\"2303401327609002516\">RSS ทิศทางเลื่อน</translation>\n\t<translation id=\"8382375758916799432\">ตามแนวนอน</translation>\n\t<translation id=\"160958144287367985\">แนวตั้ง</translation>\n\t<translation id=\"5576694760844259892\">ความเร็วของการเลื่อน RSS</translation>\n\t<translation id=\"3801245379625272309\">ช้า</translation>\n\t<translation id=\"4688460977394283086\">กลาง</translation>\n\t<translation id=\"9161614188045173336\">รวดเร็ว</translation>\n\t<translation id=\"6107231410782382609\">เกี่ยวกับเหตุการณ์ที่จะดำเนินการดังต่อไปนี้</translation>\n\t<translation id=\"8875363048655701399\">โหมดคีออสก์</translation>\n\t<translation id=\"6880124786888445040\">เล่นคอลเลกชันในลำดับ</translation>\n\t<translation id=\"2166463051767640100\">เพิ่มเนื้อหาในคอลเลกชัน</translation>\n\t<translation id=\"7365517136074263312\">คิวอาร์โค้ด</translation>\n\t<translation id=\"810733191089543608\">ปริมาณ</translation>\n\t<translation id=\"4815249204085613710\">คุณภาพวีดีโอ</translation>\n\t<translation id=\"5082095396043563283\">ภูมิภาค</translation>\n\t<translation id=\"396267502411280310\">เข้าชมมากที่สุด</translation>\n\t<translation id=\"2441920677226386245\">รายการที่กำหนดเอง</translation>\n\t<translation id=\"1223194855937061908\">รหัสวิดีโอ</translation>\n\t<translation id=\"4103549354606724944\">สายลูกค้า</translation>\n\t<translation id=\"7262144878230347914\">สีพื้นหลัง</translation>\n\t<translation id=\"1435085881129646880\">เริ่มต้นรายการเพลงตามลำดับ</translation>\n\t<translation id=\"1587536276491357593\">สถานที่ตั้งรวมตาม:></translation>\n\t<translation id=\"3325180562659478330\">ชื่อ</translation>\n\t<translation id=\"3051480550159545291\">ละติจูด</translation>\n\t<translation id=\"2703718513716530782\">ลองจิจูด</translation>\n\t<translation id=\"5602245631444655788\">ระยะเวลา</translation>\n\t<translation id=\"118487254857410201\">ช่วงรัศมี</translation>\n\t<translation id=\"9178543898761255307\">กิโลเมตร</translation>\n\t<translation id=\"7866202877490561957\">ลำดับความสำคัญของความขัดแย้ง</translation>\n\t<translation id=\"720146333131008909\">เพิ่มเนื้อหาไปที่เกิดเหตุ</translation>\n\t<translation id=\"8729372534532732068\">ชื่อสถานที่เกิดเหตุ</translation>\n\t<translation id=\"2224690894219674949\">โหมดการจำลอง</translation>\n\t<translation id=\"7220335122322620944\">เรียนรู้เพิ่มเติมเกี่ยวกับองค์กร</translation>\n\t<translation id=\"8444323300278462770\">ด้านบน</translation>\n\t<translation id=\"7449548947549758066\">ซ้าย</translation>\n\t<translation id=\"9172672254266086971\">ความกว้าง</translation>\n\t<translation id=\"4093381701787958997\">ความสูง</translation>\n\t<translation id=\"2062170564010556149\">การหมุน</translation>\n\t<translation id=\"9088937454320275395\">ใช้การเปลี่ยนแปลง</translation>\n\t<translation id=\"1870560040946711505\">ล็อค</translation>\n\t<translation id=\"6108618462851148193\">แก้ไขแคมเปญ</translation>\n\t<translation id=\"2741646832903808697\">รูปแบบหน้าจอ</translation>\n\t<translation id=\"6454444033973204385\">เลือกแคมเปญ</translation>\n\t<translation id=\"6028894272398949430\">แคมเปญใหม่</translation>\n\t<translation id=\"3008329758802399315\">รับตัวช่วยสร้างความช่วยเหลือ</translation>\n\t<translation id=\"4145364267099301397\">เลือกชื่อแคมเปญของคุณ</translation>\n\t<translation id=\"3843469504048287640\">ป้อนชื่อแคมเปญใหม่</translation>\n\t<translation id=\"4895430942430831092\">รหัสแคมเปญ:</translation>\n\t<translation id=\"1901427837939428954\">ตู้โหมด</translation>\n\t<translation id=\"8329228391349300722\">แคมเปญโหมดการเล่น:</translation>\n\t<translation id=\"8793145092368811184\">ซีเควน (โหมดง่าย):</translation>\n\t<translation id=\"4691632839818550461\">เล่นระยะเวลาสำหรับแคมเปญนี้ในวงอย่างต่อเนื่อง มันเป็นเรื่องง่ายที่จะติดตั้งและใช้งานง่าย</translation>\n\t<translation id=\"6075423017399759230\">จัดตารางเวลา (โหมดขั้นสูง):</translation>\n\t<translation id=\"750837672459228230\">เล่นระยะเวลาสำหรับแคมเปญนี้เฉพาะในเวลาที่เฉพาะเจาะจง ยกตัวอย่างเช่นการเล่นเส้นในตอนเช้าและเส้น B ในเวลากลางคืน</translation>\n\t<translation id=\"1167977099462453641\">ความละเอียดหน้าจอ</translation>\n\t<translation id=\"7626905534069326448\">ลำดับความสำคัญของความขัดแย้ง:</translation>\n\t<translation id=\"4220765745195024064\">ระยะเวลา:</translation>\n\t<translation id=\"4049333306580215724\">เล่นครั้งเดียว</translation>\n\t<translation id=\"7249155645987524413\">เล่นทุกวัน</translation>\n\t<translation id=\"8568181330490588741\">เล่นรายสัปดาห์</translation>\n\t<translation id=\"3408786538616090951\">เลือกวันนี้:</translation>\n\t<translation id=\"6324587259626414962\">ทำซ้ำเพื่อให้พอดีกับ</translation>\n\t<translation id=\"2012264763266897754\">ลำดับแบบสุ่ม</translation>\n\t<translation id=\"4324819244706823449\">แก้ไขรูปแบบ</translation>\n\t<translation id=\"5755245564638965488\">ช่องถัดไป</translation>\n\t<translation id=\"2925036210758384238\">บรรทัดที่เลือก</translation>\n\t<translation id=\"3601209751322374737\">การแจ้งเตือนล่วงหน้าของผู้คน</translation>\n\t<translation id=\"1790884679999452685\">เปิดสถานี</translation>\n\t<translation id=\"4878432943521432749\">สายการตั้งค่า</translation>\n\t<translation id=\"3728601907282119753\">คุณสมบัติคิว</translation>\n\t<translation id=\"2536017892630886700\">ลูกค้าที่เลือก:</translation>\n\t<translation id=\"6228967158577655533\">การตรวจสอบ:</translation>\n\t<translation id=\"6435015929996679472\">เรียกโดย:</translation>\n\t<translation id=\"8711852116268389728\">เลือกฉาก</translation>\n\t<translation id=\"5053705054681686956\">บรรทัดใหม่</translation>\n\t<translation id=\"5225640858395745699\">ลบบรรทัด</translation>\n\t<translation id=\"3116266439138367996\">การเชื่อมโยง</translation>\n\t<translation id=\"4159874591284333337\">ขับเคลื่อนโดยกรอบเชิงมุมของ Google</translation>\n\t<translation id=\"3008186756887926107\">อัพโหลดไฟล์</translation>\n\t<translation id=\"2123171795960509943\">เอาออก</translation>\n\t<translation id=\"7246196759043272468\">รายการ</translation>\n\t<translation id=\"946077791002604877\">ตะแกรง</translation>\n\t<translation id=\"5936943188558553659\">ไฟล์ที่รองรับ: FLV, MP4, JPG, PNG, SWF และ SVG</translation>\n\t<translation id=\"8054250976557949996\">ฉากใหม่</translation>\n\t<translation id=\"6133338617402043535\">ซ้ำ</translation>\n\t<translation id=\"1576591662761177526\">แม่แบบนำเข้า</translation>\n\t<translation id=\"2225048990372533999\">โหลด</translation>\n\t<translation id=\"987425828725037788\">ที่อยู่ IP</translation>\n\t<translation id=\"1646067470190508925\">ท่าเรือ</translation>\n\n\t<translation id=\"8097415329769247281\">เลือกแพคเกจที่เหมาะสมสำหรับคุณ</translation>\n\n\t<translation id=\"6570363013146073520\">แผงควบคุม</translation>\n\t<translation id=\"8864658120410603626\">แคมเปญ</translation>\n\t<translation id=\"2446117790692479672\">ทรัพยากร</translation>\n\t<translation id=\"794120057687191331\">ฉาก</translation>\n\t<translation id=\"4846792506513649213\">สถานี</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">ช่วยด้วย</translation>\n\t<translation id=\"6082171864197428613\">ติดตั้ง</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">ออกจากระบบ</translation>\n\t<translation id=\"7746065369460476808\">ชื่อผู้ใช้หรืออีเมล</translation>\n\t<translation id=\"4809196861118879526\">รหัสผ่าน</translation>\n\t<translation id=\"9162857816822524614\">ป้อนคีย์ปัจจัยที่สอง</translation>\n\t<translation id=\"24227595514967590\">ด้วย Google Authenticator</translation>\n\t<translation id=\"2001940299854753031\">จดจำฉัน</translation>\n\t<translation id=\"5872337092278414963\">ลืมรหัสผ่าน</translation>\n\t<translation id=\"8246600873004586882\">เปลี่ยนรหัสผ่าน</translation>\n\t<translation id=\"5289326240092186479\">ชื่อธุรกิจเปลี่ยนแปลง</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">รหัสผ่านเก่า</translation>\n\t<translation id=\"48285893667252664\">รหัสผ่านใหม่</translation>\n\t<translation id=\"6917932917401642982\">รหัสผ่านใหม่ซ้ำ</translation>\n\t<translation id=\"5666893431176348635\">ชื่อธุรกิจใหม่</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">อัพเกรด</translation>\n\t<translation id=\"8894542476475088437\">บัญชี-S</translation>\n\t<translation id=\"2347724151568473592\">ภาษา</translation>\n\t<translation id=\"4376434433661751094\">แชทสด</translation>\n\t<translation id=\"5344752701442428839\">เว็บไซต์</translation>\n\t<translation id=\"7108535247064136881\">เลือกภาษาของคุณ</translation>\n\t<translation id=\"4137049537431219133\">เข้าสู่บัญชีของคุณด้วย Google authenticator</translation>\n\t<translation id=\"4785021168351486737\">บันทึก & ออกจากระบบ</translation>\n\t<translation id=\"6524180701596149125\">เพิ่งออกจากระบบ</translation>\n\n\t<translation id=\"2503331336991669578\">ลงชื่อเข้าใช้บัญชีของคุณ</translation>\n\t<translation id=\"8359621426539146583\">ยังไม่มีบัญชี</translation>\n\t<translation id=\"569785428576811345\">ระยะเวลา:</translation>\n\t<translation id=\"9043806075514219833\">เวลาเริ่มต้น:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/tl.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"tl\">\n\t<translation id=\"9198441993514322349\">screen orientation</translation>\n\t<translation id=\"2838690440296896849\">remote status</translation>\n\t<translation id=\"2849064100927111571\">naglo-load ...</translation>\n\t<translation id=\"7309719557896597512\">magandang araw</translation>\n\t<translation id=\"5805758016483237261\">Mag-upgrade sa Enterprise - $ 99.00 bawat buwan</translation>\n\t<translation id=\"7212624462478696127\">pag-verify ng pag-access ...</translation>\n\t<translation id=\"1156206314346372426\">account dashboard</translation>\n\t<translation id=\"892759319569190037\">kulay scene background</translation>\n\t<translation id=\"463077023711449502\">kulay ng border</translation>\n\t<translation id=\"7844431484369877777\">url</translation>\n\t<translation id=\"6727478076005438064\">Pumili ng format</translation>\n\t<translation id=\"8932917860978648376\">yunit</translation>\n\t<translation id=\"6447113917741810043\">Parenhayt</translation>\n\t<translation id=\"1546647220090341106\">Sentigrado</translation>\n\t<translation id=\"6977749640368501596\">Mga estilo</translation>\n\t<translation id=\"30300572504753589\">itim</translation>\n\t<translation id=\"7850674593676755019\">puti</translation>\n\t<translation id=\"9011959596901584887\">kulay</translation>\n\t<translation id=\"5667922561719642173\">load na may tanawin</translation>\n\t<translation id=\"5466334165625502718\">agwat</translation>\n\t<translation id=\"1128028236258747485\">i-play ang video sa pagkumpleto</translation>\n\t<translation id=\"3372777815572567783\">random playback</translation>\n\t<translation id=\"6757770085960264448\">slideshow</translation>\n\t<translation id=\"6659445582099947212\">token</translation>\n\t<translation id=\"6262368721870308838\">lumikha ng instagram access token</translation>\n\t<translation id=\"6358635099770142731\">lumikha ng token</translation>\n\t<translation id=\"7499211462525828161\">Mag-load na may calendar</translation>\n\t<translation id=\"3128474301651540051\">offset range mode</translation>\n\t<translation id=\"5645011507444946232\">araw bago ang araw na ito</translation>\n\t<translation id=\"472347571959391022\">araw pagkatapos ng araw na ito</translation>\n\t<translation id=\"7382546590159708114\">petsa ng pagsisimula</translation>\n\t<translation id=\"8615958092383580706\">petsa ng pagtatapos</translation>\n\t<translation id=\"7824071976623180870\">Mag-load na may sheet</translation>\n\t<translation id=\"4370305429271412983\">screen name</translation>\n\t<translation id=\"7641098557273120361\">lumikha ng access token</translation>\n\t<translation id=\"361150460746746781\">mapanatili ang aspect ratio</translation>\n\t<translation id=\"3046991000485970172\">RSS refresh (minuto)</translation>\n\t<translation id=\"2303401327609002516\">RSS scroll direksyon</translation>\n\t<translation id=\"8382375758916799432\">Pahalang</translation>\n\t<translation id=\"160958144287367985\">patayo</translation>\n\t<translation id=\"5576694760844259892\">RSS scroll bilis</translation>\n\t<translation id=\"3801245379625272309\">mabagal</translation>\n\t<translation id=\"4688460977394283086\">medium</translation>\n\t<translation id=\"9161614188045173336\">mabilis</translation>\n\t<translation id=\"6107231410782382609\">Sa kaganapan gawin ang sumusunod na aksyon</translation>\n\t<translation id=\"8875363048655701399\">Kiosk mode</translation>\n\t<translation id=\"6880124786888445040\">I-play koleksyon sa pagkakasunod-sunod</translation>\n\t<translation id=\"2166463051767640100\">magdagdag ng nilalaman sa koleksyon</translation>\n\t<translation id=\"7365517136074263312\">QR code</translation>\n\t<translation id=\"810733191089543608\">dami</translation>\n\t<translation id=\"4815249204085613710\">kalidad ng video</translation>\n\t<translation id=\"5082095396043563283\">rehiyon</translation>\n\t<translation id=\"396267502411280310\">pinaka-pinapanood</translation>\n\t<translation id=\"2441920677226386245\">pasadyang listahan</translation>\n\t<translation id=\"1223194855937061908\">video ids</translation>\n\t<translation id=\"4103549354606724944\">linya ng customer</translation>\n\t<translation id=\"7262144878230347914\">kulay ng background</translation>\n\t<translation id=\"1435085881129646880\">Default sequential playlist</translation>\n\t<translation id=\"1587536276491357593\">Kabuuang mga lokasyon batay:></translation>\n\t<translation id=\"3325180562659478330\">pangalan</translation>\n\t<translation id=\"3051480550159545291\">latitud</translation>\n\t<translation id=\"2703718513716530782\">longhitud</translation>\n\t<translation id=\"5602245631444655788\">tagal</translation>\n\t<translation id=\"118487254857410201\">radius range</translation>\n\t<translation id=\"9178543898761255307\">kilometro</translation>\n\t<translation id=\"7866202877490561957\">priority salungatan</translation>\n\t<translation id=\"720146333131008909\">magdagdag ng nilalaman sa scene</translation>\n\t<translation id=\"8729372534532732068\">pangalan ng eksena</translation>\n\t<translation id=\"2224690894219674949\">simulation mode</translation>\n\t<translation id=\"7220335122322620944\">Matuto nang higit pa tungkol sa Enterprise</translation>\n\t<translation id=\"8444323300278462770\">tuktok</translation>\n\t<translation id=\"7449548947549758066\">kaliwa</translation>\n\t<translation id=\"9172672254266086971\">lapad</translation>\n\t<translation id=\"4093381701787958997\">taas</translation>\n\t<translation id=\"2062170564010556149\">pag-ikot</translation>\n\t<translation id=\"9088937454320275395\">ilapat ang mga pagbabago</translation>\n\t<translation id=\"1870560040946711505\">nakakandado</translation>\n\t<translation id=\"6108618462851148193\">editor ng kampanya</translation>\n\t<translation id=\"2741646832903808697\">layout ng screen</translation>\n\t<translation id=\"6454444033973204385\">pagpili ng kampanya</translation>\n\t<translation id=\"6028894272398949430\">bagong kampanya</translation>\n\t<translation id=\"3008329758802399315\">Kumuha ng Wizard tulong</translation>\n\t<translation id=\"4145364267099301397\">Piliin ang pangalan ng iyong kampanya</translation>\n\t<translation id=\"3843469504048287640\">Magpasok ng bagong pangalan ng kampanya</translation>\n\t<translation id=\"4895430942430831092\">id ng kampanya:</translation>\n\t<translation id=\"1901427837939428954\">kiosk mode</translation>\n\t<translation id=\"8329228391349300722\">Kampanya playback mode:</translation>\n\t<translation id=\"8793145092368811184\">Sequencer (simple mode):</translation>\n\t<translation id=\"4691632839818550461\">I-play timeline para sa kampanyang ito sa isang tuloy-tuloy na loop. Ito ay madali upang i-setup at simpleng upang gamitin ang</translation>\n\t<translation id=\"6075423017399759230\">Scheduler (advanced mode):</translation>\n\t<translation id=\"750837672459228230\">I-play timeline para sa kampanyang ito lamang sa mga tiyak na beses. Halimbawa, i-play Timeline A sa umaga at Timeline B sa gabi.</translation>\n\t<translation id=\"1167977099462453641\">resolution ng screen</translation>\n\t<translation id=\"7626905534069326448\">Conflict priority:</translation>\n\t<translation id=\"4220765745195024064\">Tagal:</translation>\n\t<translation id=\"4049333306580215724\">i-play nang isang beses</translation>\n\t<translation id=\"7249155645987524413\">i-play ang araw-araw na</translation>\n\t<translation id=\"8568181330490588741\">i-play ang lingguhang</translation>\n\t<translation id=\"3408786538616090951\">Piliin ang mga araw:</translation>\n\t<translation id=\"6324587259626414962\">ulitin upang magkasya</translation>\n\t<translation id=\"2012264763266897754\">random order</translation>\n\t<translation id=\"4324819244706823449\">edit layout</translation>\n\t<translation id=\"5755245564638965488\">susunod na channel</translation>\n\t<translation id=\"2925036210758384238\">napiling linya</translation>\n\t<translation id=\"3601209751322374737\">paalala nangunguna sa mga tao</translation>\n\t<translation id=\"1790884679999452685\">bukas na terminal</translation>\n\t<translation id=\"4878432943521432749\">reset linya</translation>\n\t<translation id=\"3728601907282119753\">queue properties</translation>\n\t<translation id=\"2536017892630886700\">pinili ng customer:</translation>\n\t<translation id=\"6228967158577655533\">pag-verify:</translation>\n\t<translation id=\"6435015929996679472\">na tinatawag sa pamamagitan ng:</translation>\n\t<translation id=\"8711852116268389728\">pagpili ng eksena</translation>\n\t<translation id=\"5053705054681686956\">bagong linya</translation>\n\t<translation id=\"5225640858395745699\">alisin linya</translation>\n\t<translation id=\"3116266439138367996\">mga link</translation>\n\t<translation id=\"4159874591284333337\">Pinapatakbo ng Angular framework Google</translation>\n\t<translation id=\"3008186756887926107\">upload ng mga file</translation>\n\t<translation id=\"2123171795960509943\">alisin</translation>\n\t<translation id=\"7246196759043272468\">listahan</translation>\n\t<translation id=\"946077791002604877\">parilya</translation>\n\t<translation id=\"5936943188558553659\">suportado ng mga file: flv, mp4, jpg, png, swf at svg</translation>\n\t<translation id=\"8054250976557949996\">bagong eksena</translation>\n\t<translation id=\"6133338617402043535\">Kopyahin</translation>\n\t<translation id=\"1576591662761177526\">import template</translation>\n\t<translation id=\"2225048990372533999\">reload</translation>\n\t<translation id=\"987425828725037788\">IP address</translation>\n\t<translation id=\"1646067470190508925\">port</translation>\n\t<translation id=\"8097415329769247281\">Piliin ang package na tama para sa iyo</translation>\n\n\t<translation id=\"6570363013146073520\">Dashboard</translation>\n\t<translation id=\"8864658120410603626\">Kampanya</translation>\n\t<translation id=\"2446117790692479672\">kayamanan</translation>\n\t<translation id=\"794120057687191331\">Mga eksena</translation>\n\t<translation id=\"4846792506513649213\">Stations</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">Tulong</translation>\n\t<translation id=\"6082171864197428613\">I-install</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">Mag-logout</translation>\n\t<translation id=\"7746065369460476808\">user name o email</translation>\n\t<translation id=\"4809196861118879526\">password</translation>\n\t<translation id=\"9162857816822524614\">maglagay ng dalawang mga kadahilanan susi</translation>\n\t<translation id=\"24227595514967590\">sa Google authenticator</translation>\n\t<translation id=\"2001940299854753031\">Tandaan mo ako</translation>\n\t<translation id=\"5872337092278414963\">Nakalimutan ang password</translation>\n\t<translation id=\"8246600873004586882\">palitan ANG password</translation>\n\t<translation id=\"5289326240092186479\">pagbabago ng pangalan ng negosyo</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">Lumang password</translation>\n\t<translation id=\"48285893667252664\">bagong password</translation>\n\t<translation id=\"6917932917401642982\">paulit-ulit na bagong password</translation>\n\t<translation id=\"5666893431176348635\">bagong pangalan ng negosyo</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">pag-upgrade</translation>\n\t<translation id=\"8894542476475088437\">Account-S</translation>\n\t<translation id=\"2347724151568473592\">wika</translation>\n\t<translation id=\"4376434433661751094\">live na chat</translation>\n\t<translation id=\"5344752701442428839\">website</translation>\n\t<translation id=\"7108535247064136881\">Piliin ang iyong wika</translation>\n\t<translation id=\"4137049537431219133\">mag-login sa iyong account sa Google authenticator</translation>\n\t<translation id=\"4785021168351486737\">I-save & Logout</translation>\n\t<translation id=\"6524180701596149125\">Just Logout</translation>\n\n\t<translation id=\"2503331336991669578\">mag-login sa iyong account</translation>\n\t<translation id=\"8359621426539146583\">Huwag magkaroon ng isang account</translation>\n\t<translation id=\"569785428576811345\">Tagal:</translation>\n\t<translation id=\"9043806075514219833\">Oras ng pagsisimula:</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/locale/zh-CN.xtb",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE translationbundle [\n<!ELEMENT translationbundle (translation)*>\n<!ATTLIST translationbundle lang CDATA #REQUIRED>\n\n<!ELEMENT translation (#PCDATA|ph)*>\n<!ATTLIST translation id CDATA #REQUIRED>\n<!ATTLIST translation desc CDATA #IMPLIED>\n<!ATTLIST translation meaning CDATA #IMPLIED>\n<!ATTLIST translation xml:space (default|preserve) \"default\">\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>\n]>\n<translationbundle lang=\"zh-CN\">\n\t<translation id=\"9198441993514322349\">屏幕方向</translation>\n\t<translation id=\"2838690440296896849\">远程状态</translation>\n\t<translation id=\"2849064100927111571\">载入中...</translation>\n\t<translation id=\"7309719557896597512\">祝你今天愉快</translation>\n\t<translation id=\"5805758016483237261\">升级到企业 - 每月$ 99.00</translation>\n\t<translation id=\"7212624462478696127\">验证访问...</translation>\n\t<translation id=\"1156206314346372426\">帐户控制面板</translation>\n\t<translation id=\"892759319569190037\">现场的背景颜色</translation>\n\t<translation id=\"463077023711449502\">边框颜色</translation>\n\t<translation id=\"7844431484369877777\">网址</translation>\n\t<translation id=\"6727478076005438064\">选择格式</translation>\n\t<translation id=\"8932917860978648376\">单元</translation>\n\t<translation id=\"6447113917741810043\">飞轮海</translation>\n\t<translation id=\"1546647220090341106\">摄氏</translation>\n\t<translation id=\"6977749640368501596\">样式</translation>\n\t<translation id=\"30300572504753589\">黑色</translation>\n\t<translation id=\"7850674593676755019\">白色</translation>\n\t<translation id=\"9011959596901584887\">颜色</translation>\n\t<translation id=\"5667922561719642173\">负载场景</translation>\n\t<translation id=\"5466334165625502718\">间隔</translation>\n\t<translation id=\"1128028236258747485\">播放视频完成</translation>\n\t<translation id=\"3372777815572567783\">随机播放</translation>\n\t<translation id=\"6757770085960264448\">幻灯片</translation>\n\t<translation id=\"6659445582099947212\">代币</translation>\n\t<translation id=\"6262368721870308838\">创建Instagram的访问令牌</translation>\n\t<translation id=\"6358635099770142731\">创建令牌</translation>\n\t<translation id=\"7499211462525828161\">负载日历</translation>\n\t<translation id=\"3128474301651540051\">偏移范围模式</translation>\n\t<translation id=\"5645011507444946232\">前几天的今天</translation>\n\t<translation id=\"472347571959391022\">天后的今天</translation>\n\t<translation id=\"7382546590159708114\">开始日期</translation>\n\t<translation id=\"8615958092383580706\">结束日期</translation>\n\t<translation id=\"7824071976623180870\">负载与片</translation>\n\t<translation id=\"4370305429271412983\">屏幕名称</translation>\n\t<translation id=\"7641098557273120361\">创建接入令牌</translation>\n\t<translation id=\"361150460746746781\">保持纵横比</translation>\n\t<translation id=\"3046991000485970172\">RSS刷新（分钟）</translation>\n\t<translation id=\"2303401327609002516\">RSS滚动方向</translation>\n\t<translation id=\"8382375758916799432\">横</translation>\n\t<translation id=\"160958144287367985\">垂直</translation>\n\t<translation id=\"5576694760844259892\">RSS滚动速度</translation>\n\t<translation id=\"3801245379625272309\">慢</translation>\n\t<translation id=\"4688460977394283086\">中</translation>\n\t<translation id=\"9161614188045173336\">快速</translation>\n\t<translation id=\"6107231410782382609\">事件采取以下措施</translation>\n\t<translation id=\"8875363048655701399\">Kiosk模式</translation>\n\t<translation id=\"6880124786888445040\">按顺序播放采集</translation>\n\t<translation id=\"2166463051767640100\">内容添加到收藏</translation>\n\t<translation id=\"7365517136074263312\">二维码</translation>\n\t<translation id=\"810733191089543608\">卷</translation>\n\t<translation id=\"4815249204085613710\">视频质量</translation>\n\t<translation id=\"5082095396043563283\">地区</translation>\n\t<translation id=\"396267502411280310\">最受关注</translation>\n\t<translation id=\"2441920677226386245\">自定义列表</translation>\n\t<translation id=\"1223194855937061908\">视频IDS</translation>\n\t<translation id=\"4103549354606724944\">用户线路</translation>\n\t<translation id=\"7262144878230347914\">背景颜色</translation>\n\t<translation id=\"1435085881129646880\">默认顺序播放列表</translation>\n\t<translation id=\"1587536276491357593\">总的基于位置：></translation>\n\t<translation id=\"3325180562659478330\">名称</translation>\n\t<translation id=\"3051480550159545291\">纬度</translation>\n\t<translation id=\"2703718513716530782\">经度</translation>\n\t<translation id=\"5602245631444655788\">持续时间</translation>\n\t<translation id=\"118487254857410201\">半径范围</translation>\n\t<translation id=\"9178543898761255307\">公里</translation>\n\t<translation id=\"7866202877490561957\">冲突的优先级</translation>\n\t<translation id=\"720146333131008909\">添加内容到现场</translation>\n\t<translation id=\"8729372534532732068\">场景名称</translation>\n\t<translation id=\"2224690894219674949\">模拟模式</translation>\n\t<translation id=\"7220335122322620944\">了解更多关于企业</translation>\n\t<translation id=\"8444323300278462770\">最佳</translation>\n\t<translation id=\"7449548947549758066\">剩下</translation>\n\t<translation id=\"9172672254266086971\">宽度</translation>\n\t<translation id=\"4093381701787958997\">高度</translation>\n\t<translation id=\"2062170564010556149\">回转</translation>\n\t<translation id=\"9088937454320275395\">应用更改</translation>\n\t<translation id=\"1870560040946711505\">锁定</translation>\n\t<translation id=\"6108618462851148193\">战役编辑器</translation>\n\t<translation id=\"2741646832903808697\">屏幕布局</translation>\n\t<translation id=\"6454444033973204385\">活动选择</translation>\n\t<translation id=\"6028894272398949430\">新战役</translation>\n\t<translation id=\"3008329758802399315\">获取向导的帮助</translation>\n\t<translation id=\"4145364267099301397\">选择您的广告系列的名称</translation>\n\t<translation id=\"3843469504048287640\">输入新广告系列名称</translation>\n\t<translation id=\"4895430942430831092\">活动ID：</translation>\n\t<translation id=\"1901427837939428954\">kiosk模式</translation>\n\t<translation id=\"8329228391349300722\">广告系列播放模式：</translation>\n\t<translation id=\"8793145092368811184\">测序仪（简单模式）：</translation>\n\t<translation id=\"4691632839818550461\">播放时间表这项运动在一个连续的循环。这是很容易设置和使用简单</translation>\n\t<translation id=\"6075423017399759230\">调度程序（高级模式）：</translation>\n\t<translation id=\"750837672459228230\">播放时间表此活动只在特定的时间。例如，播放时间轴中的一个早上和时间线B中的夜晚。</translation>\n\t<translation id=\"1167977099462453641\">屏幕分辨率</translation>\n\t<translation id=\"7626905534069326448\">冲突的优先级：</translation>\n\t<translation id=\"4220765745195024064\">持续时间：</translation>\n\t<translation id=\"4049333306580215724\">播放一次</translation>\n\t<translation id=\"7249155645987524413\">每天玩</translation>\n\t<translation id=\"8568181330490588741\">每周玩</translation>\n\t<translation id=\"3408786538616090951\">选择天数：</translation>\n\t<translation id=\"6324587259626414962\">重复，以适应</translation>\n\t<translation id=\"2012264763266897754\">随机顺序</translation>\n\t<translation id=\"4324819244706823449\">编辑布局</translation>\n\t<translation id=\"5755245564638965488\">下一个频道</translation>\n\t<translation id=\"2925036210758384238\">选择行</translation>\n\t<translation id=\"3601209751322374737\">超前的人提醒</translation>\n\t<translation id=\"1790884679999452685\">打开终端</translation>\n\t<translation id=\"4878432943521432749\">复位线</translation>\n\t<translation id=\"3728601907282119753\">队列属性</translation>\n\t<translation id=\"2536017892630886700\">选择客户：</translation>\n\t<translation id=\"6228967158577655533\">验证：</translation>\n\t<translation id=\"6435015929996679472\">所谓的：</translation>\n\t<translation id=\"8711852116268389728\">情景选择</translation>\n\t<translation id=\"5053705054681686956\">新队</translation>\n\t<translation id=\"5225640858395745699\">删除线</translation>\n\t<translation id=\"3116266439138367996\">链接</translation>\n\t<translation id=\"4159874591284333337\">搭载谷歌的角度框架</translation>\n\t<translation id=\"3008186756887926107\">上传文件</translation>\n\t<translation id=\"2123171795960509943\">去掉</translation>\n\t<translation id=\"7246196759043272468\">名单</translation>\n\t<translation id=\"946077791002604877\">格</translation>\n\t<translation id=\"5936943188558553659\">支持的文件：FLV，MP4，JPG，PNG，SWF和SVG</translation>\n\t<translation id=\"8054250976557949996\">新场景</translation>\n\t<translation id=\"6133338617402043535\">重复</translation>\n\t<translation id=\"1576591662761177526\">导入模板</translation>\n\t<translation id=\"2225048990372533999\">重装</translation>\n\t<translation id=\"987425828725037788\">IP地址</translation>\n\t<translation id=\"1646067470190508925\">港口</translation>\n\n\t<translation id=\"8097415329769247281\">选择最适合你的包</translation>\n\n\t<translation id=\"6570363013146073520\">仪表板</translation>\n\t<translation id=\"8864658120410603626\">广告活动</translation>\n\t<translation id=\"2446117790692479672\">资源</translation>\n\t<translation id=\"794120057687191331\">场景</translation>\n\t<translation id=\"4846792506513649213\">站</translation>\n\t<translation id=\"5686918033652531723\">Fasterq</translation>\n\t<translation id=\"7911416166208830577\">帮帮我</translation>\n\t<translation id=\"6082171864197428613\">安装</translation>\n\t<translation id=\"3476206505271758484\">Studiopro</translation>\n\t<translation id=\"3797778920049399855\">登出</translation>\n\t<translation id=\"7746065369460476808\">用户名或电子邮件</translation>\n\t<translation id=\"4809196861118879526\">密码</translation>\n\t<translation id=\"9162857816822524614\">输入两个关键因素</translation>\n\t<translation id=\"24227595514967590\">与谷歌认证</translation>\n\t<translation id=\"2001940299854753031\">记住我</translation>\n\t<translation id=\"5872337092278414963\">忘记密码</translation>\n\t<translation id=\"8246600873004586882\">更改密码</translation>\n\t<translation id=\"5289326240092186479\">变更企业名称</translation>\n\t<translation id=\"8732769503581158362\">...</translation>\n\t<translation id=\"867339644855996577\">旧密码</translation>\n\t<translation id=\"48285893667252664\">新密码</translation>\n\t<translation id=\"6917932917401642982\">重复新密码</translation>\n\t<translation id=\"5666893431176348635\">新的公司名称</translation>\n\t<translation id=\"4039555836273676912\">...</translation>\n\n\t<translation id=\"4010072142461558046\">升级</translation>\n\t<translation id=\"8894542476475088437\">帐户-S</translation>\n\t<translation id=\"2347724151568473592\">语言</translation>\n\t<translation id=\"4376434433661751094\">在线聊天</translation>\n\t<translation id=\"5344752701442428839\">网站</translation>\n\t<translation id=\"7108535247064136881\">选择你的语言</translation>\n\t<translation id=\"4137049537431219133\">使用Google验证器登录您的帐户</translation>\n\t<translation id=\"4785021168351486737\">保存并注销</translation>\n\t<translation id=\"6524180701596149125\">只需注销</translation>\n\n\t<translation id=\"2503331336991669578\">登录到您的帐户</translation>\n\t<translation id=\"8359621426539146583\">没有帐号</translation>\n\t<translation id=\"569785428576811345\">持续时间：</translation>\n\t<translation id=\"9043806075514219833\">开始时间：</translation>\n\n</translationbundle>\n"
  },
  {
    "path": "src/main.ts",
    "content": "import \"./polyfills.ts\";\nimport {platformBrowserDynamic} from \"@angular/platform-browser-dynamic\";\nimport {enableProdMode} from \"@angular/core\";\nimport {environment} from \"./environments/environment\";\nimport {AppModule} from \"./app/app-module\";\nimport {hmrBootstrap} from \"./hmr\";\n// import { AppModule } from './app/';\n\nif (environment.production)\n    enableProdMode();\n\n\nconst bootstrap = () => {\n    return platformBrowserDynamic().bootstrapModule(AppModule);\n};\n\nif (environment.hmr) {\n    if (module['hot']) {\n        hmrBootstrap(module, bootstrap);\n    } else {\n        console.error('HMR is not enabled for webpack-dev-server!');\n        console.log('Are you using the --hmr flag for ng serve?');\n    }\n} else {\n    bootstrap();\n}\n\n\n"
  },
  {
    "path": "src/manifest.json",
    "content": "{\n  \"name\": \"Dashboard\",\n  \"short_name\": \"Dashboard\",\n  \"theme_color\": \"#333333\",\n  \"background_color\": \"#333333\",\n  \"display\": \"standalone\",\n  \"orientation\": \"portrait\",\n  \"Scope\": \"/\",\n  \"start_url\": \"/\",\n  \"icons\": [\n    {\n      \"src\": \"assets/images/icons/icon-72x72.png\",\n      \"sizes\": \"72x72\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-96x96.png\",\n      \"sizes\": \"96x96\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-128x128.png\",\n      \"sizes\": \"128x128\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-144x144.png\",\n      \"sizes\": \"144x144\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-152x152.png\",\n      \"sizes\": \"152x152\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-384x384.png\",\n      \"sizes\": \"384x384\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"assets/images/icons/icon-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\"\n    }\n  ],\n  \"splash_pages\": null\n}"
  },
  {
    "path": "src/models/LocationMarkModel.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nexport class LocationMarkModel extends StoreModel {\n\n    constructor(data) {\n        super(data);\n    }\n\n    public get lng() {\n        return this.getKey('lng');\n    }\n\n    public get lat() {\n        return this.getKey('lat');\n    }\n\n    public get radius() {\n        return this.getKey('radius');\n    }\n\n    public get draggable() {\n        return this.getKey('draggable');\n    }\n\n    public setLng(value) {\n        return this.setKey<LocationMarkModel>(LocationMarkModel, 'lng', value);\n    }\n\n    public setLat(value) {\n        return this.setKey<LocationMarkModel>(LocationMarkModel, 'lat', value);\n    }\n\n    public seRadius(value) {\n        return this.setKey<LocationMarkModel>(LocationMarkModel, 'radius', value);\n    }\n\n    public getRadius() {\n        return this.getKey('radius');\n    }\n\n}"
  },
  {
    "path": "src/models/StationModel.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nimport {IStation} from \"../store/store.data\";\nexport class StationModel extends StoreModel implements IStation{\n\n    constructor(data) {\n        super(data);\n    }\n\n    public get id() {\n        return this.getKey('id');\n    }\n\n    public get localAddress() {\n        return this.getKey('localAddress');\n    }\n\n    public get publicIp() {\n        return this.getKey('publicIp');\n    }\n\n    public get peakMemory() {\n        return this.getKey('peakMemory');\n    }\n\n    public get appVersion() {\n        return this.getKey('appVersion');\n    }\n\n    public get caching() {\n        return this.getKey('caching');\n    }\n\n    public get totalMemory() {\n        return this.getKey('totalMemory');\n    }\n\n    public get runningTime() {\n        return this.getKey('runningTime');\n    }\n\n    public get startTime() {\n        return this.getKey('startTime');\n    }\n\n    public get status() {\n        return this.getKey('status');\n    }\n\n    public get watchDogConnection() {\n        return this.getKey('watchDogConnection');\n    }\n\n    public get name() {\n        return this.getKey('name');\n    }\n\n    public getStationName() {\n        return this.getKey('name');\n    }\n\n    public get connectionStatusChanged() {\n        return this.getKey('connectionStatusChanged');\n    }\n\n    public get localPort():number {\n        return this.getKey('localPort');\n    }\n\n    public get socket() {\n        return this.getKey('socket');\n    }\n\n    public get connection() {\n        return this.getKey('connection');\n    }\n\n    public get os() {\n        return this.getKey('os');\n    }\n\n    public get airVersion() {\n        return this.getKey('airVersion');\n    }\n\n    public get stationColor() {\n        return this.getKey('stationColor');\n    }\n\n    public get lastUpdate() {\n        return this.getKey('lastUpdate');\n    }\n\n\n}"
  },
  {
    "path": "src/models/StoreModel.ts",
    "content": "import {Map, List} from 'immutable';\nimport { UUID } from 'angular2-uuid';\n\n\n/**\n * StoreModel is a thin wrapper of Immutable data around for a Class\n * uses the internal immutable map to hold all values.\n * This allows us a base class on which we can extend and inject\n * into any Redux store as we follow Immutability\n *\n * Also ships with a helper static method to create unique IDs\n **/\nexport class StoreModel {\n\n    static UniqueId(){\n        return UUID.UUID();\n    }\n\n    constructor(data:any = {}) {\n        this._data = Map<string, any>(data);\n    }\n\n    _data:Map<string, any>;\n\n    public setKey<T>(ClassName:any, key:string, value:any):T {\n        return this.setData(ClassName, this._data.set(key, value)) as T;\n    }\n\n    public getKey(key:string) {\n        return this._data.get(key);\n    }\n\n    public setData<T>(ClassName, data:any):T {\n        function ClassFactory(className:{new(data): T;}, data:any):T {\n            var created:T = new className(Map<string, any>(data));\n            return created;\n        }\n\n        return ClassFactory(ClassName, data);\n    }\n\n    public getData():Map<string, any> {\n        return this._data;\n    }\n                  \n    /**\n     * Create a List or update a list if one exists, with the Map key provided and the value to push to the new/updated list\n     * @param ClassName\n     * @param i_key\n     * @param i_value\n     * @returns {T}\n     */\n    public listPush<T>(ClassName, i_key:string, i_value:string):any {\n        var value = this.getKey(i_key);\n        var model:StoreModel = this;\n        if (!value)\n            model = this.setKey<T>(ClassName, i_key, List<any>()) as any;\n        var list:List<any> = model.getKey(i_key);\n        list = list.push(i_value);\n        return model.setKey<T>(ClassName, i_key, list) as T;\n    }\n}"
  },
  {
    "path": "src/models/StoreModelAbstract.ts",
    "content": "import {Map, List} from 'immutable';\nimport { UUID } from 'angular2-uuid';\n\n/**\n * StoreModel is a thin wrapper of Immutable data around for a Class\n * uses the internal immutable map to hold all values.\n * This allows us a base class on which we can extend and inject\n * into any Redux store as we follow Immutability\n *\n * Also ships with a helper static method to create unique IDs\n **/\nexport abstract class StoreModel<T> {\n\n\n    protected abstract readonly _baseType: typeof StoreModel;\n\n    private _data: Map<string, any>;\n\n    static UniqueId(){\n        return UUID.UUID();\n    }\n\n    constructor(data: any = {}) {\n        this._data = Map<string, any>(data);\n    }\n\n\n\n    public setKey(key: string, value: any): T {\n        return this.setData(this._data.set(key, value)) as T;\n    }\n\n    public getKey(key: string) {\n        return this._data.get(key);\n    }\n\n    public setData<T>(data: any): T {\n        const baseType: any = this._baseType;\n        return new baseType(data) as T;\n    }\n\n    public getData(): Map<string, any> {\n        return this._data;\n    }\n\n    /**\n     * Create a List or update a list if one exists, with the Map key provided and the value to push to the new/updated list\n     * @param ClassName\n     * @param i_key\n     * @param i_value\n     * @returns {T}\n     */\n    public listPush<K>(i_key: string, i_value: K): T {\n        const value = this.getKey(i_key);\n        let model: StoreModel<T> = this;\n        if (!value) {\n            model = this.setKey(i_key, List<any>()) as any;\n        }\n        let list: List<any> = model.getKey(i_key);\n        list = list.push(i_value);\n        return model.setKey(i_key, list);\n    }\n}"
  },
  {
    "path": "src/models/UserModel.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nexport class UserModel extends StoreModel {\n\n    constructor(data: {user: string, pass: string, authenticated: boolean, businessId: number, rememberMe: boolean, twoFactorRequired:boolean, accountType: number, authTime?: Date}) {\n        super(data);\n    }\n\n    // setKey2 = <T extends new (...args: any[]) => UserModel, K extends keyof UserModel>\n    //     (c: T, key: K, value: UserModel[K]) => {\n    //     c.prototype[key] = value;\n    // };\n    // getKey2 = (key: string) => {\n    //     return key as any;\n    // };\n    //\n    // set authenticated2(value: boolean) {\n    //     this.setKey2(UserModel, 'authenticated2', value);\n    // }\n    //\n    // get authenticated2(): boolean {\n    //     return this.getKey2('authenticated');\n    // }\n\n    public setTime() {\n        return this.setKey<UserModel>(UserModel, 'authTime', new Date());\n    }\n\n    public getTime() {\n        return this.getKey('authTime');\n    }\n\n    setAuthenticated(value:boolean) {\n        return this.setKey<UserModel>(UserModel, 'authenticated', value);\n    }\n\n    setComponents(value) {\n        return this.setKey<UserModel>(UserModel, 'components', value);\n    }\n\n    getAuthenticated(): boolean {\n        return this.getKey('authenticated');\n    }\n\n    setUser(value:string) {\n        return this.setKey<UserModel>(UserModel, 'user', value);\n    }\n\n    getUser() {\n        return this.user();\n    }\n\n    get resellerId(){\n        return this.getKey('resellerId');\n    }\n\n    user() {\n        return this.getKey('user');\n    }\n\n    setPass(value:string) {\n        return this.setKey<UserModel>(UserModel, 'pass', value);\n    }\n\n    getPass() {\n        return this.pass();\n    }\n\n    pass() {\n        return this.getKey('pass');\n    }\n\n    getDomain() {\n        return this.getKey('domain');\n    }\n\n    getPartialDomain() {\n        return this.getKey('domain').split('.')[0];\n    }\n\n    setDomain(value:string) {\n        return this.setKey<UserModel>(UserModel, 'domain', value);\n    }\n\n    setAccountType(value:number) {\n        return this.setKey<UserModel>(UserModel, 'accountType', value);\n    }\n\n    setResellerInfo(value:XMLDocument) {\n        return this.setKey<UserModel>(UserModel, 'resellerInfo', value);\n    }\n\n    setResellerId(value:number) {\n        return this.setKey<UserModel>(UserModel, 'resellerId', value);\n    }\n\n    setResellerName(value:string) {\n        return this.setKey<UserModel>(UserModel, 'resellerName', value);\n    }\n\n    setEri(value:string) {\n        return this.setKey<UserModel>(UserModel, 'eri', value);\n    }\n\n    setResellerWhiteLabel(value:{[key: string]: string}) {\n        return this.setKey<UserModel>(UserModel, 'resellerWhiteLabelJson', value);\n    }\n\n    get resellerWhiteLabel() {\n        return this.getKey('resellerWhiteLabelJson');\n    }\n\n    getAccountType() {\n        return this.getKey('accountType');\n    }\n\n    setTwoFactorRequired(value:boolean) {\n        return this.setKey<UserModel>(UserModel, 'twoFactorRequired', value);\n    }\n\n    getTwoFactorRequired(): boolean {\n        return this.getKey('twoFactorRequired');\n    }\n\n    setBusinessId(value:number) {\n        return this.setKey<UserModel>(UserModel, 'businessId', value);\n    }\n\n    getBusinessId(): number {\n        return this.getKey('businessId');\n    }\n\n    businessId() {\n        return this.getKey('businessId');\n    }\n\n    setRememberMe(value:boolean) {\n        return this.setKey<UserModel>(UserModel, 'rememberMe', value);\n    }\n\n    getRememberMe() {\n        return this.rememberMe()\n    }\n\n    rememberMe() {\n        return this.getKey('rememberMe');\n    }\n\n\n    // public setField(i_field, i_value) {\n    //     var value = this.getKey('Value');\n    //     value[i_field] = i_value;\n    //     return this.setKey<AdnetRateModel>(AdnetRateModel, 'Value', value);\n    // }\n\n}"
  },
  {
    "path": "src/models/fasterq-analytics.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nexport class FasterqAnalyticsModel extends StoreModel {\n\n    constructor(data) {\n        super(data);\n    }\n\n    public get lineId() {\n        return this.getKey('line_id');\n    }\n\n    public get serviceId() {\n        return this.getKey('service_id');\n    }\n\n    public get queueId() {\n        return this.getKey('queue_id');\n    }\n\n    public get name() {\n        return this.getKey('name');\n    }\n\n    public get analyticId() {\n        return this.getKey('analytic_id');\n    }\n\n    public get serviced() {\n        return this.getKey('serviced');\n    }\n\n    public get entered() {\n        return this.getKey('entered');\n    }\n\n    public get verification() {\n        return this.getKey('verification');\n    }\n\n    public get called() {\n        return this.getKey('called');\n    }\n\n    public get businessId() {\n        return this.getKey('business_id');\n    }\n}\n1491283369"
  },
  {
    "path": "src/models/fasterq-line-model.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nexport class FasterqLineModel extends StoreModel {\n\n    constructor(data) {\n        super(data);\n    }\n\n    public get lineId() {\n        return this.getKey('line_id');\n    }\n\n    public get businessId() {\n        return this.getKey('business_id');\n    }\n\n    public get lineName() {\n        return this.getKey('name') ? this.getKey('name') : this.getKey('line_name');\n    }\n\n    public get serviceId() {\n        return this.getKey('service_id');\n    }\n\n    public get reminder() {\n        return this.getKey('reminder');\n    }\n\n    public get callType():'EMAIL' | 'SMS' | 'QR' {\n        return this.getKey('call_type');\n    }\n\n    public get verification() {\n        return this.getKey('verification');\n    }\n\n    public get sms() {\n        return this.getKey('sms');\n    }\n\n    public get email() {\n        return this.getKey('email');\n    }\n\n    public get date() {\n        return this.getKey('date');\n    }\n}\n"
  },
  {
    "path": "src/models/fasterq-queue-model.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nimport {Lib} from \"../Lib\";\nexport class FasterqQueueModel extends StoreModel {\n\n    constructor(data) {\n        super(data);\n    }\n\n    public get queued() {\n        return this.getKey('queue_id');\n    }\n\n    public get serviceId() {\n        var serviceId = this.getKey('service_id');\n        return Lib.PadZeros(serviceId, 3, 0);\n    }\n\n    public get lineId() {\n        return this.getKey('line_id');\n    }\n\n    public get verification() {\n        return this.getKey('verification');\n    }\n\n    public get queueId() {\n        return this.getKey('queue_id');\n    }\n\n    public get steppedOut() {\n        return this.getKey('steppedout');\n    }\n\n    public get name() {\n        return this.getKey('name');\n    }\n\n    public get analyticId() {\n        return this.getKey('analytic_id');\n    }\n\n    public get serviced() {\n        return this.getKey('serviced');\n    }\n\n    public get entered() {\n        return this.getKey('entered');\n    }\n\n    public get businessId() {\n        return this.getKey('business_id');\n    }\n\n    public get calledBy() {\n        return this.getKey('called_by');\n    }\n\n    public get called() {\n        return this.getKey('called');\n    }\n}"
  },
  {
    "path": "src/models/live-log-model.ts",
    "content": "import {StoreModel} from \"../models/StoreModel\";\nexport class LiveLogModel extends StoreModel {\n\n    constructor(data) {\n        super(data);\n    }\n\n}\n"
  },
  {
    "path": "src/modules/ngmslib-service.ts",
    "content": ""
  },
  {
    "path": "src/modules/shared.module.ts",
    "content": "import {ModuleWithProviders, NgModule} from \"@angular/core\";\nimport {CommonModule} from \"@angular/common\";\nimport {FormsModule, ReactiveFormsModule} from \"@angular/forms\";\nimport {HttpModule, JsonpModule} from \"@angular/http\";\nimport {Infobox} from \"../comps/infobox/Infobox\";\nimport {Sliderpanel} from \"../comps/sliderpanel/Sliderpanel\";\nimport {Slideritem} from \"../comps/sliderpanel/Slideritem\";\nimport {PanelSplitMain} from \"../comps/panel-split/panel-split-main\";\nimport {PanelSplitSide} from \"../comps/panel-split/panel-split-side\";\nimport {PanelSplitContainer} from \"../comps/panel-split/panel-split-container\";\nimport {ListToArrayPipe} from \"../pipes/list-to-array-pipe\";\nimport {MatchBodyHeight} from \"../comps/match-body-height/match-body-height\";\nimport {ScreenTemplate} from \"../comps/screen-template/screen-template\";\nimport {BlurForwarder} from \"../comps/blurforwarder/BlurForwarder\";\nimport {ContextMenuModule} from \"ngx-contextmenu\";\nimport {ChartModule} from \"angular2-highcharts\";\nimport {BlockPropContainer} from \"../app/blocks/block-prop-container\";\nimport {FormatSecondsPipe} from \"../pipes/format-seconds-pipe\";\nimport {DraggableList} from \"../comps/draggable-list/draggable-list\";\nimport {ColorPickerModule} from \"ngx-color-picker\";\nimport {Tabs} from \"../comps/tabs/tabs\";\nimport {Tab} from \"../comps/tabs/tab\";\nimport {BlockPropCommon} from \"../app/blocks/block-prop-common\";\nimport {BlockPropHtml} from \"../app/blocks/block-prop-html\";\nimport {BlockPropClock} from \"../app/blocks/block-prop-clock\";\nimport {FontSelector} from \"../comps/font-selector/font-selector\";\nimport {BlockPropWeather} from \"../app/blocks/block-prop-weather\";\nimport {BlockPropJsonPlayer} from \"../app/blocks/block-prop-json-player\";\nimport {SimpleGridModule} from \"../comps/simple-grid-module/SimpleGridModule\";\nimport {DropdownModule, RadioButtonModule} from \"primeng/primeng\";\nimport {BlockPropInstagram} from \"../app/blocks/block-prop-instagram\";\nimport {BlockPropCalendar} from \"../app/blocks/block-prop-calendar\";\nimport {BlockPropSheets} from \"../app/blocks/block-prop-sheets\";\nimport {BlockPropTwitter} from \"../app/blocks/block-prop-twitter\";\nimport {BlockPropVideo} from \"../app/blocks/block-prop-video\";\nimport {BlockPropLabel} from \"../app/blocks/block-prop-label\";\nimport {BlockPropImage} from \"../app/blocks/block-prop-image\";\nimport {BlockPropMrss} from \"../app/blocks/block-prop-mrss\";\nimport {BlockPropRss} from \"../app/blocks/block-prop-rss\";\nimport {BlockPropCollection} from \"../app/blocks/block-prop-collection\";\nimport {JsonEventGrid} from \"../app/blocks/json-event-grid\";\nimport {BlockPropQR} from \"../app/blocks/block-prop-qr\";\nimport {BlockPropYouTube} from \"../app/blocks/block-prop-youtube\";\nimport {BlockPropDigg} from \"../app/blocks/block-prop.digg\";\nimport {BlockPropFasterQ} from \"../app/blocks/block-prop-fasterq\";\nimport {BlockPropLocation} from \"../app/blocks/block-prop-location\";\nimport {AddContent} from \"../app/campaigns/add-content\";\nimport {BlockPropScene} from \"../app/blocks/block-prop-scene\";\nimport {Loading} from \"../comps/loading/loading\";\nimport {BlockPropJsonItem} from \"../app/blocks/block-prop-json-item\";\nimport {LivePreview} from \"../app/live-preview/live-preview\";\nimport {Ng2Bs3ModalModule} from \"ng2-bs3-modal/ng2-bs3-modal\";\nimport {AgmCoreModule} from \"angular2-google-maps/core\";\nimport {LocationMap} from \"../app/location/location-map\";\nimport {SlideritemContent} from \"../comps/sliderpanel/SliderItemContent\";\nimport {MediaPlayer} from \"../comps/media-player/media-player\";\nimport {VgCoreModule} from \"videogular2/core\";\nimport {VgControlsModule} from \"videogular2/controls\";\nimport {VgOverlayPlayModule} from \"videogular2/overlay-play\";\nimport {VgBufferingModule} from \"videogular2/buffering\";\nimport {FilterModelPipe} from \"../filters/filter-model-pipe\";\nimport {SvgIcon} from \"../comps/svg-icon/svg-icon\";\nimport {LazyImage} from \"../comps/lazy-image/lazy-image\";\nimport {ProUpgrade} from \"../app/studiopro/pro-upgrade\";\nimport {DashPanelMini} from \"../app/dashboard/dash-panel-mini\";\nimport {ResellerLogo} from \"../comps/logo/reseller-logo\";\nimport {Logo} from \"../comps/logo/Logo\";\nimport {LimitedAccess} from \"../comps/limited-access/limited-access\";\nimport {LocaleSelector} from \"../app/locale-selector/local-selector\";\nimport {ConnectFormDirective} from \"../comps/connect-form/connect-form\";\nimport {DisableControlDirective} from \"../comps/disable-control/disable-control\";\n\nvar sharedComponents = [Tabs, Tab, Infobox, Sliderpanel, Slideritem, SlideritemContent, PanelSplitMain, PanelSplitSide, PanelSplitContainer, ListToArrayPipe, FormatSecondsPipe, MatchBodyHeight, ScreenTemplate, BlurForwarder, DraggableList, AddContent, Loading, LimitedAccess,\n    FontSelector, BlockPropContainer, BlockPropCommon, BlockPropHtml, BlockPropClock, BlockPropWeather, BlockPropInstagram, BlockPropJsonPlayer, BlockPropJsonItem, ConnectFormDirective, LivePreview, LocationMap, MediaPlayer, FilterModelPipe, SvgIcon, LazyImage, ProUpgrade, ResellerLogo, Logo, LocaleSelector,\n    BlockPropScene, BlockPropCalendar, BlockPropSheets, BlockPropTwitter, BlockPropVideo, BlockPropImage, BlockPropLabel, BlockPropMrss, BlockPropLocation, BlockPropRss, BlockPropDigg, BlockPropFasterQ, BlockPropCollection, BlockPropQR, BlockPropYouTube, JsonEventGrid, DashPanelMini, DisableControlDirective];\n\n@NgModule({\n    imports: [CommonModule, FormsModule, HttpModule, JsonpModule, ReactiveFormsModule, ContextMenuModule, ChartModule, ReactiveFormsModule, ColorPickerModule, DropdownModule, RadioButtonModule, SimpleGridModule, Ng2Bs3ModalModule, AgmCoreModule, VgCoreModule, VgControlsModule, VgOverlayPlayModule, VgBufferingModule],\n    exports: [CommonModule, FormsModule, HttpModule, JsonpModule, ReactiveFormsModule, ContextMenuModule, ChartModule, ColorPickerModule, DropdownModule, RadioButtonModule, SimpleGridModule, Ng2Bs3ModalModule, AgmCoreModule, VgCoreModule, VgControlsModule, VgOverlayPlayModule, VgBufferingModule, ...sharedComponents],\n    entryComponents: [ScreenTemplate],\n    declarations: [...sharedComponents]\n})\n\nexport class SharedModule {\n    static forRoot(): ModuleWithProviders {\n        return {\n            ngModule: SharedModule,\n            providers: []\n        };\n    }\n}"
  },
  {
    "path": "src/pipes/format-seconds-pipe.ts",
    "content": "import {Pipe, PipeTransform} from '@angular/core';\n@Pipe({\n    name: 'FormatSecondsPipe'\n})\nexport class FormatSecondsPipe implements PipeTransform {\n    transform(duration, ...args: any[]): any {\n        var xdate = new XDate()\n        return xdate.clearTime().addSeconds(duration).toString('HH:mm:ss');\n    }\n}"
  },
  {
    "path": "src/pipes/list-to-array-pipe.ts",
    "content": "import {Pipe, PipeTransform} from '@angular/core';\nimport {Map, List} from 'immutable';\nimport {StoreModel} from \"../store/model/StoreModel\";\n@Pipe({\n    name: 'ListToArrayPipe'\n})\nexport class ListToArrayPipe implements PipeTransform {\n    transform(items: List<StoreModel>, ...args: any[]): any {\n        var arr = items.toArray();\n        return arr;\n    }\n}"
  },
  {
    "path": "src/polyfills.ts",
    "content": "// This file includes polyfills needed by Angular 2 and is loaded before\n// the app. You can add your own extra polyfills to this file.\nimport 'core-js/es6/symbol';\nimport 'core-js/es6/object';\nimport 'core-js/es6/function';\nimport 'core-js/es6/parse-int';\nimport 'core-js/es6/parse-float';\nimport 'core-js/es6/number';\nimport 'core-js/es6/math';\nimport 'core-js/es6/string';\nimport 'core-js/es6/date';\nimport 'core-js/es6/array';\nimport 'core-js/es6/regexp';\nimport 'core-js/es6/map';\nimport 'core-js/es6/set';\nimport 'core-js/es6/reflect';\n\nimport 'core-js/es7/reflect';\nimport 'zone.js/dist/zone';\n"
  },
  {
    "path": "src/print.html",
    "content": "<script src=\"https://code.jquery.com/jquery-1.12.4.min.js\" crossorigin=\"anonymous\"></script>\n<script>\n  var Base64 = {\n\t _keyStr: \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\", encode: function (e) {\n\t\tvar t = \"\";\n\t\tvar n, r, i, s, o, u, a;\n\t\tvar f = 0;\n\t\te = Base64._utf8_encode(e);\n\t\twhile (f < e.length) {\n\t\t  n = e.charCodeAt(f++);\n\t\t  r = e.charCodeAt(f++);\n\t\t  i = e.charCodeAt(f++);\n\t\t  s = n >> 2;\n\t\t  o = (n & 3) << 4 | r >> 4;\n\t\t  u = (r & 15) << 2 | i >> 6;\n\t\t  a = i & 63;\n\t\t  if (isNaN(r)) {\n\t\t\t u = a = 64\n\t\t  } else if (isNaN(i)) {\n\t\t\t a = 64\n\t\t  }\n\t\t  t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)\n\t\t}\n\t\treturn t\n\t }, decode: function (e) {\n\t\tvar t = \"\";\n\t\tvar n, r, i;\n\t\tvar s, o, u, a;\n\t\tvar f = 0;\n\t\te = e.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\t\twhile (f < e.length) {\n\t\t  s = this._keyStr.indexOf(e.charAt(f++));\n\t\t  o = this._keyStr.indexOf(e.charAt(f++));\n\t\t  u = this._keyStr.indexOf(e.charAt(f++));\n\t\t  a = this._keyStr.indexOf(e.charAt(f++));\n\t\t  n = s << 2 | o >> 4;\n\t\t  r = (o & 15) << 4 | u >> 2;\n\t\t  i = (u & 3) << 6 | a;\n\t\t  t = t + String.fromCharCode(n);\n\t\t  if (u != 64) {\n\t\t\t t = t + String.fromCharCode(r)\n\t\t  }\n\t\t  if (a != 64) {\n\t\t\t t = t + String.fromCharCode(i)\n\t\t  }\n\t\t}\n\t\tt = Base64._utf8_decode(t);\n\t\treturn t\n\t }, _utf8_encode: function (e) {\n\t\te = e.replace(/\\r\\n/g, \"\\n\");\n\t\tvar t = \"\";\n\t\tfor (var n = 0; n < e.length; n++) {\n\t\t  var r = e.charCodeAt(n);\n\t\t  if (r < 128) {\n\t\t\t t += String.fromCharCode(r)\n\t\t  } else if (r > 127 && r < 2048) {\n\t\t\t t += String.fromCharCode(r >> 6 | 192);\n\t\t\t t += String.fromCharCode(r & 63 | 128)\n\t\t  } else {\n\t\t\t t += String.fromCharCode(r >> 12 | 224);\n\t\t\t t += String.fromCharCode(r >> 6 & 63 | 128);\n\t\t\t t += String.fromCharCode(r & 63 | 128)\n\t\t  }\n\t\t}\n\t\treturn t\n\t }, _utf8_decode: function (e) {\n\t\tvar t = \"\";\n\t\tvar n = 0;\n\t\tvar r = c1 = c2 = 0;\n\t\twhile (n < e.length) {\n\t\t  r = e.charCodeAt(n);\n\t\t  if (r < 128) {\n\t\t\t t += String.fromCharCode(r);\n\t\t\t n++\n\t\t  } else if (r > 191 && r < 224) {\n\t\t\t c2 = e.charCodeAt(n + 1);\n\t\t\t t += String.fromCharCode((r & 31) << 6 | c2 & 63);\n\t\t\t n += 2\n\t\t  } else {\n\t\t\t c2 = e.charCodeAt(n + 1);\n\t\t\t c3 = e.charCodeAt(n + 2);\n\t\t\t t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);\n\t\t\t n += 3\n\t\t  }\n\t\t}\n\t\treturn t\n\t }\n  }\n  var urlParam = function (name) {\n\t var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);\n\t if (results == null) {\n\t\treturn null;\n\t }\n\t else {\n\t\treturn results[1] || 0;\n\t }\n  }\n</script>\n\n<style media=\"print\">\n  @page {\n\t size: auto;\n\t margin: 0;\n  }\n</style>\n\n<style>\n\t * {\n\t\tfont-family: arial;\n\t }\n\t.serviceId {\n\t  color: black;\n\t  font-family: arial;\n\t  font-weight: bold;\n\t  position: relative;\n\t  display: block;\n\t}\n</style>\n\n\n<body id=\"myBody\">\n\t<h1>I loaded</h1>\n\t<script>\n       $(document).ready(function() {\n           var arg = Base64.decode(urlParam('serviceId'));\n           var serviceId = arg.split(':_:')[0]\n           var name = arg.split(':_:')[1]\n           var msg1 = '';\n\n           // test version\n           if (name.indexOf('ver12') > -1) {\n           } else {\n\t\t\t\t\t// msg1 = '<h1>line: ' + name + '</h1><br/><p>your number is ' + serviceId + ' </p><br/>' + '<h5>created at ' + time + '</h5>';\n               var time = new Date($.now());\n               msg1 = \t'<h3>' + 'line: ' + name + ' # ' + serviceId + '' + '</h3>' +\n                   '<h3>' + 'line: ' + name + ' # ' + serviceId + '' + '</h3>' +\n                   '<h3>' + 'line: ' + name + ' # ' + serviceId + '' + '</h3>' +\n                   '<h3>' + 'line: ' + name + ' # ' + serviceId + '' + '</h3>' +\n                   '<h3>' + 'line: ' + name + ' # ' + serviceId + '' + '</h3>' +\n                   '<h5>' + time  + '</h5>';\n               \n           }\n           $('body').append(msg1);\n       });\n\t</script>\n</body>\n"
  },
  {
    "path": "src/service-worker.js",
    "content": ""
  },
  {
    "path": "src/services/AuthService.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {ActivatedRoute, ActivatedRouteSnapshot, NavigationStart, Router, RouterStateSnapshot} from \"@angular/router\";\nimport {LocalStorage} from \"./LocalStorage\";\nimport {StoreService} from \"./StoreService\";\nimport \"rxjs/add/observable/fromPromise\";\nimport {Observable} from \"rxjs/Observable\";\nimport {Map} from \"immutable\";\nimport * as _ from \"lodash\";\nimport {Store} from \"@ngrx/store\";\nimport {ApplicationState} from \"../store/application.state\";\nimport {AuthenticateFlags} from \"../store/actions/appdb.actions\";\nimport {UserModel} from \"../models/UserModel\";\nimport {EFFECT_AUTH_START, EFFECT_TWO_FACTOR_AUTH} from \"../store/effects/appdb.effects\";\nimport {NgmslibService} from \"ng-mslib\";\nimport {Lib} from \"../Lib\";\n\n@Injectable()\nexport class AuthService {\n    constructor(private ngmslibService: NgmslibService,\n                private router: Router,\n                private store: Store<ApplicationState>,\n                private localStorage: LocalStorage,\n                private storeService: StoreService,\n                private activatedRoute: ActivatedRoute) {\n\n        this.store.select(store => store.appDb.userModel).subscribe((userModel: UserModel) => {\n            this.userModel = userModel;\n        }, (e) => {\n            console.error(e)\n        })\n        this.ieAutoLoginPatch();\n        this.listenEvents();\n\n\n    }\n\n    private userModel: UserModel;\n    private requestedRoute: string;\n\n    private listenEvents() {\n        this.store.select(store => store.appDb.appAuthStatus)\n            .subscribe((i_authStatus: Map<string, AuthenticateFlags>) => {\n                let authStatus: AuthenticateFlags = i_authStatus.get('authStatus')\n                switch (authStatus) {\n                    case AuthenticateFlags.WRONG_PASS: {\n                        this.saveCredentials('', '', '');\n                        this.router.navigate(['/UserLogin']);\n                        break;\n                    }\n                    case AuthenticateFlags.TWO_FACTOR_ENABLED: {\n                        var user = this.ngmslibService.base64().encode(this.userModel.getUser());\n                        var pass = this.ngmslibService.base64().encode(this.userModel.getPass());\n                        this.router.navigate([`/UserLogin/twoFactor/${user}/${pass}`])\n                        break;\n                    }\n                    case AuthenticateFlags.TWO_FACTOR_PASS: {\n                        this.saveCredentials('', '', '');\n                        this.enterApplication();\n                        break;\n                    }\n                    case AuthenticateFlags.AUTH_PASS_NO_TWO_FACTOR: {\n                        if (this.userModel.getRememberMe()) {\n                            if (this.userModel.getUser()=='demo_lite@ms.com'){\n                                this.saveCredentials('', '', '');\n                            } else {\n                                this.saveCredentials(this.userModel.getUser(), this.userModel.getPass(), this.userModel.rememberMe());\n                            }\n                        } else {\n                            this.saveCredentials('', '', '');\n                        }\n                        console.log('Auth pass no two factor');\n                        this.enterApplication();\n                        break;\n                    }\n                }\n            }, (e) => {\n                console.error(e)\n            })\n        this.router.events.filter(event => event instanceof NavigationStart).take(1).subscribe(event => {\n            this.requestedRoute = event['url'];\n            // this.requestedRoute = event.url == '/' ? '/App1/Campaigns' : event.url;\n        }, (e) => console.error(e));\n    }\n\n    private ieAutoLoginPatch() {\n        // workaround for auto login on IE 11<\n        if (platform.name == 'IE' && Math.round(Number(platform.version)) <= 11) {\n            var url = window.location.href;\n            var credentials: any = url.split('param=')[1];\n            if (credentials) {\n                credentials = this.decodeBase64(credentials)\n                var credentialsArr = credentials.match(/user=(.*),pass=(.*)/);\n                var user = credentialsArr[1];\n                var pass = credentialsArr[2];\n                if (user && pass) {\n                    console.log('applying IE auto login patch');\n                    this.saveCredentials(user, pass, true);\n                }\n            }\n        }\n    }\n\n    private enterApplication() {\n        setTimeout(() => {\n            if (Lib.DevMode()) {\n                var nav = '/App1/Campaigns';\n                // Lib.Con(`in dev mode entering:  ${nav}`);\n                // this.router.navigate([this.requestedRoute]);\n                this.router.navigate([nav]);\n            } else {\n                console.log('requested route ' + this.requestedRoute);\n                console.log('entering /App1/Dashboard');\n                // this.router.navigate([this.requestedRoute]);\n                this.router.navigate(['/App1/Dashboard']);\n            }\n            this.storeService.loadServices();\n        }, 10)\n    }\n\n    public start() {\n        var i_user, i_pass, i_remember;\n\n        // check local store first\n        console.log('checking credentials in local storage');\n        var credentials = this.localStorage.getItem('remember_me_studioweb');\n        if (credentials && (credentials && credentials.u != '')) {\n\n            i_user = credentials.u;\n            i_pass = credentials.p;\n            i_remember = credentials.r;\n            console.log(`credentials found ${i_user}`);\n\n        } else {\n            // check url params\n            console.log('credentials not found, checking url params ' + this.activatedRoute.snapshot.queryParams);\n\n            // var id = this.activatedRoute.snapshot.queryParams['id'];\n            var id = this.activatedRoute.snapshot.queryParams['param'];\n            if (!_.isUndefined(id)) {\n                try {\n                    credentials = this.decodeBase64(id);\n                    var local = this.activatedRoute.snapshot.queryParams['local'];\n                    var credentialsArr = credentials.match(/user=(.*),pass=(.*)/);\n                    i_user = credentialsArr[1];\n                    i_pass = credentialsArr[2];\n                    i_remember = 'false';\n                    console.log('auth with url ' + i_user);\n                } catch (e) {\n                    console.error('credentials error problem decoding url base64 params on login ' + e);\n                }\n            }\n        }\n        if (i_user && i_pass) {\n            this.router.navigate(['/AutoLogin']);\n            console.log(`auth manually ${i_user}`);\n            this.authUser(i_user, i_pass, i_remember)\n        } else {\n            // no valid user/pass found so go to user login, end of process\n            console.log(`auth no valids`);\n            this.router.navigate(['/UserLogin']);\n        }\n    }\n\n    private decodeBase64(i_credentials) {\n        try {\n            return this.ngmslibService.base64().decode(i_credentials);\n        } catch (e) {\n            try {\n                i_credentials = i_credentials.replace(/=/ig, '');\n                return this.ngmslibService.base64().decode(i_credentials);\n            } catch (e) {\n                console.error('credentials error problem decoding url base64 params on login ' + e);\n            }\n        }\n    }\n\n    public saveCredentials(i_user, i_pass, i_remember) {\n        if (i_remember) {\n            this.localStorage.setItem('remember_me_studioweb', {\n                u: i_user,\n                p: i_pass,\n                r: i_remember\n            });\n        } else {\n            this.localStorage.setItem('remember_me_studioweb', {\n                u: '',\n                p: '',\n                r: i_remember\n            });\n        }\n    }\n\n    public authUser(user: string, pass: string, rememberMe: boolean = false): void {\n        this.store.dispatch({\n            type: EFFECT_AUTH_START,\n            payload: this.userModel.setUser(user.trim()).setPass(pass.trim()).setRememberMe(rememberMe)\n        })\n    }\n\n    public authServerTwoFactor(token): void {\n        this.store.dispatch({type: EFFECT_TWO_FACTOR_AUTH, payload: {token: token, enable: false}})\n    }\n\n\n    public getLocalstoreCred(): { u: string, p: string, r: string } {\n        var credentials = this.localStorage.getItem('remember_me_studioweb');\n        if (!credentials)\n            return {\n                u: '',\n                p: '',\n                r: ''\n            };\n        return {\n            u: credentials.u,\n            p: credentials.p,\n            r: credentials.r,\n        }\n    }\n\n    public checkAccess(activatedRouteSnapshot: ActivatedRouteSnapshot, routerStateSnapshot: RouterStateSnapshot): Promise<any> {\n        if (this.userModel.getAuthenticated()) {\n            // if (this.userModel.getAccountType() == AuthenticateFlags.USER_ACCOUNT_PRO)\n            //     console.log('limited');\n            return Promise.resolve(true);\n        } else {\n            return Promise.resolve(false);\n        }\n    }\n\n    public canActivate(activatedRouteSnapshot: ActivatedRouteSnapshot, routerStateSnapshot: RouterStateSnapshot): Observable<boolean> {\n        return Observable\n            .fromPromise(this.checkAccess(activatedRouteSnapshot,routerStateSnapshot))\n            .do(result => {\n                if (!result)\n                    this.router.navigate(['/AutoLogin']);\n            });\n    }\n}\n\nexport const AUTH_PROVIDERS: Array<any> = [{\n    provide: AuthService,\n    useClass: AuthService\n}];"
  },
  {
    "path": "src/services/CommBroker.ts",
    "content": "import {Component, Injectable} from '@angular/core';\nimport {Observer} from \"rxjs/Observer\";\nimport 'rxjs/add/operator/debounceTime';\nimport 'rxjs/add/operator/do';\nimport 'rxjs/add/operator/filter';\nimport 'rxjs/add/operator/share';\nimport {Subject} from \"rxjs/Subject\";\nimport * as _ from 'lodash'\nimport {Lib} from \"../Lib\";\n/**\n\n CommBroker is a React type Mediator injectable service provider\n\n Examples\n ============\n self.onEvent('click').subscribe((e:IMessage)=> {\n        console.log('I heard a click');\n    });\n\n // won't work, event != jump\n self.onEvent('jump').subscribe((e:IMessage)=> {\n        console.log('I heard a click');\n    });\n\n // wont work, this != self\n self.onInstance(null).subscribe((e:IMessage)=> {\n        console.log('XYZ#$%^& should never come here...');\n    });\n\n self.onInstanceAndEvent(this, 'click').subscribe((e:IMessage)=> {\n        console.log(`I heard you commBroker on event click ` + e.message);\n    });\n\n self.onInstanceAndEvent(self, 'click').first().subscribe((e:IMessage)=> {\n        var commBroker:CommBroker = e.fromInstance;\n        console.log(`just one ${e.event} from ${commBroker.toString()}`);\n    });\n\n self.onInstanceAndEvent(self, 'click').subscribe((e:IMessage) => {\n        console.log(`handle success: rx ${e.event}`)\n    }, (e) => {\n        console.log(`handle error ${e}`)\n    }, () => {\n        console.log(`handle complete`)\n    });\n\n // before stream ready\n var msg1:IMessage = {\n        fromInstance: self,\n        event: 'click',\n        context: 1,\n        message: 'before stream is ready'\n    };\n self.fire(msg1);\n\n // after stream ready\n setTimeout(function () {\n        var msg2:IMessage = {\n            fromInstance: self,\n            event: 'click',\n            context: 2,\n            message: 'after stream is ready'\n        };\n        self.fire(msg2);\n    }, 2000)\n **/\n\n\nexport interface IMessage {\n    event: string,\n    fromInstance: any,\n    context?: any,\n    message?: any\n}\n\n// create an alias type just so it's easier to associate\ntype SubjectMessage = Subject<IMessage>;\ntype SubjectMessages = Subject<Array<SubjectMessage>>;\n\n@Injectable()\nexport class CommBroker {\n    private streamMessages: Subject<IMessage>;\n    private services: string[];\n    private randomName: number = Math.random();\n\n    constructor() {\n        var self = this;\n        self.services = [];\n        self.streamMessages = new Subject() as SubjectMessage;\n\n        // we use share as a shorthand for publish() which converts cold to hot\n        // observable as well as connect() / refCount()\n        // when connected references moves from 0 to 1\n        self.streamMessages.share();\n\n        // if we wish to use a unidirectional stream we can convert to Observable instead of subject\n        //self.stream = new Observable(trigger => {\n        //    trigger.next(msg);\n        //    trigger.error('boom');\n        //    trigger.complete('done');\n        //}).share();\n\n        // this is the only global member we expose\n        document['commBroker'] = this;\n    }\n\n    public toString() {\n        return 'CommBroker ' + this.randomName; // to test uniqueness\n    }\n\n    /**\n     With fire we push a stream of IMessages into our stream.\n     @method fire\n     @params IMessage\n     **/\n    public fire(iMessage: IMessage): void {\n        try {\n            this.streamMessages.next(iMessage);\n        } catch (e) {\n            if (Lib.DevMode())\n                console.error('CommBroker fire exception in function: ' + iMessage + ' ' + e);\n        }\n\n    }\n\n    public onEvent(event: string) {\n        var self = this;\n        return self.streamMessages.filter((e) => {\n            return e.event == event;\n        })\n    }\n\n    public onInstance(instance: any) {\n        var self = this;\n        return self.streamMessages.filter((e) => {\n            return e.fromInstance == instance;\n        })\n    }\n\n    public onInstanceAndEvent(instance: any, event: string) {\n        var self = this;\n        return self.streamMessages.filter((e) => {\n            return e.fromInstance == instance && e.event == event\n        })\n    }\n\n    /**\n     Register a service  that others can query.\n     @method setService\n     @param {String} i_name\n     @param {Object} i_service\n     @return none\n     **/\n    setService(i_name, i_service) {\n        this.services[i_name] = i_service;\n    }\n\n    /**\n     Get a registered service.\n     @method getService\n     @param {String} i_name\n     @return {Object} services member\n     **/\n    getService(i_name): any {\n        if (i_name == undefined) {\n            //log('cant get set undefined service ' + i_name);\n            return undefined;\n        }\n        if (this.services[i_name]) {\n            return this.services[i_name]\n        } else {\n            return undefined;\n        }\n    }\n\n    /**\n     Expose all services and data members.\n     @method getAllServices\n     @return {Object} services\n     **/\n    getAllServices() {\n        return this.services;\n    }\n\n    /**\n     Clear all current registered services\n     @method clearServices\n     **/\n    clearServices() {\n        var self = this;\n        // delete self.services;\n        self.services = undefined;\n    }\n\n    /**\n     Register a data member that others can query.\n     @method setValue\n     @param {String} i_name\n     @param {Object} i_value\n     @param {Event} i_fireEvent\n     @return none\n     **/\n    setValue(i_name: any, i_value: any, i_fireEvent?: string): void {\n        var self = this;\n        this.services[i_name] = i_value;\n        if (i_fireEvent) {\n            var msg: IMessage = {\n                fromInstance: self,\n                event: i_fireEvent,\n                context: null,\n                message: {name: i_name, value: i_value}\n            };\n            self.fire(msg);\n        }\n    }\n\n    /**\n     Get a registered data member.\n     @method getValue\n     @param {String} i_name\n     @return {Object} m_services member\n     **/\n    getValue(i_name): any {\n        var v: any = this.services[i_name];\n        if (v === 0)\n            return this.services[i_name]\n        if (!_.isUndefined(v))\n            return this.services[i_name]\n        return undefined;\n    }\n}\n"
  },
  {
    "path": "src/services/CreditService.ts",
    "content": "import {Injectable, Injector} from '@angular/core';\n\n// repo: https://github.com/PawelDecowski/jQuery-CreditCardValidator/\n\n// var b = creditService.validateCardNumber('5418426187097565');\n// var b = creditService.validateCardExpiry('10','15');\n// var b = creditService.validateCardCVC(123,'visa');\n// var b = creditService.parseCardType('5418426187097565');\n// var b = creditService.parseCardExpiry('10/2016');\n// var b = creditService.formatCardNumber('5418 4261 8709 7565');\n// var b = creditService.formatCardNumber('5418-4261-8709 7565');\n// var b = creditService.formatCardExpiry('1/16');\n\n@Injectable()\nexport class CreditService {\n\n    constructor() {\n        this.credit = (function () {\n\n            var indexOf = [].indexOf || function (item) {\n                    for (var i = 0, l = this.length; i < l; i++) {\n                        if (i in this && this[i] === item) return i;\n                    }\n                    return -1;\n                };\n\n            return (function (name, definition) {\n                return definition();\n            })('cc', function () {\n                var _eventNormalize, _getCaretPos, _on, cardFromNumber, cardFromType, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardExpiry, formatCardNumber, formatForwardExpiry, formatForwardSlashAndSpace, hasTextSelected, luhnCheck, payform:any, reFormatCVC, reFormatCardNumber, reFormatExpiry, replaceFullWidthChars, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric;\n                _getCaretPos = function (ele) {\n                    var r, rc, re;\n                    if (ele.selectionStart != null) {\n                        return ele.selectionStart;\n                    } else if (this.doc.selection != null) {\n                        ele.focus();\n                        r = this.doc.selection.createRange();\n                        re = ele.createTextRange();\n                        rc = re.duplicate();\n                        re.moveToBookmark(r.getBookmark());\n                        rc.setEndPoint('EndToStart', re);\n                        return rc.text.length;\n                    }\n                };\n                _eventNormalize = function (listener) {\n                    return function (e) {\n                        if (e == null) {\n                            e = window.event;\n                        }\n                        e.target = e.target || e.srcElement;\n                        e.which = e.which || e.keyCode;\n                        if (e.preventDefault == null) {\n                            e.preventDefault = function () {\n                                return this.returnValue = false;\n                            };\n                        }\n                        return listener(e);\n                    };\n                };\n                _on = function (ele, event, listener) {\n                    listener = _eventNormalize(listener);\n                    if (ele.addEventListener != null) {\n                        return ele.addEventListener(event, listener, false);\n                    } else {\n                        return ele.attachEvent(\"on\" + event, listener);\n                    }\n                };\n                payform = {};\n                defaultFormat = /(\\d{1,4})/g;\n                payform.cards = [\n                    {\n                        type: 'visaelectron',\n                        pattern: /^4(026|17500|405|508|844|91[37])/,\n                        format: defaultFormat,\n                        length: [16],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'maestro',\n                        pattern: /^(5(018|0[23]|[68])|6(39|7))/,\n                        format: defaultFormat,\n                        length: [12, 13, 14, 15, 16, 17, 18, 19],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'forbrugsforeningen',\n                        pattern: /^600/,\n                        format: defaultFormat,\n                        length: [16],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'dankort',\n                        pattern: /^5019/,\n                        format: defaultFormat,\n                        length: [16],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'visa',\n                        pattern: /^4/,\n                        format: defaultFormat,\n                        length: [13, 16],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'mastercard',\n                        pattern: /^(5[1-5]|2[2-7])/,\n                        format: defaultFormat,\n                        length: [16],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'amex',\n                        pattern: /^3[47]/,\n                        format: /(\\d{1,4})(\\d{1,6})?(\\d{1,5})?/,\n                        length: [15],\n                        cvcLength: [3, 4],\n                        luhn: true\n                    }, {\n                        type: 'dinersclub',\n                        pattern: /^3[0689]/,\n                        format: /(\\d{1,4})(\\d{1,6})?(\\d{1,4})?/,\n                        length: [14],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'discover',\n                        pattern: /^6([045]|22)/,\n                        format: defaultFormat,\n                        length: [16],\n                        cvcLength: [3],\n                        luhn: true\n                    }, {\n                        type: 'unionpay',\n                        pattern: /^(62|88)/,\n                        format: defaultFormat,\n                        length: [16, 17, 18, 19],\n                        cvcLength: [3],\n                        luhn: false\n                    }, {\n                        type: 'jcb',\n                        pattern: /^35/,\n                        format: defaultFormat,\n                        length: [16],\n                        cvcLength: [3],\n                        luhn: true\n                    }\n                ];\n                cardFromNumber = function (num) {\n                    var card, i, len, ref;\n                    num = (num + '').replace(/\\D/g, '');\n                    ref = payform.cards;\n                    for (i = 0, len = ref.length; i < len; i++) {\n                        card = ref[i];\n                        if (card.pattern.test(num)) {\n                            return card;\n                        }\n                    }\n                };\n                cardFromType = function (type) {\n                    var card, i, len, ref;\n                    ref = payform.cards;\n                    for (i = 0, len = ref.length; i < len; i++) {\n                        card = ref[i];\n                        if (card.type === type) {\n                            return card;\n                        }\n                    }\n                };\n                luhnCheck = function (num) {\n                    var digit, digits, i, len, odd, sum;\n                    odd = true;\n                    sum = 0;\n                    digits = (num + '').split('').reverse();\n                    for (i = 0, len = digits.length; i < len; i++) {\n                        digit = digits[i];\n                        digit = parseInt(digit, 10);\n                        if ((odd = !odd)) {\n                            digit *= 2;\n                        }\n                        if (digit > 9) {\n                            digit -= 9;\n                        }\n                        sum += digit;\n                    }\n                    return sum % 10 === 0;\n                };\n                hasTextSelected = function (target) {\n                    var ref;\n                    if ((typeof document !== \"undefined\" && document !== null ? (ref = this.doc.selection) != null ? ref.createRange : void 0 : void 0) != null) {\n                        if (this.doc.selection.createRange().text) {\n                            return true;\n                        }\n                    }\n                    return (target.selectionStart != null) && target.selectionStart !== target.selectionEnd;\n                };\n                replaceFullWidthChars = function (str) {\n                    var char, chars, fullWidth, halfWidth, i, idx, len, value;\n                    if (str == null) {\n                        str = '';\n                    }\n                    fullWidth = '\\uff10\\uff11\\uff12\\uff13\\uff14\\uff15\\uff16\\uff17\\uff18\\uff19';\n                    halfWidth = '0123456789';\n                    value = '';\n                    chars = str.split('');\n                    for (i = 0, len = chars.length; i < len; i++) {\n                        char = chars[i];\n                        idx = fullWidth.indexOf(char);\n                        if (idx > -1) {\n                            char = halfWidth[idx];\n                        }\n                        value += char;\n                    }\n                    return value;\n                };\n                reFormatCardNumber = function (e) {\n                    var cursor;\n                    cursor = _getCaretPos(e.target);\n                    e.target.value = payform.formatCardNumber(e.target.value);\n                    if ((cursor != null) && e.type !== 'change') {\n                        return e.target.setSelectionRange(cursor, cursor);\n                    }\n                };\n                formatCardNumber = function (e) {\n                    var card, cursor, digit, length, re, upperLength, value;\n                    digit = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(digit)) {\n                        return;\n                    }\n                    value = e.target.value;\n                    card = cardFromNumber(value + digit);\n                    length = (value.replace(/\\D/g, '') + digit).length;\n                    upperLength = 16;\n                    if (card) {\n                        upperLength = card.length[card.length.length - 1];\n                    }\n                    if (length >= upperLength) {\n                        return;\n                    }\n                    cursor = _getCaretPos(e.target);\n                    if (cursor && cursor !== value.length) {\n                        return;\n                    }\n                    if (card && card.type === 'amex') {\n                        re = /^(\\d{4}|\\d{4}\\s\\d{6})$/;\n                    } else {\n                        re = /(?:^|\\s)(\\d{4})$/;\n                    }\n                    if (re.test(value)) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = value + \" \" + digit;\n                        });\n                    } else if (re.test(value + digit)) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = (value + digit) + \" \";\n                        });\n                    }\n                };\n                formatBackCardNumber = function (e) {\n                    var cursor, value;\n                    value = e.target.value;\n                    if (e.which !== 8) {\n                        return;\n                    }\n                    cursor = _getCaretPos(e.target);\n                    if (cursor && cursor !== value.length) {\n                        return;\n                    }\n                    if (/\\d\\s$/.test(value)) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = value.replace(/\\d\\s$/, '');\n                        });\n                    } else if (/\\s\\d?$/.test(value)) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = value.replace(/\\d$/, '');\n                        });\n                    }\n                };\n                reFormatExpiry = function (e) {\n                    var cursor;\n                    cursor = _getCaretPos(e.target);\n                    e.target.value = payform.formatCardExpiry(e.target.value);\n                    if ((cursor != null) && e.type !== 'change') {\n                        return e.target.setSelectionRange(cursor, cursor);\n                    }\n                };\n                formatCardExpiry = function (e) {\n                    var digit, val;\n                    digit = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(digit)) {\n                        return;\n                    }\n                    val = e.target.value + digit;\n                    if (/^\\d$/.test(val) && (val !== '0' && val !== '1')) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = \"0\" + val + \" / \";\n                        });\n                    } else if (/^\\d\\d$/.test(val)) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = val + \" / \";\n                        });\n                    }\n                };\n                formatForwardExpiry = function (e) {\n                    var digit, val;\n                    digit = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(digit)) {\n                        return;\n                    }\n                    val = e.target.value;\n                    if (/^\\d\\d$/.test(val)) {\n                        return e.target.value = val + \" / \";\n                    }\n                };\n                formatForwardSlashAndSpace = function (e) {\n                    var val, which;\n                    which = String.fromCharCode(e.which);\n                    if (!(which === '/' || which === ' ')) {\n                        return;\n                    }\n                    val = e.target.value;\n                    if (/^\\d$/.test(val) && val !== '0') {\n                        return e.target.value = \"0\" + val + \" / \";\n                    }\n                };\n                formatBackExpiry = function (e) {\n                    var cursor, value;\n                    value = e.target.value;\n                    if (e.which !== 8) {\n                        return;\n                    }\n                    cursor = _getCaretPos(e.target);\n                    if (cursor && cursor !== value.length) {\n                        return;\n                    }\n                    if (/\\d\\s\\/\\s$/.test(value)) {\n                        e.preventDefault();\n                        return setTimeout(function () {\n                            return e.target.value = value.replace(/\\d\\s\\/\\s$/, '');\n                        });\n                    }\n                };\n                reFormatCVC = function (e) {\n                    var cursor;\n                    cursor = _getCaretPos(e.target);\n                    e.target.value = replaceFullWidthChars(e.target.value).replace(/\\D/g, '').slice(0, 4);\n                    if ((cursor != null) && e.type !== 'change') {\n                        return e.target.setSelectionRange(cursor, cursor);\n                    }\n                };\n                restrictNumeric = function (e) {\n                    var input;\n                    if (e.metaKey || e.ctrlKey) {\n                        return;\n                    }\n                    if (e.which === 0) {\n                        return;\n                    }\n                    if (e.which < 33) {\n                        return;\n                    }\n                    input = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(input)) {\n                        return e.preventDefault();\n                    }\n                };\n                restrictCardNumber = function (e) {\n                    var card, digit, value;\n                    digit = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(digit)) {\n                        return;\n                    }\n                    if (hasTextSelected(e.target)) {\n                        return;\n                    }\n                    value = (e.target.value + digit).replace(/\\D/g, '');\n                    card = cardFromNumber(value);\n                    if (card && value.length > card.length[card.length.length - 1]) {\n                        return e.preventDefault();\n                    } else if (value.length > 16) {\n                        return e.preventDefault();\n                    }\n                };\n                restrictExpiry = function (e) {\n                    var digit, value;\n                    digit = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(digit)) {\n                        return;\n                    }\n                    if (hasTextSelected(e.target)) {\n                        return;\n                    }\n                    value = e.target.value + digit;\n                    value = value.replace(/\\D/g, '');\n                    if (value.length > 6) {\n                        return e.preventDefault();\n                    }\n                };\n                restrictCVC = function (e) {\n                    var digit, val;\n                    digit = String.fromCharCode(e.which);\n                    if (!/^\\d+$/.test(digit)) {\n                        return;\n                    }\n                    if (hasTextSelected(e.target)) {\n                        return;\n                    }\n                    val = e.target.value + digit;\n                    if (val.length > 4) {\n                        return e.preventDefault();\n                    }\n                };\n                payform.cvcInput = function (input) {\n                    _on(input, 'keypress', restrictNumeric);\n                    _on(input, 'keypress', restrictCVC);\n                    _on(input, 'paste', reFormatCVC);\n                    _on(input, 'change', reFormatCVC);\n                    return _on(input, 'input', reFormatCVC);\n                };\n                payform.expiryInput = function (input) {\n                    _on(input, 'keypress', restrictNumeric);\n                    _on(input, 'keypress', restrictExpiry);\n                    _on(input, 'keypress', formatCardExpiry);\n                    _on(input, 'keypress', formatForwardSlashAndSpace);\n                    _on(input, 'keypress', formatForwardExpiry);\n                    _on(input, 'keydown', formatBackExpiry);\n                    _on(input, 'change', reFormatExpiry);\n                    return _on(input, 'input', reFormatExpiry);\n                };\n                payform.cardNumberInput = function (input) {\n                    _on(input, 'keypress', restrictNumeric);\n                    _on(input, 'keypress', restrictCardNumber);\n                    _on(input, 'keypress', formatCardNumber);\n                    _on(input, 'keydown', formatBackCardNumber);\n                    _on(input, 'paste', reFormatCardNumber);\n                    _on(input, 'change', reFormatCardNumber);\n                    return _on(input, 'input', reFormatCardNumber);\n                };\n                payform.numericInput = function (input) {\n                    _on(input, 'keypress', restrictNumeric);\n                    _on(input, 'paste', restrictNumeric);\n                    _on(input, 'change', restrictNumeric);\n                    return _on(input, 'input', restrictNumeric);\n                };\n                payform.parseCardExpiry = function (value) {\n                    var month, prefix, ref, year;\n                    value = value.replace(/\\s/g, '');\n                    ref = value.split('/', 2), month = ref[0], year = ref[1];\n                    if ((year != null ? year.length : void 0) === 2 && /^\\d+$/.test(year)) {\n                        prefix = (new Date).getFullYear();\n                        prefix = prefix.toString().slice(0, 2);\n                        year = prefix + year;\n                    }\n                    month = parseInt(month, 10);\n                    year = parseInt(year, 10);\n                    return {\n                        month: month,\n                        year: year\n                    };\n                };\n                payform.validateCardNumber = function (num) {\n                    var card, ref;\n                    num = (num + '').replace(/\\s+|-/g, '');\n                    if (!/^\\d+$/.test(num)) {\n                        return false;\n                    }\n                    card = cardFromNumber(num);\n                    if (!card) {\n                        return false;\n                    }\n                    return (ref = num.length, indexOf.call(card.length, ref) >= 0) && (card.luhn === false || luhnCheck(num));\n                };\n                payform.validateCardExpiry = function (month, year) {\n                    var currentTime, expiry, ref;\n                    if (typeof month === 'object' && 'month' in month) {\n                        ref = month, month = ref.month, year = ref.year;\n                    }\n                    if (!(month && year)) {\n                        return false;\n                    }\n                    month = String(month).trim();\n                    year = String(year).trim();\n                    if (!/^\\d+$/.test(month)) {\n                        return false;\n                    }\n                    if (!/^\\d+$/.test(year)) {\n                        return false;\n                    }\n                    if (!((1 <= month && month <= 12))) {\n                        return false;\n                    }\n                    if (year.length === 2) {\n                        if (year < 70) {\n                            year = \"20\" + year;\n                        } else {\n                            year = \"19\" + year;\n                        }\n                    }\n                    if (year.length !== 4) {\n                        return false;\n                    }\n                    expiry = new Date(year, month);\n                    currentTime = new Date;\n                    expiry.setMonth(expiry.getMonth() - 1);\n                    expiry.setMonth(expiry.getMonth() + 1, 1);\n                    return expiry > currentTime;\n                };\n                payform.validateCardCVC = function (cvc, type) {\n                    var card, ref;\n                    cvc = String(cvc).trim();\n                    if (!/^\\d+$/.test(cvc)) {\n                        return false;\n                    }\n                    card = cardFromType(type);\n                    if (card != null) {\n                        return ref = cvc.length, indexOf.call(card.cvcLength, ref) >= 0;\n                    } else {\n                        return cvc.length >= 3 && cvc.length <= 4;\n                    }\n                };\n                payform.parseCardType = function (num) {\n                    var ref;\n                    if (!num) {\n                        return null;\n                    }\n                    return ((ref = cardFromNumber(num)) != null ? ref.type : void 0) || null;\n                };\n                payform.formatCardNumber = function (num) {\n                    var card, groups, ref, upperLength;\n                    num = replaceFullWidthChars(num);\n                    num = num.replace(/\\D/g, '');\n                    card = cardFromNumber(num);\n                    if (!card) {\n                        return num;\n                    }\n                    upperLength = card.length[card.length.length - 1];\n                    num = num.slice(0, upperLength);\n                    if (card.format.global) {\n                        return (ref = num.match(card.format)) != null ? ref.join(' ') : void 0;\n                    } else {\n                        groups = card.format.exec(num);\n                        if (groups == null) {\n                            return;\n                        }\n                        groups.shift();\n                        groups = groups.filter(Boolean);\n                        return groups.join(' ');\n                    }\n                };\n                payform.formatCardExpiry = function (expiry) {\n                    var mon, parts, sep, year;\n                    expiry = replaceFullWidthChars(expiry);\n                    parts = expiry.match(/^\\D*(\\d{1,2})(\\D+)?(\\d{1,4})?/);\n                    if (!parts) {\n                        return '';\n                    }\n                    mon = parts[1] || '';\n                    sep = parts[2] || '';\n                    year = parts[3] || '';\n                    if (year.length > 0) {\n                        sep = ' / ';\n                    } else if (sep === ' /') {\n                        mon = mon.substring(0, 1);\n                        sep = '';\n                    } else if (mon.length === 2 || sep.length > 0) {\n                        sep = ' / ';\n                    } else if (mon.length === 1 && (mon !== '0' && mon !== '1')) {\n                        mon = \"0\" + mon;\n                        sep = ' / ';\n                    }\n                    return mon + sep + year;\n                };\n                return payform;\n            });\n\n        }).call(this);\n    }\n\n    private credit;\n    private doc:any = document;\n\n    public validateCardNumber(cardNumber):boolean {\n        return this.credit.validateCardNumber(cardNumber);\n    }\n\n    public validateCardExpiry(month, year):boolean {\n        return this.credit.validateCardExpiry(month, year);\n    }\n\n    public validateCardCVC(cvc, type):boolean {\n        return this.credit.validateCardCVC(cvc, type);\n    }\n    \n    public parseCardType(cardNumber):boolean {\n        return this.credit.parseCardType(cardNumber);\n    }\n\n    public parseCardExpiry(value):boolean {\n        return this.credit.parseCardExpiry(value);\n    }\n\n    public formatCardNumber(value):boolean {\n        return this.credit.formatCardNumber(value);\n    }\n\n    public formatCardExpiry(expiry):boolean {\n        var result = this.credit.formatCardExpiry(expiry);\n        return result;\n    }\n}"
  },
  {
    "path": "src/services/LocalStorage.ts",
    "content": "import {Injectable} from '@angular/core';\n\n@Injectable()\nexport class LocalStorage {\n\n    getItem(key: string, defaultValue?: any): any {\n        if (localStorage.getItem(key)) {\n            return JSON.parse(localStorage.getItem(key));\n        } else {\n            return defaultValue;\n        }\n    }\n\n    setItem(key: string, value: any): void {\n        localStorage.setItem(key, JSON.stringify(value));\n    }\n\n    removeItem(key: string): void {\n        localStorage.removeItem(key);\n    }\n\n}"
  },
  {
    "path": "src/services/StoreService.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {Store} from \"@ngrx/store\";\nimport {ApplicationState} from \"../store/application.state\";\nimport {AppdbAction} from \"../store/actions/appdb.actions\";\nimport {EFFECT_INIT_REDUXIFY_MSDB} from \"../store/effects/msdb.effects\";\nimport {RedPepperService} from \"./redpepper.service\";\n\n@Injectable()\nexport class StoreService {\n    constructor(private store: Store<ApplicationState>, private appdbAction: AppdbAction, private rp:RedPepperService) {\n\n        // todo: disabled injection as broken in AOT\n        // constructor(@Inject(forwardRef(() => Store)) private store: Store<ApplicationState>,\n        //     @Inject(forwardRef(() => AppdbAction)) private appdbAction: AppdbAction,\n        //     @Inject(forwardRef(() => RedPepperService)) private redPepperService: RedPepperService,\n        //     @Inject('OFFLINE_ENV') private offlineEnv) {\n\n        this.store.dispatch(this.appdbAction.initAppDb());\n    }\n\n    private singleton: boolean = false;\n\n    public loadServices() {\n        if (this.singleton) return;\n        this.singleton = true;\n        this.rp.injectPseudoScenePlayersIDs();\n        this.store.dispatch({type: EFFECT_INIT_REDUXIFY_MSDB})\n        // this.rp.reduxCommit();\n        con('loaded network services...');\n    }\n}\n"
  },
  {
    "path": "src/services/block-factory-service.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {BlockLabels} from \"../interfaces/Consts\";\nimport {BlockFabricScene} from \"../app/blocks/block-fabric-scene\";\nimport {RedPepperService} from \"./redpepper.service\";\nimport {BlockFabric} from \"../app/blocks/block-fabric\";\nimport {BlockFabricImage} from \"../app/blocks/block-fabric-image\";\nimport {BlockFabricLabel} from \"../app/blocks/block-fabric-label\";\nimport {BlockFabricSvg} from \"../app/blocks/block-fabric-svg\";\nimport {BlockService} from \"../app/blocks/block-service\";\nimport * as _ from \"lodash\";\nimport * as X2JS from \"x2js\";\nimport {BlockFabricJsonItem} from \"../app/blocks/block-fabric-josn-item\";\n\n//// import X2JS from \"x2js\";\n//// import \"x2js\";\n\n@Injectable()\nexport class BlockFactoryService {\n    parser;\n\n    constructor(private rp: RedPepperService, private bs: BlockService) {\n        this.parser = new X2JS({\n            escapeMode: true,\n            attributePrefix: \"_\",\n            arrayAccessForm: \"none\",\n            emptyNodeForm: \"text\",\n            enableToStringFunc: true,\n            arrayAccessFormPaths: [],\n            skipEmptyTextNodesForObj: true\n        });\n    }\n\n    /**\n     This is factory method produces block instances which will reside on the timeline and referenced within this\n     channel instance. The factory will parse the blockCode and create the appropriate block type.\n     **/\n    createBlock(block_id, i_player_data, i_scene_id?) {\n        // con('creating block ' + blockCode + ' ' + i_player_data);\n        var block;\n        var playerData = this.parser.xml2js(i_player_data);\n        var blockCode = parseInt(playerData['Player']['_player']);\n\n        switch (blockCode) {\n            case BlockLabels.BLOCKCODE_SCENE: {\n                block = new BlockFabricScene({i_block_id: block_id}, this.bs, this.rp);\n                break;\n            }\n\n            case BlockLabels.BLOCKCODE_IMAGE: {\n                block = new BlockFabricImage({i_block_id: block_id, i_scene_player_data_id: i_scene_id}, this.bs, this.rp);\n                break;\n            }\n\n            case BlockLabels.BLOCKCODE_SVG: {\n                block = new BlockFabricSvg({i_block_id: block_id, i_scene_player_data_id: i_scene_id}, this.bs, this.rp);\n                break;\n            }\n\n            case BlockLabels.LABEL: {\n                block = new BlockFabricLabel({i_block_id: block_id, i_scene_player_data_id: i_scene_id}, this.bs, this.rp);\n                break;\n            }\n\n            case BlockLabels.BLOCKCODE_GOOGLE_SHEETS: {\n            }\n            case BlockLabels.BLOCKCODE_CALENDAR: {\n            }\n            case BlockLabels.BLOCKCODE_INSTAGRAM: {\n            }\n            case BlockLabels.BLOCKCODE_JSON_ITEM: {\n            }\n            case BlockLabels.BLOCKCODE_WORLD_WEATHER: {\n            }\n            case BlockLabels.BLOCKCODE_TWITTER_ITEM: {\n            }\n            case BlockLabels.BLOCKCODE_JSON_ITEM: {\n                block = new BlockFabricJsonItem({i_block_id: block_id, i_scene_player_data_id: i_scene_id}, this.bs, this.rp);\n                break;\n            }\n\n            default: {\n                block = new BlockFabric({i_block_id: block_id, i_scene_player_data_id: i_scene_id}, this.bs, this.rp, blockCode);\n                break;\n            }\n        }\n        return block;\n    }\n}\n\n// subclass our block from fabric.Group if resides inside scene\n// if (i_placement == PLACEMENT_SCENE) {\n//     // var g = new fabric.Group([]);\n//     // _.extend(block, g);\n//     // g = undefined;\n// }"
  },
  {
    "path": "src/services/font-loader-service.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {Lib} from \"../Lib\";\n\n@Injectable()\nexport class FontLoaderService {\n\n    private m_webFontConfig;\n    private m_fonts;\n\n    constructor() {\n\n        // deprecated\n        // google: { families: [ 'Roboto:latin,Ribeye::latin', 'Lora::latin', 'Croissant+One::latin', 'Emblema+One::latin', 'Graduate::latin', 'Hammersmith+One::latin', 'Oswald::latin', 'Oxygen::latin', 'Krona+One::latin', 'Indie+Flower::latin', 'Courgette::latin', 'Ranchers::latin' ] }\n        // this.m_fonts = 'Roboto,Graduate,Ribeye,Lora,Indie+Flowe,Croissant+One,Hammersmith+One,Oxygen,Fatty,Relief,Luxo,Qurve,Nite,CordiaUPC,SlimFast AH,Informal Roman,Old English Text MT,Juice ITC,Cheetah,RemiHead,Maiandra GD,Tangerine XCn,Rosegarden,Rivanna,Jokerman,Lab Bats,GeoBats,Baskerville Old Face,Swollen,Deftone Stylus,Suske & Wiske,Babe Bamboo,Fat,Tannenberg Fett,Sansation,Magdalena,Jamiro,HanWangMingLight,Marfhaus,Verdana,Lefferts Corners  2,Star Dust Condensed,city burn night after night and,Rx-FiveOne,Hallisey,Impossible - 500,Sniff,IGaramond,Royal Pain,Simplified Arabic,Cassatta Zig,Rub This!,Quartermain Condensed,Milkfresh,Revel,Ground Zero,Scramble,gogoâ€¢squat,Raveflire 2.0,Yellowjacket Rotate,Californian FB,Goudy Old Style,Hammer,Letter Set C,LetterGotLBol,KodchiangUPC,Zhang QA,IcedEarth,FeltMark,Irezumi,Lois Ann,Stencil,Zone23_Dreamtime 923,Yellowjacket Expanded,Jangly Bounce,Scary Monsters,Smilly,Footlight MT Light,Rambo Killer ,ILL oMen,Engravers MT,I Want My TTR!,SF Archery Black SC,Starburst,Humeur,Bandit,Sanguinaryâ„¢,Lilith,Smiley,Ridicule,MT Extra,Franklin Gothic Medium Cond,Oblivious font,Mattbats,Lowtech,Magehunter,Broadway,Hall Fetica,OCR-A BT,Berlin Sans FB,Luftwaffe,Xolto,Switching and Effects,Scriptina,QTHowardTypeFat,Snap ITC,Harlow Solid Italic,ROCKY AOE,Re-buried,Gigi,Backslide,Umpyre,Horley Old Style MT,Bubble 1,Latha,Joe,Radiated Pancake,Kartika,Zebra Parade,Cooper Black,Lewis F. Day 191,Many moods of Moe,Nameless Harbor,Blade Runner Movie Font,Year 2000 Replicant,RoteFlora,Sylfaen,Outer Limits Solid,Britannic Bold,ReskaGraf,M,Vivienne,Libritabs,YrBkMess,So Extended,Rockwell Extra Bold,Seeing Stars,Space Gimboid,Jerk,Kid Kosmic,Patriot,Junegull,Lifetime,Samba is Dead,Real Horror Show,Sagittarius,Sand,LTInagur,Fanatika One,Univers,Lindas Lament,VTC Lo-Down,LiddieBlack,Rivalry,Electroharmonix,RobinsHand,Franklin Gothic Medium,Wingdings 2,Jeff-Chris,Mars Police,Narkisim,Rep,K.P. Duty Overtime JL,Airmole,Symbol Set SWA,BeachType,STFangsong,Lower-WestSide,STXihei,Nouveau,Mikey Jax,Rogue Hero Condensed,Cream and sugar,Edwardian Script ITC,Tw Cen MT Condensed,JustSmashing,RubaiyatEngraved,David,Copperplate Gothic Light,Verticalization,Rocket YoYo,Vladimir Script,Shoestore,SteveHandwriting,Oconnor,Tw Cen MT Condensed Extra Bold,Zachary Hanson,7 days,HanWangMingHeavy,Koffee,Bernard MT Condensed,Astron Boy Video,ParisMetro,Gill Sans MT,Calibri,Year 3000 Pro,NuevoLitho,Tattoo No1,Nebraska,Mael,Stranded (BRK),CaligulaDodgy,YouYuan,y.n.w.u.a.y,Z machine (sRB),Regal box,SidTheSpider,Saltire,QUAKE,Industrial,Poor Richard,Sujeta Outline,HammerheadOutline,Curlz MT,Occasion DB,Regular,Elbjorg,Pristina,Papyrus,Omicron Zeta Slant,Bodoni MT Black,Martel,Wingdings 3,Makisupa,QTKung-Fu,TANTOR,CHICASyMUJERES,Dead Alive,Bodoni MT Condensed,Simplified Arabic Fixed,Vitamin,IkonWrite,Ruach LET,QuickExpress,Marlo,Rogue Hero Laser,HanWangMingMediumChuIn,Swirl,Lizzard,JackRoman,Skull Capz (BRK),Butterflies,Boomerang,David Transparent,STLiti,RRHeralds,Stephen,Eras Bold ITC,Raptor Attack,Jerkoff,Undercover,Love Letters,Scroll,International Super Hero Exp,National First Font,7th Service Condensed,Joint,Qurve Hollow,Birds of a Feather,XBAND Rough,Walrod,Arial Black,SinaloaIniD,Miserable,T,Maharlika,Rundfunk,Realpolitik,NimbusSanPCon,MS Reference Specialty,November,Japanette DB,Gill Sans Ultra Bold,Regulators Condensed,Bodoni MT Poster Compressed,RollingStone,Swinkydad,Arial Rounded MT Bold,u27fog,Stiletto,Kantor Ligatures,Hollywood,NuWave,WarnSymbols1,GiantTigers,NEOLITH,SimHei,Geometr415 Md BT,Bell MT,Judge,MandarinSCD,STKaiti,Sam is my Name,SF Arch Rival Extended,Rod Transparent,Qurve Thin,Centaur,SF Comic Script,Rupee,Rat Man Bane,Myopia,Karloff,Onyx,MammaGamma,Quiet Infinity,Xeroprint,Alba Super,Kunstler Script,Imprint MT Shadow,Lucida Sans,Rage Italic,Rubberneck,Night Court,Franklin Gothic Heavy,Shipper,Y2K Analog Legacy,Robokid,voxBOX,StickAroundForJoy,Gloucester MT Extra Condensed,Gas Huffer Phat,Shotgun BT,Xomic,Century,FZ JAZZY 12 CRACKED,Monsters Attack!,Vipnagorgialla,JackCondensed,Ultra,Machiavelli,Symbol,HamburgerHeaven,Dark Horse,Feuerfeste,Wide Latin,Matura MT Script Capitals,SandCastles,SF Chaerilidae,EucrosiaUPC,Oregon,Eras Light ITC,SkaterDudes,Nails,Machine-gun,Mixed up,WallStreet,MarlonDB,Ramose,Kaptain Toupe,Scroonge,Rage Italic LET,I hate Comic Sans,pills are good,Vixar ASCI,Revel Light,Rocket Type Condensed,wmtrees1,Occoluchi Italic,NobbiGConDB,French Script MT,LTColibri,YellowSubmarine,Y2K Neophyte,MS Mincho,MV Boli,Bookshelf Symbol 7,ResbalosoSlippingA,Royal box,Zymbols,Sci Fied 2002 Ultra,Arial,Spit Shine,Trebuchet MS,SILDoulos IPA93,Subeve,HanWangYenHeavy,Fixed Miriam Transparent,Andalus,SpitCurl,Stab Wound,Zero Gravity,Blackadder ITC,Felix Titling,Road Hoe,Haettenschweiler,RobleRoundedSCapsSSK,Hammerhead,Microsoft JhengHei,Ruban Dismoi Tryout,Eras Medium ITC,STZhongsong,Vrinda,Qurve Wide,Miriam,Modern No. 20,KabanaBold,Rock Star,Randi,Palatino Linotype,MotterFemD,Wingdings,Gill Sans Ultra Bold Condensed,naked monk,Courier New,Ren & Stimpy,RANXEROX,StrokeyBacon,Ogilvie,Zinc Boomerang,Scritzy,Science Project,Blue Highway Linocut,LifeT,Numskull (BRK),Swirled (BRK),SexyMF,MarionsHand,HanWangHeiLight,Kristen ITC,Masterforce Solid,Bradley Hand ITC,Magic:the Gathering,Vivaldi,HarlowD,Native Alien Extended,Gill Sans MT Condensed,Chow Fun,Tanline,Sakkal Majalla,Nina,Xephyr Italic,Luteous Industrious,Saffron,SF Chrome Fenders Extended,Linoleum,Franklin Gothic Demi,Impact,Logan,Raavi,STXingkai,Marathon II,Marburg DB,Revue BT,Algerian,Reactivare,BrowalliaUPC,Ravie,W.J. Pearce hollow,Tempus Sans ITC,Niagara Engraved,STXinwei,LTSicula,Quinquefoliolate,Anhedonia,Salter,Nuance,Good Head,SpeedballNo2SW,Reticulum 3,Swiss911 XCm BT,Takeout,Lucida Console,WeInside,RoselleCapsSSK,Lucida Sans Unicode,Quadrangle,Impossibilium (BRK),QuotaBlack DB,Neuropolitical,HanWangYenLight,Nonstop [italic],Samson Light Oblique,Geeves,Shruti,VIPER NORA,Nauvoo,MS Reference Sans Serif,Yellow Dog,ResPublica,Webdings,RuttenSpya,Constantia,Zamboni Joe Expanded,JaggaPoint,OCEAN,Liquidism part 2,Volt,QTHowardType,Raketta From Mars,STCaiyun,Agency FB,Goudy Stout,Raleigh Md BT,HanWangHeiHeavy,SF Cartoonist Hand,Groovalicious Tweak,Macedo,SF Theramin Gothic Condensed,Bauhaus 93,NudE,KabinConMedDB,GhostBayou,Vox-Slanted,Franklin Gothic Book,Justinian,STSong,Under attack skew,Electric Pickle,u26fog,stillframes,Freestyle Script,Bearpaw,Hot Rod Gang BV,HoratioDMed,MS Outlook,Napapiiri,Mistral,Back to Bay 6,KidTYPEPaint,Elephant,HanWangYanKai,Alba,Estrangelo Edessa,Xefus,Macaroni,Warlords,Script MT Bold,Arabic Transparent,VA Pe DB,Eight Track program 3,JackInput,Microsoft Sans Serif,VTC NightOfTheDeadCorruptCaps,Hacknslash,Sad Jane,Retsuc,NimbusSanTLig,Rokford,Iphegeniaâ„¢,Nine Lives,Office,Noel,Nestor,Rose,Gill Sans MT Ext Condensed Bold,Showcard Gothic,After Shok,WaldauDB,Franklin Gothic Demi Cond,Ghouly Solid,Notation Heavy JL,Reynard Demo,screenfox9,Faktos-Mirror,Random Voter,Tanne DB,Copperplate Gothic Bold,Nebullium,GF Ordner Normal,Umbles,Forte,UNCONFORM,Qirof,Nocker,Off Kilter R (BRK),OCR A Extended,SURROUNDED large,Starlight Sans JL,Radonator Anorexia,Gilgongo Doro,District,SF Collegiate Solid,Pastor of Muppets,Gautami,LTAfroculture,Unionform,Rubber Walls,KoffeeDBol,Mangal,ScrewedSW,samarin,Rod,Cordia New,Mad scientist,Serifa Blk BT,RaveParty Hollow,National Primary,Warp 1,Intrepid ExtraBold,Parchment,Belphebe,QTOptimum,Taskeksem inflamerat,Ronda,Bookman Old Style,Castellar,Viner Hand ITC,Pussycat,Myriad Web Pro,Flower Ornaments,High Tower Text,Playbill,Chiller,Comic Sans MS,Neil,Garamond,Tarnished Halo,Misconstrued,Ghostmeat,LiquidCrystal,Riquoth,STHupo,Brush Script MT,Berthside,Yesterday DB,Insane Hours,neo-geo,Colonna MT,Oakland,Miriam Transparent,Mexacali,FrankRuehl,Edmunds,Old Oak,YanksHand,Tunga,Lunch time,Carbon Block,KabanaBook,Narcosis,Something Fishy,Xenowort,Rockwell,Niagara Solid,Independence,Split splat splodge,Rainy Days,Quorum Md BT,SKULL TS 2,Kabel,Hallandale Deco Bd It. Smc JL,Odd Dog,Marquee Moon,HanWangFangSongMedium,Harrington,Wait And Bleed,GENUINE,Notepad,Intramural JL,Arabic Typesetting,DFKai-SB,Nife Fiter,Xacto Blade,AngsanaUPC,Narcotix,Miriam Fixed,Splendid 66,SF Eccentric Opus,Dead World,Faktosas-Slanted,RoundestLH,Eras Demi ITC,Xmas 97,Still Time'.split(',');\n\n        //todo: change to one font in dev mode once completed with font selector\n        if (Lib.DevMode) {\n            this.m_webFontConfig = {google: {families: ['Roboto::latin']}};\n            this.m_fonts = 'Roboto'.split(',');\n        } else {\n            this.m_webFontConfig = {google: {families: ['Roboto::latin', 'Oswald::latin', 'Montserrat::latin', 'Raleway::latin', 'Ubuntu::latin', 'Lora::latin', 'Merriweather::latin', 'Arimo::latin', 'Bitter::latin', 'Lobster::latin', 'Dosis::latin', 'Cabin::latin', 'Arvo::latin', 'Abel::latin', 'Inconsolata::latin', 'Signika::latin', 'Pacifico::latin', 'Alegreya::latin', 'Orbitron::latin', 'Anton::latin', 'Quicksand::latin', 'Exo::latin', 'Bangers::latin', 'Chewy::latin', 'Philosopher::latin', 'Righteous::latin', 'Playball::latin', 'Courgette::latin', 'Cinzel::latin', 'Satisfy::latin', 'Amaranth::latin', 'Handlee::latin', 'ABeeZee::latin', 'Tangerine::latin', 'Cookie::latin', 'Limelight::latin', 'Damion::latin', 'Niconne::latin', 'Basic::latin', 'Acme::latin', 'Ultra::latin', 'Alice::latin', 'Overlock::latin', 'Rancho::latin', 'Boogaloo::latin', 'Yellowtail::latin', 'Aclonica::latin', 'Unkempt::latin', 'Gruppo::latin', 'Belleza::latin', 'Allan::latin', 'Capriola::latin', 'Lemon::latin', 'Graduate::latin', 'Rye::latin', 'Baumans::latin', 'Italianno::latin', 'Merienda::latin', 'Englebert::latin', 'Metamorphous::latin', 'Shojumaru::latin', 'Meddon::latin', 'Sniglet::latin', 'Kavoon::latin', 'Sofia::latin', 'Gabriela::latin', 'Aladin::latin', 'Dorsa::latin', 'Redressed::latin', 'Condiment::latin', 'Quintessential::latin', 'Sail::latin', 'Bilbo::latin', 'Stoke::latin', 'Milonga::latin', 'Galindo::latin', 'Offside::latin', 'Fondamento::latin', 'Wellfleet::latin', 'Kenia::latin', 'Chango::latin', 'Julee::latin', 'Astloch::latin', 'Griffy::latin', 'Elsie::latin', 'Miniver::latin', 'Ribeye::latin', 'Piedra::latin', 'Smythe::latin', 'Trochut::latin', 'Ruthie::latin', 'Iceberg::latin', 'Lancelot::latin', 'Devonshire::latin', 'Combo::latin', 'Peralta::latin', 'Sarpanch::latin', 'Akronim::latin']}};\n            this.m_fonts = 'Roboto,Oswald,Montserrat,Raleway,Ubuntu,Lora,Merriweather,Arimo,Bitter,Lobster,Dosis,Cabin,Arvo,Abel,Inconsolata,Signika,Pacifico,Alegreya,Orbitron,Anton,Quicksand,Exo,Bangers,Chewy,Philosopher,Righteous,Playball,Courgette,Cinzel,Satisfy,Amaranth,Handlee,ABeeZee,Tangerine,Cookie,Limelight,Damion,Niconne,Basic,Acme,Ultra,Alice,Overlock,Rancho,Boogaloo,Yellowtail,Aclonica,Unkempt,Gruppo,Belleza,Allan,Capriola,Lemon,Graduate,Rye,Baumans,Italianno,Merienda,Englebert,Metamorphous,Shojumaru,Meddon,Sniglet,Kavoon,Sofia,Gabriela,Aladin,Dorsa,Redressed,Condiment,Quintessential,Sail,Bilbo,Stoke,Milonga,Galindo,Offside,Fondamento,Wellfleet,Kenia,Chango,Julee,Astloch,Griffy,Elsie,Miniver,Ribeye,Piedra,Smythe,Trochut,Ruthie,Iceberg,Lancelot,Devonshire,Combo,Peralta,Sarpanch,Akronim'.split(',');\n        }\n        this.m_webFontConfig = {google: {families: ['Roboto::latin', 'Oswald::latin', 'Montserrat::latin', 'Raleway::latin', 'Ubuntu::latin', 'Lora::latin', 'Merriweather::latin', 'Arimo::latin', 'Bitter::latin', 'Lobster::latin', 'Dosis::latin', 'Cabin::latin', 'Arvo::latin', 'Abel::latin', 'Inconsolata::latin', 'Signika::latin', 'Pacifico::latin', 'Alegreya::latin', 'Orbitron::latin', 'Anton::latin', 'Quicksand::latin', 'Exo::latin', 'Bangers::latin', 'Chewy::latin', 'Philosopher::latin', 'Righteous::latin', 'Playball::latin', 'Courgette::latin', 'Cinzel::latin', 'Satisfy::latin', 'Amaranth::latin', 'Handlee::latin', 'ABeeZee::latin', 'Tangerine::latin', 'Cookie::latin', 'Limelight::latin', 'Damion::latin', 'Niconne::latin', 'Basic::latin', 'Acme::latin', 'Ultra::latin', 'Alice::latin', 'Overlock::latin', 'Rancho::latin', 'Boogaloo::latin', 'Yellowtail::latin', 'Aclonica::latin', 'Unkempt::latin', 'Gruppo::latin', 'Belleza::latin', 'Allan::latin', 'Capriola::latin', 'Lemon::latin', 'Graduate::latin', 'Rye::latin', 'Baumans::latin', 'Italianno::latin', 'Merienda::latin', 'Englebert::latin', 'Metamorphous::latin', 'Shojumaru::latin', 'Meddon::latin', 'Sniglet::latin', 'Kavoon::latin', 'Sofia::latin', 'Gabriela::latin', 'Aladin::latin', 'Dorsa::latin', 'Redressed::latin', 'Condiment::latin', 'Quintessential::latin', 'Sail::latin', 'Bilbo::latin', 'Stoke::latin', 'Milonga::latin', 'Galindo::latin', 'Offside::latin', 'Fondamento::latin', 'Wellfleet::latin', 'Kenia::latin', 'Chango::latin', 'Julee::latin', 'Astloch::latin', 'Griffy::latin', 'Elsie::latin', 'Miniver::latin', 'Ribeye::latin', 'Piedra::latin', 'Smythe::latin', 'Trochut::latin', 'Ruthie::latin', 'Iceberg::latin', 'Lancelot::latin', 'Devonshire::latin', 'Combo::latin', 'Peralta::latin', 'Sarpanch::latin', 'Akronim::latin']}};\n        this.m_fonts = 'Roboto,Oswald,Montserrat,Raleway,Ubuntu,Lora,Merriweather,Arimo,Bitter,Lobster,Dosis,Cabin,Arvo,Abel,Inconsolata,Signika,Pacifico,Alegreya,Orbitron,Anton,Quicksand,Exo,Bangers,Chewy,Philosopher,Righteous,Playball,Courgette,Cinzel,Satisfy,Amaranth,Handlee,ABeeZee,Tangerine,Cookie,Limelight,Damion,Niconne,Basic,Acme,Ultra,Alice,Overlock,Rancho,Boogaloo,Yellowtail,Aclonica,Unkempt,Gruppo,Belleza,Allan,Capriola,Lemon,Graduate,Rye,Baumans,Italianno,Merienda,Englebert,Metamorphous,Shojumaru,Meddon,Sniglet,Kavoon,Sofia,Gabriela,Aladin,Dorsa,Redressed,Condiment,Quintessential,Sail,Bilbo,Stoke,Milonga,Galindo,Offside,Fondamento,Wellfleet,Kenia,Chango,Julee,Astloch,Griffy,Elsie,Miniver,Ribeye,Piedra,Smythe,Trochut,Ruthie,Iceberg,Lancelot,Devonshire,Combo,Peralta,Sarpanch,Akronim'.split(',');\n\n        function addGoogleFont(FontName) {\n            $(\"head\").append(\"<link href='https://fonts.googleapis.com/css?family=\" + FontName + \"' rel='stylesheet' type='text/css'>\");\n        }\n\n        for (var i = 0; i < this.m_fonts.length; i++) {\n            var family = this.m_fonts[i];\n            addGoogleFont(family);\n        }\n    }\n\n    public getFonts() {\n        return this.m_fonts;\n    }\n\n}\n\n"
  },
  {
    "path": "src/services/global-error-handler.ts",
    "content": "import {ErrorHandler, Injectable, Injector} from '@angular/core';\nimport * as moment from 'moment'\nimport * as StackTrace from 'stacktrace-js';\nimport {Lib} from \"../Lib\";\n\n@Injectable()\nexport class GlobalErrorHandler implements ErrorHandler {\n    constructor(private injector: Injector) {\n    }\n\n    handleError(error) {\n        if (Lib.DevMode()){\n            throw error;\n        }          \n\n        // const loggingService = this.injector.get(LoggingService);\n        // const location = this.injector.get(LocationStrategy);\n        // const url = location instanceof PathLocationStrategy   ? location.path() : '';\n        var message = error.message ? error.message : error.toString();\n        var url = 'https://secure.digitalsignage.com/stacktrace/';\n\n        // get the stack trace, lets grab the last 10 stacks only\n        StackTrace.fromError(error).then(stackframes => {\n            const stackString = stackframes\n                .splice(0, 20)\n                .map(function (sf) {\n                    return sf.toString();\n                }).join('\\n');\n            var date = moment().format('YYYY-MM-DD h:mm:ss');\n            message = `error :: business :: ${window['business_id']} :: studiolite :: ${date} :: ${message}`\n            StackTrace.report(stackString, url, message);\n        });\n        throw error;\n    }\n\n}"
  },
  {
    "path": "src/services/redpepper.service.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {Observable} from \"rxjs\";\nimport {IDataBaseManager, ILoadManager, IPepperAuthReply, IPepperConnection} from \"../store/imsdb.interfaces\";\nimport * as MsdbModels from \"../store/imsdb.interfaces_auto\";\nimport {ISDK, PlayerDataModel, TableNames} from \"../store/imsdb.interfaces_auto\";\nimport * as MsdbModelsExtended from \"../store/model/msdb-models-extended\";\nimport {StoreModel} from \"../store/model/StoreModel\";\nimport {List} from \"immutable\";\nimport {ACTION_INJECT_SDK} from \"../store/actions/appdb.actions\";\nimport {Store} from \"@ngrx/store\";\nimport {ApplicationState} from \"../store/application.state\";\nimport * as _ from \"lodash\";\nimport {NgmslibService} from \"ng-mslib\";\nimport {IAddContents} from \"../interfaces/IAddContent\";\nimport {BlockLabels, PLACEMENT_CHANNEL} from \"../interfaces/Consts\";\nimport * as X2JS from \"x2js\";\nimport {BlockService} from \"../app/blocks/block-service\";\nimport {Lib} from \"../Lib\";\n\n//// import X2JS from \"x2js\";\n//// import \"x2js\";\n\nexport interface IPepperUserData {\n    userName: string;\n    userPass: string;\n    domain: string;\n    businessID: number;\n    eri: string;\n    authTime: string;\n    whiteLabel: boolean;\n    resellerName: string;\n    resellerID: number;\n    components: any;\n}\n\n\nvar parser: any = new X2JS({\n    escapeMode: true,\n    attributePrefix: \"_\",\n    arrayAccessForm: \"none\",\n    emptyNodeForm: \"text\",\n    enableToStringFunc: true,\n    arrayAccessFormPaths: [],\n    skipEmptyTextNodesForObj: true\n});\n\nexport type redpepperTables = {\n    tables: ISDK\n    tableNames: Array<string>;\n}\n\n@Injectable()\nexport class RedPepperService {\n\n    constructor(private store: Store<ApplicationState>, private ngmslibService: NgmslibService) {\n    }\n\n    private m_tablesPendingToProcess: Array<any> = [];\n    private m_loaderManager: ILoadManager;\n    private m_tempScenePlayerIDs: any;\n    private databaseManager: IDataBaseManager;\n\n    private m_authenticated = false;\n    private m_domain;\n    private m_whiteLabel;\n    private m_userName;\n    private m_userPassword;\n    private m_resellerId = -1;\n    private m_resellerName = '';\n    private m_businessID = -1;\n    private m_eri = '';\n    private m_authTime;\n\n    public dbConnect(i_user, i_pass): Observable<any> {\n        var self = this;\n        return Observable.create(observer => {\n            self.m_loaderManager = new LoaderManager() as ILoadManager;\n            self.databaseManager = self.m_loaderManager.m_dataBaseManager;\n\n            self.m_loaderManager.create(i_user, i_pass, (pepperAuthReply: IPepperAuthReply) => {\n                var pepperConnection: IPepperConnection = {\n                    pepperAuthReply: pepperAuthReply,\n                    dDataBaseManager: self.databaseManager,\n                    loadManager: self.m_loaderManager,\n                }\n                observer.next(pepperConnection);\n                if (pepperAuthReply.status == true) {\n                    self.m_authenticated = true;\n                    self.m_domain = self.m_loaderManager['m_domain'];\n                    window['business_id'] = self.m_loaderManager['m_businessId'];\n                    var resellerInfo = self.m_loaderManager['m_resellerInfo'];\n                    // var resellerInfoString = (new XMLSerializer()).serializeToString(resellerInfo);\n                    self.m_userName = i_user;\n                    self.m_userPassword = i_pass;\n                    self.m_whiteLabel = parseInt($(resellerInfo).find('WhiteLabel').attr('enabled'));\n                    self.m_resellerId = parseInt($(resellerInfo).find('BusinessInfo').attr('businessId'));\n                    self.m_resellerName = $(resellerInfo).find('BusinessInfo').attr('name');\n                    self.m_businessID = self.m_loaderManager['m_businessId'];\n                    self.m_eri = self.m_loaderManager['m_eri'];\n                    self.m_authTime = Date.now();\n                }\n            });\n        })\n    }\n\n    public get loaderManager() {\n        return this.m_loaderManager;\n    }\n\n    /**\n     Save to remote server\n     @method save\n     @return none\n     **/\n    save(i_callback) {\n        this.m_loaderManager.save(i_callback);\n    }\n\n    /**\n     Sync internal sdk to remote mediaSERVER account\n     @method requestData\n     @param {Function} i_callback\n     **/\n    sync(i_callBack) {\n        this.m_loaderManager.requestData(i_callBack);\n    }\n\n    private addPendingTables(tables: Array<any>) {\n        tables.forEach(table => {\n            if (this.m_tablesPendingToProcess.indexOf(table) == -1)\n                this.m_tablesPendingToProcess.push(table);\n        });\n    }\n\n    /**\n     Return all authenticated user data\n     **/\n    getUserData(): IPepperUserData {\n        return {\n            userName: this['m_userName'],\n            userPass: this['m_userPassword'],\n            domain: this['m_domain'],\n            businessID: this['m_businessID'],\n            eri: this['m_eri'],\n            authTime: this['m_authTime'],\n            whiteLabel: this['m_whiteLabel'],\n            resellerName: this['m_resellerName'],\n            resellerID: this['m_resellerId'],\n            components: this['m_components']\n        };\n    }\n\n    private resetPendingTables() {\n        this.m_tablesPendingToProcess = [];\n    }\n\n    private capitalizeFirstLetter(string) {\n        return string.charAt(0).toUpperCase() + string.slice(1);\n    }\n\n    /**\n     * reduxCommit: this is the secret sauce that syncs the entire msdb which downloads on init\n     * to the redux store.\n     *\n     * if passed in table names, use them to sync to redux\n     * if not, try and see if any pending pendingTableSync exist, if so sync to redux\n     * if not, process the entire msdb table list to redux store\n     * if forceAll, just process all tables\n     * @param tableNameTargets\n     * @param forceAll (pass 1st arg as null and 2nd as true)\n     * @returns {redpepperTables}\n     */\n    reduxCommit(tableNameTargets?: Array<string>, forceAll?: boolean): redpepperTables {\n        var tablesNames: Array<string> = [];\n\n        if (forceAll) {\n            this.m_tablesPendingToProcess = [];\n        }\n\n        if (tableNameTargets) {\n            tablesNames = tableNameTargets;\n        } else {\n            if (this.m_tablesPendingToProcess.length > 0) {\n                tablesNames = this.m_tablesPendingToProcess;\n            } else {\n                tablesNames = TableNames;\n            }\n        }\n        tablesNames = tablesNames.map(tableName => {\n            if (tableName.indexOf('table_') > -1)  // protection against appending table_\n                return tableName.replace(/table_/, '');\n            return tableName;\n        });\n        var tableNamesTouched = {};\n        var redpepperSet: redpepperTables = {tables: null, tableNames: tablesNames};\n        var tables = {}\n        tablesNames.forEach((table, v) => {\n            var tableName = 'table_' + table;\n            var storeName = this.capitalizeFirstLetter(StringJS(table).camelize().s) + 'Model';\n            var storeModelList: List<StoreModel> = List<StoreModel>();\n            tables[tableName] = storeModelList;\n            if (this.databaseManager[tableName]().getAllPrimaryKeys().length == 0) {\n                tables[tableName] = storeModelList;\n                tableNamesTouched[tableName] = tableName;\n            } else {\n                $(this.databaseManager[tableName]().getAllPrimaryKeys()).each((k, primary_id) => {\n                    var record = this.databaseManager[tableName]().getRec(primary_id);\n                    if (record.change_type == 3)\n                        return;\n                    record.self = null;\n                    record.__proto__ = null;\n                    var newClass: StoreModel;\n                    if (MsdbModelsExtended[storeName + 'Ext']) {\n                        newClass = new MsdbModelsExtended[storeName + 'Ext'](record);\n                    } else {\n                        newClass = new MsdbModels[storeName](record);\n                    }\n                    storeModelList = storeModelList.push(newClass);\n                    tables[tableName] = storeModelList;\n                    tableNamesTouched[tableName] = tableName;\n                });\n            }\n            redpepperSet.tables = tables as any;\n            redpepperSet.tableNames = Object.keys(tableNamesTouched).map(function (key) {\n                return tableNamesTouched[key];\n            });\n        });\n        this.resetPendingTables();\n        this.store.dispatch({type: ACTION_INJECT_SDK, payload: [redpepperSet]})\n        return redpepperSet;\n    }\n\n    /**\n     Inject unique player ids for all players within a scene\n     @method injectPseudoScenePlayersIDs\n     @param {Number} i_scene_id\n     **/\n    injectPseudoScenePlayersIDs(i_scene_id?) {\n        var scenes = {};\n        if (!_.isUndefined(i_scene_id)) {\n            var domPlayerData = this.getScenePlayerdataDom(i_scene_id);\n            scenes[i_scene_id] = domPlayerData;\n        } else {\n            scenes = this.getScenes();\n        }\n        _.each(scenes, (domPlayerData: any, scene_id) => {\n            $(domPlayerData).find('Player').eq(0).attr('id', this.generateSceneId());\n            $(domPlayerData).find('Players').find('Player').each((i, player) => {\n                var blockID = this.generateSceneId();\n                $(player).attr('id', blockID);\n            });\n            this.setScenePlayerData(scene_id, (new XMLSerializer()).serializeToString(domPlayerData));\n        });\n    }\n\n    /**\n     set entire scene playerdata\n     @method setScenePlayerData\n     @return {Number} scene player_data id\n     **/\n    setScenePlayerData(i_scene_id, i_player_data) {\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        this.databaseManager.table_player_data().openForEdit(i_scene_id);\n        var recPlayerData = this.databaseManager.table_player_data().getRec(i_scene_id);\n        recPlayerData['player_data_value'] = i_player_data;\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Remove a scene\n     @method removeScene\n     **/\n    removeScene(i_scene_player_data_id) {\n        var i_scene_id = this.sterilizePseudoId(i_scene_player_data_id);\n        this.databaseManager.table_player_data().openForDelete(i_scene_id);\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Remove all player ids from i_domPlayerData\n     @method stripPlayersID\n     **/\n    stripPlayersID(i_domPlayerData) {\n        $(i_domPlayerData).removeAttr('id');\n        return i_domPlayerData;\n    }\n\n    /**\n     Remove specific player id (i.e.: block) from scene player_data\n     @method removeScenePlayer\n     @param {Number} i_scene_id\n     @param {Number} i_player_id\n     **/\n    removeScenePlayer(i_scene_id, i_player_data_id) {\n        console.log(i_player_data_id);\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        this.databaseManager.table_player_data().openForEdit(i_scene_id);\n        var recPlayerData = this.databaseManager.table_player_data().getRec(i_scene_id);\n        var player_data = recPlayerData['player_data_value'];\n        var domPlayerData = $.parseXML(player_data)\n        $(domPlayerData).find('[id=\"' + i_player_data_id + '\"]').remove();\n        this.setScenePlayerData(i_scene_id, (new XMLSerializer()).serializeToString(domPlayerData));\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     append scene player block to pepper player_data table\n     @method appendScenePlayerBlock\n     @param {Number} i_scene_id\n     @param {XML} i_player_data\n     **/\n    appendScenePlayerBlock(i_scene_id, i_player_data) {\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        this.databaseManager.table_player_data().openForEdit(i_scene_id);\n        var recPlayerData = this.databaseManager.table_player_data().getRec(i_scene_id);\n        var scene_player_data = recPlayerData['player_data_value'];\n        var sceneDomPlayerData = $.parseXML(scene_player_data);\n        var playerData: any = $.parseXML(i_player_data);\n        // use first child to overcome the removal by jXML of the HTML tag\n        $(sceneDomPlayerData).find('Players').append(playerData.firstChild);\n        // $(sceneDomPlayerData).find('Players').append($(i_player_data));\n        var player_data = this.xmlToStringIEfix(sceneDomPlayerData);\n        recPlayerData['player_data_value'] = player_data;\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     set a block id inside a scene with new player_data\n     @method setScenePlayerdataBlock\n     @param {Number} i_scene_id\n     @param {Number} i_player_data_id\n     @param {XML} player_data\n     **/\n    setScenePlayerdataBlock(i_scene_id, i_player_data_id, i_player_data) {\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        this.databaseManager.table_player_data().openForEdit(i_scene_id);\n        var recPlayerData = this.databaseManager.table_player_data().getRec(i_scene_id);\n        var player_data = recPlayerData['player_data_value'];\n        var domPlayerData = $.parseXML(player_data);\n        var playerData: any = $.parseXML(i_player_data);\n        // use first child to overcome the removal by jXML of the HTML tag\n        $(domPlayerData).find('[id=\"' + i_player_data_id + '\"]').replaceWith(playerData.firstChild);\n        player_data = this.xmlToStringIEfix(domPlayerData);\n        this.setScenePlayerData(i_scene_id, player_data);\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Create a new Scene\n     If mimetype was give as an argument and it's of format\n     Json.xxxx (i.e.: Json.weather, Json.spreadsheet ...) add it to scene table as well\n     @method createScene\n     @optional i_mimeType\n     @optional i_name\n     @return {Number} scene player_data id\n     **/\n    createScene(i_player_data, i_mimeType, i_name) {\n        var table_player_data: any = this.databaseManager.table_player_data();\n        var recPlayerData = table_player_data.createRecord();\n        if (i_mimeType && i_mimeType.match(/Json./)) {\n            i_player_data = $.parseXML(i_player_data);\n            $(i_player_data).find('Player').attr('mimeType', i_mimeType);\n            i_player_data = this.xmlToStringIEfix(i_player_data);\n        }\n        if (!_.isUndefined(i_name)) {\n            i_player_data = $.parseXML(i_player_data);\n            $(i_player_data).find('Player').attr('label', i_name);\n            i_player_data = this.xmlToStringIEfix(i_player_data);\n        }\n        recPlayerData['player_data_value'] = i_player_data;\n        table_player_data.addRecord(recPlayerData);\n        var scene_id = recPlayerData['player_data_id'];\n        this.injectPseudoScenePlayersIDs(scene_id);\n        // this.databaseManager.fire(Pepper['SCENE_CREATED'], this, null, recPlayerData['player_data_id']);\n        this.addPendingTables(['table_player_data']);\n        return this.getPseudoIdFromSceneId(scene_id);\n    }\n\n    /**\n     Translate a scene id to its matching pseudo scene id\n     @method getPseudoIdFromSceneId\n     @param {Number} i_scene_id\n     @return {Number} pseudo id\n     **/\n    getPseudoIdFromSceneId(i_scene_id) {\n        var found = undefined;\n        var scenes = this.getScenes();\n        _.each(scenes, function (domPlayerData, scene_id) {\n            var injectedID = $(domPlayerData).find('Player').eq(0).attr('id');\n            if (i_scene_id == scene_id)\n                found = injectedID;\n        });\n        return found;\n    }\n\n    /**\n     Remove all references to a scene id from within Scenes > BlockCollections that refer to that particular scene id\n     In other words, check all scenes for existing block collections, and if they refer to scene_id, remove that entry\n     @method removeSceneFromBlockCollectionWithSceneId\n     @param {Number} i_scene_id scene id to search for and remove in all scenes > BlockCollections\n     **/\n    removeSceneFromBlockCollectionInScenes(i_scene_id) {\n        $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each((k, player_data_id) => {\n            var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var currentSceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"' + BlockLabels.BLOCKCODE_COLLECTION + '\"]').each(function (i, playerDataBlockCollection) {\n                    $(playerDataBlockCollection).find('Collection').children().each(function (k, page) {\n                        var scene_id = $(page).find('Player').attr('hDataSrc');\n                        if (scene_id == i_scene_id) {\n                            $(page).remove();\n                            currentSceneID = this.sterilizePseudoId(currentSceneID);\n                            this.databaseManager.table_player_data().openForEdit(currentSceneID);\n                            var player_data = this.xmlToStringIEfix(domSceneData);\n                            recPlayerData['player_data_value'] = player_data;\n                        }\n                    });\n                });\n            });\n        });\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Remove the scene from any block collection which resides in campaign timeline channels that uses that scene in its collection list\n     @method removeSceneFromBlockCollectionsInChannels\n     @param {Number} i_scene_id\n     @return none\n     **/\n    removeSceneFromBlockCollectionsInChannels(i_scene_id) {\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var blockType = $(domPlayerData).find('Player').attr('player');\n            if (parseInt(blockType) == BlockLabels.BLOCKCODE_COLLECTION) {\n                $(domPlayerData).find('Collection').children().each((k, page) => {\n                    var scene_hDataSrc;\n                    var type = $(page).attr('type');\n                    if (type == 'scene') {\n                        scene_hDataSrc = $(page).find('Player').attr('hDataSrc');\n                        if (scene_hDataSrc == i_scene_id) {\n                            $(page).remove();\n                            var player_data = this.xmlToStringIEfix(domPlayerData)\n                            this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                            this.setCampaignTimelineChannelPlayerRecord(campaign_timeline_chanel_player_id, 'player_data', player_data);\n                        }\n                    }\n                });\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    removeSceneFromBlockLocationInScenes(i_scene_id) {\n        $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each((k, player_data_id) => {\n            var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var currentSceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"' + BlockLabels.LOCATION + '\"]').each(function (i, playerDataBlockCollection) {\n                    $(playerDataBlockCollection).find('GPS').children().each(function (k, page) {\n                        var scene_id = $(page).find('Player').attr('hDataSrc');\n                        if (scene_id == i_scene_id) {\n                            $(page).remove();\n                            currentSceneID = this.sterilizePseudoId(currentSceneID);\n                            this.databaseManager.table_player_data().openForEdit(currentSceneID);\n                            var player_data = this.xmlToStringIEfix(domSceneData);\n                            recPlayerData['player_data_value'] = player_data;\n                        }\n                    });\n                });\n            });\n        });\n        $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each((k, player_data_id) => {\n            var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var currentSceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"' + BlockLabels.LOCATION + '\"]').each(function (i, playerDataBlockCollection) {\n                    $(playerDataBlockCollection).find('Fixed').children().each(function (k, page) {\n                        var scene_id = $(page).find('Player').attr('hDataSrc');\n                        if (scene_id == i_scene_id) {\n                            $(page).remove();\n                            currentSceneID = this.sterilizePseudoId(currentSceneID);\n                            this.databaseManager.table_player_data().openForEdit(currentSceneID);\n                            var player_data = this.xmlToStringIEfix(domSceneData);\n                            recPlayerData['player_data_value'] = player_data;\n                        }\n                    });\n                });\n            });\n        });\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Remove the scene from any block collection which resides in campaign timeline channels that uses that scene in its collection list\n     @method removeSceneFromBlockCollectionsInChannels\n     @param {Number} i_scene_id\n     @return none\n     **/\n    removeSceneFromBlockLocationInChannels(i_scene_id) {\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var blockType = $(domPlayerData).find('Player').attr('player');\n            if (parseInt(blockType) == BlockLabels.LOCATION) {\n                $(domPlayerData).find('GPS').children().each((k, page) => {\n                    var scene_hDataSrc;\n                    var type = $(page).attr('type');\n                    if (type == 'scene') {\n                        scene_hDataSrc = $(page).find('Player').attr('hDataSrc');\n                        if (scene_hDataSrc == i_scene_id) {\n                            $(page).remove();\n                            var player_data = this.xmlToStringIEfix(domPlayerData)\n                            this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                            this.setCampaignTimelineChannelPlayerRecord(campaign_timeline_chanel_player_id, 'player_data', player_data);\n                        }\n                    }\n                });\n            }\n        });\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var blockType = $(domPlayerData).find('Player').attr('player');\n            if (parseInt(blockType) == BlockLabels.LOCATION) {\n                $(domPlayerData).find('Fixed').children().each((k, page) => {\n                    var scene_hDataSrc;\n                    var type = $(page).attr('type');\n                    if (type == 'scene') {\n                        scene_hDataSrc = $(page).find('Player').attr('hDataSrc');\n                        if (scene_hDataSrc == i_scene_id) {\n                            $(page).remove();\n                            var player_data = this.xmlToStringIEfix(domPlayerData)\n                            this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                            this.setCampaignTimelineChannelPlayerRecord(campaign_timeline_chanel_player_id, 'player_data', player_data);\n                        }\n                    }\n                });\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Remove blocks (a.k.a players) from all campaign timeline  channels that use the specified scene_id\n     @method removeBlocksWithSceneID\n     @param {Number} i_scene_id\n     @return none\n     **/\n    removeBlocksWithSceneID(i_scene_id) {\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var scene_id = $(domPlayerData).find('Player').attr('hDataSrc');\n            if (scene_id == i_scene_id)\n                this.removeBlockFromTimelineChannel(campaign_timeline_chanel_player_id);\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Change a viewer's (aka screen division) order (layer) z-order\n     @method updateTemplateViewerOrder\n     @param {number} i_board_template_viewer_id\n     @param {number} i_view_order\n     **/\n    updateTemplateViewerOrder(i_board_template_viewer_id, i_view_order) {\n        this.databaseManager.table_board_template_viewers().openForEdit(i_board_template_viewer_id);\n        var recEditBoardTemplateViewer = this.databaseManager.table_board_template_viewers().getRec(i_board_template_viewer_id);\n        recEditBoardTemplateViewer['viewer_order'] = i_view_order;\n        this.addPendingTables(['table_board_template_viewers']);\n    }\n\n    /**\n     Set a Board Template Viewer props\n     @method setBoardTemplateViewer\n     @param {Number} i_board_template_viewer_id\n     @return {Number} i_props\n     **/\n    setBoardTemplateViewer(i_campaign_timeline_board_template_id, i_board_template_viewer_id, i_props) {\n        var x = Math.round(i_props.x);\n        var y = Math.round(i_props.y);\n        var w = Math.round(i_props.w);\n        var h = Math.round(i_props.h);\n\n        // console.log('savings: template_id: ' + i_campaign_timeline_board_template_id + ' view_id: ' + i_board_template_viewer_id + ' ' + x + 'x' + y + ' ' + w + '/' + h);\n\n        this.databaseManager.table_board_template_viewers().openForEdit(i_board_template_viewer_id);\n        var recEditBoardTemplateViewer = this.databaseManager.table_board_template_viewers().getRec(i_board_template_viewer_id);\n        recEditBoardTemplateViewer['pixel_x'] = x;\n        recEditBoardTemplateViewer['pixel_y'] = y;\n        recEditBoardTemplateViewer['pixel_width'] = w;\n        recEditBoardTemplateViewer['pixel_height'] = h;\n        // this.announceTemplateViewerEdited(i_campaign_timeline_board_template_id);\n        this.addPendingTables(['table_board_template_viewers']);\n    }\n\n    /**\n     Remove all blocks (i.e.: players) from campaign > timeline > channel\n     @method removeBlocksFromTimelineChannel\n     @param {Number} i_block_id\n     @return none\n     **/\n    removeBlocksFromTimelineChannel(i_campaign_timeline_chanel_id) {\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            if (recCampaignTimelineChannelPlayer['campaign_timeline_chanel_id'] == i_campaign_timeline_chanel_id) {\n                var status = this.databaseManager.table_campaign_timeline_chanel_players().openForDelete(campaign_timeline_chanel_player_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Update a timeline's duration which is set as the total sum of all blocks within the longest running channel\n     @method updateTotalTimelineDuration\n     @param {Number} i_campaign_timeline_id\n     @return none\n     **/\n    updateTotalTimelineDuration(i_campaign_timeline_id): void {\n        var longestChannelDuration = 0;\n        // Get all timelines\n        $(this.databaseManager.table_campaign_timelines().getAllPrimaryKeys()).each((k, campaign_timeline_id) => {\n            if (campaign_timeline_id == i_campaign_timeline_id) {\n                // get all channels that belong to timeline\n                $(this.databaseManager.table_campaign_timeline_chanels().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_id) => {\n                    var recCampaignTimelineChannel = this.databaseManager.table_campaign_timeline_chanels().getRec(campaign_timeline_chanel_id);\n                    if (campaign_timeline_id == recCampaignTimelineChannel['campaign_timeline_id']) {\n                        var timelineDuration = 0;\n                        // get all players / resources that belong timeline\n                        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n                            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n                            if (campaign_timeline_chanel_id == recCampaignTimelineChannelPlayer['campaign_timeline_chanel_id']) {\n                                // console.log(campaign_timeline_chanel_player_id + ' ' + recCampaignTimelineChannelPlayer['player_duration']);\n                                timelineDuration += parseFloat(recCampaignTimelineChannelPlayer['player_duration']);\n                                if (timelineDuration > longestChannelDuration)\n                                    longestChannelDuration = timelineDuration;\n                            }\n                        });\n                    }\n                });\n            }\n        });\n        this.setCampaignTimelineRecord(i_campaign_timeline_id, 'timeline_duration', longestChannelDuration);\n        this.addPendingTables(['table_campaign_timelines', 'table_campaign_timeline_chanels', 'table_campaign_timeline_chanel_players']);\n    }\n\n\n    /**\n     Update a timeline's duration which is set as the total sum of all blocks within the longest running channel\n     @method updateTotalTimelineDuration\n     @param {Number} i_campaign_timeline_id\n     @return none\n     **/\n    getGlobalBoardFromCampaignId(i_campaign_id) {\n        var res;\n        _.find(this.databaseManager.table_campaign_boards().getAllPrimaryKeys(), (campaign_board_id) => {\n            var recCampaignTimeline = this.databaseManager.table_campaign_boards().getRec(campaign_board_id);\n            if (recCampaignTimeline.campaign_id == i_campaign_id) {\n                var board_id = recCampaignTimeline['board_id']\n                res = this.databaseManager.table_boards().getRec(board_id);\n            }\n        });\n        return res;\n    }\n\n    /**\n     Remove the association between the screen division (aka viewer) and all channels that are assigned with that viewer\n     @method removeTimelineBoardViewerChannel\n     @param {Number} i_campaign_timeline_board_template_id\n     @return {Number} return the channel that was de-associated with viewer\n     **/\n    removeTimelineBoardViewerChannel(i_board_template_viewer_id) {\n        var campaign_timeline_chanel_id = -1;\n        $(this.databaseManager.table_campaign_timeline_board_viewer_chanels().getAllPrimaryKeys()).each((k, campaign_timeline_board_viewer_chanel_id) => {\n            var recCampaignTimelineViewerChanels = this.databaseManager.table_campaign_timeline_board_viewer_chanels().getRec(campaign_timeline_board_viewer_chanel_id);\n            if (recCampaignTimelineViewerChanels['board_template_viewer_id'] == i_board_template_viewer_id) {\n                campaign_timeline_chanel_id = recCampaignTimelineViewerChanels['campaign_timeline_chanel_id'];\n                this.databaseManager.table_campaign_timeline_board_viewer_chanels().openForDelete(campaign_timeline_board_viewer_chanel_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_board_viewer_chanels']);\n        return campaign_timeline_chanel_id;\n    }\n\n    /**\n     Remove board template viewer\n     @method removeBoardTemplateViewer\n     @param {Number} i_board_template_id\n     @param {Number} i_board_template_viewer_id\n     **/\n    removeBoardTemplateViewer(i_board_template_id, i_board_template_viewer_id) {\n        this.databaseManager.table_board_template_viewers().openForDelete(i_board_template_viewer_id);\n        this.addPendingTables(['table_board_template_viewers']);\n    }\n\n    /**\n     Assign viewer (screen division) on the timeline to channel\n     @method assignViewerToTimelineChannel\n     @param {Number} i_campaign_timeline_board_template_id\n     @param {Object} i_viewers a json object with all viewers\n     @param {Array} i_channels a json object with all channels\n     @return none\n     **/\n    assignViewerToTimelineChannel(i_campaign_timeline_board_template_id, i_viewer_id, i_channel_id) {\n        var viewerChanels: any = this.databaseManager.table_campaign_timeline_board_viewer_chanels();\n        var viewerChanel = viewerChanels.createRecord();\n        viewerChanel.campaign_timeline_board_template_id = i_campaign_timeline_board_template_id;\n        viewerChanel.board_template_viewer_id = i_viewer_id;\n        viewerChanel.campaign_timeline_chanel_id = i_channel_id;\n        viewerChanels.addRecord(viewerChanel);\n        this.addPendingTables(['table_campaign_timeline_board_viewer_chanels']);\n    }\n\n    /**\n     Remove a channel from a timeline\n     @method removeChannelFromTimeline\n     @param {Number} i_channel_id\n     @return {Boolean} status\n     **/\n    removeChannelFromTimeline(i_channel_id): number {\n        this.addPendingTables(['table_campaign_timeline_chanels']);\n        return this.databaseManager.table_campaign_timeline_chanels().openForDelete(i_channel_id);\n    }\n\n    /**\n     Create a new campaign in the local database\n     @method createCampaign\n     @param {Number} i_campaginName\n     @return {Number} campaign id created\n     **/\n    createCampaign(i_campaignName): number {\n        var campaigns = this.databaseManager.table_campaigns();\n        var campaign = campaigns.createRecord();\n        campaign.campaign_name = i_campaignName;\n        campaigns.addRecord(campaign, undefined);\n        this.addPendingTables(['campaigns']);\n        return campaign.campaign_id;\n    }\n\n    //todo: finish process\n    createCampaignEntire(screenProps: {}, campaignName: string, resolution: string): number {\n\n        if (campaignName == '')\n            campaignName = 'new campaign';\n\n        var w = resolution.split('x')[0]\n        var h = resolution.split('x')[1]\n        var board_id = this.createBoard('my board', w, h);\n        var newTemplateData = this.createNewTemplate(board_id, screenProps);\n        var board_template_id = newTemplateData['board_template_id']\n        var viewers = newTemplateData['viewers'];\n        var m_selected_campaign_id = this.createCampaign('campaign');\n        var campaign_board_id = this.assignCampaignToBoard(m_selected_campaign_id, board_id);\n        this.setCampaignRecord(m_selected_campaign_id, 'campaign_name', campaignName);\n        var campaign_timeline_id = this.createNewTimeline(m_selected_campaign_id);\n        this.setCampaignTimelineSequencerIndex(m_selected_campaign_id, campaign_timeline_id, 0);\n        this.setTimelineTotalDuration(campaign_timeline_id, '0');\n        this.createCampaignTimelineScheduler(m_selected_campaign_id, campaign_timeline_id);\n        var campaign_timeline_board_template_id = this.assignTemplateToTimeline(campaign_timeline_id, board_template_id, campaign_board_id);\n        var channels = this.createTimelineChannels(campaign_timeline_id, viewers);\n        this.assignViewersToTimelineChannels(campaign_timeline_board_template_id, viewers, channels);\n        this.reduxCommit();\n        return m_selected_campaign_id;\n    }\n\n    /**\n     Create channel and assign that channel to the specified timeline\n     @method createTimelineChannel\n     @param {Number} i_campaign_timeline_id the timeline id to assign channel to\n     @return {Array} createdChanels array of channel ids created\n     **/\n    createTimelineChannel(i_campaign_timeline_id) {\n        var chanels: any = this.databaseManager.table_campaign_timeline_chanels();\n        var chanel = chanels.createRecord();\n        chanel.chanel_name = \"CH\";\n        chanel.campaign_timeline_id = i_campaign_timeline_id;\n        chanels.addRecord(chanel);\n        // this.databaseManager.fire(Pepper['NEW_CHANNEL_ADDED'], this, null, {\n        //     chanel: chanel['campaign_timeline_chanel_id'],\n        //     campaign_timeline_id: i_campaign_timeline_id\n        // });\n        this.addPendingTables(['table_campaign_timeline_chanels']);\n        return chanel['campaign_timeline_chanel_id'];\n    }\n\n    renameCampaign(i_campaignId, i_newCampaignName): void {\n        this.setCampaignRecord(i_campaignId, 'campaign_name', i_newCampaignName)\n        this.addPendingTables(['campaigns']);\n    }\n\n    /**\n     Create a global viewer in an existing board_template\n     @method createViewer\n     @param {Number} board_template_id\n     @param {Number} i_board_template_id\n     @param {Object} i_props\n     @return {Number} viewer id\n     **/\n    createViewer(i_board_template_id, i_props) {\n        var viewers: any = this.databaseManager.table_board_template_viewers();\n        var viewer = viewers.createRecord();\n        viewer.viewer_name = \"Viewer\";\n        viewer.pixel_width = i_props['w'];\n        viewer.pixel_height = i_props['h'];\n        viewer.pixel_x = i_props['x'];\n        viewer.pixel_y = i_props['y'];\n        viewer.board_template_id = i_board_template_id;\n        viewers.addRecord(viewer);\n        this.addPendingTables(['table_board_template_viewers']);\n        return viewer['board_template_viewer_id'];\n    }\n\n    /**\n     Create a new board, also known as Screen (screen divisions reside inside the board as viewers)\n     @method createBoard\n     @param {Number} i_boardName\n     @param {Number} i_width of the board\n     @param {Number} i_height of the board\n     @return {Number} the board id\n     **/\n    createBoard(i_boardName, i_width, i_height): number {\n        var boards = this.databaseManager.table_boards();\n        var board = boards.createRecord();\n        board.board_name = i_boardName;\n        board.board_pixel_width = i_width;\n        board.board_pixel_height = i_height;\n        boards.addRecord(board, undefined);\n        this.addPendingTables(['table_boards']);\n        return board['board_id'];\n    }\n\n    /**\n     Create a new global template (screen and viewers) and assign the new template to the given global board_id\n     @method createNewTemplate\n     @param {Number} i_board_id\n     @param {Object} i_screenProps json object with all the viewers and attributes to create in msdb\n     @return {Object} returnData encapsulates the board_template_id and board_template_viewer_ids created\n     **/\n    createNewTemplate(i_board_id, i_screenProps): any {\n        var returnData = {\n            board_template_id: -1,\n            viewers: []\n        };\n        // create screen template under board_id\n        var boardTemplates = this.databaseManager.table_board_templates();\n        var boardTemplate = boardTemplates.createRecord();\n        boardTemplate.template_name = \"board template\";\n        boardTemplate.board_id = i_board_id; // bind screen template to board\n        boardTemplates.addRecord(boardTemplate, undefined);\n\n        var board_template_id = boardTemplate['board_template_id'];\n\n        // add viewers (screen divisions)\n        var viewers = this.databaseManager.table_board_template_viewers();\n        var i = 0;\n        for (var screenValues in i_screenProps) {\n            i++;\n            var viewer = viewers.createRecord();\n            viewer.viewer_name = \"Viewer\" + i;\n            viewer.pixel_width = i_screenProps[screenValues]['w'];\n            viewer.pixel_height = i_screenProps[screenValues]['h'];\n            viewer.pixel_x = i_screenProps[screenValues]['x'];\n            viewer.pixel_y = i_screenProps[screenValues]['y'];\n            viewer.board_template_id = boardTemplate.board_template_id; // bind screen division to screen template\n            viewers.addRecord(viewer, undefined);\n            returnData['viewers'].push(viewer['board_template_viewer_id']);\n        }\n        returnData['board_template_id'] = board_template_id\n        this.addPendingTables(['table_board_templates', 'table_board_template_viewers']);\n        return returnData;\n    }\n\n    /**\n     Check that every timeline within a campaign has a scheduler table entry, if not, create one with default values\n     @method checkAndCreateCampaignTimelineScheduler\n     @param {Number} i_campaign_id\n     @return none\n     **/\n    checkAndCreateCampaignTimelineScheduler(i_campaign_id) {\n        $(this.databaseManager.table_campaign_timelines().getAllPrimaryKeys()).each((k, campaign_timeline_id) => {\n            var recCampaignTimeline = this.databaseManager.table_campaign_timelines().getRec(campaign_timeline_id);\n\n            // if found a one timeline that belongs to i_campaign_id\n            if (recCampaignTimeline['campaign_id'] == i_campaign_id) {\n                var schedulerFound = 0;\n                $(this.databaseManager.table_campaign_timeline_schedules().getAllPrimaryKeys()).each((k, campaign_timeline_schedule_id) => {\n                    var recCampaignTimelineSchedule = this.databaseManager.table_campaign_timeline_schedules().getRec(campaign_timeline_schedule_id);\n                    if (recCampaignTimelineSchedule.campaign_timeline_id == campaign_timeline_id)\n                        schedulerFound = 1;\n                });\n                if (!schedulerFound)\n                    this.createCampaignTimelineScheduler(i_campaign_id, campaign_timeline_id);\n            }\n        });\n    }\n\n    /**\n     Returns all scenes\n     @method getSceneMime\n     @param {Number} i_sceneID\n     @return {Object} scene names\n     **/\n    getSceneMime(i_sceneID) {\n        var mimeType = '';\n        $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each((k, player_data_id) => {\n            var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n            var domPlayerData = $.parseXML(recPlayerData['player_data_value'])\n            var id = $(domPlayerData).find('Player').attr('id');\n            if (id == i_sceneID)\n                mimeType = $(domPlayerData).find('Player').attr('mimeType');\n        });\n        return mimeType;\n    }\n\n    /**\n     Set a campaign table record for the specified i_campaign_id.\n     The method uses generic key / value fields so it can set any part of the record.\n     @method setCampaignRecord\n     @param {Number} i_campaign_id\n     @param {Object} i_key\n     @param {String} i_value\n     @return {Object} foundCampaignRecord\n     **/\n    setCampaignRecord(i_campaign_id, i_key, i_value): void {\n        var value = this.ngmslibService.cleanCharForXml(i_value);\n        this.databaseManager.table_campaigns().openForEdit(i_campaign_id);\n        var recCampaign = this.databaseManager.table_campaigns().getRec(i_campaign_id);\n        recCampaign[i_key] = value;\n        this.addPendingTables(['table_campaigns']);\n    }\n\n    /**\n     Assign a campaign to a board, binding the to by referenced ids\n     @method assignCampaignToBoard\n     @param {Number} i_campaign_id the campaign id to assign to board\n     @param {Number} i_board_id the board id to assign to campaign\n     @return {Number} campain_board_id\n     **/\n    assignCampaignToBoard(i_campaign_id, i_board_id): number {\n        var campaign_boards = this.databaseManager.table_campaign_boards();\n        var campain_board = campaign_boards.createRecord();\n        campain_board.campaign_id = i_campaign_id;\n        campain_board.board_id = i_board_id;\n        campaign_boards.addRecord(campain_board, undefined);\n        this.addPendingTables(['table_campaign_boards']);\n        return campain_board['campaign_board_id']\n    }\n\n    /**\n     Set a resource record via its resource_id.\n     The method uses generic key / value fields so it can set any part of the record.\n     @method setResourceRecord\n     @param {Number} i_resource_id\n     @param {Number} i_key\n     @param {String} i_value\n     @return {Object} foundResourceRecord\n     **/\n    setResourceRecord(i_resource_id, i_key, i_value) {\n        this.databaseManager.table_resources().openForEdit(i_resource_id);\n        var recResource = this.databaseManager.table_resources().getRec(i_resource_id);\n        recResource[i_key] = i_value;\n        this.addPendingTables(['table_resources']);\n    }\n\n    /**\n     Set a channel_id record in channels table using key and value\n     The method uses generic key / value fields so it can set any part of the record.\n     @method setCampaignTimelineChannelRecord\n     @param {Number} i_channel_id\n     @param {Number} i_key\n     @param {String} i_value\n     @return none\n     **/\n    setCampaignTimelineChannelRecord(i_channel_id, i_key, i_value) {\n        this.databaseManager.table_campaign_timeline_chanels().openForEdit(i_channel_id);\n        var recChannel = this.databaseManager.table_campaign_timeline_chanels().getRec(i_channel_id);\n        recChannel[i_key] = i_value;\n    }\n\n    /**\n     Create a new timeline under the specified campaign_id\n     @method createNewTimeline\n     @param {Number} i_campaign_id\n     @return {Number} campaign_timeline_id the timeline id created\n     **/\n    createNewTimeline(i_campaign_id): number {\n        var timelines = this.databaseManager.table_campaign_timelines();\n        var timeline = timelines.createRecord();\n        timeline.campaign_id = i_campaign_id;\n        timeline.timeline_name = \"Timeline\";\n        timelines.addRecord(timeline, undefined);\n        this.addPendingTables(['table_campaign_timelines']);\n        return timeline['campaign_timeline_id'];\n    }\n\n    /**\n     Set the sequence index of a timeline in campaign. If timeline is not found in sequencer, we insert it with the supplied i_sequenceIndex\n     @method setCampaignTimelineSequencerIndex\n     @param {Number} i_campaign_id\n     @param {Number} i_campaign_timeline_id\n     @param {Number} i_sequenceIndex is the index to use for the timeline so we can playback the timeline in the specified index order\n     @return none\n     **/\n    setCampaignTimelineSequencerIndex(i_campaign_id, i_campaign_timeline_id, i_sequenceIndex): void {\n        var updatedSequence = false;\n        $(this.databaseManager.table_campaign_timeline_sequences().getAllPrimaryKeys()).each((k, campaign_timeline_sequence_id) => {\n            var recCampaignTimelineSequence = this.databaseManager.table_campaign_timeline_sequences().getRec(campaign_timeline_sequence_id);\n            if (recCampaignTimelineSequence.campaign_timeline_id == i_campaign_timeline_id) {\n                this.databaseManager.table_campaign_timeline_sequences().openForEdit(campaign_timeline_sequence_id);\n                var recEditCampaignTimelineSequence = this.databaseManager.table_campaign_timeline_sequences().getRec(campaign_timeline_sequence_id);\n                recEditCampaignTimelineSequence.sequence_index = i_sequenceIndex;\n                recEditCampaignTimelineSequence.sequence_count = 0;\n                updatedSequence = true;\n            }\n        });\n\n        // i_campaign_timeline_id was not found in the sequencer so create new record\n        if (updatedSequence == false) {\n            var table_campaign_timeline_sequences = this.databaseManager.table_campaign_timeline_sequences();\n            var recCampaignTimelineSequence = table_campaign_timeline_sequences.createRecord();\n            recCampaignTimelineSequence.sequence_index = i_sequenceIndex;\n            recCampaignTimelineSequence.sequence_count = 0;\n            recCampaignTimelineSequence.campaign_timeline_id = i_campaign_timeline_id;\n            recCampaignTimelineSequence.campaign_id = i_campaign_id;\n            table_campaign_timeline_sequences.addRecord(recCampaignTimelineSequence, undefined);\n        }\n        this.addPendingTables(['table_campaign_timeline_sequences']);\n    }\n\n    /**\n     get a scene block playerdata\n     @method getScenePlayerdataBlock\n     @param {Number} i_scene_id\n     @param {Number} i_player_data_id\n     @return {Number} i_player_data_id\n     **/\n    getScenePlayerdataBlock(i_scene_id, i_player_data_id) {\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        // this.databaseManager.table_player_data().openForEdit(i_scene_id);\n        var recPlayerData = this.databaseManager.table_player_data().getRec(i_scene_id);\n        var player_data = recPlayerData['player_data_value'];\n        var domPlayerData = $.parseXML(player_data)\n        var foundSnippet = $(domPlayerData).find('[id=\"' + i_player_data_id + '\"]');\n        return foundSnippet[0];\n    }\n\n    /**\n     Assign viewers (screen divisions) on the timeline to channels, so we get one viewer per channel\n     @method assignViewersToTimelineChannels\n     @param {Number} i_campaign_timeline_board_template_id\n     @param {Object} i_viewers a json object with all viewers\n     @param {Array} i_channels a json object with all channels\n     @return none\n     **/\n    assignViewersToTimelineChannels(i_campaign_timeline_board_template_id, i_viewers, i_channels): void {\n        var viewerChanels = this.databaseManager.table_campaign_timeline_board_viewer_chanels();\n        for (var i in i_viewers) {\n            var viewerChanel = viewerChanels.createRecord();\n            viewerChanel.campaign_timeline_board_template_id = i_campaign_timeline_board_template_id;\n            viewerChanel.board_template_viewer_id = i_viewers[i];\n            viewerChanel.campaign_timeline_chanel_id = i_channels.shift();\n            viewerChanels.addRecord(viewerChanel, undefined);\n        }\n        this.addPendingTables(['table_campaign_timeline_board_viewer_chanels']);\n    }\n\n    /**\n     Create a campaign timelime scheduler record for new timeline\n     @method createCampaignTimelineScheduler\n     @param {Number} i_campaign_id\n     @param {Number} i_campaign_timeline_id\n     @return none\n     **/\n    createCampaignTimelineScheduler(i_campaign_id, i_campaign_timeline_id): void {\n        var startDate = new Date();\n        var endDate = new Date();\n        endDate.setDate(endDate.getDate() + 30);\n        var dateStart = startDate.getMonth() + 1 + '/' + startDate.getDate() + '/' + startDate.getFullYear() + ' 12:00 AM';\n        var dateEnd = endDate.getMonth() + 1 + '/' + endDate.getDate() + '/' + endDate.getFullYear() + ' 12:00 AM';\n        var table_campaign_timeline_schedules = this.databaseManager.table_campaign_timeline_schedules();\n        var recCampaignTimelineSchedules = table_campaign_timeline_schedules.createRecord();\n        recCampaignTimelineSchedules.campaign_timeline_id = i_campaign_timeline_id;\n        recCampaignTimelineSchedules.custom_duration = 'True';\n        recCampaignTimelineSchedules.duration = 3600;\n        recCampaignTimelineSchedules.repeat_type = 1;\n        recCampaignTimelineSchedules.week_days = 127;\n        recCampaignTimelineSchedules.conflict = false;\n        recCampaignTimelineSchedules.pattern_name = 'pattern';\n        recCampaignTimelineSchedules.priority = 1;\n        recCampaignTimelineSchedules.start_date = dateStart;\n        recCampaignTimelineSchedules.end_date = dateEnd;\n        table_campaign_timeline_schedules.addRecord(recCampaignTimelineSchedules, undefined);\n        this.addPendingTables(['table_campaign_timeline_schedules']);\n    }\n\n    /**\n     Returns all of the campaign IDs that all stations belonging to account are associated with\n     @method getStationCampaignIDs\n     @return {Array} array of campaign IDs\n     **/\n    getStationCampaignIDs() {\n        var campaignIDs = [];\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each((k, branch_station_id) => {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            var campaign_board_id = recBranchStation['campaign_board_id'];\n            campaignIDs.push(this.getCampaignIdFromCampaignBoardId(campaign_board_id));\n        });\n        return campaignIDs;\n    }\n\n    /**\n     Get a list of all campaigns per the account\n     @method getCampaignIDs\n     @return {Array} campaigns\n     **/\n    getCampaignIDs(): Array<number> {\n        var campaignsIds = [];\n        $(this.databaseManager.table_campaigns().getAllPrimaryKeys()).each((k, campaign_id) => {\n            campaignsIds.push(campaign_id);\n        });\n        return campaignsIds;\n    }\n\n    /**\n     Translate an injected id to a table_player_data scene id\n     @method createPseudoSceneID\n     @param {Number} getSceneIdFromPseudoId\n     @return {Number} scene id\n     **/\n    getSceneIdFromPseudoId(i_pseudo_id) {\n        var found = undefined;\n        var scenes = this.getScenes();\n        _.each(scenes, (domPlayerData, scene_id) => {\n            var pseudo_id = $(domPlayerData).find('Player').eq(0).attr('id');\n            if (pseudo_id == i_pseudo_id)\n                found = scene_id;\n        });\n        return found;\n    }\n\n    /**\n     Returns all scenes\n     @method getSceneMime\n     @param {Number} i_sceneID\n     @return {Object} scene names\n     **/\n    getSceneMimeType(i_sceneID, i_playerDataModels: List<PlayerDataModel>): string {\n        var found = i_playerDataModels.find((i_playerDataModel: PlayerDataModel) => {\n            var domPlayerData = i_playerDataModel.getPlayerDataValue();\n            return i_sceneID == jXML(domPlayerData).find('Player').attr('id')\n        })\n        return jXML(found).find('Player').attr('mimeType');\n    }\n\n    /**\n     Bind the template (screen division template)to the specified timeline (i_campaign_timeline_id).\n     We need to also provide the board_template_id (screen template of the global board) as well as\n     the campaign's board_id to complete the binding\n     @method assignTemplateToTimeline\n     @param {Number} i_campaign_timeline_id to assign to template\n     @param {Number} i_board_template_id is the global board id (does not belong to campaign) to assign to the template\n     @param {Number} i_campaign_board_id is the campaign specific board id that will be bound to the template\n     @return {Number} campaign_timeline_board_template_id\n     **/\n    assignTemplateToTimeline(i_campaign_timeline_id, i_board_template_id, i_campaign_board_id): number {\n        var timelineTemplate = this.databaseManager.table_campaign_timeline_board_templates();\n        var timelineScreen = timelineTemplate.createRecord();\n        timelineScreen.campaign_timeline_id = i_campaign_timeline_id;\n        timelineScreen.board_template_id = i_board_template_id;\n        timelineScreen.campaign_board_id = i_campaign_board_id;\n        timelineTemplate.addRecord(timelineScreen, undefined);\n        this.addPendingTables(['table_campaign_timeline_board_templates']);\n        return timelineScreen['campaign_timeline_board_template_id'];\n    }\n\n    /**\n     Create channels and assign these channels to the timeline\n     @method createTimelineChannels\n     @param {Number} i_campaign_timeline_id the timeline id to assign channel to\n     @param {Object} i_viewers we use viewer as a reference count to know how many channels to create (i.e.: one per channel)\n     @return {Array} createdChanels array of channel ids created\n     **/\n    createTimelineChannels(i_campaign_timeline_id, i_viewers): Array<any> {\n        var createdChanels = [];\n        var x = 0;\n        for (var i in i_viewers) {\n            x++;\n            var chanels = this.databaseManager.table_campaign_timeline_chanels();\n            var chanel = chanels.createRecord();\n            chanel.chanel_name = \"CH\" + x;\n            chanel.campaign_timeline_id = i_campaign_timeline_id;\n            chanels.addRecord(chanel, undefined);\n            createdChanels.push(chanel['campaign_timeline_chanel_id']);\n        }\n        this.addPendingTables(['table_campaign_timeline_chanels']);\n        return createdChanels;\n    }\n\n    /**\n     Set a timeline's total duration\n     @method setTimelineTotalDuration\n     @param {Number} i_campaign_timeline_id\n     @param {Number} i_totalDuration\n     **/\n    setTimelineTotalDuration(i_campaign_timeline_id, i_totalDuration): void {\n        this.databaseManager.table_campaign_timelines().openForEdit(i_campaign_timeline_id);\n        var recCampaignTimeline = this.databaseManager.table_campaign_timelines().getRec(i_campaign_timeline_id);\n        recCampaignTimeline['timeline_duration'] = i_totalDuration;\n        this.addPendingTables(['table_campaign_timelines']);\n    }\n\n    /**\n     Set a station record via object arg into sdk table_branch_stations\n     **/\n    setStationRecordValue(i_native_station_id, field, value) {\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each((k, branch_station_id) => {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                this.databaseManager.table_branch_stations().openForEdit(branch_station_id);\n                var recBranchStationEdit = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                recBranchStationEdit[field] = value;\n            }\n        });\n        this.addPendingTables(['table_branch_stations']);\n    }\n\n    /**\n     Remove the enitre campaigns and it's related boards\n     @method removeCampaignEntirely\n     @param {Number} i_campaign_id\n     **/\n    removeCampaignEntirely(i_campaign_id): void {\n        var timelineIDs = this.getCampaignTimelines(i_campaign_id);\n        for (var i = 0; i < timelineIDs.length; i++) {\n            var timelineID = timelineIDs[i];\n            var boardTemplateID = this.getGlobalTemplateIdOfTimeline(timelineID);\n            this.removeTimelineFromCampaign(timelineID);\n            var campaignTimelineBoardTemplateID = this.removeBoardTemplateFromTimeline(timelineID);\n            this.removeTimelineBoardViewerChannels(campaignTimelineBoardTemplateID);\n            this.removeBoardTemplate(boardTemplateID);\n            this.removeBoardTemplateViewers(boardTemplateID);\n            this.removeTimelineFromSequences(timelineID);\n            this.removeSchedulerFromTime(timelineID);\n\n            var channelsIDs = this.getChannelsOfTimeline(timelineID);\n            for (var n = 0; n < channelsIDs.length; n++) {\n                var channelID = channelsIDs[n];\n                this.removeChannelFromTimeline(channelID);\n\n                var blockIDs = this.getChannelBlocks(channelID);\n                for (var x = 0; x < blockIDs.length; x++) {\n                    var blockID = blockIDs[x];\n                    this.removeBlockFromTimelineChannel(blockID);\n                }\n            }\n        }\n        this.removeCampaign(i_campaign_id);\n        this.removeCampaignBoard(i_campaign_id);\n\n        // check to see if any other campaigns are left, do some clean house and remove all campaign > boards\n        var campaignIDs = this.getCampaignIDs();\n        if (campaignIDs.length == 0)\n            this.removeAllBoards();\n    }\n\n    /**\n     Create a new player (a.k.a block) and add it to the specified channel_id\n     @method createNewChannelPlayer\n     **/\n    createNewChannelPlayer(i_campaign_timeline_chanel_id: number, i_addContents: IAddContents, i_boilerPlate, i_offset: number) {\n        con('adding block to channel ' + i_campaign_timeline_chanel_id);\n        var timelinePlayers = this.databaseManager.table_campaign_timeline_chanel_players();\n        var recTimelinePlayer = timelinePlayers.createRecord();\n        var player_data = i_boilerPlate.getDefaultPlayerData(PLACEMENT_CHANNEL, i_addContents.resourceId);\n\n        // dealing with embedded scene, override player_data with scene handle\n        if (!_.isUndefined(i_addContents.sceneData))\n            player_data = '<Player hDataSrc=\"' + i_addContents.sceneData.scene_id + '\"/>';\n\n        recTimelinePlayer.player_data = player_data;\n        recTimelinePlayer.campaign_timeline_chanel_id = i_campaign_timeline_chanel_id;\n        recTimelinePlayer.player_duration = 10;\n        recTimelinePlayer.player_offset_time = Lib.ToValidNumber(i_offset);\n        timelinePlayers.addRecord(recTimelinePlayer, null);\n\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Returns the record for a station id\n     @method getStationRecord\n     @param {Number} i_native_station_id\n     @return {Object} recBranchStation\n     **/\n    getStationRecord(i_native_station_id) {\n        var record;\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each((k, branch_station_id) => {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                record = recBranchStation;\n            }\n        });\n        return record;\n    }\n\n    /**\n     Remove the entire campaign, but keep the board that was created with it as we can still use it in other campaign setups\n     @method removeCampaignKeepBoards\n     @param {Number} i_campaign_id\n     **/\n    removeCampaignKeepBoards(i_campaign_id): void {\n        var timelineIDs = this.getCampaignTimelines(i_campaign_id);\n        for (var i = 0; i < timelineIDs.length; i++) {\n            var timelineID = timelineIDs[i];\n            this.removeTimelineFromCampaign(timelineID);\n            var campaignTimelineBoardTemplateID = this.removeBoardTemplateFromTimeline(timelineID);\n            this.removeTimelineBoardViewerChannels(campaignTimelineBoardTemplateID);\n            this.removeTimelineFromSequences(timelineID);\n            this.removeSchedulerFromTime(timelineID);\n            var channelsIDs = this.getChannelsOfTimeline(timelineID);\n            for (var n = 0; n < channelsIDs.length; n++) {\n                var channelID = channelsIDs[n];\n                this.removeChannelFromTimeline(channelID);\n                var blockIDs = this.getChannelBlocks(channelID);\n                for (var x = 0; x < blockIDs.length; x++) {\n                    var blockID = blockIDs[x];\n                    this.removeBlockFromTimelineChannel(blockID);\n                }\n            }\n        }\n        this.removeCampaign(i_campaign_id);\n        this.removeCampaignBoard(i_campaign_id);\n    }\n\n    /**\n     Remove a campaign record\n     @method removeCampaign\n     @param {Number} i_campaign_id\n     @return none\n     **/\n    removeCampaign(i_campaign_id) {\n        this.databaseManager.table_campaigns().openForDelete(i_campaign_id);\n        this.addPendingTables(['table_campaigns']);\n    }\n\n    /**\n     Get Scene player data\n     @method getScenePlayerdata\n     @param {Number} i_scene_id\n     @return {Object} XML scene player data\n     **/\n    getScenePlayerdata(i_scene_id) {\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        return this.getScenePlayerRecord(i_scene_id)['player_data_value'];\n    }\n\n    /**\n     Get all timeline ids for specified campaign\n     @method getCampaignTimelines\n     @param {Number} i_campaign_id\n     @return {Array} timeline ids\n     **/\n    getCampaignTimelines(i_campaign_id): Array<number> {\n        var timelineIDs = [];\n        $(this.databaseManager.table_campaign_timelines().getAllPrimaryKeys()).each((k, campaign_timeline_id) => {\n            var recCampaignTimeline = this.databaseManager.table_campaign_timelines().getRec(campaign_timeline_id);\n            if (recCampaignTimeline['campaign_id'] == i_campaign_id) {\n                timelineIDs.push(campaign_timeline_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timelines']);\n        return timelineIDs;\n    }\n\n    /**\n     save new station name\n     @method setStationName\n     @param {Number} branch_station_id\n     @param {String} i_callBack\n     **/\n    setStationName(i_stationID, i_name) {\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each((k, branch_station_id) => {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_stationID) {\n                this.databaseManager.table_branch_stations().openForEdit(branch_station_id);\n                var recBranch = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                recBranch['station_name'] = i_name;\n            }\n        });\n        this.addPendingTables(['table_branch_stations']);\n    }\n\n    /**\n     Get all the global board template ids of a timeline\n     @method getGlobalTemplateIdOfTimeline\n     @param {Number} i_campaign_timeline_id\n     @return {Array} foundGlobalBoardTemplatesIDs global board template ids\n     **/\n    getGlobalTemplateIdOfTimeline(i_campaign_timeline_id): number {\n        var found = [];\n        $(this.databaseManager.table_campaign_timeline_board_templates().getAllPrimaryKeys()).each((k, table_campaign_timeline_board_template_id) => {\n            var recCampaignTimelineBoardTemplate = this.databaseManager.table_campaign_timeline_board_templates().getRec(table_campaign_timeline_board_template_id);\n            if (recCampaignTimelineBoardTemplate['campaign_timeline_id'] == i_campaign_timeline_id) {\n                found.push(recCampaignTimelineBoardTemplate['board_template_id']);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_board_templates']);\n        return found[0];\n    }\n\n    /**\n     Remove a timeline from a campaign.\n     @method removeTimelineFromCampaign\n     @param {Number} i_campaign_timeline_id\n     @return none\n     **/\n    removeTimelineFromCampaign(i_campaign_timeline_id): void {\n        this.databaseManager.table_campaign_timelines().openForDelete(i_campaign_timeline_id);\n        this.addPendingTables(['table_campaign_timelines']);\n    }\n\n    /**\n     Remove board template from timeline\n     @method removeBoardTemplateFromTimeline\n     @param {Number} i_timeline_id\n     @return {Number} campaign_timeline_board_template_id\n     **/\n    removeBoardTemplateFromTimeline(i_timeline_id): number {\n        var campaign_timeline_board_template_id = this.getTemplatesOfTimeline(i_timeline_id)[0];\n        this.databaseManager.table_campaign_timeline_board_templates().openForDelete(campaign_timeline_board_template_id);\n        this.addPendingTables(['table_campaign_timeline_board_templates']);\n        return campaign_timeline_board_template_id;\n    }\n\n    /**\n     Remove blocks (a.k.a players) from all campaign that use the specified resource_id (native id)\n     @method removeBlocksWithResourceID\n     @param {Number} i_resource_id\n     @return none\n     **/\n    removeBlocksWithResourceID(i_resource_id) {\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var xPlayerData = parser.xml2js(playerData);\n            var resourceID = undefined;\n            try {\n                resourceID = xPlayerData['Player']['Data']['Resource']['_hResource'];\n            } catch (e) {\n            }\n            if (resourceID != undefined && resourceID == i_resource_id) {\n                this.removeBlockFromTimelineChannel(campaign_timeline_chanel_player_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Remove a block (i.e.: player) from campaign > timeline > channel\n     @method removeBlockFromTimelineChannel\n     @param {Number} i_block_id\n     @return none\n     **/\n    removeBlockFromTimelineChannel(i_block_id): void {\n        var status = this.databaseManager.table_campaign_timeline_chanel_players().openForDelete(i_block_id);\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Remove board template viewers\n     @method removeTimelineBoardViewerChannels\n     @param {Number} i_campaign_timeline_board_template_id\n     @return none\n     **/\n    removeTimelineBoardViewerChannels(i_campaign_timeline_board_template_id) {\n        $(this.databaseManager.table_campaign_timeline_board_viewer_chanels().getAllPrimaryKeys()).each((k, campaign_timeline_board_viewer_chanel_id) => {\n            var recCampaignTimelineViewerChanels = this.databaseManager.table_campaign_timeline_board_viewer_chanels().getRec(campaign_timeline_board_viewer_chanel_id);\n            if (recCampaignTimelineViewerChanels['campaign_timeline_board_template_id'] == i_campaign_timeline_board_template_id) {\n                this.databaseManager.table_campaign_timeline_board_viewer_chanels().openForDelete(campaign_timeline_board_viewer_chanel_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_board_viewer_chanels']);\n    }\n\n    /**\n     Remove board template\n     @method removeBoardTemplate\n     @param {Number} i_campaign_timeline_board_template_id\n     **/\n    removeBoardTemplate(i_board_template_id): number {\n        this.databaseManager.table_board_templates().openForDelete(i_board_template_id);\n        this.addPendingTables(['table_board_templates']);\n        return i_board_template_id;\n    }\n\n    /**\n     Remove board template viewers\n     @method removeBoardTemplateViewers\n     @param {Number} i_board_template_id\n     @return {Array} boardTemplateViewerIDs\n     **/\n    removeBoardTemplateViewers(i_board_template_id): Array<number> {\n        var boardTemplateViewerIDs = [];\n        $(this.databaseManager.table_board_template_viewers().getAllPrimaryKeys()).each((k, board_template_viewer_id) => {\n            var recBoardTemplateViewers = this.databaseManager.table_board_template_viewers().getRec(board_template_viewer_id);\n            if (recBoardTemplateViewers['board_template_id'] == i_board_template_id) {\n                var a = this.databaseManager.table_board_template_viewers().openForDelete(board_template_viewer_id);\n                boardTemplateViewerIDs.push(board_template_viewer_id);\n            }\n        });\n        this.addPendingTables(['table_board_template_viewers']);\n        return boardTemplateViewerIDs;\n    }\n\n    /**\n     Get a global board record (not the board that assigned to a campaign, but global).\n     Keep in mind that we only give as an argument the campaign > timeline > board > template id, so we have to query it and find\n     out to which global board its pointing so we can grab the correct record for the correct global board.\n     @method getGlobalBoardRecFromTemplate\n     @param {Number} i_campaign_timeline_board_template_id to reverse map into global board\n     @return {Object} global board record;\n     **/\n    getGlobalBoardRecFromTemplate(i_campaign_timeline_board_template_id) {\n        var recCampaignTimelineBoardTemplate = this.databaseManager.table_campaign_timeline_board_templates().getRec(i_campaign_timeline_board_template_id);\n        var board_template_id = recCampaignTimelineBoardTemplate['board_template_id'];\n        var recBoardTemplate = this.databaseManager.table_board_templates().getRec(board_template_id);\n        var board_id = recBoardTemplate['board_id'];\n        var recBoard = this.databaseManager.table_boards().getRec(board_id);\n        return recBoard;\n    }\n\n    /**\n     Set a block's record using key value pair\n     The method uses generic key / value fields so it can set any part of the record.\n     @method setBlockRecord\n     @param {Number} i_block_id\n     @param {String} i_key\n     @param {Number} i_value\n     @return none\n     **/\n    setBlockRecord(i_block_id, i_key, i_value) {\n        this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(i_block_id);\n        var recEditBlock = this.databaseManager.table_campaign_timeline_chanel_players().getRec(i_block_id);\n        recEditBlock[i_key] = i_value;\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Remove a timeline from sequences\n     @method removeTimelineFromSequences\n     @param {Number} i_timeline_id\n     @return none\n     **/\n    removeTimelineFromSequences(i_campaign_timeline_id): void {\n        $(this.databaseManager.table_campaign_timeline_sequences().getAllPrimaryKeys()).each((k, campaign_timeline_sequence_id) => {\n            var recCampaignTimelineSequence = this.databaseManager.table_campaign_timeline_sequences().getRec(campaign_timeline_sequence_id);\n            if (recCampaignTimelineSequence['campaign_timeline_id'] == i_campaign_timeline_id) {\n                this.databaseManager.table_campaign_timeline_sequences().openForDelete(campaign_timeline_sequence_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_sequences']);\n    }\n\n    /**\n     Set a block (a.k.a player) on the timeline_channel to a specified length in total seconds.\n     @method setBlockTimelineChannelBlockLength\n     @param {Number} i_campaign_timeline_chanel_player_id {string} plyer / block id\n     @param {Number} i_hours total hours to play\n     @param {Number} i_minutes total minutes to play\n     @param {Number} i_seconds total seconds to play\n     @return none\n     **/\n    setBlockTimelineChannelBlockLength(i_campaign_timeline_chanel_player_id, i_hours, i_minutes, i_seconds) {\n        var totalSecInMin = 60;\n        var totalSecInHour = totalSecInMin * 60;\n        var totalSeconds = parseInt(i_seconds) + (parseInt(i_minutes) * totalSecInMin) + (parseInt(i_hours) * totalSecInHour)\n\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            // var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            if (campaign_timeline_chanel_player_id == i_campaign_timeline_chanel_player_id) {\n                this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                var recPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n                recPlayer.player_duration = totalSeconds;\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n        // var returnData = {\n        //     campaignTimelineChanelPlayerID: i_campaign_timeline_chanel_player_id,\n        //     totalSeconds: totalSeconds\n        // }\n        // this.databaseManager.fire(Pepper['BLOCK_LENGTH_CHANGED'], this, null, returnData);\n    }\n\n    /**\n     Set a block (a.k.a player) offset to support timeline\n     @method setBlockTimelineChannelBlockNewPosition\n     @param {Number} i_campaign_timeline_chanel_player_id {string} plyer / block id\n     @param {Number} i_hours total hours to play\n     @param {Number} i_minutes total minutes to play\n     @param {Number} i_seconds total seconds to play\n     @return none\n     **/                  \n    setBlockTimelineChannelBlockNewPosition(i_channel, i_campaign_timeline_chanel_player_id, i_field:'player_offset_time'|'player_duration', i_value) {\n        _.find(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys(), campaign_timeline_chanel_player_id => {\n            if (campaign_timeline_chanel_player_id == i_campaign_timeline_chanel_player_id) {\n                this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                var recPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n                recPlayer[i_field] = Lib.ToValidNumber(i_value);\n                recPlayer['campaign_timeline_chanel_id'] = i_channel;\n                this.addPendingTables(['table_campaign_timeline_chanel_players']);\n                return true;\n            }     \n        })\n    }\n\n    /**\n     Set a station so its bound to campaign_id\n     @method SetStationCampaignID\n     @param {Number} i_native_station_id\n     @param {Number} i_campaign_id\n     **/\n    setStationCampaignID(i_native_station_id, i_campaign_id) {\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each((k, branch_station_id) => {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                this.databaseManager.table_branch_stations().openForEdit(branch_station_id);\n                var recBranchStationEdit = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                var campaign_board_id = this.getCampaignBoardIdFromCampaignId(i_campaign_id);\n                recBranchStationEdit.campaign_board_id = campaign_board_id;\n            }\n        });\n        this.addPendingTables(['table_branch_stations']);\n    }\n\n    /**\n     Remove a schedule from timeline\n     @method removeSchedulerFromTime\n     @param {Number} i_campaign_timeline_id\n     @return none\n     **/\n    removeSchedulerFromTime(i_campaign_timeline_id): void {\n        $(this.databaseManager.table_campaign_timeline_schedules().getAllPrimaryKeys()).each((k, campaign_timeline_schedule_id) => {\n            var recCampaignTimelineSchedule = this.databaseManager.table_campaign_timeline_schedules().getRec(campaign_timeline_schedule_id);\n            if (recCampaignTimelineSchedule.campaign_timeline_id == i_campaign_timeline_id) {\n                this.databaseManager.table_campaign_timeline_schedules().openForDelete(campaign_timeline_schedule_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_schedules']);\n    }\n\n    /**\n     Remove a timeline from a campaign.\n     @method removeResource\n     @param {Number} i_resource_id\n     @return none\n     **/\n    removeResource(i_resource_id) {\n        this.databaseManager.table_resources().openForDelete(i_resource_id);\n        this.addPendingTables(['table_resources']);\n    }\n\n    /**\n     Remove all refernce to a resource id from within Scenes > BlockCollections that refer to that particulat resource id\n     In other words, check all scenes for existing block collections, and if they refer to resource id, remove that entry\n     @method removeResourceFromBlockCollectionInScenes\n     @param {Number} i_resource_id resource id to search for and remove in all scenes > BlockCollections\n     **/\n    removeResourceFromBlockCollectionInScenes(i_resource_id) {\n        var self = this;\n        $(self.databaseManager.table_player_data().getAllPrimaryKeys()).each(function (k, player_data_id) {\n            var recPlayerData = self.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var currentSceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"' + BlockLabels.BLOCKCODE_COLLECTION + '\"]').each(function (i, playerDataBlockCollection) {\n                    $(playerDataBlockCollection).find('Collection').children().each(function (k, page) {\n                        var resource_id = $(page).find('Resource').attr('hResource');\n                        if (i_resource_id == resource_id) {\n                            $(page).remove();\n                            currentSceneID = self.sterilizePseudoId(currentSceneID);\n                            self.databaseManager.table_player_data().openForEdit(currentSceneID);\n                            var player_data = self.xmlToStringIEfix(domSceneData);\n                            recPlayerData['player_data_value'] = player_data;\n                        }\n                    });\n                });\n            });\n        });\n        this.addPendingTables(['table_player_data']);\n    }\n\n    removeResourceFromBlockLocationInScenes(i_resource_id) {\n        var self = this;\n        $(self.databaseManager.table_player_data().getAllPrimaryKeys()).each(function (k, player_data_id) {\n            var recPlayerData = self.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var currentSceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"' + BlockLabels.LOCATION + '\"]').each(function (i, playerDataBlockCollection) {\n                    $(playerDataBlockCollection).find('Fixed').children().each(function (k, page) {\n                        var resource_id = $(page).find('Resource').attr('hResource');\n                        if (i_resource_id == resource_id) {\n                            $(page).remove();\n                            currentSceneID = self.sterilizePseudoId(currentSceneID);\n                            self.databaseManager.table_player_data().openForEdit(currentSceneID);\n                            var player_data = self.xmlToStringIEfix(domSceneData);\n                            recPlayerData['player_data_value'] = player_data;\n                        }\n                    });\n                });\n            });\n        });\n        $(self.databaseManager.table_player_data().getAllPrimaryKeys()).each(function (k, player_data_id) {\n            var recPlayerData = self.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var currentSceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"' + BlockLabels.LOCATION + '\"]').each(function (i, playerDataBlockCollection) {\n                    $(playerDataBlockCollection).find('GPS').children().each(function (k, page) {\n                        var resource_id = $(page).find('Resource').attr('hResource');\n                        if (i_resource_id == resource_id) {\n                            $(page).remove();\n                            currentSceneID = self.sterilizePseudoId(currentSceneID);\n                            self.databaseManager.table_player_data().openForEdit(currentSceneID);\n                            var player_data = self.xmlToStringIEfix(domSceneData);\n                            recPlayerData['player_data_value'] = player_data;\n                        }\n                    });\n                });\n            });\n        });\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Remove all scene players that use resources (3100 & 3130) and that include the specified resource id\n     @method removeAllScenePlayersWithResource\n     @param {Number} i_resource_id\n     **/\n    removeAllScenePlayersWithResource(i_resource_id) {\n        var self = this;\n        $(self.databaseManager.table_player_data().getAllPrimaryKeys()).each(function (k, player_data_id) {\n            var recPlayerData = self.databaseManager.table_player_data().getRec(player_data_id);\n            var domSceneData = $.parseXML(recPlayerData['player_data_value']);\n            var sceneID = $(domSceneData).find('Player').eq(0).attr('id');\n            $(domSceneData).find('Player').each(function (i, playerData) {\n                $(playerData).find('[player=\"3100\"],[player=\"3130\"],[player=\"3140\"]').each(function (i, playeResourceData) {\n                    var playerDataID = $(this).attr('id');\n                    var hResource = $(playeResourceData).find('Resource').attr('hResource');\n                    if (hResource == i_resource_id) {\n                        self.removeScenePlayer(sceneID, playerDataID);\n                    }\n                });\n            });\n        });\n        this.addPendingTables(['table_player_data']);\n    }\n\n    /**\n     Remove the resource from any block collection which resides in campaign timeline channels that uses that resource in its collection list\n     @method removeResourceFromBlockCollectionsInChannel\n     @param {Number} i_resource_id\n     @return none\n     **/\n    removeResourceFromBlockCollectionsInChannel(i_resource_id) {\n        var self = this;\n        $(self.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_player_id) {\n            var recCampaignTimelineChannelPlayer = self.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var blockType = $(domPlayerData).find('Player').attr('player');\n            if (parseInt(blockType) == BlockLabels.BLOCKCODE_COLLECTION) {\n                $(domPlayerData).find('Collection').children().each(function (k, page) {\n                    var resource_hResource;\n                    var type = $(page).attr('type');\n                    if (type == 'resource') {\n                        resource_hResource = $(page).find('Resource').attr('hResource');\n                        if (resource_hResource == i_resource_id) {\n                            $(page).remove();\n                            var player_data = self.xmlToStringIEfix(domPlayerData)\n                            self.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                            self.setCampaignTimelineChannelPlayerRecord(campaign_timeline_chanel_player_id, 'player_data', player_data);\n                        }\n                    }\n                });\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    removeResourceFromBlockLocationInChannel(i_resource_id) {\n        var self = this;\n        $(self.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_player_id) {\n            var recCampaignTimelineChannelPlayer = self.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var blockType = $(domPlayerData).find('Player').attr('player');\n            if (parseInt(blockType) == BlockLabels.LOCATION) {\n                $(domPlayerData).find('Fixed').children().each(function (k, page) {\n                    var resource_hResource;\n                    var type = $(page).attr('type');\n                    if (type == 'resource') {\n                        resource_hResource = $(page).find('Resource').attr('hResource');\n                        if (resource_hResource == i_resource_id) {\n                            $(page).remove();\n                            var player_data = self.xmlToStringIEfix(domPlayerData)\n                            self.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                            self.setCampaignTimelineChannelPlayerRecord(campaign_timeline_chanel_player_id, 'player_data', player_data);\n                        }\n                    }\n                });\n            }\n        });\n        $(self.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_player_id) {\n            var recCampaignTimelineChannelPlayer = self.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            var playerData = recCampaignTimelineChannelPlayer['player_data'];\n            var domPlayerData = $.parseXML(playerData);\n            var blockType = $(domPlayerData).find('Player').attr('player');\n            if (parseInt(blockType) == BlockLabels.LOCATION) {\n                $(domPlayerData).find('GPS').children().each(function (k, page) {\n                    var resource_hResource;\n                    var type = $(page).attr('type');\n                    if (type == 'resource') {\n                        resource_hResource = $(page).find('Resource').attr('hResource');\n                        if (resource_hResource == i_resource_id) {\n                            $(page).remove();\n                            var player_data = self.xmlToStringIEfix(domPlayerData)\n                            self.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                            self.setCampaignTimelineChannelPlayerRecord(campaign_timeline_chanel_player_id, 'player_data', player_data);\n                        }\n                    }\n                });\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Get all the campaign > timeline > channels ids of a timeline\n     @method getChannelsOfTimeline\n     @param {Number} i_campaign_timeline_id\n     @return {Array} channel ids\n     **/\n    getChannelsOfTimeline(i_campaign_timeline_id): Array<number> {\n        var foundChannelsIDs = [];\n        $(this.databaseManager.table_campaign_timeline_chanels().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_id) => {\n            var recCampaignTimelineChannel = this.databaseManager.table_campaign_timeline_chanels().getRec(campaign_timeline_chanel_id);\n            if (i_campaign_timeline_id == recCampaignTimelineChannel['campaign_timeline_id']) {\n                foundChannelsIDs.push(campaign_timeline_chanel_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanels']);\n        return foundChannelsIDs;\n    }\n\n    /**\n     Get all the block IDs of a particular channel.\n     Push them into an array so they are properly sorted by player offset time.\n     @method getChannelBlocksIDs\n     @param {Number} i_campaign_timeline_chanel_id\n     @return {Array} foundBlocks\n     **/\n    getChannelBlocks(i_campaign_timeline_chanel_id): Array<number> {\n        var foundBlocks = [];\n        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each((k, campaign_timeline_chanel_player_id) => {\n            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n            if (i_campaign_timeline_chanel_id == recCampaignTimelineChannelPlayer['campaign_timeline_chanel_id']) {\n                foundBlocks.push(campaign_timeline_chanel_player_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n        return foundBlocks;\n    }\n\n    /**\n     Get the assigned viewer id to the specified channel\n     @method getAssignedViewerIdFromChannelId\n     @param {Number} i_campaign_timeline_channel_id\n     @return {Number} foundViewerID\n     **/\n    getAssignedViewerIdFromChannelId(i_campaign_timeline_channel_id) {\n        var foundViewerID;\n        $(this.databaseManager.table_campaign_timeline_board_viewer_chanels().getAllPrimaryKeys()).each((k, campaign_timeline_board_viewer_chanel_id) => {\n            var recCampaignTimelineViewerChanels = this.databaseManager.table_campaign_timeline_board_viewer_chanels().getRec(campaign_timeline_board_viewer_chanel_id);\n            if (recCampaignTimelineViewerChanels['campaign_timeline_chanel_id'] == i_campaign_timeline_channel_id) {\n                foundViewerID = recCampaignTimelineViewerChanels['board_template_viewer_id']\n            }\n        });\n        return foundViewerID;\n    }\n\n    /**\n     Get campaign schedule for timeline\n     @method setCampaignsSchedule\n     @param {Number} i_campaign_timeline_id\n     @param {Object} i_key\n     @param {Object} i_value\n     **/\n    setCampaignsSchedule(i_campaign_timeline_id, i_key, i_value) {\n        $(this.databaseManager.table_campaign_timeline_schedules().getAllPrimaryKeys()).each((k, campaign_timeline_schedule_id) => {\n            var recCampaignTimelineSchedule = this.databaseManager.table_campaign_timeline_schedules().getRec(campaign_timeline_schedule_id);\n            if (recCampaignTimelineSchedule.campaign_timeline_id == i_campaign_timeline_id) {\n                this.databaseManager.table_campaign_timeline_schedules().openForEdit(campaign_timeline_schedule_id);\n                var recScheduler = this.databaseManager.table_campaign_timeline_schedules().getRec(campaign_timeline_schedule_id);\n                recScheduler[i_key] = String(i_value);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_schedules']);\n    }\n\n    /**\n     Remove station, delete it from internal sdk and push to server on save\n     @method removeStation\n     @param {Number} i_station\n     **/\n    removeStation(i_native_station_id) {\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each((k, branch_station_id) => {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                this.databaseManager.table_branch_stations().openForDelete(branch_station_id);\n                this.databaseManager.table_station_ads().openForDelete(branch_station_id);\n            }\n        });\n        this.addPendingTables(['table_station_ads', 'table_branch_stations']);\n    }\n\n    /**\n     Set a player_id record in sdk on key with value\n     The method uses generic key / value fields so it can set any part of the record.\n     **/\n    setCampaignTimelineChannelPlayerRecord(i_player_id, i_key, i_value) {\n        this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(i_player_id);\n        var recPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(i_player_id);\n        recPlayer[i_key] = i_value;\n        this.addPendingTables(['table_campaign_timeline_chanel_players']);\n    }\n\n    /**\n     Remove campaign board_id\n     @method removeCampaignBoard\n     @param {Number} i_campaign_id\n     @return none\n     **/\n    removeCampaignBoard(i_campaign_id): void {\n        $(this.databaseManager.table_campaign_boards().getAllPrimaryKeys()).each((k, campaign_board_id) => {\n            var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(campaign_board_id);\n            if (recCampaignBoard['campaign_id'] == i_campaign_id) {\n                this.databaseManager.table_campaign_boards().openForDelete(campaign_board_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_boards']);\n    }\n\n    /**\n     Get i_campaign_id into campaign_board_id using local table_campaign_boards (not global boards)\n     @method getCampaignIdFromCampaignBoardId\n     @param {Number} i_campaign_board_id\n     @return {Number} campaign_id\n     **/\n    getCampaignBoardIdFromCampaignId(i_campaign_id) {\n        var found_campaign_board_id = -1;\n        $(this.databaseManager.table_campaign_boards().getAllPrimaryKeys()).each((k, campaign_board_id) => {\n            var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(campaign_board_id);\n            if (recCampaignBoard['campaign_id'] == i_campaign_id)\n                found_campaign_board_id = recCampaignBoard['campaign_board_id'];\n        });\n        return found_campaign_board_id;\n    }\n\n    /**\n     Remove all boards in sdk\n     @method removeAllBoards\n     @return none\n     **/\n    removeAllBoards(): void {\n        $(this.databaseManager.table_boards().getAllPrimaryKeys()).each((k, board_id) => {\n            this.databaseManager.table_boards().openForDelete(board_id);\n        });\n        this.addPendingTables(['table_boards']);\n    }\n\n    /**\n     Get all the campaign > timeline > board > template ids of a timeline\n     @method getTemplatesOfTimeline\n     @param {Number} i_campaign_timeline_id\n     @return {Array} template ids\n     **/\n    getTemplatesOfTimeline(i_campaign_timeline_id): Array<number> {\n        var foundTemplatesIDs = [];\n        $(this.databaseManager.table_campaign_timeline_board_templates().getAllPrimaryKeys()).each((k, table_campaign_timeline_board_template_id) => {\n            var recCampaignTimelineBoardTemplate = this.databaseManager.table_campaign_timeline_board_templates().getRec(table_campaign_timeline_board_template_id);\n            if (recCampaignTimelineBoardTemplate['campaign_timeline_id'] == i_campaign_timeline_id) {\n                foundTemplatesIDs.push(table_campaign_timeline_board_template_id);\n            }\n        });\n        this.addPendingTables(['table_campaign_timeline_board_templates']);\n        return foundTemplatesIDs;\n    }\n\n    /**\n     Get Scene player data as dom\n     @method getScenePlayerdataDom\n     @param {Number} i_sceneID\n     @return {Object} dom\n     **/\n    getScenePlayerdataDom(i_scene_id) {\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        var scene_player_data = this.getScenePlayerRecord(i_scene_id)['player_data_value'];\n        return $.parseXML(scene_player_data)\n    }\n\n\n    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    // below here need to review code\n    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n    /**\n     Get proof of play stats report\n     @method getProofOfPlayStats\n     @param {Function} i_callBack\n     @param {Number} i_year\n     @param {Number} i_playerData\n     @return {Number} i_month clientId.\n     **/\n    getProofOfPlayStats(i_year, i_month, i_callBack) {\n        this.m_loaderManager.requestAdsReport(function (data) {\n            var report = $(data.report).find('Report');\n            i_callBack(report);\n        }, i_year, i_month)\n    }\n\n    /**\n     Get list of all create account samples, both lite and pro\n     @method getSampleList\n     @param {Function} i_callBack\n     **/\n    getSampleList(i_callBack) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/getResellerTemplates.ashx?callback=?';\n        $.getJSON(url, function (data) {\n            i_callBack(data);\n        });\n    }\n\n    /**\n     Push a command to remote station\n     @method sendCommand\n     @param {String} i_command\n     @param {Number} i_stationId\n     @param {Function} i_callBack\n     **/\n    sendCommand(i_command, i_stationId, i_callBack) {\n        var url = window.g_protocol + this.getUserData().domain + '/WebService/sendCommand.ashx?i_user=' + this.getUserData().userName + '&i_password=' + this.getUserData().userPass + '&i_stationId=' + i_stationId + '&i_command=' + i_command + '&i_param1=' + 'SignageStudioLite' + '&i_param2=' + '&callback=?';\n        console.log(url)\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Push an event to a local station / server for Location based content, see parms for details\n     Keep in mind this supports both local and remote events\n     @method sendLocalEventGPS\n     @param {String} i_mode local or remote\n     @param {Number} i_stationId\n     @param {Number} i_lat\n     @param {Number} i_lng\n     @param {Function} i_callBack\n     @return {String) short url\n     **/\n    sendLocalEventGPS(i_mode, i_lat, i_lng, i_id, i_ip, i_port, i_callBack) {\n\n        // example posts\n        // curl \"http://192.168.92.133:1024/sendLocalEvent?eventName=gps&eventParam=34.22447,-118.828\"\n        // https://sun.signage.me/WebService/sendCommand.ashx?i_user=d39@ms.com&i_password=xxxx&i_stationId=44&i_command=event&i_param1=gps&i_param2=34.22447,-118.828&callback=\n        var url;\n        var returnUrl;\n        if (i_mode == \"local\") {\n            url = 'http://' + i_ip + ':' + i_port + '/sendLocalEvent?eventName=gps&eventParam=' + i_lat + ',' + i_lng;\n            returnUrl = url;\n        } else {\n            url = window.g_protocol + this.getUserData().domain + '/WebService/sendCommand.ashx?i_user=' + this.getUserData().userName + '&i_password=' + this.getUserData().userPass + '&i_stationId=' + i_id + '&i_command=event&i_param1=' + 'gps' + '&i_param2=' + i_lat + ',' + i_lng + '&callback=?';\n            returnUrl = '//remoteServer' + '&i_stationId=' + i_id + '&i_command=event&i_param1=' + 'gps' + '&i_param2=' + i_lat + ',' + i_lng;\n        }\n        // console.log(url);\n        if (i_mode == 'local')\n            return returnUrl;\n\n        try {\n            $.ajax({\n                url: url,\n                dataType: \"jsonp\",\n                type: \"post\",\n                complete (response) {\n                    if (i_callBack)\n                        i_callBack(response.statusText);\n                },\n                error (jqXHR, exception) {\n                    console.log(jqXHR, exception);\n                    if (i_callBack)\n                        i_callBack(exception);\n                }\n            });\n        } catch (e) {\n            console.log('error on ajax' + e);\n        }\n        return returnUrl;\n    }\n\n    /**\n     Push a command to remote station\n     @method getLocalization\n     @param {String} i_command\n     @param {Number} i_stationId\n     @param {Function} i_callBack\n     **/\n    getLocalization(i_lang, i_callBack) {\n        $.getJSON(window.g_protocol + window.g_masterDomain + '/WebService/getLocalList.ashx?callback=?', function (data) {\n            data = _.invert(data);\n            if (i_lang == 'zh')\n                i_lang = 'zh-CN';\n            var local = data[i_lang];\n            var url = window.g_protocol + window.g_masterDomain + '/WebService/getResourceBundlesJson.ashx?local=' + local + '&bundleList=studiolite&callback=?';\n            $.getJSON(url, function (data) {\n                i_callBack(data);\n            });\n        });\n    }\n\n    /**\n     Push a command to remote station, this v2 has a fall back and returns null on fails\n     @method getLocalizationNew\n     @param {String} i_command\n     @param {Number} i_stationId\n     @param {Function} i_callBack\n     **/\n    getLocalizationNew(i_lang, i_callBack) {\n        // $.getJSON(window.g_protocol + window.g_masterDomain + '/WebService/getLocalList.ashx?callback=?', function (data) {\n        //     data = _.invert(data);\n        //     if (i_lang == 'zh')\n        //         i_lang = 'zh-CN';\n        //     var local = data[i_lang];\n        //     var url = window.g_protocol + window.g_masterDomain + '/WebService/getResourceBundlesJson.ashx?local=' + local + '&bundleList=studiolite&callback=?';\n        //     $.getJSON(url, function (data) {\n        //         i_callBack(data);\n        //     }).error(function () {\n        //         i_callBack(null);\n        //     });\n        // }).error(function (e) {\n        //     i_callBack(null);\n        // });\n    }\n\n    /**\n     Return the url address of StudioLite\n     @method getStudioLiteURL\n     @return {String} url address\n     **/\n    getStudioLiteURL() {\n        var protocol = window.g_protocol;\n        if (window.g_masterDomain == 'galaxy.signage.me')\n            protocol = 'https://';\n        return protocol + window.g_masterDomain + '/_studiolite-dist/studiolite.html';\n    }\n\n    /**\n     Return the url address of StudioPro\n     @method getStudioProURL\n     @return {String} url address\n     **/\n    getStudioProURL() {\n        var protocol = window.g_protocol;\n        return window.g_protocol + window.g_masterDomain + '/WebService/signagestudio_d.aspx';\n    }\n\n    /**\n     Create a new mediaCLOUD account\n     @method createAccount\n     @param {Function} i_callBack\n     **/\n    createAccount(i_businessName, i_userName, i_password, i_templateBusinessId, i_resellerId, i_firstName, i_lastName, i_contactEmail, i_workPhone, i_cellPhone, i_address, i_city, i_state, i_contry, i_zipcode, i_callback) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/createNewAccount.ashx?command=CreateCustomerAccount'\n        url += '&businessName=' + i_businessName;\n        url += '&userName=' + i_userName;\n        url += '&password=' + i_password;\n        url += '&templateBusinessId=' + i_templateBusinessId;\n        url += '&resellerId=' + i_resellerId;\n        url += '&firstName=' + i_firstName;\n        url += '&lastName=' + i_lastName;\n        url += '&contactEmail=' + i_contactEmail;\n        url += '&workPhone=' + i_workPhone;\n        url += '&cellPhone=' + i_cellPhone;\n        url += '&address=' + i_address;\n        url += '&city=' + i_city;\n        url += '&state=' + i_state;\n        url += '&contry=' + i_contry;\n        url += '&zipcode=' + i_zipcode;\n        url += '&callback=?';\n        console.log(url);\n        $.getJSON(url, i_callback);\n    }\n\n    /**\n     Get business user info\n     @method GetBusinessUserInfo\n     @param {Function} i_callBack\n     **/\n    getAccountStatus(i_businessId, i_callBack) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/createNewAccount.ashx?command=GetAccountStatus&businessId=' + i_businessId + '&callback=?';\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Get business user info\n     @method GetBusinessUserInfo\n     @param {Function} i_callBack\n     **/\n    resetPassword(i_email, i_callBack) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/createNewAccount.ashx?command=ResetPassword&userName=' + i_email + '&callback=?';\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Get business user info\n     @method ChangePassword\n     @param {Function} i_callBack\n     **/\n    changePassword(i_email, i_oldPassword, i_newPassword, i_callBack) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/createNewAccount.ashx?command=ChangePassword&userName=' + i_email + '&oldPassword=' + i_oldPassword + '&newPassword=' + i_newPassword + '&callback=?';\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Get business user info\n     @method ChangeBusinessName\n     @param {Function} i_callBack\n     **/\n    changeBusinessName(i_email, i_password, i_businessName, i_callBack) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/createNewAccount.ashx?command=ChangeBusinessName&userName=' + i_email + '&password=' + i_password + '&newBusnessName=' + i_businessName + '&callback=?';\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Get business user info\n     @method GetBusinessUserInfo\n     @param {Function} i_callBack\n     **/\n    getBusinessUserInfo(i_user, i_pass, i_callBack) {\n        var url = window.g_protocol + window.g_masterDomain + '/WebService/createNewAccount.ashx?command=GetBusinessUserInfo&userName=' + i_user + '&password=' + i_pass + '&callback=?';\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Push an event to remote station\n     @method sendEvent\n     @param {String} i_eventName\n     @param {Number} i_stationId\n     @param {Function} i_callBack\n     **/\n    sendEvent(i_eventName, i_stationId, i_callBack) {\n        var url = window.g_protocol + this.getUserData().domain + '/WebService/sendCommand.ashx?i_user=' + this.getUserData().userName + '&i_password=' + this.getUserData().userPass + '&i_stationId=' + i_stationId + '&i_command=event&i_param1=' + i_eventName + '&i_param2=' + '&callback=?';\n        $.getJSON(url, i_callBack);\n    }\n\n    /**\n     Send remote command to retrieve snapshot of a running station\n     @method sendSnapshot\n     @param {String} i_fileName\n     @param {Number} i_quality\n     @param {Number} i_stationId\n     @param {Function} i_callBack\n     @return {String} image path url\n     **/\n    sendSnapshot(i_fileName, i_quality, i_stationId, i_callBack) {\n        var url = window.g_protocol + this.getUserData().domain + '/WebService/sendCommand.ashx?i_user=' + this.getUserData().userName + '&i_password=' + this.getUserData().userPass + '&i_stationId=' + i_stationId + '&i_command=' + 'captureScreen2' + '&i_param1=' + i_fileName + '&i_param2=' + i_quality + '&callback=?';\n        $.getJSON(url, i_callBack);\n        var path = window.g_protocol + this.getUserData().domain + '/Snapshots/business' + this.getUserData().businessID + \"/station\" + i_stationId + '/' + i_fileName + '.jpg';\n        // console.log(path);\n        return path;\n    }\n\n    /**\n     Build URL for player preview using supplied player parameters\n     **/\n    _livePreviewGetLink(i_playerParams, i_bannerMode): string {\n        var rc4v2 = new RC4V2();\n        var playerParams = rc4v2.encrypt(i_playerParams, '8547963624824263');\n        var domain = this.getUserData().domain;\n        var eri = this.getUserData().eri;\n        var url = window.g_protocol + domain + '/WebService/SignagePlayerApp.html?eri=' + eri + '&playerParams=' + playerParams + '&banner=' + i_bannerMode;\n        // console.log(url);\n        return url;\n    }\n\n    /**\n     Create a live preview URL for campaign\n     @method livePreviewCampaign\n     @param {Number} i_campaignID\n     @param {Number} i_bannerMode\n     @return {String} url\n     **/\n    livePreviewCampaign(i_campaignID, i_bannerMode) {\n        var campaignBoardId = this.getCampaignBoardIdFromCampaignId(i_campaignID);\n        var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(campaignBoardId);\n        var campaignNativeID = recCampaignBoard['native_id'];\n        var playerParams = this.getUserData().businessID + ',1,' + campaignNativeID;\n        return this._livePreviewGetLink(playerParams, i_bannerMode);\n    }\n\n    /**\n     Create a live preview URL for campaign\n     @method livePreviewTimeline\n     @param {Number} i_campaignID\n     @param {Number} i_timelineID\n     @param {Number} i_bannerMode\n     @return {String} url\n     **/\n    livePreviewTimeline(i_campaignID, i_timelineID, i_bannerMode) {\n\n        var campaignBoardId = this.getCampaignBoardIdFromCampaignId(i_campaignID);\n        var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(campaignBoardId);\n        var campaignNativeID = recCampaignBoard['native_id'];\n        var recCampaignTimeline = this.getCampaignTimelineRecord(i_timelineID);\n        var timelineNativeID = recCampaignTimeline['native_id'];\n        var playerParams = this.getUserData().businessID + ',2,' + campaignNativeID + \",\" + timelineNativeID;\n        return this._livePreviewGetLink(playerParams, i_bannerMode);\n    }\n\n    /**\n     Create a live preview URL for a scene\n     **/\n    livePreviewScene(sceneID, i_bannerMode): string {\n        // var sceneID = this.getSceneIdFromPseudoId(i_scene_id);\n        var recPlayerData = this.getScenePlayerRecord(sceneID);\n        var nativeID = recPlayerData['native_id'];\n        var playerParams = this.getUserData().businessID + ',3,' + nativeID;\n        return this._livePreviewGetLink(playerParams, i_bannerMode);\n    }\n\n    /**\n     get a scene's default length\n     @method getSceneDuration\n     @param {number} i_scene_id\n     @return {number} total seconds\n     **/\n    getSceneDuration(i_scene_id) {\n\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        var seconds = 0;\n        var minutes = 0;\n        var hours = 0;\n        var totalInSeconds = 0;\n\n        var recPlayerData = this.getScenePlayerRecord(i_scene_id);\n        var player_data = recPlayerData['player_data_value'];\n        var domPlayerData = $.parseXML(player_data);\n        var xSnippet = $(domPlayerData).find('Scene');\n        var totalSeconds = parseInt(xSnippet.attr('defaultDuration'));\n\n        totalInSeconds = totalSeconds;\n        if (totalSeconds >= 3600) {\n            hours = Math.floor(totalSeconds / 3600);\n            totalSeconds = totalSeconds - (hours * 3600);\n        }\n        if (totalSeconds >= 60) {\n            minutes = Math.floor(totalSeconds / 60);\n            seconds = totalSeconds - (minutes * 60);\n        }\n        if (hours == 0 && minutes == 0)\n            seconds = totalSeconds;\n\n        var playbackLength = {\n            hours: hours,\n            minutes: minutes,\n            seconds: seconds,\n            totalInSeconds: totalInSeconds\n        };\n        return playbackLength;\n    }\n\n    /**\n     Set a scene's default length (can be overridden on timeline)\n     @method setSceneDuration\n     @param {number} i_scene_id\n     @param {string} hours\n     @param {string} minutes\n     @param {string} seconds\n     **/\n    setSceneDuration(i_scene_id, i_hours, i_minutes, i_seconds) {\n\n        i_scene_id = this.sterilizePseudoId(i_scene_id);\n        var totalSecInMin = 60\n        var totalSecInHour = totalSecInMin * 60\n        var totalSeconds = parseInt(i_seconds) + (parseInt(i_minutes) * totalSecInMin) + (parseInt(i_hours) * totalSecInHour);\n        var recPlayerData = this.getScenePlayerRecord(i_scene_id);\n        var player_data = recPlayerData['player_data_value'];\n        var domPlayerData = $.parseXML(player_data)\n        var xSnippet = $(domPlayerData).find('Scene');\n        xSnippet.attr('defaultDuration', totalSeconds);\n        var player_data: any = (new XMLSerializer()).serializeToString(domPlayerData);\n        this.setScenePlayerData(i_scene_id, player_data);\n    }\n\n    /**\n     Returns all scenes\n     @method getSceneNames\n     @param {Number} i_playerData\n     @return {Object} scene names\n     **/\n    getSceneNames() {\n        var sceneNames: any = {};\n        $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each(function (k, player_data_id: any) {\n            var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n            var domPlayerData = $.parseXML(recPlayerData['player_data_value'])\n            sceneNames[player_data_id] = {\n                label: ($(domPlayerData).find('Player').attr('label')),\n                mimeType: $(domPlayerData).find('Player').attr('mimeType')\n            };\n        });\n        return sceneNames;\n    }\n\n\n    /**\n     Returns this model's attributes as...\n     @method xmlToStringIEfix\n     @param {Object} i_domPlayerData\n     @return {String} xml string\n     **/\n    xmlToStringIEfix(i_domPlayerData) {\n        var player_data = (new XMLSerializer()).serializeToString(i_domPlayerData);\n        return this.ieFixEscaped(player_data);\n    }\n\n    /**\n     \"Good\" old IE, always a headache, jXML workarounds....\n     @method ieFixEscaped\n     @param {String} escapedHTML\n     @return {String}\n     **/\n    /**\n     \"Good\" old IE, always a headache, jXML workarounds....\n     @method ieFixEscaped\n     @param {String} escapedHTML\n     @return {String}\n     **/\n    ieFixEscaped(escapedHTML) {\n        try {\n            return escapedHTML.replace(/xmlns=\"http:\\/\\/www.w3.org\\/1999\\/xhtml\"/g, '').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&').replace(/<rss/gi, '<Rss').replace(/rss>/g, 'Rss>').replace(/<background/gi, '<Background').replace(/background>/gi, 'Background>').replace(/<appearance/gi, '<Appearance').replace(/appearance>/gi, 'Appearance>').replace(/<gradientpoints/gi, '<GradientPoints').replace(/gradientpoints>/gi, 'GradientPoints>').replace(/<aspectratio/gi, '<AspectRatio').replace(/aspectratio>/gi, 'AspectRatio>').replace(/<layout/gi, '<Layout').replace(/layout>/gi, 'Layout>').replace(/<title/gi, '<Title').replace(/title>/gi, 'Title>').replace(/<description/gi, '<Description').replace(/description>/gi, 'Description>').replace(/<data/gi, '<Data').replace(/data>/gi, 'Data>').replace(/<player/gi, '<Player').replace(/player>/gi, 'Player>').replace(/<players/gi, '<Players').replace(/players>/gi, 'Players>').replace(/<text/gi, '<Text').replace(/text>/gi, 'Text>').replace(/<eventCommands/gi, '<EventCommands').replace(/eventCommands>/gi, 'EventCommands>').replace(/<eventCommand/gi, '<EventCommand').replace(/eventCommand>/gi, 'EventCommand>').replace(/<border/gi, '<Border').replace(/border>/gi, 'Border>').replace(/<scene/gi, '<Scene').replace(/scene>/gi, 'Scene>').replace(/<clock/gi, '<Clock').replace(/clock>/gi, 'Clock>').replace(/<point/gi, '<Point').replace(/point>/gi, 'Point>').replace(/<video/gi, '<Video').replace(/video>/gi, 'Video>').replace(/<image/gi, '<Image').replace(/image>/gi, 'Image>').replace(/<label/gi, '<Label').replace(/label>/gi, 'Label>').replace(/<font/gi, '<Font').replace(/font>/gi, 'Font>').replace(/fontsize/gi, 'fontSize').replace(/startdate/gi, 'startDate').replace(/enddate/gi, 'endDate').replace(/fontcolor/gi, 'fontColor').replace(/fontfamily/gi, 'fontFamily').replace(/fontweight/gi, 'fontWeight').replace(/fontstyle/gi, 'fontStyle').replace(/bordercolor/gi, 'borderColor').replace(/borderthickness/gi, 'borderThickness').replace(/cornerradius/gi, 'cornerRadius').replace(/textdecoration/gi, 'textDecoration').replace(/textalign/gi, 'textAlign').replace(/hdatasrc/gi, 'hDataSrc').replace(/minrefreshtime/gi, 'minRefreshTime').replace(/itemspath/gi, 'itemsPath').replace(/slideshow/gi, 'slideShow').replace(/iteminterval/gi, 'itemInterval').replace(/playvideoinfull/gi, 'playVideoInFull').replace(/randomorder/gi, 'randomOrder').replace(/providertype/gi, 'providerType').replace(/fieldname/gi, 'fieldName').replace(/fieldtype/gi, 'fieldType').replace(/gradienttype/gi, 'gradientType').replace(/autorewind/gi, 'autoRewind').replace(/clockformat/gi, 'clockFormat').replace(/clockmask/gi, 'clockMask').replace(/hresource/gi, 'hResource').replace(/videoidlist/gi, 'VideoIdList').replace(/<page/gi, '<Page').replace(/page>/gi, 'Page>').replace(/<gps/gi, '<GPS').replace(/gps>/gi, 'GPS>').replace(/<fixed/gi, '<Fixed').replace(/fixed>/gi, 'Fixed>').replace(/<xmlitem/gi, '<XmlItem').replace(/xmlitem>/gi, 'XmlItem>').replace(/<json/gi, '<Json').replace(/json>/gi, 'Json>').replace(/<locationbased/gi, '<LocationBased').replace(/locationbased>/gi, 'LocationBased>').replace(/<params/gi, '<Params').replace(/params>/gi, 'Params>').replace(/<url/gi, '<Url').replace(/url>/gi, 'Url>').replace(/maintainaspectratio/gi, 'maintainAspectRatio').replace(/<resource/gi, '<Resource').replace(/resource>/g, 'Resource>').// replace(/<htdata/gi, '<htData').replace(/htdata>/gi, 'htData>').\n            replace(/<link/gi, '<LINK').replace(/link>/g, 'LINK>');\n        } catch (e) {\n            console.log(e);\n        }\n\n    }\n\n    // ieFixEscaped (escapedHTML) {\n    //     return escapedHTML.replace(/xmlns=\"http:\\/\\/www.w3.org\\/1999\\/xhtml\"/g, '').\n    //     replace(/&lt;/g, '<').\n    //     replace(/&gt;/g, '>').\n    //     replace(/&amp;/g, '&').\n    //     replace(/<rss/gi, '<Rss').replace(/rss>/g, 'Rss>').\n    //     replace(/<background/gi, '<Background').replace(/background>/gi, 'Background>').\n    //     replace(/<appearance/gi, '<Appearance').replace(/appearance>/gi, 'Appearance>').\n    //     replace(/<gradientpoints/gi, '<GradientPoints').replace(/gradientpoints>/gi, 'GradientPoints>').\n    //     replace(/<aspectratio/gi, '<AspectRatio').replace(/aspectratio>/gi, 'AspectRatio>').\n    //     replace(/<layout/gi, '<Layout').replace(/layout>/gi, 'Layout>').\n    //     replace(/<title/gi, '<Title').replace(/title>/gi, 'Title>').\n    //     replace(/<description/gi, '<Description').replace(/description>/gi, 'Description>').\n    //     replace(/<data/gi, '<Data').replace(/data>/gi, 'Data>').\n    //     replace(/<player/gi, '<Player').replace(/player>/gi, 'Player>').\n    //     replace(/<players/gi, '<Players').replace(/players>/gi, 'Players>').\n    //     replace(/<text/gi, '<Text').replace(/text>/gi, 'Text>').\n    //     replace(/<eventCommands/gi, '<EventCommands').replace(/eventCommands>/gi, 'EventCommands>').\n    //     replace(/<eventCommand/gi, '<EventCommand').replace(/eventCommand>/gi, 'EventCommand>').\n    //     replace(/<border/gi, '<Border').replace(/border>/gi, 'Border>').\n    //     replace(/<scene/gi, '<Scene').replace(/scene>/gi, 'Scene>').\n    //     replace(/<clock/gi, '<Clock').replace(/clock>/gi, 'Clock>').\n    //     replace(/<point/gi, '<Point').replace(/point>/gi, 'Point>').\n    //     replace(/<video/gi, '<Video').replace(/video>/gi, 'Video>').\n    //     replace(/<image/gi, '<Image').replace(/image>/gi, 'Image>').\n    //     replace(/<label/gi, '<Label').replace(/label>/gi, 'Label>').\n    //     replace(/<font/gi, '<Font').replace(/font>/gi, 'Font>').\n    //     replace(/fontsize/gi, 'fontSize').\n    //     replace(/startdate/gi, 'startDate').\n    //     replace(/enddate/gi, 'endDate').\n    //     replace(/fontcolor/gi, 'fontColor').\n    //     replace(/fontfamily/gi, 'fontFamily').\n    //     replace(/fontweight/gi, 'fontWeight').\n    //     replace(/fontstyle/gi, 'fontStyle').\n    //     replace(/bordercolor/gi, 'borderColor').\n    //     replace(/borderthickness/gi, 'borderThickness').\n    //     replace(/cornerradius/gi, 'cornerRadius').\n    //     replace(/textdecoration/gi, 'textDecoration').\n    //     replace(/textalign/gi, 'textAlign').\n    //     replace(/hdatasrc/gi, 'hDataSrc').\n    //     replace(/minrefreshtime/gi, 'minRefreshTime').\n    //     replace(/itemspath/gi, 'itemsPath').\n    //     replace(/slideshow/gi, 'slideShow').\n    //     replace(/iteminterval/gi, 'itemInterval').\n    //     replace(/playvideoinfull/gi, 'playVideoInFull').\n    //     replace(/randomorder/gi, 'randomOrder').\n    //     replace(/providertype/gi, 'providerType').\n    //     replace(/fieldname/gi, 'fieldName').\n    //     replace(/fieldtype/gi, 'fieldType').\n    //     replace(/gradienttype/gi, 'gradientType').\n    //     replace(/autorewind/gi, 'autoRewind').\n    //     replace(/clockformat/gi, 'clockFormat').\n    //     replace(/clockmask/gi, 'clockMask').\n    //     replace(/hresource/gi, 'hResource').\n    //     replace(/videoidlist/gi, 'VideoIdList').\n    //     replace(/<page/gi, '<Page').replace(/page>/gi, 'Page>').\n    //     replace(/<gps/gi, '<GPS').replace(/gps>/gi, 'GPS>').\n    //     replace(/<fixed/gi, '<Fixed').replace(/fixed>/gi, 'Fixed>').\n    //     replace(/<xmlitem/gi, '<XmlItem').replace(/xmlitem>/gi, 'XmlItem>').\n    //     replace(/<json/gi, '<Json').replace(/json>/gi, 'Json>').\n    //     replace(/<locationbased/gi, '<LocationBased').replace(/locationbased>/gi, 'LocationBased>').\n    //     replace(/<params/gi, '<Params').replace(/params>/gi, 'Params>').\n    //     replace(/<url/gi, '<Url').replace(/url>/gi, 'Url>').\n    //     replace(/maintainaspectratio/gi, 'maintainAspectRatio').\n    //     replace(/<resource/gi, '<Resource').replace(/resource>/g, 'Resource>').\n    //     // replace(/<htdata/gi, '<htData').replace(/htdata>/gi, 'htData>').\n    //     replace(/<link/gi, '<LINK').replace(/link>/g, 'LINK>');\n    // }\n\n    /**\n     Get a unique scene > player id\n     @method generateSceneId\n     @return {Number} Unique scene player id\n     **/\n    generateSceneId() {\n        return (jQuery.base64.encode(_.uniqueId('blockid'))).replace('=', '');\n    }\n\n    /**\n     Sterilize pseudo id to scene id always returns scene_id as an integer rather pseudo id\n     @method sterilizePseudoId\n     @param {Number} i_id\n     @return {Number} i_id\n     **/\n    sterilizePseudoId(i_id) {\n        var id = parseInt(i_id);\n        if (_.isNaN(id))\n            return this.getSceneIdFromPseudoId(i_id);\n        return i_id;\n    }\n\n    /**\n     Sterilize pseudo id to scene id always returns scene_id as an integer rather pseudo id\n     @method sterilizePseudoId\n     **/\n    sterilizePseudoIdFromScene(i_id, domPlayerData: XMLDocument) {\n        var id = parseInt(i_id);\n        if (_.isNaN(id)) {\n            var f = $(domPlayerData).find('Player').eq(0).attr('id');\n            return f;\n        }\n        return i_id;\n    }\n\n    /**\n     Remove all player ids from player_data inside a scene\n     @method stripScenePlayersIDs\n     **/\n    stripScenePlayersIDs() {\n\n        this.m_tempScenePlayerIDs = {};\n        var scenes = this.getScenes();\n        _.each(scenes, function (domPlayerData: any, scene_id) {\n            // $(domPlayerData).find('Player').eq(0).removeAttr('id');\n            this.m_tempScenePlayerIDs[scene_id] = (new XMLSerializer()).serializeToString(domPlayerData);\n            var players = $(domPlayerData).find('Players').find('Player').each(function (i, player) {\n                // var blockID = this.databaseManager.generateSceneId();\n                $(player).removeAttr('id');\n            });\n            this.databaseManager.setScenePlayerData(scene_id, (new XMLSerializer()).serializeToString(domPlayerData));\n        });\n    }\n\n    /**\n     When we remove scene player ids we actually store them aside so we can restore them back after a save as the\n     remote server expects a scene's player_data to have no player ids on its scene player_data\n     @method restoreScenesWithPlayersIDs\n     **/\n    restoreScenesWithPlayersIDs() {\n\n        _.each(this.m_tempScenePlayerIDs, function (scene_player_data, scene_id) {\n            this.databaseManager.setScenePlayerData(scene_id, scene_player_data);\n        });\n    }\n\n    /**\n     Get all Scenes and convert them to dom objects returning a hash of object literals\n     @method getScenes\n     @return {Object} all scenes as objects\n     **/\n    getScenes() {\n        var scenes = {};\n        $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each((k, player_data_id) => {\n            var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n            var domPlayerData = $.parseXML(recPlayerData['player_data_value'])\n            scenes[recPlayerData['player_data_id']] = domPlayerData;\n        });\n        return scenes;\n    }\n\n    /**\n     Get Scene player record from player_data table\n     @method getScenePlayerRecord\n     @param {Number} i_sceneID\n     @return {Object} XML playerdata\n     **/\n    getScenePlayerRecord(i_scene_id) {\n        return this.databaseManager.table_player_data().getRec(i_scene_id);\n    }\n\n    // /**\n    //  Announce via event that a template view (screen layout) has been edited\n    //  @method announceTemplateViewerEdited\n    //  @param {Number} i_campaign_timeline_board_template_id\n    //  **/\n    // announceTemplateViewerEdited(i_campaign_timeline_board_template_id) {\n    //     // this.databaseManager.fire(Pepper['TEMPLATE_VIEWER_EDITED'], this, null, i_campaign_timeline_board_template_id);\n    // }\n\n    /**\n     Get the first board_id (output) that is assigned to the specified campaign_id\n     @method getFirstBoardIDofCampaign\n     @param {Number} i_campaign_id\n     @return {Number} foundBoardID of the board, or -1 if none found\n     **/\n    getFirstBoardIDofCampaign(i_campaign_id) {\n        var totalBoardsFound = 0;\n        var foundCampainBoardID = -1;\n        $(this.databaseManager.table_campaign_boards().getAllPrimaryKeys()).each((k, campaign_board_id) => {\n            var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(campaign_board_id);\n            if (i_campaign_id == recCampaignBoard.campaign_id && totalBoardsFound == 0) {\n                foundCampainBoardID = recCampaignBoard['campaign_board_id']\n                totalBoardsFound++;\n            }\n        });\n        return foundCampainBoardID;\n    }\n\n    /**\n     Get a campaign_board into it's matching pair in global boards.\n     @method getBoardFromCampaignBoard\n     @param {Number} i_campaign_board_id\n     @return {Number} board_id\n     **/\n    getBoardFromCampaignBoard(i_campaign_board_id) {\n        var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(i_campaign_board_id);\n        return recCampaignBoard.board_id;\n    }\n\n    /**\n     Get i_campaign_board_id into campaign_id using local table_campaign_boards (not global boards)\n     @method getCampaignIdFromCampaignBoardId\n     @param {Number} i_campaign_board_id\n     @return {Number} campaign_id\n     **/\n    getCampaignIdFromCampaignBoardId(i_campaign_board_id) {\n\n        var recCampaignBoard = this.databaseManager.table_campaign_boards().getRec(i_campaign_board_id);\n        return recCampaignBoard.campaign_id;\n    }\n\n    /**\n     get a Campaign's play mode (sceduler / sequencer) from timeline id\n     @method getCampaignPlayModeFromTimeline\n     @param {Number} i_campaign_timeline_id\n     @return {Number} play mode\n     **/\n    getCampaignPlayModeFromTimeline(i_campaign_timeline_id) {\n        var recTimeline = this.getCampaignTimelineRecord(i_campaign_timeline_id);\n        var campaign_id = recTimeline.campaign_id;\n        var recCampaign = this.getCampaignRecord(campaign_id);\n        return String(recCampaign['campaign_playlist_mode']);\n    }\n\n\n    /**\n     Get a Board Template Viewer props\n     @method getBoardTemplateViewer\n     @param {Number} i_board_template_viewer_id\n     @return {Number} i_props\n     **/\n    getBoardTemplateViewer(i_board_template_viewer_id) {\n\n        var recEditBoardTemplateViewer = this.databaseManager.table_board_template_viewers().getRec(i_board_template_viewer_id);\n        return {\n            x: recEditBoardTemplateViewer['pixel_x'],\n            y: recEditBoardTemplateViewer['pixel_y'],\n            w: recEditBoardTemplateViewer['pixel_width'],\n            h: recEditBoardTemplateViewer['pixel_height']\n        };\n    }\n\n    /**\n     Get campaign schedule for timeline\n     @method getCampaignsSchedules\n     @param {Number} i_campaign_timeline_id\n     @return {Object} schedule record\n     **/\n    getCampaignsSchedule(i_campaign_timeline_id) {\n\n        var found = -1;\n        $(this.databaseManager.table_campaign_timeline_schedules().getAllPrimaryKeys()).each(function (k, campaign_timeline_schedule_id) {\n            var recCampaignTimelineSchedule = this.databaseManager.table_campaign_timeline_schedules().getRec(campaign_timeline_schedule_id);\n            if (recCampaignTimelineSchedule.campaign_timeline_id == i_campaign_timeline_id)\n                found = recCampaignTimelineSchedule;\n        });\n        return found;\n    }\n\n    /**\n     Get the timeline id of the specific sequencer index offset (0 based) under the specified campaign\n     @method getCampaignTimelineIdOfSequencerIndex\n     @param {Number} i_campaign_id\n     @param {Number} i_sequence_index\n     @return {Number} timeline_id\n     **/\n    getCampaignTimelineIdOfSequencerIndex(i_campaign_id, i_sequence_index) {\n\n        var timeline_id = -1;\n        $(this.databaseManager.table_campaign_timeline_sequences().getAllPrimaryKeys()).each(function (k, campaign_timeline_sequence_id) {\n            var recCampaignTimelineSequence = this.databaseManager.table_campaign_timeline_sequences().getRec(campaign_timeline_sequence_id);\n            var sequenceIndex = recCampaignTimelineSequence['sequence_index'];\n            if (sequenceIndex == i_sequence_index && i_campaign_id == recCampaignTimelineSequence['campaign_id'])\n                timeline_id = recCampaignTimelineSequence['campaign_timeline_id']\n        });\n        return timeline_id;\n    }\n\n    /**\n     Get the sequence index of a timeline in the specified campaign\n     @method getCampaignTimelineSequencerIndex\n     @param {Number} i_campaign_timeline_id\n     @return {Number} sequenceIndex\n     **/\n    getCampaignTimelineSequencerIndex(i_campaign_timeline_id) {\n\n        var sequenceIndex = -1;\n\n        $(this.databaseManager.table_campaign_timeline_sequences().getAllPrimaryKeys()).each((k, campaign_timeline_sequence_id) => {\n            var recCampaignTimelineSequence = this.databaseManager.table_campaign_timeline_sequences().getRec(campaign_timeline_sequence_id);\n            if (recCampaignTimelineSequence['campaign_timeline_id'] == i_campaign_timeline_id) {\n                sequenceIndex = recCampaignTimelineSequence['sequence_index'];\n            }\n        });\n        return sequenceIndex;\n    }\n\n    /**\n     Get all none deleted (!=3) resources per current account\n     @method listenResources\n     @return {Array} all records of all resources in current account\n     **/\n    getResources() {\n        var resources = [];\n        $(this.databaseManager.table_resources().getAllPrimaryKeys()).each((k, resource_id) => {\n            var recResource = this.databaseManager.table_resources().getRec(resource_id);\n            // dont process deleted resources\n            if (recResource['change_type'] == 3)\n                return;\n            var resourceName = resources.push(recResource);\n        });\n        return resources;\n    }\n\n    /**\n     Get a resource record via its resource_id.\n     @method getResourceRecord\n     @param {Number} i_resource_id\n     @return {Object} foundResourceRecord\n     **/\n    getResourceRecord(i_resource_id) {\n        return this.databaseManager.table_resources().getRec(i_resource_id);\n    }\n\n    /**\n     Get the type of a resource (png/jpg...) for specified native_id\n     @method getResourceType\n     @param {Number} i_resource_id\n     @return {String} resourceType\n     **/\n    getResourceType(i_resource_id) {\n\n        var recResource = this.databaseManager.table_resources().getRec(i_resource_id);\n        return recResource['resource_type'];\n    }\n\n    /**\n     Get the native resource id from handle\n     @method getResourceNativeID\n     @param {Number} i_resource_id\n     @return {Number} nativeID\n     **/\n    getResourceNativeID(i_resource_id) {\n        var recResource = this.databaseManager.table_resources().getRec(i_resource_id);\n        if (_.isNull(recResource))\n            return null;\n        return recResource['native_id'];\n    }\n\n    /**\n     Get the name of a resource from the resources table using it's native_id\n     @method getResourceName\n     @param {Number} i_resource_id\n     @return {Number} resourceName\n     **/\n    getResourceName(i_resource_id) {\n\n        var recResource = this.databaseManager.table_resources().getRec(i_resource_id);\n        return recResource['resource_name'];\n    }\n\n    /**\n     Get a campaign table record for the specified i_campaign_id.\n     @method getCampaignRecord\n     @param {Number} i_campaign_id\n     @return {Object} foundCampaignRecord\n     **/\n    getCampaignRecord(i_campaign_id) {\n\n        return this.databaseManager.table_campaigns().getRec(i_campaign_id);\n    }\n\n    /**\n     Sync to pepper and get station name for station id, callback on server sync return\n     @method getStationNameAsync\n     @param {Number} i_stationID\n     @param {Number} i_callBack\n     **/\n    getStationNameAsync(i_stationID, i_callBack) {\n        this.sync(function () {\n            $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each(function (k, branch_station_id) {\n                var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                if (recBranchStation['native_id'] == i_stationID) {\n                    i_callBack(recBranchStation['station_name'])\n                }\n            });\n        });\n    }\n\n    /**\n     Total branch stations\n     **/\n    getStationBranchTotal() {\n        return this.databaseManager.table_branch_stations().getAllPrimaryKeys().length;\n    }\n\n    /**\n     Get station name from sdk (no remote server async)\n     @method getStationNameSync\n     @param {Number} i_stationID\n     @return {String} stationName\n     **/\n    getStationNameSync(i_stationID) {\n        var stationName = '';\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each(function (k, branch_station_id) {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_stationID) {\n                var recBranch = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                stationName = recBranch['station_name'];\n            }\n        });\n        return stationName;\n    }\n\n    /**\n     Get station name from sdk (no remote server async)\n     @method getAdPackContNames\n     @param {Number} i_ad_local_content_id\n     @return {Object}\n     **/\n    getAdPackContNames(i_ad_local_content_id) {\n\n        var result = {\n            contentName: '',\n            packageName: ''\n        };\n        $(this.databaseManager.table_ad_local_contents().getAllPrimaryKeys()).each(function (k, ad_local_content_id) {\n            var recAdLocalContent = this.databaseManager.table_ad_local_contents().getRec(ad_local_content_id);\n            if (recAdLocalContent.native_id == i_ad_local_content_id) {\n                var recAdLocalPackage = this.databaseManager.table_ad_local_packages().getRec(recAdLocalContent.ad_local_package_id);\n                result = {\n                    contentName: recAdLocalContent.content_name,\n                    packageName: recAdLocalPackage.package_name\n                };\n            }\n        });\n        return result;\n    }\n\n    /**\n     Returns the campaign id that a station is bound to\n     @method getStationCampaignID\n     @param {Number} i_native_station_id\n     @return {Number} campaign_id\n     **/\n    getStationCampaignID(i_native_station_id) {\n\n        var campaignID = -1;\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each(function (k, branch_station_id) {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                var campaign_board_id = recBranchStation['campaign_board_id'];\n                campaignID = this.getCampaignIdFromCampaignBoardId(campaign_board_id);\n            }\n        });\n        return campaignID;\n    }\n\n    /**\n     Set a station record via object arg into sdk table_branch_stations\n     @method getStationRecord\n     @param {Number} i_native_station_id\n     @param {Object} record\n     **/\n    setStationRecord(i_native_station_id, i_record) {\n\n        var record;\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each(function (k, branch_station_id) {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                this.databaseManager.table_branch_stations().openForEdit(branch_station_id);\n                var recBranchStationEdit = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                recBranchStationEdit = i_record;\n            }\n        });\n    }\n\n\n    /**\n     Set a station to server mode enable / disable\n     @method setStationServerMode\n     @param {Number} i_native_station_id\n     @param {Boolean} i_mode\n     **/\n    setStationServerMode(i_native_station_id, i_enabled, i_lan_server_ip, i_port) {\n\n        $(this.databaseManager.table_branch_stations().getAllPrimaryKeys()).each(function (k, branch_station_id) {\n            var recBranchStation = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n            if (recBranchStation['native_id'] == i_native_station_id) {\n                this.databaseManager.table_branch_stations().openForEdit(branch_station_id);\n                var recBranchStationEdit = this.databaseManager.table_branch_stations().getRec(branch_station_id);\n                recBranchStationEdit.lan_server_enabled = i_enabled;\n                recBranchStationEdit.lan_server_port = i_port;\n                recBranchStationEdit.lan_server_ip = i_lan_server_ip;\n            }\n        });\n    }\n\n    /**\n     Upload new resources onto the remote server and return matching ids.\n     The element id is of an HTML id of a multi-part upload element.\n     @method uploadResources\n     @param {String} i_elementID\n     @return {Array} list of resources created from newly attached files or empty array if not valid resource loaded\n     **/\n    uploadResources(i_elementID, i_bs: BlockService) {\n        var i_uploadFileElement: any = document.getElementById(i_elementID);\n        var count = i_uploadFileElement.files.length;\n        for (var iFile = 0; iFile < count; iFile++) {\n            var fileName = i_uploadFileElement.files[iFile];\n            var fileExtension = fileName.name.split('.')[1].toLowerCase();\n            var block = i_bs.getBlockCodeFromFileExt(fileExtension);\n            if (block == -1)\n                return [];\n        }\n        var resourceList = this.loaderManager.createResources(document.getElementById(i_elementID));\n        // BB.comBroker.fire('EVENTS.ADDED_RESOURCE');\n        return resourceList;\n    }\n\n\n    /**\n     Get a timeline's duration which is set as the total sum of all blocks within the longest running channel\n     @method getTimelineTotalDuration\n     @param {Number} i_campaign_timeline_id\n     @return {Number} length in seconds\n     **/\n    getTimelineTotalDuration(i_campaign_timeline_id) {\n\n        var recCampaignTimeline = this.databaseManager.table_campaign_timelines().getRec(i_campaign_timeline_id);\n        if (!recCampaignTimeline)\n            return 0;\n        return recCampaignTimeline['timeline_duration'];\n    }\n\n    /**\n     Get the total duration in seconds of all given block ids\n     @method getTotalDurationOfBlocks\n     @param {Array} i_blocks\n     @return {Number} totalChannelLength\n     **/\n    getTotalDurationOfBlocks(i_blocks) {\n\n        var totalChannelLength = 0;\n\n        for (var i = 0; i < i_blocks.length; i++) {\n            var block_id = i_blocks[i];\n            $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_player_id) {\n                if (block_id == campaign_timeline_chanel_player_id) {\n                    var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n                    var playerDuration = recCampaignTimelineChannelPlayer['player_duration']\n                    this.databaseManager.table_campaign_timeline_chanel_players().openForEdit(campaign_timeline_chanel_player_id);\n                    // console.log('player ' + block_id + ' offset ' + totalChannelLength + ' playerDuration ' + playerDuration);\n                    totalChannelLength = totalChannelLength + parseFloat(playerDuration);\n                }\n            });\n        }\n        return totalChannelLength;\n    }\n\n    /**\n     Get a block's (a.k.a player) total hours / minutes / seconds playback length on the timeline_channel.\n     @method getBlockTimelineChannelBlockLength\n     @param {Number} i_campaign_timeline_chanel_player_id\n     @return {Object} playbackLength as a json object with keys of hours minutes seconds\n     **/\n    getBlockTimelineChannelBlockLength(i_campaign_timeline_chanel_player_id) {\n\n        var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(i_campaign_timeline_chanel_player_id);\n        var totalSeconds = recCampaignTimelineChannelPlayer['player_duration'];\n        return this.formatSecondsToObject(totalSeconds);\n    }\n\n    /**\n     Format an object to seconds\n     @method formatObjectToSeconds\n     @param {Object} i_object with hours minutes and seconds key / values\n     @return {Number}\n     **/\n    formatObjectToSeconds(i_object) {\n        var seconds = i_object.seconds;\n        var minutes = i_object.minutes;\n        var hours = i_object.hours;\n        hours = hours * 3600;\n        minutes = minutes * 60;\n        return seconds + minutes + hours;\n    }\n\n    /**\n     Format a seconds value into an object broken into hours / minutes / seconds\n     @method formatSecondsToObject\n     @param {Number} i_totalSeconds\n     @return {Object}\n     **/\n    formatSecondsToObject(i_totalSeconds) {\n        var seconds: any = 0;\n        var minutes: any = 0;\n        var hours: any = 0;\n        var totalInSeconds = i_totalSeconds;\n        if (i_totalSeconds >= 3600) {\n            hours = Math.floor(i_totalSeconds / 3600);\n            i_totalSeconds = i_totalSeconds - (hours * 3600);\n        }\n        if (i_totalSeconds >= 60) {\n            minutes = Math.floor(i_totalSeconds / 60);\n            seconds = i_totalSeconds - (minutes * 60);\n        }\n        if (hours == 0 && minutes == 0)\n            seconds = i_totalSeconds;\n        var playbackLength = {\n            hours: parseInt(hours),\n            minutes: parseInt(minutes),\n            seconds: parseInt(seconds),\n            totalInSeconds: parseInt(totalInSeconds)\n        };\n        return playbackLength;\n    }\n\n    /**\n     Get a player_id record from sdk by player_id primary key.\n     @method getCampaignTimelineChannelPlayerRecord\n     @param {Number} i_player_id\n     @return {Object} player record\n     **/\n    getCampaignTimelineChannelPlayerRecord(i_player_id) {\n        return this.databaseManager.table_campaign_timeline_chanel_players().getRec(i_player_id);\n    }\n\n    /**\n     Get a block's record using it's block_id\n     @method getBlockRecord\n     @param {Object} i_block_id\n     @return {Object} recBlock\n     **/\n    getBlockRecord(i_block_id) {\n        return this.databaseManager.table_campaign_timeline_chanel_players().getRec(i_block_id);\n    }\n\n    /**\n     Get a channel_id record from table channels sdk by channel_id\n     @method getCampaignTimelineChannelRecord\n     @param {Number} i_channel_id\n     @return {Object} channel record\n     **/\n    getCampaignTimelineChannelRecord(i_channel_id) {\n\n        return this.databaseManager.table_campaign_timeline_chanels().getRec(i_channel_id);\n    }\n\n    /**\n     Get a timeline record from sdk using i_campaign_timeline_id primary key.\n     @method getCampaignTimelineRecord\n     @param {Number} i_campaign_timeline_id\n     @return {Object} player record\n     **/\n    getCampaignTimelineRecord(i_campaign_timeline_id) {\n\n        return this.databaseManager.table_campaign_timelines().getRec(i_campaign_timeline_id);\n    }\n\n    /**\n     Build screenProps json object with all viewers and all of their respective attributes for the given timeline_id / template_id\n     @method getTemplateViewersScreenProps\n     @param {Number} i_campaign_timeline_id\n     @param {Number} i_campaign_timeline_board_template_id\n     @return {Object} screenProps all viewers and all their properties\n     **/\n    getTemplateViewersScreenProps(i_campaign_timeline_id, i_campaign_timeline_board_template_id) {\n\n        var counter = -1;\n        var screenProps = {};\n        var viewOrderIndexes = {};\n        $(this.databaseManager.table_campaign_timeline_board_viewer_chanels().getAllPrimaryKeys()).each(function (k, campaign_timeline_board_viewer_chanel_id) {\n\n            var recCampaignTimelineBoardViewerChanel = this.databaseManager.table_campaign_timeline_board_viewer_chanels().getRec(campaign_timeline_board_viewer_chanel_id);\n            if (recCampaignTimelineBoardViewerChanel['campaign_timeline_board_template_id'] == i_campaign_timeline_board_template_id) {\n                var recBoardTemplateViewer = this.databaseManager.table_board_template_viewers().getRec(recCampaignTimelineBoardViewerChanel['board_template_viewer_id']);\n                // console.log(i_campaign_timeline_board_template_id + ' ' + recBoardTemplateViewer['board_template_viewer_id']);\n                counter++;\n                screenProps['sd' + counter] = {};\n                screenProps['sd' + counter]['campaign_timeline_board_viewer_id'] = recBoardTemplateViewer['board_template_viewer_id'];\n                screenProps['sd' + counter]['campaign_timeline_id'] = i_campaign_timeline_id;\n                screenProps['sd' + counter]['x'] = recBoardTemplateViewer['pixel_x'];\n                screenProps['sd' + counter]['y'] = recBoardTemplateViewer['pixel_y'];\n                screenProps['sd' + counter]['w'] = recBoardTemplateViewer['pixel_width'];\n                screenProps['sd' + counter]['h'] = recBoardTemplateViewer['pixel_height'];\n\n                // make sure that every view_order we assign is unique and sequential\n                var viewOrder = recBoardTemplateViewer['viewer_order'];\n                if (!_.isUndefined(viewOrderIndexes[viewOrder])) {\n                    for (var i = 0; i < 100; i++) {\n                        if (_.isUndefined(viewOrderIndexes[i])) {\n                            viewOrder = i;\n                            break;\n                        }\n                    }\n                }\n                viewOrderIndexes[viewOrder] = true;\n                screenProps['sd' + counter]['view_order'] = viewOrder;\n            }\n        });\n\n        return screenProps;\n    }\n\n    /**\n     Set a timeline records in sdk using i_campaign_timeline_id primary key.\n     The method uses generic key / value fields so it can set any part of the record.\n     @method setCampaignTimelineRecord\n     @param {number} i_player_id\n     @param {string} i_key the key to set\n     @param {Object} i_value the value to set\n     @return none\n     **/\n    setCampaignTimelineRecord(i_campaign_timeline_id, i_key, i_value) {\n\n        this.databaseManager.table_campaign_timelines().openForEdit(i_campaign_timeline_id);\n        var recTimeline = this.databaseManager.table_campaign_timelines().getRec(i_campaign_timeline_id);\n        recTimeline[i_key] = i_value;\n    }\n\n    /**\n     Use a viewer_id to reverse enumerate over the mapping of viewers to channels via:\n     campaign_timeline_viewer_chanels -> table_campaign_timeline_chanels\n     so we can find the channel assigned to the viewer_id provided.\n     @method getChannelIdFromCampaignTimelineBoardViewer\n     @param {Number} i_campaign_timeline_board_viewer_id\n     @param {Number} i_campaign_timeline_id\n     @return {Object} recCampaignTimelineViewerChanelsFound\n     **/\n    getChannelIdFromCampaignTimelineBoardViewer(i_campaign_timeline_board_viewer_id, i_campaign_timeline_id) {\n\n\n        var recCampaignTimelineViewerChanelsFound = undefined;\n\n        $(this.databaseManager.table_campaign_timeline_board_viewer_chanels().getAllPrimaryKeys()).each(function (k, campaign_timeline_board_viewer_chanel_id) {\n            var recCampaignTimelineViewerChanels = this.databaseManager.table_campaign_timeline_board_viewer_chanels().getRec(campaign_timeline_board_viewer_chanel_id);\n\n            // if true, we found the viewer selected under table campaign_timeline_viewer_chanels\n            if (recCampaignTimelineViewerChanels['board_template_viewer_id'] == i_campaign_timeline_board_viewer_id) {\n\n                $(this.databaseManager.table_campaign_timeline_chanels().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_id) {\n                    var recCampaignTimelineChannel = this.databaseManager.table_campaign_timeline_chanels().getRec(campaign_timeline_chanel_id);\n\n                    // if true, we found the channel the viewer was assined to as long as it is part of the current selected timeline\n                    if (recCampaignTimelineViewerChanels['campaign_timeline_chanel_id'] == campaign_timeline_chanel_id && recCampaignTimelineChannel['campaign_timeline_id'] == i_campaign_timeline_id) {\n                        // console.log('selected: timeline_id ' + i_campaign_timeline_id + ' view_id ' + i_campaign_timeline_board_viewer_id + ' on channel_id ' + recCampaignTimelineViewerChanels['campaign_timeline_chanel_id']);\n                        recCampaignTimelineViewerChanelsFound = recCampaignTimelineViewerChanels;\n                    }\n                });\n            }\n        });\n\n        return recCampaignTimelineViewerChanelsFound;\n    }\n\n    /**\n     Sample function to demonstrate how to enumerate over records to query for specified template_id\n     @method populateBoardTemplate\n     @param {Number} i_campaign_timeline_board_template_id\n     @return none\n     **/\n    populateBoardTemplate(i_campaign_timeline_board_template_id) {\n\n\n        var recCampaignTimelineBoardTemplate = this.databaseManager.table_campaign_timeline_board_templates().getRec(i_campaign_timeline_board_template_id);\n\n        // Get global board > board template so we can get the total width / height resolution of the board\n\n        var recBoardTemplate = this.databaseManager.table_board_templates().getRec(recCampaignTimelineBoardTemplate['board_template_id']);\n        var recBoard = this.databaseManager.table_boards().getRec(recBoardTemplate['board_id']);\n\n        $(this.databaseManager.table_campaign_timeline_board_viewer_chanels().getAllPrimaryKeys()).each(function (k, campaign_timeline_board_viewer_chanel_id) {\n            var recCampaignTimelineBoardViewerChanel = this.databaseManager.table_campaign_timeline_board_viewer_chanels().getRec(campaign_timeline_board_viewer_chanel_id);\n            if (recCampaignTimelineBoardViewerChanel['campaign_timeline_board_template_id'] == i_campaign_timeline_board_template_id) {\n                var recBoardTemplateViewer = this.databaseManager.table_board_template_viewers().getRec(recCampaignTimelineBoardViewerChanel['board_template_viewer_id']);\n                // console.log(i_campaign_timeline_board_template_id);\n            }\n        });\n    }\n\n    /**\n     The jXML.Event constructor is exposed and can be used when calling trigger. The new operator is optional.\n     @method event\n     @param {Event} i_event\n     @param {Object} i_context\n     @param {Object} i_caller\n     @param {Object} i_data\n     @return none.\n\n     event (i_event, i_context, i_caller, i_data) {\n        return $.Event(i_event, {context: i_context, caller: i_caller, edata: i_data});\n    }\n     **/\n\n    /**\n     Sample function to demonstrate how to enumerate over records to query related tables of a campaign\n     @method populateBoardTemplate\n     @param {Number} i_campaign_timeline_board_template_id\n     @return none\n     **/\n    populateCampaign() {\n\n\n        // demo campaign_id\n        var campaign_id = 1;\n\n        // Get all timelines\n        $(this.databaseManager.table_campaign_timelines().getAllPrimaryKeys()).each(function (k, campaign_timeline_id) {\n\n            var recCampaignTimeline = this.databaseManager.table_campaign_timelines().getRec(campaign_timeline_id);\n\n            // if timeline belongs to selected campaign\n            if (recCampaignTimeline['campaign_id'] == campaign_id) {\n\n                // get all campaign timeline board templates (screen divison inside output, gets all outputs, in our case only 1)\n                $(this.databaseManager.table_campaign_timeline_board_templates().getAllPrimaryKeys()).each(function (k, table_campaign_timeline_board_template_id) {\n                    var recCampaignTimelineBoardTemplate = this.databaseManager.table_campaign_timeline_board_templates().getRec(table_campaign_timeline_board_template_id);\n                    if (recCampaignTimelineBoardTemplate['campaign_timeline_id'] == campaign_timeline_id) {\n                        // console.log(recCampaignTimelineBoardTemplate['campaign_timeline_id']);\n                        this._populateBoardTemplate(table_campaign_timeline_board_template_id);\n                    }\n                });\n\n                // get all channels that belong to timeline\n                $(this.databaseManager.table_campaign_timeline_chanels().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_id) {\n                    var recCampaignTimelineChannel = this.databaseManager.table_campaign_timeline_chanels().getRec(campaign_timeline_chanel_id);\n                    if (campaign_timeline_id == recCampaignTimelineChannel['campaign_timeline_id']) {\n\n                        // get all players / resources that belong timeline\n                        $(this.databaseManager.table_campaign_timeline_chanel_players().getAllPrimaryKeys()).each(function (k, campaign_timeline_chanel_player_id) {\n                            var recCampaignTimelineChannelPlayer = this.databaseManager.table_campaign_timeline_chanel_players().getRec(campaign_timeline_chanel_player_id);\n                            if (campaign_timeline_chanel_id == recCampaignTimelineChannelPlayer['campaign_timeline_chanel_id']) {\n                                console.log(campaign_timeline_chanel_player_id);\n                            }\n                        });\n                    }\n                });\n            }\n        });\n    }\n}\n\n// return {\n//     campaign_timeline_chanel_player_id: recTimelinePlayer['campaign_timeline_chanel_player_id'],\n//     campaign_timeline_chanel_player_data: recTimelinePlayer['player_data']\n// };\n// // pepper.fire(Pepper['NEW_PLAYER_CREATED'], self, null, returnData);"
  },
  {
    "path": "src/services/wizard-service.ts",
    "content": "import {Injectable, NgZone} from \"@angular/core\";\nimport {Router} from \"@angular/router\";\nimport {RedPepperService} from \"./redpepper.service\";\nimport {Lib} from \"../Lib\";\nimport {BLOCK_SERVICE, PLACEMENT_IS_SCENE} from \"../interfaces/Consts\";\nimport {BlockService} from \"../app/blocks/block-service\";\nimport {CommBroker, IMessage} from \"./CommBroker\";\nimport * as _ from 'lodash';\nimport {YellowPepperService} from \"./yellowpepper.service\";\n\nconst log = (i_msg) => {\n    console.log(i_msg)\n}\n\n@Injectable()\nexport class WizardService {\n    private m_enjoyHint: EnjoyHint;\n    private wizardSteps = [\n        {\n            \"click #newCampaign\": 'a quick 5 minute tutorial</text><br/>and we will teach you how to use StudioLite... its easy.',\n            \"skipButton\": {text: \"quit\"},\n            left: 10,\n            right: 10,\n            top: 6,\n            bottom: 6,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 1');\n            }\n        },\n        {\n            \"key #newCampaignName\": 'name your campaign, press [ENTER] when done</text><br/>this will become useful later<br/>when you assign your campaign to a remote screen<br/>(a screen is also referred to as a <u>station</u>)',\n            \"skipButton\": {text: \"quit\"},\n            keyCode: 13,\n            timeout: 500,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 2');\n            }\n        },\n        {\n            \"click #firstImage\": 'select your screen orientation, vertical or horizontal',\n            \"skipButton\": {text: \"quit\"},\n            timeout: 500,\n            left: -10,\n            margin: 10,\n            padding: 10,\n            debugInclude: true,\n            onBeforeStart: () => {\n                log('STEP 3');\n            }\n        },\n        {\n            \"click #resolutionList\": 'select your screen resolution',\n            \"skipButton\": {text: \"quit\"},\n            timeout: 1000,\n            bottom: 250,\n            margin: 0,\n            right: 500,\n            padding: 0,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 4');\n            }\n        },\n        {\n            selector: '#screenLayoutList',\n            event: \"click\",\n            description: 'select your screen layout</text><br/>Each screen division (area) will run some different content',\n            skipButton: {text: \"quit\"},\n            top: 0,\n            margin: 0,\n            right: 500,\n            left: 0,\n            bottom: 200,\n            padding: 0,\n            timeout: 1000,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 5');\n            }\n        },\n        {\n            \"next #screenSelectorContainer\": 'this is your Timelines</text><br/>you can create multiple timelines to play one after the other<br/>each timeline includes one or more channels',\n            timeout: 1500,\n            debugInclude: true,\n            \"skipButton\": {text: \"quit\"}\n        },\n        {\n            \"click #toggleStorylineCollapsible\": 'click to expand and see your timeline details</text><br/>',\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                //todo: fix\n                // BB.comBroker.getService(BB.SERVICES.STORYLINE).collapseStoryLine();\n                log('STEP 6');\n            }\n        },\n        {\n            \"next #storylineContainerCollapse\": 'these are your channels<br/></text>each channel is automatically assigned to one screen division<br/>right now your channels are empty (no fun)',\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 7');\n            }\n        },\n        {\n            \"click #selectNextChannel\": 'select next channel<br/></text>with this button you can simply cycle through all<br/>the channels of the currently selected timeline, its simple...',\n            \"skipButton\": {text: \"quit\"},\n            left: 6,\n            right: 6,\n            top: 6,\n            bottom: 6,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 8');\n            }\n        },\n        {\n            \"click #addBlockButton\": 'add content<br/></text>Click [+] to add content to your selected channel (and matching screen division)',\n            \"skipButton\": {text: \"quit\"},\n            left: 6,\n            right: 6,\n            top: 6,\n            bottom: 6,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 9');\n            }\n        },\n        {\n            event: \"click\",\n            skipButton: {text: \"quit\"},\n            selector: '#collapseOne',\n            description: 'select something to <br/></text>add such as images, videos and other files<br/>(later you can also upload file from your own PC)',\n            timeout: 1000,\n            padding: 15,\n            margin: 15,\n            bottom: 400,\n            top: 20,\n            left: 25,\n            right: 500,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 10');\n            }\n        },\n        {\n            \"click #campaignViewList\": 'now the resource has been added to the selected channel</text><br/>just go ahead and select it to load up its properties',\n            \"skipButton\": {text: \"quit\"},\n            timeout: 1500,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 12');\n            }\n        },\n        {\n            \"next #campaignPropsManager\": 'anytime you select anything in StudioLite,<br/>be sure to checkout the properties box<br/>on the right for additional options and settings',\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 13');\n            }\n        },\n        {\n            \"next #resourceLengthDuration\": 'resource duration<br/></text>like here, where you can set the playback duration<br/>of your currently selected resource',\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 14');\n            }\n        },\n        {\n            \"click #editScreenLayout\": 'edit your screen division layout<br/></text>use this button to edit your current screen layout',\n            \"skipButton\": {text: \"quit\"},\n            left: 6,\n            right: 6,\n            top: 6,\n            bottom: 6,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 15');\n            }\n        },\n        {\n            \"click #layoutEditorAddNew\": 'lets add a new screen division<br/></text>it will automatically be assigned a channel on your timeline',\n            \"skipButton\": {text: \"quit\"},\n            left: 8,\n            right: 8,\n            top: 6,\n            bottom: 6,\n            timeout: 1000,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 16');\n            }\n        },\n        {\n            \"next #screenLayoutEditorCanvasWrap\": 'position and size your new screen division',\n            \"skipButton\": {text: \"quit\"},\n            bottom: 20,\n            right: 100,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 17');\n            }\n        },\n        {\n            event: \"click\",\n            selector: '.openPropsButton',\n            \"skipButton\": {text: \"quit\"},\n            description: 'lets go back to the campaign editor',\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 18');\n            }\n        },\n        {\n            \"next #screenSelectorContainerCollapse\": 'good job, you just added a new timeline',\n            \"skipButton\": {text: \"quit\"},\n            timeout: 500,\n            bottom: 10,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 19');\n            }\n        },\n        {\n            event: \"click\",\n            selector: $('.fa-crosshairs', '#appWrapComp').parent(),\n            \"skipButton\": {text: \"quit\"},\n            description: 'mixing content</text><br/>sometimes you want to mix resources and components into a single screen division<br/>Scenes are perfect for that',\n            right: 10,\n            top: 6,\n            bottom: 10,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 20');\n            }\n        },\n        {\n            \"next #sceneSelection\": \"click next to create a new empty scene so we can edit it\",\n            \"skipButton\": {text: \"quit\"},\n            description: 'select a scene',\n            timeout: 1000,\n            debugInclude: true,\n            onBeforeStart: () => {\n                log('STEP 22');\n            }\n        },\n        {\n            event: \"click\",\n            selector: '.sceneAddNew',\n            \"skipButton\": {text: \"quit\"},\n            description: 'lets add a new resource or component to our scene',\n            right: 8,\n            left: 8,\n            top: 5,\n            bottom: 5,\n            timeout: 1500,\n            debugInclude: true,\n            onBeforeStart: () => {\n                this.zone.runOutsideAngular(() => {\n                    var player_data = this.m_blockService.getBlockBoilerplate('3510').getDefaultPlayerData(PLACEMENT_IS_SCENE);\n                    var sceneId = this.rp.createScene(player_data, '', 'blank scene');\n                    this.rp.reduxCommit();\n                    setTimeout(() => {\n                        $('.appList').find('a').last().find('h4').click()\n                    }, 1)\n                })\n                log('STEP 23');\n            }\n        },\n        // {\n        //     event: \"click\",\n        //     selector: '#addComponentBlockList',\n        //     \"skipButton\": {text: \"quit\"},\n        //     description: 'select a smart component',\n        //     timeout: 2000,\n        //     right: 300,\n        //     left: 50,\n        //     top: 175,\n        //     debugInclude: true,\n        //     onBeforeStart: function () {\n        //         log('STEP 24');\n        //         // $('#sceneAddNewBlock').find('[data-toggle]').trigger('click');\n        //         // $('.primeComponent').closest('.addBlockListItems').hide();\n        //         // $('#addResourcesBlockListContainer', '#sceneAddNewBlock').hide();\n        //     }\n        // },\n        {\n            \"next #sceneCanvas\": 'you can edit your scene,</text><br/>position your content<br/>anywhere you like, resize it and change any of the properties',\n            event: \"next\",\n            timeout: 300,\n            bottom: 200,\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 25');\n            }\n        },\n        // {\n        //     event: \"click\",\n        //     selector: '.sceneAddNew',\n        //     \"skipButton\": {text: \"quit\"},\n        //     description: 'lets add another resource',\n        //     right: 8,\n        //     left: 8,\n        //     top: 5,\n        //     bottom: 5,\n        //     timeout: 300,\n        //     debugInclude: true,\n        //     onBeforeStart: function () {\n        //         log('STEP 26');\n        //     }\n        // },\n        // {\n        //     event: \"click\",\n        //     selector: '#sceneAddNewBlock',\n        //     \"skipButton\": {text: \"quit\"},\n        //     description: 'select a smart component',\n        //     timeout: 500,\n        //     right: 300,\n        //     left: 50,\n        //     top: 175,\n        //     debugInclude: true,\n        //     onBeforeStart: function () {\n        //         log('STEP 27');\n        //         $('#sceneAddNewBlock').find('[data-toggle]').trigger('click');\n        //         $('#addResourcesBlockListContainer', '#sceneAddNewBlock').show();\n        //         $('#addComponentsBlockListContainer', '#sceneAddNewBlock').hide();\n        //         $('.primeComponent').closest('.addBlockListItems').hide();\n        //     }\n        // },\n        // {\n        //     \"next #sceneCanvas\": 'again position and resize the resource',\n        //     event: \"next\",\n        //     timeout: 300,\n        //     bottom: 200,\n        //     \"skipButton\": {text: \"quit\"},\n        //     debugInclude: true,\n        //     onBeforeStart: function () {\n        //         log('STEP 28');\n        //     }\n        // },\n        {\n            event: \"click\",\n            selector: $('.fa-navicon', '#appWrapComp').parent(),\n            \"skipButton\": {text: \"quit\"},\n            description: 'go back to campaigns<br/></text>so we can assign our newly created scene<br/>to any timeline and channel we like',\n            right: 10,\n            left: 6,\n            top: 10,\n            timeout: 1000,\n            bottom: 10,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 29');\n            }\n        },\n        {\n            \"click .appList\": 'select a campaign',\n            \"skipButton\": {text: \"quit\"},\n            right: 100,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 30');\n            }\n        },\n        {\n            left: 10,\n            right: 10,\n            timeout: 1000,\n            \"click #selectNextChannel\": 'select the next channel',\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 31');\n            }\n        },\n        {\n            \"click #addBlockButton\": 'now lets add our scene to this channel',\n            left: 6,\n            right: 6,\n            top: 6,\n            bottom: 6,\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 32');\n                // $('#addResourcesBlockListContainer').find('[data-toggle]').trigger('click');\n            }\n        },\n        {\n            event: \"click\",\n            \"skipButton\": {text: \"quit\"},\n            selector: '#addComponentBlockList',\n            description: 'select your item<br/></text>it will automatically get added to<br/>your selected channel',\n            timeout: 1500,\n            padding: 15,\n            margin: 15,\n            right: 500,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 33');\n            }\n        },\n        {\n            event: \"click\",\n            selector: $('.fa-rocket', '#appWrapComp').parent(),\n            \"skipButton\": {text: \"quit\"},\n            timeout: 600,\n            description: 'next lets switch to Install',\n            right: 10,\n            top: 10,\n            bottom: 10,\n            hideInEnterprise: true,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 35');\n            }\n        },\n        {\n            \"next #installPanel\": 'install SignagePlayer</text><br/>now you need to register a physical player<br/>and connect it to any type of screen you like',\n            hideInEnterprise: true,\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            bottom: 100,\n            onBeforeStart: function () {\n                log('STEP 36');\n            }\n        },\n        {\n            \"next #installPanel\": 'choose an OS</text><br/>you can pick from Android, Windows or even order our hardware (recommended)<br/>as it comes plug and play ready to impress your audience',\n            \"skipButton\": {text: \"quit\"},\n            hideInEnterprise: true,\n            debugInclude: true,\n            bottom: 100,\n            onBeforeStart: function () {\n                log('STEP 37');\n            }\n        },\n        {\n            event: \"click\",\n            selector: $('.fa-laptop', '#appWrapComp').parent(),\n            \"skipButton\": {text: \"quit\"},\n            timeout: 600,\n            top: 10,\n            bottom: 10,\n            description: 'now lets switch to stations',\n            right: 10,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 38');\n            }\n        },\n        {\n            \"next #stationsPanel\": 'station management</text><br/>here you manage remote screens<br/>(stations) and assign them any campaign you like',\n            timeout: 600,\n            \"skipButton\": {text: \"quit\"},\n            bottom: 400,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 39');\n            }\n        },\n        {\n            event: \"click\",\n            selector: $('.fa-heart', '#appWrapComp').parent(),\n            \"skipButton\": {text: \"quit\"},\n            timeout: 600,\n            description: 'switch into help, we are almost done',\n            right: 10,\n            top: 10,\n            bottom: 10,\n            hideInEnterprise: true,\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 40');\n            }\n        },\n        {\n            \"next #helpPanel\": 'here you will find video tutorials for additional help',\n            timeout: 200,\n            hideInEnterprise: true,\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 41');\n            }\n        },\n        {\n            \"next #helpPanel\": 'well done!</text><br/>give yourself a pat on the back',\n            timeout: 200,\n            \"skipButton\": {text: \"quit\"},\n            debugInclude: true,\n            onBeforeStart: function () {\n                log('STEP 42');\n                setTimeout(function () {\n                    $('#enjoyhint_arrpw_line').fadeOut();\n                }, 1000);\n            }\n        }\n    ];\n    private width: 0;\n    private height: 0;\n    m_blockService: BlockService;\n\n    constructor(private router: Router, private rp: RedPepperService, private zone: NgZone, private commBroker: CommBroker, private yp: YellowPepperService) {\n        this.m_blockService = this.commBroker.getService(BLOCK_SERVICE)\n        this.zone.runOutsideAngular(()=>{\n            this._listenAppResized();\n        })\n        // if (Lib.DevMode()) {\n        //     setTimeout(() => {\n        //         this.start();\n        //     }, 2000)\n        // }\n    }\n\n    /**\n     Listen to when the app is resized so we can re-render\n     @method _listenAppResized\n     **/\n    _listenAppResized() {\n        this.yp.listenAppSizeChanged()\n            .subscribe((size: Map<any, any>) => {\n                this.width = size.get('width');\n                this.height = size.get('height');\n                if (this.m_enjoyHint){\n                    this.m_enjoyHint.trigger('skip');\n                    this.m_enjoyHint.end();\n                }\n\n            }, (e) => console.error(e));\n    }\n\n    public start() {\n        if (this.width < 1535 || this.height < 820)\n            return bootbox.alert('Your browser window is too small to run the wizard');\n\n        this.zone.runOutsideAngular(() => {\n            this.m_enjoyHint = new EnjoyHint({\n                onStart: () => {\n                },\n                onEnd: () => {\n                    this.m_enjoyHint = null;\n                    this\n                },\n                onSkip: () => {\n                    this.m_enjoyHint = null;\n                }\n            });\n            if (this.rp.getUserData().resellerID != 1) {\n                _.forEach(this.wizardSteps, (item: any, index) => {\n                    if (item.hideInEnterprise == true) {\n                        this.wizardSteps = _.without(this.wizardSteps, item);\n                    }\n                });\n            }\n\n            if (Lib.DevMode()) {\n                _.forEach(this.wizardSteps, (item: any, index) => {\n                    if (!item.debugInclude) {\n                        this.wizardSteps = _.without(this.wizardSteps, item);\n                    }\n                });\n            }\n\n            var self = this;\n            this.zone.runOutsideAngular(() => {\n                this.m_enjoyHint.set(self.wizardSteps);\n                this.m_enjoyHint.run();\n            })\n        })\n    }\n\n\n}"
  },
  {
    "path": "src/services/yellowpepper.service.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {Action, Store} from \"@ngrx/store\";\nimport {ApplicationState} from \"../store/application.state\";\nimport {Observable} from \"rxjs\";\nimport {BranchStationsModelExt, CampaignsModelExt, PlayerDataModelExt} from \"../store/model/msdb-models-extended\";\nimport {\n    BoardsModel,\n    BoardTemplatesModel,\n    BoardTemplateViewersModel, CampaignBoardsModel,\n    CampaignTimelineBoardTemplatesModel,\n    CampaignTimelineBoardViewerChanelsModel,\n    CampaignTimelineChanelPlayersModel,\n    CampaignTimelineChanelsModel,\n    CampaignTimelineSchedulesModel,\n    CampaignTimelineSequencesModel,\n    CampaignTimelinesModel,\n    PlayerDataModel,\n    ResourcesModel\n} from \"../store/imsdb.interfaces_auto\";\nimport {OrientationEnum} from \"../app/campaigns/campaign-orientation\";\nimport {List} from \"immutable\";\nimport * as _ from \"lodash\";\nimport {UserModel} from \"../models/UserModel\";\nimport * as X2JS from \"x2js\"\nimport {ISceneData} from \"../app/blocks/block-service\";\nimport {IScreenTemplateData} from \"../interfaces/IScreenTemplate\";\nimport {LocationMarkModel} from \"../models/LocationMarkModel\";\nimport {StationModel} from \"../models/StationModel\";\nimport {FasterqLineModel} from \"../models/fasterq-line-model\";\nimport {FasterqAnalyticsModel} from \"../models/fasterq-analytics\";\nimport {FasterqQueueModel} from \"../models/fasterq-queue-model\";\nimport {EmptyObservable} from \"rxjs/observable/EmptyObservable\";\n\n//// import X2JS from \"x2js\";\n//// import \"x2js\";\n\n@Injectable()\nexport class YellowPepperService {\n\n    parser;\n\n    constructor(private store: Store<ApplicationState>) {\n        this.parser = new X2JS({\n            escapeMode: true,\n            attributePrefix: \"_\",\n            arrayAccessForm: \"none\",\n            emptyNodeForm: \"text\",\n            enableToStringFunc: true,\n            arrayAccessFormPaths: [],\n            skipEmptyTextNodesForObj: true\n        });\n    }\n\n    public dispatch(action: Action) {\n        this.store.dispatch(action);\n    }\n\n    public get ngrxStore(): Store<ApplicationState> {\n        return this.store;\n    }\n\n    private reducePlayerDataModelsToSceneData(playerDataModels: List<PlayerDataModel>): Array<ISceneData> {\n        return playerDataModels.reduce((result: Array<ISceneData>, playerDataModel: PlayerDataModelExt) => {\n            var playerDataId = playerDataModel.getPlayerDataId();\n            var xml = playerDataModel.getPlayerDataValue();\n            var domPlayerData = $.parseXML(xml)\n            var scene_id_pseudo_id = $(domPlayerData).find('Player').eq(0).attr('id')\n            result.push({\n                scene_id: playerDataId,\n                scene_id_pseudo_id: scene_id_pseudo_id,\n                scene_native_id: playerDataModel.getNativeId,\n                block_pseudo_id: scene_id_pseudo_id,\n                domPlayerData: domPlayerData,\n                playerDataModel: playerDataModel,\n                domPlayerDataXml: xml,\n                domPlayerDataJson: this.parser.xml2js(xml),\n            });\n            return result;\n        }, [])\n    }\n\n    listenMainAppState() {\n        return this.store.select(store => store.appDb.uiState.mainAppState)\n    }\n\n    listenStoryBoardListViewModeSelected() {\n        return this.store.select(store => store.appDb.uiState.campaign.storyBoardListViewModeSelected)\n    }\n\n    /**\n     Listen to when a campaign timeline channel is selected\n     **/\n    listenChannelSelected(emitOnEmpty: boolean = false): Observable<CampaignTimelineChanelsModel> {\n        var channelSelected$ = this.store.select(store => store.appDb.uiState.campaign.campaignTimelineChannelSelected);\n        var channelsList$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanels);\n        return channelSelected$.withLatestFrom(\n            channelsList$,\n            (channelId, channels) => {\n                return channels.find((i_channel: CampaignTimelineChanelsModel) => {\n                    return i_channel.getCampaignTimelineChanelId() == channelId;\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Listen to campaign timeline channel block (player) is selected (via .withLatestFrom)\n     **/\n    listenBlockChannelSelected(emitOnEmpty: boolean = false): Observable<CampaignTimelineChanelPlayersModel> {\n        var blockSelected$ = this.store.select(store => store.appDb.uiState.campaign.blockChannelSelected);\n        var channelBlocksList$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players);\n        return blockSelected$.withLatestFrom(\n            channelBlocksList$,\n            (blockId, blocks) => {\n                return blocks.find((i_block: CampaignTimelineChanelPlayersModel) => {\n                    return i_block.getCampaignTimelineChanelPlayerId() == blockId\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Listen to campaign timeline channel block (player) is selected >>>OR<<< its value has changed in store slice (via .combineLatest)\n     **/\n    listenBlockChannelSelectedOrChanged(emitOnEmpty: boolean = false): Observable<CampaignTimelineChanelPlayersModel> {\n        var blockSelected$ = this.store.select(store => store.appDb.uiState.campaign.blockChannelSelected);\n        var channelBlocksList$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players);\n        return blockSelected$.combineLatest(\n            channelBlocksList$,\n            (blockId, blocks) => {\n                return blocks.find((i_block: CampaignTimelineChanelPlayersModel) => {\n                    return i_block.getCampaignTimelineChanelPlayerId() == blockId\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Listen to when a timeline is selected via the store state uiState.campaign.timelineSelected\n     **/\n    listenTimelineSelected(emitOnEmpty: boolean = false): Observable<CampaignTimelinesModel> {\n        var timelineSelected$ = this.store.select(store => store.appDb.uiState.campaign.timelineSelected);\n        var timelineList$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timelines);\n        return timelineSelected$\n            .withLatestFrom(\n                timelineList$,\n                (timelineId, timelines) => {\n                    return timelines.find((i_timeline: CampaignTimelinesModel) => {\n                        return i_timeline.getCampaignTimelineId() == timelineId;\n                    });\n                }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n\n    /**\n     Listen to changes in selected scene\n     **/\n    listenSelectedSceneChanged(emitOnEmpty: boolean = false): Observable<PlayerDataModelExt | PlayerDataModel> {\n        var sceneSelected = this.store.select(store => store.appDb.uiState.scene.sceneSelected);\n        var playerDataList$ = this.store.select(store => store.msDatabase.sdk.table_player_data);\n        return sceneSelected.combineLatest(\n            playerDataList$,\n            (sceneId, player_data) => {\n                return player_data.find((i_player: PlayerDataModelExt) => {\n                    return i_player.getPlayerDataId() == sceneId\n                });\n            }).distinct()\n            .mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     listen UI campaign > timeline > board_viewer selected and return back the associated channel with that board id\n     **/\n    listenCampaignTimelineBoardViewerSelected(emitOnEmpty: boolean = false): Observable<CampaignTimelineBoardViewerChanelsModel> {\n        var boardSelected$ = this.store.select(store => store.appDb.uiState.campaign.campaignTimelineBoardViewerSelected);\n        var $viewerChannels$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_board_viewer_chanels);\n        return boardSelected$\n            .withLatestFrom(\n                $viewerChannels$,\n                (boardId, viewerChannels) => {\n                    if (emitOnEmpty && (_.isUndefined(boardId) || boardId == -1)) {\n                        return null;\n                    }\n                    return viewerChannels.find((i_viewerChannel: CampaignTimelineBoardViewerChanelsModel) => {\n                        return i_viewerChannel.getBoardTemplateViewerId() == boardId;\n                    });\n                }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    listenLocationMapLoad(): Observable<any> {\n        return this.store.select(store => store.appDb.uiState.locationMap.loadLocationMap);\n    }\n\n    listenAppSizeChanged(): Observable<any> {\n        return this.store.select(store => store.appDb.uiState.appSized);\n    }\n\n    listenLocationMarkerSelected(): Observable<LocationMarkModel> {\n        return this.store.select(store => store.appDb.uiState.locationMap.locationMarkerSelected)\n            .filter(v => !_.isNull(v));\n    }\n\n\n    listenTimelineDurationChanged(emitOnEmpty: boolean = false): Observable<number> {\n        var $timelinesList$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timelines);\n        return this.listenCampaignSelected()\n            .combineLatest($timelinesList$, (campaign, timelines) => {\n                return campaign\n            }).mergeMap(campaign => {\n                return this.listenCampaignTimelines(campaign.getCampaignId())\n            }).mergeMap((i_timelines: List<CampaignTimelinesModel>) => {\n                var total = 0;\n                i_timelines.forEach((v) => {\n                    var t = parseInt(v.getTimelineDuration());\n                    total = total + t;\n                })\n                return Observable.of(total);\n            })\n    }\n\n    listenSelectedTimelineChanged(): Observable<CampaignTimelinesModel> {\n        var $timelinesList$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timelines);\n        return this.listenTimelineSelected()\n            .combineLatest($timelinesList$, (timeline:CampaignTimelinesModel, timelines:List<CampaignTimelinesModel>) => {\n                return timelines.find((i_timeline:CampaignTimelinesModel)=>{\n                    return i_timeline.getCampaignTimelineId() == timeline.getCampaignTimelineId();\n                })\n            })\n    }\n\n    listenUserModel(): Observable<UserModel> {\n        return this.store.select(store => store.appDb.userModel)\n            .filter((userModel) => !_.isUndefined(userModel.resellerId))\n    }\n\n    /**\n     listen to all timeline for specified campaign id\n     **/\n    listenCampaignTimelines(i_campaign_id: number): Observable<List<CampaignTimelinesModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timelines)\n            .map((campaignTimelinesModels: List<CampaignTimelinesModel>) => {\n                return campaignTimelinesModels.filter((campaignTimelinesModel: CampaignTimelinesModel) => {\n                    return campaignTimelinesModel.getCampaignId() == i_campaign_id;\n                }) as List<CampaignTimelinesModel>;\n            })\n    }\n\n    listenFasterqLineSelected(): Observable<FasterqLineModel> {\n        var selected$ = this.store.select(store => store.appDb.uiState.fasterq.fasterqLineSelected);\n        var lines$ = this.store.select(store => store.appDb.fasterq.lines);\n        return selected$\n            .combineLatest(lines$, (lineId, lines: List<FasterqLineModel>) => {\n                return lines.find((line: FasterqLineModel) => {\n                    return line.lineId == lineId;\n                });\n            }).filter(value => value != null);\n    }\n\n    listenFasterqQueueModelSelected(): Observable<FasterqQueueModel> {\n        var selected$ = this.store.select(store => store.appDb.uiState.fasterq.fasterqQueueSelected);\n        var queues$ = this.store.select(store => store.appDb.fasterq.queues);\n        return selected$\n            .combineLatest(queues$, (serviceId, queues: List<FasterqQueueModel>) => {\n                return queues.find((queue: FasterqQueueModel) => {\n                    return queue.serviceId == serviceId;\n                });\n            }).filter(value => value != null);\n    }\n\n    listenFasterqQueueSelected(): Observable<any> {\n        return this.store.select(store => store.appDb.uiState.fasterq.fasterqQueueSelected);\n    }\n\n    listenFasterqQueueLastServicedPolled(): Observable<any> {\n        return this.store.select(store => store.appDb.uiState.fasterq.fasterqNowServicing);\n    }\n\n    listenGlobalBoardSelectedChanged(emitOnEmpty: boolean = false): Observable<BoardTemplateViewersModel> {\n        var globalBoardTemplateViewerSelected$ = this.ngrxStore.select(store => store.appDb.uiState.campaign.campaignTimelineBoardViewerSelected);\n        var tableBoardTemplatesList$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_board_template_viewers);\n        return globalBoardTemplateViewerSelected$\n            .combineLatest(tableBoardTemplatesList$, (globalBoardTemplateViewerId: number, boards: List<BoardTemplateViewersModel>) => {\n                return boards.find((i_board: BoardTemplateViewersModel) => {\n                    return i_board.getBoardTemplateViewerId() == globalBoardTemplateViewerId;\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Listen to changes in selected scene\n     **/\n    listenSceneOrBlockSelected(emitOnEmpty: boolean = false): Observable<ISceneData> {\n        var sceneSelected$ = this.store.select(store => store.appDb.uiState.scene.sceneSelected);\n        var blockSelected$ = this.store.select(store => store.appDb.uiState.scene.blockSelected);\n        return blockSelected$.combineLatest(sceneSelected$, (blockId, sceneId) => {\n            return {blockId, sceneId}\n        }).filter((ids) => {\n            if (!emitOnEmpty) return true; // no filter requested\n            return ids && ids.blockId != -1\n        }).mergeMap(ids => {\n            return this.getScene(ids.sceneId)\n                .map((playerDataModel: PlayerDataModelExt) => {\n                    var domPlayerData = $.parseXML(playerDataModel.getPlayerDataValue())\n                    var selectedSnippet: any = $(domPlayerData).find(`[id=\"${ids.blockId}\"]`)[0];\n                    var mimeType = $(domPlayerData).find('Player').attr('mimeType');\n                    var xml = (new XMLSerializer()).serializeToString(selectedSnippet);\n                    selectedSnippet = $.parseXML(xml)\n                    var sceneData: ISceneData = {\n                        scene_id: ids.sceneId,\n                        scene_native_id: playerDataModel.getNativeId,\n                        scene_id_pseudo_id: null,\n                        block_pseudo_id: ids.blockId,\n                        playerDataModel: playerDataModel,\n                        domPlayerData: selectedSnippet,\n                        domPlayerDataXml: xml,\n                        domPlayerDataJson: this.parser.xml2js(xml),\n                        mimeType: mimeType\n                    }\n                    return sceneData;\n                });\n        }).distinct()\n            .mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Listen to changes in scene fabric scale changes\n     **/\n    listenFabricSceneScaled(): Observable<number> {\n        return this.store.select(store => store.appDb.uiState.scene.fabric.scale).map(v => {\n            return v;\n        })\n    }\n\n    /**\n     Get player_data via its scene id\n     **/\n    listenScene(scene_id): Observable<PlayerDataModel> {\n        return this.store.select(store => store.msDatabase.sdk.table_player_data)\n            .map((playerDataModels: List<PlayerDataModel>) => {\n                return playerDataModels.find((playerDataModel: PlayerDataModel) => {\n                    return scene_id == playerDataModel.getPlayerDataId();\n                })\n            })\n    }\n\n    /**\n     Listen to changes in selected scene\n     **/\n    listenSceneOrBlockSelectedChanged(): Observable<ISceneData> | Observable<{}> | EmptyObservable<any> { // <<< for TS 2.4.X\n    // listenSceneOrBlockSelectedChanged(): Observable<ISceneData> {\n        var sceneSelected$ = this.store.select(store => store.appDb.uiState.scene.sceneSelected);\n        var blockSelected$ = this.store.select(store => store.appDb.uiState.scene.blockSelected);\n        var player_data$ = this.store.select(store => store.msDatabase.sdk.table_player_data);\n        return blockSelected$.combineLatest(sceneSelected$, player_data$, (blockId, sceneId) => {\n            return {blockId, sceneId}\n        }).filter((ids) => {\n            return ids && ids.sceneId != -1 && ids.blockId != -1\n        }).mergeMap(ids => {\n\n            return this.listenScene(ids.sceneId)\n                .mergeMap((playerDataModel: PlayerDataModelExt) => {\n                    var domPlayerData = $.parseXML(playerDataModel.getPlayerDataValue())\n                    var selectedSnippet: any = $(domPlayerData).find(`[id=\"${ids.blockId}\"]`)[0];\n                    var sceneData: ISceneData;\n\n                    /** if block was removed notify of empty **/\n                    if (_.isUndefined(selectedSnippet))\n                        return Observable.empty()\n\n                    var mimeType = $(domPlayerData).find('Player').attr('mimeType');\n                    var xml = (new XMLSerializer()).serializeToString(selectedSnippet);\n                    selectedSnippet = $.parseXML(xml)\n                    sceneData = {\n                        scene_id: ids.sceneId,\n                        scene_native_id: playerDataModel.getNativeId,\n                        scene_id_pseudo_id: null,\n                        block_pseudo_id: ids.blockId,\n                        playerDataModel: playerDataModel,\n                        domPlayerData: selectedSnippet,\n                        domPlayerDataXml: xml,\n                        domPlayerDataJson: this.parser.xml2js(xml),\n                        mimeType: mimeType\n                    }\n                    return Observable.of(sceneData);\n                });\n        }).distinct()\n        // .mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    listenSceneSelected(emitOnEmpty: boolean = false): Observable<ISceneData> {\n        var sceneSelected$ = this.store.select(store => store.appDb.uiState.scene.sceneSelected);\n        return sceneSelected$\n            .filter(i_scene_id => {\n                if (!emitOnEmpty) return true; // no filter requested\n                return i_scene_id != -1;\n            })\n            .withLatestFrom(\n                this.listenScenes(),\n                (sceneId, scenes: Array<ISceneData>) => {\n                    return scenes.find((scene: ISceneData) => {\n                        return scene.scene_id == sceneId;\n                    });\n                }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Listen to ONLY when a campaign is selected via the store state uiState.campaign.campaignSelected and grab latest CampaignModel\n     **/\n    listenCampaignSelected(emitOnEmpty: boolean = false): Observable<CampaignsModelExt> {\n        var campaignSelected$ = this.store.select(store => store.appDb.uiState.campaign.campaignSelected);\n        var campaignsList$ = this.store.select(store => store.msDatabase.sdk.table_campaigns);\n        return campaignSelected$\n            .withLatestFrom(\n                campaignsList$,\n                (campaignId, campaigns) => {\n                    return campaigns.find((i_campaign: CampaignsModelExt) => {\n                        return i_campaign.getCampaignId() == campaignId;\n                    }) as CampaignsModelExt;\n                }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    listenChannelsOfTimeline(i_campaign_timeline_id): Observable<List<CampaignTimelineChanelsModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanels)\n            .map((i_campaignTimelineChanelsModels: List<CampaignTimelineChanelsModel>) => {\n                return i_campaignTimelineChanelsModels.filter(campaignTimelineChanelsModel => {\n                    return campaignTimelineChanelsModel.getCampaignTimelineId() == i_campaign_timeline_id;\n                }) as List<CampaignTimelineChanelsModel>\n            });\n    }\n\n    /**\n     Listen to when a channel that is selected changed value\n     **/\n    listenChannelValueChanged(emitOnEmpty: boolean = false): Observable<CampaignTimelineChanelsModel> {\n        var channelIdSelected$ = this.ngrxStore.select(store => store.appDb.uiState.campaign.campaignTimelineChannelSelected)\n        var channels$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_chanels);\n        return channelIdSelected$\n            .combineLatest(channels$, (channelId: number, channels: List<CampaignTimelineChanelsModel>) => {\n                return channels.find((i_channel: CampaignTimelineChanelsModel) => {\n                    return i_channel.getCampaignTimelineChanelId() == channelId;\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    listenResourceSelected(emitOnEmpty: boolean = false): Observable<ResourcesModel> {\n        var selected$ = this.store.select(store => store.appDb.uiState.resources.resourceSelected);\n        var resources$ = this.store.select(store => store.msDatabase.sdk.table_resources);\n        return selected$\n            .withLatestFrom(resources$, (resourceId, resources: List<ResourcesModel>) => {\n                return resources.find((resource: ResourcesModel) => {\n                    return resource.getResourceId() == resourceId;\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    listenStationSelected(): Observable<StationModel> {\n        var selected$ = this.store.select(store => store.appDb.uiState.stations.stationSelected);\n        var stations$ = this.store.select(store => store.appDb.stations);\n        return selected$\n            .combineLatest(stations$, (stationId, stations: List<StationModel>) => {\n                if (_.isUndefined(stations))\n                    return null;\n                return stations.find((station: StationModel) => {\n                    return station.id == stationId;\n                });\n            }).filter(value => value != null);\n    }\n\n    listenStationBranchSelected(): Observable<StationModel> {\n        var selected$ = this.store.select(store => store.appDb.uiState.stations.stationSelected);\n        var stations$ = this.store.select(store => store.appDb.stations);\n        var branches$ = this.store.select(store => store.msDatabase.sdk.table_branch_stations);\n        return selected$\n            .combineLatest(stations$, branches$, (stationId, stations: List<StationModel>, branches: List<BranchStationsModelExt>) => {\n                if (_.isUndefined(stations))\n                    return null;\n                return stations.find((station: StationModel) => {\n                    return station.id == stationId;\n                });\n            }).filter(value => value != null);\n    }\n\n    listenResources(): Observable<List<ResourcesModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_resources)\n            .map((resourceModels: List<ResourcesModel>) => {\n                return resourceModels.filter((i_resourceModel: ResourcesModel) => {\n                    return i_resourceModel.getChangeType() != 3\n                }) as List<ResourcesModel>;\n            })\n    }\n\n    listenStations(): Observable<List<StationModel>> {\n        return this.store.select(store => store.appDb.stations);\n    }\n\n    /**\n     Listen to when a campaign that is selected changed value\n     **/\n    listenCampaignValueChanged(emitOnEmpty: boolean = false): Observable<CampaignsModelExt> {\n        var campaignIdSelected$ = this.ngrxStore.select(store => store.appDb.uiState.campaign.campaignSelected)\n        var campaigns$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaigns);\n        return campaignIdSelected$\n            .combineLatest(campaigns$, (campaignId: number, campaigns: List<CampaignsModelExt>) => {\n                return campaigns.find((i_campaign: CampaignsModelExt) => {\n                    return i_campaign.getCampaignId() == campaignId;\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n\n    /**\n     Listen to when a scheduler that is selected changed value\n     **/\n    listenSchedulerValueChanged(emitOnEmpty: boolean = false): Observable<CampaignTimelineSchedulesModel> {\n        var campaignTimelineIdSelected$ = this.ngrxStore.select(store => store.appDb.uiState.campaign.timelineSelected)\n        var schedules$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_schedules);\n        return campaignTimelineIdSelected$\n            .combineLatest(schedules$, (campaignSchedarId: number, schedules: List<CampaignTimelineSchedulesModel>) => {\n                return schedules.find((i_schedules: CampaignTimelineSchedulesModel) => {\n                    return i_schedules.getCampaignTimelineId() == campaignSchedarId;\n                });\n            }).mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n    }\n\n    /**\n     Get all Scenes and update on any scene change\n     **/\n    listenScenes(): Observable<Array<ISceneData>> {\n        return this.store.select(store => store.msDatabase.sdk.table_player_data)\n            .map((playerDataModels: List<PlayerDataModel>) => {\n                return this.reducePlayerDataModelsToSceneData(playerDataModels)\n            });\n    }\n\n    listenFasterqLines(): Observable<List<FasterqLineModel>> {\n        return this.store.select(store => store.appDb.fasterq.lines)\n    }\n\n    listenFasterqQueues(): Observable<List<FasterqQueueModel>> {\n        var selected$ = this.store.select(store => store.appDb.uiState.fasterq.fasterqLineSelected);\n        var queues$ = this.store.select(store => store.appDb.fasterq.queues);\n        return selected$\n            .combineLatest(queues$, (lineId, queues: List<FasterqQueueModel>) => {\n                return queues.filter((queue: FasterqQueueModel) => {\n                    return queue.lineId == lineId;\n                }) as List<FasterqQueueModel>;\n            }).filter(value => value != null);\n    }\n\n    listenFasterqAnalytics(): Observable<List<FasterqAnalyticsModel>> {\n        return this.store.select(store => store.appDb.fasterq.analytics)\n    }\n\n    /**\n     Returns the record for a station id\n     **/\n    listenStationRecord(i_native_station_id): Observable<BranchStationsModelExt> {\n        return this.ngrxStore.select(store => store.msDatabase.sdk.table_branch_stations)\n            .map((i_branchStationsModels: List<BranchStationsModelExt>) => {\n                return i_branchStationsModels.find((i_branchStationsModel) => {\n                    return i_branchStationsModel.getNativeId == i_native_station_id;\n                })\n            });\n    }\n\n    /**\n     get time line total duration by channel\n     **/\n    getTimelineTotalDurationByChannel(i_campaign_timeline_id): Observable<number> {\n        var table_campaign_timeline_chanels$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_chanels)\n        var table_campaign_timeline_chanel_players$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players)\n        return Observable.combineLatest(table_campaign_timeline_chanels$, table_campaign_timeline_chanel_players$,\n            (table_campaign_timeline_chanels: List<CampaignTimelineChanelsModel>,\n             table_campaign_timeline_chanel_players: List<CampaignTimelineChanelPlayersModel>) => {\n                var longestChannelDuration = 0;\n                // loop over channels of timeline and sum up lengths\n                table_campaign_timeline_chanels.forEach(i_campaignTimelineChanelsModel => {\n                    if (i_campaignTimelineChanelsModel.getCampaignTimelineId() == i_campaign_timeline_id) {\n                        // console.log('found channel ' + i_campaignTimelineChanelsModel.getChanelName());\n                        var timelineDuration = 0;\n                        table_campaign_timeline_chanel_players.forEach(i_campaignTimelineChanelPlayersModel => {\n                            if (i_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelId() == i_campaignTimelineChanelsModel.getCampaignTimelineChanelId()) {\n                                timelineDuration += parseFloat(i_campaignTimelineChanelPlayersModel.getPlayerDuration());\n                                if (timelineDuration > longestChannelDuration)\n                                    longestChannelDuration = timelineDuration;\n                            }\n                        })\n                        // console.log('total ' + timelineDuration + ' longest so far ' + longestChannelDuration);\n                    }\n                })\n                // console.log('winner ' + longestChannelDuration);\n                return longestChannelDuration;\n            })\n    }\n\n    getStationCampaignID(i_native_station_id): Observable<number> {\n        var table_branch_stations$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_branch_stations)\n        var table_campaign_boards$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_boards)\n        return table_branch_stations$\n            .combineLatest(\n                table_campaign_boards$, (branchStationsModels: List<BranchStationsModelExt>, campaignBoardsModels: List<CampaignBoardsModel>) => {\n                    return {branchStationsModels, campaignBoardsModels}\n                })\n            .map((value) => {\n                var branchStationsModel: BranchStationsModelExt = value.branchStationsModels.find((i_branchStationsModel: BranchStationsModelExt) => {\n                    return i_branchStationsModel.getNativeId == i_native_station_id;\n                })\n                if (!branchStationsModel)\n                    return Observable.empty()\n                var campaignBoardsModel = value.campaignBoardsModels.find((i_campaignBoardsModel: CampaignBoardsModel) => {\n                    return i_campaignBoardsModel.getCampaignBoardId() == branchStationsModel.getCampaignBoardId();\n                })\n                return campaignBoardsModel.getCampaignId();\n            }).take(1);\n    }\n\n    getPreviewMode() {\n        return this.store.select(store => store.appDb.uiState.previewMode).take(1)\n    }\n\n    /**\n     Get all Scenes in current state and return array of player_data_id domPlayerData : ISceneData\n     **/\n    getScenes(): Observable<Array<ISceneData>> {\n        return this.store.select(store => store.msDatabase.sdk.table_player_data)\n            .map((playerDataModels: List<PlayerDataModel>) => {\n                return this.reducePlayerDataModelsToSceneData(playerDataModels)\n            }).take(1);\n    }\n\n    getCampaigns(): Observable<List<CampaignsModelExt>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaigns)\n            .take(1) as Observable<List<CampaignsModelExt>>\n    }\n\n    getMultiSelectedStations(): Observable<any> {\n        return this.store.select(store => store.appDb.uiState.multiStationSelected.stations)\n    }\n\n    getTimelines(): Observable<List<CampaignTimelinesModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timelines)\n            .take(1);\n    }\n\n    getResources(): Observable<List<ResourcesModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_resources)\n            .take(1);\n    }\n\n    /**\n     Returns all scenes\n     **/\n    getSceneNames(): Observable<Array<any>> {\n        return this.store.select(store => store.msDatabase.sdk.table_player_data)\n            .map((i_layerDataModels: List<PlayerDataModel>) => {\n                return i_layerDataModels.reduce((result, i_layerDataModel) => {\n                    var domPlayerData = $.parseXML(i_layerDataModel.getPlayerDataValue())\n                    var player_data_id = i_layerDataModel.getPlayerDataId();\n                    var scene = {\n                        id: player_data_id,\n                        label: (jXML(domPlayerData).find('Player').attr('label')),\n                        mimeType: jXML(domPlayerData).find('Player').attr('mimeType')\n                    };\n                    result.push(scene)\n                    return result;\n                }, [])\n            }).take(1);\n    }\n\n    /**\n     Get a timeline's duration which is set as the total sum of all blocks within the longest running channel\n     **/\n    getTimelineTotalDuration(i_campaign_timeline_id): Observable<string> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timelines)\n            .map((campaignTimelinesModels: List<CampaignTimelinesModel>) => {\n                return campaignTimelinesModels.reduce((result: string, campaignTimelineModel) => {\n                    if (campaignTimelineModel.getCampaignTimelineId() == i_campaign_timeline_id)\n                        result = campaignTimelineModel.getTimelineDuration();\n                    return result;\n                }, '')\n            }).take(1);\n    }\n\n    /**\n     Get logged in user info\n     **/\n    getUserModel(): Observable<UserModel> {\n        return this.store.select(store => store.appDb.userModel)\n            .take(1)\n    }\n\n    isBrandingDisabled(): Observable<boolean> {\n        return this.store.select(store => store.appDb.userModel)\n            .filter(i_user => {\n                return i_user.getAccountType() != -1;\n            })\n            .map((i_user: UserModel) => {\n                var res = i_user.resellerId == 1 || (i_user.resellerWhiteLabel && i_user.resellerWhiteLabel.WhiteLabel.attr.enabled == \"0\")\n                return res;\n            })\n    }\n\n    /**\n     Get all timeline s for specified campaign id\n     **/\n    getNewCampaignParmas(): Observable<{}> {\n        return this.store.select(store => store.appDb.uiState.campaign)\n            .take(1)\n    }\n\n    /**\n     Use a viewer_id to reverse enumerate over the mapping of viewers to channels via:\n     campaign_timeline_viewer_chanels -> table_campaign_timeline_chanels\n     so we can find the channel assigned to the viewer_id provided.\n     **/\n    getChannelFromCampaignTimelineBoardViewer(i_campaign_timeline_board_viewer_id): Observable<CampaignTimelineChanelsModel> {\n        return this.ngrxStore.select(store => store.msDatabase.sdk.table_campaign_timeline_board_viewer_chanels)\n            .map((i_campaignTimelineBoardViewerChanels: List<CampaignTimelineBoardViewerChanelsModel>) => {\n                return i_campaignTimelineBoardViewerChanels.find((i_campaignTimelineBoardViewerChanel: CampaignTimelineBoardViewerChanelsModel) => {\n                    return i_campaignTimelineBoardViewerChanel.getCampaignTimelineBoardViewerChanelId() == i_campaign_timeline_board_viewer_id;\n                })\n            }).concatMap((v: CampaignTimelineBoardViewerChanelsModel) => {\n                return this.getChannelOfTimeline(v.getCampaignTimelineChanelId())\n            }).take(1);\n    }\n\n    /**\n     Get all the campaign > timeline > channel of a timeline\n     **/\n    getChannelOfTimeline(i_campaign_timeline_chanel_id): Observable<CampaignTimelineChanelsModel> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanels)\n            .map((campaignTimelineChanels: List<CampaignTimelineChanelsModel>) => {\n                return campaignTimelineChanels.find((campaignTimelineChanelsModel: CampaignTimelineChanelsModel) => {\n                    return campaignTimelineChanelsModel.getCampaignTimelineChanelId() == i_campaign_timeline_chanel_id\n                })\n            }).take(1);\n    }\n\n    /**\n     Get all the block IDs of a particular channel.\n     **/\n    getChannelBlocks(i_campaign_timeline_chanel_id): Observable<Array<number>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players)\n            .map((campaignTimelineChanelPlayersModels: List<CampaignTimelineChanelPlayersModel>) => {\n                return campaignTimelineChanelPlayersModels.reduce((result: Array<number>, campaignTimelineChanelsModel) => {\n                    if (campaignTimelineChanelsModel.getCampaignTimelineChanelId() == i_campaign_timeline_chanel_id)\n                        result.push(campaignTimelineChanelsModel.getCampaignTimelineChanelPlayerId());\n                    return result;\n                }, [])\n            }).take(1);\n    }\n\n    /**\n     Get Scene player data as dom\n     **/\n    getScenePlayerdataDom(i_scene_id): Observable<string> {\n        return this.sterilizePseudoId(i_scene_id)\n            .mergeMap(scene_id => {\n                return this.getScene(scene_id)\n                    .map((playerDataModel: PlayerDataModel) => {\n                        return playerDataModel.getPlayerDataValue();\n                    })\n            }).take(1);\n    }\n\n    /**\n     Get player_data via its scene id\n     **/\n    getScene(scene_id): Observable<PlayerDataModelExt> {\n        return this.store.select(store => store.msDatabase.sdk.table_player_data)\n            .map((playerDataModels: List<PlayerDataModel>) => {\n                return playerDataModels.find((playerDataModel: PlayerDataModel) => {\n                    return scene_id == playerDataModel.getPlayerDataId();\n                }) as PlayerDataModelExt\n            }).take(1);\n    }\n\n    /**\n     Sterilize pseudo id to scene id always returns scene_id as an integer rather pseudo id\n     @method sterilizePseudoId\n     @param {Number} i_id\n     @return {Number} i_id\n     **/\n    sterilizePseudoId(i_id): Observable<number> {\n        var id = parseInt(i_id);\n        if (_.isNaN(id))\n            return this.getSceneIdFromPseudoId(i_id);\n        return Observable.of(i_id);\n    }\n\n    /**\n     Translate an injected id to a table_player_data scene id\n     @method createPseudoSceneID\n     @param {Number} getSceneIdFromPseudoId\n     @return {Number} scene id\n     **/\n    getSceneIdFromPseudoId(i_pseudo_id): Observable<number> {\n        return this.getScenes()\n            .mergeMap((i_sceneList: Array<ISceneData>) => {\n                return Observable.from(i_sceneList)\n            }).filter((i_scene: ISceneData) => {\n                return i_pseudo_id == jXML(i_scene.domPlayerData).find('Player').eq(0).attr('id');\n            }).map((i_scene: ISceneData) => {\n                return i_scene.scene_id;\n            }).take(1);\n    }\n\n\n    /**\n     Get all the model of a particular channel.\n     Push them into an array so they are properly sorted by player offset time.\n     **/\n    getChannelBlockModels(i_campaign_timeline_chanel_id): Observable<List<CampaignTimelineChanelPlayersModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players)\n            .map((campaignTimelineChanelPlayersModels: List<CampaignTimelineChanelPlayersModel>) => {\n                return campaignTimelineChanelPlayersModels.filter(campaignTimelineChanelsModel => {\n                    return campaignTimelineChanelsModel.getCampaignTimelineChanelId() == i_campaign_timeline_chanel_id;\n                }) as List<CampaignTimelineChanelPlayersModel>\n            }).take(1);\n    }\n\n    /**\n     get a scene block playerdata\n     **/\n    // getScenBlockRecord(i_scene_id, i_player_data_id) {\n    //     var self = this;\n    //     i_scene_id = pepper.sterilizePseudoId(i_scene_id);\n    //     self.m_msdb.table_player_data().openForEdit(i_scene_id);\n    //     var recPlayerData = self.m_msdb.table_player_data().getRec(i_scene_id);\n    //     var player_data = recPlayerData['player_data_value'];\n    //     var domPlayerData = $.parseXML(player_data)\n    //     var foundSnippet = $(domPlayerData).find('[id=\"' + i_player_data_id + '\"]');\n    //     return foundSnippet[0];\n    // }\n\n    /**\n     Get a player_id record from sdk by player_id primary key.\n     **/\n    getChannelBlockRecord(i_player_id): Observable<CampaignTimelineChanelPlayersModel> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players)\n            .map((i_campaignTimelineChanelPlayersModels: List<CampaignTimelineChanelPlayersModel>) => {\n                return i_campaignTimelineChanelPlayersModels\n                    .find((i_campaignTimelineChanelPlayersModel) => {\n                        return i_campaignTimelineChanelPlayersModel.getCampaignTimelineChanelPlayerId() == i_player_id\n                    })\n            }).take(1)\n    }\n\n    /**\n     Get a resource record via its resource_id.\n     **/\n    getResourceRecord(i_resource_id): Observable<ResourcesModel> {\n        return this.store.select(store => store.msDatabase.sdk.table_resources)\n            .map((i_resourcesModels: List<ResourcesModel>) => {\n                return i_resourcesModels\n                    .find((i_resourcesModel) => {\n                        return i_resourcesModel.getResourceId() == i_resource_id\n                    })\n            }).take(1)\n    }\n\n    // /**\n    //  Get all Scenes and convert them to dom objects returning a hash of object literals\n    //  @method getScenes\n    //  @return {Object} all scenes as objects\n    //  **/\n    // getSceneMime(i_sceneID): Observable<any> {\n    //     return this.store.select(store => store.msDatabase.sdk.table_player_data)\n    //         .map((playerDataModels: List<PlayerDataModel>) => {\n    //             return playerDataModels.reduce((result: Array<any>, playerDataModel) => {\n    //                 var recPlayerData = playerDataModel.getPlayerDataValue();\n    //                 var domPlayerData = $.parseXML(recPlayerData)\n    //                 result.push(domPlayerData);\n    //                 return result;\n    //             }, [])\n    //         }).take(1);\n    // }\n    //\n    // /**\n    //  Returns all scenes\n    //  @method getSceneMime\n    //  @param {Number} i_sceneID\n    //  @return {Object} scene names\n    //  **/\n    // getSceneMime(i_sceneID) {\n    //\n    //     var mimeType = '';\n    //     $(this.databaseManager.table_player_data().getAllPrimaryKeys()).each(function (k, player_data_id) {\n    //         var recPlayerData = this.databaseManager.table_player_data().getRec(player_data_id);\n    //         var domPlayerData = $.parseXML(recPlayerData['player_data_value'])\n    //         var id = $(domPlayerData).find('Player').attr('id');\n    //         if (id == i_sceneID)\n    //             mimeType = $(domPlayerData).find('Player').attr('mimeType');\n    //     });\n    //     return mimeType;\n    // }\n\n    /**\n     Get all the campaign > timeline > channels ids of a timeline\n     **/\n    getChannelsOfTimeline(i_campaign_timeline_id): Observable<any> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanels)\n            .map((campaignTimelineChanels: List<CampaignTimelineChanelsModel>) => {\n                return campaignTimelineChanels.reduce((result: Array<number>, campaignTimelineChanelsModel) => {\n                    if (campaignTimelineChanelsModel.getCampaignTimelineId() == i_campaign_timeline_id)\n                        result.push(campaignTimelineChanelsModel.getCampaignTimelineChanelId());\n                    return result;\n                }, [])\n            }).take(1);\n    }\n\n    /**\n     Get all timeline s for specified campaign id\n     **/\n    getCampaignTimelines(i_campaign_id: number): Observable<List<CampaignTimelinesModel>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timelines)\n            .map((campaignTimelinesModels: List<CampaignTimelinesModel>) => {\n                return campaignTimelinesModels.filter((campaignTimelinesModel: CampaignTimelinesModel) => {\n                    return campaignTimelinesModel.getCampaignId() == i_campaign_id;\n                }) as List<CampaignTimelinesModel>;\n            }).take(1);\n    }\n\n    /**\n     Get a block's (a.k.a player) total hours / minutes / seconds playback length on the timeline_channel.\n     **/\n    getBlockTimelineChannelBlockLength(i_campaign_timeline_chanel_player_id): Observable<number> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_chanel_players)\n            .map((i_players: List<CampaignTimelineChanelPlayersModel>) => {\n                return i_players.reduce((result: number, i_player) => {\n                    if (i_player.getCampaignTimelineChanelPlayerId() == i_campaign_timeline_chanel_player_id)\n                        result = i_player.getPlayerDuration();\n                    return result;\n                }, 0)\n            }).take(1);\n    }\n\n    /**\n     Get the total duration in seconds of the channel\n     @method getTotalDurationChannel\n     **/\n    getTotalDurationChannel(i_selected_campaign_timeline_chanel_id) {\n        return this.getChannelBlocks(i_selected_campaign_timeline_chanel_id)\n            .concatMap((i_blockIds) => {\n                return Observable.from(i_blockIds);\n            }).flatMap((i_blockId) => {\n                return this.getBlockTimelineChannelBlockLength(i_blockId)\n            }).reduce((acc: number, x: number) => {\n                return acc + Number(x);\n            }, 0).take(1);\n    }\n\n    /**\n     Get the sequence index of a timeline in the specified campaign\n     **/\n    getCampaignTimelineSequencerIndex(i_campaign_timeline_id): Observable<number> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_sequences)\n            .map((campaignTimelineSequencesModels: List<CampaignTimelineSequencesModel>) => {\n                var found: CampaignTimelineSequencesModel = campaignTimelineSequencesModels.find((campaignTimelineSequencesModel: CampaignTimelineSequencesModel) => {\n                    return campaignTimelineSequencesModel.getCampaignTimelineId() == i_campaign_timeline_id\n                });\n                if (!found)\n                    return -1;\n                return found.getSequenceIndex();\n            }).take(1);\n    }\n\n    /**\n     Get the sequence index of a timeline in the specified campaign\n     **/\n    getCampaignsSchedule(i_campaign_timeline_id): Observable<CampaignTimelineSchedulesModel> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_schedules)\n            .map((campaignTimelineSchedulesModel: List<CampaignTimelineSchedulesModel>) => {\n                return campaignTimelineSchedulesModel.find((campaignTimelineSchedulesModel: CampaignTimelineSchedulesModel) => {\n                    return campaignTimelineSchedulesModel.getCampaignTimelineId() == i_campaign_timeline_id\n                });\n            }).take(1);\n    }\n\n    /**\n     Get all the global board template ids of a timeline\n     * **/\n    getGlobalTemplateIdOfTimeline(i_campaign_timeline_id): Observable<Array<number>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_board_templates)\n            .map((campaignTimelineBoardTemplatesModels: List<CampaignTimelineBoardTemplatesModel>) => {\n                return campaignTimelineBoardTemplatesModels.reduce((result: Array<number>, campaignTimelineBoardTemplatesModel) => {\n                    if (campaignTimelineBoardTemplatesModel.getCampaignTimelineId() == i_campaign_timeline_id)\n                        result.push(campaignTimelineBoardTemplatesModel.getBoardTemplateId());\n                    return result;\n                }, [])\n            }).take(1);\n    }\n\n    /**\n     Get all the campaign > timeline > board > template ids of a timeline\n     **/\n    getTemplatesOfTimeline(i_campaign_timeline_id): Observable<Array<number>> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_board_templates)\n            .map((campaignTimelineBoardTemplatesModels: List<CampaignTimelineBoardTemplatesModel>) => {\n                return campaignTimelineBoardTemplatesModels.reduce((result: Array<number>, campaignTimelineBoardTemplatesModel) => {\n                    if (campaignTimelineBoardTemplatesModel.getCampaignTimelineId() == i_campaign_timeline_id)\n                        result.push(campaignTimelineBoardTemplatesModel.getCampaignTimelineBoardTemplateId());\n                    return result;\n                }, [])\n            }).take(1);\n    }\n\n    /**\n     *\n     * Get a channel associated with the selected viewer\n     */\n    getChannelFromViewer(i_selectedTimeline_id, i_campaign_timeline_board_viewer_id): Observable<{}> {\n        return this.getChannelsOfTimeline(i_selectedTimeline_id).switchMap((timeline_channel_ids: Array<number>) => {\n            return Observable.from(timeline_channel_ids).concatMap((channel: number) => {\n                return this.getAssignedViewerIdFromChannelId(channel)\n                    .map(viewer_id => {\n                        if (viewer_id == i_campaign_timeline_board_viewer_id) {\n                            return {viewer_id, channel};\n                        } else {\n                            return null;\n                        }\n                    }).skipWhile(value => value == null)\n            })\n        }).take(1);\n    }\n\n    /**\n     Get the assigned viewer id to the specified channel\n     **/\n    getAssignedViewerIdFromChannelId(i_campaign_timeline_channel_id): Observable<number> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_board_viewer_chanels)\n            .map((campaignTimelineBoardViewerChanelsModel: List<CampaignTimelineBoardViewerChanelsModel>) => {\n                return campaignTimelineBoardViewerChanelsModel.reduce((result: number, campaignTimelineBoardViewerChanelsModel) => {\n                    if (campaignTimelineBoardViewerChanelsModel.getCampaignTimelineChanelId() == i_campaign_timeline_channel_id)\n                        result = (campaignTimelineBoardViewerChanelsModel.getBoardTemplateViewerId());\n                    return result;\n                }, -1)\n            }).take(1);\n    }\n\n    /**\n     Get a timeline model from timeline id\n     **/\n    getTimeline(i_campaign_timeline_id): Observable<CampaignTimelinesModel> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaign_timelines)\n            .map((campaignTimelinesModels: List<CampaignTimelinesModel>) => {\n                return campaignTimelinesModels.find((campaignTimelineModel) => {\n                    return campaignTimelineModel.getCampaignTimelineId() == i_campaign_timeline_id\n                })\n            }).take(1);\n    }\n\n    /**\n     Build screenProps json object with all viewers and all of their respective attributes for the given timeline_id / template_id\n     **/\n    getTemplateViewersScreenProps(i_campaign_timeline_id, i_campaign_timeline_board_template_id, timelineName = ''): Observable<IScreenTemplateData> {\n\n        var table_campaign_timeline_board_templates$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_board_templates);\n        var table_campaign_timeline_board_viewer_chanels$ = this.store.select(store => store.msDatabase.sdk.table_campaign_timeline_board_viewer_chanels);\n        var table_board_template_viewers$ = this.store.select(store => store.msDatabase.sdk.table_board_template_viewers);\n        var table_board_templates = this.store.select(store => store.msDatabase.sdk.table_board_templates);\n        var table_boards$ = this.store.select(store => store.msDatabase.sdk.table_boards);\n\n        var counter = -1;\n        var screenProps = {};\n        var viewOrderIndexes = {};\n        var boardWidth;\n        var boardHeight;\n        var boardOrientation;\n\n        return Observable.combineLatest(\n            table_campaign_timeline_board_templates$,\n            table_board_template_viewers$,\n            table_campaign_timeline_board_viewer_chanels$,\n            table_board_templates,\n            table_boards$,\n\n            (campaignTimelineBoardTemplatesModels: List<CampaignTimelineBoardTemplatesModel>,\n             boardTemplateViewersModels: List<BoardTemplateViewersModel>,\n             campaignTimelineBoardViewerChanelsModels: List<CampaignTimelineBoardViewerChanelsModel>,\n             boardTemplates: List<BoardTemplatesModel>,\n             boardsModel: List<BoardsModel>) => {\n\n                campaignTimelineBoardViewerChanelsModels.forEach((campaignTimelineBoardViewerChanelsModel: CampaignTimelineBoardViewerChanelsModel, v) => {\n\n                    if (campaignTimelineBoardViewerChanelsModel.getCampaignTimelineBoardTemplateId() == i_campaign_timeline_board_template_id) {\n\n                        var board_template_viewer_id = campaignTimelineBoardViewerChanelsModel.getBoardTemplateViewerId();\n                        boardTemplateViewersModels.forEach((recBoardTemplateViewer: BoardTemplateViewersModel) => {\n                            if (recBoardTemplateViewer.getBoardTemplateViewerId() == board_template_viewer_id) {\n\n                                var boardId = boardTemplates.find((boardTemplateModel) => {\n                                    return boardTemplateModel.getBoardTemplateId() == recBoardTemplateViewer.getBoardTemplateId();\n                                }).getBoardId();\n\n                                var boardModel = boardsModel.find((boardModel) => {\n                                    return boardModel.getBoardId() == boardId;\n                                });\n                                boardWidth = boardModel.getBoardPixelWidth();\n                                boardHeight = boardModel.getBoardPixelHeight();\n                                if (boardWidth > boardHeight) {\n                                    boardOrientation = OrientationEnum.HORIZONTAL;\n                                } else {\n                                    boardOrientation = OrientationEnum.VERTICAL;\n                                }\n                                // console.log(i_campaign_timeline_board_template_id + ' ' + recBoardTemplateViewer['board_template_viewer_id']);\n                                counter++;\n                                screenProps['sd' + counter] = {};\n                                screenProps['sd' + counter]['campaign_timeline_board_viewer_id'] = recBoardTemplateViewer.getBoardTemplateViewerId();\n                                screenProps['sd' + counter]['campaign_timeline_id'] = i_campaign_timeline_id;\n                                screenProps['sd' + counter]['x'] = recBoardTemplateViewer.getPixelX();\n                                screenProps['sd' + counter]['y'] = recBoardTemplateViewer.getPixelY();\n                                screenProps['sd' + counter]['w'] = recBoardTemplateViewer.getPixelWidth();\n                                screenProps['sd' + counter]['h'] = recBoardTemplateViewer.getPixelHeight();\n\n                                // make sure that every view_order we assign is unique and sequential\n                                var viewOrder = recBoardTemplateViewer.getViewerOrder();\n                                if (!_.isUndefined(viewOrderIndexes[viewOrder])) {\n                                    for (var i = 0; i < 100; i++) {\n                                        if (_.isUndefined(viewOrderIndexes[i])) {\n                                            viewOrder = i;\n                                            break;\n                                        }\n                                    }\n                                }\n                                viewOrderIndexes[viewOrder] = true;\n                                screenProps['sd' + counter]['view_order'] = viewOrder;\n                            }\n                        })\n                    }\n                })\n                var screenTemplateData: IScreenTemplateData = {\n                    screenProps: screenProps,\n                    resolution: `${boardWidth}x${boardHeight}`,\n                    screenType: '',\n                    orientation: boardOrientation,\n                    name: timelineName,\n                    scale: 14,\n                    campaignTimelineId: i_campaign_timeline_id,\n                    campaignTimelineBoardTemplateId: i_campaign_timeline_board_template_id\n                }\n                return screenTemplateData;\n            }).take(1)\n    }\n\n    /**\n     Get campaigns from campaign id\n     **/\n    getCampaign(i_campaign_id: number): Observable<CampaignsModelExt> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaigns)\n            .map((campaignModels: List<CampaignsModelExt>) => {\n                return campaignModels.find((campaignModel: CampaignsModelExt) => {\n                    return campaignModel.getCampaignId() == i_campaign_id;\n                });\n            }).take(1);\n    }\n\n\n    /*****************************************************/\n    // below are some brain dumps and examples only\n    /*****************************************************/\n\n    private campaignSelectedExampleMultipleLatestFromSelections() {\n        var campaignSelected$ = this.store.select(\n            store => store.appDb.uiState.campaign.campaignSelected\n        );\n        var boards$ = this.store.select(\n            store => store.msDatabase.sdk.table_boards\n        );\n        var campaignsList$ = this.store.select(\n            store => store.msDatabase.sdk.table_campaigns\n        );\n        return campaignSelected$.withLatestFrom(\n            campaignsList$,\n            (campaignId, campaigns) => {\n                return campaigns.find((i_campaign: CampaignsModelExt) => {\n                    return i_campaign.getCampaignId() == campaignId;\n                });\n            }).withLatestFrom(\n            boards$,\n            (campaign: CampaignsModelExt, boards: List<BoardsModel>) => {\n                return campaign;\n            });\n    }\n\n    private findCampaignByIdTest(i_campaignId: number): Observable<CampaignsModelExt> {\n        return this.store.select(store => store.msDatabase.sdk.table_campaigns)\n            .take(1)\n            .map((i_campaigns: List<CampaignsModelExt>) => {\n                // console.log('look up campaign ' + i_campaignId);\n                return i_campaigns.find((i_campaign: CampaignsModelExt) => {\n                    return i_campaign.getCampaignId() == i_campaignId;\n                });\n            });\n    }\n\n    private findCampaignByIdConcatTemp1(i_campaignId): Observable<CampaignsModelExt> {\n        var campaign1$ = this.findCampaignByIdTest(i_campaignId)\n        var campaign2$ = this.findCampaignByIdTest(1)\n        var campaign3$ = this.findCampaignByIdTest(2)\n\n        return campaign1$.concatMap((x: CampaignsModelExt) => {\n            return campaign2$;\n        }, (a: CampaignsModelExt, b: CampaignsModelExt) => {\n            return a;\n        }).concatMap((campaignsModel: CampaignsModelExt) => {\n            return this.findCampaignByIdTest(campaignsModel.getCampaignId())\n        }, (c: CampaignsModelExt, d: CampaignsModelExt) => {\n            return d;\n        }).concatMap((campaignsModel: CampaignsModelExt) => this.findCampaignByIdTest(campaignsModel.getCampaignId()), (e: CampaignsModelExt, f: CampaignsModelExt) => {\n            return e\n        }).take(1)\n    }\n\n}\n\n\n// /**\n//  Listen to changes in selected scene\n//  **/\n// listenSceneOrBlockChanged(emitOnEmpty: boolean = false): Observable<any> {\n//     return this.store.select(store => store.msDatabase.sdk.table_player_data);\n//\n//     // var sceneSelected$ = this.store.select(store => store.appDb.uiState.scene.sceneSelected);\n//     // var player_data$ = this.store.select(store => store.msDatabase.sdk.table_player_data);\n//     // var blockSelected$ = this.store.select(store => store.appDb.uiState.scene.blockSelected);\n//     // return sceneSelected$.combineLatest(player_data$, (sceneId, player_data) => {\n//     //     return {sceneId, player_data}\n//     // }).filter((ids) => {\n//     //     if (!emitOnEmpty) return true; // no filter requested\n//     //     return ids && ids.sceneId != -1\n//     // }).withLatestFrom(blockSelected$, (a, b) => {\n//     //     return {a, b};\n//     // }).map(ids => {\n//     //     return ids;\n//     //     // return this.getScene(ids.sceneId)\n//     //     // .map((playerDataModel: PlayerDataModelExt) => {\n//     //     //     var domPlayerData = $.parseXML(playerDataModel.getPlayerDataValue())\n//     //     //     var selectedSnippet: any = $(domPlayerData).find(`[id=\"${ids.blockId}\"]`)[0];\n//     //     //     var mimeType = $(domPlayerData).find('Player').attr('mimeType');\n//     //     //     var xml = (new XMLSerializer()).serializeToString(selectedSnippet);\n//     //     //     selectedSnippet = $.parseXML(xml)\n//     //     //     var sceneData: ISceneData = {\n//     //     //         scene_id: ids.sceneId,\n//     //     //         scene_id_pseudo_id: null,\n//     //     //         block_pseudo_id: ids.blockId,\n//     //     //         playerDataModel: playerDataModel,\n//     //     //         domPlayerData: selectedSnippet,\n//     //     //         domPlayerDataXml: xml,\n//     //     //         domPlayerDataJson: this.parser.xml2js(xml),\n//     //     //         mimeType: mimeType\n//     //     //     }\n//     //     //     return sceneData;\n//     //     // });\n//     // }).distinct()\n//     //     .mergeMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));\n// }"
  },
  {
    "path": "src/store/actions/appdb.actions.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {Http} from \"@angular/http\";\nimport \"rxjs/add/operator/map\";\nimport \"rxjs/add/operator/mergeMap\";\nimport \"rxjs/add/operator/merge\";\nimport \"rxjs/add/operator/debounceTime\";\nimport {Store} from \"@ngrx/store\";\nimport {ApplicationState} from \"../application.state\";\nimport {Observable} from \"rxjs\";\nimport {IUiState} from \"../store.data\";\n\nexport const APP_INIT = 'APP_INIT';\nexport const ACTION_INJECT_SDK = 'ACTION_INJECT_SDK';\nexport const ACTION_TWO_FACTOR_REMOVED = 'ACTION_TWO_FACTOR_REMOVED';\nexport const ACTION_UISTATE_UPDATE = 'ACTION_UISTATE_UPDATE';\nexport const ACTION_LIVELOG_UPDATE = 'ACTION_LIVELOG_UPDATE';\nexport const ACTION_FORM_UPDATE = 'ACTION_FORM_UPDATE';\n\nexport enum AuthenticateFlags {\n    NONE,\n    USER_ACCOUNT,\n    USER_ACCOUNT_PRO,\n    ENTERPRISE_ACCOUNT,\n    WRONG_TWO_FACTOR,\n    WRONG_PASS,\n    TWO_FACTOR_ENABLED,\n    AUTH_PASS_NO_TWO_FACTOR,\n    TWO_FACTOR_CHECK,\n    TWO_FACTOR_FAIL,\n    TWO_FACTOR_PASS,\n    TWO_FACTOR_UPDATE_PASS,\n    TWO_FACTOR_UPDATE_FAIL\n}\n\nexport enum SideProps {\n    none,\n    miniDashboard,\n    campaignProps,\n    campaignEditor,\n    timeline,\n    sceneBlock,\n    channelBlock,\n    channel,\n    screenLayoutEditor,\n    sceneProps,\n    resourceProps,\n    sceneEditor,\n    stationProps,\n    fasterqLineProps,\n    fasterqQueueProps\n}\n\n\n@Injectable()\nexport class AppdbAction {\n\n    constructor(private store: Store<ApplicationState>, private http: Http) {\n    }\n\n    public initAppDb() {\n        return {\n            type: APP_INIT,\n            payload: Date.now()\n        }\n    }\n\n    public resetCampaignSelection(){\n        var uiState: IUiState = {\n            locationMap: {\n                loadLocationMap: false,\n                locationMarkerSelected: null\n            },\n            campaign: {\n                timelineSelected: -1,\n                campaignSelected: -1,\n                campaignTimelineChannelSelected: -1,\n                campaignTimelineBoardViewerSelected: -1\n            }\n        }\n        this.store.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n    }\n\n    public getQrCodeTwoFactor(): Observable<string> {\n        return this.store.select(store => store.appDb.appBaseUrlCloud)\n            .take(1)\n            .mergeMap(appBaseUrlCloud => {\n                var url = appBaseUrlCloud.replace('END_POINT', 'twoFactorGenQr');\n                return this.http.get(url)\n                    .catch((err: any) => {\n                        return Observable.throw(err);\n                    })\n                    .map(res => {\n                        this.store.dispatch({type: ACTION_TWO_FACTOR_REMOVED})\n                        return res.text();\n                    })\n            })\n    }\n}\n"
  },
  {
    "path": "src/store/actions/msdb.actions.ts",
    "content": ""
  },
  {
    "path": "src/store/application.state.ts",
    "content": "import {IMsDatabase, INITIAL_STORE_DATA, INITIAL_APP_DB, IAppDb} from \"./store.data\";\n\nexport interface ApplicationState {\n    msDatabase: IMsDatabase\n    appDb: IAppDb\n}\nexport const INITIAL_APPLICATION_STATE: ApplicationState = {\n    msDatabase: INITIAL_STORE_DATA,\n    appDb: INITIAL_APP_DB\n};"
  },
  {
    "path": "src/store/effects/appdb.effects.ts",
    "content": "import {Injectable} from \"@angular/core\";\nimport {Headers, Http, RequestMethod, RequestOptionsArgs, Response} from \"@angular/http\";\nimport \"rxjs/add/operator/map\";\nimport \"rxjs/add/operator/mergeMap\";\nimport \"rxjs/add/operator/merge\";\nimport \"rxjs/add/operator/debounceTime\";\nimport * as xml2js from \"xml2js\";\nimport {Action, Store} from \"@ngrx/store\";\nimport {ApplicationState} from \"../application.state\";\nimport {Actions, Effect} from \"@ngrx/effects\";\nimport {Observable} from \"rxjs\";\nimport {UserModel} from \"../../models/UserModel\";\nimport {ACTION_UISTATE_UPDATE, AuthenticateFlags} from \"../actions/appdb.actions\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\nimport {IPepperConnection} from \"../../store/imsdb.interfaces\";\nimport * as _ from \"lodash\";\nimport {IStation, IUiState} from \"../store.data\";\nimport {List, Map} from \"immutable\";\nimport {StationModel} from \"../../models/StationModel\";\nimport {Lib} from \"../../Lib\";\nimport {FasterqLineModel} from \"../../models/fasterq-line-model\";\nimport {YellowPepperService} from \"../../services/yellowpepper.service\";\nimport {FasterqQueueModel} from \"../../models/fasterq-queue-model\";\nimport {FasterqAnalyticsModel} from \"../../models/fasterq-analytics\";\nimport {IQueueSave} from \"../../app/fasterq/fasterq-editor\";\nimport {CommBroker, IMessage} from \"../../services/CommBroker\";\nimport {FASTERQ_QUEUE_CALL_CANCLED} from \"../../interfaces/Consts\";\nimport {ToastsManager} from \"ng2-toastr\";\nimport {LocalStorage} from \"../../services/LocalStorage\";\nimport {formErrorAction, formSuccessAction} from \"../../comps/connect-form/connect-form\";\n\nexport const EFFECT_AUTH_START = 'EFFECT_AUTH_START';\nexport const EFFECT_AUTH_END = 'EFFECT_AUTH_END';\nexport const EFFECT_UPDATE_USER_MODEL = 'EFFECT_UPDATE_USER_MODEL';\nexport const EFFECT_AUTH_STATUS = 'EFFECT_AUTH_STATUS';\nexport const EFFECT_TWO_FACTOR_AUTH = 'EFFECT_TWO_FACTOR_AUTH';\nexport const EFFECT_TWO_FACTOR_UPDATING = 'EFFECT_TWO_FACTOR_UPDATING';\nexport const EFFECT_TWO_FACTOR_UPDATED = 'EFFECT_TWO_FACTOR_UPDATED';\nexport const EFFECT_LOAD_STATIONS = 'EFFECT_LOAD_STATIONS';\nexport const EFFECT_LOADING_STATIONS = 'EFFECT_LOADING_STATIONS';\nexport const EFFECT_LOADED_STATIONS = 'EFFECT_LOADED_STATIONS';\nexport const EFFECT_LOAD_FASTERQ_LINES = 'EFFECT_LOAD_FASTERQ_LINES';\nexport const EFFECT_LOADED_FASTERQ_LINES = 'EFFECT_LOADED_FASTERQ_LINES';\nexport const EFFECT_LOADING_FASTERQ_LINES = 'EFFECT_LOADING_FASTERQ_LINES';\nexport const EFFECT_LOAD_FASTERQ_LINE = 'EFFECT_LOAD_FASTERQ_LINE';\nexport const EFFECT_LOADED_FASTERQ_LINE = 'EFFECT_LOADED_FASTERQ_LINE';\nexport const EFFECT_LOADING_FASTERQ_LINE = 'EFFECT_LOADING_FASTERQ_LINE';\nexport const EFFECT_LOAD_FASTERQ_ANALYTICS = 'EFFECT_LOAD_FASTERQ_ANALYTICS';\nexport const EFFECT_LOADED_FASTERQ_ANALYTICS = 'EFFECT_LOADED_FASTERQ_ANALYTICS';\nexport const EFFECT_LOADING_FASTERQ_ANALYTICS = 'EFFECT_LOADING_FASTERQ_ANALYTICS';\nexport const EFFECT_LOAD_FASTERQ_QUEUES = 'EFFECT_LOAD_FASTERQ_QUEUES';\nexport const EFFECT_LOADED_FASTERQ_QUEUES = 'EFFECT_LOADED_FASTERQ_QUEUES';\nexport const EFFECT_LOADING_FASTERQ_QUEUES = 'EFFECT_LOADING_FASTERQ_QUEUES';\nexport const EFFECT_UPDATE_FASTERQ_LINE = 'EFFECT_UPDATE_FASTERQ_LINE';\nexport const EFFECT_UPDATED_FASTERQ_LINE = 'EFFECT_UPDATED_FASTERQ_LINE';\nexport const EFFECT_REMOVE_FASTERQ_LINE = 'EFFECT_REMOVE_FASTERQ_LINE';\nexport const EFFECT_REMOVED_FASTERQ_LINE = 'EFFECT_REMOVED_FASTERQ_LINE';\nexport const EFFECT_ADD_FASTERQ_LINE = 'EFFECT_ADD_FASTERQ_LINE';\nexport const EFFECT_ADDED_FASTERQ_LINE = 'EFFECT_ADDED_FASTERQ_LINE';\nexport const EFFECT_QUEUE_CALL_SAVE = 'EFFECT_QUEUE_CALL_SAVE';\nexport const EFFECT_QUEUE_CALL_SAVING = 'EFFECT_QUEUE_CALL_SAVING';\nexport const EFFECT_QUEUE_CALL_SAVED = 'EFFECT_QUEUE_CALL_SAVED';\nexport const EFFECT_QUEUE_SERVICE_SAVE = 'EFFECT_QUEUE_SERVICE_SAVE';\nexport const EFFECT_QUEUE_SERVICE_SAVING = 'EFFECT_QUEUE_SERVICE_SAVING';\nexport const EFFECT_QUEUE_SERVICE_SAVED = 'EFFECT_QUEUE_SERVICE_SAVED';\nexport const EFFECT_QUEUE_POLL_SERVICE = 'EFFECT_QUEUE_POLL_SERVICE';\nexport const EFFECT_RESET_FASTERQ_LINE = 'EFFECT_RESET_FASTERQ_LINE';\nexport const EFFECT_CONTACT_US = 'EFFECT_CONTACT_US';\n\n@Injectable()\nexport class AppDbEffects {\n\n    parseString;\n    appBaseUrlServices\n    fasterQueueInFlight = false;\n\n    constructor(private actions$: Actions,\n                private store: Store<ApplicationState>,\n                private rp: RedPepperService,\n                private yp: YellowPepperService,\n                private commBroker: CommBroker,\n                private localStorage: LocalStorage,\n                private toastr: ToastsManager,\n                private http: Http) {\n\n        // todo: disabled injection as broken in AOT\n        // @Inject('OFFLINE_ENV') private offlineEnv,\n\n        this.yp.ngrxStore.select(store => store.appDb.appBaseUrlServices)\n            .subscribe((i_appBaseUrlServices) => {\n                this.appBaseUrlServices = i_appBaseUrlServices;\n            })\n\n        this.parseString = xml2js.parseString;\n    }\n\n    /**\n     *\n     * Authentication\n     *\n     */\n\n    @Effect({dispatch: true})\n    authTwoFactor$: Observable<Action> = this.actions$.ofType(EFFECT_TWO_FACTOR_AUTH)\n        .switchMap(action => this.authTwoFactor(action))\n        .map(authStatus => ({type: EFFECT_AUTH_END, payload: authStatus}));\n\n    private authTwoFactor(action: Action): Observable<any> {\n        this.store.dispatch({type: EFFECT_AUTH_STATUS, payload: AuthenticateFlags.TWO_FACTOR_CHECK})\n\n        return this.store.select(store => store.appDb.appBaseUrlCloud)\n            .take(1)\n            .mergeMap(baseUrl => {\n                const url = baseUrl.replace('END_POINT', 'twoFactor') + `/${action.payload.token}/${action.payload.enable}`\n                return this.http.get(url)\n                    .catch((err: any) => {\n                        this.toastr.error('Error getting two factor');\n                        return Observable.throw(err);\n                    })\n                    .finally(() => {\n                    })\n                    .map(res => {\n                        var status = res.json();\n                        if (status.result) {\n                            this.store.dispatch({type: EFFECT_AUTH_STATUS, payload: AuthenticateFlags.TWO_FACTOR_PASS})\n                        } else {\n                            this.store.dispatch({type: EFFECT_AUTH_STATUS, payload: AuthenticateFlags.TWO_FACTOR_FAIL})\n                        }\n                    })\n            })\n    }\n\n    @Effect()\n    updatedTwoFactor$: Observable<Action> = this.actions$.ofType(EFFECT_TWO_FACTOR_UPDATING)\n        .switchMap(action => this.updatedTwoFactor(action))\n        .map(authStatus => ({type: EFFECT_AUTH_END, payload: authStatus}));\n\n    private updatedTwoFactor(action: Action): Observable<any> {\n        return this.store.select(store => store.appDb.appBaseUrlCloud)\n            .take(1)\n            .mergeMap(baseUrl => {\n                const url = baseUrl.replace('END_POINT', 'twoFactor') + `/${action.payload.token}/${action.payload.enable}`\n                return this.http.get(url)\n                    .catch((err: any) => {\n                        this.toastr.error('Error getting two factor');\n                        return Observable.throw(err);\n                    })\n                    .finally(() => {\n                    })\n                    .map(res => {\n                        var status = res.json().result;\n                        status == true ? this.store.dispatch({\n                            type: EFFECT_AUTH_STATUS,\n                            payload: AuthenticateFlags.TWO_FACTOR_UPDATE_PASS\n                        }) : this.store.dispatch({\n                            type: EFFECT_AUTH_STATUS,\n                            payload: AuthenticateFlags.TWO_FACTOR_UPDATE_FAIL\n                        })\n                        this.store.dispatch({\n                            type: EFFECT_TWO_FACTOR_UPDATED,\n                            payload: status\n                        })\n                    })\n            })\n    }\n\n\n    @Effect()\n    authUser$: Observable<Action> = this.actions$.ofType(EFFECT_AUTH_START)\n        .switchMap(action => this.authUser(action))\n        .map(authStatus => ({type: EFFECT_AUTH_END, payload: authStatus}));\n\n    private authUser(action: Action): Observable<any> {\n        console.log('authenticating');\n        this.toastr.clearAllToasts();\n        this.toastr.warning('Authenticating, please wait');\n        let userModel: UserModel = action.payload;\n        this.store.dispatch({type: EFFECT_UPDATE_USER_MODEL, payload: userModel});\n\n        return this.rp.dbConnect(userModel.user(), userModel.pass())\n            .take(1)\n            .map((pepperConnection: IPepperConnection) => {\n                console.log('authenticating in process');\n                if (pepperConnection.pepperAuthReply.status == false) {\n                    console.log('authentication failed');\n                    this.toastr.error('Authentication failed')\n                    userModel = userModel.setAuthenticated(false);\n                    userModel = userModel.setAccountType(-1);\n                    if (pepperConnection.pepperAuthReply.warning == 'reseller account') {\n                        userModel = userModel.setAccountType(AuthenticateFlags.ENTERPRISE_ACCOUNT);\n                        bootbox.confirm({\n                            title: \"Enterprise account\",\n                            message: \"You are attempting to login with Enterprise credentials, Would you like to be redirected to the Enterprise studio?\",\n                            buttons: {\n                                cancel: {\n                                    label: '<i class=\"fa fa-times\"></i> cancel'\n                                },\n                                confirm: {\n                                    label: '<i class=\"fa fa-check\"></i> take me there'\n                                }\n                            },\n                            callback: (result) => {\n                                if (result) {\n                                    return window.location.replace('http://dash.digitalsignage.com');\n                                } else {\n                                    this.store.dispatch({type: EFFECT_UPDATE_USER_MODEL, payload: userModel});\n                                    this.store.dispatch({type: EFFECT_AUTH_STATUS, payload: AuthenticateFlags.WRONG_PASS});\n                                    return;\n                                }\n                            }\n                        });\n                    }\n\n                } else {\n\n                    // Authenticated\n\n                    console.log('authenticating check account type');\n                    if (pepperConnection.pepperAuthReply.warning == 'not a studioLite account') {\n                        userModel = userModel.setAccountType(AuthenticateFlags.USER_ACCOUNT_PRO);\n                        var snippet = `\n                        <div id=\"installPanel\">\n                            <h4>You are login in to StudioLite with StudioPro credentials</h4>\n                            <h5>\n                                <b>This will result in limited functionality, please proceed to download StudioPro below...</b>\n                            </h5>\n                            <br/>\n                            <div>\n                                <div class=\"panel-group\" id=\"accordion\">\n                                    <div class=\"panel panel-default\">\n                                        <div class=\"panel-heading\">\n                                            <h4 class=\"panel-title\">\n                                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseThree\">\n                                                    <i class=\"installs fa fa-windows\"></i><span data-localize=\"signageWindows\">StudioPro for Windows</span></a>\n                                            </h4>\n                                        </div>\n                                        <div id=\"collapseThree\" class=\"panel-collapse collapse\">\n                                            <div class=\"panel-body\">\n                                                <ul class=\"installopts\">\n                                                    <li style=\"padding-top: 10px\">\n                                                        <a href=\"http://galaxy.signage.me/code/install/exe/CloudSignageStudioSetup.exe\" class=\"helpLinks btn btn-primary btn-xl\">download now </a>\n                                                    </li>\n                                                </ul>\n                                            </div>\n                                        </div>\n                                    </div>\n                                    <div class=\"panel panel-default\">\n                                        <div class=\"panel-heading\">\n                                            <h4 class=\"panel-title\">\n                                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseFour\">\n                                                    <i class=\"installs fa fa-apple\"></i><span data-localize=\"signageMac\">StudioPro for Mac</span></a>\n                                            </h4>\n                                        </div>\n                                        <div id=\"collapseFour\" class=\"panel-collapse collapse\">\n                                            <div class=\"panel-body\">\n                                                <ul class=\"installopts\">\n                                                    <li>\n                                                        <b data-localize=\"step1\">Step 1:</b><span data-localize=\"downloadAIR\"> download Adobe AIR runtime</span>\n                                                        <a href=\"http://get.adobe.com/air/\" target=\"_blank\" class=\"helpLinks btn btn-primary btn-xs\">download</a>\n                                                    </li>\n                                                    <li>\n                                                        <b data-localize=\"step2\">Step 2:</b><span data-localize=\"downloadSignagePlayer\"> download StudioPro for Mac</span>\n                                                        <a target=\"_blank\" href=\"http://galaxy.signage.me/Code/Install/air/CloudSignageStudio.air\" type=\"button\" class=\"helpLinks btn btn-primary btn-xs\">\n                                                            download\n                                                        </a>\n                                                    </li>\n                                                    <li>\n                                                        <b data-localize=\"step3\">Step 3:</b>\n                                                         Install the runtime and proceed with installing StudioPro for Mac\n                                                    </li>\n                                                </ul>\n                                            </div>\n                                        </div>\n                                    </div>\n                                </div>\n                            </div>\n                        `\n\n                        if (!this.localStorage.getItem('no_show_limited')) {\n                            bootbox.confirm({\n                                title: \"Limited functionality\",\n                                message: snippet,\n                                buttons: {\n                                    cancel: {\n                                        label: '<i class=\"fa fa-circle-o\"></i> do not show again'\n                                    },\n                                    confirm: {\n                                        label: '<i class=\"fa fa-circle\"></i> close'\n                                    }\n                                },\n                                callback: (result) => {\n                                    if (result) return;\n                                    this.localStorage.setItem('no_show_limited', 1);\n\n                                }\n                            });\n                        }\n\n                    } else {\n                        // console.log('lite account');\n                    }\n\n                    var whiteLabel = jXML(pepperConnection.loadManager.m_resellerInfo).find('WhiteLabel');//.attr('enabled'));\n                    var resellerId = jXML(pepperConnection.loadManager.m_resellerInfo).find('BusinessInfo');//.attr('businessId'));\n                    var resellerDataString = jXML(pepperConnection.loadManager.m_resellerInfo).children()[0].innerHTML;\n\n                    var componentList = {};\n                    var components = jXML(pepperConnection.loadManager.m_resellerInfo).find('InstalledApps').find('App');\n                    _.each(components, function (component) {\n                        if (jXML(component).attr('installed') == '1')\n                            componentList[jXML(component).attr('id')] = 1;\n                    });\n                    userModel = userModel.setComponents(componentList)\n\n                    var resellerDataJson = {};\n                    const boundCallback = Observable.bindCallback(this.processXml, (xmlData: any) => xmlData);\n                    boundCallback(this, resellerDataString).subscribe((i_resellerDataJson) => {\n                        resellerDataJson = i_resellerDataJson;\n                    }, (e) => console.error(e))\n                    userModel = userModel.setDomain(pepperConnection.loadManager.m_domain);\n                    userModel = userModel.setAuthenticated(true);\n                    userModel = userModel.setResellerInfo(pepperConnection.loadManager.m_resellerInfo);\n                    userModel = userModel.setResellerName(\n                        jXML(pepperConnection.loadManager.m_resellerInfo)\n                            .find('BusinessInfo')\n                            .attr('name')\n                    );\n\n                    if (userModel.getAccountType() != AuthenticateFlags.USER_ACCOUNT_PRO)\n                        userModel = userModel.setAccountType(AuthenticateFlags.USER_ACCOUNT);\n\n                    userModel = userModel.setResellerId(\n                        Number(jXML(pepperConnection.loadManager.m_resellerInfo)\n                            .find('BusinessInfo')\n                            .attr('businessId'))\n                    );\n                    userModel = userModel.setEri(pepperConnection.loadManager.m_eri);\n                    userModel = userModel.setResellerWhiteLabel(resellerDataJson);\n\n                    this.store.dispatch({type: EFFECT_UPDATE_USER_MODEL, payload: userModel});\n                    this.store.dispatch({\n                        type: EFFECT_AUTH_STATUS, payload: AuthenticateFlags.USER_ACCOUNT\n                    });\n\n\n                }\n\n                // if passed check for two factor\n                if (userModel.getAuthenticated()) {\n                    this.twoFactorCheck()\n                        .take(1)\n                        .subscribe((twoFactorResult) => {\n                            if (window['offlineDevMode']) {\n                                return this.store.dispatch({\n                                    type: EFFECT_AUTH_STATUS,\n                                    payload: AuthenticateFlags.AUTH_PASS_NO_TWO_FACTOR\n                                });\n                            }\n                            userModel = userModel.setBusinessId(twoFactorResult.businessId);\n                            userModel = userModel.setTwoFactorRequired(twoFactorResult.enabled);\n                            this.store.dispatch({type: EFFECT_UPDATE_USER_MODEL, payload: userModel});\n                            if (twoFactorResult.enabled) {\n                                this.store.dispatch({\n                                    type: EFFECT_AUTH_STATUS,\n                                    payload: AuthenticateFlags.TWO_FACTOR_ENABLED\n                                });\n                            } else {\n                                this.toastr.info('Authenticated successfully');\n                                this.store.dispatch({\n                                    type: EFFECT_AUTH_STATUS,\n                                    payload: AuthenticateFlags.AUTH_PASS_NO_TWO_FACTOR\n                                });\n                            }\n                        }, (e) => console.error(e))\n                }\n            });\n    }\n\n    /**\n     *\n     * Stations\n     *\n     */\n\n    @Effect({dispatch: true})\n    loadStations: Observable<Action> = this.actions$.ofType(EFFECT_LOAD_STATIONS)\n        .switchMap(action => this._loadStations(action))\n        .map(stations => ({type: EFFECT_LOADED_STATIONS, payload: stations}));\n\n    private _loadStations(action: Action): Observable<List<StationModel>> {\n\n        const insertStations = (response) => {\n            var stationsList: List<StationModel> = List([]);\n            response.Stations.Station.forEach((i_station) => {\n                if (_.isEmpty(i_station.attr.name))\n                    i_station.attr.name = 'new station';\n                var station: IStation = i_station.attr;\n                var newStation = new StationModel(station)\n                stationsList = stationsList.push(newStation);\n            })\n            return stationsList;\n        }\n\n        const boundCallback = Observable.bindCallback(this.processXml, (xmlData: any) => xmlData);\n        this.store.dispatch({type: EFFECT_LOADING_STATIONS, payload: {}})\n        var url = window.g_protocol + action.payload.userData.domain + '/WebService/getStatus.ashx?user=' + action.payload.userData.userName + '&password=' + action.payload.userData.userPass + '&callback=?';\n        return this.http.get(url)\n            .catch((err: any) => {\n                bootbox.alert('Error loading stations, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .mergeMap((result: Response) => {\n                var s64: string = String(result.text());\n                s64 = s64.replace(/\\?\\({ \"ret\": \"/, '').replace(/\" }\\)/, '');\n                var str = jQuery.base64.decode(s64);\n                return boundCallback(this, str)\n            }).map(response => {\n                if (_.isNull(response) || _.isEmpty(response.Stations))\n                    return List([]);\n\n                var totalBranches = this.rp.getStationBranchTotal();\n                var totalStations = response.Stations.Station.length;\n\n                if (totalStations != totalBranches) {\n                    this.rp.sync(() => {\n                        this.rp.reduxCommit();\n                    })\n                    return insertStations(response);\n                } else {\n                    return insertStations(response);\n                }\n            })\n    }\n\n    @Effect() contactUs$ = this.actions$\n        .ofType(EFFECT_CONTACT_US)\n        .withLatestFrom(this.store.select(store => store.appDb.contact))\n        .switchMap((value: any) =>\n            this.contactService(value[1])\n                .catch(err => {\n                    return Observable.of({err: true, error: err});\n                }).map((v: any) => {\n                return v.err ? formErrorAction('appDb.contact', 'problem connecting to server, please try later...') : formSuccessAction('appDb.contact');\n            })\n        )\n\n    private contactService(body: Map<any, any>) {\n        var data = body.toJS()\n        var options: RequestOptionsArgs = this.createServerCall(`/submitContact_lite/`, RequestMethod.Put, data)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                console.log(err);\n                return Observable.throw(err)\n            })\n            .map((response: Response) => {\n                return response.json();\n            })\n    }\n\n    private getContactUrl(i_urlEndPoint, i_method, i_body): RequestOptionsArgs {\n        var credentials = Lib.EncryptUserPass(this.rp.getUserData().userName, this.rp.getUserData().userPass);\n        var url = `${this.appBaseUrlServices}${i_urlEndPoint}`;\n        var headers = new Headers();\n        headers.append('Authorization', credentials);\n        return {\n            url: url,\n            method: i_method,\n            headers: new Headers({'Authorization': credentials}),\n            body: i_body\n        };\n    }\n\n    private createServerCall(i_urlEndPoint, i_method, i_body): RequestOptionsArgs {\n        var credentials = Lib.EncryptUserPass(this.rp.getUserData().userName, this.rp.getUserData().userPass);\n        var url = `${this.appBaseUrlServices}${i_urlEndPoint}`;\n        var headers = new Headers();\n        headers.append('Authorization', credentials);\n        return {\n            url: url,\n            method: i_method,\n            headers: new Headers({'Authorization': credentials}),\n            body: i_body\n        };\n    }\n\n    /**\n     *\n     * Fasterq\n     *\n     */\n    @Effect({dispatch: true})\n    loadfasterqLines: Observable<Action> = this.actions$.ofType(EFFECT_LOAD_FASTERQ_LINES)\n        .switchMap(action => this._loadFasterqLines(action))\n        .map(stations => ({type: EFFECT_LOADED_FASTERQ_LINES, payload: stations}));\n\n    private _loadFasterqLines(action: Action): Observable<List<FasterqLineModel>> {\n        this.store.dispatch({type: EFFECT_LOADING_FASTERQ_LINES, payload: {}})\n        var options: RequestOptionsArgs = this.createServerCall('/Lines', RequestMethod.Get, '')\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error loading fasterq lines, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                var lines = List([]);\n                var rxLines = response.json();\n                if (rxLines.error)\n                    return lines;\n                rxLines.forEach((line) => {\n                    lines = lines.push(new FasterqLineModel(line))\n                })\n                return lines;\n            })\n    }\n\n    @Effect({dispatch: true})\n    loadfasterqLine: Observable<Action> = this.actions$.ofType(EFFECT_LOAD_FASTERQ_LINE)\n        .switchMap(action => this._loadFasterqLine(action))\n        .map(stations => ({type: EFFECT_LOADED_FASTERQ_LINE, payload: stations}));\n\n    private _loadFasterqLine(action: Action): Observable<FasterqLineModel> {\n        this.store.dispatch({type: EFFECT_LOADING_FASTERQ_LINE, payload: {}})\n        var options: RequestOptionsArgs = this.createServerCall(`/GetLine`, RequestMethod.Post, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error loading fasterq line, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                var data: any = response.json()[0];\n                var line = new FasterqLineModel(data)\n                return line;\n            })\n    }\n\n\n    @Effect({dispatch: true})\n    loadfasterqAnalytics: Observable<Action> = this.actions$.ofType(EFFECT_LOAD_FASTERQ_ANALYTICS)\n        .switchMap(action => this._loadfasterqAnalytics(action))\n        .map(stations => ({type: EFFECT_LOADED_FASTERQ_ANALYTICS, payload: stations}));\n\n    private _loadfasterqAnalytics(action: Action): Observable<List<FasterqLineModel>> {\n        this.store.dispatch({type: EFFECT_LOADING_FASTERQ_ANALYTICS, payload: {}})\n        var options: RequestOptionsArgs = this.createServerCall('/LineAnalytics', RequestMethod.Post, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error loading fasterq analytics, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                var analytics = List([]);\n                var rxAnalytics = response.json();\n                rxAnalytics.forEach((data) => {\n                    analytics = analytics.push(new FasterqAnalyticsModel(data))\n                })\n                return analytics;\n            })\n    }\n\n    @Effect({dispatch: true})\n    loadfasterqQueues: Observable<Action> = this.actions$.ofType(EFFECT_LOAD_FASTERQ_QUEUES)\n        .takeWhile(() => {\n            return this.fasterQueueInFlight == false;\n        })\n        .switchMap(action => this._loadfasterqQueues(action))\n        .map(stations => ({type: EFFECT_LOADED_FASTERQ_QUEUES, payload: stations}));\n\n    private _loadfasterqQueues(action: Action): Observable<List<FasterqLineModel>> {\n        this.store.dispatch({type: EFFECT_LOADING_FASTERQ_QUEUES, payload: {}})\n        var options: RequestOptionsArgs = this.createServerCall(`/Queues`, RequestMethod.Post, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error loading fasterq queues, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                var lines = List([]);\n                var rxQueus = response.json();\n                rxQueus.forEach((queue) => {\n                    lines = lines.push(new FasterqQueueModel(queue))\n                })\n                return lines;\n            })\n    }\n\n    @Effect({dispatch: true})\n    savefasterqQueueCall: Observable<Action> = this.actions$.ofType(EFFECT_QUEUE_CALL_SAVE)\n        .do(() => this.fasterQueueInFlight = true)\n        .switchMap(action => this._savefasterqQueueCall(action))\n        .map(stations => ({type: EFFECT_QUEUE_CALL_SAVED, payload: stations}));\n\n    private _savefasterqQueueCall(action: Action): Observable<List<FasterqLineModel>> {\n        this.store.dispatch({type: EFFECT_QUEUE_CALL_SAVING, payload: {}})\n        var queueSave: IQueueSave = action.payload;\n        var data = Object.assign({}, queueSave.queue.getData().toJS(), queueSave)\n        var options: RequestOptionsArgs = this.createServerCall(`/Queue/${action.payload.queue_id}`, RequestMethod.Put, data)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error saving call fasterq queue, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n                this.fasterQueueInFlight = false;\n            })\n            .map((response: Response) => {\n                var reply = response.json();\n                if (reply.updated == 'alreadyCalled') {\n                    var message: IMessage = {\n                        event: FASTERQ_QUEUE_CALL_CANCLED,\n                        fromInstance: this,\n                        message: data\n                    }\n                    this.commBroker.fire(message)\n                    return null;\n                }\n                return data;\n            })\n    }\n\n    @Effect({dispatch: false})\n    resetFasterqLine: Observable<Action> = this.actions$.ofType(EFFECT_RESET_FASTERQ_LINE)\n        .switchMap(action => this._resetFasterqLine(action))\n        .map(res => ({type: null}));\n\n    private _resetFasterqLine(action: Action): Observable<{}> {\n        var options: RequestOptionsArgs = this.createServerCall(`/ResetQueueCounter`, RequestMethod.Post, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error resetting line, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                var reply = response.json();\n                return {};\n            })\n    }\n\n    @Effect({dispatch: true})\n    savefasterqQueueService: Observable<Action> = this.actions$.ofType(EFFECT_QUEUE_SERVICE_SAVE)\n        .do(() => this.fasterQueueInFlight = true)\n        .switchMap(action => this._savefasterqQueueService(action))\n        .map(stations => ({type: EFFECT_QUEUE_SERVICE_SAVED, payload: stations}));\n\n    private _savefasterqQueueService(action: Action): Observable<List<FasterqLineModel>> {\n        this.store.dispatch({type: EFFECT_QUEUE_SERVICE_SAVING, payload: {}})\n        var queueSave: IQueueSave = action.payload;\n        var data = Object.assign({}, queueSave.queue.getData().toJS(), queueSave)\n        var options: RequestOptionsArgs = this.createServerCall(`/Queue/${action.payload.queue_id}`, RequestMethod.Put, data)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error saving service fasterq queue, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n                this.fasterQueueInFlight = false;\n            })\n            .map((response: Response) => {\n                var data = response.json();\n                return action.payload;\n            })\n    }\n\n    @Effect({dispatch: false})\n    pollServicing: Observable<Action> = this.actions$.ofType(EFFECT_QUEUE_POLL_SERVICE)\n        .switchMap(action => this._pollServicing(action))\n        .do((data: any) => {\n            var uiState: IUiState = {fasterq: {fasterqNowServicing: data}}\n            this.yp.dispatch(({type: ACTION_UISTATE_UPDATE, payload: uiState}))\n        })\n        .map(result => ({type: null}));\n\n    private _pollServicing(action: Action): Observable<List<FasterqLineModel>> {\n        var options: RequestOptionsArgs = this.createServerCall(`/LastCalledQueue`, RequestMethod.Post, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error saving service fasterq queue, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                var data = response.json().service_id\n                return data;\n            })\n    }\n\n    @Effect({dispatch: true})\n    updateFasterqLine: Observable<Action> = this.actions$.ofType(EFFECT_UPDATE_FASTERQ_LINE)\n        .switchMap(action => this._updateFasterqLine(action))\n        .map(payload => ({type: EFFECT_UPDATED_FASTERQ_LINE, payload: payload}));\n\n    private _updateFasterqLine(action: Action): Observable<any> {\n        var options: RequestOptionsArgs = this.createServerCall(`/Line/${action.payload.id}`, RequestMethod.Put, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error saving fasterq line, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                return {\n                    data: action.payload,\n                    serverReplay: response.json()\n                }\n            })\n    }\n\n    @Effect({dispatch: true})\n    removeFasterqLine: Observable<Action> = this.actions$.ofType(EFFECT_REMOVE_FASTERQ_LINE)\n        .switchMap(action => this._removeFasterqLine(action))\n        .map(payload => ({type: EFFECT_REMOVED_FASTERQ_LINE, payload: payload}));\n\n    private _removeFasterqLine(action: Action): Observable<any> {\n        var options: RequestOptionsArgs = this.createServerCall(`/Line/${action.payload.id}`, RequestMethod.Delete, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error removing fasterq line, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                return {\n                    data: action.payload,\n                    serverReplay: response.json()\n                }\n            })\n    }\n\n    @Effect({dispatch: true})\n    addFasterqLine: Observable<Action> = this.actions$.ofType(EFFECT_ADD_FASTERQ_LINE)\n        .switchMap(action => this._addFasterqLine(action))\n        .map(payload => ({type: EFFECT_ADDED_FASTERQ_LINE, payload: payload}));\n\n    private _addFasterqLine(action: Action): Observable<any> {\n        var options: RequestOptionsArgs = this.createServerCall(`/Line`, RequestMethod.Post, action.payload)\n        return this.http.get(options.url, options)\n            .catch((err: any) => {\n                bootbox.alert('Error adding fasterq line, try again later...');\n                return Observable.throw(err);\n            })\n            .finally(() => {\n            })\n            .map((response: Response) => {\n                return {\n                    data: action.payload,\n                    serverReplay: response.json()\n                }\n            })\n    }\n\n    private processXml(context, xmlData, cb) {\n        context.parseString(xmlData, {attrkey: 'attr'}, function (err, result) {\n            if (err || !result)\n                return cb(null);\n            return cb(result);\n        })\n    }\n\n    private twoFactorCheck(): Observable<any> {\n        return this.store.select(store => store.appDb.appBaseUrlCloud)\n            .take(1)\n            .mergeMap(appBaseUrlCloud => {\n                if (window['offlineDevMode']) {\n                    return Observable.of({});\n                }\n                var url = appBaseUrlCloud.replace('END_POINT', 'twoFactorCheck');\n                return this.http.get(url)\n                    .catch((err: any) => {\n                        return Observable.throw(err);\n                    })\n                    .map(res => {\n                        return res.json()\n                    })\n            })\n    }\n}\n\n\n// this.store.select(store => store.appDb.appBaseUrl)\n//     .take(1)\n//     .mergeMap(baseUrl => {\n//         const url = `${baseUrl}?command=GetCustomers&resellerUserName=${userModel.user()}&resellerPassword=${userModel.pass()}`;\n//         return this.http.get(url)\n//             .catch((err: any) => {\n//                 alert('Error getting order details');\n//                 return Observable.throw(err);\n//             })\n//             .finally(() => {\n//             })\n//             .map(res => {\n//                 return res.text()\n//             }).flatMap((i_xmlData: string) => {\n//                 const boundCallback = Observable.bindCallback(this.processXml, (xmlData: any) => xmlData);\n//                 return boundCallback(this, i_xmlData)\n//             }).map(result => {\n//\n//\n//             })\n//     })\n// this.rp.dbConnect(userModel.user(), userModel.pass(), (result:{[key: string]: string}) => {\n//     console.log(result);\n// })\n\n\n/////////////////////////////////////////////////////////////////////////////\n//  currently if logging in with enterprise account, dbConnect will timeout,\n//  Alon needs to fix and we can dispatch code below\n// userModel = userModel.setAuthenticated(true);\n// userModel = userModel.setAccountType(AuthenticateFlags.ENTERPRISE_ACCOUNT);\n// this.store.dispatch({type: EFFECT_UPDATE_USER_MODEL, payload: userModel});\n// this.store.dispatch({\n//     type: EFFECT_AUTH_STATUS, payload: AuthenticateFlags.ENTERPRISE_ACCOUNT\n// });\n/////////////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "src/store/effects/msdb.effects.ts",
    "content": "import {Injectable, Inject} from \"@angular/core\";\nimport {Http} from \"@angular/http\";\nimport \"rxjs/add/operator/map\";\nimport \"rxjs/add/operator/mergeMap\";\nimport \"rxjs/add/operator/merge\";\nimport \"rxjs/add/operator/debounceTime\";\nimport {Action, Store} from \"@ngrx/store\";\nimport {Actions, Effect} from \"@ngrx/effects\";\nimport {Observable} from \"rxjs\";\nimport {RedPepperService} from \"../../services/redpepper.service\";\n\nexport const EFFECT_INIT_REDUXIFY_MSDB = 'EFFECT_INIT_REDUXIFY_MSDB';\nexport const EFFECT_GET_STATIONS = 'EFFECT_GET_STATIONS';\n\n@Injectable()\nexport class MsdbEffects {\n\n    constructor(private actions$: Actions,\n                private redPepperService: RedPepperService,\n                private http: Http) {\n    }\n             \n    @Effect({dispatch: false})\n    reduxifyMsdb$: Observable<Action> = this.actions$.ofType(EFFECT_INIT_REDUXIFY_MSDB)\n        .do(() => {\n            this.redPepperService.reduxCommit(null, true);\n        })\n\n    //todo: add @Effect() getStations API as it is a pure side effecr\n    @Effect()\n    getStations: Observable<Action> = this.actions$.ofType(EFFECT_GET_STATIONS)\n        .debounceTime(500)\n        .mergeMap(({payload}) => {\n            const {term, type} = payload;\n            const url = `https://api.spotify.com/v1/search?q=${term}&type=${type}`;\n            return this.http\n                .get(url)\n                .map((res) => ({type: 'SEARCH_RESULTS', payload: res.json()}))\n                .takeUntil(this.actions$.ofType('SEARCH_CANCELLED'))\n                .catch((err: any, b: any) => {\n                    return Observable.of({type: 'SEARCH_ERROR', payload: err});\n                })\n        })\n\n}\n\n\n"
  },
  {
    "path": "src/store/imsdb.interfaces.ts",
    "content": "import {IDataManager_proto} from \"./imsdb.interfaces_auto\";\n\nexport interface IDataBaseManager extends IDataManager_proto {\n    m_businessData: {\n        string: DataBaseModueBase;\n    },\n    m_selectedDataBase: DataBaseModueBase;\n}\n\n\nexport interface IPepperConnection {\n    pepperAuthReply: IPepperAuthReply;\n    dDataBaseManager: IDataBaseManager;\n    loadManager: ILoadManager;\n}\n\nexport interface IPepperAuthReply {\n    error: string;\n    status: boolean;\n    warning: string;\n}\n\nexport interface DataBaseModueBase {\n    m_tableList: Array<any>;\n    m_table: {}\n}\n\nexport interface ILoadManager {\n    create: (user: string, pass: string, func: (result: any) => void) => void;\n    save: (func: (result: any) => void) => void;\n    requestData: (func: (result: any) => void) => void;\n    importScene: (businessID, nativeID, func: (result: any) => void) => void;\n    requestAdsReport: (a: (d) => void, b: any, c: any) => any;\n    getProofOfPlayStats: any;\n    m_resellerInfo: XMLDocument;\n    m_businessId: number;\n    m_domain: string;\n    m_eri: string;\n    filesToUpload: Array<any>;\n    m_dataBaseManager: IDataBaseManager;\n    m_shortcutMap: {};\n    m_userpass64: any;\n    createResources:( v:any )=>void;\n}\n\n"
  },
  {
    "path": "src/store/imsdb.interfaces_auto.ts",
    "content": "\n\n// >>>> paste into: store/imsdb.interfaces_auto.ts\n\nimport {List} from 'immutable';\n\nimport {StoreModel} from \"../store/model/StoreModel\";\n\nexport class GlobalSettingsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getParamId() {\n        return this.getKey('param_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getParamKey() {\n        return this.getKey('param_key');\n    }\n\n    public getParamValue() {\n        return this.getKey('param_value');\n    }\n\n}\nexport class ResourcesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getResourceId() {\n        return this.getKey('resource_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getResourceName() {\n        return this.getKey('resource_name');\n    }\n\n    public getResourceType() {\n        return this.getKey('resource_type');\n    }\n\n    public getResourcePixelWidth() {\n        return this.getKey('resource_pixel_width');\n    }\n\n    public getResourcePixelHeight() {\n        return this.getKey('resource_pixel_height');\n    }\n\n    public getDefaultPlayer() {\n        return this.getKey('default_player');\n    }\n\n    public getSnapshot() {\n        return this.getKey('snapshot');\n    }\n\n    public getResourceTotalTime() {\n        return this.getKey('resource_total_time');\n    }\n\n    public getResourceDateCreated() {\n        return this.getKey('resource_date_created');\n    }\n\n    public getResourceDateModified() {\n        return this.getKey('resource_date_modified');\n    }\n\n    public getResourceTrust() {\n        return this.getKey('resource_trust');\n    }\n\n    public getResourcePublic() {\n        return this.getKey('resource_public');\n    }\n\n    public getResourceBytesTotal() {\n        return this.getKey('resource_bytes_total');\n    }\n\n    public getResourceModule() {\n        return this.getKey('resource_module');\n    }\n\n    public getTreePath() {\n        return this.getKey('tree_path');\n    }\n\n    public getAccessKey() {\n        return this.getKey('access_key');\n    }\n\n    public getResourceHtml() {\n        return this.getKey('resource_html');\n    }\n\n    public getShortcut() {\n        return this.getKey('shortcut');\n    }\n\n    public getShortcutBusinessId() {\n        return this.getKey('shortcut_business_id');\n    }\n\n    public getShortcutResourceId() {\n        return this.getKey('shortcut_resource_id');\n    }\n\n}\nexport class AdLocalPackagesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdLocalPackageId() {\n        return this.getKey('ad_local_package_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getEnabled() {\n        return this.getKey('enabled');\n    }\n\n    public getPackageName() {\n        return this.getKey('package_name');\n    }\n\n    public getUseDateRange() {\n        return this.getKey('use_date_range');\n    }\n\n    public getStartDate() {\n        return this.getKey('start_date');\n    }\n\n    public getEndDate() {\n        return this.getKey('end_date');\n    }\n\n}\nexport class AdLocalContentsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdLocalContentId() {\n        return this.getKey('ad_local_content_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdLocalPackageId() {\n        return this.getKey('ad_local_package_id');\n    }\n\n    public getEnabled() {\n        return this.getKey('enabled');\n    }\n\n    public getContentName() {\n        return this.getKey('content_name');\n    }\n\n}\nexport class CategoryValuesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCategoryValueId() {\n        return this.getKey('category_value_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getParentCategoryValueId() {\n        return this.getKey('parent_category_value_id');\n    }\n\n    public getCategoryValue() {\n        return this.getKey('category_value');\n    }\n\n}\nexport class CatalogItemsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCatalogItemId() {\n        return this.getKey('catalog_item_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getItemName() {\n        return this.getKey('item_name');\n    }\n\n    public getAdLocalContentId() {\n        return this.getKey('ad_local_content_id');\n    }\n\n}\nexport class CatalogItemInfosModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCatalogItemId() {\n        return this.getKey('catalog_item_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getInfo0() {\n        return this.getKey('info0');\n    }\n\n    public getInfo1() {\n        return this.getKey('info1');\n    }\n\n    public getInfo2() {\n        return this.getKey('info2');\n    }\n\n    public getInfo3() {\n        return this.getKey('info3');\n    }\n\n}\nexport class CatalogItemResourcesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCatalogItemResourceId() {\n        return this.getKey('catalog_item_resource_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCatalogItemId() {\n        return this.getKey('catalog_item_id');\n    }\n\n    public getResourceId() {\n        return this.getKey('resource_id');\n    }\n\n    public getResourceGroup() {\n        return this.getKey('resource_group');\n    }\n\n}\nexport class CatalogItemCategoriesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCatalogItemCategoryId() {\n        return this.getKey('catalog_item_category_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCatalogItemId() {\n        return this.getKey('catalog_item_id');\n    }\n\n    public getCategoryValueId() {\n        return this.getKey('category_value_id');\n    }\n\n}\nexport class PlayerDataModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getPlayerDataId() {\n        return this.getKey('player_data_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getPlayerDataValue() {\n        return this.getKey('player_data_value');\n    }\n\n    public getPlayerDataPublic() {\n        return this.getKey('player_data_public');\n    }\n\n    public getTreePath() {\n        return this.getKey('tree_path');\n    }\n\n    public getSourceCode() {\n        return this.getKey('source_code');\n    }\n\n    public getAccessKey() {\n        return this.getKey('access_key');\n    }\n\n}\nexport class BoardsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getBoardId() {\n        return this.getKey('board_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getBoardName() {\n        return this.getKey('board_name');\n    }\n\n    public getBoardPixelWidth() {\n        return this.getKey('board_pixel_width');\n    }\n\n    public getBoardPixelHeight() {\n        return this.getKey('board_pixel_height');\n    }\n\n    public getMonitorOrientationEnabled() {\n        return this.getKey('monitor_orientation_enabled');\n    }\n\n    public getMonitorOrientationIndex() {\n        return this.getKey('monitor_orientation_index');\n    }\n\n    public getAccessKey() {\n        return this.getKey('access_key');\n    }\n\n    public getTreePath() {\n        return this.getKey('tree_path');\n    }\n\n}\nexport class CampaignsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignId() {\n        return this.getKey('campaign_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignName() {\n        return this.getKey('campaign_name');\n    }\n\n    public getCampaignPlaylistMode() {\n        return this.getKey('campaign_playlist_mode');\n    }\n\n    public getKioskMode() {\n        return this.getKey('kiosk_mode');\n    }\n\n    public getKioskKey() {\n        return this.getKey('kiosk_key');\n    }\n\n    public getKioskTimelineId() {\n        return this.getKey('kiosk_timeline_id');\n    }\n\n    public getKioskWaitTime() {\n        return this.getKey('kiosk_wait_time');\n    }\n\n    public getMouseInterruptMode() {\n        return this.getKey('mouse_interrupt_mode');\n    }\n\n    public getTreePath() {\n        return this.getKey('tree_path');\n    }\n\n    public getAccessKey() {\n        return this.getKey('access_key');\n    }\n\n}\nexport class CampaignChannelsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignChannelId() {\n        return this.getKey('campaign_channel_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignId() {\n        return this.getKey('campaign_id');\n    }\n\n    public getChanelName() {\n        return this.getKey('chanel_name');\n    }\n\n    public getChanelColor() {\n        return this.getKey('chanel_color');\n    }\n\n    public getRandomOrder() {\n        return this.getKey('random_order');\n    }\n\n    public getRepeatToFit() {\n        return this.getKey('repeat_to_fit');\n    }\n\n    public getFixedPlayersLength() {\n        return this.getKey('fixed_players_length');\n    }\n\n}\nexport class CampaignChannelPlayersModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignChannelPlayerId() {\n        return this.getKey('campaign_channel_player_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignChannelId() {\n        return this.getKey('campaign_channel_id');\n    }\n\n    public getPlayerOffsetTime() {\n        return this.getKey('player_offset_time');\n    }\n\n    public getPlayerDuration() {\n        return this.getKey('player_duration');\n    }\n\n    public getPlayerData() {\n        return this.getKey('player_data');\n    }\n\n    public getMouseChildren() {\n        return this.getKey('mouse_children');\n    }\n\n    public getAdLocalContentId() {\n        return this.getKey('ad_local_content_id');\n    }\n\n}\nexport class CampaignTimelinesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignId() {\n        return this.getKey('campaign_id');\n    }\n\n    public getTimelineName() {\n        return this.getKey('timeline_name');\n    }\n\n    public getTimelineDuration() {\n        return this.getKey('timeline_duration');\n    }\n\n}\nexport class CampaignEventsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignEventId() {\n        return this.getKey('campaign_event_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignId() {\n        return this.getKey('campaign_id');\n    }\n\n    public getSenderName() {\n        return this.getKey('sender_name');\n    }\n\n    public getEventName() {\n        return this.getKey('event_name');\n    }\n\n    public getEventCondition() {\n        return this.getKey('event_condition');\n    }\n\n    public getCommandName() {\n        return this.getKey('command_name');\n    }\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n    public getCommandParams() {\n        return this.getKey('command_params');\n    }\n\n}\nexport class CampaignBoardsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignBoardId() {\n        return this.getKey('campaign_board_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getBoardId() {\n        return this.getKey('board_id');\n    }\n\n    public getCampaignId() {\n        return this.getKey('campaign_id');\n    }\n\n    public getCampaignBoardName() {\n        return this.getKey('campaign_board_name');\n    }\n\n    public getAllowPublicView() {\n        return this.getKey('allow_public_view');\n    }\n\n    public getAdminPublicView() {\n        return this.getKey('admin_public_view');\n    }\n\n}\nexport class BoardTemplatesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getBoardTemplateId() {\n        return this.getKey('board_template_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getBoardId() {\n        return this.getKey('board_id');\n    }\n\n    public getTemplateName() {\n        return this.getKey('template_name');\n    }\n\n}\nexport class BoardTemplateViewersModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getBoardTemplateViewerId() {\n        return this.getKey('board_template_viewer_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getBoardTemplateId() {\n        return this.getKey('board_template_id');\n    }\n\n    public getViewerName() {\n        return this.getKey('viewer_name');\n    }\n\n    public getPixelX() {\n        return this.getKey('pixel_x');\n    }\n\n    public getPixelY() {\n        return this.getKey('pixel_y');\n    }\n\n    public getPixelWidth() {\n        return this.getKey('pixel_width');\n    }\n\n    public getPixelHeight() {\n        return this.getKey('pixel_height');\n    }\n\n    public getEnableGaps() {\n        return this.getKey('enable_gaps');\n    }\n\n    public getViewerOrder() {\n        return this.getKey('viewer_order');\n    }\n\n    public getLocked() {\n        return this.getKey('locked');\n    }\n\n}\nexport class CampaignTimelineChanelsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineChanelId() {\n        return this.getKey('campaign_timeline_chanel_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n    public getChanelName() {\n        return this.getKey('chanel_name');\n    }\n\n    public getChanelColor() {\n        return this.getKey('chanel_color');\n    }\n\n    public getRandomOrder() {\n        return this.getKey('random_order');\n    }\n\n    public getRepeatToFit() {\n        return this.getKey('repeat_to_fit');\n    }\n\n    public getFixedPlayersLength() {\n        return this.getKey('fixed_players_length');\n    }\n\n}\nexport class CampaignTimelineChannelsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineChannelId() {\n        return this.getKey('campaign_timeline_channel_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n}\nexport class CampaignTimelineBoardTemplatesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineBoardTemplateId() {\n        return this.getKey('campaign_timeline_board_template_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n    public getBoardTemplateId() {\n        return this.getKey('board_template_id');\n    }\n\n    public getCampaignBoardId() {\n        return this.getKey('campaign_board_id');\n    }\n\n    public getTemplateOffsetTime() {\n        return this.getKey('template_offset_time');\n    }\n\n    public getTemplateDuration() {\n        return this.getKey('template_duration');\n    }\n\n}\nexport class CampaignTimelineBoardViewerChanelsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineBoardViewerChanelId() {\n        return this.getKey('campaign_timeline_board_viewer_chanel_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineBoardTemplateId() {\n        return this.getKey('campaign_timeline_board_template_id');\n    }\n\n    public getBoardTemplateViewerId() {\n        return this.getKey('board_template_viewer_id');\n    }\n\n    public getCampaignTimelineChanelId() {\n        return this.getKey('campaign_timeline_chanel_id');\n    }\n\n}\nexport class CampaignTimelineBoardViewerChannelsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineBoardViewerChannelId() {\n        return this.getKey('campaign_timeline_board_viewer_channel_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineBoardTemplateId() {\n        return this.getKey('campaign_timeline_board_template_id');\n    }\n\n    public getBoardTemplateViewerId() {\n        return this.getKey('board_template_viewer_id');\n    }\n\n    public getCampaignChannelId() {\n        return this.getKey('campaign_channel_id');\n    }\n\n}\nexport class CampaignTimelineChanelPlayersModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineChanelPlayerId() {\n        return this.getKey('campaign_timeline_chanel_player_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineChanelId() {\n        return this.getKey('campaign_timeline_chanel_id');\n    }\n\n    public getPlayerOffsetTime() {\n        return this.getKey('player_offset_time');\n    }\n\n    public getPlayerDuration() {\n        return this.getKey('player_duration');\n    }\n\n    public getPlayerId() {\n        return this.getKey('player_id');\n    }\n\n    public getPlayerEditorId() {\n        return this.getKey('player_editor_id');\n    }\n\n    public getPlayerData() {\n        return this.getKey('player_data');\n    }\n\n    public getMouseChildren() {\n        return this.getKey('mouse_children');\n    }\n\n    public getAdLocalContentId() {\n        return this.getKey('ad_local_content_id');\n    }\n\n}\nexport class CampaignTimelineSchedulesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineScheduleId() {\n        return this.getKey('campaign_timeline_schedule_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n    public getPriorty() {\n        return this.getKey('priorty');\n    }\n\n    public getStartDate() {\n        return this.getKey('start_date');\n    }\n\n    public getEndDate() {\n        return this.getKey('end_date');\n    }\n\n    public getRepeatType() {\n        return this.getKey('repeat_type');\n    }\n\n    public getWeekDays() {\n        return this.getKey('week_days');\n    }\n\n    public getCustomDuration() {\n        return this.getKey('custom_duration');\n    }\n\n    public getDuration() {\n        return this.getKey('duration');\n    }\n\n    public getStartTime() {\n        return this.getKey('start_time');\n    }\n\n    public getPatternEnabled() {\n        return this.getKey('pattern_enabled');\n    }\n\n    public getPatternName() {\n        return this.getKey('pattern_name');\n    }\n\n}\nexport class CampaignTimelineSequencesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getCampaignTimelineSequenceId() {\n        return this.getKey('campaign_timeline_sequence_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getCampaignId() {\n        return this.getKey('campaign_id');\n    }\n\n    public getCampaignTimelineId() {\n        return this.getKey('campaign_timeline_id');\n    }\n\n    public getSequenceIndex() {\n        return this.getKey('sequence_index');\n    }\n\n    public getSequenceCount() {\n        return this.getKey('sequence_count');\n    }\n\n}\nexport class ScriptsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getScriptId() {\n        return this.getKey('script_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getScriptSrc() {\n        return this.getKey('script_src');\n    }\n\n}\nexport class MusicChannelsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getMusicChannelId() {\n        return this.getKey('music_channel_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getMusicChannelName() {\n        return this.getKey('music_channel_name');\n    }\n\n    public getAccessKey() {\n        return this.getKey('access_key');\n    }\n\n    public getTreePath() {\n        return this.getKey('tree_path');\n    }\n\n}\nexport class MusicChannelSongsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getMusicChannelSongId() {\n        return this.getKey('music_channel_song_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getMusicChannelId() {\n        return this.getKey('music_channel_id');\n    }\n\n    public getResourceId() {\n        return this.getKey('resource_id');\n    }\n\n}\nexport class BranchStationsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getBranchStationId() {\n        return this.getKey('branch_station_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getBranchId() {\n        return this.getKey('branch_id');\n    }\n\n    public getCampaignBoardId() {\n        return this.getKey('campaign_board_id');\n    }\n\n    public getStationName() {\n        return this.getKey('station_name');\n    }\n\n    public getRebootExceedMemEnabled() {\n        return this.getKey('reboot_exceed_mem_enabled');\n    }\n\n    public getRebootExceedMemValue() {\n        return this.getKey('reboot_exceed_mem_value');\n    }\n\n    public getRebootTimeEnabled() {\n        return this.getKey('reboot_time_enabled');\n    }\n\n    public getRebootTimeValue() {\n        return this.getKey('reboot_time_value');\n    }\n\n    public getRebootErrorEnabled() {\n        return this.getKey('reboot_error_enabled');\n    }\n\n    public getMonitorStandbyEnabled() {\n        return this.getKey('monitor_standby_enabled');\n    }\n\n    public getMonitorStandbyFrom() {\n        return this.getKey('monitor_standby_from');\n    }\n\n    public getMonitorStandbyTo() {\n        return this.getKey('monitor_standby_to');\n    }\n\n    public getLocationAddress() {\n        return this.getKey('location_address');\n    }\n\n    public getLocationLong() {\n        return this.getKey('location_long');\n    }\n\n    public getLocationLat() {\n        return this.getKey('location_lat');\n    }\n\n    public getMapType() {\n        return this.getKey('map_type');\n    }\n\n    public getMapZoom() {\n        return this.getKey('map_zoom');\n    }\n\n    public getStationSelected() {\n        return this.getKey('station_selected');\n    }\n\n    public getAdvertisingDescription() {\n        return this.getKey('advertising_description');\n    }\n\n    public getAdvertisingKeys() {\n        return this.getKey('advertising_keys');\n    }\n\n    public getRebootExceedMemAction() {\n        return this.getKey('reboot_exceed_mem_action');\n    }\n\n    public getRebootTimeAction() {\n        return this.getKey('reboot_time_action');\n    }\n\n    public getRebootErrorAction() {\n        return this.getKey('reboot_error_action');\n    }\n\n    public getStationMode() {\n        return this.getKey('station_mode');\n    }\n\n    public getPowerMode() {\n        return this.getKey('power_mode');\n    }\n\n    public getPowerOnDay1() {\n        return this.getKey('power_on_day1');\n    }\n\n    public getPowerOffDay1() {\n        return this.getKey('power_off_day1');\n    }\n\n    public getPowerOnDay2() {\n        return this.getKey('power_on_day2');\n    }\n\n    public getPowerOffDay2() {\n        return this.getKey('power_off_day2');\n    }\n\n    public getPowerOnDay3() {\n        return this.getKey('power_on_day3');\n    }\n\n    public getPowerOffDay3() {\n        return this.getKey('power_off_day3');\n    }\n\n    public getPowerOnDay4() {\n        return this.getKey('power_on_day4');\n    }\n\n    public getPowerOffDay4() {\n        return this.getKey('power_off_day4');\n    }\n\n    public getPowerOnDay5() {\n        return this.getKey('power_on_day5');\n    }\n\n    public getPowerOffDay5() {\n        return this.getKey('power_off_day5');\n    }\n\n    public getPowerOnDay6() {\n        return this.getKey('power_on_day6');\n    }\n\n    public getPowerOffDay6() {\n        return this.getKey('power_off_day6');\n    }\n\n    public getPowerOnDay7() {\n        return this.getKey('power_on_day7');\n    }\n\n    public getPowerOffDay7() {\n        return this.getKey('power_off_day7');\n    }\n\n    public getSendNotification() {\n        return this.getKey('send_notification');\n    }\n\n    public getFrameRate() {\n        return this.getKey('frame_rate');\n    }\n\n    public getQuality() {\n        return this.getKey('quality');\n    }\n\n    public getTransitionEnabled() {\n        return this.getKey('transition_enabled');\n    }\n\n    public getZwaveConfig() {\n        return this.getKey('zwave_config');\n    }\n\n    public getLanServerEnabled() {\n        return this.getKey('lan_server_enabled');\n    }\n\n    public getLanServerIp() {\n        return this.getKey('lan_server_ip');\n    }\n\n    public getLanServerPort() {\n        return this.getKey('lan_server_port');\n    }\n\n}\nexport class AdRatesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdRateId() {\n        return this.getKey('ad_rate_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdRateName() {\n        return this.getKey('ad_rate_name');\n    }\n\n    public getAdRateMap() {\n        return this.getKey('ad_rate_map');\n    }\n\n    public getHourRate0() {\n        return this.getKey('hour_rate0');\n    }\n\n    public getHourRate1() {\n        return this.getKey('hour_rate1');\n    }\n\n    public getHourRate2() {\n        return this.getKey('hour_rate2');\n    }\n\n    public getHourRate3() {\n        return this.getKey('hour_rate3');\n    }\n\n}\nexport class StationAdsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getBranchStationId() {\n        return this.getKey('branch_station_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdvertisingNetwork() {\n        return this.getKey('advertising_network');\n    }\n\n    public getAdvertisingDescription() {\n        return this.getKey('advertising_description');\n    }\n\n    public getAdvertisingKeys() {\n        return this.getKey('advertising_keys');\n    }\n\n    public getAdRateId() {\n        return this.getKey('ad_rate_id');\n    }\n\n}\nexport class AdOutPackagesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdOutPackageId() {\n        return this.getKey('ad_out_package_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getPackageName() {\n        return this.getKey('package_name');\n    }\n\n    public getStartDate() {\n        return this.getKey('start_date');\n    }\n\n    public getEndDate() {\n        return this.getKey('end_date');\n    }\n\n}\nexport class AdOutPackageContentsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdOutPackageContentId() {\n        return this.getKey('ad_out_package_content_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdOutPackageId() {\n        return this.getKey('ad_out_package_id');\n    }\n\n    public getResourceId() {\n        return this.getKey('resource_id');\n    }\n\n    public getPlayerDataId() {\n        return this.getKey('player_data_id');\n    }\n\n    public getDuration() {\n        return this.getKey('duration');\n    }\n\n    public getReparationsPerHour() {\n        return this.getKey('reparations_per_hour');\n    }\n\n}\nexport class AdOutPackageStationsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdOutPackageStationId() {\n        return this.getKey('ad_out_package_station_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdOutPackageId() {\n        return this.getKey('ad_out_package_id');\n    }\n\n    public getAdOutSubdomain() {\n        return this.getKey('ad_out_subdomain');\n    }\n\n    public getAdOutBusinessId() {\n        return this.getKey('ad_out_business_id');\n    }\n\n    public getAdOutStationId() {\n        return this.getKey('ad_out_station_id');\n    }\n\n    public getDaysMask() {\n        return this.getKey('days_mask');\n    }\n\n    public getHourStart() {\n        return this.getKey('hour_start');\n    }\n\n    public getHourEnd() {\n        return this.getKey('hour_end');\n    }\n\n}\nexport class AdInDomainsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdInDomainId() {\n        return this.getKey('ad_in_domain_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdOutDomain() {\n        return this.getKey('ad_out_domain');\n    }\n\n    public getAcceptNewBusiness() {\n        return this.getKey('accept_new_business');\n    }\n\n}\nexport class AdInDomainBusinessesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdInDomainBusinessId() {\n        return this.getKey('ad_in_domain_business_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdInDomainId() {\n        return this.getKey('ad_in_domain_id');\n    }\n\n    public getAdOutBusinessId() {\n        return this.getKey('ad_out_business_id');\n    }\n\n    public getAcceptNewPackage() {\n        return this.getKey('accept_new_package');\n    }\n\n}\nexport class AdInDomainBusinessPackagesModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdInDomainBusinessPackageId() {\n        return this.getKey('ad_in_domain_business_package_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdInDomainBusinessId() {\n        return this.getKey('ad_in_domain_business_id');\n    }\n\n    public getAdPackageId() {\n        return this.getKey('ad_package_id');\n    }\n\n    public getAcceptNewStation() {\n        return this.getKey('accept_new_station');\n    }\n\n    public getSuspendModifiedPackageDate() {\n        return this.getKey('suspend_modified_package_date');\n    }\n\n    public getSuspendModifiedContent() {\n        return this.getKey('suspend_modified_content');\n    }\n\n}\nexport class AdInDomainBusinessPackageStationsModel extends StoreModel {\n    constructor(data: any = {}) {super(data);}\n\n    public getAdInDomainBusinessPackageStationId() {\n        return this.getKey('ad_in_domain_business_package_station_id');\n    }\n\n    public getChangelistId() {\n        return this.getKey('changelist_id');\n    }\n\n    public getChangeType() {\n        return this.getKey('change_type');\n    }\n\n    public getAdInDomainBusinessPackageId() {\n        return this.getKey('ad_in_domain_business_package_id');\n    }\n\n    public getAdPackageStationId() {\n        return this.getKey('ad_package_station_id');\n    }\n\n    public getAcceptStatus() {\n        return this.getKey('accept_status');\n    }\n\n    public getSuspendModifiedStation() {\n        return this.getKey('suspend_modified_station');\n    }\n\n}\n\n\n\nexport interface ISDK {\n\n    table_global_settings?: List<GlobalSettingsModel>;\n    table_resources?: List<ResourcesModel>;\n    table_ad_local_packages?: List<AdLocalPackagesModel>;\n    table_ad_local_contents?: List<AdLocalContentsModel>;\n    table_category_values?: List<CategoryValuesModel>;\n    table_catalog_items?: List<CatalogItemsModel>;\n    table_catalog_item_infos?: List<CatalogItemInfosModel>;\n    table_catalog_item_resources?: List<CatalogItemResourcesModel>;\n    table_catalog_item_categories?: List<CatalogItemCategoriesModel>;\n    table_player_data?: List<PlayerDataModel>;\n    table_boards?: List<BoardsModel>;\n    table_campaigns?: List<CampaignsModel>;\n    table_campaign_channels?: List<CampaignChannelsModel>;\n    table_campaign_channel_players?: List<CampaignChannelPlayersModel>;\n    table_campaign_timelines?: List<CampaignTimelinesModel>;\n    table_campaign_events?: List<CampaignEventsModel>;\n    table_campaign_boards?: List<CampaignBoardsModel>;\n    table_board_templates?: List<BoardTemplatesModel>;\n    table_board_template_viewers?: List<BoardTemplateViewersModel>;\n    table_campaign_timeline_chanels?: List<CampaignTimelineChanelsModel>;\n    table_campaign_timeline_channels?: List<CampaignTimelineChannelsModel>;\n    table_campaign_timeline_board_templates?: List<CampaignTimelineBoardTemplatesModel>;\n    table_campaign_timeline_board_viewer_chanels?: List<CampaignTimelineBoardViewerChanelsModel>;\n    table_campaign_timeline_board_viewer_channels?: List<CampaignTimelineBoardViewerChannelsModel>;\n    table_campaign_timeline_chanel_players?: List<CampaignTimelineChanelPlayersModel>;\n    table_campaign_timeline_schedules?: List<CampaignTimelineSchedulesModel>;\n    table_campaign_timeline_sequences?: List<CampaignTimelineSequencesModel>;\n    table_scripts?: List<ScriptsModel>;\n    table_music_channels?: List<MusicChannelsModel>;\n    table_music_channel_songs?: List<MusicChannelSongsModel>;\n    table_branch_stations?: List<BranchStationsModel>;\n    table_ad_rates?: List<AdRatesModel>;\n    table_station_ads?: List<StationAdsModel>;\n    table_ad_out_packages?: List<AdOutPackagesModel>;\n    table_ad_out_package_contents?: List<AdOutPackageContentsModel>;\n    table_ad_out_package_stations?: List<AdOutPackageStationsModel>;\n    table_ad_in_domains?: List<AdInDomainsModel>;\n    table_ad_in_domain_businesses?: List<AdInDomainBusinessesModel>;\n    table_ad_in_domain_business_packages?: List<AdInDomainBusinessPackagesModel>;\n    table_ad_in_domain_business_package_stations?: List<AdInDomainBusinessPackageStationsModel>;\n\n}\n\n\nexport const TableNames = [\n    'global_settings',\n    'resources',\n    'ad_local_packages',\n    'ad_local_contents',\n    'category_values',\n    'catalog_items',\n    'catalog_item_infos',\n    'catalog_item_resources',\n    'catalog_item_categories',\n    'player_data',\n    'boards',\n    'campaigns',\n    'campaign_channels',\n    'campaign_channel_players',\n    'campaign_timelines',\n    'campaign_events',\n    'campaign_boards',\n    'board_templates',\n    'board_template_viewers',\n    'campaign_timeline_chanels',\n    'campaign_timeline_channels',\n    'campaign_timeline_board_templates',\n    'campaign_timeline_board_viewer_chanels',\n    'campaign_timeline_board_viewer_channels',\n    'campaign_timeline_chanel_players',\n    'campaign_timeline_schedules',\n    'campaign_timeline_sequences',\n    'scripts',\n    'music_channels',\n    'music_channel_songs',\n    'branch_stations',\n    'ad_rates',\n    'station_ads',\n    'ad_out_packages',\n    'ad_out_package_contents',\n    'ad_out_package_stations',\n    'ad_in_domains',\n    'ad_in_domain_businesses',\n    'ad_in_domain_business_packages',\n    'ad_in_domain_business_package_stations',\n\n]\n\n\nexport interface IBaseProto {\n    m_name:string;\n    fields:Array<any>\n    addData: (i_xmlTable) => any;\n    getHandle: (i_id) => any;\n    setRecordId: (i_handle,i_id) => any;\n    createRecord: () => any;\n    addRecord: (i_record,i_handle) => any;\n    getRec: (i_handle) => any;\n    getAllPrimaryKeys: () => any;\n    openForEdit: (i_handel) => any;\n    openForDelete: (i_handel) => any;\n    appendModifyAndNewChangelist: (i_doc) => any;\n    appendDeletedChangelist: (i_doc) => any;\n    getPlayerDataIds: (i_playerData) => any;\n    convertToIds: (i_docPlayerData) => any;\n    createPlayId: (i_xmlPlayer) => any;\n    getNewPrimaryKeys: () => any;\n    getModifyPrimaryKeys: () => any;\n    getDeletedPrimaryKeys: () => any;\n    getConflictPrimaryKeys: () => any;\n    commitChanges: (i_changelistId) => any;\n\n}\n\n\nexport interface ITable_global_settings extends IBaseProto {\n    m_fields: [{\"field\":\"param_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"param_key\"},{\"field\":\"param_value\"}]\n}\nexport interface ITable_resources extends IBaseProto {\n    m_fields: [{\"field\":\"resource_id\",\"foriegn\":\"resources\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"resource_name\"},{\"field\":\"resource_type\"},{\"field\":\"resource_pixel_width\"},{\"field\":\"resource_pixel_height\"},{\"field\":\"default_player\"},{\"field\":\"snapshot\"},{\"field\":\"resource_total_time\"},{\"field\":\"resource_date_created\"},{\"field\":\"resource_date_modified\"},{\"field\":\"resource_trust\"},{\"field\":\"resource_public\"},{\"field\":\"resource_bytes_total\"},{\"field\":\"resource_module\"},{\"field\":\"tree_path\"},{\"field\":\"access_key\"},{\"field\":\"resource_html\"},{\"field\":\"shortcut\"},{\"field\":\"shortcut_business_id\"},{\"field\":\"shortcut_resource_id\"}]\n}\nexport interface ITable_ad_local_packages extends IBaseProto {\n    m_fields: [{\"field\":\"ad_local_package_id\",\"foriegn\":\"ad_local_packages\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"enabled\"},{\"field\":\"package_name\"},{\"field\":\"use_date_range\"},{\"field\":\"start_date\"},{\"field\":\"end_date\"}]\n}\nexport interface ITable_ad_local_contents extends IBaseProto {\n    m_fields: [{\"field\":\"ad_local_content_id\",\"foriegn\":\"ad_local_contents\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_local_package_id\",\"foriegn\":\"ad_local_packages\",\"isNullAble\":false},{\"field\":\"enabled\"},{\"field\":\"content_name\"}]\n}\nexport interface ITable_category_values extends IBaseProto {\n    m_fields: [{\"field\":\"category_value_id\",\"foriegn\":\"category_values\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"parent_category_value_id\"},{\"field\":\"category_value\"}]\n}\nexport interface ITable_catalog_items extends IBaseProto {\n    m_fields: [{\"field\":\"catalog_item_id\",\"foriegn\":\"catalog_items\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"item_name\"},{\"field\":\"ad_local_content_id\",\"foriegn\":\"ad_local_contents\",\"isNullAble\":true}]\n}\nexport interface ITable_catalog_item_infos extends IBaseProto {\n    m_fields: [{\"field\":\"catalog_item_id\",\"foriegn\":\"catalog_items\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"info0\"},{\"field\":\"info1\"},{\"field\":\"info2\"},{\"field\":\"info3\"}]\n}\nexport interface ITable_catalog_item_resources extends IBaseProto {\n    m_fields: [{\"field\":\"catalog_item_resource_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"catalog_item_id\",\"foriegn\":\"catalog_items\",\"isNullAble\":false},{\"field\":\"resource_id\",\"foriegn\":\"resources\",\"isNullAble\":false},{\"field\":\"resource_group\"}]\n}\nexport interface ITable_catalog_item_categories extends IBaseProto {\n    m_fields: [{\"field\":\"catalog_item_category_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"catalog_item_id\",\"foriegn\":\"catalog_items\",\"isNullAble\":false},{\"field\":\"category_value_id\",\"foriegn\":\"category_values\",\"isNullAble\":false}]\n}\nexport interface ITable_player_data extends IBaseProto {\n    m_fields: [{\"field\":\"player_data_id\",\"foriegn\":\"player_data\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"player_data_value\"},{\"field\":\"player_data_public\"},{\"field\":\"tree_path\"},{\"field\":\"source_code\"},{\"field\":\"access_key\"}]\n}\nexport interface ITable_boards extends IBaseProto {\n    m_fields: [{\"field\":\"board_id\",\"foriegn\":\"boards\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"board_name\"},{\"field\":\"board_pixel_width\"},{\"field\":\"board_pixel_height\"},{\"field\":\"monitor_orientation_enabled\"},{\"field\":\"monitor_orientation_index\"},{\"field\":\"access_key\"},{\"field\":\"tree_path\"}]\n}\nexport interface ITable_campaigns extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_id\",\"foriegn\":\"campaigns\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_name\"},{\"field\":\"campaign_playlist_mode\"},{\"field\":\"kiosk_mode\"},{\"field\":\"kiosk_key\"},{\"field\":\"kiosk_timeline_id\"},{\"field\":\"kiosk_wait_time\"},{\"field\":\"mouse_interrupt_mode\"},{\"field\":\"tree_path\"},{\"field\":\"access_key\"}]\n}\nexport interface ITable_campaign_channels extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_channel_id\",\"foriegn\":\"campaign_channels\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_id\",\"foriegn\":\"campaigns\",\"isNullAble\":false},{\"field\":\"chanel_name\"},{\"field\":\"chanel_color\"},{\"field\":\"random_order\"},{\"field\":\"repeat_to_fit\"},{\"field\":\"fixed_players_length\"}]\n}\nexport interface ITable_campaign_channel_players extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_channel_player_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_channel_id\",\"foriegn\":\"campaign_channels\",\"isNullAble\":false},{\"field\":\"player_offset_time\"},{\"field\":\"player_duration\"},{\"field\":\"player_data\"},{\"field\":\"mouse_children\"},{\"field\":\"ad_local_content_id\",\"foriegn\":\"ad_local_contents\",\"isNullAble\":true}]\n}\nexport interface ITable_campaign_timelines extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_id\",\"foriegn\":\"campaigns\",\"isNullAble\":false},{\"field\":\"timeline_name\"},{\"field\":\"timeline_duration\"}]\n}\nexport interface ITable_campaign_events extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_event_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_id\",\"foriegn\":\"campaigns\",\"isNullAble\":true},{\"field\":\"sender_name\"},{\"field\":\"event_name\"},{\"field\":\"event_condition\"},{\"field\":\"command_name\"},{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":true},{\"field\":\"command_params\"}]\n}\nexport interface ITable_campaign_boards extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_board_id\",\"foriegn\":\"campaign_boards\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"board_id\",\"foriegn\":\"boards\",\"isNullAble\":false},{\"field\":\"campaign_id\",\"foriegn\":\"campaigns\",\"isNullAble\":false},{\"field\":\"campaign_board_name\"},{\"field\":\"allow_public_view\"},{\"field\":\"admin_public_view\"}]\n}\nexport interface ITable_board_templates extends IBaseProto {\n    m_fields: [{\"field\":\"board_template_id\",\"foriegn\":\"board_templates\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"board_id\",\"foriegn\":\"boards\",\"isNullAble\":false},{\"field\":\"template_name\"}]\n}\nexport interface ITable_board_template_viewers extends IBaseProto {\n    m_fields: [{\"field\":\"board_template_viewer_id\",\"foriegn\":\"board_template_viewers\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"board_template_id\",\"foriegn\":\"board_templates\",\"isNullAble\":false},{\"field\":\"viewer_name\"},{\"field\":\"pixel_x\"},{\"field\":\"pixel_y\"},{\"field\":\"pixel_width\"},{\"field\":\"pixel_height\"},{\"field\":\"enable_gaps\"},{\"field\":\"viewer_order\"},{\"field\":\"locked\"}]\n}\nexport interface ITable_campaign_timeline_chanels extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_chanel_id\",\"foriegn\":\"campaign_timeline_chanels\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":false},{\"field\":\"chanel_name\"},{\"field\":\"chanel_color\"},{\"field\":\"random_order\"},{\"field\":\"repeat_to_fit\"},{\"field\":\"fixed_players_length\"}]\n}\nexport interface ITable_campaign_timeline_channels extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_channel_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":false}]\n}\nexport interface ITable_campaign_timeline_board_templates extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_board_template_id\",\"foriegn\":\"campaign_timeline_board_templates\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":false},{\"field\":\"board_template_id\",\"foriegn\":\"board_templates\",\"isNullAble\":false},{\"field\":\"campaign_board_id\",\"foriegn\":\"campaign_boards\",\"isNullAble\":false},{\"field\":\"template_offset_time\"},{\"field\":\"template_duration\"}]\n}\nexport interface ITable_campaign_timeline_board_viewer_chanels extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_board_viewer_chanel_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_board_template_id\",\"foriegn\":\"campaign_timeline_board_templates\",\"isNullAble\":false},{\"field\":\"board_template_viewer_id\",\"foriegn\":\"board_template_viewers\",\"isNullAble\":false},{\"field\":\"campaign_timeline_chanel_id\",\"foriegn\":\"campaign_timeline_chanels\",\"isNullAble\":false}]\n}\nexport interface ITable_campaign_timeline_board_viewer_channels extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_board_viewer_channel_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_board_template_id\",\"foriegn\":\"campaign_timeline_board_templates\",\"isNullAble\":false},{\"field\":\"board_template_viewer_id\",\"foriegn\":\"board_template_viewers\",\"isNullAble\":false},{\"field\":\"campaign_channel_id\",\"foriegn\":\"campaign_channels\",\"isNullAble\":false}]\n}\nexport interface ITable_campaign_timeline_chanel_players extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_chanel_player_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_chanel_id\",\"foriegn\":\"campaign_timeline_chanels\",\"isNullAble\":false},{\"field\":\"player_offset_time\"},{\"field\":\"player_duration\"},{\"field\":\"player_id\"},{\"field\":\"player_editor_id\"},{\"field\":\"player_data\"},{\"field\":\"mouse_children\"},{\"field\":\"ad_local_content_id\",\"foriegn\":\"ad_local_contents\",\"isNullAble\":true}]\n}\nexport interface ITable_campaign_timeline_schedules extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_schedule_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":false},{\"field\":\"priorty\"},{\"field\":\"start_date\"},{\"field\":\"end_date\"},{\"field\":\"repeat_type\"},{\"field\":\"week_days\"},{\"field\":\"custom_duration\"},{\"field\":\"duration\"},{\"field\":\"start_time\"},{\"field\":\"pattern_enabled\"},{\"field\":\"pattern_name\"}]\n}\nexport interface ITable_campaign_timeline_sequences extends IBaseProto {\n    m_fields: [{\"field\":\"campaign_timeline_sequence_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"campaign_id\",\"foriegn\":\"campaigns\",\"isNullAble\":false},{\"field\":\"campaign_timeline_id\",\"foriegn\":\"campaign_timelines\",\"isNullAble\":false},{\"field\":\"sequence_index\"},{\"field\":\"sequence_count\"}]\n}\nexport interface ITable_scripts extends IBaseProto {\n    m_fields: [{\"field\":\"script_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"script_src\"}]\n}\nexport interface ITable_music_channels extends IBaseProto {\n    m_fields: [{\"field\":\"music_channel_id\",\"foriegn\":\"music_channels\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"music_channel_name\"},{\"field\":\"access_key\"},{\"field\":\"tree_path\"}]\n}\nexport interface ITable_music_channel_songs extends IBaseProto {\n    m_fields: [{\"field\":\"music_channel_song_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"music_channel_id\",\"foriegn\":\"music_channels\",\"isNullAble\":false},{\"field\":\"resource_id\",\"foriegn\":\"resources\",\"isNullAble\":false}]\n}\nexport interface ITable_branch_stations extends IBaseProto {\n    m_fields: [{\"field\":\"branch_station_id\",\"foriegn\":\"branch_stations\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"branch_id\"},{\"field\":\"campaign_board_id\",\"foriegn\":\"campaign_boards\",\"isNullAble\":true},{\"field\":\"station_name\"},{\"field\":\"reboot_exceed_mem_enabled\"},{\"field\":\"reboot_exceed_mem_value\"},{\"field\":\"reboot_time_enabled\"},{\"field\":\"reboot_time_value\"},{\"field\":\"reboot_error_enabled\"},{\"field\":\"monitor_standby_enabled\"},{\"field\":\"monitor_standby_from\"},{\"field\":\"monitor_standby_to\"},{\"field\":\"location_address\"},{\"field\":\"location_long\"},{\"field\":\"location_lat\"},{\"field\":\"map_type\"},{\"field\":\"map_zoom\"},{\"field\":\"station_selected\"},{\"field\":\"advertising_description\"},{\"field\":\"advertising_keys\"},{\"field\":\"reboot_exceed_mem_action\"},{\"field\":\"reboot_time_action\"},{\"field\":\"reboot_error_action\"},{\"field\":\"station_mode\"},{\"field\":\"power_mode\"},{\"field\":\"power_on_day1\"},{\"field\":\"power_off_day1\"},{\"field\":\"power_on_day2\"},{\"field\":\"power_off_day2\"},{\"field\":\"power_on_day3\"},{\"field\":\"power_off_day3\"},{\"field\":\"power_on_day4\"},{\"field\":\"power_off_day4\"},{\"field\":\"power_on_day5\"},{\"field\":\"power_off_day5\"},{\"field\":\"power_on_day6\"},{\"field\":\"power_off_day6\"},{\"field\":\"power_on_day7\"},{\"field\":\"power_off_day7\"},{\"field\":\"send_notification\"},{\"field\":\"frame_rate\"},{\"field\":\"quality\"},{\"field\":\"transition_enabled\"},{\"field\":\"zwave_config\"},{\"field\":\"lan_server_enabled\"},{\"field\":\"lan_server_ip\"},{\"field\":\"lan_server_port\"}]\n}\nexport interface ITable_ad_rates extends IBaseProto {\n    m_fields: [{\"field\":\"ad_rate_id\",\"foriegn\":\"ad_rates\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_rate_name\"},{\"field\":\"ad_rate_map\"},{\"field\":\"hour_rate0\"},{\"field\":\"hour_rate1\"},{\"field\":\"hour_rate2\"},{\"field\":\"hour_rate3\"}]\n}\nexport interface ITable_station_ads extends IBaseProto {\n    m_fields: [{\"field\":\"branch_station_id\",\"foriegn\":\"branch_stations\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"advertising_network\"},{\"field\":\"advertising_description\"},{\"field\":\"advertising_keys\"},{\"field\":\"ad_rate_id\",\"foriegn\":\"ad_rates\",\"isNullAble\":true}]\n}\nexport interface ITable_ad_out_packages extends IBaseProto {\n    m_fields: [{\"field\":\"ad_out_package_id\",\"foriegn\":\"ad_out_packages\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"package_name\"},{\"field\":\"start_date\"},{\"field\":\"end_date\"}]\n}\nexport interface ITable_ad_out_package_contents extends IBaseProto {\n    m_fields: [{\"field\":\"ad_out_package_content_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_out_package_id\",\"foriegn\":\"ad_out_packages\",\"isNullAble\":false},{\"field\":\"resource_id\",\"foriegn\":\"resources\",\"isNullAble\":true},{\"field\":\"player_data_id\",\"foriegn\":\"player_data\",\"isNullAble\":true},{\"field\":\"duration\"},{\"field\":\"reparations_per_hour\"}]\n}\nexport interface ITable_ad_out_package_stations extends IBaseProto {\n    m_fields: [{\"field\":\"ad_out_package_station_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_out_package_id\",\"foriegn\":\"ad_out_packages\",\"isNullAble\":false},{\"field\":\"ad_out_subdomain\"},{\"field\":\"ad_out_business_id\"},{\"field\":\"ad_out_station_id\"},{\"field\":\"days_mask\"},{\"field\":\"hour_start\"},{\"field\":\"hour_end\"}]\n}\nexport interface ITable_ad_in_domains extends IBaseProto {\n    m_fields: [{\"field\":\"ad_in_domain_id\",\"foriegn\":\"ad_in_domains\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_out_domain\"},{\"field\":\"accept_new_business\"}]\n}\nexport interface ITable_ad_in_domain_businesses extends IBaseProto {\n    m_fields: [{\"field\":\"ad_in_domain_business_id\",\"foriegn\":\"ad_in_domain_businesses\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_in_domain_id\",\"foriegn\":\"ad_in_domains\",\"isNullAble\":false},{\"field\":\"ad_out_business_id\"},{\"field\":\"accept_new_package\"}]\n}\nexport interface ITable_ad_in_domain_business_packages extends IBaseProto {\n    m_fields: [{\"field\":\"ad_in_domain_business_package_id\",\"foriegn\":\"ad_in_domain_business_packages\",\"isNullAble\":false},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_in_domain_business_id\",\"foriegn\":\"ad_in_domain_businesses\",\"isNullAble\":false},{\"field\":\"ad_package_id\"},{\"field\":\"accept_new_station\"},{\"field\":\"suspend_modified_package_date\"},{\"field\":\"suspend_modified_content\"}]\n}\nexport interface ITable_ad_in_domain_business_package_stations extends IBaseProto {\n    m_fields: [{\"field\":\"ad_in_domain_business_package_station_id\"},{\"field\":\"changelist_id\"},{\"field\":\"change_type\"},{\"field\":\"ad_in_domain_business_package_id\",\"foriegn\":\"ad_in_domain_business_packages\",\"isNullAble\":false},{\"field\":\"ad_package_station_id\"},{\"field\":\"accept_status\"},{\"field\":\"suspend_modified_station\"}]\n}\nexport interface ICreateDataBase extends IBaseProto {\n    m_fields: undefined\n}\nexport interface ICreateHandles extends IBaseProto {\n    m_fields: undefined\n}\n\n\n\nexport interface IDataManager_proto {\n    table_global_settings:()=> ITable_global_settings\n    table_resources:()=> ITable_resources\n    table_ad_local_packages:()=> ITable_ad_local_packages\n    table_ad_local_contents:()=> ITable_ad_local_contents\n    table_category_values:()=> ITable_category_values\n    table_catalog_items:()=> ITable_catalog_items\n    table_catalog_item_infos:()=> ITable_catalog_item_infos\n    table_catalog_item_resources:()=> ITable_catalog_item_resources\n    table_catalog_item_categories:()=> ITable_catalog_item_categories\n    table_player_data:()=> ITable_player_data\n    table_boards:()=> ITable_boards\n    table_campaigns:()=> ITable_campaigns\n    table_campaign_channels:()=> ITable_campaign_channels\n    table_campaign_channel_players:()=> ITable_campaign_channel_players\n    table_campaign_timelines:()=> ITable_campaign_timelines\n    table_campaign_events:()=> ITable_campaign_events\n    table_campaign_boards:()=> ITable_campaign_boards\n    table_board_templates:()=> ITable_board_templates\n    table_board_template_viewers:()=> ITable_board_template_viewers\n    table_campaign_timeline_chanels:()=> ITable_campaign_timeline_chanels\n    table_campaign_timeline_channels:()=> ITable_campaign_timeline_channels\n    table_campaign_timeline_board_templates:()=> ITable_campaign_timeline_board_templates\n    table_campaign_timeline_board_viewer_chanels:()=> ITable_campaign_timeline_board_viewer_chanels\n    table_campaign_timeline_board_viewer_channels:()=> ITable_campaign_timeline_board_viewer_channels\n    table_campaign_timeline_chanel_players:()=> ITable_campaign_timeline_chanel_players\n    table_campaign_timeline_schedules:()=> ITable_campaign_timeline_schedules\n    table_campaign_timeline_sequences:()=> ITable_campaign_timeline_sequences\n    table_scripts:()=> ITable_scripts\n    table_music_channels:()=> ITable_music_channels\n    table_music_channel_songs:()=> ITable_music_channel_songs\n    table_branch_stations:()=> ITable_branch_stations\n    table_ad_rates:()=> ITable_ad_rates\n    table_station_ads:()=> ITable_station_ads\n    table_ad_out_packages:()=> ITable_ad_out_packages\n    table_ad_out_package_contents:()=> ITable_ad_out_package_contents\n    table_ad_out_package_stations:()=> ITable_ad_out_package_stations\n    table_ad_in_domains:()=> ITable_ad_in_domains\n    table_ad_in_domain_businesses:()=> ITable_ad_in_domain_businesses\n    table_ad_in_domain_business_packages:()=> ITable_ad_in_domain_business_packages\n    table_ad_in_domain_business_package_stations:()=> ITable_ad_in_domain_business_package_stations\n    createDataBase:()=> ICreateDataBase\n    createHandles:()=> ICreateHandles\n\n}\n\n"
  },
  {
    "path": "src/store/model/StoreModel.ts",
    "content": "import {Map, List} from \"immutable\";\nimport {UUID} from \"angular2-uuid\";\n\n\n/**\n * StoreModel is a thin wrapper of Immutable data around for a Class\n * uses the internal immutable map to hold all values.\n * This allows us a base class on which we can extend and inject\n * into any Redux store as we follow Immutability\n *\n * Also ships with a helper static method to create unique IDs\n **/\nexport class StoreModel {\n\n    static UniqueId() {\n        return UUID.UUID();\n    }\n\n    constructor(data: any = {}) {\n        this._data = Map<string, any>(data);\n    }\n\n    _data: Map<string, any>;\n\n    public setKey<T>(ClassName: any, key: string, value: any): T {\n        return this.setData(ClassName, this._data.set(key, value)) as T;\n    }\n\n    public getKey(key: string) {\n        return this._data.get(key);\n    }\n\n    public setData<T>(ClassName, data: any): T {\n        function ClassFactory(className: { new(data): T; }, data: any): T {\n            var created: T = new className(Map<string, any>(data));\n            return created;\n        }\n\n        return ClassFactory(ClassName, data);\n    }\n\n    public getData(): Map<string, any> {\n        return this._data;\n    }\n\n    public toPureJs(){\n        return this.getData().toObject();\n    }\n\n    /**\n     * Create a List or update a list if one exists, with the Map key provided and the value to push to the new/updated list\n     * @param ClassName\n     * @param i_key\n     * @param i_value\n     * @returns {T}\n     */\n    public listPush<T>(ClassName, i_key: string, i_value: string): any {\n        var value = this.getKey(i_key);\n        var model: StoreModel = this;\n        if (!value)\n            model = this.setKey<T>(ClassName, i_key, List<any>()) as any;\n        var list: List<any> = model.getKey(i_key);\n        list = list.push(i_value);\n        return model.setKey<T>(ClassName, i_key, list) as T;\n    }\n}"
  },
  {
    "path": "src/store/model/msdb-models-extended.ts",
    "content": "/**\n * extend msdb.interfaces_auto with additional functionality\n * requirement: same name as extended class / model + Ext\n */\n\n\nimport {BranchStationsModel, CampaignsModel, CampaignTimelineChanelPlayersModel, PlayerDataModel} from \"../imsdb.interfaces_auto\";\n\nexport class CampaignsModelExt extends CampaignsModel {\n\n    public getCampaignPlaylistModeName(): string {\n        if (this.getCampaignPlaylistMode() == 0) {\n            return 'sequencer'\n        } else {\n            return 'scheduler'\n        }\n    }\n\n}\n\nexport class CampaignTimelineChanelPlayersModelExt extends CampaignTimelineChanelPlayersModel {\n    public getPlayerOffsetTimeInt() {\n        return parseFloat(this.getKey('player_offset_time'));\n    }\n\n    public getPlayerDurationInt() {\n        return parseFloat(this.getKey('player_duration'));\n    }\n\n}\n\n\nexport class BranchStationsModelExt extends BranchStationsModel {\n    public get getLanEnabled() {\n        return this.getLanServerEnabled() == 'True' ? true : false;\n    }\n\n    public get getNativeId() {\n        return this.getKey('native_id');\n    }\n\n}\n\nexport class PlayerDataModelExt extends PlayerDataModel {\n\n    public get getSceneName() {\n        var domPlayerData = jXML.parseXML(this.getPlayerDataValue())\n        return jXML(domPlayerData).find('Player').attr('label');\n    }\n\n    public get getSceneMime() {\n        var domPlayerData = jXML.parseXML(this.getPlayerDataValue())\n        return jXML(domPlayerData).find('Player').attr('mimeType');\n    }\n\n    public get getNativeId() {\n        return Number(this.getKey('native_id'));\n    }\n\n}"
  },
  {
    "path": "src/store/reducers/appdb.reducer.ts",
    "content": "import {IAppDb} from \"../store.data\";\nimport {UserModel} from \"../../models/UserModel\";\nimport * as StoreActions from \"../actions/appdb.actions\";\nimport * as EffectActions from \"../effects/appdb.effects\";\nimport * as ActionsConst from \"../actions/appdb.actions\";\nimport * as _ from 'lodash';\nimport {Map, List} from 'immutable';\nimport {StationModel} from \"../../models/StationModel\";\nimport {Lib} from \"../../Lib\";\nimport {FasterqLineModel} from \"../../models/fasterq-line-model\";\nimport {FasterqQueueModel} from \"../../models/fasterq-queue-model\";\nimport {FasterqAnalyticsModel} from \"../../models/fasterq-analytics\";\nimport {LiveLogModel} from \"../../models/live-log-model\";\nimport * as moment from 'moment'\n\nconst baseUrl = `${window.g_protocol}${window.g_masterDomain}/WebService/ResellerService.ashx`;\n\nexport const appBaseUrlCloud = 'https://secure.digitalsignage.com';\n\nexport function appDb(state: IAppDb, action: any): IAppDb {\n\n    switch (action.type) {\n        case StoreActions.APP_INIT:\n            state.appStartTime = Date.now();\n            state.appBaseUrl = `${baseUrl}`;\n            state.appBaseUrlServices = `https://secure.digitalsignage.com${Lib.DevMode() ? ':443' : ''}`;\n            return state;\n\n        case ActionsConst.ACTION_UISTATE_UPDATE: {\n            _.merge(state.uiState, action.payload);\n            return state;\n        }\n\n        case EffectActions.EFFECT_UPDATE_USER_MODEL:\n            var userModel: UserModel = action.payload;\n            state.userModel = userModel.setTime();\n            state.appBaseUrlUser = `${baseUrl}?resellerUserName=${userModel.getKey('user')}&resellerPassword=${userModel.getKey('pass')}`;\n            state.appBaseUrlCloud = `${appBaseUrlCloud}/END_POINT/${userModel.getKey('user')}/${userModel.getKey('pass')}`;\n            return state;\n\n        case EffectActions.EFFECT_LOADED_STATIONS:\n            var stations: List<StationModel> = action.payload;\n            state.stations = stations;\n            return state;\n\n        case EffectActions.EFFECT_UPDATED_FASTERQ_LINE:\n            var index = state.fasterq.lines.findIndex((i_fasterqLineModel: FasterqLineModel) => i_fasterqLineModel.lineId == action.payload.data.id);\n            state.fasterq.lines = state.fasterq.lines.update(index, (i_fasterqLineModel: FasterqLineModel) => {\n                i_fasterqLineModel = i_fasterqLineModel.setKey<FasterqLineModel>(FasterqLineModel, 'name', action.payload.data.name);\n                return i_fasterqLineModel.setKey<FasterqLineModel>(FasterqLineModel, 'reminder', action.payload.data.reminder);\n            });\n            return state;\n\n        case EffectActions.EFFECT_REMOVED_FASTERQ_LINE:\n            var index = state.fasterq.lines.findIndex((i_fasterqLineModel: FasterqLineModel) => i_fasterqLineModel.lineId == action.payload.data.id);\n            state.fasterq.lines = state.fasterq.lines.remove(index)\n            return state;\n\n        case EffectActions.EFFECT_QUEUE_CALL_SAVED:\n            if (_.isNull(action.payload))\n                return state;\n            var index = state.fasterq.queues.findIndex((i_fasterqLineModel: FasterqQueueModel) => i_fasterqLineModel.queueId == action.payload.queue_id);\n            state.fasterq.queues = state.fasterq.queues.update(index, (i_fasterqQueueModel: FasterqQueueModel) => {\n                // var prev = state.fasterq.queues.get(index).called\n                // var curr = i_fasterqQueueModel.called;\n                // if (!_.isNull(prev) && _.isNull(curr)){\n                //     console.log('oops');\n                // }\n                delete action.payload.queue;\n                var queue = i_fasterqQueueModel.setData<FasterqQueueModel>(FasterqQueueModel, action.payload)\n                return queue;\n            });\n            return state;\n\n        case EffectActions.EFFECT_QUEUE_SERVICE_SAVED:\n            var index = state.fasterq.queues.findIndex((i_fasterqLineModel: FasterqQueueModel) => i_fasterqLineModel.queueId == action.payload.queue_id);\n            state.fasterq.queues = state.fasterq.queues.update(index, (i_fasterqQueueModel: FasterqQueueModel) => {\n                // var prev = state.fasterq.queues.get(index).serviced\n                // var curr = i_fasterqQueueModel.serviced;\n                // if (!_.isNull(prev) && _.isNull(curr)){\n                //     console.log('oops');\n                // }\n                return i_fasterqQueueModel.setKey<FasterqQueueModel>(FasterqQueueModel, 'serviced', action.payload.serviced);\n            });\n            return state;\n\n        case EffectActions.EFFECT_ADDED_FASTERQ_LINE:\n            var fasterqLineModel: FasterqLineModel = new FasterqLineModel(action.payload.serverReplay);\n            state.fasterq.lines = state.fasterq.lines.push(fasterqLineModel)\n            return state;\n\n        case EffectActions.EFFECT_LOADED_FASTERQ_LINES:\n            var lines: List<FasterqLineModel> = action.payload;\n            state.fasterq.lines = lines;\n            return state;\n\n        case EffectActions.EFFECT_LOADED_FASTERQ_LINE:\n            var line: FasterqLineModel = action.payload;\n            state.fasterq.terminal = line;\n            return state;\n\n        case EffectActions.EFFECT_LOADED_FASTERQ_ANALYTICS:\n            var analytics: List<FasterqAnalyticsModel> = action.payload;\n            state.fasterq.analytics = analytics;\n            return state;\n\n        case EffectActions.EFFECT_LOADED_FASTERQ_QUEUES:\n            var queues: List<FasterqQueueModel> = action.payload;\n            state.fasterq.queues = queues;\n            return state;\n\n        case EffectActions.EFFECT_TWO_FACTOR_UPDATED:\n            var userModel = state.userModel;\n            userModel = userModel.setTwoFactorRequired(action.payload);\n            state.userModel = userModel.setTime();\n            return state;\n\n        case StoreActions.ACTION_TWO_FACTOR_REMOVED:\n            var userModel = state.userModel;\n            userModel = userModel.setTwoFactorRequired(false);\n            state.userModel = userModel.setTime();\n            return state;\n\n        case StoreActions.ACTION_LIVELOG_UPDATE:\n            var liveLog: LiveLogModel = action.payload;\n            liveLog = liveLog.setKey<LiveLogModel>(LiveLogModel, 'date', moment().format('h:mm:ss MM/DD/YYYY'))\n            state.liveLog = state.liveLog.push(liveLog)\n            return state;\n\n        case EffectActions.EFFECT_AUTH_STATUS:\n            state.appAuthStatus = Map({authStatus: action.payload});\n            return state;\n\n        case ActionsConst.ACTION_FORM_UPDATE: {\n            state[action.payload.path] = Map(action.payload.value);\n            return state;\n        }\n\n        default:\n            return state;\n    }\n}\n\n\n\n"
  },
  {
    "path": "src/store/reducers/msdb.reducer.ts",
    "content": "import {Action} from \"@ngrx/store\";\nimport {ACTION_INJECT_SDK} from \"../actions/appdb.actions\";\nimport {IMsDatabase} from \"../store.data\";\nimport {redpepperTables} from \"../../services/redpepper.service\";\nimport {List, Map} from \"immutable\";\nimport * as _ from \"lodash\";\n            \nexport function msDatabase(state: IMsDatabase, action: Action): IMsDatabase {\n    switch (action.type) {\n\n        /**\n         * this special reducer can receive a single or array of redpepperTables and reduce it into the new store state\n         * if multiple redpepperTables are given, we reduce it in such a way that if duplicate tables of the same type\n         * are given, the last one (i.e.: has the freshest data) wins and gets injected into the state.sdk\n         *\n         */\n        case ACTION_INJECT_SDK:\n            if (!state.sdk) {\n                var redpepperList: Array<redpepperTables> = action.payload;\n                state.sdk = redpepperList[0].tables;\n                return state;\n            }\n            var redpepperList: Array<redpepperTables> = action.payload;\n            var redpepperReducer = {};\n            redpepperList.map((redpepperSet: redpepperTables) => {\n                redpepperSet.tableNames.map((tableName: string) => {\n                    redpepperReducer[tableName] = redpepperSet.tables[tableName];\n                })\n            })\n            _.forEach(redpepperReducer, (storeModelList: List<Storage>, tableName) => {\n                state.sdk[tableName] = storeModelList;\n            })\n            return state;\n\n        default:\n            return state;\n    }\n}\n\n"
  },
  {
    "path": "src/store/signage_sdk.js",
    "content": "//todo: Alon need to add this logic for offline\n\njQuery.ajaxSetup({\n    cache: false,\n    timeout: 8000,\n    crossDomain: true\n});\n\n/**\n DigitalSignage.com JS SDK\n\n to minify:\n ==========\n 1. find . -type f -name '*.js' -exec cat {} + >> SignageSDK_combined.js\n 2. http://www.minifier.org/\n\n old: https://js.signage.me/SignageSDK.js\n new: https://js.signage.me/SignageSDK_combined.js\n hosted: http://go.digitalsignage.com\n **/\nif (window.g_protocol == undefined) {\n    window.g_protocol = \"https://\";\n}\n\nif (window.g_sdkDomain == undefined) {\n    window.g_sdkDomain = \"js.signage.me\";\n}\n\nif (window.g_masterDomain == undefined) {\n    window.g_masterDomain = \"galaxy.signage.me\";\n}\n\n\nfunction BarrettMu(m) {\n    this.modulus = biCopy(m);\n    this.k = biHighIndex(this.modulus) + 1;\n    var b2k = new BigInt();\n    b2k.digits[2 * this.k] = 1; // b2k = b^(2k)\n    this.mu = biDivide(b2k, this.modulus);\n    this.bkplus1 = new BigInt();\n    this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1)\n    this.modulo = BarrettMu_modulo;\n    this.multiplyMod = BarrettMu_multiplyMod;\n    this.powMod = BarrettMu_powMod;\n}\n\nfunction BarrettMu_modulo(x) {\n    var q1 = biDivideByRadixPower(x, this.k - 1);\n    var q2 = biMultiply(q1, this.mu);\n    var q3 = biDivideByRadixPower(q2, this.k + 1);\n    var r1 = biModuloByRadixPower(x, this.k + 1);\n    var r2term = biMultiply(q3, this.modulus);\n    var r2 = biModuloByRadixPower(r2term, this.k + 1);\n    var r = biSubtract(r1, r2);\n    if (r.isNeg) {\n        r = biAdd(r, this.bkplus1);\n    }\n    var rgtem = biCompare(r, this.modulus) >= 0;\n    while (rgtem) {\n        r = biSubtract(r, this.modulus);\n        rgtem = biCompare(r, this.modulus) >= 0;\n    }\n    return r;\n}\n\nfunction BarrettMu_multiplyMod(x, y) {\n    /*\n     x = this.modulo(x);\n     y = this.modulo(y);\n     */\n    var xy = biMultiply(x, y);\n    return this.modulo(xy);\n}\n\nfunction BarrettMu_powMod(x, y) {\n    var result = new BigInt();\n    result.digits[0] = 1;\n    var a = x;\n    var k = y;\n    while (true) {\n        if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a);\n        k = biShiftRight(k, 1);\n        if (k.digits[0] == 0 && biHighIndex(k) == 0) break;\n        a = this.multiplyMod(a, a);\n    }\n    return result;\n}\n\nvar biRadixBase = 2;\nvar biRadixBits = 16;\nvar bitsPerDigit = biRadixBits;\nvar biRadix = 1 << 16; // = 2^16 = 65536\nvar biHalfRadix = biRadix >>> 1;\nvar biRadixSquared = biRadix * biRadix;\nvar maxDigitVal = biRadix - 1;\nvar maxInteger = 9999999999999998;\n\n\nvar maxDigits;\nvar ZERO_ARRAY;\nvar bigZero, bigOne;\n\nfunction setMaxDigits(value) {\n    maxDigits = value;\n    ZERO_ARRAY = new Array(maxDigits);\n    for (var iza = 0; iza < ZERO_ARRAY.length; iza++) ZERO_ARRAY[iza] = 0;\n    bigZero = new BigInt();\n    bigOne = new BigInt();\n    bigOne.digits[0] = 1;\n}\n\nsetMaxDigits(20);\n\n// The maximum number of digits in base 10 you can convert to an\n// integer without JavaScript throwing up on you.\nvar dpl10 = 15;\n// lr10 = 10 ^ dpl10\nvar lr10 = biFromNumber(1000000000000000);\n\nfunction BigInt(flag) {\n    if (typeof flag == \"boolean\" && flag == true) {\n        this.digits = null;\n    }\n    else {\n        this.digits = ZERO_ARRAY.slice(0);\n    }\n    this.isNeg = false;\n}\n\nfunction biFromDecimal(s) {\n    var isNeg = s.charAt(0) == '-';\n    var i = isNeg ? 1 : 0;\n    var result;\n    // Skip leading zeros.\n    while (i < s.length && s.charAt(i) == '0') ++i;\n    if (i == s.length) {\n        result = new BigInt();\n    }\n    else {\n        var digitCount = s.length - i;\n        var fgl = digitCount % dpl10;\n        if (fgl == 0) fgl = dpl10;\n        result = biFromNumber(Number(s.substr(i, fgl)));\n        i += fgl;\n        while (i < s.length) {\n            result = biAdd(biMultiply(result, lr10),\n                biFromNumber(Number(s.substr(i, dpl10))));\n            i += dpl10;\n        }\n        result.isNeg = isNeg;\n    }\n    return result;\n}\n\nfunction biCopy(bi) {\n    var result = new BigInt(true);\n    result.digits = bi.digits.slice(0);\n    result.isNeg = bi.isNeg;\n    return result;\n}\n\nfunction biFromNumber(i) {\n    var result = new BigInt();\n    result.isNeg = i < 0;\n    i = Math.abs(i);\n    var j = 0;\n    while (i > 0) {\n        result.digits[j++] = i & maxDigitVal;\n        i >>= biRadixBits;\n    }\n    return result;\n}\n\nfunction reverseStr(s) {\n    var result = \"\";\n    for (var i = s.length - 1; i > -1; --i) {\n        result += s.charAt(i);\n    }\n    return result;\n}\n\nvar hexatrigesimalToChar = new Array(\n    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',\n    'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',\n    'u', 'v', 'w', 'x', 'y', 'z'\n);\n\nfunction biToString(x, radix)\n// 2 <= radix <= 36\n{\n    var b = new BigInt();\n    b.digits[0] = radix;\n    var qr = biDivideModulo(x, b);\n    var result = hexatrigesimalToChar[qr[1].digits[0]];\n    while (biCompare(qr[0], bigZero) == 1) {\n        qr = biDivideModulo(qr[0], b);\n        digit = qr[1].digits[0];\n        result += hexatrigesimalToChar[qr[1].digits[0]];\n    }\n    return (x.isNeg ? \"-\" : \"\") + reverseStr(result);\n}\n\nfunction biToDecimal(x) {\n    var b = new BigInt();\n    b.digits[0] = 10;\n    var qr = biDivideModulo(x, b);\n    var result = String(qr[1].digits[0]);\n    while (biCompare(qr[0], bigZero) == 1) {\n        qr = biDivideModulo(qr[0], b);\n        result += String(qr[1].digits[0]);\n    }\n    return (x.isNeg ? \"-\" : \"\") + reverseStr(result);\n}\n\nvar hexToChar = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n    'a', 'b', 'c', 'd', 'e', 'f');\n\nfunction digitToHex(n) {\n    var mask = 0xf;\n    var result = \"\";\n    for (i = 0; i < 4; ++i) {\n        result += hexToChar[n & mask];\n        n >>>= 4;\n    }\n    return reverseStr(result);\n}\n\nfunction biToHex(x) {\n    var result = \"\";\n    var n = biHighIndex(x);\n    for (var i = biHighIndex(x); i > -1; --i) {\n        result += digitToHex(x.digits[i]);\n    }\n    return result;\n}\n\nfunction charToHex(c) {\n    var ZERO = 48;\n    var NINE = ZERO + 9;\n    var littleA = 97;\n    var littleZ = littleA + 25;\n    var bigA = 65;\n    var bigZ = 65 + 25;\n    var result;\n\n    if (c >= ZERO && c <= NINE) {\n        result = c - ZERO;\n    } else if (c >= bigA && c <= bigZ) {\n        result = 10 + c - bigA;\n    } else if (c >= littleA && c <= littleZ) {\n        result = 10 + c - littleA;\n    } else {\n        result = 0;\n    }\n    return result;\n}\n\nfunction hexToDigit(s) {\n    var result = 0;\n    var sl = Math.min(s.length, 4);\n    for (var i = 0; i < sl; ++i) {\n        result <<= 4;\n        result |= charToHex(s.charCodeAt(i))\n    }\n    return result;\n}\n\nfunction biFromHex(s) {\n    var result = new BigInt();\n    var sl = s.length;\n    for (var i = sl, j = 0; i > 0; i -= 4, ++j) {\n        result.digits[j] = hexToDigit(s.substr(Math.max(i - 4, 0), Math.min(i, 4)));\n    }\n    return result;\n}\n\nfunction biFromString(s, radix) {\n    var isNeg = s.charAt(0) == '-';\n    var istop = isNeg ? 1 : 0;\n    var result = new BigInt();\n    var place = new BigInt();\n    place.digits[0] = 1; // radix^0\n    for (var i = s.length - 1; i >= istop; i--) {\n        var c = s.charCodeAt(i);\n        var digit = charToHex(c);\n        var biDigit = biMultiplyDigit(place, digit);\n        result = biAdd(result, biDigit);\n        place = biMultiplyDigit(place, radix);\n    }\n    result.isNeg = isNeg;\n    return result;\n}\n\nfunction biDump(b) {\n    return (b.isNeg ? \"-\" : \"\") + b.digits.join(\" \");\n}\n\nfunction biAdd(x, y) {\n    var result;\n\n    if (x.isNeg != y.isNeg) {\n        y.isNeg = !y.isNeg;\n        result = biSubtract(x, y);\n        y.isNeg = !y.isNeg;\n    }\n    else {\n        result = new BigInt();\n        var c = 0;\n        var n;\n        for (var i = 0; i < x.digits.length; ++i) {\n            n = x.digits[i] + y.digits[i] + c;\n            result.digits[i] = n & 0xffff;\n            c = Number(n >= biRadix);\n        }\n        result.isNeg = x.isNeg;\n    }\n    return result;\n}\n\nfunction biSubtract(x, y) {\n    var result;\n    if (x.isNeg != y.isNeg) {\n        y.isNeg = !y.isNeg;\n        result = biAdd(x, y);\n        y.isNeg = !y.isNeg;\n    } else {\n        result = new BigInt();\n        var n, c;\n        c = 0;\n        for (var i = 0; i < x.digits.length; ++i) {\n            n = x.digits[i] - y.digits[i] + c;\n            result.digits[i] = n & 0xffff;\n            // Stupid non-conforming modulus operation.\n            if (result.digits[i] < 0) result.digits[i] += biRadix;\n            c = 0 - Number(n < 0);\n        }\n        // Fix up the negative sign, if any.\n        if (c == -1) {\n            c = 0;\n            for (var i = 0; i < x.digits.length; ++i) {\n                n = 0 - result.digits[i] + c;\n                result.digits[i] = n & 0xffff;\n                // Stupid non-conforming modulus operation.\n                if (result.digits[i] < 0) result.digits[i] += biRadix;\n                c = 0 - Number(n < 0);\n            }\n            // Result is opposite sign of arguments.\n            result.isNeg = !x.isNeg;\n        } else {\n            // Result is same sign.\n            result.isNeg = x.isNeg;\n        }\n    }\n    return result;\n}\n\nfunction biHighIndex(x) {\n    var result = x.digits.length - 1;\n    while (result > 0 && x.digits[result] == 0) --result;\n    return result;\n}\n\nfunction biNumBits(x) {\n    var n = biHighIndex(x);\n    var d = x.digits[n];\n    var m = (n + 1) * bitsPerDigit;\n    var result;\n    for (result = m; result > m - bitsPerDigit; --result) {\n        if ((d & 0x8000) != 0) break;\n        d <<= 1;\n    }\n    return result;\n}\n\nfunction biMultiply(x, y) {\n    var result = new BigInt();\n    var c;\n    var n = biHighIndex(x);\n    var t = biHighIndex(y);\n    var u, uv, k;\n\n    for (var i = 0; i <= t; ++i) {\n        c = 0;\n        k = i;\n        for (j = 0; j <= n; ++j, ++k) {\n            uv = result.digits[k] + x.digits[j] * y.digits[i] + c;\n            result.digits[k] = uv & maxDigitVal;\n            c = uv >>> biRadixBits;\n        }\n        result.digits[i + n + 1] = c;\n    }\n    // Someone give me a logical xor, please.\n    result.isNeg = x.isNeg != y.isNeg;\n    return result;\n}\n\nfunction biMultiplyDigit(x, y) {\n    var n, c, uv;\n\n    result = new BigInt();\n    n = biHighIndex(x);\n    c = 0;\n    for (var j = 0; j <= n; ++j) {\n        uv = result.digits[j] + x.digits[j] * y + c;\n        result.digits[j] = uv & maxDigitVal;\n        c = uv >>> biRadixBits;\n    }\n    result.digits[1 + n] = c;\n    return result;\n}\n\nfunction arrayCopy(src, srcStart, dest, destStart, n) {\n    var m = Math.min(srcStart + n, src.length);\n    for (var i = srcStart, j = destStart; i < m; ++i, ++j) {\n        dest[j] = src[i];\n    }\n}\n\nvar highBitMasks = new Array(0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800,\n    0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,\n    0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF);\n\nfunction biShiftLeft(x, n) {\n    var digitCount = Math.floor(n / bitsPerDigit);\n    var result = new BigInt();\n    arrayCopy(x.digits, 0, result.digits, digitCount,\n        result.digits.length - digitCount);\n    var bits = n % bitsPerDigit;\n    var rightBits = bitsPerDigit - bits;\n    for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) {\n        result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) |\n            ((result.digits[i1] & highBitMasks[bits]) >>>\n            (rightBits));\n    }\n    result.digits[0] = ((result.digits[i] << bits) & maxDigitVal);\n    result.isNeg = x.isNeg;\n    return result;\n}\n\nvar lowBitMasks = new Array(0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,\n    0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,\n    0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF);\n\nfunction biShiftRight(x, n) {\n    var digitCount = Math.floor(n / bitsPerDigit);\n    var result = new BigInt();\n    arrayCopy(x.digits, digitCount, result.digits, 0,\n        x.digits.length - digitCount);\n    var bits = n % bitsPerDigit;\n    var leftBits = bitsPerDigit - bits;\n    for (var i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) {\n        result.digits[i] = (result.digits[i] >>> bits) |\n            ((result.digits[i1] & lowBitMasks[bits]) << leftBits);\n    }\n    result.digits[result.digits.length - 1] >>>= bits;\n    result.isNeg = x.isNeg;\n    return result;\n}\n\nfunction biMultiplyByRadixPower(x, n) {\n    var result = new BigInt();\n    arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n);\n    return result;\n}\n\nfunction biDivideByRadixPower(x, n) {\n    var result = new BigInt();\n    arrayCopy(x.digits, n, result.digits, 0, result.digits.length - n);\n    return result;\n}\n\nfunction biModuloByRadixPower(x, n) {\n    var result = new BigInt();\n    arrayCopy(x.digits, 0, result.digits, 0, n);\n    return result;\n}\n\nfunction biCompare(x, y) {\n    if (x.isNeg != y.isNeg) {\n        return 1 - 2 * Number(x.isNeg);\n    }\n    for (var i = x.digits.length - 1; i >= 0; --i) {\n        if (x.digits[i] != y.digits[i]) {\n            if (x.isNeg) {\n                return 1 - 2 * Number(x.digits[i] > y.digits[i]);\n            } else {\n                return 1 - 2 * Number(x.digits[i] < y.digits[i]);\n            }\n        }\n    }\n    return 0;\n}\n\nfunction biDivideModulo(x, y) {\n    var nb = biNumBits(x);\n    var tb = biNumBits(y);\n    var origYIsNeg = y.isNeg;\n    var q, r;\n    if (nb < tb) {\n        // |x| < |y|\n        if (x.isNeg) {\n            q = biCopy(bigOne);\n            q.isNeg = !y.isNeg;\n            x.isNeg = false;\n            y.isNeg = false;\n            r = biSubtract(y, x);\n            // Restore signs, 'cause they're references.\n            x.isNeg = true;\n            y.isNeg = origYIsNeg;\n        } else {\n            q = new BigInt();\n            r = biCopy(x);\n        }\n        return new Array(q, r);\n    }\n\n    q = new BigInt();\n    r = x;\n\n    // Normalize Y.\n    var t = Math.ceil(tb / bitsPerDigit) - 1;\n    var lambda = 0;\n    while (y.digits[t] < biHalfRadix) {\n        y = biShiftLeft(y, 1);\n        ++lambda;\n        ++tb;\n        t = Math.ceil(tb / bitsPerDigit) - 1;\n    }\n    // Shift r over to keep the quotient constant. We'll shift the\n    // remainder back at the end.\n    r = biShiftLeft(r, lambda);\n    nb += lambda; // Update the bit count for x.\n    var n = Math.ceil(nb / bitsPerDigit) - 1;\n\n    var b = biMultiplyByRadixPower(y, n - t);\n    while (biCompare(r, b) != -1) {\n        ++q.digits[n - t];\n        r = biSubtract(r, b);\n    }\n    for (var i = n; i > t; --i) {\n        var ri = (i >= r.digits.length) ? 0 : r.digits[i];\n        var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1];\n        var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2];\n        var yt = (t >= y.digits.length) ? 0 : y.digits[t];\n        var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1];\n        if (ri == yt) {\n            q.digits[i - t - 1] = maxDigitVal;\n        } else {\n            q.digits[i - t - 1] = Math.floor((ri * biRadix + ri1) / yt);\n        }\n\n        var c1 = q.digits[i - t - 1] * ((yt * biRadix) + yt1);\n        var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2);\n        while (c1 > c2) {\n            --q.digits[i - t - 1];\n            c1 = q.digits[i - t - 1] * ((yt * biRadix) | yt1);\n            c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2);\n        }\n\n        b = biMultiplyByRadixPower(y, i - t - 1);\n        r = biSubtract(r, biMultiplyDigit(b, q.digits[i - t - 1]));\n        if (r.isNeg) {\n            r = biAdd(r, b);\n            --q.digits[i - t - 1];\n        }\n    }\n    r = biShiftRight(r, lambda);\n    // Fiddle with the signs and stuff to make sure that 0 <= r < y.\n    q.isNeg = x.isNeg != origYIsNeg;\n    if (x.isNeg) {\n        if (origYIsNeg) {\n            q = biAdd(q, bigOne);\n        } else {\n            q = biSubtract(q, bigOne);\n        }\n        y = biShiftRight(y, lambda);\n        r = biSubtract(y, r);\n    }\n    // Check for the unbelievably stupid degenerate case of r == -0.\n    if (r.digits[0] == 0 && biHighIndex(r) == 0) r.isNeg = false;\n\n    return new Array(q, r);\n}\n\nfunction biDivide(x, y) {\n    return biDivideModulo(x, y)[0];\n}\n\nfunction biModulo(x, y) {\n    return biDivideModulo(x, y)[1];\n}\n\nfunction biMultiplyMod(x, y, m) {\n    return biModulo(biMultiply(x, y), m);\n}\n\nfunction biPow(x, y) {\n    var result = bigOne;\n    var a = x;\n    while (true) {\n        if ((y & 1) != 0) result = biMultiply(result, a);\n        y >>= 1;\n        if (y == 0) break;\n        a = biMultiply(a, a);\n    }\n    return result;\n}\n\nfunction biPowMod(x, y, m) {\n    var result = bigOne;\n    var a = x;\n    var k = y;\n    while (true) {\n        if ((k.digits[0] & 1) != 0) result = biMultiplyMod(result, a, m);\n        k = biShiftRight(k, 1);\n        if (k.digits[0] == 0 && biHighIndex(k) == 0) break;\n        a = biMultiplyMod(a, a, m);\n    }\n    return result;\n}\n\n\n// test\n\nfunction DataBaseManager() {\n    DataManager.call(this);\n}\n\nextend(DataManager, DataBaseManager);\n\n\nDataBaseManager.prototype.table_global_settings = function () {\n    return this.m_selectedDataBase.m_tables['global_settings'];\n}\nDataBaseManager.prototype.table_resources = function () {\n    return this.m_selectedDataBase.m_tables['resources'];\n}\nDataBaseManager.prototype.table_ad_local_packages = function () {\n    return this.m_selectedDataBase.m_tables['ad_local_packages'];\n}\nDataBaseManager.prototype.table_ad_local_contents = function () {\n    return this.m_selectedDataBase.m_tables['ad_local_contents'];\n}\nDataBaseManager.prototype.table_category_values = function () {\n    return this.m_selectedDataBase.m_tables['category_values'];\n}\nDataBaseManager.prototype.table_catalog_items = function () {\n    return this.m_selectedDataBase.m_tables['catalog_items'];\n}\nDataBaseManager.prototype.table_catalog_item_infos = function () {\n    return this.m_selectedDataBase.m_tables['catalog_item_infos'];\n}\nDataBaseManager.prototype.table_catalog_item_resources = function () {\n    return this.m_selectedDataBase.m_tables['catalog_item_resources'];\n}\nDataBaseManager.prototype.table_catalog_item_categories = function () {\n    return this.m_selectedDataBase.m_tables['catalog_item_categories'];\n}\nDataBaseManager.prototype.table_player_data = function () {\n    return this.m_selectedDataBase.m_tables['player_data'];\n}\nDataBaseManager.prototype.table_boards = function () {\n    return this.m_selectedDataBase.m_tables['boards'];\n}\nDataBaseManager.prototype.table_campaigns = function () {\n    return this.m_selectedDataBase.m_tables['campaigns'];\n}\nDataBaseManager.prototype.table_campaign_channels = function () {\n    return this.m_selectedDataBase.m_tables['campaign_channels'];\n}\nDataBaseManager.prototype.table_campaign_channel_players = function () {\n    return this.m_selectedDataBase.m_tables['campaign_channel_players'];\n}\nDataBaseManager.prototype.table_campaign_timelines = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timelines'];\n}\nDataBaseManager.prototype.table_campaign_events = function () {\n    return this.m_selectedDataBase.m_tables['campaign_events'];\n}\nDataBaseManager.prototype.table_campaign_boards = function () {\n    return this.m_selectedDataBase.m_tables['campaign_boards'];\n}\nDataBaseManager.prototype.table_board_templates = function () {\n    return this.m_selectedDataBase.m_tables['board_templates'];\n}\nDataBaseManager.prototype.table_board_template_viewers = function () {\n    return this.m_selectedDataBase.m_tables['board_template_viewers'];\n}\nDataBaseManager.prototype.table_campaign_timeline_chanels = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_chanels'];\n}\nDataBaseManager.prototype.table_campaign_timeline_channels = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_channels'];\n}\nDataBaseManager.prototype.table_campaign_timeline_board_templates = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_board_templates'];\n}\nDataBaseManager.prototype.table_campaign_timeline_board_viewer_chanels = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_board_viewer_chanels'];\n}\nDataBaseManager.prototype.table_campaign_timeline_board_viewer_channels = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_board_viewer_channels'];\n}\nDataBaseManager.prototype.table_campaign_timeline_chanel_players = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_chanel_players'];\n}\nDataBaseManager.prototype.table_campaign_timeline_schedules = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_schedules'];\n}\nDataBaseManager.prototype.table_campaign_timeline_sequences = function () {\n    return this.m_selectedDataBase.m_tables['campaign_timeline_sequences'];\n}\nDataBaseManager.prototype.table_scripts = function () {\n    return this.m_selectedDataBase.m_tables['scripts'];\n}\nDataBaseManager.prototype.table_music_channels = function () {\n    return this.m_selectedDataBase.m_tables['music_channels'];\n}\nDataBaseManager.prototype.table_music_channel_songs = function () {\n    return this.m_selectedDataBase.m_tables['music_channel_songs'];\n}\nDataBaseManager.prototype.table_branch_stations = function () {\n    return this.m_selectedDataBase.m_tables['branch_stations'];\n}\nDataBaseManager.prototype.table_ad_rates = function () {\n    return this.m_selectedDataBase.m_tables['ad_rates'];\n}\nDataBaseManager.prototype.table_station_ads = function () {\n    return this.m_selectedDataBase.m_tables['station_ads'];\n}\nDataBaseManager.prototype.table_ad_out_packages = function () {\n    return this.m_selectedDataBase.m_tables['ad_out_packages'];\n}\nDataBaseManager.prototype.table_ad_out_package_contents = function () {\n    return this.m_selectedDataBase.m_tables['ad_out_package_contents'];\n}\nDataBaseManager.prototype.table_ad_out_package_stations = function () {\n    return this.m_selectedDataBase.m_tables['ad_out_package_stations'];\n}\nDataBaseManager.prototype.table_ad_in_domains = function () {\n    return this.m_selectedDataBase.m_tables['ad_in_domains'];\n}\nDataBaseManager.prototype.table_ad_in_domain_businesses = function () {\n    return this.m_selectedDataBase.m_tables['ad_in_domain_businesses'];\n}\nDataBaseManager.prototype.table_ad_in_domain_business_packages = function () {\n    return this.m_selectedDataBase.m_tables['ad_in_domain_business_packages'];\n}\nDataBaseManager.prototype.table_ad_in_domain_business_package_stations = function () {\n    return this.m_selectedDataBase.m_tables['ad_in_domain_business_package_stations'];\n}\n\n\nDataBaseManager.prototype.createDataBase = function (i_businessDomain, i_businessId) {\n    var dataModule = this.createDataModule(i_businessDomain, i_businessId);\n    dataModule.m_tableList = [\"global_settings\", \"resources\", \"ad_local_packages\", \"ad_local_contents\", \"category_values\", \"catalog_items\", \"catalog_item_infos\", \"catalog_item_resources\", \"catalog_item_categories\", \"player_data\", \"boards\", \"campaigns\", \"campaign_channels\", \"campaign_channel_players\", \"campaign_timelines\", \"campaign_events\", \"campaign_boards\", \"board_templates\", \"board_template_viewers\", \"campaign_timeline_chanels\", \"campaign_timeline_channels\", \"campaign_timeline_board_templates\", \"campaign_timeline_board_viewer_chanels\", \"campaign_timeline_board_viewer_channels\", \"campaign_timeline_chanel_players\", \"campaign_timeline_schedules\", \"campaign_timeline_sequences\", \"scripts\", \"music_channels\", \"music_channel_songs\", \"branch_stations\", \"ad_rates\", \"station_ads\", \"ad_out_packages\", \"ad_out_package_contents\", \"ad_out_package_stations\", \"ad_in_domains\", \"ad_in_domain_businesses\", \"ad_in_domain_business_packages\", \"ad_in_domain_business_package_stations\"];\n\n\n    dataModule.m_tables[\"global_settings\"] = new Table_global_settings(this);\n    dataModule.m_tables[\"resources\"] = new Table_resources(this);\n    dataModule.m_tables[\"ad_local_packages\"] = new Table_ad_local_packages(this);\n    dataModule.m_tables[\"ad_local_contents\"] = new Table_ad_local_contents(this);\n    dataModule.m_tables[\"category_values\"] = new Table_category_values(this);\n    dataModule.m_tables[\"catalog_items\"] = new Table_catalog_items(this);\n    dataModule.m_tables[\"catalog_item_infos\"] = new Table_catalog_item_infos(this);\n    dataModule.m_tables[\"catalog_item_resources\"] = new Table_catalog_item_resources(this);\n    dataModule.m_tables[\"catalog_item_categories\"] = new Table_catalog_item_categories(this);\n    dataModule.m_tables[\"player_data\"] = new Table_player_data(this);\n    dataModule.m_tables[\"boards\"] = new Table_boards(this);\n    dataModule.m_tables[\"campaigns\"] = new Table_campaigns(this);\n    dataModule.m_tables[\"campaign_channels\"] = new Table_campaign_channels(this);\n    dataModule.m_tables[\"campaign_channel_players\"] = new Table_campaign_channel_players(this);\n    dataModule.m_tables[\"campaign_timelines\"] = new Table_campaign_timelines(this);\n    dataModule.m_tables[\"campaign_events\"] = new Table_campaign_events(this);\n    dataModule.m_tables[\"campaign_boards\"] = new Table_campaign_boards(this);\n    dataModule.m_tables[\"board_templates\"] = new Table_board_templates(this);\n    dataModule.m_tables[\"board_template_viewers\"] = new Table_board_template_viewers(this);\n    dataModule.m_tables[\"campaign_timeline_chanels\"] = new Table_campaign_timeline_chanels(this);\n    dataModule.m_tables[\"campaign_timeline_channels\"] = new Table_campaign_timeline_channels(this);\n    dataModule.m_tables[\"campaign_timeline_board_templates\"] = new Table_campaign_timeline_board_templates(this);\n    dataModule.m_tables[\"campaign_timeline_board_viewer_chanels\"] = new Table_campaign_timeline_board_viewer_chanels(this);\n    dataModule.m_tables[\"campaign_timeline_board_viewer_channels\"] = new Table_campaign_timeline_board_viewer_channels(this);\n    dataModule.m_tables[\"campaign_timeline_chanel_players\"] = new Table_campaign_timeline_chanel_players(this);\n    dataModule.m_tables[\"campaign_timeline_schedules\"] = new Table_campaign_timeline_schedules(this);\n    dataModule.m_tables[\"campaign_timeline_sequences\"] = new Table_campaign_timeline_sequences(this);\n    dataModule.m_tables[\"scripts\"] = new Table_scripts(this);\n    dataModule.m_tables[\"music_channels\"] = new Table_music_channels(this);\n    dataModule.m_tables[\"music_channel_songs\"] = new Table_music_channel_songs(this);\n    dataModule.m_tables[\"branch_stations\"] = new Table_branch_stations(this);\n    dataModule.m_tables[\"ad_rates\"] = new Table_ad_rates(this);\n    dataModule.m_tables[\"station_ads\"] = new Table_station_ads(this);\n    dataModule.m_tables[\"ad_out_packages\"] = new Table_ad_out_packages(this);\n    dataModule.m_tables[\"ad_out_package_contents\"] = new Table_ad_out_package_contents(this);\n    dataModule.m_tables[\"ad_out_package_stations\"] = new Table_ad_out_package_stations(this);\n    dataModule.m_tables[\"ad_in_domains\"] = new Table_ad_in_domains(this);\n    dataModule.m_tables[\"ad_in_domain_businesses\"] = new Table_ad_in_domain_businesses(this);\n    dataModule.m_tables[\"ad_in_domain_business_packages\"] = new Table_ad_in_domain_business_packages(this);\n    dataModule.m_tables[\"ad_in_domain_business_package_stations\"] = new Table_ad_in_domain_business_package_stations(this);\n}\n\n\nDataBaseManager.prototype.createHandles = function () {\n    self2 = this;\n    self2.createFieldHandles(self2.table_campaign_timeline_chanel_players(), \"player_data\");\n    self2.createFieldHandles(self2.table_campaign_channel_players(), \"player_data\");\n    self2.createFieldHandles(self2.table_player_data(), \"player_data_value\");\n}\n\nfunction DataManager() {\n    this.m_businessData = {};\n    this.m_selectedDataBase = -1;\n}\n\n\nDataManager.prototype.createDataModule = function (i_businessDomain, i_businessId) {\n    var domainBusinessKey = i_businessDomain + \".\" + i_businessId;\n    var dataBase = new DataModuleBase();\n    this.m_businessData[domainBusinessKey] = dataBase;\n    return dataBase;\n}\n\nDataManager.prototype.getDataModule = function (i_businessDomain, i_businessId) {\n    var domainBusinessKey = i_businessDomain + \".\" + i_businessId;\n    return this.m_businessData[domainBusinessKey];\n}\n\nDataManager.prototype.selectDomainBusiness = function (i_businessDomain, i_businessId) {\n    var domainBusinessKey = i_businessDomain + \".\" + i_businessId;\n    this.m_selectedDataBase = this.m_businessData[domainBusinessKey];\n}\n\nDataManager.prototype.getPrimaryToTableMap = function () {\n    return this.m_selectedDataBase.getPrimaryToTableMap();\n}\n\nDataManager.prototype.loadTables = function (i_xmlTables) {\n    var self = this;\n    try {\n        for (var iTable = 0; iTable < i_xmlTables.documentElement.childNodes.length; iTable++) {\n            var xmlTable = i_xmlTables.documentElement.childNodes[iTable]\n            // console.log(xmlTable.nodeName);\n            var tableName = xmlTable.attributes[\"name\"].value;\n\n            var table = this.getTable(tableName);\n\n            table.addData(xmlTable);\n\n        }\n\n\n        // a2\n\n\n        self.createHandles();  // ppp2\n    }\n    catch (error) {\n        alert(\"error1=\" + error)\n    }\n}\n\n\nDataManager.prototype.getTable = function (i_table) {\n    return this.m_selectedDataBase.getTable(i_table);\n}\n//let try to debug now k\nDataManager.prototype.getChangelist = function () {\n    return this.m_selectedDataBase.getChangelist();\n}\n\n\nDataManager.prototype.commitChanges = function (i_changelistId) {\n    this.m_selectedDataBase.commitChanges(i_changelistId);\n}\n\n\nDataManager.prototype.createHandles = function () {\n\n}\n\n\nDataManager.prototype.createFieldHandles = function (i_table, i_field) {\n    this.m_selectedDataBase.createFieldHandles(i_table, i_field);\n}\nfunction DataModuleBase() {\n    this.m_tables = {};\n}\n\nDataModuleBase.prototype.getTable = function getTable(i_table) {\n    return this.m_tables[i_table];\n}\n\n\nDataModuleBase.prototype.getChangelist = function () {\n    var reverseList = [];\n\n    for (var iTable in this.m_tableList) {\n        var sTable = this.m_tableList[iTable];\n        reverseList.push(sTable);\n    }\n    reverseList.reverse();\n\n    var doc = jQuery.parseXML(\"<Changelist/>\");\n    // var xmlChangelist =  jQuery.parseXML(\"<Changelist/>\").firstChild;\n\n    var table;\n    for (var iTable in this.m_tableList) {\n        var tableName = this.m_tableList[iTable];\n        this.getTable(tableName).appendModifyAndNewChangelist(doc);\n    }\n\n    for (var iTable in this.m_tableList) {\n        var tableName = this.m_tableList[iTable];\n        this.getTable(tableName).appendDeletedChangelist(doc);\n    }\n\n\n    return (new XMLSerializer()).serializeToString(doc);\n}\n\n\nDataModuleBase.prototype.commitChanges = function (i_changelistId) {\n    for (var iTable in this.m_tables) {\n        var table = this.m_tables[iTable];\n        table.commitChanges(i_changelistId);\n    }\n}\n\n\nDataModuleBase.prototype.getPrimaryToTableMap = function () {\n    var fields = {};\n    for (var iTable in this.m_tables) {\n        var table = this.m_tables[iTable];\n        var field = table.m_fields[0].field;\n        var tableList = fields[field];\n        if (tableList == null) {\n            fields[field] = tableList = [];\n        }\n        tableList.push(table);\n    }\n    return fields;\n}\n\n\nDataModuleBase.prototype.createFieldHandles = function (i_table, i_field) {\n    var self3 = this;\n    var keys = i_table.getAllPrimaryKeys();\n\n    for (var iKey in keys) {\n        var handle = keys[iKey];\n        record = i_table.getRec(handle);\n        try {\n            var data = record[i_field];\n            if (data != null && data != \"\") {\n                var doc = jQuery.parseXML(data);\n                var xmlField = doc.documentElement;\n                self3.convertToHandels(xmlField);\n                record[i_field] = new XMLSerializer().serializeToString(xmlField);\n            }\n        }\n        catch (error) {\n            alert(\"error\");\n        }\n    }\n}\n\n\nDataModuleBase.prototype.convertToHandels = function (i_xmlField) {\n    var self4 = this;\n    var resources = i_xmlField.getElementsByTagName('Resource');\n    for (var i = 0; i < resources.length; i++) {\n        var xmlResource = resources[i];\n        var resourceId = xmlResource.getAttribute('resource');\n        if (resourceId != -1) {\n            var hResource = self4.getTable(\"resources\").getHandle(resourceId);\n            xmlResource.setAttribute(\"hResource\", hResource);\n        }\n    }\n\n\n    self4.createPlayHandle(i_xmlField);\n    var playerList = i_xmlField.getElementsByTagName('Player');\n    for (var i = 0; i < playerList.length; i++) {\n        var xmlPlayer = playerList[i];\n        self4.createPlayHandle(xmlPlayer);\n    }\n\n\n    var categoryList = i_xmlField.getElementsByTagName('Category');\n    for (var i = 0; i < categoryList.length; i++) {\n        var xmlCategory = categoryList[i];\n        var categoryId = xmlCategory.getAttribute('id');\n        if (categoryId != -1) {\n            var hCategory = self4.getTable(\"category_values\").getHandle(categoryId);\n            xmlCategory.setAttribute(\"handle\", hCategory);\n        }\n    }\n\n\n    var adLocalContentList = i_xmlField.getElementsByTagName('AdLocalContent');\n    for (var i = 0; i < adLocalContentList.length; i++) {\n        var xmlAdLocalContent = adLocalContentList[i];\n        var adLocalContentId = xmlAdLocalContent.getAttribute('id');\n        if (adLocalContentId != -1) {\n            var hAdLocalContent = self4.getTable(\"ad_local_contents\").getHandle(adLocalContentId);\n            xmlAdLocalContent.setAttribute(\"handle\", hAdLocalContent);\n        }\n    }\n}\n\n\nDataModuleBase.prototype.createPlayHandle = function (i_xmlPlayer) {\n    var self5 = this;\n    var dataId = i_xmlPlayer.getAttribute('src');\n    if (dataId != null && dataId != -1) {\n        var dataSrc = self5.getTable(\"player_data\").getHandle(dataId);\n        i_xmlPlayer.setAttribute(\"hDataSrc\", dataSrc);\n    }\n}\n/*\tThis work is licensed under Creative Commons GNU LGPL License.\n\n License: http://creativecommons.org/licenses/LGPL/2.1/\n Version: 0.9\n Author:  Stefan Goessner/2006\n Web:     http://goessner.net/\n */\nfunction json2xml(o, tab) {\n    var toXml = function (v, name, ind) {\n        var xml = \"\";\n        if (v instanceof Array) {\n            for (var i = 0, n = v.length; i < n; i++)\n                xml += ind + toXml(v[i], name, ind + \"\\t\") + \"\\n\";\n        }\n        else if (typeof(v) == \"object\") {\n            var hasChild = false;\n            xml += ind + \"<\" + name;\n            for (var m in v) {\n                if (m.charAt(0) == \"@\")\n                    xml += \" \" + m.substr(1) + \"=\\\"\" + v[m].toString() + \"\\\"\";\n                else\n                    hasChild = true;\n            }\n            xml += hasChild ? \">\" : \"/>\";\n            if (hasChild) {\n                for (var m in v) {\n                    if (m == \"#text\")\n                        xml += v[m];\n                    else if (m == \"#cdata\")\n                        xml += \"<![CDATA[\" + v[m] + \"]]>\";\n                    else if (m.charAt(0) != \"@\")\n                        xml += toXml(v[m], m, ind + \"\\t\");\n                }\n                xml += (xml.charAt(xml.length - 1) == \"\\n\" ? ind : \"\") + \"</\" + name + \">\";\n            }\n        }\n        else {\n            xml += ind + \"<\" + name + \">\" + v.toString() + \"</\" + name + \">\";\n        }\n        return xml;\n    }, xml = \"\";\n    for (var m in o)\n        xml += toXml(o[m], m, \"\");\n    return tab ? xml.replace(/\\t/g, tab) : xml.replace(/\\t|\\n/g, \"\");\n}\nfunction LoaderManager() {\n    this.root = this;\n    this.m_dataBaseManager = new DataBaseManager();\n    this.m_domain = null;\n    this.m_businessId = -1;\n    this.m_userpass64 = null;\n    this.filesToUpload = [];\n    this.m_shortcutMap = {};\n};\n\n\nLoaderManager.prototype.create = function (i_user, i_password, i_requestCallback) {\n    var me = this;\n    var userPass = i_user + \",\" + i_password;\n    var param = jQuery.base64.encode(userPass);\n    param = param.replace(/=/g, \".\");\n    param = param.replace(/[+]/g, \"_\");\n    this.m_userpass64 = param.replace(/[/]/g, \"-\");\n\n    var url = window.g_protocol + g_masterDomain + '/WebService/getUserDomain.ashx?i_userpass=' + this.m_userpass64 + '&callback=?';\n    // url = 'https://galaxy.signage.me/WebService/getUserDomain.ashx?i_userpass=bGl0ZTkwQG1zLmNvbSwxMjMxMjM.&callback=?'\n    // url = url.replace(/\\.\\.&callback/,'\\.&callback')\n\n    //todo: Alon add this logic for offline\n    if (window['offlineDevMode']) {\n        // ;debugger; //offline\n        // var data = JSON.parse(offlineDataUser);\n        var data = JSON.parse(localStorage.getItem('offlineDataUser'));\n        if (data.businessId == -1) {\n            i_requestCallback({status: false, error: 'login fail'});\n            return;\n        }\n        me.m_domain = data.domain;\n        me.m_businessId = data.businessId;\n        me.m_eri = data.eri;\n        me.m_studioLite = data.studioLite;\n\n        var s64 = data.resellerInfo;\n        var str = jQuery.base64.decode(s64);\n\n        var xml = jQuery.parseXML(str);\n        me.m_resellerInfo = xml;\n        me.m_dataBaseManager.createDataBase(me.m_domain, me.m_businessId);\n        me.m_dataBaseManager.selectDomainBusiness(me.m_domain, me.m_businessId);\n\n        me.requestData(\n            function () {\n                if (data.studioLite == 0) {\n                    i_requestCallback({status: true, error: '', warning: 'not a studioLite account'});\n                }\n                else {\n                    i_requestCallback({status: true, error: '', warning: ''});\n                }\n            }\n        );\n    } else {\n\n        //todo: Alon replace all $ with jQuery\n        // console.log('url 1 ' + url);\n        // debugger;\n        jQuery.getJSON(url,\n            function (data) {\n                // to update latest offline grab 'data' and paste onto the top var: offlineDataUser\n                ;\n                // debugger; /// <<< here\n                if (data.businessId == -1) {\n                    i_requestCallback({status: false, error: 'login fail'});\n                    return;\n                }\n                localStorage.setItem('offlineDataUser', JSON.stringify(data));\n\n                me.m_domain = data.domain;\n                me.m_businessId = data.businessId;\n                me.m_eri = data.eri;\n                me.m_studioLite = data.studioLite;\n                // debugger\n                var s64 = data.resellerInfo;\n                var str = jQuery.base64.decode(s64);\n                var xml = jQuery.parseXML(str);\n                me.m_resellerInfo = xml;\n\n                me.m_dataBaseManager.createDataBase(me.m_domain, me.m_businessId);\n                me.m_dataBaseManager.selectDomainBusiness(me.m_domain, me.m_businessId);\n\n                me.requestData(\n                    function () {\n                        if (data.studioLite == 0) {\n                            i_requestCallback({status: true, error: '', warning: 'not a studioLite account'});\n                        }\n                        else {\n                            i_requestCallback({status: true, error: '', warning: ''});\n                        }\n                    }\n                );\n            }\n            // todo: Alon needs to add the following lines done, fail, always\n        ).done(function (msg) {\n        }).fail(function (err) {\n            i_requestCallback({status: false, error: err, warning: 'reseller account'});\n        }).always(function (msg) {\n        });\n    }\n\n\n}\n\nLoaderManager.prototype.requestData = function (i_requestCallback) {\n\n    var self = this;\n    self.requestCallback = i_requestCallback;\n\n    //todo: Alon add this logic for offline\n    if (window['offlineDevMode']) {\n        // ;debugger; //offline\n        // var data = JSON.parse(offlineDataAccount);\n        var data = JSON.parse(localStorage.getItem('offlineDataAccount'));\n        var s64 = data.ret;\n        var str = jQuery.base64.decode(s64);\n        var xml = jQuery.parseXML(str);\n        self.m_dataBaseManager.loadTables(xml);\n\n        self.requestCallback();\n\n        /*\n         self.importScene(401212, 1, function()\n         {\n         self.importScene(401212, 5, self.requestCallback)\n         })\n         */\n    } else {\n        var url = window.g_protocol + self.m_domain + '/WebService/RequestData.ashx?businessId=' + this.m_businessId + '&callback=?';\n        // console.log('url 2 ' + url);\n        // debugger;\n        jQuery.getJSON(url,\n            function (data) {\n                //;debugger; /// <<< here\n                // to update latest offline grab 'data' and paste onto the top var: offlineDataAccount\n                localStorage.setItem('offlineDataAccount', JSON.stringify(data));\n\n                var s64 = data.ret;\n                var str = jQuery.base64.decode(s64);\n                var xml = jQuery.parseXML(str);\n                self.m_dataBaseManager.loadTables(xml);\n\n                self.requestCallback();\n\n                /*\n                 self.importScene(401212, 1, function()\n                 {\n                 self.importScene(401212, 5, self.requestCallback)\n                 })\n                 */\n            }\n        );\n    }\n\n}\n\nLoaderManager.prototype.importScene = function (i_businessId, i_playerDataId, i_importCallback) {\n    var self = this;\n    self.importCallback = i_importCallback;\n\n    //var url= window.g_protocol + g_masterDomain + '/WebService/getBusinessDomain.ashx?businessId='+i_businessId+'&callback=?';\n    var url = window.g_protocol + 'galaxy.signage.me' + '/WebService/getBusinessDomain.ashx?businessId=' + i_businessId + '&callback=?';\n    //alert(url);\n    // debugger;\n    jQuery.getJSON(url,\n        function (data1) {\n            // debugger\n            var srcDB = self.m_dataBaseManager.getDataModule(data1.domain, i_businessId);\n            if (srcDB == null) {\n                self.m_dataBaseManager.createDataBase(data1.domain, i_businessId);\n                self.m_dataBaseManager.selectDomainBusiness(data1.domain, i_businessId);\n\n                var url = window.g_protocol + data1.domain + '/WebService/RequestData.ashx?businessId=' + i_businessId + '&mode=playerData&callback=?';\n                // debugger;\n                jQuery.getJSON(url,\n                    function (data2) {\n                        // debugger\n                        var str = jQuery.base64.decode(data2.ret);\n                        var xml = jQuery.parseXML(str);\n                        self.m_dataBaseManager.loadTables(xml);\n\n                        var hPlayerData = self.copyScene(data1.domain, i_businessId, i_playerDataId)\n                        self.m_dataBaseManager.selectDomainBusiness(self.m_domain, self.m_businessId);\n                        self.importCallback(hPlayerData);\n                    });\n            }\n            else {\n                var hPlayerData = self.copyScene(data1.domain, i_businessId, i_playerDataId);\n                self.m_dataBaseManager.selectDomainBusiness(self.m_domain, self.m_businessId);\n                self.importCallback(hPlayerData);\n            }\n        }\n    );\n}\n\n\nLoaderManager.prototype.copyScene = function (i_srcBusinessDomain, i_srcBusiness, i_playerDataId) {\n    var self = this;\n    if (self.m_businessId == i_srcBusiness)\n        return false;\n\n    var srcDB = self.m_dataBaseManager.getDataModule(i_srcBusinessDomain, i_srcBusiness);\n    if (srcDB == null)\n        return false;\n\n    var dstDB = self.m_dataBaseManager.getDataModule(self.m_domain, self.m_businessId);\n    if (dstDB == null)\n        return false;\n\n    var srcResourceTable = srcDB.getTable(\"resources\");\n    var dstResourceTable = dstDB.getTable(\"resources\");\n\n\n    self.m_shortcutMap = {};\n\n    var resourceKeys = dstResourceTable.getAllPrimaryKeys();\n\n    for (var i = 0; i < resourceKeys.length; i++) {\n        var hResource = resourceKeys[i];\n        var recResource = dstResourceTable.getRec(hResource);\n        var resourcekey = self.getUniqueId(self.m_businessId, recResource);\n        if (resourcekey != null) {\n            self.m_shortcutMap[resourcekey] = hResource;\n        }\n    }\n\n\n    var srcTable = srcDB.getTable(\"player_data\");\n    var hPlayerData = srcTable.getHandle(i_playerDataId);\n    var srcRecPlayerData = srcTable.getRec(hPlayerData);\n    var value = srcRecPlayerData.player_data_value;\n\n    var dstPlayerDataTable = dstDB.getTable(\"player_data\");\n    var dstRecPlayerData = dstPlayerDataTable.createRecord();\n    dstPlayerDataTable.addRecord(dstRecPlayerData);\n\n    var playerDataValue = srcRecPlayerData.player_data_value;\n\n\n    var xml = jQuery.parseXML(playerDataValue);\n\n\n    jQuery(xml).find('Resource').each(function () {\n        var hSrcResource = jQuery(this).attr('hResource');\n        var srcRecResource = srcResourceTable.getRec(hSrcResource);\n\n        var hDstResource = -1;\n        var resourcekey = self.getUniqueId(i_srcBusiness, srcRecResource);\n        if (self.m_shortcutMap[resourcekey] != null) {\n            hDstResource = self.m_shortcutMap[resourcekey];\n        }\n        else {\n            var dstRecResource = dstResourceTable.createRecord();\n            dstResourceTable.addRecord(dstRecResource);\n            hDstResource = dstRecResource.resource_id;\n\n            dstRecResource.default_player = srcRecResource.default_player;\n            dstRecResource.resource_bytes_total = srcRecResource.resource_bytes_total;\n            dstRecResource.resource_name = srcRecResource.resource_name;\n            dstRecResource.resource_type = srcRecResource.resource_type;\n            dstRecResource.shortcut_business_id = i_srcBusiness;\n            dstRecResource.shortcut_resource_id = srcRecResource.native_id;\n\n            var filePack = {};\n            filePack.type = \"url\";\n            filePack.url = window.g_protocol + i_srcBusinessDomain + '/Resources/business' + i_srcBusiness + '/resources/' + srcRecResource.native_id + '.' + srcRecResource.resource_type;\n            filePack.fileName = dstRecResource.resource_id + \".\" + dstRecResource.resource_type;\n            self.filesToUpload.push(filePack);\n        }\n        jQuery(this).attr('hResource', hDstResource);\n        jQuery(this).removeAttr('resource');\n    });\n\n    dstRecPlayerData.player_data_value = (new XMLSerializer()).serializeToString(xml);\n\n    return dstRecPlayerData.player_data_id;\n}\n\n\nLoaderManager.prototype.getUniqueId = function (i_businessId, i_recResource) {\n    var resourcekey = null;\n    if (i_recResource.shortcut_business_id > 0) {\n        resourcekey = i_recResource.shortcut_business_id + \".\" + i_recResource.shortcut_resource_id;\n    }\n    else if (i_recResource.native_id != -1) {\n        resourcekey = i_businessId + \".\" + i_recResource.native_id;\n    }\n\n    return resourcekey;\n}\n\n\nLoaderManager.prototype.createResources = function (i_uploadFileElement) {\n    var self = this;\n\n    var resourceList = [];\n\n    var fnAddResource = function addResource(i_file) {\n        var filePack = {};\n        filePack.type = \"file\";\n        filePack.file = i_file;\n        var fileNameAndExt = self.getFileNameAndExt(filePack.file.name);\n        var fileName = fileNameAndExt[0];\n        var fileExt = fileNameAndExt[1];\n        var defaultPlayer = self.getDefaultPlayer(fileExt);\n\n        var resources = self.m_dataBaseManager.table_resources();\n        var resource = resources.createRecord();\n        resource.resource_name = fileName;\n        resource.resource_type = fileExt;\n        resource.default_player = defaultPlayer;\n        resource.resource_bytes_total = filePack.file.size;\n        resources.addRecord(resource);\n        resourceList.push(resource.resource_id);\n        filePack.fileName = resource.resource_id + \".\" + fileExt\n\n        self.filesToUpload.push(filePack);\n\n        //alert(fileName);\n    }\n\n\n    if (i_uploadFileElement.files) {\n        //alert('multi files')\n        var count = i_uploadFileElement.files.length;\n        for (var iFile = 0; iFile < count; iFile++) {\n            fnAddResource(i_uploadFileElement.files[iFile])\n        }\n    }\n    else {\n        alert('Your browser version does not support HTML5, please upgrade to a newer version.')\n        //fnAddResource(i_uploadFileElement)\n    }\n\n\n    return resourceList;\n}\n\n\nLoaderManager.prototype.getFileNameAndExt = function (i_fileName) {\n    var result = null;\n    var nameAndExt = i_fileName.split(\".\");\n    try {\n        var ext = nameAndExt[nameAndExt.length - 1];\n        var name = i_fileName.substring(0, i_fileName.length - ext.length - 1);\n        result = [name, ext.toLowerCase()];\n    }\n    catch (error) {\n        // Invalid file format\n        return null;\n    }\n    return result;\n}\n\n\nLoaderManager.prototype.getDefaultPlayer = function (i_fileExt) {\n    var playerModule = -1;\n    switch (i_fileExt) {\n        case \"flv\":\n        case \"mp4\":\n        case \"m4v\":\n        case \"mov\":\n        case \"3gp\":\n            playerModule = 3100;\n            break;\n        case \"jpg\":\n        case \"jpeg\":\n        case \"gif\":\n        case \"png\":\n        case \"bmp\": //??? bmp\n        case \"swf\":\n        case \"pdf\":\n            playerModule = 3130;\n            break;\n    }\n    return playerModule;\n}\n\n\nLoaderManager.prototype.save = function (i_saveCallback) {\n    var sv = this;\n    var url1 = window.g_protocol + sv.m_domain + '/WebService/SubmitData.ashx?command=Begin&userpass=' + sv.m_userpass64 + '&appVersion=4.12&appType=StudioLite' + '&callback=?';\n\n    jQuery.getJSON(url1, function (d1) {\n        // debugger\n        uploadNextFile(d1.ret);\n    });\n\n\n    function uploadNextFile(i_cookie) {\n        var filePack = sv.filesToUpload.shift();\n        if (filePack != null) {\n            if (filePack.type == \"file\") {\n                var httpRequest = new XMLHttpRequest();\n                try {\n                    httpRequest.onload = function (oEvent) {\n                        if (httpRequest.status == 200) {\n\n                            uploadNextFile(i_cookie);\n                        }\n                    };\n                    var formData = new FormData();\n                    formData.append(\"cookie\", i_cookie);\n                    formData.append(\"file\", filePack.file);\n                    formData.append(\"filename\", filePack.fileName);\n                    httpRequest.open(\"POST\", window.g_protocol + sv.m_domain + '/WebService/JsUpload.ashx');\n                    httpRequest.send(formData);\n                }\n                catch (error) {\n                    alert(\"error2=\" + error)\n                }\n            }\n            else if (filePack.type == \"url\") {\n                var url = window.g_protocol + sv.m_domain + '/WebService/UploadResource.ashx?cookie=' + i_cookie + '&fileName=' + filePack.fileName + '&url=' + filePack.url + '&callback=?';\n                // debugger;\n                jQuery.getJSON(url,\n                    function (data2) {\n                        // debugger\n                        if (data2.success) {\n                            uploadNextFile(i_cookie);\n                        }\n                    });\n            }\n        }\n        else {\n            uploadTables(i_cookie);\n        }\n\n\n        /*\n         var iframe = document.createElement(\"iframe\");\n         iframe.setAttribute(\"id\", \"upload_iframe\");\n         iframe.setAttribute(\"name\", \"upload_iframe\");\n         iframe.setAttribute(\"width\", \"0\");\n         iframe.setAttribute(\"height\", \"0\");\n         iframe.setAttribute(\"border\", \"0\");\n         iframe.setAttribute(\"style\", \"width: 0; height: 0; border: none;\");\n\n         // Add to document...\n         sv.m_uploadFormElement.parentNode.appendChild(iframe);\n         window.frames['upload_iframe'].name = \"upload_iframe\";\n\n         iframeId = document.getElementById(\"upload_iframe\");\n\n         // Add event...\n         var eventHandler = function () {\n\n         if (iframeId.detachEvent) iframeId.detachEvent(\"onload\", eventHandler);\n         else iframeId.removeEventListener(\"load\", eventHandler, false);\n\n         // Message from server...\n         if (iframeId.contentDocument) {\n         content = iframeId.contentDocument.body.innerHTML;\n         } else if (iframeId.contentWindow) {\n         content = iframeId.contentWindow.document.body.innerHTML;\n         } else if (iframeId.document) {\n         content = iframeId.document.body.innerHTML;\n         }\n\n         document.getElementById(div_id).innerHTML = content;\n\n         // Del the iframe...\n         setTimeout('iframeId.parentNode.removeChild(iframeId)', 250);\n         }\n\n         if (iframeId.addEventListener) iframeId.addEventListener(\"load\", eventHandler, true);\n         if (iframeId.attachEvent) iframeId.attachEvent(\"onload\", eventHandler);\n\n         // Set properties of form...\n         sv.m_uploadFormElement.setAttribute(\"target\", \"upload_iframe\");\n         sv.m_uploadFormElement.setAttribute(\"action\", window.g_protocol+sv.m_domain+'/WebService/JsUpload.ashx');\n         sv.m_uploadFormElement.setAttribute(\"method\", \"post\");\n         sv.m_uploadFormElement.setAttribute(\"enctype\", \"multipart/form-data\");\n         sv.m_uploadFormElement.setAttribute(\"encoding\", \"multipart/form-data\");\n\n\n         // Submit the form...\n         sv.m_uploadFormElement.submit();\n\n         sv.m_uploadDivElement.innerHTML = \"Uploading...\";\n         */\n    }\n\n\n    function uploadTables(i_cookie) {\n\n        // todo: Alon needs to fix, Mantis bug: 0002650, add support for extended characters via fix of Base64 encode / decode in signage_sdk.js\n        // debugger;\n        // var arg = Base64Encode('先秦兩');\n        // var v = Base64Decode(arg);\n        // console.log(v);\n        \n        var changelist = sv.m_dataBaseManager.getChangelist();\n        var s64 = jQuery.base64.encode(changelist);\n        s64 = s64.replace(/=/g, \".\");\n        s64 = s64.replace(/[+]/g, \"_\");\n        s64 = s64.replace(/[/]/g, \"-\");\n        multiPost(i_cookie, s64, 0)\n    }\n\n\n    function multiPost(i_cookie, i_data, i) {\n        var url2 = window.g_protocol + sv.m_domain + '/WebService/SubmitData.ashx?command=Commit&cookie=' + i_cookie + '&callback=?';\n        //var j = Math.min(i+300, i_data.length); // 1850 pass  1950 fail\n        var j = Math.min(i + 1500, i_data.length); // 1850 pass  1950 fail\n        var d1 = i_data.substring(i, j);\n        //alert(d1);\n\n        jQuery.getJSON(url2,\n            {prm: d1},\n            function (data) {\n                // debugger\n                if (i == j) {\n                    //alert(data.ret);\n                    if (data != null && data.ret != \"\") {\n                        var s64 = data.ret;\n                        var str = jQuery.base64.decode(s64);\n                        var xml = jQuery.parseXML(str);\n                        onSubmitData(xml.documentElement)\n\n                        if (i_saveCallback != null) {\n                            i_saveCallback({status: true});\n                        }\n                    }\n                    else {\n                        if (i_saveCallback != null) {\n                            i_saveCallback({status: false, error: data.error});\n                        }\n                    }\n                }\n                else {\n                    multiPost(i_cookie, i_data, j);\n                }\n            },\n            'JSON'\n        );\n    }\n\n\n    function onSubmitData(i_xmlTables) {\n        var xmlTable;\n        var iTable;\n        var table;\n\n        sv.m_dataBaseManager.selectDomainBusiness(sv.m_domain, sv.m_businessId);\n        var primaryToTables = sv.m_dataBaseManager.getPrimaryToTableMap();\n\n\n        var changelistId = i_xmlTables.getAttribute(\"lastChangelistId\");\n        sv.m_dataBaseManager.lastChangelist = changelistId;\n\n        for (iTable = 0; iTable < i_xmlTables.childNodes.length; iTable++) {\n            xmlTable = i_xmlTables.childNodes[iTable];\n\n            var field = xmlTable.getAttribute(\"name\");\n            var tableList = primaryToTables[field];\n            for (iTable2 in tableList) {\n                var table = tableList[iTable2];\n                for (var iRec = 0; iRec < xmlTable.childNodes.length; iRec++) {\n                    var xmlRec = xmlTable.childNodes[iRec];\n                    var handle = xmlRec.getAttribute(\"handle\");\n                    var id = xmlRec.getAttribute(\"id\");\n                    var rec = table.getRec(handle);\n                    if (rec != null) {\n                        rec.native_id = id;\n                        table.setRecordId(handle, id);\n                    }\n                }\n            }\n        }\n        sv.m_dataBaseManager.commitChanges(changelistId);\n    }\n\n}\n\nLoaderManager.prototype.requestAdsReport = function (i_callback, i_year, i_month) {\n    var self = this;\n\n    var url = window.g_protocol + this.m_domain + '/WebService/requestAdsReport.ashx?i_userpass=' + self.m_userpass64 + '&i_year=' + i_year + '&i_month=' + i_month + '&callback=?';\n    // debugger;\n    jQuery.getJSON(url,\n        function (data) {\n            // debugger\n            var s64 = data.ret;\n            var str = jQuery.base64.decode(s64);\n            var xml = jQuery.parseXML(str);\n            i_callback({report: xml});\n        }\n    );\n}\n\n\nfunction OrderedMap() {\n    this.m_dictionary = {};\n    this.m_keys = [];\n}\n\n\nOrderedMap.prototype.getValue = function (i_key) {\n    return this.m_dictionary[i_key];\n}\n\nOrderedMap.prototype.count = function () {\n    return this.m_keys.length;\n}\n\nOrderedMap.prototype.getKeyAt = function (i_index) {\n    return this.m_keys[i_index];\n}\n\nOrderedMap.prototype.add = function (i_key, i_value) {\n    if (this.m_dictionary[i_key] == null) {\n        this.m_keys.push(i_key);\n    }\n    this.m_dictionary[i_key] = i_value;\n}\n\nOrderedMap.prototype.remove = function (i_key) {\n    delete this.m_dictionary[i_key];\n    for (var i = 0; i < this.m_keys.length; i++) {\n        if (this.m_keys[i] == i_key) {\n            this.m_keys.splice(i, 1);\n            break;\n        }\n    }\n}\n\nOrderedMap.prototype.concatinateKeys = function (i_destKeys) {\n    for (var iKey in this.m_keys) {\n        var key = this.m_keys[iKey];\n        i_destKeys.push(key);\n    }\n}\n\nOrderedMap.prototype.removeAll = function () {\n    this.m_dictionary = {};\n    this.m_keys = [];\n}\n// Avoid `console` errors in browsers that lack a console.\n(function () {\n    var method;\n    var noop = function () {\n    };\n    var methods = [\n        'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',\n        'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',\n        'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',\n        'timeStamp', 'trace', 'warn'\n    ];\n    var length = methods.length;\n    var console = (window.console = window.console || {});\n\n    while (length--) {\n        method = methods[length];\n\n        // Only stub undefined methods.\n        if (!console[method]) {\n            console[method] = noop;\n        }\n    }\n}());\n\n// Place any jQuery/helper plugins in here.\nfunction Record() {\n    this.self = this;\n    this.native_id = -1;\n    this.changelist_id = -1;\n    this.change_type = 0;\n    this.status = 0; // 0 - nothing; 1-update; 2- added; 3-deleted\n    this.conflict = false;\n};\nfunction Rec_ad_in_domain() {\n    Record.call(this);\n\n    this.ad_in_domain_id;\n    this.ad_out_domain;\n    this.accept_new_business = 0;\n\n}\n\nextend(Record, Rec_ad_in_domain);\nfunction Rec_ad_in_domain_business() {\n    Record.call(this);\n\n    this.ad_in_domain_business_id;\n    this.ad_in_domain_id;\n    this.ad_out_business_id;\n    this.accept_new_package = 0;\n\n}\n\nextend(Record, Rec_ad_in_domain_business);\nfunction Rec_ad_in_domain_business_package() {\n    Record.call(this);\n\n    this.ad_in_domain_business_package_id;\n    this.ad_in_domain_business_id;\n    this.ad_package_id;\n    this.accept_new_station = 0;\n    this.suspend_modified_package_date = false;\n    this.suspend_modified_content = false;\n\n}\n\nextend(Record, Rec_ad_in_domain_business_package);\nfunction Rec_ad_in_domain_business_package_station() {\n    Record.call(this);\n\n    this.ad_in_domain_business_package_station_id;\n    this.ad_in_domain_business_package_id;\n    this.ad_package_station_id;\n    this.accept_status = 0;\n    this.suspend_modified_station = false;\n\n}\n\nextend(Record, Rec_ad_in_domain_business_package_station);\nfunction Rec_ad_local_content() {\n    Record.call(this);\n\n    this.ad_local_content_id;\n    this.ad_local_package_id;\n    this.enabled = true;\n    this.content_name = \"\";\n\n}\n\nextend(Record, Rec_ad_local_content);\nfunction Rec_ad_local_package() {\n    Record.call(this);\n\n    this.ad_local_package_id;\n    this.enabled = true;\n    this.package_name = \"Package\";\n    this.use_date_range = false;\n    this.start_date = new Date();\n    this.end_date = new Date();\n\n}\n\nextend(Record, Rec_ad_local_package);\nfunction Rec_ad_out_package() {\n    Record.call(this);\n\n    this.ad_out_package_id;\n    this.package_name = \"Package\";\n    this.start_date = new Date();\n    this.end_date = new Date();\n\n}\n\nextend(Record, Rec_ad_out_package);\nfunction Rec_ad_out_package_content() {\n    Record.call(this);\n\n    this.ad_out_package_content_id;\n    this.ad_out_package_id;\n    this.resource_id;\n    this.player_data_id;\n    this.duration = 5;\n    this.reparations_per_hour = 12;\n\n}\n\nextend(Record, Rec_ad_out_package_content);\nfunction Rec_ad_out_package_station() {\n    Record.call(this);\n\n    this.ad_out_package_station_id;\n    this.ad_out_package_id;\n    this.ad_out_subdomain;\n    this.ad_out_business_id;\n    this.ad_out_station_id;\n    this.days_mask = 127;\n    this.hour_start = 0;\n    this.hour_end = 23;\n\n}\n\nextend(Record, Rec_ad_out_package_station);\nfunction Rec_ad_rate() {\n    Record.call(this);\n\n    this.ad_rate_id;\n    this.ad_rate_name = \"Rate\";\n    this.ad_rate_map;\n    this.hour_rate0 = 0;\n    this.hour_rate1 = 0;\n    this.hour_rate2 = 0;\n    this.hour_rate3 = 0;\n\n}\n\nextend(Record, Rec_ad_rate);\nfunction Rec_board() {\n    Record.call(this);\n\n    this.board_id = (-1);\n    this.board_name = \"S800x600\";\n    this.board_pixel_width = 800;\n    this.board_pixel_height = 600;\n    this.monitor_orientation_enabled = false;\n    this.monitor_orientation_index = 0;\n    this.access_key = 0;\n    this.tree_path = \"\";\n\n}\n\nextend(Record, Rec_board);\nfunction Rec_board_template() {\n    Record.call(this);\n\n    this.board_template_id = (-1);\n    this.board_id = (-1);\n    this.template_name = \"Screen Division\";\n\n}\n\nextend(Record, Rec_board_template);\nfunction Rec_board_template_viewer() {\n    Record.call(this);\n\n    this.board_template_viewer_id = (-1);\n    this.board_template_id = (-1);\n    this.viewer_name = \"Viewer\";\n    this.pixel_x = 0;\n    this.pixel_y = 0;\n    this.pixel_width = 100;\n    this.pixel_height = 100;\n    this.enable_gaps = false;\n    this.viewer_order = 0;\n    this.locked = false;\n\n}\n\nextend(Record, Rec_board_template_viewer);\nfunction Rec_branch_station() {\n    Record.call(this);\n\n    this.branch_station_id = (-1);\n    this.branch_id = (-1);\n    this.campaign_board_id;\n    this.station_name = \"Station\";\n    this.reboot_exceed_mem_enabled = false;\n    this.reboot_exceed_mem_value = 1;\n    this.reboot_time_enabled = true;\n    this.reboot_time_value = 0;\n    this.reboot_error_enabled = false;\n    this.monitor_standby_enabled = false;\n    this.monitor_standby_from = 3600;\n    this.monitor_standby_to = 14400;\n    this.location_address;\n    this.location_long = (-1);\n    this.location_lat = (-1);\n    this.map_type;\n    this.map_zoom = 4;\n    this.station_selected;\n    this.advertising_description;\n    this.advertising_keys;\n    this.reboot_exceed_mem_action = 1;\n    this.reboot_time_action = 2;\n    this.reboot_error_action = 1;\n    this.station_mode = 1;\n    this.power_mode = 0;\n    this.power_on_day1 = 25200;\n    this.power_off_day1 = 68400;\n    this.power_on_day2 = 25200;\n    this.power_off_day2 = 68400;\n    this.power_on_day3 = 25200;\n    this.power_off_day3 = 68400;\n    this.power_on_day4 = 25200;\n    this.power_off_day4 = 68400;\n    this.power_on_day5 = 25200;\n    this.power_off_day5 = 68400;\n    this.power_on_day6 = 25200;\n    this.power_off_day6 = 68400;\n    this.power_on_day7 = 25200;\n    this.power_off_day7 = 68400;\n    this.send_notification = false;\n    this.frame_rate = 24;\n    this.quality = 2;\n    this.transition_enabled = true;\n    this.zwave_config;\n    this.lan_server_enabled = false;\n    this.lan_server_ip;\n    this.lan_server_port = 9999;\n\n}\n\nextend(Record, Rec_branch_station);\nfunction Rec_campaign() {\n    Record.call(this);\n\n    this.campaign_id = (-1);\n    this.campaign_name = \"Campaign\";\n    this.campaign_playlist_mode = 0;\n    this.kiosk_mode = false;\n    this.kiosk_key = \"esc\";\n    this.kiosk_timeline_id = -1;\n    this.kiosk_wait_time = (5);\n    this.mouse_interrupt_mode = false;\n    this.tree_path = \"\";\n    this.access_key = 0;\n\n}\n\nextend(Record, Rec_campaign);\nfunction Rec_campaign_board() {\n    Record.call(this);\n\n    this.campaign_board_id = (-1);\n    this.board_id = (-1);\n    this.campaign_id = (-1);\n    this.campaign_board_name = \"Output\";\n    this.allow_public_view = false;\n    this.admin_public_view = 0;\n\n}\n\nextend(Record, Rec_campaign_board);\nfunction Rec_campaign_channel() {\n    Record.call(this);\n\n    this.campaign_channel_id = (-1);\n    this.campaign_id = (-1);\n    this.chanel_name = \"CH\";\n    this.chanel_color = 0;\n    this.random_order = false;\n    this.repeat_to_fit = true;\n    this.fixed_players_length = true;\n\n}\n\nextend(Record, Rec_campaign_channel);\nfunction Rec_campaign_channel_player() {\n    Record.call(this);\n\n    this.campaign_channel_player_id = (-1);\n    this.campaign_channel_id = (-1);\n    this.player_offset_time = 0;\n    this.player_duration = 60;\n    this.player_data;\n    this.mouse_children = false;\n    this.ad_local_content_id = (-1);\n\n}\n\nextend(Record, Rec_campaign_channel_player);\nfunction Rec_campaign_event() {\n    Record.call(this);\n\n    this.campaign_event_id = (-1);\n    this.campaign_id = (-1);\n    this.sender_name = \"\";\n    this.event_name = \"\";\n    this.event_condition = \"\";\n    this.command_name = \"\";\n    this.campaign_timeline_id = (-1);\n    this.command_params = \"\";\n\n}\n\nextend(Record, Rec_campaign_event);\nfunction Rec_campaign_timeline() {\n    Record.call(this);\n\n    this.campaign_timeline_id = (-1);\n    this.campaign_id = (-1);\n    this.timeline_name = \"Timeline\";\n    this.timeline_duration = 60;\n\n}\n\nextend(Record, Rec_campaign_timeline);\nfunction Rec_campaign_timeline_board_template() {\n    Record.call(this);\n\n    this.campaign_timeline_board_template_id = (-1);\n    this.campaign_timeline_id = (-1);\n    this.board_template_id = (-1);\n    this.campaign_board_id = (-1);\n    this.template_offset_time = 0;\n    this.template_duration = 60;\n\n}\n\nextend(Record, Rec_campaign_timeline_board_template);\nfunction Rec_campaign_timeline_board_viewer_chanel() {\n    Record.call(this);\n\n    this.campaign_timeline_board_viewer_chanel_id = (-1);\n    this.campaign_timeline_board_template_id = (-1);\n    this.board_template_viewer_id = (-1);\n    this.campaign_timeline_chanel_id = (-1);\n\n}\n\nextend(Record, Rec_campaign_timeline_board_viewer_chanel);\nfunction Rec_campaign_timeline_board_viewer_channel() {\n    Record.call(this);\n\n    this.campaign_timeline_board_viewer_channel_id = (-1);\n    this.campaign_timeline_board_template_id = (-1);\n    this.board_template_viewer_id = (-1);\n    this.campaign_channel_id = (-1);\n\n}\n\nextend(Record, Rec_campaign_timeline_board_viewer_channel);\nfunction Rec_campaign_timeline_chanel() {\n    Record.call(this);\n\n    this.campaign_timeline_chanel_id = (-1);\n    this.campaign_timeline_id = (-1);\n    this.chanel_name = \"CH\";\n    this.chanel_color = 0;\n    this.random_order = false;\n    this.repeat_to_fit = false;\n    this.fixed_players_length = true;\n\n}\n\nextend(Record, Rec_campaign_timeline_chanel);\nfunction Rec_campaign_timeline_chanel_player() {\n    Record.call(this);\n\n    this.campaign_timeline_chanel_player_id = (-1);\n    this.campaign_timeline_chanel_id = (-1);\n    this.player_offset_time = 0;\n    this.player_duration = 60;\n    this.player_id = (-1);\n    this.player_editor_id = (-1);\n    this.player_data;\n    this.mouse_children = false;\n    this.ad_local_content_id = (-1);\n\n}\n\nextend(Record, Rec_campaign_timeline_chanel_player);\nfunction Rec_campaign_timeline_channel() {\n    Record.call(this);\n\n    this.campaign_timeline_channel_id = (-1);\n    this.campaign_timeline_id = (-1);\n\n}\n\nextend(Record, Rec_campaign_timeline_channel);\nfunction Rec_campaign_timeline_schedule() {\n    Record.call(this);\n\n    this.campaign_timeline_schedule_id = (-1);\n    this.campaign_timeline_id = (-1);\n    this.priorty = 0;\n    this.start_date = new Date(2007, 10, 24);\n    this.end_date = new Date(2007, 10, 25);\n    this.repeat_type = 0;\n    this.week_days = 0;\n    this.custom_duration = false;\n    this.duration = 0;\n    this.start_time = 0;\n    this.pattern_enabled = true;\n    this.pattern_name = \"pattern\";\n\n}\n\nextend(Record, Rec_campaign_timeline_schedule);\nfunction Rec_campaign_timeline_sequence() {\n    Record.call(this);\n\n    this.campaign_timeline_sequence_id;\n    this.campaign_id = (-1);\n    this.campaign_timeline_id = (-1);\n    this.sequence_index;\n    this.sequence_count;\n\n}\n\nextend(Record, Rec_campaign_timeline_sequence);\nfunction Rec_catalog_item() {\n    Record.call(this);\n\n    this.catalog_item_id = (-1);\n    this.item_name = \"Item\";\n    this.ad_local_content_id = (-1);\n\n}\n\nextend(Record, Rec_catalog_item);\nfunction Rec_catalog_item_category() {\n    Record.call(this);\n\n    this.catalog_item_category_id = (-1);\n    this.catalog_item_id = (-1);\n    this.category_value_id = (-1);\n\n}\n\nextend(Record, Rec_catalog_item_category);\nfunction Rec_catalog_item_info() {\n    Record.call(this);\n\n    this.catalog_item_id = (-1);\n    this.info0 = \"\";\n    this.info1 = \"\";\n    this.info2 = \"\";\n    this.info3 = \"\";\n\n}\n\nextend(Record, Rec_catalog_item_info);\nfunction Rec_catalog_item_resource() {\n    Record.call(this);\n\n    this.catalog_item_resource_id = (-1);\n    this.catalog_item_id = (-1);\n    this.resource_id = (-1);\n    this.resource_group = 0;\n\n}\n\nextend(Record, Rec_catalog_item_resource);\nfunction Rec_category_value() {\n    Record.call(this);\n\n    this.category_value_id = (-1);\n    this.parent_category_value_id = (-1);\n    this.category_value = \"Category\";\n\n}\n\nextend(Record, Rec_category_value);\nfunction Rec_global_setting() {\n    Record.call(this);\n\n    this.param_id = (-1);\n    this.param_key = \"\";\n    this.param_value = \"\";\n\n}\n\nextend(Record, Rec_global_setting);\nfunction Rec_music_channel() {\n    Record.call(this);\n\n    this.music_channel_id;\n    this.music_channel_name = \"Channel\";\n    this.access_key = 0;\n    this.tree_path = \"\";\n\n}\n\nextend(Record, Rec_music_channel);\nfunction Rec_music_channel_song() {\n    Record.call(this);\n\n    this.music_channel_song_id;\n    this.music_channel_id = (-1);\n    this.resource_id = (-1);\n\n}\n\nextend(Record, Rec_music_channel_song);\nfunction Rec_player_data() {\n    Record.call(this);\n\n    this.player_data_id = (-1);\n    this.player_data_value;\n    this.player_data_public = false;\n    this.tree_path = \"\";\n    this.source_code;\n    this.access_key = 0;\n\n}\n\nextend(Record, Rec_player_data);\nfunction Rec_resource() {\n    Record.call(this);\n\n    this.resource_id = (-1);\n    this.resource_name = \"Resource\";\n    this.resource_type;\n    this.resource_pixel_width = 0;\n    this.resource_pixel_height = 0;\n    this.default_player;\n    this.snapshot;\n    this.resource_total_time = 0;\n    this.resource_date_created;\n    this.resource_date_modified;\n    this.resource_trust = false;\n    this.resource_public = false;\n    this.resource_bytes_total = 0;\n    this.resource_module = false;\n    this.tree_path = \"\";\n    this.access_key = 0;\n    this.resource_html = false;\n    this.shortcut = false;\n    this.shortcut_business_id = (-1);\n    this.shortcut_resource_id = (-1);\n}\n\nextend(Record, Rec_resource);\nfunction Rec_script() {\n    Record.call(this);\n\n    this.script_id = (-1);\n    this.script_src;\n\n}\n\nextend(Record, Rec_script);\nfunction Rec_station_ad() {\n    Record.call(this);\n\n    this.branch_station_id;\n    this.advertising_network;\n    this.advertising_description = \"\";\n    this.advertising_keys = \"\";\n    this.ad_rate_id;\n\n}\n\nextend(Record, Rec_station_ad);\n// RSA, a suite of routines for performing RSA public-key computations in\n// JavaScript.\n//\n// Requires BigInt.js and Barrett.js.\n//\n// Copyright 1998-2005 David Shapiro.\n//\n// You may use, re-use, abuse, copy, and modify this code to your liking, but\n// please keep this header.\n//\n// Thanks!\n//\n// Dave Shapiro\n// dave@ohdave.com\n\nfunction RSAKeyPair(encryptionExponent, decryptionExponent, modulus) {\n    this.e = biFromHex(encryptionExponent);\n    this.d = biFromHex(decryptionExponent);\n    this.m = biFromHex(modulus);\n    // We can do two bytes per digit, so\n    // chunkSize = 2 * (number of digits in modulus - 1).\n    // Since biHighIndex returns the high index, not the number of digits, 1 has\n    // already been subtracted.\n    this.chunkSize = 2 * biHighIndex(this.m);\n    this.radix = 16;\n    this.barrett = new BarrettMu(this.m);\n}\n\nfunction twoDigit(n) {\n    return (n < 10 ? \"0\" : \"\") + String(n);\n}\n\nfunction encryptedString(key, s)\n// Altered by Rob Saunders (rob@robsaunders.net). New routine pads the\n// string after it has been converted to an array. This fixes an\n// incompatibility with Flash MX's ActionScript.\n{\n    var a = new Array();\n    var sl = s.length;\n    var i = 0;\n    while (i < sl) {\n        a[i] = s.charCodeAt(i);\n        i++;\n    }\n\n    while (a.length % key.chunkSize != 0) {\n        a[i++] = 0;\n    }\n\n    var al = a.length;\n    var result = \"\";\n    var j, k, block;\n    for (i = 0; i < al; i += key.chunkSize) {\n        block = new BigInt();\n        j = 0;\n        for (k = i; k < i + key.chunkSize; ++j) {\n            block.digits[j] = a[k++];\n            block.digits[j] += a[k++] << 8;\n        }\n        var crypt = key.barrett.powMod(block, key.e);\n        var text = key.radix == 16 ? biToHex(crypt) : biToString(crypt, key.radix);\n        result += text + \" \";\n    }\n    return result.substring(0, result.length - 1); // Remove last space.\n}\n\nfunction decryptedString(key, s) {\n    var blocks = s.split(\" \");\n    var result = \"\";\n    var i, j, block;\n    for (i = 0; i < blocks.length; ++i) {\n        var bi;\n        if (key.radix == 16) {\n            bi = biFromHex(blocks[i]);\n        }\n        else {\n            bi = biFromString(blocks[i], key.radix);\n        }\n        block = key.barrett.powMod(bi, key.d);\n        for (j = 0; j <= biHighIndex(block); ++j) {\n            result += String.fromCharCode(block.digits[j] & 255,\n                block.digits[j] >> 8);\n        }\n    }\n    // Remove trailing null, if any.\n    if (result.charCodeAt(result.length - 1) == 0) {\n        result = result.substring(0, result.length - 1);\n    }\n    return result;\n}\n\n\nfunction Table(i_dataBaseManager) {\n    this.m_dataBaseManager = i_dataBaseManager;\n    this.m_name\n    this.m_fields;\n    this.m_fieldDefinitions = [];  // [fieldName] = FeildDefinition\n    this.m_primaryField;\n    this.m_Id2Handle = {};\n\n\n    this.m_originalRecords = new OrderedMap();\n    this.m_modifiedRecords = new OrderedMap();\n    this.m_deletedRecords = new OrderedMap();\n    this.m_conflictRecords = new OrderedMap();\n    this.m_newRecords = new OrderedMap();\n\n    this.m_lastHandle = 0;\n}\n\n\nTable.prototype.addData = function (i_xmlTable) {\n    var field;\n    var foriegn;\n    var value;\n    var foriegnTable;\n    var handle;\n    var pk;\n    var newRec;\n    var id;\n\n\n    for (var iRec = 0; iRec < i_xmlTable.childNodes.length; iRec++) {\n        var xmlRec = i_xmlTable.childNodes[iRec]\n\n\n        pk = true;\n        var i = 0;\n\n        for (var iData = 0; iData < xmlRec.childNodes.length; iData++) {\n            var data = xmlRec.childNodes[iData];\n\n            // case Dev add new field to DB bug application is old version.\n            if (i >= this.m_fields.length)\n                break;\n\n            field = this.m_fields[i].field;\n            foriegn = this.m_fields[i].foriegn;\n            value = data.textContent;\n\n            if (pk) {\n                pk = false;\n                id = value;\n\n                if (foriegn != null && foriegn != this.m_name) {\n                    foriegnTable = this.m_dataBaseManager.getTable(foriegn);\n                    handle = foriegnTable.getHandle(value);\n                }\n                else {\n                    handle = this.getHandle(value);\n                }\n                newRec = this.createRecord();\n                newRec[field] = handle\n                newRec.native_id = value;\n            }\n            else {\n                if (foriegn != null) {\n                    foriegnTable = this.m_dataBaseManager.getTable(foriegn);\n                    newRec[field] = (value != \"\") ? foriegnTable.getHandle(value) : -1;\n                }\n                else {    /*\n                 if (newRec[field] is Date)\n                 {\n                 var date:Date = new Date();\n                 newRec[field] = date;\n                 date.setTime( Date.parse(value) );\n                 }\n                 else if (newRec[field] is Boolean)\n                 {\n                 newRec[field] = (value==\"True\");\n                 }\n                 else   */\n                    {\n                        newRec[field] = value;\n                    }\n                }\n            }\n            i++;\n        }\n\n\n        var existRec = this.getRec(handle);\n        if (existRec == null) {\n            if (newRec.change_type != 3) {\n                this.m_originalRecords.add(handle, newRec);\n            }\n            else {\n                //trace(\"recored deleted\");\n            }\n        }\n        else {\n            if (newRec.changelist_id > existRec.changelist_id) {\n                if (newRec.change_type == 3) // new recode was deleted.\n                {\n                    if (existRec.status == 0) // wasn't changed.\n                    {\n                        this.m_originalRecords.remove(handle);\n                        this.m_modifiedRecords.remove(handle);\n                        this.m_deletedRecords.remove(handle);\n                    }\n                    else {\n                        existRec.conflict = true;\n                        newRec.conflict = true;\n                        this.m_conflictRecords.add(handle, newRec);\n                    }\n\n                }\n                else {\n                    if (existRec.status == 0) // wasn't changed.\n                    {\n                        this.m_originalRecords.add(handle, newRec);\n                    }\n                    else {\n                        existRec.conflict = true;\n                        newRec.conflict = true;\n                        this.m_conflictRecords.add(handle, newRec);\n                    }\n                }\n            }\n        }\n\n    }\n}\n\n\nTable.prototype.getHandle = function (i_id) {\n    var handle = this.m_Id2Handle[i_id];\n    if (handle == null) {\n        handle = this.m_lastHandle;\n        this.m_lastHandle++;\n        if (i_id != -1)\n            this.m_Id2Handle[i_id] = handle;\n    }\n    return handle;\n}\n\n\nTable.prototype.setRecordId = function (i_handle, i_id) {\n    this.m_Id2Handle[i_id] = i_handle;\n}\n\n\nTable.prototype.createRecord = function () {\n    return null;\n}\n\n\nTable.prototype.addRecord = function (i_record, i_handle) {\n    var handle = (i_handle == null) ? this.getHandle(-1) : i_handle;\n    this.m_newRecords.add(handle, i_record);\n    i_record.status = 2;\n    i_record[this.m_fields[0].field] = handle;\n}\n\nTable.prototype.getRec = function (i_handle) {\n    if (this.m_deletedRecords.getValue(i_handle) != null)\n        return this.m_deletedRecords.getValue(i_handle);\n    else if (this.m_newRecords.getValue(i_handle) != null)\n        return this.m_newRecords.getValue(i_handle);\n    else if (this.m_modifiedRecords.getValue(i_handle) != null)\n        return this.m_modifiedRecords.getValue(i_handle);\n    else if (this.m_originalRecords.getValue(i_handle) != null)\n        return this.m_originalRecords.getValue(i_handle);\n    return null;\n}\n\n\nTable.prototype.getAllPrimaryKeys = function () {\n    var primaryKeys = [];\n    this.m_originalRecords.concatinateKeys(primaryKeys);\n    this.m_newRecords.concatinateKeys(primaryKeys);\n    return primaryKeys;\n}\n\n\nTable.prototype.openForEdit = function (i_handel) {\n    if (this.m_deletedRecords.getValue(i_handel) != null) {\n        return false;\n    }\n    else if (this.m_newRecords.getValue(i_handel) != null || this.m_modifiedRecords.getValue(i_handel) != null) {\n        return true;\n    }\n    else if (this.m_originalRecords.getValue(i_handel) != null) {\n        var modifiedRecord = this.createRecord();\n        var record = this.m_originalRecords.getValue(i_handel);\n        for (var iField in this.m_fields) {\n            var field = this.m_fields[iField];\n            modifiedRecord[field.field] = record[field.field]\n        }\n        modifiedRecord.native_id = record.native_id;\n        modifiedRecord.status = 1;\n        this.m_modifiedRecords.add(i_handel, modifiedRecord);\n    }\n    else {\n        return false;\n    }\n    return true\n}\n\n\nTable.prototype.openForDelete = function (i_handel) {\n    this.m_newRecords.remove(i_handel);\n    this.m_modifiedRecords.remove(i_handel);\n    if (this.m_originalRecords.getValue(i_handel) != null) {\n        var record = this.getRec(i_handel);\n        record.status = 3;\n        this.m_deletedRecords.add(i_handel, this.m_originalRecords.getValue(i_handel));\n        this.m_originalRecords.remove(i_handel);\n    }\n    else {\n        return false;\n    }\n    return true;\n}\n\n\nTable.prototype.appendModifyAndNewChangelist = function (i_doc) {\n    self = this;\n    var xmlTable = i_doc.createElement(\"Table\");\n    xmlTable.setAttribute(\"name\", this.m_name);\n    var xmlChangelist = i_doc.firstChild;\n\n\n    var key;\n    var record;\n    var xmlRec;\n    var xmlCol;\n    var field;\n    var pk;\n    var foriegnTable;\n    var record2;\n    var value;\n    var date;\n    var modifyKeys = this.getModifyPrimaryKeys();\n\n\n    if (modifyKeys.length > 0) {\n        var xmlUpdate = i_doc.createElement(\"Update\");\n        xmlTable.appendChild(xmlUpdate);\n        for (var iKey in modifyKeys) {\n            key = modifyKeys[iKey];\n\n            xmlRec = i_doc.createElement(\"Rec\");\n            xmlUpdate.appendChild(xmlRec);\n            record = this.getRec(key);\n            var attName = this.m_fields[0].field;\n            xmlRec.setAttribute(attName, record[this.m_fields[0].field])\n\n\n            for (var iField in this.m_fields) {\n                field = this.m_fields[iField];\n\n                if (field.field == this.m_fields[0].field) // primary key\n                {\n                    value = record.native_id;\n                }\n                else if (field.foriegn != null) {\n                    xmlRec.setAttribute(field.field, record[field.field])\n                    foriegnTable = this.m_dataBaseManager.getTable(field.foriegn);\n                    if (record[field.field] != -1) {\n                        record2 = foriegnTable.getRec(record[field.field]);\n                        value = (record2 != null) ? record2.native_id : -1;\n                    }\n                    else {\n                        value = null;\n                    }\n                }\n                else {\n                    if ((this.m_name == \"player_data\" && field.field == \"player_data_value\") ||\n                        (this.m_name == \"campaign_timeline_chanel_players\" && field.field == \"player_data\") ||\n                        (this.m_name == \"campaign_channel_players\" && field.field == \"player_data\")) {\n                        xmlCol = i_doc.createElement(\"Col\");\n\n                        var xml = self.getPlayerDataIds(record[field.field]);\n                        xmlCol.appendChild(xml);\n\n                        xmlRec.appendChild(xmlCol);\n                        continue;\n                    }\n                    else {\n                        value = record[field.field];\n                    }\n                }\n                xmlCol = i_doc.createElement(\"Col\"); //<Col>{value}</Col>;\n                xmlCol.textContent = (value != null) ? value : \"null\";\n                xmlRec.appendChild(xmlCol);\n            }\n\n        }\n    }\n\n    var newKeys = this.getNewPrimaryKeys();\n    if (newKeys.length > 0) {\n        var xmlNew = i_doc.createElement(\"New\");\n        xmlTable.appendChild(xmlNew);\n\n        for (var iKey in newKeys) {\n            key = newKeys[iKey];\n            xmlRec = i_doc.createElement(\"Rec\");\n\n            xmlNew.appendChild(xmlRec);\n            record = this.getRec(key);\n\n            xmlRec.setAttribute(this.m_fields[0].field, record[this.m_fields[0].field]);\n\n\n            for (var iField in this.m_fields) {\n\n                field = this.m_fields[iField];\n\n                if (field.field == this.m_fields[0].field) // primary key\n                {\n                    value = record.native_id;\n                }\n\n                else if (field.foriegn != null) {\n                    xmlRec.setAttribute(field.field, record[field.field])\n                    foriegnTable = this.m_dataBaseManager.getTable(field.foriegn);\n                    if (record[field.field] != -1) {\n                        record2 = foriegnTable.getRec(record[field.field]);\n                        value = (record2 != null) ? record2.native_id : -1;\n                    }\n                    else {\n                        value = null;\n                    }\n                }\n\n                else {\n                    if ((this.m_name == \"player_data\" && field.field == \"player_data_value\") ||\n                        (this.m_name == \"campaign_timeline_chanel_players\" && field.field == \"player_data\") ||\n                        (this.m_name == \"campaign_channel_players\" && field.field == \"player_data\")) {\n                        xmlCol = i_doc.createElement(\"Col\");\n\n\n                        var xml = self.getPlayerDataIds(record[field.field]);\n                        xmlCol.appendChild(xml);\n\n                        xmlRec.appendChild(xmlCol);\n                        continue;\n                    }\n                    else {\n                        value = record[field.field];\n                    }\n                }\n\n\n                xmlCol = i_doc.createElement(\"Col\");\n                xmlCol.textContent = (value != null) ? value : \"null\";\n                xmlRec.appendChild(xmlCol);\n            }\n\n        }\n\n    }\n\n\n    if (modifyKeys.length > 0 || newKeys.length > 0) {\n        var xmlFlields = i_doc.createElement(\"Fields\");\n        xmlTable.appendChild(xmlFlields);\n        for (var iField in this.m_fields) {\n            field = this.m_fields[iField];\n            var xmlField = i_doc.createElement(\"Field\");\n            xmlField.textContent = field.field;\n            if (field.pk != null) {\n                xmlField.setAttribute(\"pk\", field.pk)\n            }\n            xmlFlields.appendChild(xmlField);\n        }\n    }\n\n    if (xmlTable.childNodes.length > 0) {\n        xmlChangelist.appendChild(xmlTable);\n\n    }\n\n}\n\n\nTable.prototype.appendDeletedChangelist = function (i_doc) {\n    var xmlTable = i_doc.createElement(\"Table\");\n    xmlTable.setAttribute(\"name\", this.m_name);\n    var xmlChangelist = i_doc.firstChild;\n\n    var key;\n    var record;\n    var xmlRec;\n    var xmlCol;\n    var field;\n    var pk;\n    var foriegnTable;\n    var record2;\n    var value;\n    var date;\n    var deletedKeys = this.getDeletedPrimaryKeys();\n    if (deletedKeys.length > 0) {\n        var xmlDelete = i_doc.createElement(\"Delete\");\n        xmlTable.appendChild(xmlDelete);\n        for (var iKey in deletedKeys) {\n            key = deletedKeys[iKey];\n            xmlRec = i_doc.createElement(\"Rec\");\n            xmlDelete.appendChild(xmlRec);\n            record = this.getRec(key);\n            xmlRec.setAttribute(\"pk\", record.native_id);\n        }\n    }\n\n    if (deletedKeys.length > 0) {\n        var xmlFlields = i_doc.createElement(\"Fields\");\n        xmlTable.appendChild(xmlFlields);\n        for (var iField in this.m_fields) {\n            var field = this.m_fields[iField];\n            var xmlField = i_doc.createElement(\"Field\");\n            xmlField.textContent = field.field;\n            xmlFlields.appendChild(xmlField);\n        }\n    }\n\n    if (xmlTable.childNodes.length > 0) {\n        xmlChangelist.appendChild(xmlTable);\n    }\n\n}\n\n\nTable.prototype.getPlayerDataIds = function (i_playerData) {\n    var doc = jQuery.parseXML(i_playerData);\n    this.convertToIds(doc);\n    return doc.documentElement;\n}\n\n\nTable.prototype.convertToIds = function (i_docPlayerData) {\n    var self = this;\n    var elements = i_docPlayerData.getElementsByTagName(\"Resource\");\n    for (var iResource = 0; iResource < elements.length; iResource++) {\n        var xmlResource = elements[iResource];\n        var hResource = xmlResource.getAttribute(\"hResource\");\n        if (hResource != null && hResource != \"\") {\n            var record2 = this.m_dataBaseManager.table_resources().getRec(hResource);\n            if (record2 != null) {\n                xmlResource.setAttribute(\"resource\", record2.native_id);\n            }\n        }\n    }\n\n    //??? self.createPlayId(i_docPlayerData);\n    var playerList = i_docPlayerData.getElementsByTagName(\"Player\");\n    for (var i = 0; i < playerList.length; i++) {\n        var xmlPlayer = playerList[i];\n        self.createPlayId(xmlPlayer);\n    }\n\n\n    var categoryList = i_docPlayerData.getElementsByTagName(\"Category\");\n    for (var i = 0; i < categoryList.length; i++) {\n        var xmlCategory = categoryList[i];\n        var hCategory = xmlCategory.getAttribute(\"handle\");\n        if (hCategory != null && hCategory != -1) {\n            var recCategoryValue = m_dataBaseManager.table_category_values.getRec(hCategory);\n            xmlCategory.setAttribute(\"id\", recCategoryValue.native_id);\n        }\n    }\n}\n\nTable.prototype.createPlayId = function (i_xmlPlayer) {\n    var self2 = this;\n    var hDataSrc = i_xmlPlayer.getAttribute('hDataSrc');\n    if (hDataSrc != null && hDataSrc != -1) {\n        var record2 = self2.m_dataBaseManager.table_player_data().getRec(hDataSrc);\n        i_xmlPlayer.setAttribute(\"src\", (record2 != null) ? record2.native_id : -1);\n    }\n}\n\n\nTable.prototype.getNewPrimaryKeys = function () {\n    var primaryKeys = [];\n    this.m_newRecords.concatinateKeys(primaryKeys);\n    return primaryKeys;\n}\n\nTable.prototype.getModifyPrimaryKeys = function () {\n    var primaryKeys = [];\n    this.m_modifiedRecords.concatinateKeys(primaryKeys);\n    return primaryKeys;\n}\n\nTable.prototype.getDeletedPrimaryKeys = function () {\n    var primaryKeys = [];\n    this.m_deletedRecords.concatinateKeys(primaryKeys);\n    return primaryKeys;\n}\n\nTable.prototype.getConflictPrimaryKeys = function () {\n    var primaryKeys = [];\n    this.m_conflictRecords.concatinateKeys(primaryKeys);\n    return primaryKeys;\n}\n\n\nTable.prototype.commitChanges = function (i_changelistId) {\n    var iHandle;\n    var handle;\n    var record;\n    var newKeys = this.getNewPrimaryKeys();\n    for (iHandle in newKeys) {\n        handle = newKeys[iHandle];\n        record = this.m_newRecords.getValue(handle);\n        record.status = 0;\n        record.change_type = 2;\n        record.changelist_id = i_changelistId;\n        this.m_originalRecords.add(handle, record);\n        this.m_newRecords.remove(handle);\n    }\n\n    var modifyKeys = this.getModifyPrimaryKeys();\n    for (iHandle in modifyKeys) {\n        handle = modifyKeys[iHandle];\n        record = this.m_modifiedRecords.getValue(handle);\n        record.status = 0;\n        record.change_type = 1;\n        record.changelist_id = i_changelistId;\n        this.m_originalRecords.add(handle, record);\n        this.m_modifiedRecords.remove(handle);\n    }\n\n    var deletedKeys = this.getDeletedPrimaryKeys();\n    for (iHandle in deletedKeys) {\n        handle = deletedKeys[iHandle];\n        record = this.m_deletedRecords.getValue(handle);\n        if (record != null && record.native_id != -1) {\n            delete this.m_Id2Handle[record.native_id];\n        }\n        this.m_deletedRecords.remove(handle);\n        this.m_originalRecords.remove(handle); // (??? check if do need for this line)\n    }\n}\n\n\nfunction Table_ad_in_domains(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_in_domains\"\n    this.m_fields = [{field: \"ad_in_domain_id\", foriegn: \"ad_in_domains\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_out_domain\"}\n        , {field: \"accept_new_business\"}];\n}\n\nextend(Table, Table_ad_in_domains);\n\nTable_ad_in_domains.prototype.createRecord = function () {\n    return new Rec_ad_in_domain;\n}\n\nfunction Table_ad_in_domain_businesses(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_in_domain_businesses\"\n    this.m_fields = [{field: \"ad_in_domain_business_id\", foriegn: \"ad_in_domain_businesses\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_in_domain_id\", foriegn: \"ad_in_domains\", isNullAble: false}\n        , {field: \"ad_out_business_id\"}\n        , {field: \"accept_new_package\"}];\n}\n\nextend(Table, Table_ad_in_domain_businesses);\n\nTable_ad_in_domain_businesses.prototype.createRecord = function () {\n    return new Rec_ad_in_domain_business;\n}\n\nfunction Table_ad_in_domain_business_packages(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_in_domain_business_packages\"\n    this.m_fields = [{\n        field: \"ad_in_domain_business_package_id\",\n        foriegn: \"ad_in_domain_business_packages\",\n        isNullAble: false\n    }\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_in_domain_business_id\", foriegn: \"ad_in_domain_businesses\", isNullAble: false}\n        , {field: \"ad_package_id\"}\n        , {field: \"accept_new_station\"}\n        , {field: \"suspend_modified_package_date\"}\n        , {field: \"suspend_modified_content\"}];\n}\n\nextend(Table, Table_ad_in_domain_business_packages);\n\nTable_ad_in_domain_business_packages.prototype.createRecord = function () {\n    return new Rec_ad_in_domain_business_package;\n}\n\nfunction Table_ad_in_domain_business_package_stations(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_in_domain_business_package_stations\"\n    this.m_fields = [{field: \"ad_in_domain_business_package_station_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_in_domain_business_package_id\", foriegn: \"ad_in_domain_business_packages\", isNullAble: false}\n        , {field: \"ad_package_station_id\"}\n        , {field: \"accept_status\"}\n        , {field: \"suspend_modified_station\"}];\n}\n\nextend(Table, Table_ad_in_domain_business_package_stations);\n\nTable_ad_in_domain_business_package_stations.prototype.createRecord = function () {\n    return new Rec_ad_in_domain_business_package_station;\n}\n\nfunction Table_ad_local_contents(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_local_contents\"\n    this.m_fields = [{field: \"ad_local_content_id\", foriegn: \"ad_local_contents\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_local_package_id\", foriegn: \"ad_local_packages\", isNullAble: false}\n        , {field: \"enabled\"}\n        , {field: \"content_name\"}];\n}\n\nextend(Table, Table_ad_local_contents);\n\nTable_ad_local_contents.prototype.createRecord = function () {\n    return new Rec_ad_local_content;\n}\n\nfunction Table_ad_local_packages(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_local_packages\"\n    this.m_fields = [{field: \"ad_local_package_id\", foriegn: \"ad_local_packages\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"enabled\"}\n        , {field: \"package_name\"}\n        , {field: \"use_date_range\"}\n        , {field: \"start_date\"}\n        , {field: \"end_date\"}];\n}\n\nextend(Table, Table_ad_local_packages);\n\nTable_ad_local_packages.prototype.createRecord = function () {\n    return new Rec_ad_local_package;\n}\n\nfunction Table_ad_out_packages(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_out_packages\"\n    this.m_fields = [{field: \"ad_out_package_id\", foriegn: \"ad_out_packages\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"package_name\"}\n        , {field: \"start_date\"}\n        , {field: \"end_date\"}];\n}\n\nextend(Table, Table_ad_out_packages);\n\nTable_ad_out_packages.prototype.createRecord = function () {\n    return new Rec_ad_out_package;\n}\n\nfunction Table_ad_out_package_contents(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_out_package_contents\"\n    this.m_fields = [{field: \"ad_out_package_content_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_out_package_id\", foriegn: \"ad_out_packages\", isNullAble: false}\n        , {field: \"resource_id\", foriegn: \"resources\", isNullAble: true}\n        , {field: \"player_data_id\", foriegn: \"player_data\", isNullAble: true}\n        , {field: \"duration\"}\n        , {field: \"reparations_per_hour\"}];\n}\n\nextend(Table, Table_ad_out_package_contents);\n\nTable_ad_out_package_contents.prototype.createRecord = function () {\n    return new Rec_ad_out_package_content;\n}\n\nfunction Table_ad_out_package_stations(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_out_package_stations\"\n    this.m_fields = [{field: \"ad_out_package_station_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_out_package_id\", foriegn: \"ad_out_packages\", isNullAble: false}\n        , {field: \"ad_out_subdomain\"}\n        , {field: \"ad_out_business_id\"}\n        , {field: \"ad_out_station_id\"}\n        , {field: \"days_mask\"}\n        , {field: \"hour_start\"}\n        , {field: \"hour_end\"}];\n}\n\nextend(Table, Table_ad_out_package_stations);\n\nTable_ad_out_package_stations.prototype.createRecord = function () {\n    return new Rec_ad_out_package_station;\n}\n\nfunction Table_ad_rates(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"ad_rates\"\n    this.m_fields = [{field: \"ad_rate_id\", foriegn: \"ad_rates\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"ad_rate_name\"}\n        , {field: \"ad_rate_map\"}\n        , {field: \"hour_rate0\"}\n        , {field: \"hour_rate1\"}\n        , {field: \"hour_rate2\"}\n        , {field: \"hour_rate3\"}];\n}\n\nextend(Table, Table_ad_rates);\n\nTable_ad_rates.prototype.createRecord = function () {\n    return new Rec_ad_rate;\n}\n\nfunction Table_boards(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"boards\"\n    this.m_fields = [{field: \"board_id\", foriegn: \"boards\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"board_name\"}\n        , {field: \"board_pixel_width\"}\n        , {field: \"board_pixel_height\"}\n        , {field: \"monitor_orientation_enabled\"}\n        , {field: \"monitor_orientation_index\"}\n        , {field: \"access_key\"}\n        , {field: \"tree_path\"}];\n}\n\nextend(Table, Table_boards);\n\nTable_boards.prototype.createRecord = function () {\n    return new Rec_board;\n}\n\nfunction Table_board_templates(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"board_templates\"\n    this.m_fields = [{field: \"board_template_id\", foriegn: \"board_templates\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"board_id\", foriegn: \"boards\", isNullAble: false}\n        , {field: \"template_name\"}];\n}\n\nextend(Table, Table_board_templates);\n\nTable_board_templates.prototype.createRecord = function () {\n    return new Rec_board_template;\n}\n\nfunction Table_board_template_viewers(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"board_template_viewers\"\n    this.m_fields = [{field: \"board_template_viewer_id\", foriegn: \"board_template_viewers\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"board_template_id\", foriegn: \"board_templates\", isNullAble: false}\n        , {field: \"viewer_name\"}\n        , {field: \"pixel_x\"}\n        , {field: \"pixel_y\"}\n        , {field: \"pixel_width\"}\n        , {field: \"pixel_height\"}\n        , {field: \"enable_gaps\"}\n        , {field: \"viewer_order\"}\n        , {field: \"locked\"}];\n}\n\nextend(Table, Table_board_template_viewers);\n\nTable_board_template_viewers.prototype.createRecord = function () {\n    return new Rec_board_template_viewer;\n}\n\nfunction Table_branch_stations(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"branch_stations\"\n    this.m_fields = [{field: \"branch_station_id\", foriegn: \"branch_stations\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"branch_id\"}\n        , {field: \"campaign_board_id\", foriegn: \"campaign_boards\", isNullAble: true}\n        , {field: \"station_name\"}\n        , {field: \"reboot_exceed_mem_enabled\"}\n        , {field: \"reboot_exceed_mem_value\"}\n        , {field: \"reboot_time_enabled\"}\n        , {field: \"reboot_time_value\"}\n        , {field: \"reboot_error_enabled\"}\n        , {field: \"monitor_standby_enabled\"}\n        , {field: \"monitor_standby_from\"}\n        , {field: \"monitor_standby_to\"}\n        , {field: \"location_address\"}\n        , {field: \"location_long\"}\n        , {field: \"location_lat\"}\n        , {field: \"map_type\"}\n        , {field: \"map_zoom\"}\n        , {field: \"station_selected\"}\n        , {field: \"advertising_description\"}\n        , {field: \"advertising_keys\"}\n        , {field: \"reboot_exceed_mem_action\"}\n        , {field: \"reboot_time_action\"}\n        , {field: \"reboot_error_action\"}\n        , {field: \"station_mode\"}\n        , {field: \"power_mode\"}\n        , {field: \"power_on_day1\"}\n        , {field: \"power_off_day1\"}\n        , {field: \"power_on_day2\"}\n        , {field: \"power_off_day2\"}\n        , {field: \"power_on_day3\"}\n        , {field: \"power_off_day3\"}\n        , {field: \"power_on_day4\"}\n        , {field: \"power_off_day4\"}\n        , {field: \"power_on_day5\"}\n        , {field: \"power_off_day5\"}\n        , {field: \"power_on_day6\"}\n        , {field: \"power_off_day6\"}\n        , {field: \"power_on_day7\"}\n        , {field: \"power_off_day7\"}\n        , {field: \"send_notification\"}\n        , {field: \"frame_rate\"}\n        , {field: \"quality\"}\n        , {field: \"transition_enabled\"}\n        , {field: \"zwave_config\"}\n        , {field: \"lan_server_enabled\"}\n        , {field: \"lan_server_ip\"}\n        , {field: \"lan_server_port\"}];\n}\n\nextend(Table, Table_branch_stations);\n\nTable_branch_stations.prototype.createRecord = function () {\n    return new Rec_branch_station;\n}\n\nfunction Table_campaigns(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaigns\"\n    this.m_fields = [{field: \"campaign_id\", foriegn: \"campaigns\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_name\"}\n        , {field: \"campaign_playlist_mode\"}\n        , {field: \"kiosk_mode\"}\n        , {field: \"kiosk_key\"}\n        , {field: \"kiosk_timeline_id\"}\n        , {field: \"kiosk_wait_time\"}\n        , {field: \"mouse_interrupt_mode\"}\n        , {field: \"tree_path\"}\n        , {field: \"access_key\"}];\n}\n\nextend(Table, Table_campaigns);\n\nTable_campaigns.prototype.createRecord = function () {\n    return new Rec_campaign;\n}\n\nfunction Table_campaign_boards(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_boards\"\n    this.m_fields = [{field: \"campaign_board_id\", foriegn: \"campaign_boards\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"board_id\", foriegn: \"boards\", isNullAble: false}\n        , {field: \"campaign_id\", foriegn: \"campaigns\", isNullAble: false}\n        , {field: \"campaign_board_name\"}\n        , {field: \"allow_public_view\"}\n        , {field: \"admin_public_view\"}];\n}\n\nextend(Table, Table_campaign_boards);\n\nTable_campaign_boards.prototype.createRecord = function () {\n    return new Rec_campaign_board;\n}\n\nfunction Table_campaign_channels(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_channels\"\n    this.m_fields = [{field: \"campaign_channel_id\", foriegn: \"campaign_channels\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_id\", foriegn: \"campaigns\", isNullAble: false}\n        , {field: \"chanel_name\"}\n        , {field: \"chanel_color\"}\n        , {field: \"random_order\"}\n        , {field: \"repeat_to_fit\"}\n        , {field: \"fixed_players_length\"}];\n}\n\nextend(Table, Table_campaign_channels);\n\nTable_campaign_channels.prototype.createRecord = function () {\n    return new Rec_campaign_channel;\n}\n\nfunction Table_campaign_channel_players(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_channel_players\"\n    this.m_fields = [{field: \"campaign_channel_player_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_channel_id\", foriegn: \"campaign_channels\", isNullAble: false}\n        , {field: \"player_offset_time\"}\n        , {field: \"player_duration\"}\n        , {field: \"player_data\"}\n        , {field: \"mouse_children\"}\n        , {field: \"ad_local_content_id\", foriegn: \"ad_local_contents\", isNullAble: true}];\n}\n\nextend(Table, Table_campaign_channel_players);\n\nTable_campaign_channel_players.prototype.createRecord = function () {\n    return new Rec_campaign_channel_player;\n}\n\nfunction Table_campaign_events(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_events\"\n    this.m_fields = [{field: \"campaign_event_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_id\", foriegn: \"campaigns\", isNullAble: true}\n        , {field: \"sender_name\"}\n        , {field: \"event_name\"}\n        , {field: \"event_condition\"}\n        , {field: \"command_name\"}\n        , {field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: true}\n        , {field: \"command_params\"}];\n}\n\nextend(Table, Table_campaign_events);\n\nTable_campaign_events.prototype.createRecord = function () {\n    return new Rec_campaign_event;\n}\n\nfunction Table_campaign_timelines(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timelines\"\n    this.m_fields = [{field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_id\", foriegn: \"campaigns\", isNullAble: false}\n        , {field: \"timeline_name\"}\n        , {field: \"timeline_duration\"}];\n}\n\nextend(Table, Table_campaign_timelines);\n\nTable_campaign_timelines.prototype.createRecord = function () {\n    return new Rec_campaign_timeline;\n}\n\nfunction Table_campaign_timeline_board_templates(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_board_templates\"\n    this.m_fields = [{\n        field: \"campaign_timeline_board_template_id\",\n        foriegn: \"campaign_timeline_board_templates\",\n        isNullAble: false\n    }\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: false}\n        , {field: \"board_template_id\", foriegn: \"board_templates\", isNullAble: false}\n        , {field: \"campaign_board_id\", foriegn: \"campaign_boards\", isNullAble: false}\n        , {field: \"template_offset_time\"}\n        , {field: \"template_duration\"}];\n}\n\nextend(Table, Table_campaign_timeline_board_templates);\n\nTable_campaign_timeline_board_templates.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_board_template;\n}\n\nfunction Table_campaign_timeline_board_viewer_chanels(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_board_viewer_chanels\"\n    this.m_fields = [{field: \"campaign_timeline_board_viewer_chanel_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {\n            field: \"campaign_timeline_board_template_id\",\n            foriegn: \"campaign_timeline_board_templates\",\n            isNullAble: false\n        }\n        , {field: \"board_template_viewer_id\", foriegn: \"board_template_viewers\", isNullAble: false}\n        , {field: \"campaign_timeline_chanel_id\", foriegn: \"campaign_timeline_chanels\", isNullAble: false}];\n}\n\nextend(Table, Table_campaign_timeline_board_viewer_chanels);\n\nTable_campaign_timeline_board_viewer_chanels.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_board_viewer_chanel;\n}\n\nfunction Table_campaign_timeline_board_viewer_channels(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_board_viewer_channels\"\n    this.m_fields = [{field: \"campaign_timeline_board_viewer_channel_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {\n            field: \"campaign_timeline_board_template_id\",\n            foriegn: \"campaign_timeline_board_templates\",\n            isNullAble: false\n        }\n        , {field: \"board_template_viewer_id\", foriegn: \"board_template_viewers\", isNullAble: false}\n        , {field: \"campaign_channel_id\", foriegn: \"campaign_channels\", isNullAble: false}];\n}\n\nextend(Table, Table_campaign_timeline_board_viewer_channels);\n\nTable_campaign_timeline_board_viewer_channels.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_board_viewer_channel;\n}\n\nfunction Table_campaign_timeline_chanels(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_chanels\"\n    this.m_fields = [{field: \"campaign_timeline_chanel_id\", foriegn: \"campaign_timeline_chanels\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: false}\n        , {field: \"chanel_name\"}\n        , {field: \"chanel_color\"}\n        , {field: \"random_order\"}\n        , {field: \"repeat_to_fit\"}\n        , {field: \"fixed_players_length\"}];\n}\n\nextend(Table, Table_campaign_timeline_chanels);\n\nTable_campaign_timeline_chanels.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_chanel;\n}\n\nfunction Table_campaign_timeline_chanel_players(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_chanel_players\"\n    this.m_fields = [{field: \"campaign_timeline_chanel_player_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_timeline_chanel_id\", foriegn: \"campaign_timeline_chanels\", isNullAble: false}\n        , {field: \"player_offset_time\"}\n        , {field: \"player_duration\"}\n        , {field: \"player_id\"}\n        , {field: \"player_editor_id\"}\n        , {field: \"player_data\"}\n        , {field: \"mouse_children\"}\n        , {field: \"ad_local_content_id\", foriegn: \"ad_local_contents\", isNullAble: true}];\n}\n\nextend(Table, Table_campaign_timeline_chanel_players);\n\nTable_campaign_timeline_chanel_players.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_chanel_player;\n}\n\nfunction Table_campaign_timeline_channels(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_channels\"\n    this.m_fields = [{field: \"campaign_timeline_channel_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: false}];\n}\n\nextend(Table, Table_campaign_timeline_channels);\n\nTable_campaign_timeline_channels.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_channel;\n}\n\nfunction Table_campaign_timeline_schedules(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_schedules\"\n    this.m_fields = [{field: \"campaign_timeline_schedule_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: false}\n        , {field: \"priorty\"}\n        , {field: \"start_date\"}\n        , {field: \"end_date\"}\n        , {field: \"repeat_type\"}\n        , {field: \"week_days\"}\n        , {field: \"custom_duration\"}\n        , {field: \"duration\"}\n        , {field: \"start_time\"}\n        , {field: \"pattern_enabled\"}\n        , {field: \"pattern_name\"}];\n}\n\nextend(Table, Table_campaign_timeline_schedules);\n\nTable_campaign_timeline_schedules.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_schedule;\n}\n\nfunction Table_campaign_timeline_sequences(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"campaign_timeline_sequences\"\n    this.m_fields = [{field: \"campaign_timeline_sequence_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"campaign_id\", foriegn: \"campaigns\", isNullAble: false}\n        , {field: \"campaign_timeline_id\", foriegn: \"campaign_timelines\", isNullAble: false}\n        , {field: \"sequence_index\"}\n        , {field: \"sequence_count\"}];\n}\n\nextend(Table, Table_campaign_timeline_sequences);\n\nTable_campaign_timeline_sequences.prototype.createRecord = function () {\n    return new Rec_campaign_timeline_sequence;\n}\n\nfunction Table_catalog_items(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"catalog_items\"\n    this.m_fields = [{field: \"catalog_item_id\", foriegn: \"catalog_items\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"item_name\"}\n        , {field: \"ad_local_content_id\", foriegn: \"ad_local_contents\", isNullAble: true}];\n}\n\nextend(Table, Table_catalog_items);\n\nTable_catalog_items.prototype.createRecord = function () {\n    return new Rec_catalog_item;\n}\n\nfunction Table_catalog_item_categories(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"catalog_item_categories\"\n    this.m_fields = [{field: \"catalog_item_category_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"catalog_item_id\", foriegn: \"catalog_items\", isNullAble: false}\n        , {field: \"category_value_id\", foriegn: \"category_values\", isNullAble: false}];\n}\n\nextend(Table, Table_catalog_item_categories);\n\nTable_catalog_item_categories.prototype.createRecord = function () {\n    return new Rec_catalog_item_category;\n}\n\nfunction Table_catalog_item_infos(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"catalog_item_infos\"\n    this.m_fields = [{field: \"catalog_item_id\", foriegn: \"catalog_items\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"info0\"}\n        , {field: \"info1\"}\n        , {field: \"info2\"}\n        , {field: \"info3\"}];\n}\n\nextend(Table, Table_catalog_item_infos);\n\nTable_catalog_item_infos.prototype.createRecord = function () {\n    return new Rec_catalog_item_info;\n}\n\nfunction Table_catalog_item_resources(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"catalog_item_resources\"\n    this.m_fields = [{field: \"catalog_item_resource_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"catalog_item_id\", foriegn: \"catalog_items\", isNullAble: false}\n        , {field: \"resource_id\", foriegn: \"resources\", isNullAble: false}\n        , {field: \"resource_group\"}];\n}\n\nextend(Table, Table_catalog_item_resources);\n\nTable_catalog_item_resources.prototype.createRecord = function () {\n    return new Rec_catalog_item_resource;\n}\n\nfunction Table_category_values(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"category_values\"\n    this.m_fields = [{field: \"category_value_id\", foriegn: \"category_values\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"parent_category_value_id\"}\n        , {field: \"category_value\"}];\n}\n\nextend(Table, Table_category_values);\n\nTable_category_values.prototype.createRecord = function () {\n    return new Rec_category_value;\n}\n\nfunction Table_global_settings(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"global_settings\"\n    this.m_fields = [{field: \"param_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"param_key\"}\n        , {field: \"param_value\"}];\n}\n\nextend(Table, Table_global_settings);\n\nTable_global_settings.prototype.createRecord = function () {\n    return new Rec_global_setting;\n}\n\nfunction Table_music_channels(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"music_channels\"\n    this.m_fields = [{field: \"music_channel_id\", foriegn: \"music_channels\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"music_channel_name\"}\n        , {field: \"access_key\"}\n        , {field: \"tree_path\"}];\n}\n\nextend(Table, Table_music_channels);\n\nTable_music_channels.prototype.createRecord = function () {\n    return new Rec_music_channel;\n}\n\nfunction Table_music_channel_songs(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"music_channel_songs\"\n    this.m_fields = [{field: \"music_channel_song_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"music_channel_id\", foriegn: \"music_channels\", isNullAble: false}\n        , {field: \"resource_id\", foriegn: \"resources\", isNullAble: false}];\n}\n\nextend(Table, Table_music_channel_songs);\n\nTable_music_channel_songs.prototype.createRecord = function () {\n    return new Rec_music_channel_song;\n}\n\nfunction Table_player_data(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"player_data\"\n    this.m_fields = [{field: \"player_data_id\", foriegn: \"player_data\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"player_data_value\"}\n        , {field: \"player_data_public\"}\n        , {field: \"tree_path\"}\n        , {field: \"source_code\"}\n        , {field: \"access_key\"}];\n}\n\nextend(Table, Table_player_data);\n\nTable_player_data.prototype.createRecord = function () {\n    return new Rec_player_data;\n}\n\nfunction Table_resources(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"resources\"\n    this.m_fields = [{field: \"resource_id\", foriegn: \"resources\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"resource_name\"}\n        , {field: \"resource_type\"}\n        , {field: \"resource_pixel_width\"}\n        , {field: \"resource_pixel_height\"}\n        , {field: \"default_player\"}\n        , {field: \"snapshot\"}\n        , {field: \"resource_total_time\"}\n        , {field: \"resource_date_created\"}\n        , {field: \"resource_date_modified\"}\n        , {field: \"resource_trust\"}\n        , {field: \"resource_public\"}\n        , {field: \"resource_bytes_total\"}\n        , {field: \"resource_module\"}\n        , {field: \"tree_path\"}\n        , {field: \"access_key\"}\n        , {field: \"resource_html\"}\n        , {field: \"shortcut\"}\n        , {field: \"shortcut_business_id\"}\n        , {field: \"shortcut_resource_id\"}];\n}\n\nextend(Table, Table_resources);\n\nTable_resources.prototype.createRecord = function () {\n    return new Rec_resource;\n}\n\nfunction Table_scripts(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"scripts\"\n    this.m_fields = [{field: \"script_id\"}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"script_src\"}];\n}\n\nextend(Table, Table_scripts);\n\nTable_scripts.prototype.createRecord = function () {\n    return new Rec_script;\n}\n\nfunction Table_station_ads(i_database) {\n    Table.call(this, i_database);\n    this.m_name = \"station_ads\"\n    this.m_fields = [{field: \"branch_station_id\", foriegn: \"branch_stations\", isNullAble: false}\n        , {field: \"changelist_id\"}\n        , {field: \"change_type\"}\n        , {field: \"advertising_network\"}\n        , {field: \"advertising_description\"}\n        , {field: \"advertising_keys\"}\n        , {field: \"ad_rate_id\", foriegn: \"ad_rates\", isNullAble: true}];\n}\n\nextend(Table, Table_station_ads);\n\nTable_station_ads.prototype.createRecord = function () {\n    return new Rec_station_ad;\n}\n\nfunction surrogateCtor() {\n}\n\nfunction extend(base, sub) {\n    // Copy the prototype from the base to setup inheritance\n    surrogateCtor.prototype = base.prototype;\n    // Tricky huh?\n    sub.prototype = new surrogateCtor();\n    // Remember the constructor property was set wrong, let's fix it\n    sub.prototype.constructor = sub;\n}\n/*\tThis work is licensed under Creative Commons GNU LGPL License.\n\n License: http://creativecommons.org/licenses/LGPL/2.1/\n Version: 0.9\n Author:  Stefan Goessner/2006\n Web:     http://goessner.net/\n */\nfunction xml2json(xml, tab) {\n    var X = {\n        toObj: function (xml) {\n            var o = {};\n            if (xml.nodeType == 1) {   // element node ..\n                if (xml.attributes.length)   // element with attributes  ..\n                    for (var i = 0; i < xml.attributes.length; i++)\n                        o[\"@\" + xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue || \"\").toString();\n                if (xml.firstChild) { // element has child nodes ..\n                    var textChild = 0, cdataChild = 0, hasElementChild = false;\n                    for (var n = xml.firstChild; n; n = n.nextSibling) {\n                        if (n.nodeType == 1) hasElementChild = true;\n                        else if (n.nodeType == 3 && n.nodeValue.match(/[^ \\f\\n\\r\\t\\v]/)) textChild++; // non-whitespace text\n                        else if (n.nodeType == 4) cdataChild++; // cdata section node\n                    }\n                    if (hasElementChild) {\n                        if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..\n                            X.removeWhite(xml);\n                            for (var n = xml.firstChild; n; n = n.nextSibling) {\n                                if (n.nodeType == 3)  // text node\n                                    o[\"#text\"] = X.escape(n.nodeValue);\n                                else if (n.nodeType == 4)  // cdata node\n                                    o[\"#cdata\"] = X.escape(n.nodeValue);\n                                else if (o[n.nodeName]) {  // multiple occurence of element ..\n                                    if (o[n.nodeName] instanceof Array)\n                                        o[n.nodeName][o[n.nodeName].length] = X.toObj(n);\n                                    else\n                                        o[n.nodeName] = [o[n.nodeName], X.toObj(n)];\n                                }\n                                else  // first occurence of element..\n                                    o[n.nodeName] = X.toObj(n);\n                            }\n                        }\n                        else { // mixed content\n                            if (!xml.attributes.length)\n                                o = X.escape(X.innerXml(xml));\n                            else\n                                o[\"#text\"] = X.escape(X.innerXml(xml));\n                        }\n                    }\n                    else if (textChild) { // pure text\n                        if (!xml.attributes.length)\n                            o = X.escape(X.innerXml(xml));\n                        else\n                            o[\"#text\"] = X.escape(X.innerXml(xml));\n                    }\n                    else if (cdataChild) { // cdata\n                        if (cdataChild > 1)\n                            o = X.escape(X.innerXml(xml));\n                        else\n                            for (var n = xml.firstChild; n; n = n.nextSibling)\n                                o[\"#cdata\"] = X.escape(n.nodeValue);\n                    }\n                }\n                if (!xml.attributes.length && !xml.firstChild) o = null;\n            }\n            else if (xml.nodeType == 9) { // document.node\n                o = X.toObj(xml.documentElement);\n            }\n            else\n                alert(\"unhandled node type: \" + xml.nodeType);\n            return o;\n        },\n        toJson: function (o, name, ind) {\n            var json = name ? (\"\\\"\" + name + \"\\\"\") : \"\";\n            if (o instanceof Array) {\n                for (var i = 0, n = o.length; i < n; i++)\n                    o[i] = X.toJson(o[i], \"\", ind + \"\\t\");\n                json += (name ? \":[\" : \"[\") + (o.length > 1 ? (\"\\n\" + ind + \"\\t\" + o.join(\",\\n\" + ind + \"\\t\") + \"\\n\" + ind) : o.join(\"\")) + \"]\";\n            }\n            else if (o == null)\n                json += (name && \":\") + \"null\";\n            else if (typeof(o) == \"object\") {\n                var arr = [];\n                for (var m in o)\n                    arr[arr.length] = X.toJson(o[m], m, ind + \"\\t\");\n                json += (name ? \":{\" : \"{\") + (arr.length > 1 ? (\"\\n\" + ind + \"\\t\" + arr.join(\",\\n\" + ind + \"\\t\") + \"\\n\" + ind) : arr.join(\"\")) + \"}\";\n            }\n            else if (typeof(o) == \"string\")\n                json += (name && \":\") + \"\\\"\" + o.toString() + \"\\\"\";\n            else\n                json += (name && \":\") + o.toString();\n            return json;\n        },\n        innerXml: function (node) {\n            var s = \"\"\n            if (\"innerHTML\" in node)\n                s = node.innerHTML;\n            else {\n                var asXml = function (n) {\n                    var s = \"\";\n                    if (n.nodeType == 1) {\n                        s += \"<\" + n.nodeName;\n                        for (var i = 0; i < n.attributes.length; i++)\n                            s += \" \" + n.attributes[i].nodeName + \"=\\\"\" + (n.attributes[i].nodeValue || \"\").toString() + \"\\\"\";\n                        if (n.firstChild) {\n                            s += \">\";\n                            for (var c = n.firstChild; c; c = c.nextSibling)\n                                s += asXml(c);\n                            s += \"</\" + n.nodeName + \">\";\n                        }\n                        else\n                            s += \"/>\";\n                    }\n                    else if (n.nodeType == 3)\n                        s += n.nodeValue;\n                    else if (n.nodeType == 4)\n                        s += \"<![CDATA[\" + n.nodeValue + \"]]>\";\n                    return s;\n                };\n                for (var c = node.firstChild; c; c = c.nextSibling)\n                    s += asXml(c);\n            }\n            return s;\n        },\n        escape: function (txt) {\n            return txt.replace(/[\\\\]/g, \"\\\\\\\\\")\n                .replace(/[\\\"]/g, '\\\\\"')\n                .replace(/[\\n]/g, '\\\\n')\n                .replace(/[\\r]/g, '\\\\r');\n        },\n        removeWhite: function (e) {\n            e.normalize();\n            for (var n = e.firstChild; n;) {\n                if (n.nodeType == 3) {  // text node\n                    if (!n.nodeValue.match(/[^ \\f\\n\\r\\t\\v]/)) { // pure whitespace text node\n                        var nxt = n.nextSibling;\n                        e.removeChild(n);\n                        n = nxt;\n                    }\n                    else\n                        n = n.nextSibling;\n                }\n                else if (n.nodeType == 1) {  // element node\n                    X.removeWhite(n);\n                    n = n.nextSibling;\n                }\n                else                      // any other node\n                    n = n.nextSibling;\n            }\n            return e;\n        }\n    };\n    if (xml.nodeType == 9) // document node\n        xml = xml.documentElement;\n    var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, \"\\t\");\n    return \"{\\n\" + tab + (tab ? json.replace(/\\t/g, tab) : json.replace(/\\t|\\n/g, \"\")) + \"\\n}\";\n}"
  },
  {
    "path": "src/store/store.data.ts",
    "content": "import {Map, List} from 'immutable';\nimport {UserModel} from \"../models/UserModel\";\nimport {AuthenticateFlags, SideProps} from \"./actions/appdb.actions\";\nimport {ISDK, CampaignBoardsModel} from \"../store/imsdb.interfaces_auto\";\nimport {appDb} from \"../store/reducers/appdb.reducer\";\nimport {msDatabase} from \"../store/reducers/msdb.reducer\";\nimport {storeFreeze} from \"ngrx-store-freeze\";\nimport {ActionReducer, combineReducers} from \"@ngrx/store\";\nimport {ApplicationState} from \"./application.state\";\nimport {compose} from \"@ngrx/core\";\nimport {MainAppShowStateEnum} from \"../app/app-component\";\nimport {LocationMarkModel} from \"../models/LocationMarkModel\";\nimport {StationModel} from \"../models/StationModel\";\nimport {FasterqLineModel} from \"../models/fasterq-line-model\";\nimport {FasterqQueueModel} from \"../models/fasterq-queue-model\";\nimport {FasterqAnalyticsModel} from \"../models/fasterq-analytics\";\nimport {LiveLogModel} from \"../models/live-log-model\";\n\nconst reducers = {msDatabase, appDb};\nexport const developmentReducer: ActionReducer<ApplicationState> = compose(storeFreeze, combineReducers)(reducers);\nexport const productionReducer: ActionReducer<ApplicationState> = combineReducers(reducers);\n\nexport enum StoryBoardListViewModeEnum {\n    ListMode,\n    StoryMode\n}\n\nexport interface IMsDatabase {\n    thread: { [key: number]: any };\n    sdk: ISDK;\n}\n\nexport interface IStation {\n    id: number;\n    localAddress: any;\n    publicIp: string;\n    localPort: number;\n    name: string;\n    watchDogConnection: number;\n    status: string;\n    startTime: string;\n    runningTime: string;\n    caching: boolean;\n    totalMemory: number;\n    peakMemory: number;\n    appVersion: string;\n    airVersion: string;\n    os: string;\n    socket: number;\n    connection: number;\n    connectionStatusChanged: boolean;\n    lastUpdate: string;\n    stationColor: string;\n}\n\nexport interface IUiStateCampaign {\n    campaignTimelineChannelSelected?: number;\n    campaignTimelineBoardViewerSelected?: number;\n    campaignCreateOrientation?: number,\n    campaignCreateResolution?: string,\n    campaignCreateName?: string,\n    campaignSelected?: number;\n    timelineSelected?: number;\n    blockChannelSelected?: number;\n    storyBoardItemSelected?: number;\n    storyBoardOutputSelected?: number;\n    storyBoardChannelSelected?: number;\n    storyBoardListViewModeSelected?: number;\n}\n\nexport interface IUiStateLocation {\n    loadLocationMap?: boolean;\n    locationMarkerSelected?: LocationMarkModel;\n}\n\nexport interface IUiStateResources {\n    resourceSelected?: number;\n}\n\nexport interface IUiStateStations {\n    stationSelected?: number;\n}\n\nexport interface IUiStateFatserq {\n    fasterqLineSelected?: number;\n    fasterqQueueSelected?: number;\n    fasterqNowServicing?: string;\n}\n\nexport interface IUiStateScene {\n    sceneSelected?: number;\n    blockSelected?: number;\n    fabric?: {\n        scale?: number;\n    }\n}\n\nexport interface IUIMultiStationSelected {\n    stations: Map<any,any>;\n}\n\nexport interface IUiState {\n    mainAppState?: MainAppShowStateEnum;\n    previewMode?: number;\n    uiSideProps?: number;\n    appSized?: Map<any, any>;\n    appSaved?: string;\n    campaign?: IUiStateCampaign;\n    locationMap?: IUiStateLocation;\n    resources?: IUiStateResources;\n    stations?: IUiStateStations;\n    fasterq?: IUiStateFatserq;\n    scene?: IUiStateScene;\n    multiStationSelected?: IUIMultiStationSelected;\n}\n\nexport interface IFasterQ {\n    lines: List<FasterqLineModel>\n    queues: List<FasterqQueueModel>\n    analytics: List<FasterqAnalyticsModel>\n    terminal: FasterqLineModel\n}\n\nexport interface IContactForm {\n    email: string;\n    message: string;\n}\n\nexport interface IAppDb {\n    uiState: IUiState;\n    totalStations: string;\n    appStartTime: number;\n    appBaseUrl: string;\n    userModel: UserModel;\n    liveLog: List<LiveLogModel>;\n    stations: List<StationModel>;\n    fasterq: IFasterQ;\n    cloudServers: string;\n    serversStatus: string;\n    appAuthStatus: Map<string, AuthenticateFlags>;\n    appBaseUrlUser: string;\n    appBaseUrlCloud: string;\n    appBaseUrlServices: string;\n    contact: Map<string, any>; //IContactForm waiting for next version of immutablejs to support typed maps\n}\n\nexport const INITIAL_STORE_DATA: IMsDatabase = {\n    thread: null,\n    sdk: null\n}\n\nexport const INITIAL_APP_DB: IAppDb = {\n    uiState: {\n        mainAppState: MainAppShowStateEnum.INIT,\n        previewMode: -1,\n        uiSideProps: SideProps.none,\n        appSized: Map({}),\n        appSaved: '00:00:00',\n        campaign: {\n            campaignTimelineBoardViewerSelected: -1,\n            campaignTimelineChannelSelected: -1,\n            campaignSelected: -1,\n            timelineSelected: -1,\n            storyBoardListViewModeSelected: StoryBoardListViewModeEnum.ListMode,\n            campaignCreateOrientation: -1,\n            blockChannelSelected: -1,\n            campaignCreateResolution: '',\n            campaignCreateName: '',\n            storyBoardItemSelected: -1,\n            storyBoardOutputSelected: -1,\n            storyBoardChannelSelected: -1\n        },\n        locationMap: {\n            loadLocationMap: false,\n            locationMarkerSelected: null\n        },\n        resources: {\n            resourceSelected: -1\n        },\n        stations: {\n            stationSelected: -1\n        },\n        fasterq: {\n            fasterqLineSelected: -1,\n            fasterqQueueSelected: -1,\n            fasterqNowServicing: ''\n\n        },\n        scene: {\n            sceneSelected: -1,\n            blockSelected: -1,\n            fabric: {\n                scale: -1\n            }\n        },\n        multiStationSelected: {\n            stations: Map({})\n        }\n\n    },\n    totalStations: '',\n    appStartTime: -1,\n    appBaseUrl: '',\n    stations: List([]),\n    liveLog: List([]),\n    fasterq: {\n        lines: List([]),\n        queues: List([]),\n        analytics: List([]),\n        terminal: null\n\n    },\n    userModel: new UserModel({\n        user: '',\n        pass: '',\n        authenticated: false,\n        businessId: -1,\n        rememberMe: false,\n        twoFactorRequired: false,\n        accountType: -1\n    }),\n    appAuthStatus: Map({authStatus: AuthenticateFlags.NONE}),\n    cloudServers: '',\n    serversStatus: '',\n    appBaseUrlUser: '',\n    appBaseUrlCloud: '',\n    appBaseUrlServices: '',\n    contact: Map({\n        email: '',\n        message: '',\n        type: 0\n    })\n};"
  },
  {
    "path": "src/styles/material-design/css/bootstrap-material-design.css",
    "content": "/*\n\nTo get this list of colors inject jQuery at http://www.google.com/design/spec/style/color.html#color-color-palette\n\nThen, run this script to get the list.\n\n\n(function() {\n  var colors = {}, main = {};\n  $(\".color-group\").each(function() {\n    var color = $(this).find(\".name\").text().trim().toLowerCase().replace(\" \", \"-\");\n    colors[color] = {};\n\n    $(this).find(\".color\").not(\".main-color\").each(function() {\n      var shade = $(this).find(\".shade\").text().trim(),\n          hex   = $(this).find(\".hex\").text().trim();\n\n      colors[color][shade] = hex;\n    });\n    main[color] = color + \"-\" + $(this).find(\".main-color .shade\").text().trim();\n\n  });\n  var LESS = \"\";\n  $.each(colors, function(name, shades) {\n    LESS += \"\\n\\n\";\n    $.each(shades, function(shade, hex) {\n      LESS += \"@\" + name + \"-\" + shade + \": \" + hex + \";\\n\";\n    });\n    if (main[name]) {\n      LESS += \"@\" + name + \": \" + main[name] + \";\\n\";\n    }\n  });\n  console.log(LESS);\n})();\n\n\n*/\n/* ANIMATION */\n/* SHADOWS */\n/* Shadows (from mdl http://www.getmdl.io/) */\nbody {\n  background-color: #EEEEEE;\n}\nbody.inverse {\n  background: #333333;\n}\nbody.inverse,\nbody.inverse .form-control {\n  color: rgba(255,255,255, 0.84);\n}\nbody.inverse .modal,\nbody.inverse .panel-default,\nbody.inverse .card,\nbody.inverse .modal .form-control,\nbody.inverse .panel-default .form-control,\nbody.inverse .card .form-control {\n  background-color: initial;\n  color: initial;\n}\nbody,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4 {\n  font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;\n  font-weight: 300;\n}\nh5,\nh6 {\n  font-weight: 400;\n}\na,\na:hover,\na:focus {\n  color: #009688;\n}\na .material-icons,\na:hover .material-icons,\na:focus .material-icons {\n  vertical-align: middle;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 0;\n}\n.form-horizontal .radio {\n  margin-bottom: 10px;\n}\n.form-horizontal label {\n  text-align: right;\n}\n.form-horizontal label.control-label {\n  margin: 0;\n}\nbody .container .well.well-sm,\nbody .container-fluid .well.well-sm {\n  padding: 10px;\n}\nbody .container .well.well-lg,\nbody .container-fluid .well.well-lg {\n  padding: 26px;\n}\nbody .container .well,\nbody .container-fluid .well,\nbody .container .jumbotron,\nbody .container-fluid .jumbotron {\n  background-color: #fff;\n  padding: 19px;\n  margin-bottom: 20px;\n  -webkit-box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n          box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n  border-radius: 2px;\n  border: 0;\n}\nbody .container .well p,\nbody .container-fluid .well p,\nbody .container .jumbotron p,\nbody .container-fluid .jumbotron p {\n  font-weight: 300;\n}\nbody .container .well,\nbody .container-fluid .well,\nbody .container .jumbotron,\nbody .container-fluid .jumbotron,\nbody .container .well-default,\nbody .container-fluid .well-default,\nbody .container .jumbotron-default,\nbody .container-fluid .jumbotron-default {\n  background-color: #ffffff;\n}\nbody .container .well-inverse,\nbody .container-fluid .well-inverse,\nbody .container .jumbotron-inverse,\nbody .container-fluid .jumbotron-inverse {\n  background-color: #3f51b5;\n}\nbody .container .well-primary,\nbody .container-fluid .well-primary,\nbody .container .jumbotron-primary,\nbody .container-fluid .jumbotron-primary {\n  background-color: #009688;\n}\nbody .container .well-success,\nbody .container-fluid .well-success,\nbody .container .jumbotron-success,\nbody .container-fluid .jumbotron-success {\n  background-color: #4caf50;\n}\nbody .container .well-info,\nbody .container-fluid .well-info,\nbody .container .jumbotron-info,\nbody .container-fluid .jumbotron-info {\n  background-color: #03a9f4;\n}\nbody .container .well-warning,\nbody .container-fluid .well-warning,\nbody .container .jumbotron-warning,\nbody .container-fluid .jumbotron-warning {\n  background-color: #ff5722;\n}\nbody .container .well-danger,\nbody .container-fluid .well-danger,\nbody .container .jumbotron-danger,\nbody .container-fluid .jumbotron-danger {\n  background-color: #f44336;\n}\n.btn,\n.input-group-btn .btn {\n  border: none;\n  border-radius: 2px;\n  position: relative;\n  padding: 8px 30px;\n  margin: 10px 1px;\n  font-size: 14px;\n  font-weight: 500;\n  text-transform: uppercase;\n  letter-spacing: 0;\n  will-change: box-shadow, transform;\n  -webkit-transition: -webkit-box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n       -o-transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n          transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n  outline: 0;\n  cursor: pointer;\n  text-decoration: none;\n  background: transparent;\n}\n.btn::-moz-focus-inner,\n.input-group-btn .btn::-moz-focus-inner {\n  border: 0;\n}\n.btn:not(.btn-raised),\n.input-group-btn .btn:not(.btn-raised) {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn:not(.btn-raised),\n.input-group-btn .btn:not(.btn-raised),\n.btn:not(.btn-raised).btn-default,\n.input-group-btn .btn:not(.btn-raised).btn-default {\n  color: rgba(0,0,0, 0.87);\n}\n.btn:not(.btn-raised).btn-inverse,\n.input-group-btn .btn:not(.btn-raised).btn-inverse {\n  color: #3f51b5;\n}\n.btn:not(.btn-raised).btn-primary,\n.input-group-btn .btn:not(.btn-raised).btn-primary {\n  color: #009688;\n}\n.btn:not(.btn-raised).btn-success,\n.input-group-btn .btn:not(.btn-raised).btn-success {\n  color: #4caf50;\n}\n.btn:not(.btn-raised).btn-info,\n.input-group-btn .btn:not(.btn-raised).btn-info {\n  color: #03a9f4;\n}\n.btn:not(.btn-raised).btn-warning,\n.input-group-btn .btn:not(.btn-raised).btn-warning {\n  color: #ff5722;\n}\n.btn:not(.btn-raised).btn-danger,\n.input-group-btn .btn:not(.btn-raised).btn-danger {\n  color: #f44336;\n}\n.btn:not(.btn-raised):not(.btn-link):hover,\n.input-group-btn .btn:not(.btn-raised):not(.btn-link):hover,\n.btn:not(.btn-raised):not(.btn-link):focus,\n.input-group-btn .btn:not(.btn-raised):not(.btn-link):focus {\n  background-color: rgba(153, 153, 153, 0.2);\n}\n.theme-dark .btn:not(.btn-raised):not(.btn-link):hover,\n.theme-dark .input-group-btn .btn:not(.btn-raised):not(.btn-link):hover,\n.theme-dark .btn:not(.btn-raised):not(.btn-link):focus,\n.theme-dark .input-group-btn .btn:not(.btn-raised):not(.btn-link):focus {\n  background-color: rgba(204, 204, 204, 0.15);\n}\n.btn.btn-raised,\n.input-group-btn .btn.btn-raised,\n.btn.btn-fab,\n.input-group-btn .btn.btn-fab,\n.btn-group-raised .btn,\n.btn-group-raised .input-group-btn .btn,\n.btn.btn-raised.btn-default,\n.input-group-btn .btn.btn-raised.btn-default,\n.btn.btn-fab.btn-default,\n.input-group-btn .btn.btn-fab.btn-default,\n.btn-group-raised .btn.btn-default,\n.btn-group-raised .input-group-btn .btn.btn-default {\n  background-color: #EEEEEE;\n  color: rgba(0,0,0, 0.87);\n}\n.btn.btn-raised.btn-inverse,\n.input-group-btn .btn.btn-raised.btn-inverse,\n.btn.btn-fab.btn-inverse,\n.input-group-btn .btn.btn-fab.btn-inverse,\n.btn-group-raised .btn.btn-inverse,\n.btn-group-raised .input-group-btn .btn.btn-inverse {\n  background-color: #3f51b5;\n  color: #ffffff;\n}\n.btn.btn-raised.btn-primary,\n.input-group-btn .btn.btn-raised.btn-primary,\n.btn.btn-fab.btn-primary,\n.input-group-btn .btn.btn-fab.btn-primary,\n.btn-group-raised .btn.btn-primary,\n.btn-group-raised .input-group-btn .btn.btn-primary {\n  background-color: #009688;\n  color: rgba(255,255,255, 0.84);\n}\n.btn.btn-raised.btn-success,\n.input-group-btn .btn.btn-raised.btn-success,\n.btn.btn-fab.btn-success,\n.input-group-btn .btn.btn-fab.btn-success,\n.btn-group-raised .btn.btn-success,\n.btn-group-raised .input-group-btn .btn.btn-success {\n  background-color: #4caf50;\n  color: rgba(255,255,255, 0.84);\n}\n.btn.btn-raised.btn-info,\n.input-group-btn .btn.btn-raised.btn-info,\n.btn.btn-fab.btn-info,\n.input-group-btn .btn.btn-fab.btn-info,\n.btn-group-raised .btn.btn-info,\n.btn-group-raised .input-group-btn .btn.btn-info {\n  background-color: #03a9f4;\n  color: rgba(255,255,255, 0.84);\n}\n.btn.btn-raised.btn-warning,\n.input-group-btn .btn.btn-raised.btn-warning,\n.btn.btn-fab.btn-warning,\n.input-group-btn .btn.btn-fab.btn-warning,\n.btn-group-raised .btn.btn-warning,\n.btn-group-raised .input-group-btn .btn.btn-warning {\n  background-color: #ff5722;\n  color: rgba(255,255,255, 0.84);\n}\n.btn.btn-raised.btn-danger,\n.input-group-btn .btn.btn-raised.btn-danger,\n.btn.btn-fab.btn-danger,\n.input-group-btn .btn.btn-fab.btn-danger,\n.btn-group-raised .btn.btn-danger,\n.btn-group-raised .input-group-btn .btn.btn-danger {\n  background-color: #f44336;\n  color: rgba(255,255,255, 0.84);\n}\n.btn.btn-raised:not(.btn-link),\n.input-group-btn .btn.btn-raised:not(.btn-link),\n.btn-group-raised .btn:not(.btn-link),\n.btn-group-raised .input-group-btn .btn:not(.btn-link) {\n  -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n          box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n.btn.btn-raised:not(.btn-link):hover,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover,\n.btn-group-raised .btn:not(.btn-link):hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover,\n.btn.btn-raised:not(.btn-link):focus,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus,\n.btn-group-raised .btn:not(.btn-link):focus,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus,\n.btn.btn-raised:not(.btn-link).active,\n.input-group-btn .btn.btn-raised:not(.btn-link).active,\n.btn-group-raised .btn:not(.btn-link).active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active,\n.btn.btn-raised:not(.btn-link):active,\n.input-group-btn .btn.btn-raised:not(.btn-link):active,\n.btn-group-raised .btn:not(.btn-link):active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active {\n  outline: 0;\n}\n.btn.btn-raised:not(.btn-link):hover,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover,\n.btn-group-raised .btn:not(.btn-link):hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover,\n.btn.btn-raised:not(.btn-link):focus,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus,\n.btn-group-raised .btn:not(.btn-link):focus,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus,\n.btn.btn-raised:not(.btn-link).active,\n.input-group-btn .btn.btn-raised:not(.btn-link).active,\n.btn-group-raised .btn:not(.btn-link).active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active,\n.btn.btn-raised:not(.btn-link):active,\n.input-group-btn .btn.btn-raised:not(.btn-link):active,\n.btn-group-raised .btn:not(.btn-link):active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active,\n.btn.btn-raised:not(.btn-link):hover.btn-default,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-default,\n.btn-group-raised .btn:not(.btn-link):hover.btn-default,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-default,\n.btn.btn-raised:not(.btn-link):focus.btn-default,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-default,\n.btn-group-raised .btn:not(.btn-link):focus.btn-default,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-default,\n.btn.btn-raised:not(.btn-link).active.btn-default,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-default,\n.btn-group-raised .btn:not(.btn-link).active.btn-default,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-default,\n.btn.btn-raised:not(.btn-link):active.btn-default,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-default,\n.btn-group-raised .btn:not(.btn-link):active.btn-default,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-default {\n  background-color: #e4e4e4;\n}\n.btn.btn-raised:not(.btn-link):hover.btn-inverse,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-inverse,\n.btn-group-raised .btn:not(.btn-link):hover.btn-inverse,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-inverse,\n.btn.btn-raised:not(.btn-link):focus.btn-inverse,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-inverse,\n.btn-group-raised .btn:not(.btn-link):focus.btn-inverse,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-inverse,\n.btn.btn-raised:not(.btn-link).active.btn-inverse,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-inverse,\n.btn-group-raised .btn:not(.btn-link).active.btn-inverse,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-inverse,\n.btn.btn-raised:not(.btn-link):active.btn-inverse,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-inverse,\n.btn-group-raised .btn:not(.btn-link):active.btn-inverse,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-inverse {\n  background-color: #495bc0;\n}\n.btn.btn-raised:not(.btn-link):hover.btn-primary,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-primary,\n.btn-group-raised .btn:not(.btn-link):hover.btn-primary,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-primary,\n.btn.btn-raised:not(.btn-link):focus.btn-primary,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-primary,\n.btn-group-raised .btn:not(.btn-link):focus.btn-primary,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-primary,\n.btn.btn-raised:not(.btn-link).active.btn-primary,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-primary,\n.btn-group-raised .btn:not(.btn-link).active.btn-primary,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-primary,\n.btn.btn-raised:not(.btn-link):active.btn-primary,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-primary,\n.btn-group-raised .btn:not(.btn-link):active.btn-primary,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-primary {\n  background-color: #00aa9a;\n}\n.btn.btn-raised:not(.btn-link):hover.btn-success,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-success,\n.btn-group-raised .btn:not(.btn-link):hover.btn-success,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-success,\n.btn.btn-raised:not(.btn-link):focus.btn-success,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-success,\n.btn-group-raised .btn:not(.btn-link):focus.btn-success,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-success,\n.btn.btn-raised:not(.btn-link).active.btn-success,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-success,\n.btn-group-raised .btn:not(.btn-link).active.btn-success,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-success,\n.btn.btn-raised:not(.btn-link):active.btn-success,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-success,\n.btn-group-raised .btn:not(.btn-link):active.btn-success,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-success {\n  background-color: #59b75c;\n}\n.btn.btn-raised:not(.btn-link):hover.btn-info,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-info,\n.btn-group-raised .btn:not(.btn-link):hover.btn-info,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-info,\n.btn.btn-raised:not(.btn-link):focus.btn-info,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-info,\n.btn-group-raised .btn:not(.btn-link):focus.btn-info,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-info,\n.btn.btn-raised:not(.btn-link).active.btn-info,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-info,\n.btn-group-raised .btn:not(.btn-link).active.btn-info,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-info,\n.btn.btn-raised:not(.btn-link):active.btn-info,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-info,\n.btn-group-raised .btn:not(.btn-link):active.btn-info,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-info {\n  background-color: #0fb2fc;\n}\n.btn.btn-raised:not(.btn-link):hover.btn-warning,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-warning,\n.btn-group-raised .btn:not(.btn-link):hover.btn-warning,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-warning,\n.btn.btn-raised:not(.btn-link):focus.btn-warning,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-warning,\n.btn-group-raised .btn:not(.btn-link):focus.btn-warning,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-warning,\n.btn.btn-raised:not(.btn-link).active.btn-warning,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-warning,\n.btn-group-raised .btn:not(.btn-link).active.btn-warning,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-warning,\n.btn.btn-raised:not(.btn-link):active.btn-warning,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-warning,\n.btn-group-raised .btn:not(.btn-link):active.btn-warning,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-warning {\n  background-color: #ff6736;\n}\n.btn.btn-raised:not(.btn-link):hover.btn-danger,\n.input-group-btn .btn.btn-raised:not(.btn-link):hover.btn-danger,\n.btn-group-raised .btn:not(.btn-link):hover.btn-danger,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):hover.btn-danger,\n.btn.btn-raised:not(.btn-link):focus.btn-danger,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.btn-danger,\n.btn-group-raised .btn:not(.btn-link):focus.btn-danger,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.btn-danger,\n.btn.btn-raised:not(.btn-link).active.btn-danger,\n.input-group-btn .btn.btn-raised:not(.btn-link).active.btn-danger,\n.btn-group-raised .btn:not(.btn-link).active.btn-danger,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active.btn-danger,\n.btn.btn-raised:not(.btn-link):active.btn-danger,\n.input-group-btn .btn.btn-raised:not(.btn-link):active.btn-danger,\n.btn-group-raised .btn:not(.btn-link):active.btn-danger,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active.btn-danger {\n  background-color: #f55549;\n}\n.btn.btn-raised:not(.btn-link).active,\n.input-group-btn .btn.btn-raised:not(.btn-link).active,\n.btn-group-raised .btn:not(.btn-link).active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active,\n.btn.btn-raised:not(.btn-link):active,\n.input-group-btn .btn.btn-raised:not(.btn-link):active,\n.btn-group-raised .btn:not(.btn-link):active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active,\n.btn.btn-raised:not(.btn-link).active:hover,\n.input-group-btn .btn.btn-raised:not(.btn-link).active:hover,\n.btn-group-raised .btn:not(.btn-link).active:hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link).active:hover,\n.btn.btn-raised:not(.btn-link):active:hover,\n.input-group-btn .btn.btn-raised:not(.btn-link):active:hover,\n.btn-group-raised .btn:not(.btn-link):active:hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):active:hover {\n  -webkit-box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2);\n          box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2);\n}\n.btn.btn-raised:not(.btn-link):focus,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus,\n.btn-group-raised .btn:not(.btn-link):focus,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus,\n.btn.btn-raised:not(.btn-link):focus.active,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.active,\n.btn-group-raised .btn:not(.btn-link):focus.active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.active,\n.btn.btn-raised:not(.btn-link):focus:active,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus:active,\n.btn-group-raised .btn:not(.btn-link):focus:active,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus:active,\n.btn.btn-raised:not(.btn-link):focus:hover,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus:hover,\n.btn-group-raised .btn:not(.btn-link):focus:hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus:hover,\n.btn.btn-raised:not(.btn-link):focus.active:hover,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus.active:hover,\n.btn-group-raised .btn:not(.btn-link):focus.active:hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus.active:hover,\n.btn.btn-raised:not(.btn-link):focus:active:hover,\n.input-group-btn .btn.btn-raised:not(.btn-link):focus:active:hover,\n.btn-group-raised .btn:not(.btn-link):focus:active:hover,\n.btn-group-raised .input-group-btn .btn:not(.btn-link):focus:active:hover {\n  -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.18), 0 8px 16px rgba(0, 0, 0, 0.36);\n          box-shadow: 0 0 8px rgba(0, 0, 0, 0.18), 0 8px 16px rgba(0, 0, 0, 0.36);\n}\n.btn.btn-fab,\n.input-group-btn .btn.btn-fab {\n  border-radius: 50%;\n  font-size: 24px;\n  height: 56px;\n  margin: auto;\n  min-width: 56px;\n  width: 56px;\n  padding: 0;\n  overflow: hidden;\n  -webkit-box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24);\n          box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24);\n  position: relative;\n  line-height: normal;\n}\n.btn.btn-fab .ripple-container,\n.input-group-btn .btn.btn-fab .ripple-container {\n  border-radius: 50%;\n}\n.btn.btn-fab.btn-fab-mini,\n.input-group-btn .btn.btn-fab.btn-fab-mini,\n.btn-group-sm .btn.btn-fab,\n.btn-group-sm .input-group-btn .btn.btn-fab {\n  height: 40px;\n  min-width: 40px;\n  width: 40px;\n}\n.btn.btn-fab.btn-fab-mini.material-icons,\n.input-group-btn .btn.btn-fab.btn-fab-mini.material-icons,\n.btn-group-sm .btn.btn-fab.material-icons,\n.btn-group-sm .input-group-btn .btn.btn-fab.material-icons {\n  top: 0px;\n  left: 0px;\n}\n.btn.btn-fab i.material-icons,\n.input-group-btn .btn.btn-fab i.material-icons {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  -webkit-transform: translate(-12px, -12px);\n      -ms-transform: translate(-12px, -12px);\n       -o-transform: translate(-12px, -12px);\n          transform: translate(-12px, -12px);\n  line-height: 24px;\n  width: 24px;\n}\n.btn i.material-icons,\n.input-group-btn .btn i.material-icons {\n  vertical-align: middle;\n}\n.btn.btn-lg,\n.input-group-btn .btn.btn-lg,\n.btn-group-lg .btn,\n.btn-group-lg .input-group-btn .btn {\n  font-size: 16px;\n}\n.btn.btn-sm,\n.input-group-btn .btn.btn-sm,\n.btn-group-sm .btn,\n.btn-group-sm .input-group-btn .btn {\n  padding: 5px 20px;\n  font-size: 12px;\n}\n.btn.btn-xs,\n.input-group-btn .btn.btn-xs,\n.btn-group-xs .btn,\n.btn-group-xs .input-group-btn .btn {\n  padding: 4px 15px;\n  font-size: 10px;\n}\nfieldset[disabled][disabled] .btn,\nfieldset[disabled][disabled] .input-group-btn .btn,\nfieldset[disabled][disabled] .btn-group,\nfieldset[disabled][disabled] .btn-group-vertical,\n.btn.disabled,\n.input-group-btn .btn.disabled,\n.btn-group.disabled,\n.btn-group-vertical.disabled,\n.btn:disabled,\n.input-group-btn .btn:disabled,\n.btn-group:disabled,\n.btn-group-vertical:disabled,\n.btn[disabled][disabled],\n.input-group-btn .btn[disabled][disabled],\n.btn-group[disabled][disabled],\n.btn-group-vertical[disabled][disabled] {\n  color: rgba(0, 0, 0, 0.26);\n  background: transparent;\n}\n.theme-dark fieldset[disabled][disabled] .btn,\n.theme-dark fieldset[disabled][disabled] .input-group-btn .btn,\n.theme-dark fieldset[disabled][disabled] .btn-group,\n.theme-dark fieldset[disabled][disabled] .btn-group-vertical,\n.theme-dark .btn.disabled,\n.theme-dark .input-group-btn .btn.disabled,\n.theme-dark .btn-group.disabled,\n.theme-dark .btn-group-vertical.disabled,\n.theme-dark .btn:disabled,\n.theme-dark .input-group-btn .btn:disabled,\n.theme-dark .btn-group:disabled,\n.theme-dark .btn-group-vertical:disabled,\n.theme-dark .btn[disabled][disabled],\n.theme-dark .input-group-btn .btn[disabled][disabled],\n.theme-dark .btn-group[disabled][disabled],\n.theme-dark .btn-group-vertical[disabled][disabled] {\n  color: rgba(255, 255, 255, 0.3);\n}\nfieldset[disabled][disabled] .btn.btn-raised,\nfieldset[disabled][disabled] .input-group-btn .btn.btn-raised,\nfieldset[disabled][disabled] .btn-group.btn-raised,\nfieldset[disabled][disabled] .btn-group-vertical.btn-raised,\n.btn.disabled.btn-raised,\n.input-group-btn .btn.disabled.btn-raised,\n.btn-group.disabled.btn-raised,\n.btn-group-vertical.disabled.btn-raised,\n.btn:disabled.btn-raised,\n.input-group-btn .btn:disabled.btn-raised,\n.btn-group:disabled.btn-raised,\n.btn-group-vertical:disabled.btn-raised,\n.btn[disabled][disabled].btn-raised,\n.input-group-btn .btn[disabled][disabled].btn-raised,\n.btn-group[disabled][disabled].btn-raised,\n.btn-group-vertical[disabled][disabled].btn-raised,\nfieldset[disabled][disabled] .btn.btn-group-raised,\nfieldset[disabled][disabled] .input-group-btn .btn.btn-group-raised,\nfieldset[disabled][disabled] .btn-group.btn-group-raised,\nfieldset[disabled][disabled] .btn-group-vertical.btn-group-raised,\n.btn.disabled.btn-group-raised,\n.input-group-btn .btn.disabled.btn-group-raised,\n.btn-group.disabled.btn-group-raised,\n.btn-group-vertical.disabled.btn-group-raised,\n.btn:disabled.btn-group-raised,\n.input-group-btn .btn:disabled.btn-group-raised,\n.btn-group:disabled.btn-group-raised,\n.btn-group-vertical:disabled.btn-group-raised,\n.btn[disabled][disabled].btn-group-raised,\n.input-group-btn .btn[disabled][disabled].btn-group-raised,\n.btn-group[disabled][disabled].btn-group-raised,\n.btn-group-vertical[disabled][disabled].btn-group-raised,\nfieldset[disabled][disabled] .btn.btn-raised.active,\nfieldset[disabled][disabled] .input-group-btn .btn.btn-raised.active,\nfieldset[disabled][disabled] .btn-group.btn-raised.active,\nfieldset[disabled][disabled] .btn-group-vertical.btn-raised.active,\n.btn.disabled.btn-raised.active,\n.input-group-btn .btn.disabled.btn-raised.active,\n.btn-group.disabled.btn-raised.active,\n.btn-group-vertical.disabled.btn-raised.active,\n.btn:disabled.btn-raised.active,\n.input-group-btn .btn:disabled.btn-raised.active,\n.btn-group:disabled.btn-raised.active,\n.btn-group-vertical:disabled.btn-raised.active,\n.btn[disabled][disabled].btn-raised.active,\n.input-group-btn .btn[disabled][disabled].btn-raised.active,\n.btn-group[disabled][disabled].btn-raised.active,\n.btn-group-vertical[disabled][disabled].btn-raised.active,\nfieldset[disabled][disabled] .btn.btn-group-raised.active,\nfieldset[disabled][disabled] .input-group-btn .btn.btn-group-raised.active,\nfieldset[disabled][disabled] .btn-group.btn-group-raised.active,\nfieldset[disabled][disabled] .btn-group-vertical.btn-group-raised.active,\n.btn.disabled.btn-group-raised.active,\n.input-group-btn .btn.disabled.btn-group-raised.active,\n.btn-group.disabled.btn-group-raised.active,\n.btn-group-vertical.disabled.btn-group-raised.active,\n.btn:disabled.btn-group-raised.active,\n.input-group-btn .btn:disabled.btn-group-raised.active,\n.btn-group:disabled.btn-group-raised.active,\n.btn-group-vertical:disabled.btn-group-raised.active,\n.btn[disabled][disabled].btn-group-raised.active,\n.input-group-btn .btn[disabled][disabled].btn-group-raised.active,\n.btn-group[disabled][disabled].btn-group-raised.active,\n.btn-group-vertical[disabled][disabled].btn-group-raised.active,\nfieldset[disabled][disabled] .btn.btn-raised:active,\nfieldset[disabled][disabled] .input-group-btn .btn.btn-raised:active,\nfieldset[disabled][disabled] .btn-group.btn-raised:active,\nfieldset[disabled][disabled] .btn-group-vertical.btn-raised:active,\n.btn.disabled.btn-raised:active,\n.input-group-btn .btn.disabled.btn-raised:active,\n.btn-group.disabled.btn-raised:active,\n.btn-group-vertical.disabled.btn-raised:active,\n.btn:disabled.btn-raised:active,\n.input-group-btn .btn:disabled.btn-raised:active,\n.btn-group:disabled.btn-raised:active,\n.btn-group-vertical:disabled.btn-raised:active,\n.btn[disabled][disabled].btn-raised:active,\n.input-group-btn .btn[disabled][disabled].btn-raised:active,\n.btn-group[disabled][disabled].btn-raised:active,\n.btn-group-vertical[disabled][disabled].btn-raised:active,\nfieldset[disabled][disabled] .btn.btn-group-raised:active,\nfieldset[disabled][disabled] .input-group-btn .btn.btn-group-raised:active,\nfieldset[disabled][disabled] .btn-group.btn-group-raised:active,\nfieldset[disabled][disabled] .btn-group-vertical.btn-group-raised:active,\n.btn.disabled.btn-group-raised:active,\n.input-group-btn .btn.disabled.btn-group-raised:active,\n.btn-group.disabled.btn-group-raised:active,\n.btn-group-vertical.disabled.btn-group-raised:active,\n.btn:disabled.btn-group-raised:active,\n.input-group-btn .btn:disabled.btn-group-raised:active,\n.btn-group:disabled.btn-group-raised:active,\n.btn-group-vertical:disabled.btn-group-raised:active,\n.btn[disabled][disabled].btn-group-raised:active,\n.input-group-btn .btn[disabled][disabled].btn-group-raised:active,\n.btn-group[disabled][disabled].btn-group-raised:active,\n.btn-group-vertical[disabled][disabled].btn-group-raised:active,\nfieldset[disabled][disabled] .btn.btn-raised:focus:not(:active),\nfieldset[disabled][disabled] .input-group-btn .btn.btn-raised:focus:not(:active),\nfieldset[disabled][disabled] .btn-group.btn-raised:focus:not(:active),\nfieldset[disabled][disabled] .btn-group-vertical.btn-raised:focus:not(:active),\n.btn.disabled.btn-raised:focus:not(:active),\n.input-group-btn .btn.disabled.btn-raised:focus:not(:active),\n.btn-group.disabled.btn-raised:focus:not(:active),\n.btn-group-vertical.disabled.btn-raised:focus:not(:active),\n.btn:disabled.btn-raised:focus:not(:active),\n.input-group-btn .btn:disabled.btn-raised:focus:not(:active),\n.btn-group:disabled.btn-raised:focus:not(:active),\n.btn-group-vertical:disabled.btn-raised:focus:not(:active),\n.btn[disabled][disabled].btn-raised:focus:not(:active),\n.input-group-btn .btn[disabled][disabled].btn-raised:focus:not(:active),\n.btn-group[disabled][disabled].btn-raised:focus:not(:active),\n.btn-group-vertical[disabled][disabled].btn-raised:focus:not(:active),\nfieldset[disabled][disabled] .btn.btn-group-raised:focus:not(:active),\nfieldset[disabled][disabled] .input-group-btn .btn.btn-group-raised:focus:not(:active),\nfieldset[disabled][disabled] .btn-group.btn-group-raised:focus:not(:active),\nfieldset[disabled][disabled] .btn-group-vertical.btn-group-raised:focus:not(:active),\n.btn.disabled.btn-group-raised:focus:not(:active),\n.input-group-btn .btn.disabled.btn-group-raised:focus:not(:active),\n.btn-group.disabled.btn-group-raised:focus:not(:active),\n.btn-group-vertical.disabled.btn-group-raised:focus:not(:active),\n.btn:disabled.btn-group-raised:focus:not(:active),\n.input-group-btn .btn:disabled.btn-group-raised:focus:not(:active),\n.btn-group:disabled.btn-group-raised:focus:not(:active),\n.btn-group-vertical:disabled.btn-group-raised:focus:not(:active),\n.btn[disabled][disabled].btn-group-raised:focus:not(:active),\n.input-group-btn .btn[disabled][disabled].btn-group-raised:focus:not(:active),\n.btn-group[disabled][disabled].btn-group-raised:focus:not(:active),\n.btn-group-vertical[disabled][disabled].btn-group-raised:focus:not(:active) {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  margin: 10px 1px;\n}\n.btn-group.open > .dropdown-toggle.btn,\n.btn-group-vertical.open > .dropdown-toggle.btn,\n.btn-group.open > .dropdown-toggle.btn.btn-default,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-default {\n  background-color: #EEEEEE;\n}\n.btn-group.open > .dropdown-toggle.btn.btn-inverse,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-inverse {\n  background-color: #3f51b5;\n}\n.btn-group.open > .dropdown-toggle.btn.btn-primary,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-primary {\n  background-color: #009688;\n}\n.btn-group.open > .dropdown-toggle.btn.btn-success,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-success {\n  background-color: #4caf50;\n}\n.btn-group.open > .dropdown-toggle.btn.btn-info,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-info {\n  background-color: #03a9f4;\n}\n.btn-group.open > .dropdown-toggle.btn.btn-warning,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-warning {\n  background-color: #ff5722;\n}\n.btn-group.open > .dropdown-toggle.btn.btn-danger,\n.btn-group-vertical.open > .dropdown-toggle.btn.btn-danger {\n  background-color: #f44336;\n}\n.btn-group .dropdown-menu,\n.btn-group-vertical .dropdown-menu {\n  border-radius: 0 0 2px 2px;\n}\n.btn-group.btn-group-raised,\n.btn-group-vertical.btn-group-raised {\n  -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n          box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n.btn-group .btn + .btn,\n.btn-group-vertical .btn + .btn,\n.btn-group .btn,\n.btn-group-vertical .btn,\n.btn-group .btn:active,\n.btn-group-vertical .btn:active,\n.btn-group .btn-group,\n.btn-group-vertical .btn-group {\n  margin: 0;\n}\n.checkbox label {\n  cursor: pointer;\n  padding-left: 0;\n  color: rgba(0,0,0, 0.26);\n}\n.form-group.is-focused .checkbox label {\n  color: rgba(0,0,0, 0.26);\n}\n.form-group.is-focused .checkbox label:hover,\n.form-group.is-focused .checkbox label:focus {\n  color: rgba(0,0,0, .54);\n}\nfieldset[disabled] .form-group.is-focused .checkbox label {\n  color: rgba(0,0,0, 0.26);\n}\n.checkbox input[type=checkbox] {\n  opacity: 0;\n  position: absolute;\n  margin: 0;\n  z-index: -1;\n  width: 0;\n  height: 0;\n  overflow: hidden;\n  left: 0;\n  pointer-events: none;\n}\n.checkbox .checkbox-material {\n  vertical-align: middle;\n  position: relative;\n  top: 3px;\n}\n.checkbox .checkbox-material:before {\n  display: block;\n  position: absolute;\n  left: 0;\n  content: \"\";\n  background-color: rgba(0, 0, 0, 0.84);\n  height: 20px;\n  width: 20px;\n  border-radius: 100%;\n  z-index: 1;\n  opacity: 0;\n  margin: 0;\n  -webkit-transform: scale3d(2.3, 2.3, 1);\n          transform: scale3d(2.3, 2.3, 1);\n}\n.checkbox .checkbox-material .check {\n  position: relative;\n  display: inline-block;\n  width: 20px;\n  height: 20px;\n  border: 2px solid rgba(0,0,0, .54);\n  overflow: hidden;\n  z-index: 1;\n}\n.checkbox .checkbox-material .check:before {\n  position: absolute;\n  content: \"\";\n  -webkit-transform: rotate(45deg);\n      -ms-transform: rotate(45deg);\n       -o-transform: rotate(45deg);\n          transform: rotate(45deg);\n  display: block;\n  margin-top: -4px;\n  margin-left: 6px;\n  width: 0;\n  height: 0;\n  -webkit-box-shadow: 0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0 inset;\n          box-shadow: 0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0,\n        0 0 0 0 inset;\n  -webkit-animation: checkbox-off 0.3s forwards;\n       -o-animation: checkbox-off 0.3s forwards;\n          animation: checkbox-off 0.3s forwards;\n}\n.checkbox input[type=checkbox]:focus + .checkbox-material .check:after {\n  opacity: 0.2;\n}\n.checkbox input[type=checkbox]:checked + .checkbox-material .check {\n  color: #009688;\n  border-color: #009688;\n}\n.checkbox input[type=checkbox]:checked + .checkbox-material .check:before {\n  color: #009688;\n  -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n          box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n  -webkit-animation: checkbox-on 0.3s forwards;\n       -o-animation: checkbox-on 0.3s forwards;\n          animation: checkbox-on 0.3s forwards;\n}\n.checkbox input[type=checkbox]:checked + .checkbox-material:before {\n  -webkit-animation: rippleOn 500ms;\n       -o-animation: rippleOn 500ms;\n          animation: rippleOn 500ms;\n}\n.checkbox input[type=checkbox]:checked + .checkbox-material .check:after {\n  -webkit-animation: rippleOn 500ms forwards;\n       -o-animation: rippleOn 500ms forwards;\n          animation: rippleOn 500ms forwards;\n}\n.checkbox input[type=checkbox]:not(:checked) + .checkbox-material:before {\n  -webkit-animation: rippleOff 500ms;\n       -o-animation: rippleOff 500ms;\n          animation: rippleOff 500ms;\n}\n.checkbox input[type=checkbox]:not(:checked) + .checkbox-material .check:after {\n  -webkit-animation: rippleOff 500ms forwards;\n       -o-animation: rippleOff 500ms forwards;\n          animation: rippleOff 500ms forwards;\n}\nfieldset[disabled] .checkbox,\nfieldset[disabled] .checkbox input[type=checkbox],\n.checkbox input[type=checkbox][disabled]:not(:checked) ~ .checkbox-material .check:before,\n.checkbox input[type=checkbox][disabled]:not(:checked) ~ .checkbox-material .check,\n.checkbox input[type=checkbox][disabled] + .circle {\n  opacity: 0.5;\n}\n.checkbox input[type=checkbox][disabled] + .checkbox-material .check:after {\n  background-color: rgba(0,0,0, 0.87);\n  -webkit-transform: rotate(-45deg);\n      -ms-transform: rotate(-45deg);\n       -o-transform: rotate(-45deg);\n          transform: rotate(-45deg);\n}\n@-webkit-keyframes checkbox-on {\n  0% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px;\n  }\n  50% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px 2px 0 11px;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px 2px 0 11px;\n  }\n  100% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n  }\n}\n@-o-keyframes checkbox-on {\n  0% {\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px;\n  }\n  50% {\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px 2px 0 11px;\n  }\n  100% {\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n  }\n}\n@keyframes checkbox-on {\n  0% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px;\n  }\n  50% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px 2px 0 11px;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px 2px 0 11px;\n  }\n  100% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n  }\n}\n@-webkit-keyframes checkbox-off {\n  0% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n  }\n  25% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n  }\n  50% {\n    -webkit-transform: rotate(45deg);\n            transform: rotate(45deg);\n    margin-top: -4px;\n    margin-left: 6px;\n    width: 0;\n    height: 0;\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px, 0 0 0 0 inset;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px, 0 0 0 0 inset;\n  }\n  51% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n    margin-top: -2px;\n    margin-left: -2px;\n    width: 20px;\n    height: 20px;\n    -webkit-box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 10px inset;\n            box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 10px inset;\n  }\n  100% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n    margin-top: -2px;\n    margin-left: -2px;\n    width: 20px;\n    height: 20px;\n    -webkit-box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 0 inset;\n            box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 0 inset;\n  }\n}\n@-o-keyframes checkbox-off {\n  0% {\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n  }\n  25% {\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n  }\n  50% {\n    -o-transform: rotate(45deg);\n       transform: rotate(45deg);\n    margin-top: -4px;\n    margin-left: 6px;\n    width: 0;\n    height: 0;\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px, 0 0 0 0 inset;\n  }\n  51% {\n    -o-transform: rotate(0deg);\n       transform: rotate(0deg);\n    margin-top: -2px;\n    margin-left: -2px;\n    width: 20px;\n    height: 20px;\n    box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 10px inset;\n  }\n  100% {\n    -o-transform: rotate(0deg);\n       transform: rotate(0deg);\n    margin-top: -2px;\n    margin-left: -2px;\n    width: 20px;\n    height: 20px;\n    box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 0 inset;\n  }\n}\n@keyframes checkbox-off {\n  0% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n  }\n  25% {\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px, 0 0 0 0 inset;\n  }\n  50% {\n    -webkit-transform: rotate(45deg);\n         -o-transform: rotate(45deg);\n            transform: rotate(45deg);\n    margin-top: -4px;\n    margin-left: 6px;\n    width: 0;\n    height: 0;\n    -webkit-box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px, 0 0 0 0 inset;\n            box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px, 0 0 0 0 inset;\n  }\n  51% {\n    -webkit-transform: rotate(0deg);\n         -o-transform: rotate(0deg);\n            transform: rotate(0deg);\n    margin-top: -2px;\n    margin-left: -2px;\n    width: 20px;\n    height: 20px;\n    -webkit-box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 10px inset;\n            box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 10px inset;\n  }\n  100% {\n    -webkit-transform: rotate(0deg);\n         -o-transform: rotate(0deg);\n            transform: rotate(0deg);\n    margin-top: -2px;\n    margin-left: -2px;\n    width: 20px;\n    height: 20px;\n    -webkit-box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 0 inset;\n            box-shadow: 0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0 0 0 0,\n      0px 0 0 0 inset;\n  }\n}\n@-webkit-keyframes rippleOn {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n@-o-keyframes rippleOn {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n@keyframes rippleOn {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n@-webkit-keyframes rippleOff {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n@-o-keyframes rippleOff {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n@keyframes rippleOff {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n.togglebutton {\n  vertical-align: middle;\n}\n.togglebutton,\n.togglebutton label,\n.togglebutton input,\n.togglebutton .toggle {\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n}\n.togglebutton label {\n  cursor: pointer;\n  color: rgba(0,0,0, 0.26);\n}\n.form-group.is-focused .togglebutton label {\n  color: rgba(0,0,0, 0.26);\n}\n.form-group.is-focused .togglebutton label:hover,\n.form-group.is-focused .togglebutton label:focus {\n  color: rgba(0,0,0, .54);\n}\nfieldset[disabled] .form-group.is-focused .togglebutton label {\n  color: rgba(0,0,0, 0.26);\n}\n.togglebutton label input[type=checkbox] {\n  opacity: 0;\n  width: 0;\n  height: 0;\n}\n.togglebutton label .toggle {\n  text-align: left;\n}\n.togglebutton label .toggle,\n.togglebutton label input[type=checkbox][disabled] + .toggle {\n  content: \"\";\n  display: inline-block;\n  width: 30px;\n  height: 15px;\n  background-color: rgba(80, 80, 80, 0.7);\n  border-radius: 15px;\n  margin-right: 15px;\n  -webkit-transition: background 0.3s ease;\n       -o-transition: background 0.3s ease;\n          transition: background 0.3s ease;\n  vertical-align: middle;\n}\n.togglebutton label .toggle:after {\n  content: \"\";\n  display: inline-block;\n  width: 20px;\n  height: 20px;\n  background-color: #F1F1F1;\n  border-radius: 20px;\n  position: relative;\n  -webkit-box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4);\n          box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4);\n  left: -5px;\n  top: -2px;\n  -webkit-transition: left 0.3s ease, background 0.3s ease, -webkit-box-shadow 0.1s ease;\n       -o-transition: left 0.3s ease, background 0.3s ease, box-shadow 0.1s ease;\n          transition: left 0.3s ease, background 0.3s ease, box-shadow 0.1s ease;\n}\n.togglebutton label input[type=checkbox][disabled] + .toggle:after,\n.togglebutton label input[type=checkbox][disabled]:checked + .toggle:after {\n  background-color: #BDBDBD;\n}\n.togglebutton label input[type=checkbox] + .toggle:active:after,\n.togglebutton label input[type=checkbox][disabled] + .toggle:active:after {\n  -webkit-box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(0, 0, 0, 0.1);\n          box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(0, 0, 0, 0.1);\n}\n.togglebutton label input[type=checkbox]:checked + .toggle:after {\n  left: 15px;\n}\n.togglebutton label input[type=checkbox]:checked + .toggle {\n  background-color: rgba(0, 150, 136, 0.5);\n}\n.togglebutton label input[type=checkbox]:checked + .toggle:after {\n  background-color: #009688;\n}\n.togglebutton label input[type=checkbox]:checked + .toggle:active:after {\n  -webkit-box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(0, 150, 136, 0.1);\n          box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(0, 150, 136, 0.1);\n}\n.radio label {\n  cursor: pointer;\n  padding-left: 45px;\n  position: relative;\n  color: rgba(0,0,0, 0.26);\n}\n.form-group.is-focused .radio label {\n  color: rgba(0,0,0, 0.26);\n}\n.form-group.is-focused .radio label:hover,\n.form-group.is-focused .radio label:focus {\n  color: rgba(0,0,0, .54);\n}\nfieldset[disabled] .form-group.is-focused .radio label {\n  color: rgba(0,0,0, 0.26);\n}\n.radio label span {\n  display: block;\n  position: absolute;\n  left: 10px;\n  top: 2px;\n  -webkit-transition-duration: 0.2s;\n       -o-transition-duration: 0.2s;\n          transition-duration: 0.2s;\n}\n.radio label .circle {\n  border: 2px solid rgba(0,0,0, .54);\n  height: 15px;\n  width: 15px;\n  border-radius: 100%;\n}\n.radio label .check {\n  height: 15px;\n  width: 15px;\n  border-radius: 100%;\n  background-color: #009688;\n  -webkit-transform: scale3d(0, 0, 0);\n          transform: scale3d(0, 0, 0);\n}\n.radio label .check:after {\n  display: block;\n  position: absolute;\n  content: \"\";\n  background-color: rgba(0,0,0, 0.87);\n  left: -18px;\n  top: -18px;\n  height: 50px;\n  width: 50px;\n  border-radius: 100%;\n  z-index: 1;\n  opacity: 0;\n  margin: 0;\n  -webkit-transform: scale3d(1.5, 1.5, 1);\n          transform: scale3d(1.5, 1.5, 1);\n}\n.radio label input[type=radio]:not(:checked) ~ .check:after {\n  -webkit-animation: rippleOff 500ms;\n       -o-animation: rippleOff 500ms;\n          animation: rippleOff 500ms;\n}\n.radio label input[type=radio]:checked ~ .check:after {\n  -webkit-animation: rippleOn 500ms;\n       -o-animation: rippleOn 500ms;\n          animation: rippleOn 500ms;\n}\n.radio input[type=radio] {\n  opacity: 0;\n  height: 0;\n  width: 0;\n  overflow: hidden;\n}\n.radio input[type=radio]:checked ~ .check,\n.radio input[type=radio]:checked ~ .circle {\n  opacity: 1;\n}\n.radio input[type=radio]:checked ~ .check {\n  background-color: #009688;\n}\n.radio input[type=radio]:checked ~ .circle {\n  border-color: #009688;\n}\n.radio input[type=radio]:checked ~ .check {\n  -webkit-transform: scale3d(0.55, 0.55, 1);\n          transform: scale3d(0.55, 0.55, 1);\n}\n.radio input[type=radio][disabled] ~ .check,\n.radio input[type=radio][disabled] ~ .circle {\n  opacity: 0.26;\n}\n.radio input[type=radio][disabled] ~ .check {\n  background-color: #000000;\n}\n.radio input[type=radio][disabled] ~ .circle {\n  border-color: #000000;\n}\n.theme-dark .radio input[type=radio][disabled] ~ .check,\n.theme-dark .radio input[type=radio][disabled] ~ .circle {\n  opacity: 0.3;\n}\n.theme-dark .radio input[type=radio][disabled] ~ .check {\n  background-color: #ffffff;\n}\n.theme-dark .radio input[type=radio][disabled] ~ .circle {\n  border-color: #ffffff;\n}\n@keyframes rippleOn {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n@keyframes rippleOff {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 0.2;\n  }\n  100% {\n    opacity: 0;\n  }\n}\nlegend {\n  margin-bottom: 22px;\n  font-size: 24px;\n}\noutput {\n  padding-top: 8px;\n  font-size: 16px;\n  line-height: 1.42857143;\n}\n.form-control {\n  height: 38px;\n  padding: 7px 0;\n  font-size: 16px;\n  line-height: 1.42857143;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"].form-control,\n  input[type=\"time\"].form-control,\n  input[type=\"datetime-local\"].form-control,\n  input[type=\"month\"].form-control {\n    line-height: 38px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 24px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 44px;\n  }\n}\n.radio label,\n.checkbox label {\n  min-height: 22px;\n}\n.form-control-static {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  min-height: 38px;\n}\n.input-sm .input-sm {\n  height: 24px;\n  padding: 3px 0;\n  font-size: 11px;\n  line-height: 1.5;\n  border-radius: 0;\n}\n.input-sm select.input-sm {\n  height: 24px;\n  line-height: 24px;\n}\n.input-sm textarea.input-sm,\n.input-sm select[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 24px;\n  padding: 3px 0;\n  font-size: 11px;\n  line-height: 1.5;\n}\n.form-group-sm select.form-control {\n  height: 24px;\n  line-height: 24px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 24px;\n  min-height: 33px;\n  padding: 4px 0;\n  font-size: 11px;\n  line-height: 1.5;\n}\n.input-lg .input-lg {\n  height: 44px;\n  padding: 9px 0;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 0;\n}\n.input-lg select.input-lg {\n  height: 44px;\n  line-height: 44px;\n}\n.input-lg textarea.input-lg,\n.input-lg select[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 44px;\n  padding: 9px 0;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.form-group-lg select.form-control {\n  height: 44px;\n  line-height: 44px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 44px;\n  min-height: 40px;\n  padding: 10px 0;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 8px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 30px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    padding-top: 8px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 12.9999997px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 4px;\n    font-size: 11px;\n  }\n}\n.label {\n  border-radius: 1px;\n}\n.label,\n.label.label-default {\n  background-color: #9e9e9e;\n}\n.label.label-inverse {\n  background-color: #3f51b5;\n}\n.label.label-primary {\n  background-color: #009688;\n}\n.label.label-success {\n  background-color: #4caf50;\n}\n.label.label-info {\n  background-color: #03a9f4;\n}\n.label.label-warning {\n  background-color: #ff5722;\n}\n.label.label-danger {\n  background-color: #f44336;\n}\n.form-control,\n.form-group .form-control {\n  border: 0;\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#009688), to(#009688)), -webkit-gradient(linear, left top, left bottom, from(#D2D2D2), to(#D2D2D2));\n  background-image: -webkit-linear-gradient(#009688, #009688), -webkit-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: -o-linear-gradient(#009688, #009688), -o-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: linear-gradient(#009688, #009688), linear-gradient(#D2D2D2, #D2D2D2);\n  -webkit-background-size: 0 2px, 100% 1px;\n          background-size: 0 2px, 100% 1px;\n  background-repeat: no-repeat;\n  background-position: center bottom, center -webkit-calc(100% - 1px);\n  background-position: center bottom, center calc(100% - 1px);\n  background-color: rgba(0, 0, 0, 0);\n  -webkit-transition: background 0s ease-out;\n       -o-transition: background 0s ease-out;\n          transition: background 0s ease-out;\n  float: none;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  border-radius: 0;\n}\n.form-control::-moz-placeholder,\n.form-group .form-control::-moz-placeholder {\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-control:-ms-input-placeholder,\n.form-group .form-control:-ms-input-placeholder {\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-control::-webkit-input-placeholder,\n.form-group .form-control::-webkit-input-placeholder {\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-control[readonly],\n.form-group .form-control[readonly],\n.form-control[disabled],\n.form-group .form-control[disabled],\nfieldset[disabled] .form-control,\nfieldset[disabled] .form-group .form-control {\n  background-color: rgba(0, 0, 0, 0);\n}\n.form-control[disabled],\n.form-group .form-control[disabled],\nfieldset[disabled] .form-control,\nfieldset[disabled] .form-group .form-control {\n  background-image: none;\n  border-bottom: 1px dotted #D2D2D2;\n}\n.form-group {\n  position: relative;\n}\n.form-group.label-static label.control-label,\n.form-group.label-placeholder label.control-label,\n.form-group.label-floating label.control-label {\n  position: absolute;\n  pointer-events: none;\n  -webkit-transition: 0.3s ease all;\n       -o-transition: 0.3s ease all;\n          transition: 0.3s ease all;\n}\n.form-group.label-floating label.control-label {\n  will-change: left, top, contents;\n}\n.form-group.label-placeholder:not(.is-empty) label.control-label {\n  display: none;\n}\n.form-group .help-block {\n  position: absolute;\n  display: none;\n}\n.form-group.is-focused .form-control {\n  outline: none;\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#009688), to(#009688)), -webkit-gradient(linear, left top, left bottom, from(#D2D2D2), to(#D2D2D2));\n  background-image: -webkit-linear-gradient(#009688, #009688), -webkit-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: -o-linear-gradient(#009688, #009688), -o-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: linear-gradient(#009688, #009688), linear-gradient(#D2D2D2, #D2D2D2);\n  -webkit-background-size: 100% 2px, 100% 1px;\n          background-size: 100% 2px, 100% 1px;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  -webkit-transition-duration: 0.3s;\n       -o-transition-duration: 0.3s;\n          transition-duration: 0.3s;\n}\n.form-group.is-focused .form-control .material-input:after {\n  background-color: #009688;\n}\n.form-group.is-focused label,\n.form-group.is-focused label.control-label {\n  color: #009688;\n}\n.form-group.is-focused.label-placeholder label,\n.form-group.is-focused.label-placeholder label.control-label {\n  color: #BDBDBD;\n}\n.form-group.is-focused .help-block {\n  display: block;\n}\n.form-group.has-warning .form-control {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.form-group.has-warning.is-focused .form-control {\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#ff5722), to(#ff5722)), -webkit-gradient(linear, left top, left bottom, from(#D2D2D2), to(#D2D2D2));\n  background-image: -webkit-linear-gradient(#ff5722, #ff5722), -webkit-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: -o-linear-gradient(#ff5722, #ff5722), -o-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: linear-gradient(#ff5722, #ff5722), linear-gradient(#D2D2D2, #D2D2D2);\n}\n.form-group.has-warning label.control-label,\n.form-group.has-warning .help-block {\n  color: #ff5722;\n}\n.form-group.has-error .form-control {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.form-group.has-error.is-focused .form-control {\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f44336), to(#f44336)), -webkit-gradient(linear, left top, left bottom, from(#D2D2D2), to(#D2D2D2));\n  background-image: -webkit-linear-gradient(#f44336, #f44336), -webkit-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: -o-linear-gradient(#f44336, #f44336), -o-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: linear-gradient(#f44336, #f44336), linear-gradient(#D2D2D2, #D2D2D2);\n}\n.form-group.has-error label.control-label,\n.form-group.has-error .help-block {\n  color: #f44336;\n}\n.form-group.has-success .form-control {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.form-group.has-success.is-focused .form-control {\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#4caf50), to(#4caf50)), -webkit-gradient(linear, left top, left bottom, from(#D2D2D2), to(#D2D2D2));\n  background-image: -webkit-linear-gradient(#4caf50, #4caf50), -webkit-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: -o-linear-gradient(#4caf50, #4caf50), -o-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: linear-gradient(#4caf50, #4caf50), linear-gradient(#D2D2D2, #D2D2D2);\n}\n.form-group.has-success label.control-label,\n.form-group.has-success .help-block {\n  color: #4caf50;\n}\n.form-group.has-info .form-control {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.form-group.has-info.is-focused .form-control {\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#03a9f4), to(#03a9f4)), -webkit-gradient(linear, left top, left bottom, from(#D2D2D2), to(#D2D2D2));\n  background-image: -webkit-linear-gradient(#03a9f4, #03a9f4), -webkit-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: -o-linear-gradient(#03a9f4, #03a9f4), -o-linear-gradient(#D2D2D2, #D2D2D2);\n  background-image: linear-gradient(#03a9f4, #03a9f4), linear-gradient(#D2D2D2, #D2D2D2);\n}\n.form-group.has-info label.control-label,\n.form-group.has-info .help-block {\n  color: #03a9f4;\n}\n.form-group textarea {\n  resize: none;\n}\n.form-group textarea ~ .form-control-highlight {\n  margin-top: -11px;\n}\n.form-group select {\n  -webkit-appearance: none;\n     -moz-appearance: none;\n          appearance: none;\n}\n.form-group select ~ .material-input:after {\n  display: none;\n}\n.form-control {\n  margin-bottom: 7px;\n}\n.form-control::-moz-placeholder {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-control:-ms-input-placeholder {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-control::-webkit-input-placeholder {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.checkbox label,\n.radio label,\nlabel {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\nlabel.control-label {\n  font-size: 12px;\n  line-height: 1.07142857;\n  color: #BDBDBD;\n  font-weight: 400;\n  margin: 16px 0 0 0;\n}\n.help-block {\n  margin-top: 0;\n  font-size: 12px;\n}\n.form-group {\n  padding-bottom: 7px;\n  margin: 28px 0 0 0;\n}\n.form-group .form-control {\n  margin-bottom: 7px;\n}\n.form-group .form-control::-moz-placeholder {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group .form-control:-ms-input-placeholder {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group .form-control::-webkit-input-placeholder {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group .checkbox label,\n.form-group .radio label,\n.form-group label {\n  font-size: 16px;\n  line-height: 1.42857143;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group label.control-label {\n  font-size: 12px;\n  line-height: 1.07142857;\n  color: #BDBDBD;\n  font-weight: 400;\n  margin: 16px 0 0 0;\n}\n.form-group .help-block {\n  margin-top: 0;\n  font-size: 12px;\n}\n.form-group.label-floating label.control-label,\n.form-group.label-placeholder label.control-label {\n  top: -7px;\n  font-size: 16px;\n  line-height: 1.42857143;\n}\n.form-group.label-static label.control-label,\n.form-group.label-floating.is-focused label.control-label,\n.form-group.label-floating:not(.is-empty) label.control-label {\n  top: -30px;\n  left: 0;\n  font-size: 12px;\n  line-height: 1.07142857;\n}\n.form-group.label-floating input.form-control:-webkit-autofill ~ label.control-label label.control-label {\n  top: -30px;\n  left: 0;\n  font-size: 12px;\n  line-height: 1.07142857;\n}\n.form-group.form-group-sm {\n  padding-bottom: 3px;\n  margin: 21px 0 0 0;\n}\n.form-group.form-group-sm .form-control {\n  margin-bottom: 3px;\n}\n.form-group.form-group-sm .form-control::-moz-placeholder {\n  font-size: 11px;\n  line-height: 1.5;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-sm .form-control:-ms-input-placeholder {\n  font-size: 11px;\n  line-height: 1.5;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-sm .form-control::-webkit-input-placeholder {\n  font-size: 11px;\n  line-height: 1.5;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-sm .checkbox label,\n.form-group.form-group-sm .radio label,\n.form-group.form-group-sm label {\n  font-size: 11px;\n  line-height: 1.5;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-sm label.control-label {\n  font-size: 9px;\n  line-height: 1.125;\n  color: #BDBDBD;\n  font-weight: 400;\n  margin: 16px 0 0 0;\n}\n.form-group.form-group-sm .help-block {\n  margin-top: 0;\n  font-size: 9px;\n}\n.form-group.form-group-sm.label-floating label.control-label,\n.form-group.form-group-sm.label-placeholder label.control-label {\n  top: -11px;\n  font-size: 11px;\n  line-height: 1.5;\n}\n.form-group.form-group-sm.label-static label.control-label,\n.form-group.form-group-sm.label-floating.is-focused label.control-label,\n.form-group.form-group-sm.label-floating:not(.is-empty) label.control-label {\n  top: -25px;\n  left: 0;\n  font-size: 9px;\n  line-height: 1.125;\n}\n.form-group.form-group-sm.label-floating input.form-control:-webkit-autofill ~ label.control-label label.control-label {\n  top: -25px;\n  left: 0;\n  font-size: 9px;\n  line-height: 1.125;\n}\n.form-group.form-group-lg {\n  padding-bottom: 9px;\n  margin: 30px 0 0 0;\n}\n.form-group.form-group-lg .form-control {\n  margin-bottom: 9px;\n}\n.form-group.form-group-lg .form-control::-moz-placeholder {\n  font-size: 18px;\n  line-height: 1.3333333;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-lg .form-control:-ms-input-placeholder {\n  font-size: 18px;\n  line-height: 1.3333333;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-lg .form-control::-webkit-input-placeholder {\n  font-size: 18px;\n  line-height: 1.3333333;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-lg .checkbox label,\n.form-group.form-group-lg .radio label,\n.form-group.form-group-lg label {\n  font-size: 18px;\n  line-height: 1.3333333;\n  color: #BDBDBD;\n  font-weight: 400;\n}\n.form-group.form-group-lg label.control-label {\n  font-size: 14px;\n  line-height: 0.99999998;\n  color: #BDBDBD;\n  font-weight: 400;\n  margin: 16px 0 0 0;\n}\n.form-group.form-group-lg .help-block {\n  margin-top: 0;\n  font-size: 14px;\n}\n.form-group.form-group-lg.label-floating label.control-label,\n.form-group.form-group-lg.label-placeholder label.control-label {\n  top: -5px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.form-group.form-group-lg.label-static label.control-label,\n.form-group.form-group-lg.label-floating.is-focused label.control-label,\n.form-group.form-group-lg.label-floating:not(.is-empty) label.control-label {\n  top: -32px;\n  left: 0;\n  font-size: 14px;\n  line-height: 0.99999998;\n}\n.form-group.form-group-lg.label-floating input.form-control:-webkit-autofill ~ label.control-label label.control-label {\n  top: -32px;\n  left: 0;\n  font-size: 14px;\n  line-height: 0.99999998;\n}\nselect.form-control {\n  border: 0;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  border-radius: 0;\n}\n.form-group.is-focused select.form-control {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  border-color: #D2D2D2;\n}\nselect.form-control[multiple],\n.form-group.is-focused select.form-control[multiple] {\n  height: 85px;\n}\n.input-group-btn .btn {\n  margin: 0 0 7px 0;\n}\n.form-group.form-group-sm .input-group-btn .btn {\n  margin: 0 0 3px 0;\n}\n.form-group.form-group-lg .input-group-btn .btn {\n  margin: 0 0 9px 0;\n}\n.input-group .input-group-btn {\n  padding: 0 12px;\n}\n.input-group .input-group-addon {\n  border: 0;\n  background: transparent;\n}\n.form-group input[type=file] {\n  opacity: 0;\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 100;\n}\nlegend {\n  border-bottom: 0;\n}\n.list-group {\n  border-radius: 0;\n}\n.list-group .list-group-item {\n  background-color: transparent;\n  overflow: hidden;\n  border: 0;\n  border-radius: 0;\n  padding: 0 16px;\n}\n.list-group .list-group-item.baseline {\n  border-bottom: 1px solid #cecece;\n}\n.list-group .list-group-item.baseline:last-child {\n  border-bottom: none;\n}\n.list-group .list-group-item .row-picture,\n.list-group .list-group-item .row-action-primary {\n  display: inline-block;\n  padding-right: 16px;\n}\n.list-group .list-group-item .row-picture img,\n.list-group .list-group-item .row-action-primary img,\n.list-group .list-group-item .row-picture i,\n.list-group .list-group-item .row-action-primary i,\n.list-group .list-group-item .row-picture label,\n.list-group .list-group-item .row-action-primary label {\n  display: block;\n  width: 56px;\n  height: 56px;\n}\n.list-group .list-group-item .row-picture img,\n.list-group .list-group-item .row-action-primary img {\n  background: rgba(0, 0, 0, 0.1);\n  padding: 1px;\n}\n.list-group .list-group-item .row-picture img.circle,\n.list-group .list-group-item .row-action-primary img.circle {\n  border-radius: 100%;\n}\n.list-group .list-group-item .row-picture i,\n.list-group .list-group-item .row-action-primary i {\n  background: rgba(0, 0, 0, 0.25);\n  border-radius: 100%;\n  text-align: center;\n  line-height: 56px;\n  font-size: 20px;\n  color: white;\n}\n.list-group .list-group-item .row-picture label,\n.list-group .list-group-item .row-action-primary label {\n  margin-left: 7px;\n  margin-right: -7px;\n  margin-top: 5px;\n  margin-bottom: -5px;\n}\n.list-group .list-group-item .row-picture label .checkbox-material,\n.list-group .list-group-item .row-action-primary label .checkbox-material {\n  left: -10px;\n}\n.list-group .list-group-item .row-content {\n  display: inline-block;\n  width: -webkit-calc(100% - 92px);\n  width: calc(100% - 92px);\n  min-height: 66px;\n}\n.list-group .list-group-item .row-content .action-secondary {\n  position: absolute;\n  right: 16px;\n  top: 16px;\n}\n.list-group .list-group-item .row-content .action-secondary i {\n  font-size: 20px;\n  color: rgba(0, 0, 0, 0.25);\n  cursor: pointer;\n}\n.list-group .list-group-item .row-content .action-secondary ~ * {\n  max-width: -webkit-calc(100% - 30px);\n  max-width: calc(100% - 30px);\n}\n.list-group .list-group-item .row-content .least-content {\n  position: absolute;\n  right: 16px;\n  top: 0;\n  color: rgba(0, 0, 0, 0.54);\n  font-size: 14px;\n}\n.list-group .list-group-item .list-group-item-heading {\n  color: rgba(0, 0, 0, 0.77);\n  font-size: 20px;\n  line-height: 29px;\n}\n.list-group .list-group-item.active:hover,\n.list-group .list-group-item.active:focus {\n  background: rgba(0, 0, 0, 0.15);\n  outline: 10px solid rgba(0, 0, 0, 0.15);\n}\n.list-group .list-group-item.active .list-group-item-heading,\n.list-group .list-group-item.active .list-group-item-text {\n  color: rgba(0,0,0, 0.87);\n}\n.list-group .list-group-separator {\n  clear: both;\n  overflow: hidden;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.list-group .list-group-separator:before {\n  content: \"\";\n  width: -webkit-calc(100% - 90px);\n  width: calc(100% - 90px);\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  float: right;\n}\n.navbar {\n  background-color: #009688;\n  border: 0;\n  border-radius: 0;\n}\n.navbar .navbar-brand {\n  position: relative;\n  height: 60px;\n  line-height: 30px;\n  color: inherit;\n}\n.navbar .navbar-brand:hover,\n.navbar .navbar-brand:focus {\n  color: inherit;\n  background-color: transparent;\n}\n.navbar .navbar-text {\n  color: inherit;\n  margin-top: 20px;\n  margin-bottom: 20px;\n}\n.navbar .navbar-nav > li > a {\n  color: inherit;\n  padding-top: 20px;\n  padding-bottom: 20px;\n}\n.navbar .navbar-nav > li > a:hover,\n.navbar .navbar-nav > li > a:focus {\n  color: inherit;\n  background-color: transparent;\n}\n.navbar .navbar-nav > .active > a,\n.navbar .navbar-nav > .active > a:hover,\n.navbar .navbar-nav > .active > a:focus {\n  color: inherit;\n  background-color: rgba(255, 255, 255, 0.1);\n}\n.navbar .navbar-nav > .disabled > a,\n.navbar .navbar-nav > .disabled > a:hover,\n.navbar .navbar-nav > .disabled > a:focus {\n  color: inherit;\n  background-color: transparent;\n  opacity: 0.9;\n}\n.navbar .navbar-toggle {\n  border: 0;\n}\n.navbar .navbar-toggle:hover,\n.navbar .navbar-toggle:focus {\n  background-color: transparent;\n}\n.navbar .navbar-toggle .icon-bar {\n  background-color: inherit;\n  border: 1px solid;\n}\n.navbar .navbar-default .navbar-toggle,\n.navbar .navbar-inverse .navbar-toggle {\n  border-color: transparent;\n}\n.navbar .navbar-collapse,\n.navbar .navbar-form {\n  border-color: rgba(0, 0, 0, 0.1);\n}\n.navbar .navbar-nav > .open > a,\n.navbar .navbar-nav > .open > a:hover,\n.navbar .navbar-nav > .open > a:focus {\n  background-color: transparent;\n  color: inherit;\n}\n@media (max-width: 767px) {\n  .navbar .navbar-nav .navbar-text {\n    color: inherit;\n    margin-top: 15px;\n    margin-bottom: 15px;\n  }\n  .navbar .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border: 0;\n    color: inherit;\n  }\n  .navbar .navbar-nav .open .dropdown-menu .divider {\n    border-bottom: 1px solid;\n    opacity: 0.08;\n  }\n  .navbar .navbar-nav .open .dropdown-menu > li > a {\n    color: inherit;\n  }\n  .navbar .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: inherit;\n    background-color: transparent;\n  }\n  .navbar .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: inherit;\n    background-color: transparent;\n  }\n  .navbar .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: inherit;\n    background-color: transparent;\n  }\n}\n.navbar .navbar-link {\n  color: inherit;\n}\n.navbar .navbar-link:hover {\n  color: inherit;\n}\n.navbar .btn-link {\n  color: inherit;\n}\n.navbar .btn-link:hover,\n.navbar .btn-link:focus {\n  color: inherit;\n}\n.navbar .btn-link[disabled]:hover,\nfieldset[disabled] .navbar .btn-link:hover,\n.navbar .btn-link[disabled]:focus,\nfieldset[disabled] .navbar .btn-link:focus {\n  color: inherit;\n}\n.navbar .navbar-form {\n  margin-top: 16px;\n}\n.navbar .navbar-form .form-group {\n  margin: 0;\n  padding: 0;\n}\n.navbar .navbar-form .form-group .material-input:before,\n.navbar .navbar-form .form-group.is-focused .material-input:after {\n  background-color: inherit;\n}\n.navbar .navbar-form .form-group .form-control,\n.navbar .navbar-form .form-control {\n  border-color: inherit;\n  color: inherit;\n  padding: 0;\n  margin: 0;\n  height: 28px;\n  font-size: 14px;\n  line-height: 1.42857143;\n}\n.navbar,\n.navbar.navbar-default {\n  background-color: #009688;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-default .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar .navbar-form input.form-control::-moz-placeholder,\n.navbar.navbar-default .navbar-form input.form-control::-moz-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-default .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar .navbar-form input.form-control:-ms-input-placeholder,\n.navbar.navbar-default .navbar-form input.form-control:-ms-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-default .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar .navbar-form input.form-control::-webkit-input-placeholder,\n.navbar.navbar-default .navbar-form input.form-control::-webkit-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar .dropdown-menu,\n.navbar.navbar-default .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar .dropdown-menu li > a,\n.navbar.navbar-default .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar .dropdown-menu li > a:hover,\n.navbar.navbar-default .dropdown-menu li > a:hover,\n.navbar .dropdown-menu li > a:focus,\n.navbar.navbar-default .dropdown-menu li > a:focus {\n  color: #009688;\n  background-color: #eeeeee;\n}\n.navbar .dropdown-menu .active > a,\n.navbar.navbar-default .dropdown-menu .active > a {\n  background-color: #009688;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar .dropdown-menu .active > a:hover,\n.navbar.navbar-default .dropdown-menu .active > a:hover,\n.navbar .dropdown-menu .active > a:focus,\n.navbar.navbar-default .dropdown-menu .active > a:focus {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-inverse {\n  background-color: #3f51b5;\n  color: #ffffff;\n}\n.navbar.navbar-inverse .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-inverse .navbar-form input.form-control::-moz-placeholder {\n  color: #ffffff;\n}\n.navbar.navbar-inverse .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-inverse .navbar-form input.form-control:-ms-input-placeholder {\n  color: #ffffff;\n}\n.navbar.navbar-inverse .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-inverse .navbar-form input.form-control::-webkit-input-placeholder {\n  color: #ffffff;\n}\n.navbar.navbar-inverse .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar.navbar-inverse .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar.navbar-inverse .dropdown-menu li > a:hover,\n.navbar.navbar-inverse .dropdown-menu li > a:focus {\n  color: #3f51b5;\n  background-color: #eeeeee;\n}\n.navbar.navbar-inverse .dropdown-menu .active > a {\n  background-color: #3f51b5;\n  color: #ffffff;\n}\n.navbar.navbar-inverse .dropdown-menu .active > a:hover,\n.navbar.navbar-inverse .dropdown-menu .active > a:focus {\n  color: #ffffff;\n}\n.navbar.navbar-primary {\n  background-color: #009688;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-primary .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-primary .navbar-form input.form-control::-moz-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-primary .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-primary .navbar-form input.form-control:-ms-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-primary .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-primary .navbar-form input.form-control::-webkit-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-primary .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar.navbar-primary .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar.navbar-primary .dropdown-menu li > a:hover,\n.navbar.navbar-primary .dropdown-menu li > a:focus {\n  color: #009688;\n  background-color: #eeeeee;\n}\n.navbar.navbar-primary .dropdown-menu .active > a {\n  background-color: #009688;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-primary .dropdown-menu .active > a:hover,\n.navbar.navbar-primary .dropdown-menu .active > a:focus {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-success {\n  background-color: #4caf50;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-success .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-success .navbar-form input.form-control::-moz-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-success .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-success .navbar-form input.form-control:-ms-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-success .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-success .navbar-form input.form-control::-webkit-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-success .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar.navbar-success .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar.navbar-success .dropdown-menu li > a:hover,\n.navbar.navbar-success .dropdown-menu li > a:focus {\n  color: #4caf50;\n  background-color: #eeeeee;\n}\n.navbar.navbar-success .dropdown-menu .active > a {\n  background-color: #4caf50;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-success .dropdown-menu .active > a:hover,\n.navbar.navbar-success .dropdown-menu .active > a:focus {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-info {\n  background-color: #03a9f4;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-info .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-info .navbar-form input.form-control::-moz-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-info .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-info .navbar-form input.form-control:-ms-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-info .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-info .navbar-form input.form-control::-webkit-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-info .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar.navbar-info .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar.navbar-info .dropdown-menu li > a:hover,\n.navbar.navbar-info .dropdown-menu li > a:focus {\n  color: #03a9f4;\n  background-color: #eeeeee;\n}\n.navbar.navbar-info .dropdown-menu .active > a {\n  background-color: #03a9f4;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-info .dropdown-menu .active > a:hover,\n.navbar.navbar-info .dropdown-menu .active > a:focus {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-warning {\n  background-color: #ff5722;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-warning .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-warning .navbar-form input.form-control::-moz-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-warning .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-warning .navbar-form input.form-control:-ms-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-warning .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-warning .navbar-form input.form-control::-webkit-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-warning .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar.navbar-warning .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar.navbar-warning .dropdown-menu li > a:hover,\n.navbar.navbar-warning .dropdown-menu li > a:focus {\n  color: #ff5722;\n  background-color: #eeeeee;\n}\n.navbar.navbar-warning .dropdown-menu .active > a {\n  background-color: #ff5722;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-warning .dropdown-menu .active > a:hover,\n.navbar.navbar-warning .dropdown-menu .active > a:focus {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-danger {\n  background-color: #f44336;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-danger .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-danger .navbar-form input.form-control::-moz-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-danger .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-danger .navbar-form input.form-control:-ms-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-danger .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-danger .navbar-form input.form-control::-webkit-input-placeholder {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-danger .dropdown-menu {\n  border-radius: 2px;\n}\n.navbar.navbar-danger .dropdown-menu li > a {\n  font-size: 16px;\n  padding: 13px 16px;\n}\n.navbar.navbar-danger .dropdown-menu li > a:hover,\n.navbar.navbar-danger .dropdown-menu li > a:focus {\n  color: #f44336;\n  background-color: #eeeeee;\n}\n.navbar.navbar-danger .dropdown-menu .active > a {\n  background-color: #f44336;\n  color: rgba(255,255,255, 0.84);\n}\n.navbar.navbar-danger .dropdown-menu .active > a:hover,\n.navbar.navbar-danger .dropdown-menu .active > a:focus {\n  color: rgba(255,255,255, 0.84);\n}\n.navbar-inverse {\n  background-color: #3f51b5;\n}\n@media (max-width: 1199px) {\n  .navbar .navbar-brand {\n    height: 50px;\n    padding: 10px 15px;\n  }\n  .navbar .navbar-form {\n    margin-top: 10px;\n  }\n  .navbar .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n.dropdown-menu {\n  border: 0;\n  -webkit-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);\n          box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);\n}\n.dropdown-menu .divider {\n  background-color: rgba(229, 229, 229, 0.12);\n}\n.dropdown-menu li {\n  overflow: hidden;\n  position: relative;\n}\n.dropdown-menu li a:hover {\n  background-color: transparent;\n  color: #009688;\n}\n.alert {\n  border: 0;\n  border-radius: 0;\n}\n.alert,\n.alert.alert-default {\n  background-color: rgba(255,255,255, 0.84);\n  color: rgba(255,255,255, 0.84);\n}\n.alert a,\n.alert.alert-default a,\n.alert .alert-link,\n.alert.alert-default .alert-link {\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-inverse {\n  background-color: #3f51b5;\n  color: #ffffff;\n}\n.alert.alert-inverse a,\n.alert.alert-inverse .alert-link {\n  color: #ffffff;\n}\n.alert.alert-primary {\n  background-color: #009688;\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-primary a,\n.alert.alert-primary .alert-link {\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-success {\n  background-color: #4caf50;\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-success a,\n.alert.alert-success .alert-link {\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-info {\n  background-color: #03a9f4;\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-info a,\n.alert.alert-info .alert-link {\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-warning {\n  background-color: #ff5722;\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-warning a,\n.alert.alert-warning .alert-link {\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-danger {\n  background-color: #f44336;\n  color: rgba(255,255,255, 0.84);\n}\n.alert.alert-danger a,\n.alert.alert-danger .alert-link {\n  color: rgba(255,255,255, 0.84);\n}\n.alert-info,\n.alert-danger,\n.alert-warning,\n.alert-success {\n  color: rgba(255,255,255, 0.84);\n}\n.alert-default a,\n.alert-default .alert-link {\n  color: rgba(0,0,0, 0.87);\n}\n.progress {\n  height: 4px;\n  border-radius: 0;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  background: #c8c8c8;\n}\n.progress .progress-bar {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.progress .progress-bar,\n.progress .progress-bar.progress-bar-default {\n  background-color: #009688;\n}\n.progress .progress-bar.progress-bar-inverse {\n  background-color: #3f51b5;\n}\n.progress .progress-bar.progress-bar-primary {\n  background-color: #009688;\n}\n.progress .progress-bar.progress-bar-success {\n  background-color: #4caf50;\n}\n.progress .progress-bar.progress-bar-info {\n  background-color: #03a9f4;\n}\n.progress .progress-bar.progress-bar-warning {\n  background-color: #ff5722;\n}\n.progress .progress-bar.progress-bar-danger {\n  background-color: #f44336;\n}\n.text-warning {\n  color: #ff5722;\n}\n.text-primary {\n  color: #009688;\n}\n.text-danger {\n  color: #f44336;\n}\n.text-success {\n  color: #4caf50;\n}\n.text-info {\n  color: #03a9f4;\n}\n.nav-tabs {\n  background: #009688;\n}\n.nav-tabs > li > a {\n  color: #FFFFFF;\n  border: 0;\n  margin: 0;\n}\n.nav-tabs > li > a:hover {\n  background-color: transparent;\n  border: 0;\n}\n.nav-tabs > li > a,\n.nav-tabs > li > a:hover,\n.nav-tabs > li > a:focus {\n  background-color: transparent !important;\n  border: 0 !important;\n  color: #FFFFFF !important;\n  font-weight: 500;\n}\n.nav-tabs > li.disabled > a,\n.nav-tabs > li.disabled > a:hover {\n  color: rgba(255, 255, 255, 0.5);\n}\n.popover,\n.tooltip-inner {\n  color: #ececec;\n  line-height: 1em;\n  background: rgba(101, 101, 101, 0.9);\n  border: none;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);\n          box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);\n}\n.tooltip,\n.tooltip.in {\n  opacity: 1;\n}\n.popover .arrow,\n.tooltip .arrow,\n.popover .tooltip-arrow,\n.tooltip .tooltip-arrow {\n  display: none;\n}\n.card {\n  /***** Make height equal to width (http://stackoverflow.com/a/6615994) ****/\n  display: inline-block;\n  position: relative;\n  width: 100%;\n  /**************************************************************************/\n  border-radius: 2px;\n  color: rgba(0,0,0, 0.87);\n  background: #fff;\n  -webkit-box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n          box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n}\n.card .card-height-indicator {\n  margin-top: 100%;\n}\n.card .card-content {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n}\n.card .card-image {\n  height: 60%;\n  position: relative;\n  overflow: hidden;\n}\n.card .card-image img {\n  width: 100%;\n  height: 100%;\n  border-top-left-radius: 2px;\n  border-top-right-radius: 2px;\n  pointer-events: none;\n}\n.card .card-image .card-image-headline {\n  position: absolute;\n  bottom: 16px;\n  left: 18px;\n  color: #fff;\n  font-size: 2em;\n}\n.card .card-body {\n  height: 30%;\n  padding: 18px;\n}\n.card .card-footer {\n  height: 10%;\n  padding: 18px;\n}\n.card .card-footer button {\n  margin: 0 !important;\n  position: relative;\n  bottom: 25px;\n  width: auto;\n}\n.card .card-footer button:first-child {\n  left: -15px;\n}\n.modal-content {\n  -webkit-box-shadow: 0 27px 24px 0 rgba(0, 0, 0, 0.2), 0 40px 77px 0 rgba(0, 0, 0, 0.22);\n          box-shadow: 0 27px 24px 0 rgba(0, 0, 0, 0.2), 0 40px 77px 0 rgba(0, 0, 0, 0.22);\n  border-radius: 2px;\n  border: none;\n}\n.modal-content .modal-header {\n  border-bottom: none;\n  padding-top: 24px;\n  padding-right: 24px;\n  padding-bottom: 0;\n  padding-left: 24px;\n}\n.modal-content .modal-body {\n  padding-top: 24px;\n  padding-right: 24px;\n  padding-bottom: 16px;\n  padding-left: 24px;\n}\n.modal-content .modal-footer {\n  border-top: none;\n  padding: 7px;\n}\n.modal-content .modal-footer button {\n  margin: 0;\n  padding-left: 16px;\n  padding-right: 16px;\n  width: auto;\n}\n.modal-content .modal-footer button.pull-left {\n  padding-left: 5px;\n  padding-right: 5px;\n  position: relative;\n  left: -5px;\n}\n.modal-content .modal-footer button + button {\n  margin-bottom: 16px;\n}\n.modal-content .modal-body + .modal-footer {\n  padding-top: 0;\n}\n.modal-backdrop {\n  background: rgba(0, 0, 0, 0.3);\n}\n.panel {\n  border-radius: 2px;\n  border: 0;\n  -webkit-box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);\n          box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);\n}\n.panel > .panel-heading,\n.panel.panel-default > .panel-heading {\n  background-color: #eeeeee;\n}\n.panel.panel-inverse > .panel-heading {\n  background-color: #3f51b5;\n}\n.panel.panel-primary > .panel-heading {\n  background-color: #009688;\n}\n.panel.panel-success > .panel-heading {\n  background-color: #4caf50;\n}\n.panel.panel-info > .panel-heading {\n  background-color: #03a9f4;\n}\n.panel.panel-warning > .panel-heading {\n  background-color: #ff5722;\n}\n.panel.panel-danger > .panel-heading {\n  background-color: #f44336;\n}\n[class*=\"panel-\"] > .panel-heading {\n  color: rgba(255,255,255, 0.84);\n  border: 0;\n}\n.panel-default > .panel-heading,\n.panel:not([class*=\"panel-\"]) > .panel-heading {\n  color: rgba(0,0,0, 0.87);\n}\n.panel-footer {\n  background-color: #eeeeee;\n}\nhr.on-dark {\n  color: #1a1a1a;\n}\nhr.on-light {\n  color: #ffffff;\n}\n@media (-webkit-min-device-pixel-ratio: 0.75), (min--moz-device-pixel-ratio: 0.75), (-o-device-pixel-ratio: 3/4), (min-device-pixel-ratio: 0.75), (-o-min-device-pixel-ratio: 3/4), (min-resolution: 0.75dppx), (-webkit-min-device-pixel-ratio: 1.25), (-o-min-device-pixel-ratio: 5/4), (min-resolution: 120dpi) {\n  hr {\n    height: 0.75px;\n  }\n}\n@media (-webkit-min-device-pixel-ratio: 1), (min--moz-device-pixel-ratio: 1), (-o-device-pixel-ratio: 1), (min-device-pixel-ratio: 1), (-o-min-device-pixel-ratio: 1/1), (min-resolution: 1dppx), (-webkit-min-device-pixel-ratio: 1.6666666666666667), (-o-min-device-pixel-ratio: 5/3), (min-resolution: 160dpi) {\n  hr {\n    height: 1px;\n  }\n}\n@media (-webkit-min-device-pixel-ratio: 1.33), (min--moz-device-pixel-ratio: 1.33), (-o-device-pixel-ratio: 133/100), (min-device-pixel-ratio: 1.33), (-o-min-device-pixel-ratio: 133/100), (min-resolution: 1.33dppx), (-webkit-min-device-pixel-ratio: 2.21875), (-o-min-device-pixel-ratio: 71/32), (min-resolution: 213dpi) {\n  hr {\n    height: 1.333px;\n  }\n}\n@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-device-pixel-ratio: 3/2), (min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx), (-webkit-min-device-pixel-ratio: 2.5), (-o-min-device-pixel-ratio: 5/2), (min-resolution: 240dpi) {\n  hr {\n    height: 1.5px;\n  }\n}\n@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-device-pixel-ratio: 2/1), (min-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 3.9583333333333335), (-o-min-device-pixel-ratio: 95/24), (min-resolution: 380dpi) {\n  hr {\n    height: 2px;\n  }\n}\n@media (-webkit-min-device-pixel-ratio: 3), (min--moz-device-pixel-ratio: 3), (-o-device-pixel-ratio: 3/1), (min-device-pixel-ratio: 3), (-o-min-device-pixel-ratio: 3/1), (min-resolution: 3dppx), (-webkit-min-device-pixel-ratio: 5), (-o-min-device-pixel-ratio: 5/1), (min-resolution: 480dpi) {\n  hr {\n    height: 3px;\n  }\n}\n@media (-webkit-min-device-pixel-ratio: 4), (min--moz-device-pixel-ratio: 4), (-o-device-pixel-ratio: 4/1), (min-device-pixel-ratio: 3), (-o-min-device-pixel-ratio: 4/1), (min-resolution: 4dppx), (-webkit-min-device-pixel-ratio: 6.666666666666667), (-o-min-device-pixel-ratio: 20/3), (min-resolution: 640dpi) {\n  hr {\n    height: 4px;\n  }\n}\n* {\n  -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n  -webkit-tap-highlight-color: transparent;\n}\n*:focus {\n  outline: 0;\n}\n.snackbar {\n  background-color: #323232;\n  color: rgba(255,255,255, 0.84);\n  font-size: 14px;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);\n          box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);\n  height: 0;\n  -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;\n       -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;\n          transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;\n  -webkit-transform: translateY(200%);\n      -ms-transform: translateY(200%);\n       -o-transform: translateY(200%);\n          transform: translateY(200%);\n}\n.snackbar.snackbar-opened {\n  padding: 14px 15px;\n  margin-bottom: 20px;\n  height: auto;\n  -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;\n       -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;\n          transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;\n  -webkit-transform: none;\n      -ms-transform: none;\n       -o-transform: none;\n          transform: none;\n}\n.snackbar.toast {\n  border-radius: 200px;\n}\n.noUi-target,\n.noUi-target * {\n  -webkit-touch-callout: none;\n  -ms-touch-action: none;\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n.noUi-base {\n  width: 100%;\n  height: 100%;\n  position: relative;\n}\n.noUi-origin {\n  position: absolute;\n  right: 0;\n  top: 0;\n  left: 0;\n  bottom: 0;\n}\n.noUi-handle {\n  position: relative;\n  z-index: 1;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n.noUi-stacking .noUi-handle {\n  z-index: 10;\n}\n.noUi-state-tap .noUi-origin {\n  -webkit-transition: left 0.3s, top 0.3s;\n       -o-transition: left 0.3s, top 0.3s;\n          transition: left 0.3s, top 0.3s;\n}\n.noUi-state-drag * {\n  cursor: inherit !important;\n}\n.noUi-horizontal {\n  height: 10px;\n}\n.noUi-handle {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  width: 12px;\n  height: 12px;\n  left: -10px;\n  top: -5px;\n  cursor: ew-resize;\n  border-radius: 100%;\n  -webkit-transition: all 0.2s ease-out;\n       -o-transition: all 0.2s ease-out;\n          transition: all 0.2s ease-out;\n  border: 1px solid;\n}\n.noUi-vertical .noUi-handle {\n  margin-left: 5px;\n  cursor: ns-resize;\n}\n.noUi-horizontal.noUi-extended {\n  padding: 0 15px;\n}\n.noUi-horizontal.noUi-extended .noUi-origin {\n  right: -15px;\n}\n.noUi-background {\n  height: 2px;\n  margin: 20px 0;\n}\n.noUi-origin {\n  margin: 0;\n  border-radius: 0;\n  height: 2px;\n  background: #c8c8c8;\n}\n.noUi-origin[style^=\"left: 0\"] .noUi-handle {\n  background-color: #fff;\n  border: 2px solid #c8c8c8;\n}\n.noUi-origin[style^=\"left: 0\"] .noUi-handle.noUi-active {\n  border-width: 1px;\n}\n.noUi-target {\n  border-radius: 2px;\n}\n.noUi-horizontal {\n  height: 2px;\n  margin: 15px 0;\n}\n.noUi-vertical {\n  height: 100%;\n  width: 2px;\n  margin: 0 15px;\n  display: inline-block;\n}\n.noUi-handle.noUi-active {\n  -webkit-transform: scale3d(2.5, 2.5, 1);\n          transform: scale3d(2.5, 2.5, 1);\n}\n[disabled].noUi-slider {\n  opacity: 0.5;\n}\n[disabled] .noUi-handle {\n  cursor: not-allowed;\n}\n.slider {\n  background: #c8c8c8;\n}\n.slider.noUi-connect,\n.slider.slider-default.noUi-connect {\n  background-color: #009688;\n}\n.slider.slider-inverse.noUi-connect {\n  background-color: #3f51b5;\n}\n.slider.slider-primary.noUi-connect {\n  background-color: #009688;\n}\n.slider.slider-success.noUi-connect {\n  background-color: #4caf50;\n}\n.slider.slider-info.noUi-connect {\n  background-color: #03a9f4;\n}\n.slider.slider-warning.noUi-connect {\n  background-color: #ff5722;\n}\n.slider.slider-danger.noUi-connect {\n  background-color: #f44336;\n}\n.slider .noUi-connect,\n.slider.slider-default .noUi-connect {\n  background-color: #009688;\n}\n.slider.slider-inverse .noUi-connect {\n  background-color: #3f51b5;\n}\n.slider.slider-primary .noUi-connect {\n  background-color: #009688;\n}\n.slider.slider-success .noUi-connect {\n  background-color: #4caf50;\n}\n.slider.slider-info .noUi-connect {\n  background-color: #03a9f4;\n}\n.slider.slider-warning .noUi-connect {\n  background-color: #ff5722;\n}\n.slider.slider-danger .noUi-connect {\n  background-color: #f44336;\n}\n.slider .noUi-handle,\n.slider.slider-default .noUi-handle {\n  background-color: #009688;\n}\n.slider.slider-inverse .noUi-handle {\n  background-color: #3f51b5;\n}\n.slider.slider-primary .noUi-handle {\n  background-color: #009688;\n}\n.slider.slider-success .noUi-handle {\n  background-color: #4caf50;\n}\n.slider.slider-info .noUi-handle {\n  background-color: #03a9f4;\n}\n.slider.slider-warning .noUi-handle {\n  background-color: #ff5722;\n}\n.slider.slider-danger .noUi-handle {\n  background-color: #f44336;\n}\n.slider .noUi-handle,\n.slider.slider-default .noUi-handle {\n  border-color: #009688;\n}\n.slider.slider-inverse .noUi-handle {\n  border-color: #3f51b5;\n}\n.slider.slider-primary .noUi-handle {\n  border-color: #009688;\n}\n.slider.slider-success .noUi-handle {\n  border-color: #4caf50;\n}\n.slider.slider-info .noUi-handle {\n  border-color: #03a9f4;\n}\n.slider.slider-warning .noUi-handle {\n  border-color: #ff5722;\n}\n.slider.slider-danger .noUi-handle {\n  border-color: #f44336;\n}\n.selectize-control.single,\n.selectize-control.multi {\n  padding: 0;\n}\n.selectize-control.single .selectize-input,\n.selectize-control.multi .selectize-input,\n.selectize-control.single .selectize-input.input-active,\n.selectize-control.multi .selectize-input.input-active {\n  cursor: text;\n  background: transparent;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  border: 0;\n  padding: 0;\n  height: 100%;\n  font-size: 14px;\n  line-height: 30px;\n}\n.selectize-control.single .selectize-input .has-items,\n.selectize-control.multi .selectize-input .has-items,\n.selectize-control.single .selectize-input.input-active .has-items,\n.selectize-control.multi .selectize-input.input-active .has-items {\n  padding: 0;\n}\n.selectize-control.single .selectize-input:after,\n.selectize-control.multi .selectize-input:after,\n.selectize-control.single .selectize-input.input-active:after,\n.selectize-control.multi .selectize-input.input-active:after {\n  right: 5px;\n  position: absolute;\n  font-size: 7px;\n  content: \"\\e894\";\n  font-family: \"Material-Design-Icons\";\n  speak: none;\n  font-style: normal;\n  font-weight: normal;\n  font-variant: normal;\n  text-transform: none;\n  line-height: 4;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.selectize-control.single .selectize-input input,\n.selectize-control.multi .selectize-input input,\n.selectize-control.single .selectize-input.input-active input,\n.selectize-control.multi .selectize-input.input-active input {\n  font-size: 14px;\n  outline: 0;\n  border: 0;\n  background: transparent;\n}\n.selectize-control.single .selectize-input.label-floating-fix input,\n.selectize-control.multi .selectize-input.label-floating-fix input,\n.selectize-control.single .selectize-input.input-active.label-floating-fix input,\n.selectize-control.multi .selectize-input.input-active.label-floating-fix input {\n  opacity: 0;\n}\n.selectize-control.single .selectize-input > div,\n.selectize-control.multi .selectize-input > div,\n.selectize-control.single .selectize-input.input-active > div,\n.selectize-control.multi .selectize-input.input-active > div,\n.selectize-control.single .selectize-input > .item,\n.selectize-control.multi .selectize-input > .item,\n.selectize-control.single .selectize-input.input-active > .item,\n.selectize-control.multi .selectize-input.input-active > .item {\n  display: inline-block;\n  margin: 0 8px 3px 0;\n  padding: 0;\n  background: transparent;\n  border: 0;\n}\n.selectize-control.single .selectize-input > div:after,\n.selectize-control.multi .selectize-input > div:after,\n.selectize-control.single .selectize-input.input-active > div:after,\n.selectize-control.multi .selectize-input.input-active > div:after,\n.selectize-control.single .selectize-input > .item:after,\n.selectize-control.multi .selectize-input > .item:after,\n.selectize-control.single .selectize-input.input-active > .item:after,\n.selectize-control.multi .selectize-input.input-active > .item:after {\n  content: \",\";\n}\n.selectize-control.single .selectize-input > div:last-of-type:after,\n.selectize-control.multi .selectize-input > div:last-of-type:after,\n.selectize-control.single .selectize-input.input-active > div:last-of-type:after,\n.selectize-control.multi .selectize-input.input-active > div:last-of-type:after,\n.selectize-control.single .selectize-input > .item:last-of-type:after,\n.selectize-control.multi .selectize-input > .item:last-of-type:after,\n.selectize-control.single .selectize-input.input-active > .item:last-of-type:after,\n.selectize-control.multi .selectize-input.input-active > .item:last-of-type:after {\n  content: \"\";\n}\n.selectize-control.single .selectize-input > div.active,\n.selectize-control.multi .selectize-input > div.active,\n.selectize-control.single .selectize-input.input-active > div.active,\n.selectize-control.multi .selectize-input.input-active > div.active,\n.selectize-control.single .selectize-input > .item.active,\n.selectize-control.multi .selectize-input > .item.active,\n.selectize-control.single .selectize-input.input-active > .item.active,\n.selectize-control.multi .selectize-input.input-active > .item.active {\n  font-weight: bold;\n  background: transparent;\n  border: 0;\n}\n.selectize-control.single .selectize-dropdown,\n.selectize-control.multi .selectize-dropdown {\n  position: absolute;\n  z-index: 1000;\n  border: 0;\n  width: 100% !important;\n  left: 0 !important;\n  height: auto;\n  background-color: #FFF;\n  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\n          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\n  border-radius: 2px;\n  padding: 0;\n  margin-top: 3px;\n}\n.selectize-control.single .selectize-dropdown .active,\n.selectize-control.multi .selectize-dropdown .active {\n  background-color: inherit;\n}\n.selectize-control.single .selectize-dropdown .highlight,\n.selectize-control.multi .selectize-dropdown .highlight {\n  background-color: #d5d8ff;\n}\n.selectize-control.single .selectize-dropdown .selected,\n.selectize-control.multi .selectize-dropdown .selected,\n.selectize-control.single .selectize-dropdown .selected.active,\n.selectize-control.multi .selectize-dropdown .selected.active {\n  background-color: #EEEEEE;\n}\n.selectize-control.single .selectize-dropdown [data-selectable],\n.selectize-control.multi .selectize-dropdown [data-selectable],\n.selectize-control.single .selectize-dropdown .optgroup-header,\n.selectize-control.multi .selectize-dropdown .optgroup-header {\n  padding: 10px 20px;\n  cursor: pointer;\n}\n.selectize-control.single .dropdown-active ~ .selectize-dropdown,\n.selectize-control.multi .dropdown-active ~ .selectize-dropdown {\n  display: block;\n}\n.dropdownjs::after {\n  right: 5px;\n  top: 3px;\n  font-size: 25px;\n  position: absolute;\n  font-family: 'Material Icons';\n  font-style: normal;\n  font-weight: 400;\n  content: \"\\e5c5\";\n  pointer-events: none;\n  color: #757575;\n}\n/*# sourceMappingURL=bootstrap-material-design.css.map */"
  },
  {
    "path": "src/styles/material-design/css/ripples.css",
    "content": ".withripple {\n  position: relative;\n}\n.ripple-container {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  border-radius: inherit;\n  pointer-events: none;\n}\n.ripple {\n  position: absolute;\n  width: 20px;\n  height: 20px;\n  margin-left: -10px;\n  margin-top: -10px;\n  border-radius: 100%;\n  background-color: #000;\n  background-color: rgba(0, 0, 0, 0.05);\n  -webkit-transform: scale(1);\n      -ms-transform: scale(1);\n       -o-transform: scale(1);\n          transform: scale(1);\n  -webkit-transform-origin: 50%;\n      -ms-transform-origin: 50%;\n       -o-transform-origin: 50%;\n          transform-origin: 50%;\n  opacity: 0;\n  pointer-events: none;\n}\n.ripple.ripple-on {\n  -webkit-transition: opacity 0.15s ease-in 0s, -webkit-transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;\n       -o-transition: opacity 0.15s ease-in 0s, -o-transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;\n          transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;\n  opacity: 0.1;\n}\n.ripple.ripple-out {\n  -webkit-transition: opacity 0.1s linear 0s !important;\n       -o-transition: opacity 0.1s linear 0s !important;\n          transition: opacity 0.1s linear 0s !important;\n  opacity: 0;\n}\n/*# sourceMappingURL=ripples.css.map */"
  },
  {
    "path": "src/styles/style.css",
    "content": "/*@import url(https://fonts.googleapis.com/css?family=Montserrat);*/\n\n/*@font-face {*/\n/*font-family: 'Montserrat';*/\n/*font-style: normal;*/\n/*font-weight: 400;*/\n/*src: local('Montserrat-Regular'), url(https://fonts.gstatic.com/s/montserrat/v7/zhcz-_WihjSQC0oHJ9TCYPk_vArhqVIZ0nv9q090hN8.woff2) format('woff2');*/\n/*unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;*/\n/*}*/\n\n@media print {\n    @page { margin: 0; }\n    body { margin: 1.6cm; }\n}\n\n@font-face {\n    font-family: 'Montserrat';\n    font-style: normal;\n    font-weight: 400;\n    src: local('Montserrat-Regular');\n    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;\n}\n\n* {\n    font-family: 'Montserrat', arial;\n    font-size: 13px;\n}\n\nselect {\n    border-radius: 0 !important;\n}\n\nbutton, a {\n    border-radius: 0 !important;\n}\n\nhtml,\nbody {\n    font-family: 'Raleway', 'arial';\n    height: 100%;\n    background-color: #f3f3f4;\n    overflow-x: hidden;\n    padding-top: 25px;\n}\n\na {\n    text-decoration: none !important;\n}\n\n.faHeader {\n    font-size: 1.9em !important;\n    color: #bababa;\n    position: relative;\n    top: -20px;\n}\n\n#loading {\n    position: relative;\n    top: 100px;\n    background-color: #222223;\n    text-align: center;\n    width: 100%;\n    height: 40%;\n}\n\n#loading img {\n    height: 200px;\n    width: 500px;\n    padding-top: 100px;\n}\n\n#sceneCanvasContainer {\n    width: 100%;\n    height: 100%;\n    padding-top: 100px;\n    -webkit-user-select: none;\n    /* opacity: 0.01; */\n}\n\n.appMenu {\n    padding: 0px;\n    margin: 0px;\n    background-color: #3e3f48;\n    border-right: 1px solid #dddddd;\n    font-size: 1.1em;\n    /* enable following for dropshadow on appNavPanel */\n    /*-webkit-box-shadow: 2px 0px 5px 0px rgba(50, 50, 50, 0.75);\n    -moz-box-shadow: 2px 0px 5px 0px rgba(50, 50, 50, 0.75);\n    box-shadow: 2px 0px 5px 0px rgba(50, 50, 50, 0.75);*/\n    z-index: 999;\n}\n\n.appMenu li {\n    cursor: pointer;\n    background-color: #3e3f48;\n    border-color: #3e3f48;\n    padding-top: 15px;\n    padding-bottom: 15px;\n    border-right: 0px;\n}\n\n.appMenu span, #appMenu i {\n    color: white;\n}\n\n.appMenu i {\n    padding: 5px;\n    color: #cbcbcb;\n}\n\n#angularText .flipcard {\n    padding-top: 2px;\n}\n\n#appNavigatorWasp {\n    position: fixed;\n    padding: 0px;\n    margin: 0px;\n    border-right: 1px solid #dddddd;\n}\n\n#appNavigatorWasp li {\n    cursor: pointer;\n    padding-top: 15px;\n    padding-bottom: 15px;\n    border-right: 0px;\n}\n\n#appNavigatorWasp li:hover {\n    /*bootstrap theme color*/;\n    background-color: #428bca;\n    color: white;\n}\n\n#appNavigatorWasp {\n    padding: 0px;\n    margin: 0px;\n    border-right: 1px solid #dddddd;\n}\n\n#appNavigatorWasp li {\n    cursor: pointer;\n    padding-top: 15px;\n    padding-bottom: 15px;\n    border-right: 0px;\n}\n\n#appNavigatorWasp li:hover {\n    /*bootstrap theme color*/;\n    background-color: #428bca;\n    color: white;\n}\n\n#popModal {\n    padding: 20px;\n}\n\n.noScroll {\n    overflow: hidden;\n}\n\n.noYscroll {\n    overflow-y: hidden !important;\n}\n\n.noSpace {\n    padding: 0;\n    margin: 0;\n\n}\n\n.yScroll {\n    overflow-y: scroll;\n    height: 100%;\n}\n\n.appList {\n    padding-right: 10px;\n}\n\n.appList .openProps {\n    float: right;\n    position: relative;\n    top: -45px;\n}\n\n.form-signin {\n    max-width: 330px;\n    padding: 15px;\n    margin: 0 auto;\n}\n\n.form-signin .form-signin-heading,\n.form-signin .checkbox {\n    margin-bottom: 10px;\n}\n\n.form-signin .checkbox {\n    font-weight: normal;\n}\n\n.form-signin .form-control {\n    position: relative;\n    font-size: 16px;\n    height: auto;\n    padding: 10px;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.form-signin .form-control:focus {\n    z-index: 2;\n}\n\n.form-signin input[type=\"text\"] {\n    margin-bottom: -1px;\n    border-bottom-left-radius: 0;\n    border-bottom-right-radius: 0;\n}\n\n.form-signin input[type=\"password\"] {\n    margin-bottom: 10px;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n}\n\n.centerElement {\n    margin: 0 auto;\n}\n\n.navbar-nav {\n    display: none;\n}\n\n.alignTextLeft {\n    text-align: left;\n}\n\n.alignTextCenter {\n    text-align: center;\n}\n\n.navicons {\n    font-size: 1.2em;\n    position: relative;\n    top: 2px;\n    padding-right: 5px;\n}\n\n.activated {\n    background-color: #428bca;\n    color: white;\n}\n\n.list-group-item:first-child {\n    border-top-right-radius: 0px;\n    border-top-left-radius: 0px;\n}\n\n.page {\n    position: absolute;\n    padding: 12px;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n}\n\n/************************************\n Hardware accelerated horizontal\n/************************************\n\n/*\n.page.left {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n}\n.page.center {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n}\n.page.right {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n}\n.page.transition {\n    -webkit-transition-duration: .25s;\n    transition-duration: .25s;\n}\n*/\n\n/************************************\n Software accelerated horizontal\n/************************************\n*/\n\n.page.left {\n    left: -200%;\n}\n\n.page.center {\n    left: 0;\n}\n\n.page.right {\n    left: 200%;\n}\n\n.page.transition {\n    -webkit-transition-duration: .50s;\n    transition-duration: .50s;\n}\n\n/************************************\nSoftware accelerated vertical\n/************************************\n\n/*\n.page.left {\n    top: -100%;\n}\n.page.center {\n    top: 0;\n}\n.page.right {\n    top: 100%;\n}\n.page.transition {\n    -webkit-transition-duration: 3.25s;\n    transition-duration: 0.65s;\n}\n*/\n\n/************************************\n Hardware accelerated vertical\n/************************************\n\n/*\n.page.left {\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n}\n.page.center {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n}\n.page.right {\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n}\n.page.transition {\n    -webkit-transition-duration: 3.25s;\n    transition-duration: 3.25s;\n}\n*/\n\n/*#logoContainer {*/\n/*position: relative;*/\n/*top: -3px;*/\n/*float: left;*/\n/*padding: 0;*/\n/*margin: 0;*/\n/*}*/\n\n.clearFloat {\n    clear: both;\n}\n\n.hrThin {\n    margin-top: 8px;\n    margin-bottom: 8px;\n}\n\n/* material switches */\n\n.material-switch {\n    padding-left: 7px;\n}\n\n.material-switch > input[type=\"checkbox\"] {\n    display: none;\n}\n\n.material-switch > label {\n    cursor: pointer;\n    height: 0px;\n    position: relative;\n    width: 40px;\n}\n\n.material-switch > label::before {\n    background: rgb(0, 0, 0);\n    border-radius: 8px;\n    content: '';\n    height: 16px;\n    margin-top: -8px;\n    position: absolute;\n    opacity: 0.3;\n    transition: all 0.4s ease-in-out;\n    width: 40px;\n}\n\n.material-switch > label::after {\n    background: rgb(255, 255, 255);\n    border-radius: 16px;\n    box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);\n    content: '';\n    height: 24px;\n    left: -4px;\n    margin-top: -8px;\n    position: absolute;\n    top: -4px;\n    transition: all 0.3s ease-in-out;\n    width: 24px;\n}\n\n.material-switch > input[type=\"checkbox\"]:checked + label::before {\n    background: inherit;\n    opacity: 0.5;\n}\n\n.material-switch > input[type=\"checkbox\"]:checked + label::after {\n    background: inherit;\n    left: 20px;\n}\n\n.flip {\n    -webkit-perspective: 800px;\n    -ms-perspective: 800px;\n    -moz-perspective: 800px;\n\n    width: 39px;\n    height: 25px;\n    position: relative;\n    /*margin: 50px auto;*/\n}\n\n.flip .flipcard.flipped {\n    -webkit-transform: rotatey(-180deg);\n    -ms-transform: rotatey(-180deg);\n    -moz-transform: rotatey(-180deg);\n}\n\n.flip .flipcard {\n    width: 39px;\n    height: 25px;\n    -webkit-transform-style: preserve-3d;\n    -ms-transform-style: preserve-3d;\n    -moz-transform-style: preserve-3d;\n\n    -webkit-transition: 0.5s;\n    -ms-transition: 0.5s;\n    -moz-transition: 0.5s;\n}\n\n.flip .flipcard .face {\n    width: 39px;\n    height: 25px;\n    position: absolute;\n    -webkit-backface-visibility: hidden;\n    -ms-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    z-index: 2;\n    font-size: 3em;\n    text-align: center;\n    line-height: 39px;\n}\n\n.flip .flipcard .front {\n    position: absolute;\n    z-index: 1;\n    cursor: pointer;\n}\n\n.flip .flipcard .back {\n    -webkit-transform: rotatex(-180deg);\n    -ms-transform: rotatex(-180deg);\n    -moz-transform: rotatex(-180deg);\n    cursor: pointer;\n}\n\n.container {\n    height: 100%;\n}\n\n.fill {\n    height: 100%;\n    min-height: 100%;\n    /*background-color: #990000;*/\n    /*color: #efefef;*/\n}\n\n.fill_less {\n    height: 95%;\n    min-height: 95%;\n    /*background-color: #990000;*/\n    /*color: #efefef;*/\n}\n\n.fill_scroll {\n    overflow-y: scroll;\n    overflow-x: hidden;\n    height: 100%;\n    min-height: 100%;\n    padding-bottom: 50px;\n}\n\n/** SimpleTable **/\n\n.selectedTr {\n    background-color: #ABD3FB !important;\n}\n\n.simpleGridRecord:nth-child(odd) {\n    background-color: #eee;\n}\n\n.simpleGridRecord:nth-child(even) {\n    background-color: #fff;\n}\n\n.login-page {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    overflow: auto;\n    background: #222;\n    text-align: center;\n    color: #fff;\n    padding: 3em;\n}\n\n.login-page .col-lg-4 {\n    padding: 0;\n}\n\n.login-page .input-lg {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 0;\n}\n\n.login-page .input-underline {\n    background: 0 0;\n    border: none;\n    box-shadow: none;\n    border-bottom: 2px solid rgba(255, 255, 255, 0.5);\n    color: #FFF;\n    border-radius: 0;\n}\n\n.login-page .input-underline:focus {\n    border-bottom: 2px solid #fff;\n    box-shadow: none;\n}\n\n.login-page .rounded-btn {\n    -webkit-border-radius: 50px;\n    border-radius: 50px;\n    color: rgba(255, 255, 255, 0.8);\n    background: #222;\n    border: 2px solid rgba(255, 255, 255, 0.8);\n    font-size: 18px;\n    line-height: 40px;\n    padding: 0 25px;\n}\n\n.login-page .rounded-btn:hover, .login-page .rounded-btn:focus, .login-page .rounded-btn:active, .login-page .rounded-btn:visited {\n    color: white;\n    border: 2px solid white;\n    outline: none;\n}\n\n.login-page h1 {\n    font-weight: 300;\n    margin-top: 20px;\n    margin-bottom: 10px;\n    font-size: 36px;\n}\n\n.login-page h1 small {\n    color: rgba(255, 255, 255, 0.7);\n}\n\n.login-page .form-group {\n    padding: 8px 0;\n}\n\n.login-page .form-group input::-webkit-input-placeholder {\n    color: rgba(255, 255, 255, 0.6) !important;\n}\n\n.login-page .form-group input:-moz-placeholder {\n    /* Firefox 18- */\n    color: rgba(255, 255, 255, 0.6) !important;\n}\n\n.login-page .form-group input::-moz-placeholder {\n    /* Firefox 19+ */\n    color: rgba(255, 255, 255, 0.6) !important;\n}\n\n.login-page .form-group input:-ms-input-placeholder {\n    color: rgba(255, 255, 255, 0.6) !important;\n}\n\n.login-page .form-content {\n    padding: 40px 0;\n}\n\n.orange {\n    background-color: #ec971f;\n}\n\n.green {\n    background-color: #3f913f;\n}\n\n.blue {\n    background-color: #31b0d5;\n}\n\n.red {\n    background-color: #c9302c;\n}\n\n.paddingCeilingFloor20 {\n    padding-top: 20px;\n    padding-bottom: 20px;\n}\n\n.marginsCeilingFloor20 {\n    padding-top: 20px;\n    padding-bottom: 20px;\n}\n\nsmall {\n    font-size: 0.9em;\n    display: block;\n}\n\n.panel-title {\n    font-size: 0.9em;\n}\n\n.material-switch {\n    position: relative;\n    top: -10px\n}\n\n/**\n for hovers see: http://ianlunn.github.io/Hover/\n**/\n.hvr-grow-shadow {\n    display: inline-block;\n    vertical-align: middle;\n    -webkit-transform: perspective(1px) translateZ(0);\n    transform: perspective(1px) translateZ(0);\n    box-shadow: 0 0 1px transparent;\n    -webkit-transition-duration: 0.3s;\n    transition-duration: 0.3s;\n    -webkit-transition-property: box-shadow, transform;\n    transition-property: box-shadow, transform;\n}\n\n.hvr-grow-shadow:hover, .hvr-grow-shadow:focus, .hvr-grow-shadow:active {\n    box-shadow: 0 10px 10px -10px rgba(0, 0, 0, 0.5);\n    -webkit-transform: scale(1.1);\n    transform: scale(1.1);\n}\n\n@media (max-width: 1200px) {\n    .responsive-pad-top {\n        margin-top: 50px !important;\n        padding-top: 50px !important;\n    }\n}\n\n@media (min-width: 767px) {\n    .responsive-pad-right {\n        margin-right: 60px !important;\n    }\n}\n\n@media (min-width: 768px) {\n    .responsive-pad-right {\n        margin-right: 10px !important;\n    }\n}\n\n@media (min-width: 992px) {\n    .responsive-pad-right {\n        margin-right: 30px !important;\n    }\n}\n\n@media (min-width: 1900px) {\n    .responsive-pad-right {\n        margin-right: 30px !important;\n    }\n}\n\na.list-group-item:focus, button.list-group-item:focus {\n    background-color: #c4c4c4;\n}\n\n.offline {\n    color: red;\n}\n\n.selectedItem {\n    background-color: #c4c4c4 !important;\n}\n\n.dottedHR {\n    height: 6px;\n    width: 1500px;\n    opacity: 0.6;\n    position: relative;\n    border-top: 12px dotted #c1c1c1;\n    padding-bottom: 7px;\n    top: 20px;\n}\n\n.bootstrap-timepicker-widget a.btn, .bootstrap-timepicker-widget input {\n    border-radius: 0px;\n}\n\n/************************************\n ColorPicker\n ************************************/\n\n.colorpicker {\n    width: 356px;\n    height: 176px;\n    overflow: hidden;\n    position: absolute;\n    background: url(\"../assets/custom_background.png\");\n    font-family: Arial, Helvetica, sans-serif;\n    display: none;\n    z-index: 9999;\n}\n\n.color-chooser {\n    width: 30px;\n    height: 30px;\n    margin-top: 5px;\n    background: url(\"../assets/select.png\") center;\n}\n\n.color-chooser > div {\n    width: 30px;\n    height: 30px;\n    background: url(\"../assets/select.png\") center;\n}\n\n.colorpicker_color {\n    width: 150px;\n    height: 150px;\n    left: 14px;\n    top: 13px;\n    position: absolute;\n    background: #f00;\n    overflow: hidden;\n    cursor: crosshair;\n}\n\n.colorpicker_color div {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 150px;\n    height: 150px;\n    background: url(../assets/colorpicker_overlay.png);\n}\n\n.colorpicker_color div div {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 11px;\n    height: 11px;\n    overflow: hidden;\n    background: url(../assets/colorpicker_select.gif);\n    margin: -5px 0 0 -5px;\n}\n\n.colorpicker_hue {\n    position: absolute;\n    top: 13px;\n    left: 171px;\n    width: 35px;\n    height: 150px;\n    cursor: n-resize;\n}\n\n.colorpicker_hue div {\n    position: absolute;\n    width: 35px;\n    height: 9px;\n    overflow: hidden;\n    background: url(../assets/custom_indic.gif) left top;\n    margin: -4px 0 0 0;\n    left: 0px;\n}\n\n.colorpicker_new_color {\n    position: absolute;\n    width: 60px;\n    height: 30px;\n    left: 213px;\n    top: 13px;\n    background: #f00;\n}\n\n.colorpicker_current_color {\n    position: absolute;\n    width: 60px;\n    height: 30px;\n    left: 283px;\n    top: 13px;\n    background: #f00;\n}\n\n.colorpicker input {\n    background-color: transparent;\n    border: 1px solid transparent;\n    position: absolute;\n    font-size: 10px;\n    font-family: Arial, Helvetica, sans-serif;\n    color: #898989;\n    top: 4px;\n    right: 11px;\n    text-align: right;\n    margin: 0;\n    padding: 0;\n    height: 11px;\n}\n\n.colorpicker_hex {\n    position: absolute;\n    width: 72px;\n    height: 22px;\n    background: url(../assets/custom_hex.png) top;\n    left: 212px;\n    top: 142px;\n}\n\n.colorpicker_hex input {\n    right: 6px;\n}\n\n.colorpicker_field {\n    height: 22px;\n    width: 62px;\n    background-position: top;\n    position: absolute;\n}\n\n.colorpicker_field > input {\n    width: 42px;\n}\n\n.colorpicker_hex > input {\n    width: 42px;\n}\n\n.colorpicker_field span {\n    position: absolute;\n    width: 12px;\n    height: 22px;\n    overflow: hidden;\n    top: 0;\n    right: 0;\n    cursor: n-resize;\n}\n\n.colorpicker_rgb_r {\n    background-image: url(../assets/custom_rgb_r.png);\n    top: 52px;\n    left: 212px;\n}\n\n.colorpicker_rgb_g {\n    background-image: url(../assets/custom_rgb_g.png);\n    top: 82px;\n    left: 212px;\n}\n\n.colorpicker_rgb_b {\n    background-image: url(../assets/custom_rgb_b.png);\n    top: 112px;\n    left: 212px;\n}\n\n.colorpicker_hsb_h {\n    background-image: url(../assets/custom_hsb_h.png);\n    top: 52px;\n    left: 282px;\n}\n\n.colorpicker_hsb_s {\n    background-image: url(../assets/custom_hsb_s.png);\n    top: 82px;\n    left: 282px;\n}\n\n.colorpicker_hsb_b {\n    background-image: url(../assets/custom_hsb_b.png);\n    top: 112px;\n    left: 282px;\n}\n\n.colorpicker_submit {\n    position: absolute;\n    width: 22px;\n    height: 22px;\n    background: url(../assets/custom_submit.png) top;\n    left: 322px;\n    top: 142px;\n    overflow: hidden;\n}\n\n.colorpicker_focus {\n    background-position: center;\n}\n\n.colorpicker_hex.colorpicker_focus {\n    background-position: bottom;\n}\n\n.colorpicker_submit.colorpicker_focus {\n    background-position: bottom;\n}\n\n.colorpicker_slider {\n    background-position: bottom;\n}\n\n/************************************\n Gradient picker\n ************************************/\n\n#bgColorGradientSelector {\n    width: 180px;\n    height: 20px;\n    margin-bottom: 32px;\n}\n\n.gradientPicker-preview {\n    width: 200px;\n    height: 30px;\n    border: 1px solid rgba(0, 0, 0, 0.2);\n    /*box-sizing: border-box;\n    -moz-box-sizing: border-box;*/\n}\n\n.gradientPicker-ctrlPt {\n    width: 8px;\n    height: 8px;\n    border: 2px solid gray;\n    position: absolute;\n    display: inline-block;\n}\n\n.gradientPicker-ctrlPts {\n    position: relative;\n    height: 10px;\n    width: 190px;\n}\n\n.gradientPicker-ptConfig {\n    position: absolute;\n    width: 35px;\n    height: 40px;\n    z-index: 1;\n    margin-top: 2px;\n\n    background-color: white;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.2);\n    padding: 0 3px;\n    -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n    -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n\n.gradientPicker-close {\n    position: absolute;\n    top: -4px;\n    right: -4px;\n    /*font-size: 18px;\n    font-weight: bold;\n    color: black;\n    line-height: 20px;\n    text-shadow: 0 1px 0 white;\n    opacity: 0.2;\n    filter: alpha(opacity=20);*/\n    width: 16px;\n    height: 16px;\n    background-image: url(\"../assets/circle_remove.png\");\n}\n\n.gradientPicker-ptConfig .color-chooser {\n    float: left;\n}\n\n.clearFloat {\n    clear: both;\n}\n\n.floatLeftWidth {\n    float: left;\n    width: 60px;\n}\n\n.floatLeftWidthAdDrops {\n    float: left;\n    margin-left: 10px;\n}\n\n.hrThin {\n    margin-top: 8px;\n    margin-bottom: 8px;\n    color: #535353;\n}\n\n.hrThinDash {\n    margin-top: 8px;\n    margin-bottom: 8px;\n    color: #535353;\n    border-top: 1px solid #DDDDDD !important;\n    position: relative;\n    left: -50px;\n    width: 240px;\n}\n\ninput.ng-invalid {\n    border-right: 10px solid red;\n}\n\n.material-switch {\n    position: relative;\n    padding-top: 10px;\n}\n\n.input-group {\n    padding-top: 10px;\n}\n\ni {\n    width: 20px;\n}\n\nform .list-group, form .list-group-item {\n    border: 0 none !important;\n}\n\n.inner5 {\n    padding-left: 5px;\n    padding-right: 5px;\n}\n\n.inner10 {\n    padding-left: 10px;\n    padding-right: 10px;\n}\n\n.inner15 {\n    padding-left: 15px;\n    padding-right: 15px;\n}\n\n.default-prop-width {\n    width: 280px;\n}\n\n.checkers {\n    background-image: url(data:image/gif;base64,R0lGODlhCgAKAIAAAOLi4v///yH5BAAHAP8ALAAAAAAKAAoAAAIRhB2ZhxoM3GMSykqd1VltzxQAOw==);\n    display: inline-block;\n}\n\n.grid25 {\n    background-image: url(data:image/gif;base64,R0lGODlhGQAZAKIAAAAAAP///+rq6tLS0v///wAAAAAAAAAAACH5BAEAAAQALAAAAAAZABkAAAM2OLrc3iLKSWtUNmesu+ReB4bbQIrmWaorW43ulcbfTAtwnLs726u/U5A0DBU9R9SttpQ9ntAEADs=);\n    display: inline-block;\n}\n\n.grid50 {\n    background-image: url(data:image/gif;base64,R0lGODlhMgAyAKIAAAAAAP///+rq6tLS0v///wAAAAAAAAAAACH5BAEAAAQALAAAAAAyADIAAAN8OLrc/jA6Qau9OOtdFf9gSHliaY7DqYbk6mbtK6NzLcT2iufnzpe+HyslVAWLnCNSo1ximk4LNEqjgqZUbFTr5C69SHBRLCT/zDx0Tm1j19wzuEz+orvsOqI1qd8z+35PgIFSg4RVhxd4RoaHiz2NhI8mk0CRgRKZmpsNCQA7);\n    display: inline-block;\n}\n\n.basicBorder {\n    border: 1px solid rgb(170, 170, 170);\n}\n\n.lockPosition input {\n    position: relative;\n    left: 50px;\n}\n\n.vg-icon-fullscreen:before {\n    font-family: FontAwesome;\n    content: \"\\f26c\";\n}\n\n.inliner {\n    display: inline-block;\n    width: 130px;\n}\n\n.peopleInGroup {\n    font-size: 2.4em;\n    width: 10px !important;\n    overflow: hidden;\n    padding-left: 18px;\n    display: inline;\n    margin: 0;\n}\n\n.peopleInLine:nth-child(1) {\n    color: #969696;\n    padding: 0;\n    margin: 0;\n}\n\n.peopleInLine:nth-child(2) {\n    position: relative;\n    left: -35px;\n    color: #717171;\n    padding: 0;\n    margin: 0;\n}\n\n.peopleInLine:nth-child(3) {\n    position: relative;\n    left: -70px;\n    color: #4c4c4c;\n    padding: 0;\n    margin: 0;\n}\n\n.peopleInLine:nth-child(4) {\n    position: relative;\n    left: -105px;\n    color: #2f2f2f;\n    padding: 0;\n    margin: 0;\n}\n\n#fqLineQueueComponentContainer {\n    width: 2000px;\n    overflow: hidden;\n}\n\n#fqLineQueueComponent {\n    height: 200px;\n    width: 1000000px;\n    padding: 0;\n    margin: 0;\n    overflow: scroll;\n}\n\n#fqLineQueueComponentWrap {\n    width: 700px;\n    padding: 0;\n    margin: 0;\n    position: relative;\n}\n\n#fqSelectedCustomer {\n    border: 2px dashed red;\n    cursor: pointer;\n    background-color: transparent;\n    width: 60px;\n    height: 110px;\n    z-index: 100;\n    position: absolute;\n    left: 486px;\n}\n\n#fqSelectedCustomer:hover {\n    opacity: 0.3;\n    background-color: gray;\n}\n\n.fqStats > div {\n    border: solid 1px #b5b5b5;\n    padding-top: 5px;\n    margin-top: 5px;\n    background-color: white;\n}\n\n#fqGoToLineInput {\n    padding: 0;\n    margin: 0;\n    width: 60px;\n}\n\n#fqLineCompCall {\n    background-color: #BE6734;\n}\n\n.lineComponentButtons:nth-child(1) {\n    height: 40px;\n}\n\n.lineComponentButtons:nth-child(2) {\n    height: 40px;\n    background-color: #ACFD89;\n}\n\n.lineComponentButtons:nth-child(3) {\n    height: 40px;\n}\n\n.lineComponentButtons:nth-child(5) {\n    height: 40px;\n}\n\n.lineComponentButtons {\n    font-size: 1em;\n    width: 20%;\n    float: left;\n    height: 70px;\n    padding: 0;\n}\n\n.personInLine {\n    margin: 10px;\n    padding: 0;\n    float: left;\n    width: 40px;\n    height: 100px;\n    cursor: pointer;\n}\n\n.personInLine:hover {\n    opacity: 0.6;\n}\n\n.noCollapsing {\n    -webkit-transition: height 0.01s;\n    -moz-transition: height 0.01s;\n    -ms-transition: height 0.01s;\n    -o-transition: height 0.01s;\n    transition: height 0.01s;\n}\n\n#toast-container > div {\n    position: relative;\n    overflow: hidden;\n    margin: 0 0 6px;\n    padding: 15px 15px 15px 50px;\n    width: 300px;\n    -moz-border-radius: 3px 3px 3px 3px;\n    -webkit-border-radius: 3px 3px 3px 3px;\n    border-radius: 3px 3px 3px 3px;\n    background-position: 15px center;\n    background-repeat: no-repeat;\n    color: #FFFFFF;\n    opacity: 0.8;\n}\n\n/** Enjoy hint **/\n\n.enjoyhint {\n    position: fixed;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n    z-index: 1010;\n    pointer-events: none;\n    overflow: hidden;\n}\n\n.enjoyhint_hide {\n    display: none;\n}\n\n.enjoyhint_disable_events {\n    position: absolute;\n    width: 2000px;\n    height: 1500px;\n    z-index: 1011;\n    /*display: none;*/\n    pointer-events: all;\n}\n\n.enjoyhint_next_btn {\n    position: absolute;\n    z-index: 1012;\n    /*display: none;*/\n    pointer-events: all;\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    width: 100px;\n    height: 40px;\n    cursor: pointer;\n    margin: 0 auto;\n    border: 2px solid rgb(30, 205, 151);\n    -webkit-border-radius: 40px;\n    border-radius: 40px;\n    font: normal normal normal 17px/40px \"Advent Pro\", Helvetica, sans-serif;\n    color: rgb(30, 205, 151);\n    text-align: center;\n    -o-text-overflow: clip;\n    text-overflow: clip;\n    letter-spacing: 1px;\n    background: rgba(0, 0, 0, 0);\n    -webkit-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    -moz-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    -o-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n}\n\n.enjoyhint_next_btn:hover {\n    color: rgba(255, 255, 255, 1);\n    background: rgb(30, 205, 151);\n}\n\n.enjoyhint_next_btn:active {\n    border: 2px solid rgba(33, 224, 163, 1);\n    background: rgba(33, 224, 163, 1);\n    -webkit-transition: none;\n    -moz-transition: none;\n    -o-transition: none;\n    transition: none;\n}\n\n.enjoyhint_skip_btn {\n    position: absolute;\n    position: absolute;\n    z-index: 1012;\n    /*display: none;*/\n    pointer-events: all;\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    width: 100px;\n    height: 40px;\n    cursor: pointer;\n    margin: 0 auto;\n    border: 2px solid rgb(30, 205, 151);\n    -webkit-border-radius: 40px;\n    border-radius: 40px;\n    font: normal normal normal 17px/40px \"Advent Pro\", Helvetica, sans-serif;\n    color: rgb(30, 205, 151);\n    text-align: center;\n    -o-text-overflow: clip;\n    text-overflow: clip;\n    letter-spacing: 1px;\n    background: rgba(0, 0, 0, 0);\n    -webkit-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    -moz-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    -o-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n}\n\n.enjoyhint_skip_btn:hover {\n    color: rgba(255, 255, 255, 1);\n    background: rgb(30, 205, 151);\n}\n\n.enjoyhint_skip_btn:active {\n    border: 2px solid rgba(33, 224, 163, 1);\n    background: rgba(33, 224, 163, 1);\n    -webkit-transition: none;\n    -moz-transition: none;\n    -o-transition: none;\n    transition: none;\n}\n\n.enjoyhint_close_btn {\n    display: inline-block;\n    position: absolute;\n    z-index: 1012;\n    pointer-events: all;\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    width: .3em;\n    height: .3em;\n    border: none;\n    -webkit-border-radius: 1em;\n    border-radius: 1em;\n    font: 400 8em/normal Arial, Helvetica, sans-serif;\n    color: rgba(0, 0, 0, 1);\n    -o-text-overflow: clip;\n    text-overflow: clip;\n    background: rgba(0, 0, 0, 0);\n    border: 2px solid rgba(33, 224, 163, 1);\n}\n\n.enjoyhint_close_btn::before {\n    display: inline-block;\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    width: 73%;\n    height: 2px;\n    position: absolute;\n    content: \"\";\n    top: 48%;\n    left: 14%;\n    border: none;\n    font: normal 100%/normal Arial, Helvetica, sans-serif;\n    color: rgba(0, 0, 0, 1);\n    -o-text-overflow: clip;\n    text-overflow: clip;\n    background: #fff;\n    text-shadow: none;\n    -webkit-transform: rotateZ(45deg);\n    transform: rotateZ(45deg);\n}\n\n.enjoyhint_close_btn::after {\n    display: inline-block;\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    width: 73%;\n    height: 2px;\n    position: absolute;\n    content: \"\";\n    top: 46%;\n    left: 15%;\n    border: none;\n    font: normal 100%/normal Arial, Helvetica, sans-serif;\n    color: rgba(0, 0, 0, 1);\n    -o-text-overflow: clip;\n    text-overflow: clip;\n    background: #fff;\n    text-shadow: none;\n    -webkit-transform: rotateZ(-45deg);\n    transform: rotateZ(-45deg);\n}\n\n.enjoyhint_close_btn:hover {\n    color: rgba(255, 255, 255, 1);\n    background: rgb(30, 205, 151);\n    cursor: pointer;\n}\n\n.enjoyhint_close_btn:active {\n    border: 2px solid rgba(33, 224, 163, 1);\n    background: rgba(33, 224, 163, 1);\n    -webkit-transition: none;\n    -moz-transition: none;\n    -o-transition: none;\n    transition: none;\n}\n\n.enjoyhint_btn {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    width: 150px;\n    height: 40px;\n    cursor: pointer;\n    margin: 0 auto;\n    border: 2px solid rgb(30, 205, 151);\n    -webkit-border-radius: 40px;\n    border-radius: 40px;\n    font: normal normal normal 17px/40px \"Advent Pro\", Helvetica, sans-serif;\n    color: rgb(30, 205, 151);\n    text-align: center;\n    -o-text-overflow: clip;\n    text-overflow: clip;\n    letter-spacing: 1px;\n    background: rgba(0, 0, 0, 0);\n    -webkit-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    -moz-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    -o-transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n    transition: background-color 0.3s cubic-bezier(0, 0, 0, 0), color 0.3s cubic-bezier(0, 0, 0, 0), width 0.3s cubic-bezier(0, 0, 0, 0), border-width 0.3s cubic-bezier(0, 0, 0, 0), border-color 0.3s cubic-bezier(0, 0, 0, 0);\n}\n\n.enjoyhint_btn:hover {\n    color: rgba(255, 255, 255, 1);\n    background: rgb(30, 205, 151);\n}\n\n.enjoyhint_btn:active {\n    border: 2px solid rgba(33, 224, 163, 1);\n    background: rgba(33, 224, 163, 1);\n    -webkit-transition: none;\n    -moz-transition: none;\n    -o-transition: none;\n    transition: none;\n}\n\n.enjoyhint div.canvas-container {\n    position: absolute;\n}\n\n.enjoyhint_canvas {\n    position: absolute;\n    z-index: 100;\n    width: 100%;\n    height: 100%;\n    pointer-events: none;\n}\n\n#kinetic_container {\n    pointer-events: none;\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n}\n\n.enjoyhint_svg {\n}\n\n.enjoyhint_svg_wrapper {\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n    z-index: 100;\n    -webkit-transition: opacity 400ms cubic-bezier(0.42, 0, 0.58, 1);\n    -moz-transition: opacity 400ms cubic-bezier(0.42, 0, 0.58, 1);\n    transition: opacity 400ms cubic-bezier(0.42, 0, 0.58, 1);\n}\n\n.enjoyhint_svg_wrapper svg {\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n}\n\n.enjoyhint_svg_transparent .enjoyhint_svg_wrapper, .enjoyhint_svg_transparent .enjoy_hint_label {\n    opacity: 0;\n}\n\n.enjoy_hint_label {\n    position: absolute;\n    color: white;\n    z-index: 107;\n    font-size: 22px;\n    font-family: 'casino_handregular', 'Arial';\n    -webkit-transition: opacity 400ms cubic-bezier(0.42, 0, 0.58, 1);\n    -moz-transition: opacity 400ms cubic-bezier(0.42, 0, 0.58, 1);\n    transition: opacity 400ms cubic-bezier(0.42, 0, 0.58, 1);\n}\n\ndiv.kineticjs-content {\n    position: absolute !important;\n}\n\n.enjoyhint_skip_btn {\n    position: fixed;\n}\n\n.enjoy_hint_label {\n    display: inline-block;\n    min-width: 200px;\n    text-align: center;\n    max-width: 80%;\n}\n\n.installopts li {\n    height: 40px;\n    min-height: 40px;\n    overflow: hidden;\n}\n\n.installs {\n    font-size: 22px !important;\n    margin-right: 10px !important;\n    color: #4a4a4a !important;\n    opacity: 0.8 !important;\n}\n\n.installs:hover {\n    opacity: 1 !important;\n}\n\n/**dev_mode_start**/\nsmall.debug {\n    color: red;\n    display: none !important;\n}\n\nsmall.release {\n    text-transform: lowercase;\n    color: #4c4c4c;\n}\n/**dev_mode_end**/\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "src/styles/style_dark.css",
    "content": "\n\n\n\n/* Dark theme */\nhtml, body\n{\n    background-color\t: #262626;\n}\nbody\n{\n    color\t\t\t\t: #ccc;\n}\na\n{\n    color\t\t\t\t: #ccc;\n}\nh2\n{\n    color\t\t\t\t: #fff;\n}\nhr\n{\n    border-top\t\t\t: 1px solid #6a6a6a;\n}\n\n#fileMenu {\n    background-color: #151515;\n}\n\n#headerPad\n{\n    background-color\t: #ec7c66;\n}\n.navbar-inverse\n{\n    background-color\t: #535353;\n    border-color\t\t: #535353;\n}\n\n#propPanelWrap\n{\n    background-color\t: #535353;\n}\n#mainPanelWrap\n{\n    border-right\t\t: 1px solid #6a6a6a;\n}\n.btn-default\n{\n    color\t\t\t\t: #ccc;\n    background-color\t: #535353;\n    border-color\t\t: #6a6a6a;\n}\n.btn-default:hover\n{\n    background-color\t: #4c4c4c;\n}\n.list-group-item\n{\n    background-color\t: #535353;\n    border\t\t\t\t: 1px solid #6a6a6a;\n}\na:hover, a:focus\n{\n    color\t\t\t\t: #ccc;\n}\n\n#footer\n{\n    background-color\t: #151515;\n    border-top\t\t\t: 1px solid #6a6a6a;\n    padding\t\t\t\t: 21px 10px;\n}\n#footerText\n{\n    color\t\t\t\t: #ccc;\n}\n#footer br\n{\n    display\t\t\t\t: none;\n}\n.btn-primary\n{\n    color\t\t\t\t: #fff;\n    background-color\t: #535353;\n    border-color\t\t: #6a6a6a;\n}\n.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary\n{\n    background-color\t: #4c4c4c;\n    border-color\t\t: #6a6a6a;\n}\nli:hover a\n{\n    color\t\t\t\t: #ccc;\n}\n.alert-danger\n{\n    color\t\t\t\t: #FFF;\n    background-color\t: #ec7c66;\n    border-color\t\t: #ec7c66;\n}\nbutton, select\n{\n    text-transform\t\t: none;\n    border\t\t\t\t: 1px solid #6a6a6a;\n    background\t\t\t: #535353;\n}\n.panel\n{\n    background-color\t: #535353;\n}\n.panel-default > .panel-heading\n{\n    color\t\t\t\t: #fff;\n    background-color\t: #535353;\n    border-color\t\t: #6a6a6a;\n}\n.panel-default\n{\n    border-color\t\t: #6a6a6a;\n}\n.installs\n{\n    color\t\t\t\t: #ccc !important;\n}\n\n\n@media (min-width: 768px)\n{\n}\n\n.list-group-item.active, .list-group-item.active:hover, .list-group-item.active:focus {\n    background-color: #777777 !important;\n    border-color: #eb7c66 !important;\n}\n\ninput {\n    background-color: #262626 !important;\n    color: #cbcbcb !important;\n    border-color: #eb7c66 !important;\n}\n\n.panel {\n    border-color: #dcdcdc !important;\n}\n\n.navActiveSel {\n    background-color: #454545 !important;\n}\n\n#headerPad {\n    background-color: #eb7c66 !important;\n}\n\n.channelHeadSelected {\n    background-color: #eb7c66 !important;\n}\n\n.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {\n    background-color: #eb7c66 !important;\n}\n\n.activated {\n    background-color: #eb7c66 !important;\n}\n\n\n.space {\n    background-color: #b14117;\n}\n\n::-webkit-scrollbar-track\n{\n    background: rgba(0, 0, 0, 0.1);\n}\n\n::-webkit-scrollbar-thumb\n{\n    background: rgba(66, 66, 66, 0.5);\n}\n\n.modal-body {\n    color: darkslategray !important;;\n}"
  },
  {
    "path": "src/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \"\",\n    \"declaration\": false,\n    \"emitDecoratorMetadata\": true,\n    \"skipLibCheck\": false,\n    \"experimentalDecorators\": true,\n    \"lib\": [\n      \"es6\",\n      \"dom\"\n    ],\n    \"mapRoot\": \"./\",\n    \"module\": \"es6\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"../dist/out-tsc\",\n    \"sourceMap\": true,\n    \"target\": \"es5\",\n    \"typeRoots\": [\n      \"../node_modules/@types\"\n    ]\n  },\n  \"angularCompilerOptions\": {\n    \"genDir\": \"../src/locale\"\n  }\n}\n"
  },
  {
    "path": "src/typings.d.ts",
    "content": "// Typings reference file, you can add your own global typings here\n// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html\n\ndeclare module Reflect {\n    function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;\n\n    function construct(target: Function, argumentsList: ArrayLike<any>): any;\n\n    function getMetadata(annotations: string, constructor: any): any;\n\n    function defineProperty(target: any, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;\n\n    function deleteProperty(target: any, propertyKey: PropertyKey): boolean;\n\n    function get(target: any, propertyKey: PropertyKey, receiver?: any): any;\n\n    function getOwnPropertyDescriptor(target: any, propertyKey: PropertyKey): PropertyDescriptor;\n\n    function getPrototypeOf(target: any): any;\n\n    function has(target: any, propertyKey: PropertyKey): boolean;\n\n    function isExtensible(target: any): boolean;\n\n    function ownKeys(target: any): Array<PropertyKey>;\n\n    function preventExtensions(target: any): boolean;\n\n    function set(target: any, propertyKey: PropertyKey, value: any, receiver?: any): boolean;\n\n    function setPrototypeOf(target: any, proto: any): boolean;\n}\n\ndeclare module 'redux-thunk' {\n    import {Middleware, Dispatch} from 'redux';\n    const thunkMiddleware: Middleware;\n    export default thunkMiddleware;\n\n}\n\n\ndeclare module FlashDetect {\n    export var installed;\n    export var versionAtLeast: (v: number) => void;\n}\n\ndeclare class EnjoyHint {\n    constructor(config: any)\n\n    set(value: any);\n\n    trigger(value: any);\n\n    run: () => void;\n    end: () => void;\n    getCurrentStep: () => void;\n}\n\ndeclare class RC4 {\n    constructor(key: any);\n\n    doEncrypt: any;\n    doDecrypt: any;\n}\n\ndeclare class QRCode {\n    constructor(a: any, b: any);\n\n    makeCode(a: any);\n}\n\ndeclare class Stopwatch {\n    stop: () => void;\n    reset: () => void;\n    setListener: () => void;\n}\n\ndeclare class Power4 {\n    easeOut: any;\n}\n\ndeclare class RC4V2 {\n    encrypt: any;\n    decrypt: any;\n    calculate: any;\n}\n\ninterface Window {\n    g_protocol: string;\n    g_masterDomain: string;\n}\n\ndeclare module \"*.json\" {\n    export var name;\n    export var version;\n    const value: any;\n    export default value;\n}\n\ndeclare class LoaderManager {\n    create: any;\n}\n\n\n// declare var require: any;\n\n\ndeclare module 'xml2js' {\n    var parseString;\n}\n\n// declare module 'bootbox' {\n//   var hideAll:any;\n//   var prompt:any;\n//   var alert:any;\n//   var dialog:any;\n//   var alert:any;\n//   var confirm:any;\n// }\n//\n// declare var bootbox:any;\n\ninterface jQueryModal extends JQuery {\n}\n\ninterface JQueryStatic {\n    base64: any;\n    timepicker: any;\n    carousel: any;\n    knob: any;\n    gradientPicker: any;\n}\n\ninterface JQuery {\n    modal:any;\n    base64: any;\n    timepicker: any;\n    carousel: any;\n    knob: any;\n    gradientPicker: any;\n}\n\ndeclare var Draggable;\n\ndeclare function printJS(a:any, b:any): any;\n\n\n\ndeclare var con: Con;\ndeclare var jXML: JQueryStatic;\ndeclare var jQueryAny: JQueryStatic | any;\n\ninterface Con {\n    (msg: any, stringify?: boolean): void;\n}\n\ninterface PlatformStatic {\n    description?: string;\n    layout?: string;\n    manufacturer?: string;\n    name?: string;\n    prerelease?: string;\n    product?: string;\n    ua?: string;\n    version?: string;\n    os?: PlatformOS;\n\n    parse?(ua: string): PlatformStatic;\n\n    toString?(): string;\n}\n\ninterface PlatformOS {\n    architecture?: number;\n    family?: string;\n    version?: string;\n\n    toString(): string;\n}\n\ninterface Window {\n    platform: PlatformStatic\n}\n\ndeclare var platform: PlatformStatic;\n\n\n// declare class  ActiveXObject {\n//   constructor(a:any);\n//   async;\n//   loadXML;\n// }\n\n// declare module 'highcharts/highstock' {\n//   var Ng2Highcharts: any\n// }\n//\n// declare module 'highcharts/modules/map' {\n//\n// }\n//\n// declare module 'highcharts' {\n// }\n\n// import {Middleware, Dispatch} from \"redux\";\n// export type ThunkAction<R, S, E> = (dispatch: Dispatch<S>, getState: () => S,\n//                                     extraArgument: E) => R;\n// declare module \"redux\" {\n//   export interface Dispatch<S> {\n//     <R, E>(asyncAction: ThunkAction<R, S, E>): R;\n//   }\n// }\n// declare const thunk: Middleware & {\n//   withExtraArgument(extraArgument: any): Middleware;\n// };\n// export default thunk;\n\n\n// Generated by typings\n// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/fabricjs/fabricjs.d.ts\n// Type definitions for FabricJS v1.5.0\n// Project: http://fabricjs.com/\n// Definitions by: Oliver Klemencic <https://github.com/oklemencic/>, Joseph Livecchi <https://github.com/joewashear007/>, Michael Randolph <https://github.com/mrand01/>\n// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped\n\n/* tslint:disable:no-unused-variable */\n/* tslint:disable:whitespace */\n/* tslint:disable:typedef */\n\n// Support AMD require\ndeclare module \"fabric\" {\n    export = fabric;\n}\n\ndeclare namespace fabric {\n\n    var isLikelyNode: boolean;\n    var isTouchSupported: boolean;\n\n    /////////////////////////////////////////////////////////////\n    // farbic Functions\n    /////////////////////////////////////////////////////////////\n\n    function createCanvasForNode(width: number, height: number): ICanvas;\n\n    // Parse\n    // ----------------------------------------------------------\n    /**\n     * Creates markup containing SVG referenced elements like patterns, gradients etc.\n     * @param {fabric.Canvas} canvas instance of fabric.Canvas\n     */\n    function createSVGRefElementsMarkup(canvas: IStaticCanvas): string;\n\n    /**\n     * Creates markup containing SVG font faces\n     * @param {Array} objects Array of fabric objects\n     */\n    function createSVGFontFacesMarkup(objects: IObject[]): string;\n\n    /**\n     * Takes string corresponding to an SVG document, and parses it into a set of fabric objects\n     * @param {String} string\n     * @param {Function} callback\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    function loadSVGFromString(string: string, callback: (results: IObject[], options: any) => void, reviver?: Function): void;\n\n    /**\n     * Takes url corresponding to an SVG document, and parses it into a set of fabric objects.\n     * Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy)\n     * @param {String} url\n     * @param {Function} callback\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    function loadSVGFromURL(url: string, callback: (results: IObject[], options: any) => void, reviver?: Function): void;\n\n    /**\n     * Returns CSS rules for a given SVG document\n     * @param {SVGDocument} doc SVG document to parse\n     */\n    function getCSSRules(doc: SVGElement): any;\n\n    function parseElements(elements: any[], callback: Function, options: any, reviver?: Function): void;\n\n    /**\n     * Parses \"points\" attribute, returning an array of values\n     * @param {String} points points attribute string\n     */\n    function parsePointsAttribute(points: string): any[];\n\n    /**\n     * Parses \"style\" attribute, retuning an object with values\n     * @param {SVGElement} element Element to parse\n     */\n    function parseStyleAttribute(element: SVGElement): any;\n\n    /**\n     * Transforms an array of svg elements to corresponding fabric.* instances\n     * @param {Array} elements Array of elements to parse\n     * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements)\n     * @param {Object} [options] Options object\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    function parseElements(elements: any[], callback: Function, options?: any, reviver?: Function): void;\n\n    /**\n     * Returns an object of attributes' name/value, given element and an array of attribute names;\n     * Parses parent \"g\" nodes recursively upwards.\n     * @param {DOMElement} element Element to parse\n     * @param {Array} attributes Array of attributes to parse\n     */\n    function parseAttributes(elemen: HTMLElement, attributes: string[], svgUid?: string): { [key: string]: string }\n\n    /**\n     * Parses an SVG document, returning all of the gradient declarations found in it\n     * @param {SVGDocument} doc SVG document to parse\n     */\n    function getGradientDefs(doc: SVGElement): { [key: string]: any };\n\n    /**\n     * Parses a short font declaration, building adding its properties to a style object\n     * @param {String} value font declaration\n     * @param {Object} oStyle definition\n     */\n    function parseFontDeclaration(value: string, oStyle: any): void;\n\n    /**\n     * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback\n     * @param {SVGDocument} doc SVG document to parse\n     * @param {Function} callback Callback to call when parsing is finished; It's being passed an array of elements (parsed from a document).\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    function parseSVGDocument(doc: SVGElement, callback: (results: IObject[], options: any) => void, reviver?: Function): void;\n\n    /**\n     * Parses \"transform\" attribute, returning an array of values\n     * @param {String} attributeValue String containing attribute value\n     */\n    function parseTransformAttribute(attributeValue: string): number[];\n\n    // fabric Log\n    // ---------------\n    /**\n     * Wrapper around `console.log` (when available)\n     */\n    function log(...values: any[]): void;\n\n    /**\n     * Wrapper around `console.warn` (when available)\n     */\n    function warn(...values: any[]): void;\n\n    ////////////////////////////////////////////////////\n    // Classes\n    ////////////////////////////////////////////////////\n    var Canvas: ICanvasStatic;\n    var StaticCanvas: IStaticCanvasStatic;\n\n    var Color: IColorStatic;\n    var Pattern: IPatternStatic;\n    var Intersection: IIntersectionStatic;\n    var Point: IPointStatic;\n\n    var Circle: ICircleStatic;\n    var Ellipse: IEllipseStatic;\n    var Group: IGroupStatic;\n    var Image: IImageStatic;\n    var Line: ILineStatic;\n    var Object: IObjectStatic;\n    var Path: IPathStatic;\n    var PathGroup: IPathGroupStatic;\n    var Polygon: IPolygonStatic;\n    var Polyline: IPolylineStatic;\n    var Rect: IRectStatic;\n    var Shadow: IShadowStatic;\n    var Text: ITextStatic;\n    var IText: IITextStatic;\n    var Triangle: ITriangleStatic;\n\n    var util: IUtil;\n\n    ///////////////////////////////////////////////////////////////////////////////\n    // Data Object Interfaces - These intrface are not specific part of fabric,\n    // They are just helpful for for defining function paramters\n    //////////////////////////////////////////////////////////////////////////////\n    interface IDataURLOptions {\n        /**\n         * The format of the output image. Either \"jpeg\" or \"png\"\n         */\n        format?: string;\n        /**\n         * Quality level (0..1). Only used for jpeg\n         */\n        quality?: number;\n        /**\n         * Multiplier to scale by\n         */\n        multiplier?: number;\n        /**\n         * Cropping left offset. Introduced in v1.2.14\n         */\n        left?: number;\n        /**\n         * Cropping top offset. Introduced in v1.2.14\n         */\n        top?: number;\n        /**\n         * Cropping width. Introduced in v1.2.14\n         */\n        width?: number;\n        /**\n         * Cropping height. Introduced in v1.2.14\n         */\n        height?: number;\n    }\n\n    interface IEvent {\n        e: Event;\n        target?: IObject;\n    }\n\n    interface IFillOptions {\n        /**\n         * options.source Pattern source\n         */\n        source: string | HTMLImageElement;\n        /**\n         * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n         */\n        repeat?: string;\n        /**\n         * Pattern horizontal offset from object's left/top corner\n         */\n        offsetX?: number;\n        /**\n         * Pattern vertical offset from object's left/top corner\n         */\n        offsetY?: number;\n    }\n\n    interface IToSVGOptions {\n        /**\n         * If true xml tag is not included\n         */\n        suppressPreamble: boolean;\n        /**\n         * SVG viewbox object\n         */\n        viewBox: IViewBox;\n        /**\n         * Encoding of SVG output\n         */\n        encoding: string;\n    }\n\n    interface IViewBox {\n        /**\n         * x-cooridnate of viewbox\n         */\n        x: number;\n        /**\n         * y-coordinate of viewbox\n         */\n        y: number;\n        /**\n         * Width of viewbox\n         */\n        width: number;\n        /**\n         * Height of viewbox\n         */\n        height: number;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////\n    // Mixins Interfaces\n    //////////////////////////////////////////////////////////////////////////////\n    interface ICollection<T> {\n        /**\n         * Adds objects to collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n         * Objects should be instances of (or inherit from) fabric.Object\n         * @param {...fabric.Object} object Zero or more fabric instances\n         */\n        add(...object: IObject[]): T;\n\n        /**\n         * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)\n         * An object should be an instance of (or inherit from) fabric.Object\n         * @param {Object} object Object to insert\n         * @param {Number} index Index to insert object at\n         * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs\n         * @return {Self} thisArg\n         * @chainable\n         */\n        insertAt(object: IObject, index: number, nonSplicing: boolean): T;\n\n        /**\n         * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n         * @param {...fabric.Object} object Zero or more fabric instances\n         * @return {Self} thisArg\n         * @chainable\n         */\n        remove(...object: IObject[]): T;\n\n        /**\n         * Executes given function for each object in this group\n         * @param {Function} callback\n         * @param {Object} context Context (aka thisObject)\n         * @return {Self} thisArg\n         */\n        forEachObject(callback: (element: IObject, index: number, array: IObject[]) => any, context?: any): T;\n\n        /**\n         * Returns an array of children objects of this instance\n         * Type parameter introduced in 1.3.10\n         * @param {String} [type] When specified, only objects of this type are returned\n         * @return {Array}\n         */\n        getObjects(type?: string): IObject[];\n\n        /**\n         * Returns object at specified index\n         * @param {Number} index\n         * @return {Self} thisArg\n         */\n        item(index: number): T;\n\n        /**\n         * Returns true if collection contains no objects\n         * @return {Boolean} true if collection is empty\n         */\n        isEmpty(): boolean;\n\n        /**\n         * Returns a size of a collection (i.e: length of an array containing its objects)\n         * @return {Number} Collection size\n         */\n        size(): number;\n\n        /**\n         * Returns true if collection contains an object\n         * @param {Object} object Object to check against\n         * @return {Boolean} `true` if collection contains an object\n         */\n        contains(object: IObject): boolean;\n\n        /**\n         * Returns number representation of a collection complexity\n         * @return {Number} complexity\n         */\n        complexity(): number;\n    }\n\n    interface IObservable<T> {\n        /**\n         * Observes specified event\n         * @param eventName Event name (eg. 'after:render')\n         * @param handler Function that receives a notification when an event of the specified type occurs\n         */\n        on(eventName: string, handler: (e: IEvent) => any): T;\n\n        /**\n         * Observes specified event\n         * @param eventName Object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n         */\n        on(eventName: { [key: string]: Function }): T;\n\n        /**\n         * Fires event with an optional options object\n         * @deprecated `fire` deprecated since 1.0.7 (use `trigger` instead)\n         * @param {String} eventName Event name to fire\n         * @param {Object} [options] Options object\n         */\n        trigger(eventName: string, options?: any): T;\n\n        /**\n         * Stops event observing for a particular event handler. Calling this method\n         * without arguments removes all handlers for all events\n         * @deprecated `stopObserving` deprecated since 0.8.34 (use `off` instead)\n         * @param eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n         * @param handler Function to be deleted from EventListeners\n         */\n        off(eventName?: string | any, handler?: (e: IEvent) => any): T;\n    }\n\n    // animation mixin\n    // ----------------------------------------------------\n    interface ICanvasAnimation<T> {\n        FX_DURATION: number;\n\n        /**\n         * Centers object horizontally with animation.\n         * @param {fabric.Object} object Object to center\n         * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n         * @param {Function} [callbacks.onComplete] Invoked on completion\n         * @param {Function} [callbacks.onChange] Invoked on every step of animation\n         */\n        fxCenterObjectH(object: IObject, callbacks?: { onComplete: Function; onChange: Function; }): T;\n\n        /**\n         * Centers object vertically with animation.\n         * @param {fabric.Object} object Object to center\n         * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n         * @param {Function} [callbacks.onComplete] Invoked on completion\n         * @param {Function} [callbacks.onChange] Invoked on every step of animation\n         */\n        fxCenterObjectV(object: IObject, callbacks?: { onComplete: Function; onChange: Function; }): T;\n\n        /**\n         * Same as `fabric.Canvas#remove` but animated\n         * @param {fabric.Object} object Object to remove\n         * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n         * @param {Function} [callbacks.onComplete] Invoked on completion\n         * @param {Function} [callbacks.onChange] Invoked on every step of animation\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        fxRemove(object: IObject, callbacks?: { onComplete: Function; onChange: Function; }): T;\n    }\n\n    interface IObjectAnimation<T> {\n        /**\n         * Animates object's properties\n         * object.animate('left', ..., {duration: ...});\n         * @param property Property to animate\n         * @param value Value to animate property\n         * @param options The animation options\n         */\n        animate(property: string, value: number | string, options?: IAnimationOptions): IObject;\n\n        /**\n         * Animates object's properties\n         * object.animate({ left: ..., top: ... }, { duration: ... });\n         * @param properties Properties to animate\n         * @param value Options object\n         */\n        animate(properties: any, options?: IAnimationOptions): IObject;\n    }\n\n    interface IAnimationOptions {\n        /**\n         * Allows to specify starting value of animatable property (if we don't want current value to be used).\n         */\n        from?: string | number;\n        /**\n         * Defaults to 500 (ms). Can be used to change duration of an animation.\n         */\n        duration?: number;\n        /**\n         * Callback; invoked on every value change\n         */\n        onChange?: Function;\n        /**\n         * Callback; invoked when value change is completed\n         */\n        onComplete?: Function;\n\n        /**\n         * Easing function. Default: fabric.util.ease.easeInSine\n         */\n        easing?: Function;\n        /**\n         *  Value to modify the property by, default: end - start\n         */\n        by?: number;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////\n    // General Fabric Interfaces\n    //////////////////////////////////////////////////////////////////////////////\n    interface IColor {\n        /**\n         * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n         */\n        getSource(): number[];\n\n        /**\n         * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n         */\n        setSource(source: number[]): void;\n\n        /**\n         * Returns color represenation in RGB format ex: rgb(0-255,0-255,0-255)\n         */\n        toRgb(): string;\n\n        /**\n         * Returns color represenation in RGBA format ex: rgba(0-255,0-255,0-255,0-1)\n         */\n        toRgba(): string;\n\n        /**\n         * Returns color represenation in HSL format ex: hsl(0-360,0%-100%,0%-100%)\n         */\n        toHsl(): string;\n\n        /**\n         * Returns color represenation in HSLA format ex: hsla(0-360,0%-100%,0%-100%,0-1)\n         */\n        toHsla(): string;\n\n        /**\n         * Returns color represenation in HEX format ex: FF5555\n         */\n        toHex(): string;\n\n        /**\n         * Gets value of alpha channel for this color\n         */\n        getAlpha(): number;\n\n        /**\n         * Sets value of alpha channel for this color\n         * @param {Number} alpha Alpha value 0-1\n         */\n        setAlpha(alpha: number): void;\n\n        /**\n         * Transforms color to its grayscale representation\n         */\n        toGrayscale(): IColor;\n\n        /**\n         * Transforms color to its black and white representation\n         * @param {Number} threshold\n         */\n        toBlackWhite(threshold: number): IColor;\n\n        /**\n         * Overlays color with another color\n         * @param {String|fabric.Color} otherColor\n         */\n        overlayWith(otherColor: string | IColor): IColor;\n    }\n\n    interface IColorStatic {\n        /**\n         * Color class\n         * The purpose of Color is to abstract and encapsulate common color operations;\n         * @param {String} color optional in hex or rgb(a) format\n         */\n        new (color?: string): IColor;\n\n        /**\n         * Returns new color object, when given a color in RGB format\n         * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n         */\n        fromRgb(color: string): IColor;\n\n        /**\n         * Returns new color object, when given a color in RGBA format\n         * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n         */\n        fromRgba(color: string): IColor;\n\n        /**\n         * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format\n         * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)\n         */\n        sourceFromRgb(color: string): number[];\n\n        /**\n         * Returns new color object, when given a color in HSL format\n         * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n         */\n        fromHsl(color: string): IColor;\n\n        /**\n         * Returns new color object, when given a color in HSLA format\n         * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n         */\n        fromHsla(color: string): IColor;\n\n        /**\n         * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.\n         * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)\n         */\n        sourceFromHsl(color: string): number[];\n\n        /**\n         * Returns new color object, when given a color in HEX format\n         * @param {String} color Color value ex: FF5555\n         */\n        fromHex(color: string): IColor;\n\n        /**\n         * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HEX format\n         * @param {String} color ex: FF5555\n         */\n        sourceFromHex(color: string): number[];\n\n        /**\n         * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])\n         * @param {Array} source\n         */\n        fromSource(source: number[]): IColor;\n\n        prototype: any;\n    }\n\n    interface IGradientOptions {\n        /**\n         * @param {String} [options.type] Type of gradient 'radial' or 'linear'\n         */\n        type?: string;\n        /**\n         * x-coordinate of start point\n         */\n        x1?: number;\n        /**\n         * y-coordinate of start point\n         */\n        y1?: number;\n        /**\n         * x-coordinate of end point\n         */\n        x2?: number;\n        /**\n         * y-coordinate of end point\n         */\n        y2?: number;\n        /**\n         * Radius of start point (only for radial gradients)\n         */\n        r1?: number;\n        /**\n         * Radius of end point (only for radial gradients)\n         */\n        r2?: number;\n        /**\n         * Color stops object eg. {0:string; 1:string;\n     */\n        colorStops?: any;\n    }\n\n    interface IGradient extends IGradientOptions {\n        /**\n         * Adds another colorStop\n         * @param {Object} colorStop Object with offset and color\n         */\n        addColorStop(colorStop: any): IGradient;\n\n        /**\n         * Returns object representation of a gradient\n         */\n        toObject(): any;\n\n        /**\n         * Returns SVG representation of an gradient\n         * @param {Object} object Object to create a gradient for\n         * @param {Boolean} normalize Whether coords should be normalized\n         * @return {String} SVG representation of an gradient (linear/radial)\n         */\n        toSVG(object: IObject, normalize?: boolean): string;\n\n        /**\n         * Returns an instance of CanvasGradient\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        toLive(ctx: CanvasRenderingContext2D, object?: IPathGroup): CanvasGradient;\n    }\n\n    interface IGrandientStatic {\n        new (options?: IGradientOptions): IGradient;\n\n        /**\n         * Returns instance from an SVG element\n         * @param {SVGGradientElement} el SVG gradient element\n         * @param {fabric.Object} instance\n         */\n        fromElement(el: SVGGradientElement, instance: IObject): IGradient;\n\n        /**\n         * Returns instance from its object representation\n         * @param {Object} obj\n         * @param {Object} [options] Options object\n         */\n        fromObject(obj: any, options: any[]): IGradient;\n    }\n\n    interface IIntersection {\n        /**\n         * Appends a point to intersection\n         */\n        appendPoint(point: IPoint): void;\n\n        /**\n         * Appends points to intersection\n         */\n        appendPoints(points: IPoint[]): void;\n    }\n\n    interface IIntersectionStatic {\n        /**\n         * Intersection class\n         */\n        new (status?: string): void;\n\n        /**\n         * Checks if polygon intersects another polygon\n         */\n        intersectPolygonPolygon(points1: IPoint[], points2: IPoint[]): IIntersection;\n\n        /**\n         * Checks if line intersects polygon\n         */\n        intersectLinePolygon(a1: IPoint, a2: IPoint, points: IPoint[]): IIntersection;\n\n        /**\n         * Checks if one line intersects another\n         */\n        intersectLineLine(a1: IPoint, a2: IPoint, b1: IPoint, b2: IPoint): IIntersection;\n\n        /**\n         * Checks if polygon intersects rectangle\n         */\n        intersectPolygonRectangle(points: IPoint[], r1: number, r2: number): IIntersection;\n    }\n\n    interface IPatternOptions {\n        /**\n         * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n         */\n        repeat: string;\n\n        /**\n         * Pattern horizontal offset from object's left/top corner\n         */\n        offsetX: number;\n\n        /**\n         * Pattern vertical offset from object's left/top corner\n         */\n        offsetY: number;\n        /**\n         * The source for the pattern\n         */\n        source: string | HTMLImageElement;\n    }\n\n    interface IPattern extends IPatternOptions {\n        new (options?: IPatternOptions): IPattern;\n\n        initialise(options?: IPatternOptions): IPattern;\n\n        /**\n         * Returns an instance of CanvasPattern\n         */\n        toLive(ctx: CanvasRenderingContext2D): IPattern;\n\n        /**\n         * Returns object representation of a pattern\n         */\n        toObject(): any;\n\n        /**\n         * Returns SVG representation of a pattern\n         * @param {fabric.Object} object\n         */\n        toSVG(object: IObject): string;\n    }\n\n    interface IPatternStatic {\n        new (options?: IPatternOptions): IPattern;\n\n        prototype: any;\n    }\n\n    interface IPoint {\n        x: number;\n        y: number;\n\n        /**\n         * Adds another point to this one and returns another one\n         * @param {fabric.Point} that\n         */\n        add(that: IPoint): IPoint;\n\n        /**\n         * Adds another point to this one\n         * @param {fabric.Point} that\n         */\n        addEquals(that: IPoint): IPoint;\n\n        /**\n         * Adds value to this point and returns a new one\n         * @param {Number} scalar\n         */\n        scalarAdd(scalar: number): IPoint;\n\n        /**\n         * Adds value to this point\n         * @param {Number} scalar\n         */\n        scalarAddEquals(scalar: number): IPoint;\n\n        /**\n         * Subtracts another point from this point and returns a new one\n         * @param {fabric.Point} that\n         */\n        subtract(that: IPoint): IPoint;\n\n        /**\n         * Subtracts another point from this point\n         * @param {fabric.Point} that\n         */\n        subtractEquals(that: IPoint): IPoint;\n\n        /**\n         * Subtracts value from this point and returns a new one\n         * @param {Number} scalar\n         */\n        scalarSubtract(scalar: number): IPoint;\n\n        /**\n         * Subtracts value from this point\n         * @param {Number} scalar\n         */\n        scalarSubtractEquals(scalar: number): IPoint;\n\n        /**\n         * Miltiplies this point by a value and returns a new one\n         * @param {Number} scalar\n         */\n        multiply(scalar: number): IPoint;\n\n        /**\n         * Miltiplies this point by a value\n         * @param {Number} scalar\n         */\n        multiplyEquals(scalar: number): IPoint;\n\n        /**\n         * Divides this point by a value and returns a new one\n         * @param {Number} scalar\n         */\n        divide(scalar: number): IPoint;\n\n        /**\n         * Divides this point by a value\n         * @param {Number} scalar\n         */\n        divideEquals(scalar: number): IPoint;\n\n        /**\n         * Returns true if this point is equal to another one\n         * @param {fabric.Point} that\n         */\n        eq(that: IPoint): IPoint;\n\n        /**\n         * Returns true if this point is less than another one\n         * @param {fabric.Point} that\n         */\n        lt(that: IPoint): IPoint;\n\n        /**\n         * Returns true if this point is less than or equal to another one\n         * @param {fabric.Point} that\n         */\n        lte(that: IPoint): IPoint;\n\n        /**\n         * Returns true if this point is greater another one\n         * @param {fabric.Point} that\n         */\n        gt(that: IPoint): IPoint;\n\n        /**\n         * Returns true if this point is greater than or equal to another one\n         * @param {fabric.Point} that\n         */\n        gte(that: IPoint): IPoint;\n\n        /**\n         * Returns new point which is the result of linear interpolation with this one and another one\n         * @param {fabric.Point} that\n         * @param {Number} t\n         */\n        lerp(that: IPoint, t: number): IPoint;\n\n        /**\n         * Returns distance from this point and another one\n         * @param {fabric.Point} that\n         */\n        distanceFrom(that: IPoint): number;\n\n        /**\n         * Returns the point between this point and another one\n         * @param {fabric.Point} that\n         */\n        midPointFrom(that: IPoint): IPoint;\n\n        /**\n         * Returns a new point which is the min of this and another one\n         * @param {fabric.Point} that\n         */\n        min(that: IPoint): IPoint;\n\n        /**\n         * Returns a new point which is the max of this and another one\n         * @param {fabric.Point} that\n         */\n        max(that: IPoint): IPoint;\n\n        /**\n         * Returns string representation of this point\n         */\n        toString(): string;\n\n        /**\n         * Sets x/y of this point\n         * @param {Number} x\n         * @param {Number} y\n         */\n        setXY(x: number, y: number): IPoint;\n\n        /**\n         * Sets x/y of this point from another point\n         * @param {fabric.Point} that\n         */\n        setFromPoint(that: IPoint): IPoint;\n\n        /**\n         * Swaps x/y of this point and another point\n         * @param {fabric.Point} that\n         */\n        swap(that: IPoint): IPoint;\n    }\n\n    interface IPointStatic {\n        new (x: number, y: number): IPoint;\n\n        prototype: any;\n    }\n\n    interface IShadowOptions {\n        /**\n         * Whether the shadow should affect stroke operations\n         */\n        affectStrike: boolean;\n        /**\n         * Shadow blur\n         */\n        blur: number;\n        /**\n         * Shadow color\n         */\n        color: string;\n        /**\n         * Indicates whether toObject should include default values\n         */\n        includeDefaultValues: boolean;\n        /**\n         * Shadow horizontal offset\n         */\n        offsetX: number;\n        /**\n         * Shadow vertical offset\n         */\n        offsetY: number;\n    }\n\n    interface IShadow extends IShadowOptions {\n        initialize(options?: IShadowOptions | string): IShadow;\n\n        /**\n         * Returns object representation of a shadow\n         */\n        toObject(): IObject;\n\n        /**\n         * Returns a string representation of an instance, CSS3 text-shadow declaration\n         */\n        toString(): string;\n\n        /**\n         * Returns SVG representation of a shadow\n         * @param {fabric.Object} object\n         */\n        toSVG(object: IObject): string;\n\n        /**\n         * Regex matching shadow offsetX, offsetY and blur, Static\n         */\n        reOffsetsAndBlur: RegExp\n    }\n\n    interface IShadowStatic {\n        new (options?: IShadowOptions): IShadow;\n\n        reOffsetsAndBlur: RegExp;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////\n    // Canvas Interfaces\n    //////////////////////////////////////////////////////////////////////////////\n    interface ICanvasDimensions {\n        /**\n         * Width of canvas element\n         */\n        width: number;\n        /**\n         * Height of canvas element\n         */\n        height: number;\n    }\n\n    interface ICanvasDimensionsOptions {\n        /**\n         * Set the given dimensions only as canvas backstore dimensions\n         */\n        backstoreOnly?: boolean;\n        /**\n         * Set the given dimensions only as css dimensions\n         */\n        cssOnly?: boolean;\n    }\n\n    interface IStaticCanvasOptions {\n        /**\n         * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas\n         */\n        allowTouchScrolling?: boolean;\n        /**\n         * Indicates whether this canvas will use image smoothing, this is on by default in browsers\n         */\n        imageSmoothingEnabled?: boolean;\n\n        /**\n         * Indicates whether objects should remain in current stack position when selected.\n         * When false objects are brought to top and rendered as part of the selection group\n         */\n        preserveObjectStacking?: boolean;\n\n        /**\n         * The transformation (in the format of Canvas transform) which focuses the viewport\n         */\n        viewportTransform?: number[];\n\n        freeDrawingColor?: string;\n        freeDrawingLineWidth?: number;\n\n        /**\n         * Background color of canvas instance.\n         * Should be set via setBackgroundColor\n         */\n        backgroundColor?: string | IPattern;\n        /**\n         * Background image of canvas instance.\n         * Should be set via setBackgroundImage\n         * <b>Backwards incompatibility note:</b> The \"backgroundImageOpacity\" and \"backgroundImageStretch\" properties are deprecated since 1.3.9.\n         */\n        backgroundImage?: IImage | string;\n        backgroundImageOpacity?: number;\n        backgroundImageStretch?: number;\n        /**\n         * Function that determines clipping of entire canvas area\n         * Being passed context as first argument. See clipping canvas area\n         */\n        clipTo?: (context: CanvasRenderingContext2D) => void;\n\n        /**\n         * Indicates whether object controls (borders/controls) are rendered above overlay image\n         */\n        controlsAboveOverlay?: boolean;\n\n        /**\n         * Indicates whether toObject/toDatalessObject should include default values\n         */\n        includeDefaultValues?: boolean;\n        /**\n         * Overlay color of canvas instance.\n         * Should be set via setOverlayColor\n         */\n        overlayColor?: string | IPattern;\n        /**\n         * Overlay image of canvas instance.\n         * Should be set via setOverlayImage\n         * <b>Backwards incompatibility note:</b> The \"overlayImageLeft\" and \"overlayImageTop\" properties are deprecated since 1.3.9.\n         */\n        overlayImage?: IImage;\n        overlayImageLeft?: number;\n        overlayImageTop?: number;\n        /**\n         * Indicates whether add, insertAt and remove should also re-render canvas.\n         * Disabling this option could give a great performance boost when adding/removing a lot of objects to/from canvas at once\n         * (followed by a manual rendering after addition/deletion)\n         */\n        renderOnAddRemove?: boolean;\n        /**\n         * Indicates whether objects' state should be saved\n         */\n        stateful?: boolean;\n    }\n\n    interface IStaticCanvas extends IObservable<IStaticCanvas>, IStaticCanvasOptions, ICollection<IStaticCanvas>, ICanvasAnimation<IStaticCanvas> {\n        /**\n         * Calculates canvas element offset relative to the document\n         * This method is also attached as \"resize\" event handler of window\n         */\n        calcOffset(): IStaticCanvas;\n\n        /**\n         * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas\n         * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to\n         * @param {Function} callback callback to invoke when image is loaded and set as an overlay\n         * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}.\n         */\n        setOverlayImage(image: IImage | string, callback: Function, options?: IObjectOptions): IStaticCanvas;\n\n        /**\n         * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas\n         * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to\n         * @param {Function} callback Callback to invoke when image is loaded and set as background\n         * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}.\n         */\n        setBackgroundImage(image: IImage | string, callback: Function, options?: IObjectOptions): IStaticCanvas;\n\n        /**\n         * Sets {@link fabric.StaticCanvas#overlayColor|background color} for this canvas\n         * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set background color to\n         * @param {Function} callback Callback to invoke when background color is set\n         */\n        setOverlayColor(overlayColor: string | IPattern, callback: Function): IStaticCanvas;\n\n        /**\n         * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas\n         * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to\n         * @param {Function} callback Callback to invoke when background color is set\n         */\n        setBackgroundColor(backgroundColor: string | IPattern, callback: Function): IStaticCanvas;\n\n        /**\n         * Returns canvas width (in px)\n         */\n        getWidth(): number;\n\n        /**\n         * Returns canvas height (in px)\n         */\n        getHeight(): number;\n\n        /**\n         * Sets width of this canvas instance\n         * @param {Number|String} value                         Value to set width to\n         * @param {Object}        [options]                     Options object\n         */\n        setWidth(value: number | string, options?: ICanvasDimensionsOptions): IStaticCanvas\n\n        /**\n         * Sets height of this canvas instance\n         * @param {Number|String} value                         Value to set height to\n         * @param {Object}        [options]                     Options object\n         */\n        setHeight(value: number | string, options?: ICanvasDimensionsOptions): IStaticCanvas;\n\n        /**\n         * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em)\n         * @param {Object}        dimensions                    Object with width/height properties\n         * @param {Object}        [options]                     Options object\n         */\n        setDimensions(dimensions: ICanvasDimensions, options?: ICanvasDimensionsOptions): IStaticCanvas;\n\n        /**\n         * Returns canvas zoom level\n         */\n        getZoom(): number;\n\n        /**\n         * Sets viewport transform of this canvas instance\n         * @param {Array} vpt the transform in the form of context.transform\n         */\n        setViewportTransform(vpt: number[]): IStaticCanvas;\n\n        /**\n         * Sets zoom level of this canvas instance, zoom centered around point\n         * @param {fabric.Point} point to zoom with respect to\n         * @param {Number} value to set zoom to, less than 1 zooms out\n         */\n        zoomToPoint(point: IPoint, value: number): IStaticCanvas;\n\n        /**\n         * Sets zoom level of this canvas instance\n         * @param {Number} value to set zoom to, less than 1 zooms out\n         */\n        setZoom(value: number): IStaticCanvas;\n\n        /**\n         * Pan viewport so as to place point at top left corner of canvas\n         * @param {fabric.Point} point to move to\n         */\n        absolutePan(point: IPoint): IStaticCanvas;\n\n        /**\n         * Pans viewpoint relatively\n         * @param {fabric.Point} point (position vector) to move by\n         */\n        relativePan(point: IPoint): IStaticCanvas;\n\n        /**\n         * Returns <canvas> element corresponding to this instance\n         */\n        getElement(): HTMLCanvasElement;\n\n        /**\n         * Returns currently selected object, if any\n         */\n        getActiveObject(): IObject;\n\n        /**\n         * Returns currently selected group of object, if any\n         */\n        getActiveGroup(): IGroup;\n\n        /**\n         * Clears specified context of canvas element\n         * @param {CanvasRenderingContext2D} ctx Context to clear\n         * @chainable\n         */\n        clearContext(ctx: CanvasRenderingContext2D): IStaticCanvas;\n\n        /**\n         * Returns context of canvas where objects are drawn\n         */\n        getContext(): CanvasRenderingContext2D;\n\n        /**\n         * Clears all contexts (background, main, top) of an instance\n         */\n        clear(): IStaticCanvas;\n\n        /**\n         * Renders both the top canvas and the secondary container canvas.\n         * @param {Boolean} [allOnTop] Whether we want to force all images to be rendered on the top canvas\n         * @chainable\n         */\n        renderAll(allOnTop?: boolean): IStaticCanvas;\n\n        /**\n         * Method to render only the top canvas.\n         * Also used to render the group selection box.\n         * @chainable\n         */\n        renderTop(): IStaticCanvas;\n\n        /**\n         * Returns coordinates of a center of canvas.\n         * Returned value is an object with top and left properties\n         */\n        getCenter(): { top: number; left: number; };\n\n        /**\n         * Centers object horizontally.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @param {fabric.Object} object Object to center horizontally\n         */\n        centerObjectH(object: IObject): IStaticCanvas;\n\n        /**\n         * Centers object vertically.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @param {fabric.Object} object Object to center vertically\n         */\n        centerObjectV(object: IObject): IStaticCanvas;\n\n        /**\n         * Centers object vertically and horizontally.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         * @param {fabric.Object} object Object to center vertically and horizontally\n         */\n        centerObject(object: IObject): IStaticCanvas;\n\n        /**\n         * Returs dataless JSON representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toDatalessJSON(propertiesToInclude?: any[]): string;\n\n        /**\n         * Returns object representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns dataless object representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toDatalessObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true,\n         * a zoomed canvas will then produce zoomed SVG output.\n         */\n        svgViewportTransformation: boolean;\n\n        /**\n         * Returns SVG representation of canvas\n         * @param {Object} [options] Options object for SVG output\n         * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.\n         */\n        toSVG(options: IToSVGOptions, reviver?: Function): string;\n\n        /**\n         * Moves an object to the bottom of the stack of drawn objects\n         * @param {fabric.Object} object Object to send to back\n         * @chainable\n         */\n        sendToBack(object: IObject): IStaticCanvas;\n\n        /**\n         * Moves an object to the top of the stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @chainable\n         */\n        bringToFront(object: IObject): IStaticCanvas;\n\n        /**\n         * Moves an object down in stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n         * @chainable\n         */\n        sendBackwards(object: IObject): IStaticCanvas;\n\n        /**\n         * Moves an object up in stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n         * @chainable\n         */\n        bringForward(object: IObject): IStaticCanvas;\n\n        /**\n         * Moves an object to specified level in stack of drawn objects\n         * @param {fabric.Object} object Object to send\n         * @param {Number} index Position to move to\n         * @chainable\n         */\n        moveTo(object: IObject, index: number): IStaticCanvas;\n\n        /**\n         * Clears a canvas element and removes all event listeners\n         */\n        dispose(): IStaticCanvas;\n\n        /**\n         * Returns a string representation of an instance\n         */\n        toString(): string;\n\n        /**\n         * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately\n         * @param {Object} [options] Options object\n         */\n        toDataURL(options?: IDataURLOptions): string;\n\n        /**\n         * Provides a way to check support of some of the canvas methods\n         * (either those of HTMLCanvasElement itself, or rendering context)\n         * @param {String} methodName Method to check support for; Could be one of \"getImageData\", \"toDataURL\", \"toDataURLWithQuality\" or \"setLineDash\"\n         * @return {Boolean | null} `true` if method is supported (or at least exists), null` if canvas element or context can not be initialized\n         */\n        supports(methodName: string): boolean;\n\n        /**\n         * Populates canvas with data from the specified JSON.\n         * JSON format must conform to the one of toJSON formats\n         * @param {String|Object} json JSON string or object\n         * @param {Function} callback Callback, invoked when json is parsed\n         *                            and corresponding objects (e.g: {@link fabric.Image})\n         *                            are initialized\n         * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n         */\n        loadFromJSON(json: string | any, callback: Function, reviver?: Function): ICanvas;\n\n        /**\n         * Clones canvas instance\n         * @param {Object} [callback] Receives cloned instance as a first argument\n         * @param {Array} [properties] Array of properties to include in the cloned canvas and children\n         */\n        clone(callback: (canvas: IStaticCanvas) => any, properties?: any[]): void;\n\n        /**\n         * Clones canvas instance without cloning existing data.\n         * This essentially copies canvas dimensions, clipping properties, etc.\n         * but leaves data empty (so that you can populate it with your own)\n         * @param {Object} [callback] Receives cloned instance as a first argument\n         */\n        cloneWithoutData(callback: (canvas: IStaticCanvas) => any): void;\n\n        /**\n         * Callback; invoked right before object is about to be scaled/rotated\n         */\n        onBeforeScaleRotate(target: IObject): void;\n\n        // Functions from object straighten mixin\n        // --------------------------------------------------------------------------------------------------------------------------------\n\n        /**\n         * Straightens object, then rerenders canvas\n         * @param {fabric.Object} object Object to straighten\n         */\n        straightenObject(object: IObject): IStaticCanvas\n\n        /**\n         * Same as straightenObject, but animated\n         * @param {fabric.Object} object Object to straighten\n         */\n        fxStraightenObject(object: IObject): IStaticCanvas\n    }\n\n    interface IStaticCanvasStatic {\n        /**\n         * Constructor\n         * @param {HTMLElement|String} element <canvas> element to initialize instance on\n         * @param {Object} [options] Options object\n         */\n        new (element: HTMLCanvasElement | string, options?: ICanvasOptions): IStaticCanvas;\n\n        EMPTY_JSON: string;\n\n        /**\n         * Provides a way to check support of some of the canvas methods\n         * (either those of HTMLCanvasElement itself, or rendering context)\n         * @param {String} methodName Method to check support for; Could be one of \"getImageData\", \"toDataURL\", \"toDataURLWithQuality\" or \"setLineDash\"\n         */\n        supports(methodName: string): boolean;\n\n        prototype: any;\n\n        /**\n         * Returns JSON representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toJSON(propertiesToInclude?: any[]): string;\n    }\n\n    interface ICanvasOptions extends IStaticCanvasOptions {\n        /**\n         * When true, objects can be transformed by one side (unproportionally)\n         */\n        uniScaleTransform?: boolean;\n\n        /**\n         * When true, objects use center point as the origin of scale transformation.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         */\n        centeredScaling?: boolean;\n\n        /**\n         * When true, objects use center point as the origin of rotate transformation.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         */\n        centeredRotation?: boolean;\n\n        /**\n         * Indicates that canvas is interactive. This property should not be changed.\n         */\n        interactive?: boolean;\n\n        /**\n         * Indicates whether group selection should be enabled\n         */\n        selection?: boolean;\n\n        /**\n         * Color of selection\n         */\n        selectionColor?: string;\n\n        /**\n         * Default dash array pattern\n         * If not empty the selection border is dashed\n         */\n        selectionDashArray?: any[];\n\n        /**\n         * Color of the border of selection (usually slightly darker than color of selection itself)\n         */\n        selectionBorderColor?: string;\n\n        /**\n         * Width of a line used in object/group selection\n         */\n        selectionLineWidth?: number;\n\n        /**\n         * Default cursor value used when hovering over an object on canvas\n         */\n        hoverCursor?: string;\n\n        /**\n         * Default cursor value used when moving an object on canvas\n         */\n        moveCursor?: string;\n\n        /**\n         * Default cursor value used for the entire canvas\n         */\n        defaultCursor?: string;\n\n        /**\n         * Cursor value used during free drawing\n         */\n        freeDrawingCursor?: string;\n\n        /**\n         * Cursor value used for rotation point\n         */\n        rotationCursor?: string;\n\n        /**\n         * Default element class that's given to wrapper (div) element of canvas\n         */\n        containerClass?: string;\n\n        /**\n         * When true, object detection happens on per-pixel basis rather than on per-bounding-box\n         */\n        perPixelTargetFind?: boolean;\n\n        /**\n         * Number of pixels around target pixel to tolerate (consider active) during object detection\n         */\n        targetFindTolerance?: number;\n\n        /**\n         * When true, target detection is skipped when hovering over canvas. This can be used to improve performance.\n         */\n        skipTargetFind?: boolean;\n\n        /**\n         * When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing.\n         * After mousedown, mousemove creates a shape,\n         * and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas.\n         */\n        isDrawingMode?: boolean;\n    }\n\n    interface ICanvas extends IStaticCanvas, ICanvasOptions {\n        _objects: IObject[];\n\n        /**\n         * Checks if point is contained within an area of given object\n         * @param {Event} e Event object\n         * @param {fabric.Object} target Object to test against\n         */\n        containsPoint(e: Event, target: IObject): boolean;\n\n        /**\n         * Deactivates all objects on canvas, removing any active group or object\n         * @return {fabric.Canvas} thisArg\n         */\n        deactivateAll(): ICanvas;\n\n        /**\n         * Deactivates all objects and dispatches appropriate events\n         * @param {Event} [e] Event (passed along when firing)\n         * @return {fabric.Canvas} thisArg\n         */\n        deactivateAllWithDispatch(e?: Event): ICanvas;\n\n        /**\n         * Discards currently active group\n         * @param {Event} [e] Event (passed along when firing)\n         * @return {fabric.Canvas} thisArg\n         */\n        discardActiveGroup(e?: Event): ICanvas;\n\n        /**\n         * Discards currently active object\n         * @param {Event} [e] Event (passed along when firing)\n         * @return {fabric.Canvas} thisArg\n         * @chainable\n         */\n        discardActiveObject(e?: Event): ICanvas;\n\n        /**\n         * Draws objects' controls (borders/controls)\n         * @param {CanvasRenderingContext2D} ctx Context to render controls on\n         */\n        drawControls(ctx: CanvasRenderingContext2D): void;\n\n        /**\n         * Method that determines what object we are clicking on\n         * @param {Event} e mouse event\n         * @param {Boolean} skipGroup when true, group is skipped and only objects are traversed through\n         */\n        findTarget(e: MouseEvent, skipGroup: boolean): ICanvas;\n\n        /**\n         * Returns currently active group\n         * @return {fabric.Group} Current group\n         */\n        getActiveGroup(): IGroup;\n\n        /**\n         * Returns currently active object\n         * @return {fabric.Object} active object\n         */\n        getActiveObject(): IObject;\n\n        /**\n         * Returns pointer coordinates relative to canvas.\n         * @param {Event} e\n         * @return {Object} object with \"x\" and \"y\" number values\n         */\n        getPointer(e: Event, ignoreZoom?: boolean, upperCanvasEl?: CanvasRenderingContext2D): { x: number; y: number; };\n\n        /**\n         * Returns context of canvas where object selection is drawn\n         * @return {CanvasRenderingContext2D}\n         */\n        getSelectionContext(): CanvasRenderingContext2D;\n\n        /**\n         * Returns <canvas> element on which object selection is drawn\n         * @return {HTMLCanvasElement}\n         */\n        getSelectionElement(): HTMLCanvasElement;\n\n        /**\n         * Returns true if object is transparent at a certain location\n         * @param {fabric.Object} target Object to check\n         * @param {Number} x Left coordinate\n         * @param {Number} y Top coordinate\n         */\n        isTargetTransparent(target: IObject, x: number, y: number): boolean;\n\n        /**\n         * Sets active group to a speicified one\n         * @param {fabric.Group} group Group to set as a current one\n         * @param {Event} [e] Event (passed along when firing)\n         */\n        setActiveGroup(group: IGroup, e?: Event): ICanvas;\n\n        /**\n         * Sets given object as the only active object on canvas\n         * @param {fabric.Object} object Object to set as an active one\n         * @param {Event} [e] Event (passed along when firing \"object:selected\")\n         */\n        setActiveObject(object: IObject, e?: Event): ICanvas;\n\n        /**\n         * Set the cursor type of the canvas element\n         * @param {String} value Cursor type of the canvas element.\n         * @see http://www.w3.org/TR/css3-ui/#cursor\n         */\n        setCursor(value: string): void;\n\n        /**\n         * Removes all event listeners\n         */\n        removeListeners(): void\n    }\n\n    interface ICanvasStatic {\n        /**\n         * Constructor\n         * @param {HTMLElement|String} element <canvas> element to initialize instance on\n         * @param {Object} [options] Options object\n         */\n        new (element: HTMLCanvasElement | string, options?: ICanvasOptions): ICanvas;\n\n        EMPTY_JSON: string;\n\n        /**\n         * Provides a way to check support of some of the canvas methods\n         * (either those of HTMLCanvasElement itself, or rendering context)\n         * @param {String} methodName Method to check support for; Could be one of \"getImageData\", \"toDataURL\", \"toDataURLWithQuality\" or \"setLineDash\"\n         */\n        supports(methodName: string): boolean;\n\n        prototype: any;\n\n        /**\n         * Returns JSON representation of canvas\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toJSON(propertiesToInclude?: any[]): string;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////\n    // Shape Interfaces\n    //////////////////////////////////////////////////////////////////////////////\n\n    interface ICircleOptions extends IObjectOptions {\n        /**\n         * Radius of this circle\n         */\n        radius?: number;\n        /**\n         * Start angle of the circle, moving clockwise\n         */\n        startAngle?: number;\n\n        /**\n         * End angle of the circle\n         */\n        endAngle?: number;\n    }\n\n    interface ICircle extends IObject, ICircleOptions {\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity(): number;\n\n        /**\n         * Returns horizontal radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRadiusX(): number;\n\n        /**\n         * Returns vertical radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRadiusY(): number;\n\n        /**\n         * Sets radius of an object (and updates width accordingly)\n         * @return {Number}\n         */\n        setRadius(value: number): number;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface ICircleStatic {\n        /**\n         * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})\n         */\n        ATTRIBUTE_NAMES: string[];\n\n        /**\n         * Returns Circle instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options: ICircleOptions): ICircle;\n\n        /**\n         * Returns Circle instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): ICircle;\n\n        /**\n         * Circle class\n         */\n        new (options?: ICircleOptions): ICircle;\n\n        prototype: any;\n    }\n\n    interface IEllipseOptions extends IObjectOptions {\n        /**\n         * Horizontal radius\n         */\n        rx?: number;\n        /**\n         * Vertical radius\n         */\n        ry?: number;\n    }\n\n    interface IEllipse extends IObject, IEllipseOptions {\n        /**\n         * Returns horizontal radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRx(): number;\n\n        /**\n         * Returns Vertical radius of an object (according to how an object is scaled)\n         * @return {Number}\n         */\n        getRy(): number;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity(): number;\n    }\n\n    interface IEllipseStatic {\n        new (options?: IEllipseOptions): IEllipse;\n\n        /**\n         * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement})\n         */\n        ATTRIBUTE_NAMES: string[];\n\n        /**\n         * Returns Ellipse instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options?: IEllipseOptions): IEllipse;\n\n        /**\n         * Returns Ellipse instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): IEllipse;\n    }\n\n    interface IGroup extends IObject, ICollection<IGroup> {\n        activateAllObjects(): IGroup;\n\n        /**\n         * Adds an object to a group; Then recalculates group's dimension, position.\n         * @param {Object} object\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        addWithUpdate(object: IObject): IGroup;\n\n        containsPoint(point: IPoint): boolean;\n\n        /**\n         * Destroys a group (restoring state of its objects)\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        destroy(): IGroup;\n\n        /**\n         * Returns requested property\n         * @param {String} prop Property to get\n         * @return {Any}\n         */\n        get(prop: string): any;\n\n        /**\n         * Checks whether this group was moved (since `saveCoords` was called last)\n         * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called)\n         */\n        hasMoved(): boolean;\n\n        /**\n         * Removes an object from a group; Then recalculates group's dimension, position.\n         * @param {Object} object\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        removeWithUpdate(object: IObject): IGroup;\n\n        /**\n         * Renders instance on a given context\n         * @param {CanvasRenderingContext2D} ctx context to render instance on\n         */\n        render(ctx: CanvasRenderingContext2D): void;\n\n        /**\n         * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n         * @param {...fabric.Object} object Zero or more fabric instances\n         * @return {Self} thisArg\n         * @chainable\n         */\n        remove(...object: IObject[]): IGroup;\n\n        /**\n         * Saves coordinates of this instance (to be used together with `hasMoved`)\n         * @saveCoords\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        saveCoords(): IGroup;\n\n        /**\n         * Sets coordinates of all group objects\n         * @return {fabric.Group} thisArg\n         * @chainable\n         */\n        setObjectsCoords(): IGroup;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns string represenation of a group\n         * @return {String}\n         */\n        toString(): string;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface IGroupStatic {\n        /**\n         * Constructor\n         * @param {Object} objects Group objects\n         * @param {Object} [options] Options object\n         */\n        new (items?: any[], options?: IObjectOptions): IGroup;\n\n        /**\n         * Returns {@link fabric.Group} instance from an object representation\n         * @param {Object} object Object to create a group from\n         * @param {Function} [callback] Callback to invoke when an group instance is created\n         */\n        fromObject(object: any, callback: (group: IGroup) => any): void;\n    }\n\n    interface IImageOptions extends IObjectOptions {\n        /**\n         * crossOrigin value (one of \"\", \"anonymous\", \"allow-credentials\")\n         */\n        crossOrigin: string;\n\n        /**\n         * AlignX value, part of preserveAspectRatio (one of \"none\", \"mid\", \"min\", \"max\")\n         * This parameter defines how the picture is aligned to its viewport when image element width differs from image width.\n         */\n        alignX: string;\n\n        /**\n         * AlignY value, part of preserveAspectRatio (one of \"none\", \"mid\", \"min\", \"max\")\n         * This parameter defines how the picture is aligned to its viewport when image element height differs from image height.\n         */\n        alignY: string;\n\n        /**\n         * meetOrSlice value, part of preserveAspectRatio  (one of \"meet\", \"slice\").\n         * if meet the image is always fully visibile, if slice the viewport is always filled with image.\n         * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute\n         */\n        meetOrSlice: string;\n\n        /**\n         * Image filter array\n         */\n        filters: IBaseFilter[];\n    }\n\n    interface IImage extends IObject, IImageOptions {\n        initialize(element?: string | HTMLImageElement, options?: IImageOptions): void;\n\n        /**\n         * Applies filters assigned to this image (from \"filters\" array)\n         * @param {Function} callback Callback is invoked when all filters have been applied and new image is generated\n         */\n        applyFilters(callback: Function): void;\n\n        /**\n         * Returns a clone of an instance\n         * @param {Function} callback Callback is invoked with a clone as a first argument\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        clone(callback?: Function, propertiesToInclude?: any[]): IObject;\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity(): number;\n\n        /**\n         * Returns image element which this instance if based on\n         * @return {HTMLImageElement} Image element\n         */\n        getElement(): HTMLImageElement;\n\n        /**\n         * Returns original size of an image\n         * @return {Object} Object with \"width\" and \"height\" properties\n         */\n        getOriginalSize(): { width: number; height: number; };\n\n        /**\n         * Returns source of an image\n         * @return {String} Source of an image\n         */\n        getSrc(): string;\n\n        render(ctx: CanvasRenderingContext2D, noTransform: boolean): void;\n\n        /**\n         * Sets image element for this instance to a specified one.\n         * If filters defined they are applied to new image.\n         * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area.\n         * @param {HTMLImageElement} element\n         * @param {Function} [callback] Callback is invoked when all filters have been applied and new image is generated\n         * @param {Object} [options] Options object\n         */\n        setElement(element: HTMLImageElement, callback: Function, options: IImageOptions): IImage;\n\n        /**\n         * Sets crossOrigin value (on an instance and corresponding image element)\n         */\n        setCrossOrigin(value: string): IImage;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns string representation of an instance\n         * @return {String} String representation of an instance\n         */\n        toString(): string;\n\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n\n        /**\n         * Sets source of an image\n         * @param {String} src Source string (URL)\n         * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied)\n         * @param {Object} [options] Options object\n         */\n        setSrc(src: string, callback: Function, options: IImageOptions): IImage;\n    }\n\n    interface IImageStatic {\n        /**\n         * Constructor\n         * @param {HTMLImageElement | String} element Image element\n         * @param {Object} [options] Options object\n         */\n        new (element: HTMLImageElement, objObjects: IObjectOptions): IImage;\n\n        /**\n         * Creates an instance of fabric.Image from an URL string\n         * @param {String} url URL to create an image from\n         * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument)\n         * @param {Object} [imgOptions] Options object\n         */\n        fromURL(url: string, callback?: (image: IImage) => any, objObjects?: IObjectOptions): IImage;\n\n        /**\n         * Creates an instance of fabric.Image from its object representation\n         * @static\n         * @param {Object} object Object to create an instance from\n         * @param {Function} [callback] Callback to invoke when an image instance is created\n         */\n        fromObject(object: any, callback: (image: IImage) => {}): void;\n\n        /**\n         * Returns Image instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Function} callback Callback to execute when fabric.Image object is created\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, callback: Function, options?: IImageOptions): void;\n\n        prototype: any;\n        /**\n         * Default CSS class name for canvas\n         */\n        CSS_CANVAS: string;\n\n        filters: IAllFilters\n    }\n\n    interface ILineOptions extends IObjectOptions {\n        /**\n         * x value or first line edge\n         */\n        x1: number;\n        /**\n         * x value or second line edge\n         */\n        x2: number;\n        /**\n         * y value or first line edge\n         */\n        y1: number;\n        /**\n         * y value or second line edge\n         */\n        y2: number;\n    }\n\n    interface ILine extends IObject, ILineOptions {\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity(): number;\n\n        initialize(points?: number[], options?: ILineOptions): ILine;\n\n        /**\n         * Returns object representation of an instance\n         * @methd toObject\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude: any[]): any;\n\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface ILineStatic {\n        ATTRIBUTE_NAMES: string[];\n\n        /**\n         * Returns fabric.Line instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options?: ILineOptions): ILine;\n\n        /**\n         * Returns fabric.Line instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): ILine;\n\n        prototype: any;\n\n        /**\n         * Constructor\n         * @param {Array} [points] Array of points\n         * @param {Object} [options] Options object\n         */\n        new (points?: number[], objObjects?: IObjectOptions): ILine;\n    }\n\n    interface IObjectOptions {\n        /**\n         * Type of an object (rect, circle, path, etc.).\n         * Note that this property is meant to be read-only and not meant to be modified.\n         * If you modify, certain parts of Fabric (such as JSON loading) won't work correctly.\n         */\n        type?: string;\n\n        /**\n         * Horizontal origin of transformation of an object (one of \"left\", \"right\", \"center\")\n         */\n        originX?: string;\n\n        /**\n         * Vertical origin of transformation of an object (one of \"top\", \"bottom\", \"center\")\n         */\n        originY?: string;\n\n        /**\n         * Top position of an object. Note that by default it's relative to object center. You can change this by setting originY={top/center/bottom}\n         */\n        top?: number;\n\n        /**\n         * Left position of an object. Note that by default it's relative to object center. You can change this by setting originX={left/center/right}\n         */\n        left?: number;\n\n        /**\n         * Object width\n         */\n        width?: number;\n\n        /**\n         * Object height\n         */\n        height?: number;\n\n        /**\n         * Object scale factor (horizontal)\n         */\n        scaleX?: number;\n\n        /**\n         * Object scale factor (vertical)\n         */\n        scaleY?: number;\n\n        /**\n         * When true, an object is rendered as flipped horizontally\n         */\n        flipX?: boolean;\n\n        /**\n         * When true, an object is rendered as flipped vertically\n         */\n        flipY?: boolean;\n\n        /**\n         * Opacity of an object\n         */\n        opacity?: number;\n\n        /**\n         * Angle of rotation of an object (in degrees)\n         */\n        angle?: number;\n\n        /**\n         * Size of object's controlling corners (in pixels)\n         */\n        cornerSize?: number;\n\n        /**\n         * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)\n         */\n        transparentCorners?: boolean;\n\n        /**\n         * Default cursor value used when hovering over this object on canvas\n         */\n        hoverCursor?: string;\n\n        /**\n         * Padding between object and its controlling borders (in pixels)\n         */\n        padding?: number;\n\n        /**\n         * Color of controlling borders of an object (when it's active)\n         */\n        borderColor?: string;\n\n        /**\n         * Color of controlling corners of an object (when it's active)\n         */\n        cornerColor?: string;\n\n        /**\n         * When true, this object will use center point as the origin of transformation\n         * when being scaled via the controls.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         */\n        centeredScaling?: boolean;\n\n        /**\n         * When true, this object will use center point as the origin of transformation\n         * when being rotated via the controls.\n         * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n         */\n        centeredRotation?: boolean;\n\n        /**\n         * Color of object's fill\n         */\n        fill?: string;\n\n        /**\n         * Fill rule used to fill an object\n         * accepted values are nonzero, evenodd\n         * Backwards incompatibility note: This property was used for setting globalCompositeOperation until v1.4.12, use `globalCompositeOperation` instead\n         */\n        fillRule?: string;\n\n        /**\n         * Composite rule used for canvas globalCompositeOperation\n         */\n        globalCompositeOperation?: string;\n\n        /**\n         * Background color of an object. Only works with text objects at the moment.\n         */\n        backgroundColor?: string;\n\n        /**\n         * When defined, an object is rendered via stroke and this property specifies its color\n         */\n        stroke?: string;\n\n        /**\n         * Width of a stroke used to render this object\n         */\n        strokeWidth?: number;\n\n        /**\n         * Array specifying dash pattern of an object's stroke (stroke must be defined)\n         */\n        strokeDashArray?: any[];\n\n        /**\n         * Line endings style of an object's stroke (one of \"butt\", \"round\", \"square\")\n         */\n        strokeLineCap?: string;\n\n        /**\n         * Corner style of an object's stroke (one of \"bevil\", \"round\", \"miter\")\n         */\n        strokeLineJoin?: string;\n\n        /**\n         * Maximum miter length (used for strokeLineJoin = \"miter\") of an object's stroke\n         */\n        strokeMiterLimit?: number;\n\n        /**\n         * Shadow object representing shadow of this shape\n         */\n        shadow?: IShadow | string;\n\n        /**\n         * Opacity of object's controlling borders when object is active and moving\n         */\n        borderOpacityWhenMoving?: number;\n\n        /**\n         * Scale factor of object's controlling borders\n         */\n        borderScaleFactor?: number;\n\n        /**\n         * Transform matrix (similar to SVG's transform matrix)\n         */\n        transformMatrix?: any[];\n\n        /**\n         * Minimum allowed scale value of an object\n         */\n        minScaleLimit?: number;\n\n        /**\n         * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).\n         * But events still fire on it.\n         */\n        selectable?: boolean;\n\n        /**\n         * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4\n         */\n        evented?: boolean;\n\n        /**\n         * When set to `false`, an object is not rendered on canvas\n         */\n        visible?: boolean;\n\n        /**\n         * When set to `false`, object's controls are not displayed and can not be used to manipulate object\n         */\n        hasControls?: boolean;\n\n        /**\n         * When set to `false`, object's controlling borders are not rendered\n         */\n        hasBorders?: boolean;\n\n        /**\n         * When set to `false`, object's controlling rotating point will not be visible or selectable\n         */\n        hasRotatingPoint?: boolean;\n\n        /**\n         * Offset for object's controlling rotating point (when enabled via `hasRotatingPoint`)\n         */\n        rotatingPointOffset?: number;\n\n        /**\n         * When set to `true`, objects are \"found\" on canvas on per-pixel basis rather than according to bounding box\n         */\n        perPixelTargetFind?: boolean;\n\n        /**\n         * When `false`, default object's values are not included in its serialization\n         */\n        includeDefaultValues?: boolean;\n\n        /**\n         * Function that determines clipping of an object (context is passed as a first argument)\n         * Note that context origin is at the object's center point (not left/top corner)\n         * @type Function\n         */\n        clipTo?: Function;\n\n        /**\n         * When `true`, object horizontal movement is locked\n         */\n        lockMovementX?: boolean;\n\n        /**\n         * When `true`, object vertical movement is locked\n         */\n        lockMovementY?: boolean;\n\n        /**\n         * When `true`, object rotation is locked\n         */\n        lockRotation?: boolean;\n\n        /**\n         * When `true`, object horizontal scaling is locked\n         */\n        lockScalingX?: boolean;\n\n        /**\n         * When `true`, object vertical scaling is locked\n         */\n        lockScalingY?: boolean;\n\n        /**\n         * When `true`, object non-uniform scaling is locked\n         */\n        lockUniScaling?: boolean;\n\n        /**\n         * When `true`, object cannot be flipped by scaling into negative values\n         */\n        lockScalingFlip?: boolean;\n\n        /**\n         * Not used by fabric, just for convenience\n         */\n        name?: string;\n\n        /**\n         * Not used by fabric, just for convenience\n         */\n        data?: any;\n    }\n\n    interface IObject extends IObservable<IObject>, IObjectOptions, IObjectAnimation<IObject> {\n        getCurrentWidth(): number;\n\n        getCurrentHeight(): number;\n\n        getAngle(): number;\n\n        setAngle(value: number): IObject;\n\n        getBorderColor(): string;\n\n        setBorderColor(value: string): IObject;\n\n        getBorderScaleFactor(): number;\n\n        getCornersize(): number;\n\n        setCornersize(value: number): IObject;\n\n        getFill(): string;\n\n        setFill(value: string): IObject;\n\n        getFillRule(): string;\n\n        setFillRule(value: string): IObject;\n\n        getFlipX(): boolean;\n\n        setFlipX(value: boolean): IObject;\n\n        getFlipY(): boolean;\n\n        setFlipY(value: boolean): IObject;\n\n        getHeight(): number;\n\n        setHeight(value: number): IObject;\n\n        getLeft(): number;\n\n        setLeft(value: number): IObject;\n\n        getOpacity(): number;\n\n        setOpacity(value: number): IObject;\n\n        overlayFill: string;\n\n        getOverlayFill(): string;\n\n        setOverlayFill(value: string): IObject;\n\n        getScaleX(): number;\n\n        setScaleX(value: number): IObject;\n\n        getScaleY(): number;\n\n        setScaleY(value: number): IObject;\n\n        setShadow(options: any): IObject;\n\n        getShadow(): IObject;\n\n        stateProperties: any[];\n\n        getTop(): number;\n\n        setTop(value: number): IObject;\n\n        getWidth(): number;\n\n        setWidth(value: number): IObject;\n\n        /* * Sets object's properties from options\n         * @param {Object} [options] Options object\n         */\n        setOptions(options: any): void;\n\n        /**\n         * Transforms context when rendering an object\n         * @param {CanvasRenderingContext2D} ctx Context\n         * @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node\n         */\n        transform(ctx: CanvasRenderingContext2D, fromLeft: boolean): void;\n\n        /**\n         * Returns an object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns (dataless) object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toDatalessObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns a string representation of an instance\n         */\n        toString(): string;\n\n        /**\n         * Basic getter\n         * @param {String} property Property name\n         */\n        get(property: string): any;\n\n        /**\n         * Sets property to a given value.\n         * When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls.\n         * If you need to update those, call `setCoords()`.\n         * @param {String} key Property name\n         * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n         */\n        set(key: string, value: any | Function): IObject;\n\n        /**\n         * Sets property to a given value.\n         * When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls.\n         * If you need to update those, call `setCoords()`.\n         * @param Object key Property object, iterate over the object properties\n         */\n        set(key: any): IObject;\n\n        /**\n         * Toggles specified property from `true` to `false` or from `false` to `true`\n         * @param {String} property Property to toggle\n         */\n        toggle(property: string): IObject;\n\n        /**\n         * Sets sourcePath of an object\n         * @param {String} value Value to set sourcePath to\n         */\n        setSourcePath(value: string): IObject;\n\n        /**\n         * Retrieves viewportTransform from Object's canvas if possible\n         */\n        getViewportTransform(): boolean;\n\n        /**\n         * Renders an object on a specified context\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        render(ctx: CanvasRenderingContext2D, noTransform?: boolean): void;\n\n        /**\n         * Clones an instance\n         * @param {Function} callback Callback is invoked with a clone as a first argument\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        clone(callback: Function, propertiesToInclude?: any[]): IObject;\n\n        /**\n         * Creates an instance of fabric.Image out of an object\n         * @param {Function} callback callback, invoked with an instance as a first argument\n         */\n        cloneAsImage(callback: (image: IImage) => any): IObject;\n\n        /**\n         * Converts an object into a data-url-like string\n         * @param options Options object\n         */\n        toDataURL(options: IDataURLOptions): string;\n\n        /**\n         * Returns true if specified type is identical to the type of an instance\n         * @param {String} type Type to check against\n         */\n        isType(type: string): boolean;\n\n        /**\n         * Returns complexity of an instance\n         */\n        complexity(): number;\n\n        /**\n         * Returns a JSON representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toJSON(propertiesToInclude?: any[]): any;\n\n        /**\n         * Sets gradient (fill or stroke) of an object\n         * <b>Backwards incompatibility note:</b> This method was named \"setGradientFill\" until v1.1.0\n         * @param {String} property Property name 'stroke' or 'fill'\n         * @param {Object} [options] Options object\n         */\n        setGradient(property: string, options: IGradientOptions): IObject;\n\n        /**\n         * Sets pattern fill of an object\n         * @param {Object} options Options object\n         */\n        setPatternFill(options: IFillOptions): IObject;\n\n        /**\n         * Sets shadow of an object\n         * @param {String} [options] Options object or string (e.g. \"2px 2px 10px rgba(0,0,0,0.2)\")\n         */\n        setShadow(options?: string): IObject;\n\n        /**\n         * Sets shadow of an object\n         * @param [options] Options object\n         */\n        setShadow(options: IShadow): IObject;\n\n        /**\n         * Sets \"color\" of an instance (alias of `set('fill', …)`)\n         * @param {String} color Color value\n         */\n        setColor(color: string): IObject;\n\n        /**\n         * Sets \"angle\" of an instance\n         * @param {Number} angle Angle value\n         */\n        setAngle(angle: number): IObject;\n\n        /**\n         * Sets \"angle\" of an instance\n         * @param {Number} angle Angle value\n         */\n        rotate(angle: number): IObject;\n\n        /**\n         * Centers object horizontally on canvas to which it was added last.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         */\n        centerH(): void;\n\n        /**\n         * Centers object vertically on canvas to which it was added last.\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         */\n        centerV(): void;\n\n        /**\n         * Centers object vertically and horizontally on canvas to which is was added last\n         * You might need to call `setCoords` on an object after centering, to update controls area.\n         */\n        center(): void;\n\n        /**\n         * Removes object from canvas to which it was added last\n         */\n        remove(): IObject;\n\n        /**\n         * Returns coordinates of a pointer relative to an object\n         * @param {Event} e Event to operate upon\n         * @param {Object} [pointer] Pointer to operate upon (instead of event)\n         */\n        getLocalPointer(e: Event, pointer: any): any;\n\n        /**\n         * Sets object's properties from options\n         * @param {Object} [options] Options object\n         */\n        setOptions(options: any): void;\n\n        /**\n         * Sets sourcePath of an object\n         * @param {String} value Value to set sourcePath to\n         */\n        setSourcePath(value: string): IObject;\n\n        // functions from object svg export mixin\n        // -----------------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Returns styles-string for svg-export\n         */\n        getSvgStyles(): string;\n\n        /**\n         * Returns transform-string for svg-export\n         */\n        getSvgTransform(): string;\n\n        /**\n         * Returns transform-string for svg-export from the transform matrix of single elements\n         */\n        getSvgTransformMatrix(): string;\n\n        // functions from stateful mixin\n        // -----------------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Returns true if object state (one of its state properties) was changed\n         */\n        hasStateChanged(): boolean;\n\n        /**\n         * Saves state of an object\n         * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n         * @return {fabric.Object} thisArg\n         */\n        saveState(options?: { stateProperties: any[] }): IObject;\n\n        /**\n         * Setups state of an object\n         */\n        setupState(): IObject;\n\n        // functions from object straightening mixin\n        // -----------------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer)\n         */\n        straighten(): IObject;\n\n        /**\n         * Same as straighten but with animation\n         * @param {Object} callbacks Object with callback functions\n         * @param {Function} [callbacks.onComplete] Invoked on completion\n         * @param {Function} [callbacks.onChange] Invoked on every step of animation\n         */\n        fxStraighten(callbacks: { onComplete?: Function; onChange: Function }): IObject;\n\n        // functions from object stacking mixin\n        // -----------------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Moves an object up in stack of drawn objects\n         * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n         */\n        bringForward(intersecting?: boolean): IObject;\n\n        /**\n         * Moves an object to the top of the stack of drawn objects\n         */\n        bringToFront(): IObject;\n\n        /**\n         * Moves an object down in stack of drawn objects\n         * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n         */\n        sendBackwards(intersecting?: boolean): IObject;\n\n        /**\n         * Moves an object to the bottom of the stack of drawn objects\n         */\n        sendToBack(): IObject;\n\n        /**\n         * Moves an object to specified level in stack of drawn objects\n         * @param {Number} index New position of object\n         */\n        moveTo(index: number): IObject;\n\n        // functions from object origin mixin\n        // -----------------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Translates the coordinates from origin to center coordinates (based on the object's dimensions)\n         * @param {fabric.Point} point The point which corresponds to the originX and originY params\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         */\n        translateToCenterPoint(point: IPoint, originX: string, originY: string): IPoint;\n\n        /**\n         * Translates the coordinates from center to origin coordinates (based on the object's dimensions)\n         * @param {fabric.Point} center The point which corresponds to center of the object\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         */\n        translateToOriginPoint(center: IPoint, originX: string, originY: string): IPoint;\n\n        /**\n         * Returns the real center coordinates of the object\n         */\n        getCenterPoint(): IPoint;\n\n        /**\n         * Returns the coordinates of the object as if it has a different origin\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         */\n        getPointByOrigin(): IPoint;\n\n        /**\n         * Returns the point in local coordinates\n         * @param {fabric.Point} point The point relative to the global coordinate system\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         */\n        toLocalPoint(point: IPoint, originX: string, originY: string): IPoint;\n\n        /**\n         * Sets the position of the object taking into consideration the object's origin\n         * @param {fabric.Point} pos The new position of the object\n         * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n         * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n         * @return {void}\n         */\n        setPositionByOrigin(pos: IPoint, originX: string, originY: string): void;\n\n        /**\n         * @param {String} to One of 'left', 'center', 'right'\n         */\n        adjustPosition(to: string): void;\n\n        // functions from interactivity mixin\n        // -----------------------------------------------------------------------------------------------------------------------------------\n        /**-\n         * Draws borders of an object's bounding box.\n         * Requires public properties: width, height\n         * Requires public options: padding, borderColor\n         * @param {CanvasRenderingContext2D} ctx Context to draw on\n         */\n        drawBorders(context: CanvasRenderingContext2D): IObject;\n\n        /**\n         * Draws corners of an object's bounding box.\n         * Requires public properties: width, height\n         * Requires public options: cornerSize, padding\n         * @param {CanvasRenderingContext2D} ctx Context to draw on\n         */\n        drawCorners(context: CanvasRenderingContext2D): IObject;\n\n        /**\n         * Returns true if the specified control is visible, false otherwise.\n         * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n         */\n        isControlVisible(controlName: string): boolean;\n\n        /**\n         * Sets the visibility of the specified control.\n         * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n         * @param {Boolean} visible true to set the specified control visible, false otherwise\n         */\n        setControlVisible(controlName: string, visible: boolean): IObject;\n\n        /**\n         * Sets the visibility state of object controls.\n         * @param {Object} [options] Options object\n         */\n        setControlsVisibility(options?: {\n            bl?: boolean;\n            br?: boolean;\n            mb?: boolean;\n            ml?: boolean;\n            mr?: boolean;\n            mt?: boolean;\n            tl?: boolean;\n            tr?: boolean;\n            mtr?: boolean;\n        }): IObject;\n\n        // functions from geometry mixin\n        // -------------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Sets corner position coordinates based on current angle, width and height\n         * See https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords\n         */\n        setCoords(): IObject;\n\n        /**\n         * Returns coordinates of object's bounding rectangle (left, top, width, height)\n         * @return {Object} Object with left, top, width, height properties\n         */\n        getBoundingRect(): { left: number; top: number; width: number; height: number };\n\n        /**\n         * Checks if object is fully contained within area of another object\n         * @param {Object} other Object to test\n         */\n        isContainedWithinObject(other: IObject): boolean;\n\n        /**\n         * Checks if object is fully contained within area formed by 2 points\n         * @param {Object} pointTL top-left point of area\n         * @param {Object} pointBR bottom-right point of area\n         */\n        isContainedWithinRect(pointTL: any, pointBR: any): boolean;\n\n        /**\n         * Checks if point is inside the object\n         * @param {fabric.Point} point Point to check against\n         */\n        containsPoint(point: IPoint): boolean;\n\n        /**\n         * Scales an object (equally by x and y)\n         * @param {Number} value Scale factor\n         * @return {fabric.Object} thisArg\n         */\n        scale(value: number): IObject;\n\n        /**\n         * Scales an object to a given height, with respect to bounding box (scaling by x/y equally)\n         * @param {Number} value New height value\n         */\n        scaleToHeight(value: number): IObject;\n\n        /**\n         * Scales an object to a given width, with respect to bounding box (scaling by x/y equally)\n         * @param {Number} value New width value\n         */\n        scaleToWidth(value: number): IObject;\n\n        /**\n         * Checks if object intersects with another object\n         * @param {Object} other Object to test\n         */\n        intersectsWithObject(other: IObject): boolean;\n\n        /**\n         * Checks if object intersects with an area formed by 2 points\n         * @param {Object} pointTL top-left point of area\n         * @param {Object} pointBR bottom-right point of area\n         */\n        intersectsWithRect(pointTL: any, pointBR: any): boolean;\n    }\n\n    interface IObjectStatic {\n        prototype: any;\n    }\n\n    interface IPathOptions extends IObjectOptions {\n        /**\n         * Array of path points\n         */\n        path?: any[];\n\n        /**\n         * Minimum X from points values, necessary to offset points\n         */\n        minX?: number;\n\n        /**\n         * Minimum Y from points values, necessary to offset points\n         */\n        minY?: number;\n    }\n\n    interface IPath extends IObject, IPathOptions {\n        initialize(path?: any[], options?: IPathOptions): IPath;\n\n        /**\n         * Returns number representation of an instance complexity\n         * @return {Number} complexity of this instance\n         */\n        complexity(): number;\n\n        /**\n         * Renders path on a specified context\n         * @param {CanvasRenderingContext2D} ctx context to render path on\n         * @param {Boolean} [noTransform] When true, context is not transformed\n         */\n        render(ctx: CanvasRenderingContext2D, noTransform: boolean): void;\n\n        /**\n         * Returns dataless object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toDatalessObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns string representation of an instance\n         * @return {String} string representation of an instance\n         */\n        toString(): string;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface IPathStatic {\n        /**\n         * Creates an instance of fabric.Path from an SVG <path> element\n         * @param {SVGElement} element to parse\n         * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, callback: (path: IPath) => any, options?: IPathOptions): void;\n\n        /**\n         * Creates an instance of fabric.Path from an object\n         * @param {Object} object\n         * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n         */\n        fromObject(object: any, callback: (path: IPath) => any): void;\n\n        /**\n         * Constructor\n         * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n         * @param {Object} [options] Options object\n         */\n        new (path?: string | any[], options?: IPathOptions): IPath;\n    }\n\n    interface IPathGroup extends IObject {\n        initialize(paths: IPath[], options?: IObjectOptions): void;\n\n        /**\n         * Returns number representation of object's complexity\n         * @return {Number} complexity\n         */\n        complexity(): number;\n\n        /**\n         * Returns true if all paths in this group are of same color\n         * @return {Boolean} true if all paths are of the same color (`fill`)\n         */\n        isSameColor(): boolean;\n\n        /**\n         * Renders this group on a specified context\n         * @param {CanvasRenderingContext2D} ctx Context to render this instance on\n         */\n        render(ctx: CanvasRenderingContext2D): void;\n\n        /**\n         * Returns dataless object representation of this path group\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} dataless object representation of an instance\n         */\n        toDatalessObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns object representation of this path group\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns a string representation of this path group\n         * @return {String} string representation of an object\n         */\n        toString(): string;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n\n        /**\n         * Returns all paths in this path group\n         * @return {Array} array of path objects included in this path group\n         */\n        getObjects(): IPath[];\n    }\n\n    interface IPathGroupStatic {\n        fromObject(object: any): IPathGroup;\n\n        /**\n         * Constructor\n         * @param {Array} paths\n         * @param {Object} [options] Options object\n         */\n        new (paths: IPath[], options?: IObjectOptions): IPathGroup;\n\n        /**\n         * Creates fabric.PathGroup instance from an object representation\n         * @static\n         * @memberOf fabric.PathGroup\n         * @param {Object} object Object to create an instance from\n         * @param {Function} callback Callback to invoke when an fabric.PathGroup instance is created\n         */\n        fromObject(object: any, callback: (group: IPathGroup) => any): void;\n\n        prototype: any;\n    }\n\n    interface IPolygonOptions extends IObjectOptions {\n        /**\n         * Points array\n         */\n        points?: IPoint[];\n\n        /**\n         * Minimum X from points values, necessary to offset points\n         */\n        minX?: number;\n\n        /**\n         * Minimum Y from points values, necessary to offset points\n         */\n        minY?: number;\n    }\n\n    interface IPolygon extends IObject, IPolygonOptions {\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity(): number;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface IPolygonStatic {\n        /**\n         * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)\n         */\n        ATTRIBUTE_NAMES: string[];\n\n        /**\n         * Returns Polygon instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options?: IPolygonOptions): IPolygon;\n\n        /**\n         * Returns fabric.Polygon instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): IPolygon;\n\n        /**\n         * Constructor\n         * @param {Array} points Array of points\n         * @param {Object} [options] Options object\n         */\n        new (points: { x: number; y: number }[], options?: IObjectOptions, skipOffset?: boolean): IPolygon;\n\n        prototype: any;\n    }\n\n    interface IPolylineOptions extends IObjectOptions {\n        /**\n         * Points array\n         */\n        points?: IPoint[];\n\n        /**\n         * Minimum X from points values, necessary to offset points\n         */\n        minX?: number;\n\n        /**\n         * Minimum Y from points values, necessary to offset points\n         */\n        minY?: number;\n    }\n\n    interface IPolyline extends IObject, IPolylineOptions {\n        initialize(points: IPoint[], options?: IPolylineOptions): void;\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n        complexity(): number;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} Object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): any;\n\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface IPolylineStatic {\n        /**\n         * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)\n         */\n        ATTRIBUTE_NAMES: string[];\n\n        /**\n         * Returns Polyline  instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options?: IPolylineOptions): IPolyline;\n\n        /**\n         * Returns fabric.Polyline instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): IPolyline;\n\n        /**\n         * Constructor\n         * @param {Array} points Array of points (where each point is an object with x and y)\n         * @param {Object} [options] Options object\n         * @param {Boolean} [skipOffset] Whether points offsetting should be skipped\n         */\n        new (points: { x: number; y: number }[], options?: IPolylineOptions): IPolyline;\n\n        prototype: any;\n    }\n\n    interface IRectOptions extends IObjectOptions {\n        id?: any;\n        lineWidth?: number;\n        x?: number;\n        y?: number;\n        /**\n         * Horizontal border radius\n         */\n        rx?: number;\n\n        /**\n         * Vertical border radius\n         */\n        ry?: number;\n\n    }\n\n    interface IRect extends IObject, IRectOptions {\n        initialize(points?: number[], options?: any): IRect;\n\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity\n         */\n        complexity(): number;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude: any[]): any;\n\n        /**\n         * Returns svg representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface IRectStatic {\n        /**\n         * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)\n         */\n        ATTRIBUTE_NAMES: string[];\n\n        /**\n         * Returns Rect instance from an SVG element\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options?: IRectOptions): IRect;\n\n        /**\n         * Returns Rect instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): IRect;\n\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         */\n        new (options?: IRectOptions): IRect;\n\n        prototype: any;\n    }\n\n    interface ITextOptions extends IObjectOptions {\n        /**\n         * Font size (in pixels)\n         */\n        fontSize?: number;\n        /**\n         * Font weight (e.g. bold, normal, 400, 600, 800)\n         */\n        fontWeight?: number | string;\n        /**\n         * Font family\n         */\n        fontFamily?: string;\n        /**\n         * Text decoration Possible values?: \"\", \"underline\", \"overline\" or \"line-through\".\n         */\n        textDecoration?: string;\n        /**\n         * Text alignment. Possible values?: \"left\", \"center\", or \"right\".\n         */\n        textAlign?: string;\n        /**\n         * Font style . Possible values?: \"\", \"normal\", \"italic\" or \"oblique\".\n         */\n        fontStyle?: string;\n        /**\n         * Line height\n         */\n        lineHeight?: number;\n        /**\n         * When defined, an object is rendered via stroke and this property specifies its color.\n         * <b>Backwards incompatibility note?:</b> This property was named \"strokeStyle\" until v1.1.6\n         */\n        stroke?: string;\n        /**\n         * Shadow object representing shadow of this shape.\n         * <b>Backwards incompatibility note?:</b> This property was named \"textShadow\" (String) until v1.2.11\n         */\n        shadow?: IShadow | string;\n        /**\n         * Background color of text lines\n         */\n        textBackgroundColor?: string;\n\n        path?: string;\n        useNative?: Boolean;\n        text?: string;\n    }\n\n    interface IText extends IObject, ITextOptions {\n        /**\n         * Returns complexity of an instance\n         */\n        complexity(): number;\n\n        /**\n         * Returns string representation of an instance\n         */\n        toString(): string;\n\n        /**\n         * Renders text instance on a specified context\n         * @param {CanvasRenderingContext2D} ctx Context to render on\n         */\n        render(ctx: CanvasRenderingContext2D, noTransform: boolean): void;\n\n        /**\n         * Returns object representation of an instance\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         */\n        toObject(propertiesToInclude?: any[]): IObject;\n\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         */\n        toSVG(reviver?: Function): string;\n\n        /**\n         * Retrieves object's fontSize\n         */\n        getFontSize(): number;\n\n        /**\n         * Sets object's fontSize\n         * @param {Number} fontSize Font size (in pixels)\n         */\n        setFontSize(fontSize: number): IText;\n\n        /**\n         * Retrieves object's fontWeight\n         */\n        getFontWeight(): number | string;\n\n        /**\n         * Sets object's fontWeight\n         * @param {(Number|String)} fontWeight Font weight\n         */\n        setFontWeight(fontWeight: string | number): IText;\n\n        /**\n         * Retrieves object's fontFamily\n         */\n        getFontFamily(): string;\n\n        /**\n         * Sets object's fontFamily\n         * @param {String} fontFamily Font family\n         */\n        setFontFamily(fontFamily: string): IText;\n\n        /**\n         * Retrieves object's text\n         */\n        getText(): string;\n\n        /**\n         * Sets object's text\n         * @param {String} text Text\n         */\n        setText(text: string): IText;\n\n        /**\n         * Retrieves object's textDecoration\n         */\n        getTextDecoration(): string;\n\n        /**\n         * Sets object's textDecoration\n         * @param {String} textDecoration Text decoration\n         */\n        setTextDecoration(textDecoration: string): IText;\n\n        /**\n         * Retrieves object's fontStyle\n         */\n        getFontStyle(): string;\n\n        /**\n         * Sets object's fontStyle\n         * @param {String} fontStyle Font style\n         */\n        setFontStyle(fontStyle: string): IText;\n\n        /**\n         * Retrieves object's lineHeight\n         */\n        getLineHeight(): number;\n\n        /**\n         * Sets object's lineHeight\n         * @param {Number} lineHeight Line height\n         */\n        setLineHeight(lineHeight: number): IText;\n\n        /**\n         * Retrieves object's textAlign\n         */\n        getTextAlign(): string;\n\n        /**\n         * Sets object's textAlign\n         * @param {String} textAlign Text alignment\n         */\n        setTextAlign(textAlign: string): IText;\n\n        /**\n         * Retrieves object's textBackgroundColor\n         */\n        getTextBackgroundColor(): string;\n\n        /**\n         * Sets object's textBackgroundColor\n         * @param {String} textBackgroundColor Text background color\n         */\n        setTextBackgroundColor(textBackgroundColor: string): IText;\n    }\n\n    interface ITextStatic {\n        /**\n         * List of attribute names to account for when parsing SVG element (used by `fabric.Text.fromElement`)\n         */\n        ATTRIBUTE_NAMES: string[];\n        /**\n         * Default SVG font size\n         */\n        DEFAULT_SVG_FONT_SIZE: number;\n\n        /**\n         * Constructor\n         * @param {String} text Text string\n         * @param {Object} [options] Options object\n         */\n        new (text: string, options?: ITextOptions): IText;\n\n        /**\n         * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)\n         * @param {SVGElement} element Element to parse\n         * @param {Object} [options] Options object\n         */\n        fromElement(element: SVGElement, options?: ITextOptions): IText;\n\n        /**\n         * Returns fabric.Text instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): IText;\n    }\n\n    interface IITextOptions extends IObjectOptions, ITextOptions {\n        /**\n         * Index where text selection starts (or where cursor is when there is no selection)\n         */\n        selectionStart?: number;\n\n        /**\n         * Index where text selection ends\n         */\n        selectionEnd?: number;\n\n        /**\n         * Color of text selection\n         */\n        selectionColor?: string;\n\n        /**\n         * Indicates whether text is in editing mode\n         */\n        isEditing?: boolean;\n\n        /**\n         * Indicates whether a text can be edited\n         */\n        editable?: boolean;\n\n        /**\n         * Border color of text object while it's in editing mode\n         */\n        editingBorderColor?: string;\n\n        /**\n         * Width of cursor (in px)\n         */\n        cursorWidth?: number;\n\n        /**\n         * Color of default cursor (when not overwritten by character style)\n         */\n        cursorColor?: string;\n\n        /**\n         * Delay between cursor blink (in ms)\n         */\n        cursorDelay?: number;\n\n        /**\n         * Duration of cursor fadein (in ms)\n         */\n        cursorDuration?: number;\n\n        /**\n         * Object containing character styles\n         * (where top-level properties corresponds to line number and 2nd-level properties -- to char number in a line)\n         */\n        styles?: any;\n\n        /**\n         * Indicates whether internal text char widths can be cached\n         */\n        caching?: boolean;\n    }\n\n    interface IIText extends IObject, IText, IITextOptions {\n        /**\n         * Returns true if object has no styling\n         */\n        isEmptyStyles(): boolean;\n\n        render(ctx: CanvasRenderingContext2D, noTransform: boolean): void;\n\n        /**\n         * Returns object representation of an instance\n         * @method toObject\n         * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n         * @return {Object} object representation of an instance\n         */\n        toObject(propertiesToInclude?: any[]): IObject;\n\n        setText(value: string): IText;\n\n        /**\n         * Sets selection start (left boundary of a selection)\n         * @param {Number} index Index to set selection start to\n         */\n        setSelectionStart(index: number): void;\n\n        /**\n         * Sets selection end (right boundary of a selection)\n         * @param {Number} index Index to set selection end to\n         */\n        setSelectionEnd(index: number): void;\n\n        /**\n         * Gets style of a current selection/cursor (at the start position)\n         * @param {Number} [startIndex] Start index to get styles at\n         * @param {Number} [endIndex] End index to get styles at\n         * @return {Object} styles Style object at a specified (or current) index\n         */\n        getSelectionStyles(startIndex: number, endIndex: number): any;\n\n        /**\n         * Sets style of a current selection\n         * @param {Object} [styles] Styles object\n         * @return {fabric.IText} thisArg\n         * @chainable\n         */\n        setSelectionStyles(styles: any): IText;\n\n        /**\n         * Renders cursor or selection (depending on what exists)\n         */\n        renderCursorOrSelection(): void;\n\n        /**\n         * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n         * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n         */\n        get2DCursorLocation(selectionStart?: number): void;\n\n        /**\n         * Returns complete style of char at the current cursor\n         * @param {Number} lineIndex Line index\n         * @param {Number} charIndex Char index\n         * @return {Object} Character style\n         */\n        getCurrentCharStyle(lineIndex: number, charIndex: number): any;\n\n        /**\n         * Returns fontSize of char at the current cursor\n         * @param {Number} lineIndex Line index\n         * @param {Number} charIndex Char index\n         * @return {Number} Character font size\n         */\n        getCurrentCharFontSize(lineIndex: number, charIndex: number): number;\n\n        /**\n         * Returns color (fill) of char at the current cursor\n         * @param {Number} lineIndex Line index\n         * @param {Number} charIndex Char index\n         * @return {String} Character color (fill)\n         */\n        getCurrentCharColor(lineIndex: number, charIndex: number): string;\n\n        /**\n         * Renders cursor\n         * @param {Object} boundaries\n         */\n        renderCursor(boundaries: any): void;\n\n        /**\n         * Renders text selection\n         * @param {Array} chars Array of characters\n         * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n         */\n        renderSelection(chars: string[], boundaries: any): void;\n\n        // functions from itext behavior mixin\n        // ------------------------------------------------------------------------------------------------------------------------\n        /**\n         * Initializes all the interactive behavior of IText\n         */\n        initBehavior(): void;\n\n        /**\n         * Initializes \"selected\" event handler\n         */\n        initSelectedHandler(): void;\n\n        /**\n         * Initializes \"added\" event handler\n         */\n        initAddedHandler(): void;\n\n        initRemovedHandler(): void;\n\n        /**\n         * Initializes delayed cursor\n         */\n        initDelayedCursor(restart: boolean): void;\n\n        /**\n         * Aborts cursor animation and clears all timeouts\n         */\n        abortCursorAnimation(): void;\n\n        /**\n         * Selects entire text\n         */\n        selectAll(): void;\n\n        /**\n         * Returns selected text\n         */\n        getSelectedText(): string;\n\n        /**\n         * Find new selection index representing start of current word according to current selection index\n         * @param {Number} startFrom Surrent selection index\n         * @return {Number} New selection index\n         */\n        findWordBoundaryLeft(startFrom: number): number;\n\n        /**\n         * Find new selection index representing end of current word according to current selection index\n         * @param {Number} startFrom Current selection index\n         * @return {Number} New selection index\n         */\n        findWordBoundaryRight(startFrom: number): number;\n\n        /**\n         * Find new selection index representing start of current line according to current selection index\n         * @param {Number} startFrom Current selection index\n         */\n        findLineBoundaryLeft(startFrom: number): number;\n\n        /**\n         * Find new selection index representing end of current line according to current selection index\n         * @param {Number} startFrom Current selection index\n         */\n        findLineBoundaryRight(startFrom: number): number;\n\n        /**\n         * Returns number of newlines in selected text\n         */\n        getNumNewLinesInSelectedText(): number;\n\n        /**\n         * Finds index corresponding to beginning or end of a word\n         * @param {Number} selectionStart Index of a character\n         * @param {Number} direction: 1 or -1\n         */\n        searchWordBoundary(selectionStart: number, direction: number): number;\n\n        /**\n         * Selects a word based on the index\n         * @param {Number} selectionStart Index of a character\n         */\n        selectWord(selectionStart: number): void;\n\n        /**\n         * Selects a line based on the index\n         * @param {Number} selectionStart Index of a character\n         */\n        selectLine(selectionStart: number): void;\n\n        /**\n         * Enters editing state\n         */\n        enterEditing(): IIText;\n\n        /**\n         * Initializes \"mousemove\" event handler\n         */\n        initMouseMoveHandler(): void;\n\n        /**\n         * Exits from editing state\n         * @return {fabric.IText} thisArg\n         * @chainable\n         */\n        exitEditing(): IIText;\n\n        /**\n         * Inserts a character where cursor is (replacing selection if one exists)\n         * @param {String} _chars Characters to insert\n         */\n        insertChars(_chars: string, useCopiedStyle?: boolean): void;\n\n        /**\n         * Inserts new style object\n         * @param {Number} lineIndex Index of a line\n         * @param {Number} charIndex Index of a char\n         * @param {Boolean} isEndOfLine True if it's end of line\n         */\n        insertNewlineStyleObject(lineIndex: number, charIndex: number, isEndOfLine: boolean): void;\n\n        /**\n         * Inserts style object for a given line/char index\n         * @param {Number} lineIndex Index of a line\n         * @param {Number} charIndex Index of a char\n         * @param {Object} [style] Style object to insert, if given\n         */\n        insertCharStyleObject(lineIndex: number, charIndex: number, isEndOfLine: boolean): void;\n\n        /**\n         * Inserts style object(s)\n         * @param {String} _chars Characters at the location where style is inserted\n         * @param {Boolean} isEndOfLine True if it's end of line\n         * @param {Boolean} [useCopiedStyle] Style to insert\n         */\n        insertStyleObjects(_chars: string, isEndOfLine: boolean, useCopiedStyle?: boolean): void;\n\n        /**\n         * Shifts line styles up or down\n         * @param {Number} lineIndex Index of a line\n         * @param {Number} offset Can be -1 or +1\n         */\n        shiftLineStyles(lineIndex: number, offset: number): void;\n\n        /**\n         * Removes style object\n         * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line\n         * @param {Number} [index] Optional index. When not given, current selectionStart is used.\n         */\n        removeStyleObject(isBeginningOfLine: boolean, index?: number): void;\n\n        /**\n         * Inserts new line\n         */\n        insertNewline(): void;\n\n    }\n\n    interface IITextStatic extends ITextStatic {\n        /**\n         * Constructor\n         * @param {String} text Text string\n         * @param {Object} [options] Options object\n         */\n        new (text: string, options?: IITextOptions): IIText;\n\n        /**\n         * Returns fabric.IText instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): IIText;\n    }\n\n    interface ITriangleOptions extends IObjectOptions {\n    }\n\n    interface ITriangle extends IObject {\n        /**\n         * Returns complexity of an instance\n         * @return {Number} complexity of this instance\n         */\n\n        complexity(): number;\n\n        /**\n         * Returns SVG representation of an instance\n         * @param {Function} [reviver] Method for further parsing of svg representation.\n         * @return {String} svg representation of an instance\n         */\n        toSVG(reviver?: Function): string;\n    }\n\n    interface ITriangleStatic {\n        /**\n         * Constructor\n         * @param {Object} [options] Options object\n         */\n        new (options?: ITriangleOptions): ITriangle;\n\n        /**\n         * Returns Triangle instance from an object representation\n         * @param {Object} object Object to create an instance from\n         */\n        fromObject(object: any): ITriangle;\n    }\n\n    ////////////////////////////////////////////////////////////\n    // Filters\n    ////////////////////////////////////////////////////////////\n    interface IAllFilters {\n        BaseFilter: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: any): IBaseFilter;\n        };\n        Blend: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: { color?: string; mode?: string; alpha?: number; image?: IImage }): IBlendFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IBlendFilter\n        };\n        Brightness: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Number} [options.brightness=0] Value to brighten the image up (0..255)\n             */\n            new (options?: { brightness: number }): IBrightnessFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IBrightnessFilter\n        };\n        Convolute: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Boolean} [options.opaque=false] Opaque value (true/false)\n             * @param {Array} [options.matrix] Filter matrix\n             */\n            new (options?: { opaque?: boolean; matrix?: number[] }): IConvoluteFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IConvoluteFilter\n        };\n        GradientTransparency: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Number} [options.threshold=100] Threshold value\n             */\n            new (options?: { threshold?: number; }): IGradientTransparencyFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IGradientTransparencyFilter\n        };\n        Grayscale: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: any): IGrayscaleFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IGrayscaleFilter\n        };\n        Invert: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: any): IInvertFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IInvertFilter\n        };\n        Mask: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {fabric.Image} [options.mask] Mask image object\n             * @param {Number} [options.channel=0] Rgb channel (0, 1, 2 or 3)\n             */\n            new (options?: { mask?: IImage; channel: number; }): IMaskFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IMaskFilter\n        };\n        Multiply: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Number} [options.color=#000000] Color to multiply the image pixels with\n             */\n            new (options?: { color: string; }): IMultiplyFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IMultiplyFilter\n        };\n        Noise: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Number} [options.noise=0] Noise value\n             */\n            new (options?: { noise: number; }): INoiseFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): INoiseFilter\n        };\n        Pixelate: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Number} [options.blocksize=4] Blocksize for pixelate\n             */\n            new (options?: { blocksize?: number; }): IPixelateFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IPixelateFilter\n        };\n        RemoveWhite: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {Number} [options.threshold=30] Threshold value\n             * @param {Number} [options.distance=20] Distance value\n             */\n            new (options?: { threshold?: number; distance?: number; }): IRemoveWhiteFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IRemoveWhiteFilter\n        };\n        Resize: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: any): IResizeFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): IResizeFilter\n        };\n        Sepia2: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: any): ISepia2Filter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): ISepia2Filter\n        };\n        Sepia: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             */\n            new (options?: any): ISepiaFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): ISepiaFilter\n        };\n        Tint: {\n            /**\n             * Constructor\n             * @param {Object} [options] Options object\n             * @param {String} [options.color=#000000] Color to tint the image with\n             * @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1)\n             */\n            new (options?: { color?: string; opacity?: number; }): ITintFilter;\n            /**\n             * Returns filter instance from an object representation\n             * @param {Object} object Object to create an instance from\n             */\n            fromObject(object: any): ITintFilter\n        };\n    }\n\n    interface IBaseFilter {\n        /**\n         * Sets filter's properties from options\n         * @param {Object} [options] Options object\n         */\n        setOptions(options?: any): void;\n\n        /**\n         * Returns object representation of an instance\n         */\n        toObject(): any;\n\n        /**\n         * Returns a JSON representation of an instance\n         */\n        toJSON(): string;\n    }\n\n    interface IBlendFilter extends IBaseFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IBrightnessFilter extends IBaseFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IConvoluteFilter extends IBaseFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IGradientTransparencyFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IGrayscaleFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IInvertFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IMaskFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IMultiplyFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface INoiseFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IPixelateFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IRemoveWhiteFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface IResizeFilter {\n        /**\n         * Resize type\n         */\n        resizeType: string;\n\n        /**\n         * Scale factor for resizing, x axis\n         */\n        scaleX: number;\n\n        /**\n         * Scale factor for resizing, y axis\n         */\n        scaleY: number;\n\n        /**\n         * LanczosLobes parameter for lanczos filter\n         */\n        lanczosLobes: number;\n\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface ISepiaFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface ISepia2Filter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    interface ITintFilter {\n        /**\n         * Applies filter to canvas element\n         * @param {Object} canvasEl Canvas element to apply filter to\n         */\n        applyTo(canvasEl: HTMLCanvasElement): void;\n    }\n\n    ////////////////////////////////////////////////////////////\n    // Brushes\n    ////////////////////////////////////////////////////////////\n    interface IBaseBrush {\n        /**\n         * Color of a brush\n         */\n        color: string;\n\n        /**\n         * Width of a brush\n         */\n        width: number;\n\n        /**\n         * Shadow object representing shadow of this shape.\n         * <b>Backwards incompatibility note:</b> This property replaces \"shadowColor\" (String), \"shadowOffsetX\" (Number),\n         * \"shadowOffsetY\" (Number) and \"shadowBlur\" (Number) since v1.2.12\n         */\n        shadow: IShadow | string;\n        /**\n         * Line endings style of a brush (one of \"butt\", \"round\", \"square\")\n         */\n        strokeLineCap: string;\n\n        /**\n         * Corner style of a brush (one of \"bevil\", \"round\", \"miter\")\n         */\n        strokeLineJoin: string;\n\n        /**\n         * Stroke Dash Array.\n         */\n        strokeDashArray: any[];\n\n        /**\n         * Sets shadow of an object\n         * @param {Object|String} [options] Options object or string (e.g. \"2px 2px 10px rgba(0,0,0,0.2)\")\n         */\n        setShadow(options: string | any): IBaseBrush;\n\n    }\n\n    interface ICircleBrush extends IBaseBrush {\n        /**\n         * Width of a brush\n         */\n        width: number;\n\n        /**\n         * Invoked inside on mouse down and mouse move\n         * @param {Object} pointer\n         */\n        drawDot(pointer: any): void;\n\n        /**\n         * @param {Object} pointer\n         * @return {fabric.Point} Just added pointer point\n         */\n        addPoint(pointer: any): IPoint\n    }\n\n    interface ISprayBrush extends IBaseBrush {\n        /**\n         * Width of a brush\n         */\n        width: number;\n        /**\n         * Density of a spray (number of dots per chunk)\n         */\n        density: number;\n\n        /**\n         * Width of spray dots\n         */\n        dotWidth: number;\n        /**\n         * Width variance of spray dots\n         */\n        dotWidthVariance: number;\n\n        /**\n         * Whether opacity of a dot should be random\n         */\n        randomOpacity: boolean;\n        /**\n         * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n         */\n        optimizeOverlapping: boolean;\n\n        /**\n         * @param {Object} pointer\n         */\n        addSprayChunk(pointer: any): void\n    }\n\n    interface IPatternBrush extends IPencilBrush {\n        getPatternSrc(): HTMLCanvasElement;\n\n        getPatternSrcFunction(): string;\n\n        /**\n         * Creates \"pattern\" instance property\n         */\n        getPattern(): any;\n\n        /**\n         * Creates path\n         */\n        createPath(pathData: string): IPath;\n    }\n\n    interface IPencilBrush extends IBaseBrush {\n        /**\n         * Converts points to SVG path\n         * @param {Array} points Array of points\n         * @param {Number} minX\n         * @param {Number} minY\n         */\n        convertPointsToSVGPath(points: { x: number; y: number }[], minX?: number, minY?: number): string[];\n\n        /**\n         * Creates fabric.Path object to add on canvas\n         * @param {String} pathData Path data\n         */\n        createPath(pathData: string): IPath;\n    }\n\n    var BaseBrush: {\n        new (): IBaseBrush\n    };\n    var CircleBrush: {\n        new (canvas: fabric.ICanvas): ICircle\n    };\n    var SprayBrush: {\n        new (canvas: fabric.ICanvas): ISprayBrush\n    };\n    var PencilBrush: {\n        new (canvas: fabric.ICanvas): IPencilBrush\n    };\n    var PatternBrush: {\n        new (canvas: fabric.ICanvas): IPatternBrush\n    };\n    ///////////////////////////////////////////////////////////////////////////////\n    // Fabric util Interface\n    //////////////////////////////////////////////////////////////////////////////\n    interface IUtilAnimationOptions {\n        /**\n         * Starting value\n         */\n        startValue?: number;\n        /**\n         * Ending value\n         */\n        endValue?: number;\n        /**\n         * Value to modify the property by\n         */\n        byValue: number;\n        /**\n         * Duration of change (in ms)\n         */\n        duration?: number;\n        /**\n         * Callback; invoked on every value change\n         */\n        onChange?: Function;\n        /**\n         * Callback; invoked when value change is completed\n         */\n        onComplete?: Function;\n        /**\n         * Easing function\n         */\n        easing?: Function;\n    }\n\n    interface IUtilAnimation {\n        /**\n         * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.\n         * @param {Object} [options] Animation options\n         */\n        animate(options?: IUtilAnimationOptions): void;\n\n        /**\n         * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n         * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method\n         * @param {Function} callback Callback to invoke\n         */\n        requestAnimFrame(callback: Function): void;\n    }\n\n    interface IUtilAminEaseFunction {\n        (t: number, b: number, c: number, d: number): number;\n    }\n\n    interface IUtilAnimEase {\n        easeInBack: IUtilAminEaseFunction;\n        easeInBounce: IUtilAminEaseFunction;\n        easeInCirc: IUtilAminEaseFunction;\n        easeInCubic: IUtilAminEaseFunction;\n        easeInElastic: IUtilAminEaseFunction;\n        easeInExpo: IUtilAminEaseFunction;\n        easeInOutBack: IUtilAminEaseFunction;\n        easeInOutBounce: IUtilAminEaseFunction;\n        easeInOutCirc: IUtilAminEaseFunction;\n        easeInOutCubic: IUtilAminEaseFunction;\n        easeInOutElastic: IUtilAminEaseFunction;\n        easeInOutExpo: IUtilAminEaseFunction;\n        easeInOutQuad: IUtilAminEaseFunction;\n        easeInOutQuart: IUtilAminEaseFunction;\n        easeInOutQuint: IUtilAminEaseFunction;\n        easeInOutSine: IUtilAminEaseFunction;\n        easeInQuad: IUtilAminEaseFunction;\n        easeInQuart: IUtilAminEaseFunction;\n        easeInQuint: IUtilAminEaseFunction;\n        easeInSine: IUtilAminEaseFunction;\n        easeOutBack: IUtilAminEaseFunction;\n        easeOutBounce: IUtilAminEaseFunction;\n        easeOutCirc: IUtilAminEaseFunction;\n        easeOutCubic: IUtilAminEaseFunction;\n        easeOutElastic: IUtilAminEaseFunction;\n        easeOutExpo: IUtilAminEaseFunction;\n        easeOutQuad: IUtilAminEaseFunction;\n        easeOutQuart: IUtilAminEaseFunction;\n        easeOutQuint: IUtilAminEaseFunction;\n        easeOutSine: IUtilAminEaseFunction;\n    }\n\n    interface IUtilArc {\n        /**\n         * Draws arc\n         * @param {CanvasRenderingContext2D} ctx\n         * @param {Number} fx\n         * @param {Number} fy\n         * @param {Array} coords\n         */\n        drawArc(ctx: CanvasRenderingContext2D, fx: number, fy: number, coords: number[]): void;\n\n        /**\n         * Calculate bounding box of a elliptic-arc\n         * @param {Number} fx start point of arc\n         * @param {Number} fy\n         * @param {Number} rx horizontal radius\n         * @param {Number} ry vertical radius\n         * @param {Number} rot angle of horizontal axe\n         * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points\n         * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction\n         * @param {Number} tx end point of arc\n         * @param {Number} ty\n         */\n        getBoundsOfArc(fx: number, fy: number, rx: number, ry: number, rot: number, large: number, sweep: number, tx: number, ty: number): IPoint[];\n\n        /**\n         * Calculate bounding box of a beziercurve\n         * @param {Number} x0 starting point\n         * @param {Number} y0\n         * @param {Number} x1 first control point\n         * @param {Number} y1\n         * @param {Number} x2 secondo control point\n         * @param {Number} y2\n         * @param {Number} x3 end of beizer\n         * @param {Number} y3\n         */\n        getBoundsOfCurve(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): IPoint[];\n\n    }\n\n    interface IUtilDomEvent {\n        /**\n         * Cross-browser wrapper for getting event's coordinates\n         * @param {Event} event Event object\n         * @param {HTMLCanvasElement} upperCanvasEl &lt;canvas> element on which object selection is drawn\n         */\n        getPointer(event: Event, upperCanvasEl: HTMLCanvasElement): IPoint;\n\n        /**\n         * Adds an event listener to an element\n         * @param {HTMLElement} element\n         * @param {String} eventName\n         * @param {Function} handler\n         */\n        addListener(element: HTMLElement, eventName: string, handler: Function): void;\n\n        /**\n         * Removes an event listener from an element\n         * @param {HTMLElement} element\n         * @param {String} eventName\n         * @param {Function} handler\n         */\n        removeListener(element: HTMLElement, eventName: string, handler: Function): void;\n    }\n\n    interface IUtilDomMisc {\n        /**\n         * Takes id and returns an element with that id (if one exists in a document)\n         * @param {String|HTMLElement} id\n         */\n        getById(id: string | HTMLElement): HTMLElement;\n\n        /**\n         * Converts an array-like object (e.g. arguments or NodeList) to an array\n         * @param {Object} arrayLike\n         */\n        toArray(arrayLike: any): any[];\n\n        /**\n         * Creates specified element with specified attributes\n         * @memberOf fabric.util\n         * @param {String} tagName Type of an element to create\n         * @param {Object} [attributes] Attributes to set on an element\n         * @return {HTMLElement} Newly created element\n         */\n        makeElement(tagName: string, attributes?: any): HTMLElement;\n\n        /**\n         * Adds class to an element\n         * @param {HTMLElement} element Element to add class to\n         * @param {String} className Class to add to an element\n         */\n        addClass(element: HTMLElement, classname: string): void;\n\n        /**\n         * Wraps element with another element\n         * @param {HTMLElement} element Element to wrap\n         * @param {HTMLElement|String} wrapper Element to wrap with\n         * @param {Object} [attributes] Attributes to set on a wrapper\n         */\n        wrapElement(element: HTMLElement, wrapper: HTMLElement | string, attributes?: any): HTMLElement;\n\n        /**\n         * Returns element scroll offsets\n         * @param {HTMLElement} element Element to operate on\n         * @param {HTMLElement} upperCanvasEl Upper canvas element\n         */\n        getScrollLeftTop(element: HTMLElement, upperCanvasEl: HTMLElement): { left: number; right: number; };\n\n        /**\n         * Returns offset for a given element\n         * @param {HTMLElement} element Element to get offset for\n         */\n        getElementOffset(element: HTMLElement): { left: number; right: number; };\n\n        /**\n         * Returns style attribute value of a given element\n         * @param {HTMLElement} element Element to get style attribute for\n         * @param {String} attr Style attribute to get for element\n         */\n        getElementStyle(elment: HTMLElement, attr: string): string;\n\n        /**\n         * Inserts a script element with a given url into a document; invokes callback, when that script is finished loading\n         * @memberOf fabric.util\n         * @param {String} url URL of a script to load\n         * @param {Function} callback Callback to execute when script is finished loading\n         */\n        getScript(url: string, callback: Function): void;\n\n        /**\n         * Makes element unselectable\n         * @param {HTMLElement} element Element to make unselectable\n         */\n        makeElementUnselectable(element: HTMLElement): HTMLElement;\n\n        /**\n         * Makes element selectable\n         * @param {HTMLElement} element Element to make selectable\n         */\n        makeElementSelectable(element: HTMLElement): HTMLElement;\n    }\n\n    interface IUtilDomRequest {\n        /**\n         * Cross-browser abstraction for sending XMLHttpRequest\n         * @param {String} url URL to send XMLHttpRequest to\n         * @param {Object} [options] Options object\n         * @param {String} [options.method=\"GET\"]\n         * @param {Function} options.onComplete Callback to invoke when request is completed\n         */\n        request(url: string, options?: { method?: string; onComplete: Function }): XMLHttpRequest;\n    }\n\n    interface IUtilDomStyle {\n        /**\n         * Cross-browser wrapper for setting element's style\n         * @param {HTMLElement} element\n         * @param {Object} styles\n         */\n        setStyle(element: HTMLElement, styles: any): HTMLElement;\n    }\n\n    interface IUtilArray {\n        /**\n         * Invokes method on all items in a given array\n         * @param {Array} array Array to iterate over\n         * @param {String} method Name of a method to invoke\n         */\n        invoke(array: any[], method: string): any[];\n\n        /**\n         * Finds minimum value in array (not necessarily \"first\" one)\n         * @param {Array} array Array to iterate over\n         * @param {String} byProperty\n         */\n        min(array: any[], byProperty: string): any;\n\n        /**\n         * Finds maximum value in array (not necessarily \"first\" one)\n         * @param {Array} array Array to iterate over\n         * @param {String} byProperty\n         */\n        max(array: any[], byProperty: string): any;\n    }\n\n    interface IUtilClass {\n        /**\n         * Helper for creation of \"classes\".\n         * @param {Function} [parent] optional \"Class\" to inherit from\n         * @param {Object} [properties] Properties shared by all instances of this class\n         *                  (be careful modifying objects defined here as this would affect all instances)\n         */\n        createClass(parent: Function, properties?: any): void;\n\n        /**\n         * Helper for creation of \"classes\".\n         * @param {Object} [properties] Properties shared by all instances of this class\n         *                  (be careful modifying objects defined here as this would affect all instances)\n         */\n        createClass(properties?: any): void;\n\n    }\n\n    interface IUtilObject {\n        /**\n         * Copies all enumerable properties of one object to another\n         * @param {Object} destination Where to copy to\n         * @param {Object} source Where to copy from\n         */\n        extend(destination: any, source: any): any;\n\n        /**\n         * Creates an empty object and copies all enumerable properties of another object to it\n         * @memberOf fabric.util.object\n         * @param {Object} object Object to clone\n         * @return {Object}\n         */\n        clone(object: any): any\n    }\n\n    interface IUtilString {\n        /**\n         * Camelizes a string\n         * @param {String} string String to camelize\n         */\n        camelize(string: string): string;\n\n        /**\n         * Capitalizes a string\n         * @param {String} string String to capitalize\n         * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized\n         * and other letters stay untouched, if false first letter is capitalized\n         * and other letters are converted to lowercase.\n         */\n        capitalize(string: string, firstLetterOnly: boolean): string;\n\n        /**\n         * Escapes XML in a string\n         * @param {String} string String to escape\n         */\n        escapeXml(string: string): string;\n    }\n\n    interface IUtilMisc {\n        /**\n         * Removes value from an array.\n         * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf`\n         * @param {Array} array\n         * @param {Any} value\n         */\n        removeFromArray(array: any[], value: any): any[];\n\n        /**\n         * Returns random number between 2 specified ones.\n         * @param {Number} min lower limit\n         * @param {Number} max upper limit\n         */\n        getRandomInt(min: number, max: number): number;\n\n        /**\n         * Transforms degrees to radians.\n         * @param {Number} degrees value in degrees\n         */\n        degreesToRadians(degrees: number): number;\n\n        /**\n         * Transforms radians to degrees.\n         * @memberOf fabric.util\n         * @param {Number} radians value in radians\n         */\n        radiansToDegrees(radians: number): number;\n\n        /**\n         * Rotates `point` around `origin` with `radians`\n         * @param {fabric.Point} point The point to rotate\n         * @param {fabric.Point} origin The origin of the rotation\n         * @param {Number} radians The radians of the angle for the rotation\n         */\n        rotatePoint(point: IPoint, origin: IPoint, radians: number): IPoint;\n\n        /**\n         * Apply transform t to point p\n         * @param  {fabric.Point} p The point to transform\n         * @param  {Array} t The transform\n         * @param  {Boolean} [ignoreOffset] Indicates that the offset should not be applied\n         */\n        transformPoint(p: IPoint, t: any[], ignoreOffset?: boolean): IPoint;\n\n        /**\n         * Invert transformation t\n         * @param {Array} t The transform\n         */\n        invertTransform(t: any[]): any[];\n\n        /**\n         * A wrapper around Number#toFixed, which contrary to native method returns number, not string.\n         * @param {Number|String} number number to operate on\n         * @param {Number} fractionDigits number of fraction digits to \"leave\"\n         */\n        toFixed(number: number, fractionDigits: number): number;\n\n        /**\n         * Converts from attribute value to pixel value if applicable.\n         * Returns converted pixels or original value not converted.\n         * @param {Number|String} value number to operate on\n         */\n        parseUnit(value: number | string, fontSize?: number): number | string;\n\n        /**\n         * Function which always returns `false`.\n         */\n        falseFunction(): boolean;\n\n        /**\n         * Returns klass \"Class\" object of given namespace\n         * @param {String} type Type of object (eg. 'circle')\n         * @param {String} namespace Namespace to get klass \"Class\" object from\n         */\n        getKlass(type: string, namespace: string): any;\n\n        /**\n         * Returns object of given namespace\n         * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric'\n         */\n        resolveNamespace(namespace: string): any;\n\n        /**\n         * Loads image element from given url and passes it to a callback\n         * @param {String} url URL representing an image\n         * @param {Function} callback Callback; invoked with loaded image\n         * @param {Any} [context] Context to invoke callback in\n         * @param {Object} [crossOrigin] crossOrigin value to set image element to\n         */\n        loadImage(url: string, callback: (image: HTMLImageElement) => {}, context?: any, crossOrigin?: boolean): void;\n\n        /**\n         * Creates corresponding fabric instances from their object representations\n         * @param {Array} objects Objects to enliven\n         * @param {Function} callback Callback to invoke when all objects are created\n         * @param {String} namespace Namespace to get klass \"Class\" object from\n         * @param {Function} reviver Method for further parsing of object elements, called after each fabric object created.\n         */\n        enlivenObjects(objects: any[], callback: Function, namespace: string, reviver?: Function): void;\n\n        /**\n         * Groups SVG elements (usually those retrieved from SVG document)\n         * @param {Array} elements SVG elements to group\n         * @param {Object} [options] Options object\n         */\n        groupSVGElements(elements: any[], options?: any, path?: any): IPathGroup;\n\n        /**\n         * Populates an object with properties of another object\n         * @param {Object} source Source object\n         * @param {Object} destination Destination object\n         * @param {Array} properties Propertie names to include\n         */\n        populateWithProperties(source: any, destination: any, properties: any): void;\n\n        /**\n         * Draws a dashed line between two points\n         * This method is used to draw dashed line around selection area.\n         * @param {CanvasRenderingContext2D} ctx context\n         * @param {Number} x  start x coordinate\n         * @param {Number} y start y coordinate\n         * @param {Number} x2 end x coordinate\n         * @param {Number} y2 end y coordinate\n         * @param {Array} da dash array pattern\n         */\n        drawDashedLine(ctx: CanvasRenderingContext2D, x: number, y: number, x2: number, y2: number, da: any[]): void;\n\n        /**\n         * Creates canvas element and initializes it via excanvas if necessary\n         * @param {CanvasElement} [canvasEl] optional canvas element to initialize;\n         * when not given, element is created implicitly\n         */\n        createCanvasElement(canvasEl?: HTMLCanvasElement): HTMLCanvasElement;\n\n        /**\n         * Creates image element (works on client and node)\n         */\n        createImage(): HTMLImageElement;\n\n        /**\n         * Creates accessors (getXXX, setXXX) for a \"class\", based on \"stateProperties\" array\n         * @param {Object} klass \"Class\" to create accessors for\n         */\n        createAccessors(klass: any): any;\n\n        /**\n         * @param {fabric.Object} receiver Object implementing `clipTo` method\n         * @param {CanvasRenderingContext2D} ctx Context to clip\n         */\n        clipContext(receiver: IObject, ctx: CanvasRenderingContext2D): void;\n\n        /**\n         * Multiply matrix A by matrix B to nest transformations\n         * @param  {Array} a First transformMatrix\n         * @param  {Array} b Second transformMatrix\n         */\n        multiplyTransformMatrices(a: any[], b: any[]): any[];\n\n        /**\n         * Returns string representation of function body\n         * @param {Function} fn Function to get body of\n         */\n        getFunctionBody(fn: Function): string;\n\n        /**\n         * Returns true if context has transparent pixel\n         * at specified location (taking tolerance into account)\n         * @param {CanvasRenderingContext2D} ctx context\n         * @param {Number} x x coordinate\n         * @param {Number} y y coordinate\n         * @param {Number} tolerance Tolerance\n         */\n        isTransparent(ctx: CanvasRenderingContext2D, x: number, y: number, tolerance: number): boolean;\n    }\n\n    interface IUtil extends IUtilAnimation, IUtilArc, IObservable<IUtil>, IUtilDomEvent, IUtilDomMisc,\n        IUtilDomRequest, IUtilDomStyle, IUtilClass, IUtilMisc {\n        ease: IUtilAnimEase;\n        array: IUtilArray;\n        object: IUtilObject;\n        string: IUtilString;\n    }\n}"
  },
  {
    "path": "src/validators/NameTakenValidator.ts",
    "content": "import {NgControl} from \"@angular/forms\";\ninterface ValidationResult {\n    [key:string]:boolean;\n}\n\nexport default function NameTakenValidator(control:NgControl):Promise<ValidationResult> | Promise<any> {\n    let q = new Promise((resolve, reject) => {\n        setTimeout(() => {\n            if (control.value === 'Sean') {\n                resolve({\"taken\": true});\n            } else {\n                resolve(null);\n            }\n        }, 1000)\n    });\n    return q;\n}\n"
  },
  {
    "path": "src/validators/StartCapValidator.ts",
    "content": "import {NgControl} from \"@angular/forms\";\nexport default function StartCapValidator(control: NgControl): { [s: string]: boolean } {\n    if (!control.value.match(/^[A-Z]/)) {\n        return {notCapped: true};\n    } else {\n        return null;\n    }\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"rulesDirectory\": [\n    \"node_modules/codelyzer\"\n  ],\n  \"rules\": {\n    \"class-name\": true,\n    \"comment-format\": [\n      true,\n      \"check-space\"\n    ],\n    \"curly\": false,\n    \"eofline\": false,\n    \"forin\": false,\n    \"indent\": [\n      true,\n      \"spaces\"\n    ],\n    \"label-position\": false,\n    \"max-line-length\": [\n      true,\n      440\n    ],\n    \"member-access\": false,\n    \"member-ordering\": [\n      true,\n      \"static-before-instance\",\n      \"variables-before-functions\"\n    ],\n    \"no-console\": [\n      true,\n      \"debug\",\n      \"info\",\n      \"time\",\n      \"timeEnd\",\n      \"trace\"\n    ],\n    \"callable-types\": true,\n    \"import-blacklist\": [true, \"rxjs\"],\n    \"import-spacing\": true,\n    \"interface-over-type-literal\": true,\n    \"no-empty-interface\": true,\n    \"no-string-throw\": true,\n    \"prefer-const\": true,\n    \"typeof-compare\": true,\n    \"unified-signatures\": true,\n    \"no-construct\": true,             \n    \"no-debugger\": true,\n    \"no-duplicate-variable\": true,\n    \"no-empty\": false,\n    \"no-eval\": true,\n    \"no-inferrable-types\": true,\n    \"no-shadowed-variable\": false,\n    \"no-string-literal\": false,\n    \"no-switch-case-fall-through\": true,\n    \"no-trailing-whitespace\": false,\n    \"no-unused-expression\": true,\n    \"no-use-before-declare\": true,\n    \"no-var-keyword\": false,\n    \"object-literal-sort-keys\": false,\n    \"one-line\": [\n      true,\n      \"check-open-brace\",\n      \"check-catch\",\n      \"check-else\"\n    ],\n    \"quotemark\": [\n      false,\n      \"single\"\n    ],\n    \"radix\": false,\n    \"semicolon\": [\n      \"always\"\n    ],\n    \"triple-equals\": [\n      false,\n      \"allow-null-check\"\n    ],\n    \"typedef-whitespace\": [\n      false,\n      {\n        \"call-signature\": \"nospace\",\n        \"index-signature\": \"nospace\",\n        \"parameter\": \"nospace\",\n        \"property-declaration\": \"nospace\",\n        \"variable-declaration\": \"nospace\"\n      }\n    ],\n    \"variable-name\": false,\n    \"whitespace\": [\n      false,\n      \"check-branch\",\n      \"check-decl\",\n      \"check-operator\",\n      \"check-separator\",\n      \"check-type\"\n    ],\n\n    \"directive-selector\": [true, \"attribute\", \"app\", \"camelCase\"],\n    \"component-selector\": [false, \"element\", \"app\", \"kebab-case\"],\n    \"use-input-property-decorator\": true,\n    \"use-output-property-decorator\": true,\n    \"use-host-property-decorator\": false,\n    \"no-input-rename\": true,\n    \"no-output-rename\": true,\n    \"use-life-cycle-interface\": true,\n    \"use-pipe-transform-interface\": true,\n    \"component-class-suffix\": false,\n    \"directive-class-suffix\": false,\n    \"no-access-missing-member\": true,\n    \"templates-use-public\": true,\n    \"invoke-injectable\": true\n  }\n}\n"
  },
  {
    "path": "typings.json",
    "content": "{\n  \"ambientDevDependencies\": {\n    \"es6-shim\": \"github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2\"\n  },\n  \"ambientDependencies\": {\n    \"require\": \"github:DefinitelyTyped/DefinitelyTyped/requirejs/require.d.ts#853544cb7068af64bdb10ef1ae0c54d3aa3a80f6\"\n  },\n  \"dependencies\": {\n    \"moment\": \"github:typed-typings/npm-moment#a4075cd50e63efbedd850f654594f293ab81a385\"\n  }\n}\n"
  }
]