From 2b7b3b78c388e2f7ecee98e87b793b9a19d2307a Mon Sep 17 00:00:00 2001 From: Rafael Monnerat <rafael@nexedi.com> Date: Mon, 16 Aug 2010 02:18:00 +0000 Subject: [PATCH] 2010-08-15 rafael * The initial version. Integration of Bespin Text Editor (http://mozillalabs.com/bespin) with ERP5 Editor Field. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@37826 20353a03-c40f-0410-a6d1-a30d3c3de9de --- .../registered_skin_selection.xml | 6 + .../portal_skins/erp5_bespin.xml | 35 + .../erp5_bespin/BespinEmbedded.css.xml | 162 + .../erp5_bespin/BespinEmbedded.js.xml | 10732 ++++++++++ .../erp5_bespin/BespinMain.js.xml | 17597 ++++++++++++++++ .../erp5_bespin/BespinWorker.js.xml | 1691 ++ .../erp5_bespin/bespin_support.xml | 83 + .../portal_skins/erp5_bespin/resources.xml | 29 + .../erp5_bespin/resources/completion.xml | 23 + .../erp5_bespin/resources/screen_theme.xml | 29 + .../resources/screen_theme/images.xml | 29 + .../screen_theme/images/bespin-s.png.xml | 186 + .../images/check-selected.png.xml | 65 + .../screen_theme/images/lines.png.xml | 113 + .../screen_theme/images/scroll-down.png.xml | 55 + .../screen_theme/images/scroll-left.png.xml | 55 + .../screen_theme/images/scroll-right.png.xml | 55 + .../screen_theme/images/scroll-up.png.xml | 55 + .../resources/screen_theme/theme.less.xml | 307 + bt5/erp5_bespin/bt/categories_list | 0 bt5/erp5_bespin/bt/change_log | 2 + bt5/erp5_bespin/bt/comment | 1 + bt5/erp5_bespin/bt/copyright_list | 1 + bt5/erp5_bespin/bt/dependency_list | 1 + bt5/erp5_bespin/bt/description | 1 + bt5/erp5_bespin/bt/license | 1 + bt5/erp5_bespin/bt/maintainer_list | 1 + bt5/erp5_bespin/bt/provision_list | 0 bt5/erp5_bespin/bt/publication_url | 1 + bt5/erp5_bespin/bt/revision | 1 + bt5/erp5_bespin/bt/template_action_path_list | 0 .../bt/template_base_category_list | 0 .../bt/template_catalog_datetime_key_list | 0 .../bt/template_catalog_full_text_key_list | 0 .../bt/template_catalog_keyword_key_list | 0 .../bt/template_catalog_local_role_key_list | 0 .../bt/template_catalog_method_id_list | 0 .../bt/template_catalog_multivalue_key_list | 0 .../bt/template_catalog_related_key_list | 0 .../bt/template_catalog_request_key_list | 0 .../bt/template_catalog_result_key_list | 0 .../bt/template_catalog_result_table_list | 0 .../bt/template_catalog_role_key_list | 0 .../bt/template_catalog_scriptable_key_list | 0 .../bt/template_catalog_topic_key_list | 0 .../bt/template_constraint_id_list | 0 bt5/erp5_bespin/bt/template_document_id_list | 0 bt5/erp5_bespin/bt/template_extension_id_list | 0 bt5/erp5_bespin/bt/template_format_version | 1 + bt5/erp5_bespin/bt/template_local_role_list | 0 bt5/erp5_bespin/bt/template_local_roles_list | 0 .../bt/template_message_translation_list | 0 bt5/erp5_bespin/bt/template_module_id_list | 0 bt5/erp5_bespin/bt/template_path_list | 0 ...late_portal_type_allowed_content_type_list | 0 .../template_portal_type_base_category_list | 0 ...plate_portal_type_hidden_content_type_list | 0 .../bt/template_portal_type_id_list | 0 .../template_portal_type_property_sheet_list | 0 .../bt/template_portal_type_role_list | 0 .../bt/template_portal_type_roles_list | 0 .../template_portal_type_workflow_chain_list | 0 bt5/erp5_bespin/bt/template_preference_list | 0 bt5/erp5_bespin/bt/template_product_id_list | 0 .../bt/template_property_sheet_id_list | 0 .../template_registered_skin_selection_list | 1 + bt5/erp5_bespin/bt/template_role_list | 0 .../bt/template_site_property_id_list | 0 bt5/erp5_bespin/bt/template_skin_id_list | 1 + bt5/erp5_bespin/bt/template_test_id_list | 0 bt5/erp5_bespin/bt/template_tool_id_list | 0 ...template_update_business_template_workflow | 1 + bt5/erp5_bespin/bt/template_update_tool | 1 + bt5/erp5_bespin/bt/template_workflow_id_list | 0 bt5/erp5_bespin/bt/title | 1 + bt5/erp5_bespin/bt/version | 1 + 76 files changed, 31324 insertions(+) create mode 100644 bt5/erp5_bespin/RegisteredSkinSelectionTemplateItem/registered_skin_selection.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.css.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.js.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinMain.js.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinWorker.js.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/bespin_support.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/completion.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/bespin-s.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/check-selected.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/lines.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-down.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-left.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-right.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-up.png.xml create mode 100644 bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/theme.less.xml create mode 100644 bt5/erp5_bespin/bt/categories_list create mode 100644 bt5/erp5_bespin/bt/change_log create mode 100644 bt5/erp5_bespin/bt/comment create mode 100644 bt5/erp5_bespin/bt/copyright_list create mode 100644 bt5/erp5_bespin/bt/dependency_list create mode 100644 bt5/erp5_bespin/bt/description create mode 100644 bt5/erp5_bespin/bt/license create mode 100644 bt5/erp5_bespin/bt/maintainer_list create mode 100644 bt5/erp5_bespin/bt/provision_list create mode 100644 bt5/erp5_bespin/bt/publication_url create mode 100644 bt5/erp5_bespin/bt/revision create mode 100644 bt5/erp5_bespin/bt/template_action_path_list create mode 100644 bt5/erp5_bespin/bt/template_base_category_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_datetime_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_full_text_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_keyword_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_local_role_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_method_id_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_multivalue_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_related_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_request_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_result_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_result_table_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_role_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_scriptable_key_list create mode 100644 bt5/erp5_bespin/bt/template_catalog_topic_key_list create mode 100644 bt5/erp5_bespin/bt/template_constraint_id_list create mode 100644 bt5/erp5_bespin/bt/template_document_id_list create mode 100644 bt5/erp5_bespin/bt/template_extension_id_list create mode 100644 bt5/erp5_bespin/bt/template_format_version create mode 100644 bt5/erp5_bespin/bt/template_local_role_list create mode 100644 bt5/erp5_bespin/bt/template_local_roles_list create mode 100644 bt5/erp5_bespin/bt/template_message_translation_list create mode 100644 bt5/erp5_bespin/bt/template_module_id_list create mode 100644 bt5/erp5_bespin/bt/template_path_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_allowed_content_type_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_base_category_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_hidden_content_type_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_id_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_property_sheet_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_role_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_roles_list create mode 100644 bt5/erp5_bespin/bt/template_portal_type_workflow_chain_list create mode 100644 bt5/erp5_bespin/bt/template_preference_list create mode 100644 bt5/erp5_bespin/bt/template_product_id_list create mode 100644 bt5/erp5_bespin/bt/template_property_sheet_id_list create mode 100644 bt5/erp5_bespin/bt/template_registered_skin_selection_list create mode 100644 bt5/erp5_bespin/bt/template_role_list create mode 100644 bt5/erp5_bespin/bt/template_site_property_id_list create mode 100644 bt5/erp5_bespin/bt/template_skin_id_list create mode 100644 bt5/erp5_bespin/bt/template_test_id_list create mode 100644 bt5/erp5_bespin/bt/template_tool_id_list create mode 100644 bt5/erp5_bespin/bt/template_update_business_template_workflow create mode 100644 bt5/erp5_bespin/bt/template_update_tool create mode 100644 bt5/erp5_bespin/bt/template_workflow_id_list create mode 100644 bt5/erp5_bespin/bt/title create mode 100644 bt5/erp5_bespin/bt/version diff --git a/bt5/erp5_bespin/RegisteredSkinSelectionTemplateItem/registered_skin_selection.xml b/bt5/erp5_bespin/RegisteredSkinSelectionTemplateItem/registered_skin_selection.xml new file mode 100644 index 0000000000..5ea5849d9e --- /dev/null +++ b/bt5/erp5_bespin/RegisteredSkinSelectionTemplateItem/registered_skin_selection.xml @@ -0,0 +1,6 @@ +<registered_skin_selection> + <skin_folder_selection> + <skin_folder>erp5_bespin</skin_folder> + <skin_selection>View</skin_selection> + </skin_folder_selection> +</registered_skin_selection> \ No newline at end of file diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin.xml new file mode 100644 index 0000000000..2dbfc96c2a --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Folder" module="OFS.Folder"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_local_properties</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>_objects</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>erp5_bespin</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.css.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.css.xml new file mode 100644 index 0000000000..77d700854a --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.css.xml @@ -0,0 +1,162 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="DTMLMethod" module="OFS.DTMLMethod"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>__name__</string> </key> + <value> <string>BespinEmbedded.css</string> </value> + </item> + <item> + <key> <string>_vars</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>globals</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>raw</string> </key> + <value> <string>.bespin-completion-panel {\n + font-family: Helvetica, Arial, sans-serif;\n + position: absolute;\n + cursor: default;\n + line-height: normal;\n + -moz-user-select: none;\n + -webkit-user-select: none;\n +}\n +\n +.bespin-completion-pointer {\n + position: absolute;\n + z-index: 2;\n + height: 21px;\n + width: 21px;\n +}\n +\n +.bespin-completion-pointer-up {\n + top: 1px;\n + border-top: solid #555 1px;\n + border-left: solid #555 1px;\n + background-image: -moz-linear-gradient(top left, #333333, #333333 50%, transparent 50%, transparent);\n + background-image: -webkit-gradient(linear, left top, right bottom, from(#333333), color-stop(0.5, #333333), color-stop(0.5, transparent), to(transparent));\n + -moz-transform: rotate(45deg);\n + -webkit-transform: rotate(45deg);\n +}\n +\n +.bespin-completion-pointer-down {\n + bottom: 1px;\n + border-top: solid #000 1px;\n + border-left: solid #000 1px;\n + background-image: -moz-linear-gradient(top left, #000, #000 50%, transparent 50%, transparent);\n + background-image: -webkit-gradient(linear, left top, right bottom, from(#000), color-stop(0.5, #000), color-stop(0.5, transparent), to(transparent));\n + -moz-transform: rotate(225deg);\n + -webkit-transform: rotate(225deg);\n +}\n +\n +.bespin-completion-bubble-outer {\n + position: relative;\n + z-index: 1;\n + margin: 11px 0px 11px 0px;\n + border-top: solid #555 1px;\n + -moz-border-radius: 8px;\n + -webkit-border-radius: 8px;\n +}\n +\n +.bespin-completion-bubble-inner {\n + position: relative;\n + z-index: 3;\n + padding: 6px;\n + background: -moz-linear-gradient(top, #333333, #000000);\n + background: -webkit-gradient(linear, center top, center bottom, from(#333333), to(#000000));\n + color: #ffffff;\n + font-size: 10.5pt;\n + -moz-border-radius: 8px;\n + -webkit-border-radius: 8px;\n + -moz-box-shadow: 0px 6px 16px 2px rgba(0, 0, 0, 0.5);\n + -webkit-box-shadow: 0px 6px 16px 2px rgba(0, 0, 0, 0.5);\n +}\n +\n +.bespin-completion-panel ul {\n + list-style: none;\n + margin: 0px;\n + padding: 0px;\n +}\n +\n +.bespin-completion-panel li {\n + text-indent: 0px;\n + margin: 0px;\n + padding: 6px 16px;\n +}\n +\n +.bespin-completion-highlight {\n + position: absolute;\n + z-index: -1;\n + background-image: -moz-linear-gradient(top, #3e59be, #312d80);\n + background-image: -webkit-gradient(linear, center top, center bottom, from(#3e59be), to(#312d80));\n + border: solid rgba(37, 34, 91, 1.0) 1px;\n + -moz-border-radius: 6px;\n + -webkit-border-radius: 6px;\n +}\n +\n +.bespin-completion-kind {\n + display: block;\n + float: left;\n + top: 0px;\n + left: 0px;\n + width: 8px;\n + height: 8px;\n + padding: 2px;\n + margin: 0px 5px 0px 0px;\n + font-size: 6.5pt;\n + font-weight: bold;\n + text-transform: uppercase;\n + text-align: center;\n + -moz-border-radius: 3px;\n + -webkit-border-radius: 3px;\n +}\n +\n +.bespin-completion-kind-m {\n + background-color: maroon;\n +}\n +\n +.bespin-completion-kind-f {\n + background-color: green;\n +}\n +\n +.bespin-completion-top-row {\n + position: relative;\n +}\n +\n +.bespin-completion-second-row {\n + margin: 6px 0px 0px 17px;\n + display: none;\n +}\n +\n +.bespin-completion-ident {\n + font-weight: bold;\n +}\n +\n +.bespin-completion-container {\n + color: #a0a0a0;\n +}\n +\n +</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.js.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.js.xml new file mode 100644 index 0000000000..6a32d8e9a5 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinEmbedded.js.xml @@ -0,0 +1,10732 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="DTMLMethod" module="OFS.DTMLMethod"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>__name__</string> </key> + <value> <string>BespinEmbedded.js</string> </value> + </item> + <item> + <key> <string>_vars</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>globals</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>raw</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +if (typeof(bespin) === \'undefined\') {\n + bespin = {};\n +}\n +\n +if (typeof(document) !== \'undefined\') {\n + var link = document.getElementById("bespin_base");\n + if (link) {\n + var href = link.href;\n + bespin.base = href.substring(href.length - 1) !== "/" ? href + "/" : href;\n + } else {\n + bespin.base = "";\n + }\n +}\n +\n +\n +(function() {\n +/*! @license\n +==========================================================================\n +Tiki 1.0 - CommonJS Runtime\n +copyright 2009-2010, Apple Inc., Sprout Systems Inc., and contributors.\n +\n +Permission is hereby granted, free of charge, to any person obtaining a \n +copy of this software and associated documentation files (the "Software"), \n +to deal in the Software without restriction, including without limitation \n +the rights to use, copy, modify, merge, publish, distribute, sublicense, \n +and/or sell copies of the Software, and to permit persons to whom the \n +Software is furnished to do so, subject to the following conditions:\n +\n +The above copyright notice and this permission notice shall be included in \n +all copies or substantial portions of the Software.\n +\n +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \n +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n +DEALINGS IN THE SOFTWARE.\n +\n +Tiki is part of the SproutCore project.\n +\n +SproutCore and the SproutCore logo are trademarks of Sprout Systems, Inc.\n +\n +For more information visit http://www.sproutcore.com/tiki\n +\n +==========================================================================\n +@license */\n +\n +/*globals tiki ENV ARGV ARGS */\n +\n +"use modules false";\n +"use loader false";\n +\n +/**\n + Implements a very simple handler for the loader registration API so that\n + additional scripts can load without throwing exceptions. This loader can\n + also return module instances for modules registered with an actual factory\n + function.\n + \n + Note that this stub loader cannot be used on its own. You must load the \n + regular tiki package as well, which will replace this loader as soon as it\n + is fetched.\n +*/\n +if ("undefined" === typeof tiki) { var tiki = function() {\n + \n + var T_UNDEFINED = \'undefined\',\n + queue = [];\n + \n + // save a registration method in a queue to be replayed later once the \n + // real loader is available.\n + function _record(method, args) {\n + queue.push({ m: method, a: args });\n + }\n + \n + var tiki = {\n + \n + // used to detect when real loader should replace this one\n + isBootstrap: true,\n + \n + // log of actions to be replayed later\n + queue: queue, \n + \n + // helpers just record into queue\n + register: function(packageId, opts) { \n + \n + // this hack will make unit tests work for tiki by adding core_test to\n + // the list of dependencies.\n + if (packageId.match(/^tiki/) && this.ENV) {\n + if ((this.ENV.app === \'tiki\') && (this.ENV.mode === \'test\')) {\n + if (!opts.dependencies) opts.dependencies = {};\n + opts.dependencies[\'core_test\'] = \'~\';\n + }\n + }\n + \n + _record(\'register\', arguments);\n + return this; \n + },\n + \n + // Keep these around just in case we need them in the end...\n + // script: function() { \n + // _record(\'script\', arguments); \n + // return this; \n + // },\n + // \n + // stylesheet: function() { \n + // _record(\'stylesheet\', arguments); \n + // return this; \n + // },\n +\n + // modules actually get saved as well a recorded so you can use them.\n + module: function(moduleId, factory) {\n + if (moduleId.match(/\\:tiki$/)) this.tikiFactory = factory;\n + _record(\'module\', arguments);\n + return this ;\n + },\n +\n + // load the tikiFactory \n + start: function() {\n + var exp = {}, ret;\n + this.tikiFactory(null, exp, null); // no require or module!\n + ret = exp.Browser.start(this.ENV, this.ARGS, queue);\n + queue = null;\n + return ret ;\n + }\n + \n + };\n + \n + if (T_UNDEFINED !== typeof ENV) tiki.ENV = ENV;\n + if (T_UNDEFINED !== typeof ARGV) tiki.ARGS = ARGV; // for older versions\n + if (T_UNDEFINED !== typeof ARGS) tiki.ARGS = ARGS;\n + \n + return tiki;\n + \n +}(); }\n +\n +\n +tiki.register(\'::tiki/1.0.0\', {\n +"name": "tiki",\n +"version": "1.0.0"\n +});\n +\n +tiki.module(\'::tiki/1.0.0:tiki\', function(require, exports, module) {\n +// ==========================================================================\n +// Project: Tiki - CommonJS Runtime\n +// Copyright: ©2009-2010 Apple Inc. All rights reserved.\n +// License: Licened under MIT license (see __preamble__.js)\n +// ==========================================================================\n +/*jslint evil:true */\n +\n +/**\n + @file \n + \n + This file implements the core building blocks needed to implement the \n + tiki runtime in an environment. If you can require this one module, you can\n + setup a runtime that will load additional packages.\n + \n + It is important that this module NOT require() any other modules since a\n + functioning require() statement may not be available. The module can \n + populate, but not replace, the exports object.\n +\n + To configure a Tiki runtime, you need to create a Sandbox and Loader \n + instance from this API with one or more loader Sources. The BrowserSource\n + object implements the basic source you need to work in the browser. The\n + Repository object implemented in the server-side only \'file\' API can be \n + used to load from a local repository of packages.\n +*/\n +\n +// used for type checking. This allows the type strings to be minified.\n +var T_FUNCTION = \'function\',\n + T_STRING = \'string\',\n + T_UNDEFINED = \'undefined\';\n + \n + \n +var IS_CANONICAL = /^::/; // must begin with ::\n +var isCanonicalId = function(id) {\n + return !!IS_CANONICAL.exec(id);\n +}; \n +\n +var DEBUG = function() {\n + exports.debug.apply(this, arguments);\n +};\n +\n +exports.debug = function() {\n + var msg = Array.prototype.join.call(arguments, \'\');\n + require(\'sys\').debug(msg);\n +};\n +\n +// ..........................................................\n +// CORE UTILITIES\n +// \n +\n +var TMP_ARY = [];\n +\n +/**\n + Tests whether the passed object is an array or not.\n +*/\n +var isArray;\n +\n +if (Array.isArray) {\n + isArray = Array.isArray;\n +} else {\n + isArray = function(obj) {\n + if (\'object\' !== typeof obj) return false;\n + if (obj instanceof Array) return true;\n + return obj.constructor && (obj.constructor.name===\'Array\');\n + };\n +}\n +exports.isArray = isArray;\n +\n +/**\n + Create a new object with the passed object as the prototype.\n +*/\n +var createObject;\n +if (Object.create) {\n + createObject = Object.create;\n +} else {\n + var K = function() {},\n + Kproto = K.prototype;\n + createObject = function(obj) {\n + if (!obj) obj = Object.prototype;\n + K.prototype = obj;\n + \n + var ret = new K();\n + ret.prototype = obj;\n + K.prototype = Kproto;\n + \n + return ret ;\n + };\n +}\n +exports.createObject = createObject;\n +\n +var _constructor, _extend, extend;\n +\n +// returns a new constructor function with clean closure...\n +_constructor = function() {\n + return function() {\n + if (this.init) return this.init.apply(this, arguments);\n + else return this;\n + };\n +};\n +\n +_extend = function() {\n + return extend(this);\n +};\n +\n +/**\n + Creates a "subclass" of the passed constructor. The default constructor\n + will call look for a local "init" method and call it.\n + \n + If you don\'t pass an initial constructor, this will create a new based \n + object.\n +*/\n +extend = function(Constructor) {\n + var Ret = _constructor();\n + Ret.prototype = createObject(Constructor.prototype);\n + Ret.prototype.constructor = Ret;\n + Ret.super_ = Constructor;\n + Ret.extend = _extend;\n + return Ret;\n +};\n +exports.extend = extend;\n +\n +/**\n + Invokes the passed fn on each item in the array in parallel. Invokes\n + done when finished.\n + \n + # Example\n + \n + parallel([1,2,3], function(item, done) {\n + // do something with item\n + done();\n + })(function(err) {\n + // invoked when done, err if there was an error\n + });\n + \n + @param {Array} array \n + items to iterate\n + \n + @param {Function} fn\n + callback to invoke\n + \n + @returns {void}\n +*/\n +var parallel = function(array, fn) {\n + if (fn && !fn.displayName) fn.displayName = \'parallel#fn\';\n + \n + return function(done) {\n + if (array.length === 0) return done(null, []);\n + \n + var len = array.length,\n + cnt = len,\n + cancelled = false,\n + idx;\n +\n + var tail = function(err) {\n + if (cancelled) return; // nothing to do\n +\n + if (err) {\n + cancelled = true;\n + return done(err);\n + }\n +\n + if (--cnt <= 0) done(); \n + };\n + tail.displayName = \'parallel#tail\';\n +\n + for(idx=0;idx<len;idx++) fn(array[idx], tail);\n + };\n +};\n +parallel.displayName = \'parallel\';\n +\n +/**\n + @private\n + \n + Implements the sync map() on all platforms\n +*/\n +var map;\n +if (Array.prototype.map) {\n + map = function(array, fn) {\n + return array.map(fn);\n + };\n +\n +} else {\n + map = function(array, fn) {\n + var idx, len = array.length, ret = [];\n + for(idx=0;idx<len;idx++) {\n + ret[idx] = fn(array[idx], idx);\n + }\n + return ret ;\n + };\n +}\n +map.displayName = \'map\';\n +\n +\n +var PENDING = \'pending\',\n + READY = \'ready\',\n + RUNNING = \'running\';\n + \n +/**\n + Returns a function that will execute the continuable exactly once and \n + then cache the result. Invoking the same return function more than once\n + will simply return the old result. \n + \n + This is a good replacement for promises in many cases.\n + \n + h3. Example\n + \n + {{{\n + // load a file only once\n + var loadit = Co.once(Co.fs.loadFile(pathToFile));\n +\n + loadit(function(content) { \n + // loads the file\n + });\n + \n + loadit(function(content) {\n + // if already loaded, just invokes with past content\n + });\n + \n + }}}\n + \n + @param {Function} cont\n + Continuable to invoke \n + \n + @returns {Function} \n + A new continuable that will only execute once then returns the cached\n + result.\n +*/\n +var once = function(action, context) {\n + var state = PENDING,\n + queue = [],\n + makePending = false,\n + args = null;\n +\n + var ret = function(callback) {\n + if (!context) context = this;\n + \n + // cont has already finished, just invoke callback based on result\n + switch(state) {\n + \n + // already resolved, invoke callback immediately\n + case READY:\n + callback.apply(null, args);\n + break;\n +\n + // action has started running but hasn\'t finished yet\n + case RUNNING:\n + queue.push(callback);\n + break;\n + \n + // action has not started yet\n + case PENDING:\n + queue.push(callback);\n + state = RUNNING;\n +\n + action.call(context, function(err) {\n + args = Array.prototype.slice.call(arguments);\n + \n + var oldQueue = queue, oldArgs = args;\n +\n + if (makePending) {\n + state = PENDING;\n + queue = [];\n + args = null; \n + makePending = false;\n +\n + } else {\n + state = READY;\n + queue = null;\n + }\n + \n + if (oldQueue) {\n + oldQueue.forEach(function(q) { q.apply(null, oldArgs); });\n + }\n + });\n + break;\n + }\n + return this;\n + };\n + ret.displayName = \'once#handler\';\n +\n + // allow the action to be reset so it is called again\n + ret.reset = function() {\n + switch(state) {\n + \n + // already run, need to reset\n + case READY: \n + state = PENDING;\n + queue = [];\n + args = null;\n + break;\n + \n + // in process - set makePending so that resolving will reset to pending\n + case RUNNING:\n + makePending = true;\n + break;\n + \n + // otherwise ignore pending since there is nothing to reset\n + }\n + };\n + ret.reset.displayName = \'once#handler.reset\';\n + \n + return ret ;\n +};\n +exports.once = once;\n +\n +\n +/**\n + Iterate over a property, setting display names on functions as needed.\n + Call this on your own exports to setup display names for debugging.\n +*/\n +var displayNames = function(obj, root) {\n + var k,v;\n + for(k in obj) {\n + if (!obj.hasOwnProperty(k)) continue ;\n + v = obj[k];\n + if (\'function\' === typeof v) {\n + if (!v.displayName) {\n + v.displayName = root ? (root+\'.\'+k) : k;\n + displayNames(v.prototype, v.displayName);\n + }\n + \n + }\n + }\n + return obj;\n +};\n +\n +// ..........................................................\n +// ERRORS\n +// \n +\n +var NotFound = extend(Error);\n +NotFound.prototype.init = function(canonicalId, pkgId) {\n + var msg = canonicalId+\' not found\';\n + if (pkgId) {\n + if (T_STRING === typeof pkgId) msg = msg+\' \'+pkgId;\n + else msg = msg+\' in package \'+(pkgId.id || \'(unknown)\');\n + }\n + this.message = msg;\n + return this;\n +};\n +exports.NotFound = NotFound;\n +\n +var InvalidPackageDef = extend(Error);\n +InvalidPackageDef.prototype.init = function(def, reason) {\n + if (\'undefined\' !== typeof JSON) def = JSON.stringify(def);\n + this.message = "Invalid package definition. "+reason+" "+def;\n +};\n +exports.InvalidPackageDef = InvalidPackageDef;\n +\n +// ..........................................................\n +// semver\n +// \n +\n +// ..........................................................\n +// NATCOMPARE\n +// \n +// Used with thanks to Kristof Coomans \n +// Find online at http://sourcefrog.net/projects/natsort/natcompare.js\n +// Cleaned up JSLint errors\n +\n +/*\n +natcompare.js -- Perform \'natural order\' comparisons of strings in JavaScript.\n +Copyright (C) 2005 by SCK-CEN (Belgian Nucleair Research Centre)\n +Written by Kristof Coomans <kristof[dot]coomans[at]sckcen[dot]be>\n +\n +Based on the Java version by Pierre-Luc Paour, of which this is more or less a straight conversion.\n +Copyright (C) 2003 by Pierre-Luc Paour <natorder@paour.com>\n +\n +The Java version was based on the C version by Martin Pool.\n +Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>\n +\n +This software is provided \'as-is\', without any express or implied\n +warranty. In no event will the authors be held liable for any damages\n +arising from the use of this software.\n +\n +Permission is granted to anyone to use this software for any purpose,\n +including commercial applications, and to alter it and redistribute it\n +freely, subject to the following restrictions:\n +\n +1. The origin of this software must not be misrepresented; you must not\n +claim that you wrote the original software. If you use this software\n +in a product, an acknowledgment in the product documentation would be\n +appreciated but is not required.\n +2. Altered source versions must be plainly marked as such, and must not be\n +misrepresented as being the original software.\n +3. This notice may not be removed or altered from any source distribution.\n +*/\n +var natcompare = function() {\n + \n + var isWhitespaceChar = function(a) {\n + var charCode = a.charCodeAt(0);\n + return charCode <= 32;\n + };\n +\n + var isDigitChar = function(a) {\n + var charCode = a.charCodeAt(0);\n + return ( charCode >= 48 && charCode <= 57 );\n + };\n +\n + var compareRight = function(a,b) {\n + var bias = 0,\n + ia = 0,\n + ib = 0,\n + ca, cb;\n +\n + // The longest run of digits wins. That aside, the greatest\n + // value wins, but we can\'t know that it will until we\'ve scanned\n + // both numbers to know that they have the same magnitude, so we\n + // remember it in BIAS.\n + for (;; ia++, ib++) {\n + ca = a.charAt(ia);\n + cb = b.charAt(ib);\n +\n + if (!isDigitChar(ca) && !isDigitChar(cb)) return bias;\n + else if (!isDigitChar(ca)) return -1;\n + else if (!isDigitChar(cb)) return +1;\n + else if (ca < cb) if (bias === 0) bias = -1;\n + else if (ca > cb) if (bias === 0) bias = +1;\n + else if (ca === 0 && cb === 0) return bias;\n + }\n + };\n +\n + var natcompare = function(a,b) {\n +\n + var ia = 0, \n + ib = 0,\n + nza = 0, \n + nzb = 0,\n + ca, cb, result;\n +\n + while (true) {\n + // only count the number of zeroes leading the last number compared\n + nza = nzb = 0;\n +\n + ca = a.charAt(ia);\n + cb = b.charAt(ib);\n +\n + // skip over leading spaces or zeros\n + while ( isWhitespaceChar( ca ) || ca ==\'0\' ) {\n + if (ca == \'0\') nza++;\n + else nza = 0; // only count consecutive zeroes\n + ca = a.charAt(++ia);\n + }\n +\n + while ( isWhitespaceChar( cb ) || cb == \'0\') {\n + if (cb == \'0\') nzb++;\n + else nzb = 0; // only count consecutive zeroes\n + cb = b.charAt(++ib);\n + }\n +\n + // process run of digits\n + if (isDigitChar(ca) && isDigitChar(cb)) {\n + if ((result = compareRight(a.substring(ia), b.substring(ib))) !== 0) {\n + return result;\n + }\n + }\n +\n + // The strings compare the same. Perhaps the caller\n + // will want to call strcmp to break the tie.\n + if (ca === 0 && cb === 0) return nza - nzb;\n +\n + if (ca < cb) return -1;\n + else if (ca > cb) return +1;\n +\n + ++ia; ++ib;\n + }\n + };\n +\n + return natcompare;\n +}();\n +exports.natcompare = natcompare;\n +\n +// ..........................................................\n +// PUBLIC API\n +// \n +\n +// Support Methods\n +var invalidVers = function(vers) {\n + return new Error(\'\' + vers + \' is an invalid version string\');\n +};\n +invalidVers.displayName = \'invalidVers\';\n +\n +var compareNum = function(vers1, vers2, num1, num2) {\n + num1 = Number(num1);\n + num2 = Number(num2);\n + if (isNaN(num1)) throw invalidVers(vers1);\n + if (isNaN(num2)) throw invalidVers(vers2);\n + return num1 - num2 ;\n +};\n +compareNum.displayName = \'compareNum\';\n +\n +\n +var vparse;\n +var semver = {\n + \n + /**\n + Parse the version number into its components. Returns result of a regex.\n + */\n + parse: function(vers) {\n + var ret = vers.match(/^(=|~)?([\\d]+?)(\\.([\\d]+?)(\\.(.+))?)?$/);\n + if (!ret) return null; // no match\n + return [ret, ret[2], ret[4] || \'0\', ret[6] || \'0\', ret[1]];\n + },\n +\n +\n + /**\n + Returns the major version number of a version string. \n +\n + @param {String} vers\n + version string\n +\n + @returns {Number} version number or null if could not be parsed\n + */\n + major: function(vers) {\n + return Number(vparse(vers)[1]);\n + },\n +\n + /**\n + Returns the minor version number of a version string\n +\n +\n + @param {String} vers\n + version string\n +\n + @returns {Number} version number or null if could not be parsed\n + */\n + minor: function(vers) {\n + return Number(vparse(vers)[2]);\n + },\n +\n + /**\n + Returns the patch of a version string. The patch value is always a string\n + not a number\n + */\n + patch: function(vers) {\n + var ret = vparse(vers)[3];\n + return isNaN(Number(ret)) ? ret : Number(ret);\n + },\n +\n + STRICT: \'strict\',\n + NORMAL: \'normal\',\n +\n + /**\n + Returns the comparison mode. Will be one of NORMAL or STRICT\n + */\n + mode: function(vers) {\n + var ret = vparse(vers)[4];\n + return ret === \'=\' ? semver.STRICT : semver.NORMAL;\n + },\n +\n + /**\n + Compares two patch strings using the proper matching formula defined by\n + semver.org. Returns:\n + \n + @param {String} patch1 first patch to compare\n + @param {String} patch2 second patch to compare\n + @returns {Number} -1 if patch1 < patch2, 1 if patch1 > patch2, 0 if equal \n + */\n + comparePatch: function(patch1, patch2) {\n + var num1, num2;\n +\n + if (patch1 === patch2) return 0; // equal\n +\n + num1 = Number(patch1);\n + num2 = Number(patch2);\n +\n + if (isNaN(num1)) {\n + if (isNaN(num2)) {\n + // do lexigraphic comparison\n + return natcompare(patch1, patch2);\n +\n + } else return -1; // num2 is a number therefore num1 < num2\n +\n + // num1 is a number but num2 is not so num1 > num2\n + } else if (isNaN(num2)) {\n + return 1 ;\n + } else {\n + return num1<num2 ? -1 : (num1>num2 ? 1 : 0) ;\n + }\n + },\n +\n + /**\n + Compares two version strings, using natural sorting for the patch.\n + */\n + compare: function(vers1, vers2) {\n + var ret ;\n +\n + if (vers1 === vers2) return 0;\n + if (vers1) vers1 = vparse(vers1);\n + if (vers2) vers2 = vparse(vers2);\n +\n + if (!vers1 && !vers2) return 0;\n + if (!vers1) return -1; \n + if (!vers2) return 1; \n +\n +\n + ret = compareNum(vers1[0], vers2[0], vers1[1], vers2[1]);\n + if (ret === 0) {\n + ret = compareNum(vers1[0], vers2[0], vers1[2], vers2[2]);\n + if (ret === 0) ret = semver.comparePatch(vers1[3], vers2[3]);\n + }\n +\n + return (ret < 0) ? -1 : (ret>0 ? 1 : 0);\n + },\n +\n + /**\n + Returns true if the second version string represents a version compatible \n + with the first version. In general this means the second version must be\n + greater than or equal to the first version but its major version must not \n + be different.\n + */\n + compatible: function(reqVers, curVers) {\n + if (!reqVers) return true; // always compatible with no version\n + if (reqVers === curVers) return true; // fast path\n +\n + // make sure these parse - or else treat them like null\n + if (reqVers && !vparse(reqVers)) reqVers = null;\n + if (curVers && !vparse(curVers)) curVers = null;\n +\n + // try fast paths again in case they changed state\n + if (!reqVers) return true; // always compatible with no version\n + if (reqVers === curVers) return true; // fast path\n + \n + // strict mode, must be an exact (semantic) match\n + if (semver.mode(reqVers) === semver.STRICT) {\n + return curVers && (semver.compare(reqVers, curVers)===0);\n +\n + } else {\n + if (!curVers) return true; // if no vers, always assume compat\n +\n + // major vers\n + if (semver.major(reqVers) !== semver.major(curVers)) return false; \n + return semver.compare(reqVers, curVers) <= 0;\n + }\n + },\n +\n + /**\n + Normalizes version numbers so that semantically equivalent will be treated \n + the same.\n + */\n + normalize: function(vers) {\n + var patch;\n +\n + if (!vers || vers.length===0) return null;\n + vers = semver.parse(vers);\n + if (!vers) return null;\n +\n + patch = Number(vers[3]);\n + if (isNaN(patch)) patch = vers[3];\n +\n + return [Number(vers[1]), Number(vers[2]), patch].join(\'.\');\n + }\n + \n +};\n +exports.semver = semver;\n +vparse = semver.parse;\n +\n +\n +// ..........................................................\n +// FACTORY\n +// \n +\n +/**\n + @constructor\n + \n + A factory knows how to instantiate a new module for a sandbox, including \n + generating the require() method used by the module itself. You can return\n + custom factories when you install a plugin. Your module should export\n + loadFactory().\n + \n + The default factory here actually expects to receive a module descriptor\n + as generated by the build tools.\n +*/\n +var Factory = exports.extend(Object);\n +exports.Factory = Factory;\n +\n +Factory.prototype.init = function(moduleId, pkg, factory) {\n + this.id = moduleId;\n + this.pkg = pkg;\n + this.factory = factory;\n +};\n +\n +/**\n + Actually generates a new set of exports for the named sandbox. The sandbox\n + must return a module object that can be used to generate the factory.\n + \n + If the current value of the local factory is a string, then we will actually\n + eval/compile the factory as well.\n + \n + @param sandbox {Sandbox}\n + The sandbox the will own the module instance\n + \n + @param module {Module}\n + The module object the exports will belong to\n + \n + @returns {Hash} exports from instantiated module\n +*/\n +Factory.prototype.call = function(sandbox, module) {\n +\n + // get the factory function, evaluate if needed\n + var func = this.factory,\n + filename = this.__filename,\n + dirname = this.__dirname;\n + \n + if (T_STRING === typeof(func)) {\n + func = this.factory = Factory.compile(func, this.pkg.id+\':\'+this.id);\n + }\n +\n + // generate a nested require for this puppy\n + var req = sandbox.createRequire(module),\n + exp = module.exports;\n + func.call(exp, req, exp, module, filename, dirname);\n + return module.exports;\n +};\n +\n +\n +// standard wrapper around a module. replace item[1] with a string and join.\n +var MODULE_WRAPPER = [\n + \'(function(require, exports, module) {\',\n + null,\n + \'\\n});\\n//@ sourceURL=\',\n + null,\n + \'\\n\'];\n +\n +/**\n + Evaluates the passed string. Returns a function.\n + \n + @param moduleText {String}\n + The module text to compile\n + \n + @param moduleId {String}\n + Optional moduleId. If provided will be used for debug\n + \n + @returns {Function} compiled factory\n +*/\n +Factory.compile = function(moduleText, moduleId) {\n + var ret;\n + \n + MODULE_WRAPPER[1] = moduleText;\n + MODULE_WRAPPER[3] = moduleId || \'(unknown module)\';\n + \n + ret = MODULE_WRAPPER.join(\'\');\n + ret = eval(ret);\n + \n + MODULE_WRAPPER[1] = MODULE_WRAPPER[3] = null;\n + return ret;\n +};\n +\n +exports.Factory = Factory;\n +\n +// ..........................................................\n +// MODULE\n +// \n +\n +/**\n + A Module describes a single module, including its id, ownerPackage, and\n + the actual module exports once the module has been instantiated. It also\n + implements the resource() method which can lookup a resource on the module\'s\n + package.\n +*/\n +var Module = exports.extend(Object);\n +exports.Module = Module;\n +\n +Module.prototype.init = function(id, ownerPackage, sandbox) {\n + this.id = id;\n + this.ownerPackage = ownerPackage;\n + this.exports = {};\n + var module = this;\n + \n + /**\n + Lookup a resource on the module\'s ownerPackage. Returns a URL or path \n + for the discovered resource. The method used to detect the module or \n + package is implemented in the package.\n + \n + Note that this method is generated for each module we create because some\n + code will try to pluck this method off of the module and call it in a\n + different context.\n + \n + @param resourceId {String}\n + Full or partial name of resource to retrieve\n + \n + @param done {Function}\n + Optional. Makes the resource discovery asyncronous\n + \n + @returns {String} url or path if not called async\n + */\n + this.resource = function(id) {\n + return sandbox.resource(id, module.id, ownerPackage);\n + };\n +};\n +\n +// ..........................................................\n +// PACKAGE\n +// \n +\n +/**\n + Package expects you to register the package with a config having the \n + following keys:\n + \n + {\n + "name": "name-of-package" (vs canonical id)\n + "version": current version of package (if known)\n + \n + // these are dependencies you require to run. If the package is \n + // async loaded, these will be the ones loaded\n + "dependencies": {\n + "package-name": "version"\n + },\n + \n + // these map a specific package-name/version to a canonicalId that must\n + // be registered for the package to be loaded. You may include \n + // additional packages here that may be referenced but are not required\n + // to run (for example - lazy loaded packages)\n + //\n + // This also forms the universe of packages this particular package can\n + // reference.\n + //\n + "tiki:packages": {\n + "package-name": [\n + { "version": "1.0.0", "id": "canonicalId", "url": "url" }\n + ]\n + },\n +\n + // ids mapped to urls. all of these scripts must be loaded for this \n + // package to be considered ready \n + "tiki:scripts": {\n + "id": "url"\n + },\n + \n + // stylesheets that must be loaded for this package to be considered\n + // ready. The id is used so that the URL can load from a relative path\n + // that may move around and still be accurate.\n + "tiki:stylesheets": {\n + "id": "url",\n + "id": "url"\n + },\n + \n + // maps asset paths for non-JS and non-CSS assets to URLs. Used to \n + // progrmatically load images, etc.\n + "tiki:resources": {\n + "asset/path": "url",\n + "asset/path": "url"\n + }\n + }\n +\n + This registration ensures that the package and it\'s related assets are \n + loaded.\n +*/\n + \n +var Package = exports.extend(Object);\n +exports.Package = Package;\n +\n +Package.prototype.init = function(id, config) {\n + if (!isCanonicalId(id)) id = \'::\'+id; // normalize\n + this.id = id;\n + this.config = config;\n + this.isReady = true;\n +};\n +\n +// ..........................................................\n +// Package Configs\n +// \n +\n +/**\n + Retrieves the named config property. This method can be overidden by \n + subclasses to perform more advanced processing on the key data\n + \n + @param {String} key\n + The key to retrieve\n + \n + @returns {Object} the key value or undefined\n +*/\n +Package.prototype.get = function(key) {\n + return this.config ? this.config[key] : undefined;\n +};\n +\n +/**\n + Updates the named config property.\n +\n + @param {String} key\n + The key to update\n + \n + @param {Object} value\n + The object value to change\n + \n + @returns {Package} receiver\n +*/\n +Package.prototype.set = function(key, value) {\n + if (!this.config) this.config = {};\n + this.config[key] = value;\n + return this;\n +};\n +\n +/**\n + Determines the required version of the named packageId, if any, specified\n + in this package.\n + \n + @param {String} packageId\n + The packageId to lookup\n + \n + @returns {String} The required version or null (meaning any)\n +*/\n +Package.prototype.requiredVersion = function(packageId) { \n + var deps = this.get(\'dependencies\');\n + return deps ? deps[packageId] : null;\n +};\n +\n +// ..........................................................\n +// Nested Packages\n +// \n +\n +/**\n + Attempts to match the passed packageId and version to the receiver or a \n + nested package inside the receiver. If a match is found, returns the \n + packages canonicalId. Otherwise returns null. \n + \n + This does not search remote sources for the package. It only looks at \n + what packages are available locally.\n + \n + This method is called after a package version has been checked for \n + compatibility with the package dependencies. It is not necessary to \n + validate the requested version against any dependencies.\n + \n + @param {String} packageId\n + The package id to look up\n +\n + @param {String} vers\n + The expected version. If null, then return the newest version for the \n + package.\n + \n + @param {String} Canonical packageId or null\n +*/\n +Package.prototype.canonicalPackageId = function(packageId, vers) {\n + if ((packageId === this.get(\'name\')) && \n + semver.compatible(vers, this.get(\'version\'))) {\n + return this.id;\n + }\n + return null;\n +};\n +\n +/**\n + Returns the receiver or an instance of a nested package if it matches the\n + canonicalId passed here. This method will only be called with a canonicalId\n + returned from a previous call to Package#canonicalPackageId.\n + \n + If the package identified by the canonicalId is not available locally for\n + some reason, return null.\n + \n + @param {String} canonicalId \n + The canonical packageId.\n + \n + @returns {Package} a package instance or null\n +*/\n +Package.prototype.packageFor = function(canonicalId) {\n + if (canonicalId === this.id) return this;\n + return null;\n +};\n +\n +/**\n + Verifies that the package identified by the passed canonical id is available\n + locally and ready for use. If it is not available, this method should \n + attempt to download the package from a remote source.\n + \n + Invokes the `done` callback when complete.\n + \n + If for some reason you cannot download and install the package you should\n + invoke the callback with an error object describing the reason. There are\n + a number of standard errors defined on Package such as NotFound.\n + \n + @param {String} canonicalId\n + The canonical packageId\n + \n + @param {Function} done\n + Callback to invoke with result. Pass an error object if the package \n + could not be loaded for some reason. Otherwise invoke with no params\n + \n + @returns {void}\n +*/\n +Package.prototype.ensurePackage = function(canonicalId, done) {\n + if (canonicalId === this.id) return done();\n + else return done(new NotFound(canonicalId, this));\n +};\n +\n +/**\n + Returns all packages in the package including the package itself and any \n + nested packages. Default just returns self.\n +*/\n +Package.prototype.catalogPackages = function() {\n + return [this];\n +};\n +\n +// ..........................................................\n +// Package Module Loading\n +// \n +\n +/**\n + Detects whether the moduleId exists in the current package.\n + \n + @param {String} moduleId\n + The moduleId to check\n + \n + @returns {Boolean} true if the module exists\n +*/\n +Package.prototype.exists = function(moduleId) {\n + return !!(this.factories && this.factories[moduleId]);\n +};\n +\n +/**\n + Returns a Factory object for the passed moduleId or null if no matching\n + factory could be found.\n + \n + @param {String} moduleId\n + The moduleId to check\n + \n + @returns {Factory} factory object\n +*/\n +Package.prototype.load = function(moduleId) {\n + return this.factories ? this.factories[moduleId] : null;\n +};\n +\n +// ..........................................................\n +// LOADER\n +// \n +\n +// potentially optimize to avoid memory churn.\n +var joinPackageId = function joinPackageId(packageId, moduleId) {\n + return packageId+\':\'+moduleId;\n +};\n +\n +/**\n + A loader is responsible for finding and loading factory functions. The \n + primary purpose of the loader is to find packages and modules in those \n + packages. The loader typically relies on one or more sources to actually\n + find a particular package.\n +*/\n +var Loader = exports.extend(Object);\n +exports.Loader = Loader;\n +\n +Loader.prototype.init = function(sources) {\n + this.sources = sources || [];\n + this.clear();\n +};\n +\n +/**\n + Clear caches in the loader causing future requests to go back to the \n + sources.\n +*/\n +Loader.prototype.clear = function() {\n + this.factories = {};\n + this.canonicalIds = {};\n + this.packages ={};\n + this.packageSources = {};\n + this.canonicalPackageIds = {};\n +};\n +\n +/**\n + The default package. This can be replaced but normally it is empty, meaning\n + it will never match a module.\n + \n + @property {Package}\n +*/\n +Loader.prototype.defaultPackage = new Package(\'default\', { \n + name: "default" \n +});\n +\n +/**\n + The anonymous package. This can be used when loading files outside of a \n + package.\n + \n + @property {Package}\n +*/\n +Loader.prototype.anonymousPackage = new Package(\'(anonymous)\', { \n + name: "(anonymous)"\n +});\n +\n +\n +/**\n +\n + Discovers the canonical id for a module. A canonicalId is a valid URN that\n + can be used to uniquely identify a module.\n + that looks like:\n + \n + ::packageId:moduleId\n + \n + For example:\n + \n + ::sproutcore-runtime/1.2.0:mixins/enumerable\n + \n + Canonical Ids are discovered according to the following algorithm:\n + \n + 1. If you pass in an already canonicalId, return it\n + 2. If you pass in a relative moduleId, it will be expanded and attached\n + to the workingPackage.\n + 3. If you pass in a moduleId with a packageId embedded, lookup the latest\n + version of the package that is compatible with the passed workingPackage\n + 4. If you pass a moduleId with no packageId embedded, then first look\n + for the module on the workingPackage. \n + 5. If not found there, look for a packageId with the same name. If that is \n + found, return either packageId:index or packageId:packageId as module. \n + 6. Otherwise, assume it is part of the default package. \n +\n + @param {String} moduleId\n + The moduleId to lookup. May be a canonicalId, packageId:moduleId, \n + absolute moduleId or relative moduleId\n + \n + @param {String} curModuleId\n + Optional. moduleId of the module requesting the lookup. Only needed if\n + the moduleId param might be relative.\n + \n + @param {Package} workingPackage\n + The working package making the request. When searching for a package,\n + only use packages that are compatible with the workingPackage.\n + \n + This parameter is also optional, though if you omit it, this method \n + assumes the anonymousPackage.\n + \n + @returns {void}\n +*/\n +Loader.prototype.canonical = function(moduleId, curModuleId, workingPackage) {\n + \n + var cache, cacheId, idx, packageId, canonicalId, pkg, ret; \n + \n + // NORMALIZE PARAMS\n + // normalize params - curModuleId can be omitted (though relative ids won\'t)\n + // work\n + if (curModuleId && (T_STRING !== typeof curModuleId)) {\n + workingPackage = curModuleId;\n + curModuleId = null;\n + }\n + \n + // return immediately if already canonical\n + if (isCanonicalId(moduleId)) return moduleId;\n + \n + // if no workingPackage, assume anonymous\n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + \n + // Resolve moduleId - may return canonical\n + moduleId = this._resolve(moduleId, curModuleId, workingPackage);\n + if (isCanonicalId(moduleId)) return moduleId;\n + \n + // then lookup in cache\n + cacheId = workingPackage ? workingPackage.id : \'(null)\';\n + cache = this.canonicalIds;\n + if (!cache) cache = this.canonicalIds = {};\n + if (!cache[cacheId]) cache[cacheId] = {};\n + cache = cache[cacheId];\n + if (cache[moduleId]) return cache[moduleId];\n + cacheId = moduleId; // save for later\n +\n + // Not Found in Cache. Do a lookup\n + idx = moduleId.indexOf(\':\');\n + if (idx>=0) {\n + packageId = moduleId.slice(0,idx);\n + moduleId = moduleId.slice(idx+1);\n + if (moduleId[0]===\'/\') {\n + throw new Error(\'Absolute path not allowed with packageId\');\n + }\n + }\n +\n + // if packageId is provided, just resolve packageId to a canonicalId\n + ret = null;\n + if (packageId && (packageId.length>0)) {\n + canonicalId = this._canonicalPackageId(packageId, null, workingPackage);\n + if (canonicalId) ret = joinPackageId(canonicalId, moduleId);\n +\n + // no packageId is provided, we\'ll need to do a little more searching\n + } else {\n +\n + // first look in workingPackage for match...\n + if (workingPackage && workingPackage.exists(moduleId)) {\n + ret = joinPackageId(workingPackage.id, moduleId);\n + \n + // not in working package, look for packageId:index or\n + // packageId:packageId\n + } else {\n + canonicalId = this._canonicalPackageId(moduleId, null, workingPackage);\n + if (canonicalId) pkg = this._packageFor(canonicalId, workingPackage);\n + if (pkg) {\n + if (pkg.exists(\'index\')) ret = joinPackageId(pkg.id, \'index\');\n + else if (pkg.exists(moduleId)) ret = joinPackageId(pkg.id,moduleId);\n + }\n + }\n + \n + // not in working package and isn\'t a package itself, assume default\n + // package. If there is no defaultPackage, return with the working\n + // package. This will fail but at least the error will be more \n + // helpful\n + if (!ret) {\n + if (this.defaultPackage) packageId = this.defaultPackage.id;\n + else if (this.workingPackage) packageId = this.workingPackage.id;\n + else if (this.anonymousPackage) packageId = this.anonymousPackage.id;\n + else return packageId = null;\n + \n + if (packageId) ret = joinPackageId(packageId, moduleId);\n + }\n + }\n +\n + // save to cache and return\n + cache[cacheId] = ret;\n + return ret ;\n +};\n + \n +/**\n +\n + Loads a factory for the named canonical module Id. If you did not obtain\n + the canonical module id through the loader\'s canonical() method, then you\n + must also pass a workingPackage property so that the loader can locate the\n + package that owns the module.\n + \n + The returns factory function can be used to actually generate a module.\n + \n + @param {String} canonicalId\n + A canonical module id\n + \n + @param {Package} workingPackage\n + Optional working package. Only required if you pass in a canonical id\n + that you did not obtain from the loader\'s canonical() method.\n + \n + @returns {void}\n + \n +*/\n +Loader.prototype.load = function(canonicalId, workingPackage, sandbox) {\n +\n + var cache, ret, idx, packageId, moduleId, pkg;\n + \n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + \n + cache = this.factories;\n + if (!cache) cache = this.factories = {};\n + if (cache[canonicalId]) return cache[canonicalId];\n +\n + // not in cache - load from package\n + idx = canonicalId.indexOf(\':\',2);\n + packageId = canonicalId.slice(0,idx);\n + moduleId = canonicalId.slice(idx+1);\n +\n + pkg = this._packageFor(packageId, workingPackage);\n + \n +//@if(debug)\n + if (!pkg) DEBUG(\'Loader#load - \'+packageId+\' not found for \'+moduleId);\n +//@endif\n +\n + if (!pkg) return null; // not found\n + \n + ret = pkg.load(moduleId, sandbox);\n + cache[canonicalId] = ret;\n + return ret ;\n +};\n +\n +/**\n + Returns a catalog of all known packages visible to the workingPackage.\n + The catalog is simply an array of package objects in no particular order\n +*/\n +Loader.prototype.catalogPackages = function(workingPackage) {\n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + var catalog = [], sources, idx, len, seen = {};\n + if (this.defaultPackage) catalog.push(this.defaultPackage);\n + \n + // anonymous package is never visible unless it is working..\n + //if (this.anonymousPackage) ret.push(this.anonymousPackage);\n +\n + // append any packages with versions that haven\'t been seen already\n + var append = function(packages) {\n + var idx, len, check, cur;\n + \n + if (!packages) return; // nothing to do\n + len = packages.length;\n + for(idx=0;idx<len;idx++) {\n + cur = packages[idx];\n + check = seen[cur.get(\'name\')];\n + if (!check) check = seen[cur.get(\'name\')] = {}; \n + if (!check[cur.get(\'version\')]) {\n + catalog.push(cur);\n + check[cur.get(\'version\')] = cur;\n + }\n + }\n + };\n + \n + if (workingPackage) append(workingPackage.catalogPackages());\n +\n + sources = this.sources;\n + len = sources.length;\n + for(idx=0;idx<len;idx++) append(sources[idx].catalogPackages());\n + \n + seen = null; // no longer needed.\n + return catalog;\n +};\n +\n +/**\n + Discovers the canonical id for a package. A cnaonicalID is a URN that can\n + be used to uniquely identify a package. It looks like: \n + \n + ::packageId\n + \n + for example:\n + \n + ::sproutcore-datastore/1.2.0/1ef3ab23ce23ff938\n +\n + If you need to perform some low-level operation on a package, this method\n + is the best way to identify the package you want to work with specifically.\n + \n + ## Examples\n + \n + Find a compatible package named \'foo\' in the current owner module:\n + \n + loader.canonicalPackage(\'foo\', ownerPackage, function(err, pkg) {\n + // process response\n + });\n + \n + Find the package named \'foo\', exactly version \'1.0.0\'. This may return a\n + packes nested in the ownerPackage:\n + \n + loader.canonicalPackage(\'foo\', \'=1.0.0\', ownerPackage, function(err, pkg) {\n + // process response\n + });\n + \n + Find the latest version of \'foo\' installed in the system - not specific to \n + any particular package\n + \n + loader.canonicalPackage(\'foo\', loader.anonymousPackage, function(err, pkg) {\n + // process result\n + });\n + \n + @param {String|Package} packageId\n + The packageId to load. If you pass a package, the package itself will\n + be returned.\n + \n + @param {String} vers \n + The required version. Pass null or omit this parameter to use the latest\n + version (compatible with the workingPackage).\n + \n + @param {Package} workingPackage\n + The working package. This method will search in this package first for\n + nested packages. It will also consult the workingPackage to determine \n + the required version if you don\'t name a version explicitly.\n + \n + You may pass null or omit this parameter, in which case the anonymous\n + package will be used for context.\n + \n + @param {Function} done \n + Callback. Invoked with an error and the loaded package. If no matching\n + package can be found, invoked with null for the package.\n +\n + @returns {void}\n +*/\n +Loader.prototype.canonicalPackageId = function(packageId, vers, workingPackage) {\n +\n + var idx;\n +\n + // fast path in case you pass in a package already\n + if (packageId instanceof Package) return packageId.id;\n +\n + // fast path packageId is already canonical - slice of moduleId first\n + if (isCanonicalId(packageId)) {\n + idx = packageId.indexOf(\':\', 2);\n + if (idx>=0) packageId = packageId.slice(0,idx);\n + return packageId;\n + }\n + \n + // normalize the params. vers may be omitted\n + if (vers && (T_STRING !== typeof vers)) {\n + workingPackage = vers;\n + vers = null;\n + } \n +\n + // must always have a package\n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + \n + // if packageId includes a moduleId, slice it off\n + idx = packageId.indexOf(\':\');\n + if (idx>=0) packageId = packageId.slice(0, idx);\n + \n + // now we can just pass onto internal primitive\n + return this._canonicalPackageId(packageId, vers, workingPackage);\n +};\n +\n +\n +/**\n + Primitive returns the package instance for the named canonicalId. You can\n + pass in a canonicalId for a package only or a package and module. In either\n + case, this method will only return the package instance itself.\n + \n + Note that to load a canonicalId that was not resolved through the \n + canonicalPackageId() or canonical() method, you will need to also pass in\n + a workingPackage so the loader can find the package.\n + \n + @param {String} canonicalId\n + The canonicalId to load a package for. May contain only the packageId or\n + a moduleId as well.\n + \n + @param {Package} workingPackage\n + Optional workingPackage used to locate the package. This is only needed\n + if you request a canonicalId that you did not obtain through the \n + canonical*() methods on the loader.\n +\n + @returns {void}\n +*/\n +Loader.prototype.packageFor = function(canonicalId, workingPackage){\n +\n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + \n + // remove moduleId\n + var idx = canonicalId.indexOf(\':\', 2);\n + if (idx>=0) canonicalId = canonicalId.slice(0, idx);\n +\n + return this._packageFor(canonicalId, workingPackage);\n +};\n +\n +/**\n + Verifies that the named canonicalId is ready for use, including any of its\n + dependencies. You can pass in either a canonical packageId only or a \n + moduleId. In either case, this method will actually only check the package\n + properties for dependency resolution since dependencies are not tracked for\n + individual modules.\n + \n + @param {String} canonicalId\n + The canonicalId to use for lookup\n + \n + @param \n +*/\n +Loader.prototype.ready = function(canonicalId, workingPackage) {\n +\n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + \n + // strip out moduleId\n + var idx = canonicalId.indexOf(\':\', 2), \n + moduleId, pkg;\n + \n + if (idx >= 0) {\n + moduleId = canonicalId.slice(idx+1);\n + canonicalId = canonicalId.slice(0, idx);\n + }\n + \n + if (this._packageReady(canonicalId, workingPackage, {})) {\n + pkg = this._packageFor(canonicalId, workingPackage);\n + if (!pkg) return false;\n + return !!pkg.exists(moduleId);\n + } else return false;\n + \n +};\n +\n +/**\n + Ensures the package that maps to the passed packageId/vers combo and all\n + of its known dependencies are loaded and ready for use. If anything is not\n + loaded, it will load them also. \n + \n + Invokes the passed callback when loading is complete.\n + \n + This method ends up calling ensurePackage() on one or more of its sources\n + to get the actual packages to load.\n + \n + @param {String} packageId\n + The packageID to load. May be a packageId name or a canonical packageId\n + \n + @param {String} vers\n + Optional version used to constrain the compatible package\n + \n + @param {Package} workingPackage\n + Optional working package used to match the packageId. If the package \n + might be nested you should always pass a workingPackage. Default assumes\n + anonymousPackage.\n + \n + @param {Function} done\n + Callback invoked when package is loaded. Passes an error if there was an\n + error. Otherwise no params.\n + \n + @returns {void}\n +*/\n +Loader.prototype.ensurePackage = function(packageId, vers, workingPackage, done) {\n +\n + // normalize params\n + if (vers && (T_STRING !== typeof vers)) {\n + done = workingPackage ;\n + workingPackage = vers;\n + vers = null;\n + }\n +\n + if (workingPackage && (T_FUNCTION === typeof workingPackage)) {\n + done = workingPackage;\n + workingPackage = null;\n + }\n + \n + if (!workingPackage) workingPackage = this.anonymousPackage;\n +\n + this._ensurePackage(packageId, vers, workingPackage, {}, done);\n +};\n +\n +/**\n + @private\n + \n + Primitive for ensurePackage(). Does no param normalization. Called \n + recursively for dependencies.\n +*/\n +Loader.prototype._ensurePackage = function(packageId, vers, workingPackage, seen, done) {\n +\n + var loader = this, canonicalId, source;\n + \n + // find the canonicalId and source to ask to ensure...\n + canonicalId = this._canonicalPackageId(packageId, vers, workingPackage);\n + if (!canonicalId) {\n + return done(new NotFound(packageId, workingPackage));\n + }\n +\n + if (seen[canonicalId]) return done(); // success\n + seen[canonicalId] = true;\n +\n + source = this._sourceForCanonicalPackageId(canonicalId, workingPackage);\n + if (!source) {\n + return done(new NotFound(canonicalId, workingPackage));\n + }\n +\n + source.ensurePackage(canonicalId, function(err) {\n + var pkg, deps, packageId, packageIds;\n +\n + if (err) return done(err);\n + pkg = loader.packageFor(canonicalId, workingPackage);\n + if (!pkg) {\n + return done(new NotFound(canonicalId, workingPackage));\n + }\n +\n + deps = pkg.get(\'dependencies\');\n + if (!deps) return done(); // nothing to do\n + \n + // map deps to array to we can process in parallel\n + packageIds = [];\n + for(packageId in deps) {\n + if (!deps.hasOwnProperty(packageId)) continue;\n + packageIds.push({ packageId: packageId, vers: deps[packageId] });\n + }\n + \n + parallel(packageIds, function(info, done) {\n + loader._ensurePackage(info.packageId, info.vers, pkg, seen, done);\n + })(done);\n +\n + });\n + \n +};\n +\n +/**\n + @private\n + \n + Discovers the canonical packageId for the named packageId, version and \n + working package. This will also store in cache the source where you can\n + locare and load the associated package, if needed.\n + \n + This primitive is used by all other package methods to resolve a package\n + into a canonicalId that can be used to reference a specific package instance\n + \n + It does not perform any error checking on passed in parameters which is why\n + it should never be called directly outside of the Loader itself.\n + \n + @param {String|Package} packageId\n + The packageId to load. If you pass a package, the package itself will\n + be returned.\n + \n + @param {String} vers \n + The required version. Pass null or omit this parameter to use the latest\n + version (compatible with the workingPackage).\n + \n + @param {Package} workingPackage\n + The working package. This method will search in this package first for\n + nested packages. It will also consult the workingPackage to determine \n + the required version if you don\'t name a version explicitly.\n + \n + @returns {String}\n +*/\n +Loader.prototype._canonicalPackageId = function(packageId, vers, workingPackage) {\n +\n + // fast paths\n + if (packageId instanceof Package) return packageId.id;\n + if (isCanonicalId(packageId)) return packageId;\n + if ((packageId === \'default\') && this.defaultPackage) {\n + return this.defaultPackage.id;\n + }\n + \n + var cache = this.canonicalPackageIds,\n + cacheId, sources, ret, idx, len, source;\n +\n + // use anonymousPackage if no workingPackage is provided\n + if (!workingPackage) workingPackage = this.anonymousPackage;\n + if (!workingPackage) throw new Error(\'working package is required\');\n +\n + // if packageId is already canonical, vers must be null, otherwise lookup\n + // vers in working package\n + if (!vers) vers = workingPackage.requiredVersion(packageId);\n + \n + // look in cache...\n + cacheId = workingPackage.id;\n + if (!cache) cache = this.canonicalPackageIds = {};\n + if (!cache[cacheId]) cache[cacheId] = {};\n + cache = cache[cacheId];\n + if (!cache[packageId]) cache[packageId] = {};\n + cache = cache[packageId];\n + if (cache[vers]) return cache[vers];\n +\n + sources = this.sources;\n +\n + // first, ask the workingPackage \n + ret = workingPackage.canonicalPackageId(packageId, vers);\n + source = workingPackage;\n + \n +\n + // not found - make sure there isn\'t another incompatible version in \n + // workingPackage. nested packages superceed all other packages so if there\n + // is an incompatible nested version we need to throw an error.\n + if (!ret) {\n + ret = workingPackage.canonicalPackageId(packageId, null);\n + if (ret) {\n + throw new Error(\n + workingPackage.get(\'name\')+" contains an incompatible nested"+\n + " package "+packageId+" (expected: "+vers+")");\n + }\n + }\n + \n + \n + // next, if not found in the workingPackage, then ask each of our \n + // sources in turn until a match is found. When found, return\n + if (!ret && sources) {\n + len = sources.length;\n + for(idx=0;!ret && (idx<len);idx++) {\n + source = sources[idx];\n + ret = source.canonicalPackageId(packageId, vers);\n + }\n + }\n + \n + if (ret) this._cachePackageSource(ret, workingPackage, source);\n + cache[vers] = ret;\n + return ret ;\n +};\n +\n +// add a function to the cache that will immediately return the source\n +Loader.prototype._cachePackageSource = function(id, workingPackage, source) {\n + var scache = this.packageSources, pkgId = workingPackage.id;\n + \n + if (!scache) scache = this.packageSources = {};\n + if (!scache[pkgId]) scache[pkgId] = {};\n + scache = scache[pkgId];\n + scache[id] = source;\n +};\n +\n +/**\n + Looks up the source for the named canonicalId in the cache. Returns null\n + if no match is found.\n +*/\n +Loader.prototype._sourceForCanonicalPackageId = function(canonicalId, workingPackage) {\n + var scache = this.packageSources, \n + wpackageId = workingPackage.id, \n + pkg, sources, len, idx, ret;\n +\n + if (!scache) scache = this.packageSources = {};\n + if (!scache[wpackageId]) scache[wpackageId] = {};\n + scache = scache[wpackageId];\n + if (scache[canonicalId]) return scache[canonicalId];\n + \n + sources = this.sources;\n + \n + // first, ask the workingPackage to find any matching package (since it \n + // can only have one version). Then check the returned version against \n + // the expected version. \n + if (workingPackage) {\n + pkg = workingPackage.packageFor(canonicalId);\n + if (pkg) ret = workingPackage; \n + }\n + \n + if (!ret && sources) {\n + len = sources.length;\n + for(idx=0;!ret && (idx<len); idx++) {\n + ret = sources[idx];\n + if (!ret.packageFor(canonicalId)) ret = null;\n + }\n + }\n + \n + scache[canonicalId] = ret;\n + return ret ;\n +};\n +\n +/**\n + Primitive actually loads a package from a canonicalId. Throws an exception\n + if source for package is not already in cache. Also caches loaded package.\n +*/\n +Loader.prototype._packageFor = function(canonicalId, workingPackage) {\n + var cache, source, ret;\n +\n + // special case - if default packageId just get the default package.\n + if (this.defaultPackage && (canonicalId === this.defaultPackage.id)) {\n + return this.defaultPackage;\n + }\n + \n + // try to resolve out of cache\n + cache = this.packages;\n + if (!cache) cache = this.packages = {};\n + if (cache[canonicalId]) return cache[canonicalId];\n +\n + source = this._sourceForCanonicalPackageId(canonicalId, workingPackage);\n + if (source) ret = source.packageFor(canonicalId);\n + cache[canonicalId] = ret;\n + return ret ;\n +};\n +\n +/**\n + Primitive simply checks to see if the named canonicalId is ready or not\n + along with any dependencies\n +*/\n +Loader.prototype._packageReady = function(canonicalId, workingPackage, seen) {\n + var cache = this.packages, pkg, deps, packageId, vers;\n +\n + // if we\'ve already seen this package, exit immediately\n + if (seen[canonicalId]) return true;\n + seen[canonicalId] = true;\n + \n + // first try to find the package for the receiver\n + pkg = this._packageFor(canonicalId, workingPackage);\n + if (!pkg) return false; // nothing to do.\n +\n + // look at dependencies. make sure they are also loaded\n + deps = pkg.get(\'dependencies\');\n + for(packageId in deps) {\n + if (!deps.hasOwnProperty(packageId)) continue;\n + vers = deps[packageId];\n + canonicalId = this._canonicalPackageId(packageId, vers, pkg);\n + if (!canonicalId) return false;\n + return this._packageReady(canonicalId, pkg, seen);\n + }\n + \n + return true;\n +};\n +\n +/**\n + Take a relative or fully qualified module name as well as an optional\n + base module Id name and returns a fully qualified module name. If you \n + pass a relative module name and no baseId, throws an exception.\n +\n + Any embedded package name will remain in-tact.\n +\n + resolve(\'foo\', \'bar\', \'my_package\') => \'foo\'\n + resolve(\'./foo\', \'bar/baz\', \'my_package\') => \'my_package:bar/foo\'\n + resolve(\'/foo/bar/baz\', \'bar/baz\', \'my_package\') => \'default:/foo/bar/baz\'\n + resolve(\'foo/../bar\', \'baz\', \'my_package\') => \'foo/bar\'\n + resolve(\'your_package:foo\', \'baz\', \'my_package\') => \'your_package:foo\'\n +\n + If the returned id does not include a packageId then the canonical() \n + method will attempt to resolve the ID by searching the default package, \n + then the current package, then looking for a package by the same name.\n +\n + @param {String} moduleId relative or fully qualified module id\n + @param {String} baseId fully qualified base id\n + @returns {String} fully qualified name\n +*/\n +Loader.prototype._resolve = function(moduleId, curModuleId, pkg){\n + var path, len, idx, part, parts, packageId, err;\n +\n + // if id does not contain a packageId and it starts with a / then \n + // return with anonymous package id.\n + if (moduleId[0]===\'/\' && moduleId.indexOf(\':\')<0) {\n + return this.anonymousPackage.id + \':\' + moduleId;\n + }\n +\n + // contains relative components?\n + if (moduleId.match(/(^\\.\\.?\\/)|(\\/\\.\\.?\\/)|(\\/\\.\\.?\\/?$)/)) {\n +\n + // if we have a packageId embedded, get that first\n + if ((idx=moduleId.indexOf(\':\'))>=0) {\n + packageId = moduleId.slice(0,idx);\n + moduleId = moduleId.slice(idx+1);\n + path = []; // path must always be absolute.\n +\n + // if no package ID, then use baseId if first component is . or ..\n + } else if (moduleId.match(/^\\.\\.?\\//)) {\n + if (!curModuleId) {\n + throw new Error("id required to resolve relative id: "+moduleId);\n + }\n +\n + // if base moduleId contains a packageId return an error\n + if (curModuleId.indexOf(\':\')>=0) {\n + throw new Error("current moduleId cannot contain packageId");\n + }\n + \n + // use the pkg.id (which will be canonical)\n + if (pkg) packageId = pkg.id;\n +\n + // work from current moduleId as base. Ignore current module name\n + path = curModuleId.split(\'/\');\n + path.pop(); \n +\n + } else path = [];\n +\n + // iterate through path components and update path\n + parts = moduleId.split(\'/\');\n + len = parts.length;\n + for(idx=0;idx<len;idx++) {\n + part = parts[idx];\n + if (part === \'..\') {\n + if (path.length<1) throw new Error("invalid path: "+moduleId);\n + path.pop();\n +\n + } else if (part !== \'.\') path.push(part);\n + }\n +\n + moduleId = path.join(\'/\');\n + if (packageId) moduleId = joinPackageId(packageId, moduleId);\n + }\n +\n + return moduleId ;\n +};\n +\n +\n +// ..........................................................\n +// SANDBOX\n +// \n +\n +/**\n + A Sandbox maintains a cache of instantiated modules. Whenever a modules \n + is instantiated, it will always be owned by a single sandbox. This way\n + when you required the same module more than once, you will always get the\n + same module.\n + \n + Each sandbox is owned by a single loader, which is responsible for providing\n + the sandbox with Factory objects to instantiate new modules.\n + \n + A sandbox can also have a \'main\' module which can be used as a primary\n + entry point for finding other related modules.\n + \n +*/\n +var Sandbox = exports.extend(Object);\n +exports.Sandbox = Sandbox;\n +\n +Sandbox.prototype.init = function(loader, env, args, mainModuleId) {\n + this.loader = loader;\n + this.env = env;\n + this.args = args;\n + if (mainModuleId) this.main(mainModuleId);\n +\n + this.clear();\n +};\n +\n +Sandbox.prototype.catalogPackages = function(workingPackage) {\n + return this.loader.catalogPackages(workingPackage);\n +};\n +\n +Sandbox.prototype.createRequire = function(module) {\n + \n + var sandbox = this,\n + curId = module.id,\n + curPkg = module.ownerPackage,\n + reqd;\n + \n + // basic synchronous require\n + var req = function(moduleId, packageId) {\n + if (packageId && moduleId.indexOf(\':\')<0) {\n + if (packageId.isPackage) packageId = packageId.id;\n + moduleId = packageId+\':\'+moduleId;\n + }\n + return sandbox.require(moduleId, curId, curPkg);\n + };\n + reqd = req.displayName = (curId||\'(unknown)\')+\'#require\';\n +\n + // expose any native require. Mostly used by seed\n + req.nativeRequire = sandbox.nativeRequire;\n + \n + // async version - packageId is optional\n + req.ensure = function(moduleIds, done) {\n + // always normalize moduleId to an array\n + if (!isArray(moduleIds)) {\n + moduleIds = Array.prototype.slice.call(arguments);\n + done = moduleIds.pop();\n + }\n +\n + // ensure each module is loaded \n + parallel(moduleIds, function(moduleId, done) {\n + sandbox.ensure(moduleId, curId, curPkg, done);\n +\n + })(function(err) { \n + if (err) return done(err);\n + if (done.length<=1) return done(); // don\'t lookup modules themselves\n + \n + done(null, map(moduleIds, function(moduleId) {\n + return sandbox.require(moduleId, curId, curPkg);\n + }));\n + });\n + };\n + req.ensure.displayName = reqd+\'.ensure\';\n + \n + // return true if the passed module or modules are ready for use right now\n + // this is like calling ensure() but it won\'t load anything that isn\'t \n + // actually ready\n + req.ready = function(moduleIds) {\n + var idx, len ;\n + \n + // always normalize moduleId to an array\n + if (!isArray(moduleIds)) {\n + moduleIds = Array.prototype.slice.call(arguments);\n + }\n +\n + len = moduleIds.length;\n + for(idx=0;idx<len;idx++) {\n + if (!sandbox.ready(moduleIds[idx], curId, curPkg)) return false;\n + }\n + return true;\n + };\n + req.ready.displayName = reqd+\'.ready\';\n +\n + /**\n + Returns the package for the named packageId and optional version from\n + the perspective of the current package. This invokes a similar method \n + on the sandbox, which will pass it along to the loader, though a secure\n + sandbox may actually wrap the responses as well.\n + \n + This method only acts on packages available locally. To get possibly\n + remote packages, you must first call require.ensurePackage() to ensure\n + the package and its dependencies have been loaded.\n + \n + @param {String} packageId\n + The packageId to load\n + \n + @param {String} vers\n + Optional version\n + \n + @returns {Package} the package or null\n + */\n + req.packageFor = function(packageId, vers) {\n + return sandbox.packageFor(packageId, vers, curPkg);\n + };\n + req.packageFor.displayName = reqd+\'.packageFor\';\n + \n + /**\n + Asynchronously loads the named package and any dependencies if needed.\n + This is only required if you suspect your package may not be available \n + locally. If your callback accepts only one parameter, then the packages\n + will be loaded but not instantiated. The first parameter is always an \n + error object or null.\n + \n + If your callback accepts more than one parameter, then the packages will\n + be instantiated and passed to your callback as well.\n + \n + If a package cannot be loaded for some reason, your callback will be \n + invoked with an error of type NotFound.\n + \n + @param {String} packageId\n + The packageId to load\n + \n + @param {String} vers\n + Optional version\n +\n + @param {Function} done\n + Callback invoked once packages have loaded.\n + \n + @returns {Package} the package or null\n + */\n + req.ensurePackage = function(packageId, vers, done) {\n + sandbox.ensurePackage(packageId, vers, curPkg, function(err) {\n + if (err) return done(err);\n + if (done.length <= 1) return done();\n + done(null, sandbox.packageFor(packageId, vers, curPkg));\n + });\n + };\n + req.ensurePackage.displayName = reqd+\'.ensurePackage.displayName\';\n + \n + /**\n + Returns a catalog of all packages visible to the current module without\n + any additional loading. This may be an expensive operation; you should\n + only use it when necessary to detect plugins, etc.\n + */\n + req.catalogPackages = function() {\n + return sandbox.catalogPackages(curPkg);\n + };\n + \n + // mark main module in sandbox\n + req.main = sandbox.main();\n + req.env = sandbox.env;\n + req.args = sandbox.args;\n + req.sandbox = sandbox;\n + req.loader = sandbox.loader;\n + \n + req.isTiki = true; // walk like a duck\n + \n + return req;\n +};\n +\n +// ..........................................................\n +// RESOLVING MODULE IDS\n +// \n +\n +Sandbox.prototype.Module = Module;\n +\n +/**\n + Retrieves a module object for the passed moduleId. You can also pass \n + optional package information, including an optional curModuleId and a\n + workingPackage. You MUST pass at least a workingPackage.\n + \n + The returned module object represents the module but the module exports may\n + not yet be instantiated. Use require() to retrieve the module exports.\n + \n + @param {String} moduleId\n + The module id to lookup. Should include a nested packageId\n + \n + @param {String} curModuleId\n + Optional current module id to resolve relative modules.\n + \n + @param {Package} workingPackage\n + The working package making the request\n + \n + @returns {void}\n +*/\n +Sandbox.prototype.module = function(moduleId, curModuleId, workingPackage) {\n +\n + var ret, canonicalId, cache, packageId, idx, pkg;\n + \n + // assume canonicalId will normalize params\n + canonicalId = this.loader.canonical(moduleId, curModuleId, workingPackage);\n + if (!canonicalId) throw(new NotFound(moduleId, workingPackage));\n +\n + // get out of cache first\n + cache = this.modules;\n + if (!cache) cache = this.modules = {};\n + if (ret = cache[canonicalId]) return ret;\n + \n + // not in cache...add it\n + idx = canonicalId.indexOf(\':\', 2);\n + moduleId = canonicalId.slice(idx+1);\n + packageId = canonicalId.slice(0, idx);\n + pkg = this.loader.packageFor(packageId, workingPackage);\n + if (!pkg) throw(new NotFound(packageId, workingPackage));\n + ret = cache[canonicalId] = new this.Module(moduleId, pkg, this);\n + \n + return ret ;\n +};\n +\n +/**\n + Returns the main module for the sandbox. This should only be called \n + from the factory when it is setting main on itself. Otherwise the main\n + module may not exist yet.\n + \n + Note that the mainModule will be resolved using the anonymousPackage so\n + the named module must be visible from there.\n +*/\n +Sandbox.prototype.main = function(newMainModuleId, workingPackage) {\n + if (newMainModuleId !== undefined) {\n + this._mainModule = null;\n + this._mainModuleId = newMainModuleId;\n + this._mainModuleWorkingPackage = workingPackage;\n + return this;\n + \n + } else {\n + if (!this._mainModule && this._mainModuleId) {\n + workingPackage = this._mainModuleWorkingPackage;\n + this._mainModule = this.module(this._mainModuleId, workingPackage);\n + }\n + return this._mainModule;\n + }\n +};\n +\n +/**\n + Returns the exports for the named module.\n +\n + @param {String} moduleId\n + The module id to lookup. Should include a nested packageId\n + \n + @param {String} curModuleId\n + Optional current module id to resolve relative modules.\n + \n + @param {Package} workingPackage\n + The working package making the request\n + \n + @param {Function} done\n + Callback to invoke when the module has been retrieved.\n + \n + @returns {void}\n +*/\n +Sandbox.prototype.require = function(moduleId, curModuleId, workingPackage) {\n +\n + var ret, canonicalId, cache, used, factory, module, exp;\n + \n + // assume canonical() will normalize params\n + canonicalId = this.loader.canonical(moduleId, curModuleId, workingPackage);\n + if (!canonicalId) throw new NotFound(moduleId, workingPackage);\n +\n + // return out of cache\n + cache = this.exports; used = this.usedExports;\n + if (!cache) cache = this.exports = {};\n + if (!used) used = this.usedExports = {};\n + if (ret = cache[canonicalId]) {\n + ret = ret.exports;\n + if (!used[canonicalId]) used[canonicalId] = ret;\n + return ret;\n + }\n +\n + // not in cache, get factory, module, and run function...\n + factory = this.loader.load(canonicalId, workingPackage, this);\n + if (!factory) throw(new NotFound(canonicalId, workingPackage));\n +\n + module = this.module(canonicalId, workingPackage);\n + cache[canonicalId] = module;\n +\n + exp = factory.call(this, module);\n + module.exports = exp;\n + \n + // check for cyclical refs\n + if (used[canonicalId] && (used[canonicalId] !== exp)) {\n + throw new Error("cyclical requires() in "+canonicalId);\n + }\n +\n + return exp;\n +};\n +\n +/**\n + Returns true if the given module is ready. This checks the local cache \n + first then hands this off to the loader.\n +*/\n +Sandbox.prototype.ready = function(moduleId, curModuleId, workingPackage) {\n + // assume canonicalPackageId() will normalize params\n + var id = this.loader.canonical(moduleId, curModuleId, workingPackage);\n + return id ? this.loader.ready(id) : false;\n +};\n +\n +/**\n + Ensures the passed moduleId and all of its dependencies are available in\n + the local domain. If any dependencies are not available locally, attempts\n + to retrieve them from a remote server.\n + \n + You don\'t usually call this method directly. Instead you should call the \n + require.ensure() method defined on a module\'s local require() method.\n + \n +*/\n +Sandbox.prototype.ensure = function(moduleId, curModuleId, workingPackage, done) {\n +\n + var id, loader, packageId, idx;\n + \n + // normalize params so that done is in right place\n + if (curModuleId && (T_STRING !== typeof curModuleId)) {\n + done = workingPackage;\n + workingPackage = curModuleId;\n + curModuleId = null;\n + }\n + \n + if (workingPackage && (T_FUNCTION === typeof workingPackage)) {\n + done = workingPackage ;\n + workingPackage = null;\n + }\n + \n + id = this.loader.canonical(moduleId, curModuleId, workingPackage);\n + if (!id) return done(new NotFound(moduleId, workingPackage));\n + \n + idx = id.indexOf(\':\', 2);\n + moduleId = id.slice(idx+1);\n + packageId = id.slice(0, idx);\n + loader = this.loader;\n +\n + loader.ensurePackage(packageId, workingPackage, function(err) {\n + if (err) return done(err);\n + var pkg = loader.packageFor(packageId, workingPackage);\n + if (!pkg.exists(moduleId)) done(new NotFound(moduleId, pkg));\n + else done(); // all clear\n + });\n +};\n +\n +/**\n + TODO: document\n +*/\n +Sandbox.prototype.packageFor = function(packageId, vers, workingPackage) {\n +\n + // assume canonicalPackageId() will normalize params\n + var id = this.loader.canonicalPackageId(packageId, vers, workingPackage);\n + if (!id) return null;\n + return this.loader.packageFor(id);\n +};\n +\n +/** \n + TODO: document\n +*/\n +Sandbox.prototype.ensurePackage = function(packageId, vers, workingPackage, done) {\n +\n + // normalize params so that done is in right place\n + if (vers && (T_STRING !== typeof vers)) {\n + done = workingPackage;\n + workingPackage = vers;\n + vers = null;\n + }\n + \n + if (workingPackage && (T_FUNCTION === typeof workingPackage)) {\n + done = workingPackage ;\n + workingPackage = null;\n + }\n + \n + var id = this.loader.canonicalPackageId(packageId, vers, workingPackage);\n + if (!id) return done(new NotFound(packageId, workingPackage));\n + this.loader.ensurePackage(id, done);\n +};\n +\n +\n +/**\n + Returns the path or URL to a resource in the named package. \n +*/\n +Sandbox.prototype.resource = function(resourceId, moduleId, ownerPackage) {\n + if (!ownerPackage.resource) return null;\n + return ownerPackage.resource(resourceId, moduleId);\n +};\n +\n +/**\n + Clears the sandbox. requiring modules will cause them to be reinstantied\n +*/\n +Sandbox.prototype.clear = function() {\n + this.exports = {};\n + this.modules = {};\n + this.usedExports = {};\n + return this;\n +};\n +\n +// ..........................................................\n +// BROWSER\n +// \n +\n +// Implements a default loader source for use in the browser. This object\n +// should also be set as the "require" global on the browser to allow for\n +// module registrations\n +\n +var Browser = exports.extend(Object);\n +exports.Browser = Browser;\n +\n +Browser.prototype.init = function() {\n + this._ready = {};\n + this._unload = {};\n + \n + this.clear();\n +};\n +\n +/**\n + Reset the browser caches. This would require all packages and modules \n + to register themselves. You should also clear the associated loader and\n + sandbox if you use this.\n +*/\n +Browser.prototype.clear = function() {\n + this.packageInfoByName = {}; // stores package info sorted by name/version\n + this.packageInfoById = {}; // stores package info sorted by id\n + this.packages = {}; // instantiated packages\n + this.factories = {}; // registered module factories by id\n +\n + this.stylesheetActions = {}; // resolvable stylesheet load actions\n + this.scriptActions = {}; // resolvable script actions\n + this.ensureActions = {}; // resolvable package actions\n +};\n +\n +/**\n + Configures a basic sandbox environment based on the browser. Now you can\n + register and require from it.\n + \n + @returns {Browser} new instance\n +*/\n +Browser.start = function(env, args, queue) {\n + // build new chain of objects and setup require.\n + var browser, len, idx, action;\n + \n + browser = new Browser();\n + browser.loader = new Loader([browser]);\n + browser.sandbox = new Sandbox(browser.loader, env, args);\n + browser.queue = queue;\n +\n + var mod = { \n + id: \'index\', \n + ownerPackage: browser.loader.anonymousPackage \n + };\n +\n + browser.require = browser.sandbox.createRequire(mod);\n + // TODO: amend standard CommonJS methods for loading modules when they\n + // are standardized\n + \n + return browser;\n +};\n +\n +Browser.prototype.replay = function() {\n + var queue = this.queue,\n + len = queue ? queue.length : 0,\n + idx, action;\n + \n + this.queue = null;\n + for(idx=0;idx<len;idx++) {\n + action = queue[idx];\n + this[action.m].apply(this, action.a);\n + }\n + \n + return this;\n +};\n +\n +// safe - in place of preamble start()\n +Browser.prototype.start = function() {\n + return this;\n +};\n +\n +/**\n + Makes all dependencies of the passed canonical packageId global. Used\n + for backwards compatibility with non-CommonJS libraries.\n +*/\n +Browser.prototype.global = function(canonicalId) {\n + if (!domAvailable && !xhrAvailable) return this; // don\'t work out of brsr\n + var GLOBAL = (function() { return this; })();\n + \n + var globals, pkg, deps, packageId, exports, keys, key, idx, len;\n + \n + globals = this.globals;\n + if (!globals) globals = this.globals = {};\n +\n + pkg = this.packageFor(canonicalId);\n + if (!pkg) throw new Error(canonicalId+\' package not found\');\n + \n + deps = pkg.get(\'dependencies\');\n + if (!deps) return this; // nothing to do\n + \n + for(packageId in deps) {\n + if (!deps.hasOwnProperty(packageId)) continue;\n + canonicalId = this.loader.canonical(packageId, pkg);\n + if (globals[canonicalId]) continue;\n + globals[canonicalId] = true;\n + \n + // some cases a dependency refers to a package that is itself not \n + // using modules. In this case just ignore\n + if (!this.sandbox.ready(packageId, pkg)) continue;\n + \n + exports = this.sandbox.require(packageId, pkg);\n + if (keys = exports.__globals__) {\n + len = keys.length;\n + for(idx=0;idx<len;idx++) {\n + key = keys[idx];\n + GLOBAL[key] = exports[key];\n + }\n +\n + // no __globals__ key is defined so just iterate through any exported\n + // properties. this should actually be the more common case\n + } else {\n + for(key in exports) {\n + if (!exports.hasOwnProperty(key)) continue;\n + GLOBAL[key] = exports[key];\n + }\n + }\n + \n + }\n +\n + return this;\n +};\n +\n +// ..........................................................\n +// Ready & Unload Handlers\n +// \n +\n +var buildInvocation = function(args) {\n + var context, method;\n + \n + if (args.length === 1) {\n + context = null;\n + method = args[0];\n + args = Array.prototype.slice.call(args, 1);\n + } else {\n + context = args[0];\n + method = args[1];\n + args = Array.prototype.slice.call(args, 2);\n + }\n +\n + return { target: context, method: method, args: args };\n +};\n +\n +var queueListener = function(base, queueName, args) {\n + if (!base[queueName]) base[queueName] = [];\n + base[queueName].push(buildInvocation(args));\n +};\n +\n +/**\n + Invoke the passed callback when the document is ready. You can pass \n + either an object/function or a moduleId and property name plus additional\n + arguments.\n +*/\n +Browser.prototype.addReadyListener = function(context, method) {\n + if (this._ready && this._ready.isReady) {\n + this._invoke(buildInvocation(arguments));\n + } else {\n + this._setupReadyListener();\n + queueListener(this._ready, \'queue\', arguments);\n + }\n +};\n +\n +/**\n + Invoke the passed callback just after any ready listeners have fired but\n + just before the main moduleId is required. This is primarily provided as \n + a way for legacy environments to hook in their own main function.\n +*/\n +Browser.prototype.addMainListener = function(context, method) {\n + if (this._ready && this._ready.isReady) {\n + this._invoke(buildInvocation(arguments));\n + } else {\n + this._setupReadyListener();\n + queueListener(this._ready, \'mqueue\', arguments);\n + }\n +};\n +\n +/**\n + Invoke the passed callback when the browser is about to unload.\n +*/\n +Browser.prototype.addUnloadListener = function(context, method) {\n + if (this._unload && this._unload.isUnloading) {\n + this._invoke(buildInvocation(arguments));\n + } else {\n + this._setupUnloadListener();\n + queueListener(this._unload, \'queue\', arguments);\n + }\n +};\n +\n +\n +Browser.prototype._invoke = function(inv) {\n + var target = inv.target, method = inv.method;\n + if (T_STRING === typeof target) target = this.require(target);\n + if (T_STRING === typeof method) method = target[method];\n + if (method) method.apply(target, inv.args);\n + inv.target = inv.method = inv.args = null;\n +};\n +\n +Browser.prototype._setupReadyListener = function() {\n + if (this._ready.setup) return this;\n + this._ready.setup =true;\n + \n + var ready = this._ready, source = this, fire;\n + \n + fire = function() {\n + if (ready.isReady) return;\n + ready.isReady = true;\n + \n + // first cleanup any listeners so they don\'t fire again\n + if (ready.cleanup) ready.cleanup();\n + ready.cleanup = null;\n + \n + var q, len, idx;\n + \n + q = ready.queue;\n + len = q ? q.length : 0;\n + ready.queue = null;\n + for(idx=0;idx<len;idx++) source._invoke(q[idx]);\n + \n + q = ready.mqueue;\n + len = q ? q.length : 0 ;\n + ready.mqueue = null;\n + for(idx=0;idx<len;idx++) source._invoke(q[idx]);\n +\n + source._runMain(); // get main module.\n + };\n + \n + // always listen for onready event - detect based on platform\n + // those code is derived from jquery 1.3.1\n + // server-side JS\n + if (T_UNDEFINED === typeof document) {\n + // TODO: handler server-side JS cases here\n +\n + // Mozilla, Opera, webkit nightlies\n + } else if (document.addEventListener) {\n +\n + // cleanup handler to be called whenever any registered listener fires\n + // should prevent additional listeners from firing\n + ready.cleanup = function() {\n + document.removeEventListener(\'DOMContentLoaded\', fire, false);\n + document.removeEventListener(\'load\', fire, false);\n + };\n +\n + // register listeners\n + document.addEventListener(\'DOMContentLoaded\', fire, false);\n + document.addEventListener(\'load\', fire, false);\n +\n + // IE\n + } else if (document.attachEvent) {\n +\n + // cleanup handler - should cleanup all registered listeners\n + ready.cleanup = function() {\n + document.detachEvent(\'onreadystatechange\', fire);\n + document.detachEvent(\'onload\', fire);\n + ready.ieHandler = null; // will stop the ieHandler from firing again\n + };\n +\n + // listen for readystate and load events\n + document.attachEvent(\'onreadystatechange\', fire);\n + document.attachEvent(\'onload\', fire);\n +\n + // also if IE and no an iframe, continually check to see if the document \n + // is ready\n + // NOTE: DO NOT CHANGE TO ===, FAILS IN IE.\n + if ( document.documentElement.doScroll && window == window.top ) {\n + ready.ieHandler = function() {\n +\n + // If IE is used, use the trick by Diego Perini\n + // http://javascript.nwbox.com/IEContentLoaded/\n + if (ready.ieHandler && !ready.isReady) {\n + try {\n + document.documentElement.doScroll("left");\n + } catch( error ) {\n + setTimeout( ready.ieHandler, 0 );\n + return;\n + }\n + }\n +\n + // and execute any waiting functions\n + fire();\n + };\n +\n + ready.ieHandler();\n + }\n +\n + } \n +};\n +\n +Browser._scheduleUnloadListener = function() {\n + if (this._unload.setup) return this;\n + this._unload.setup =true;\n + \n + var unload = this._unload, source = this, fire;\n +\n + unload.isUnloading = false;\n + fire = function() { \n + if (unload.isUnloading) return;\n + unload.isUnloading = true;\n + \n + if (unload.cleanup) unload.cleanup();\n + unload.cleanup = null;\n + \n + var q = unload.queue,\n + len = q ? q.length : 0,\n + idx, inv;\n + \n + unload.queue = null;\n + for(idx=0;idx<len;idx++) source._invoke(q[idx]);\n + };\n +\n + if (T_UNDEFINED === typeof document) {\n + // TODO: Handle server-side JS mode\n + \n + } else if (document.addEventListener) {\n + unload.cleanup = function() {\n + document.removeEventListener(\'unload\', fire);\n + };\n + document.addEventListener(\'unload\', fire, false);\n + \n + } else if (document.attachEvent) {\n + unload.cleanup = function() {\n + document.detachEvent(\'onunload\', fire);\n + };\n + document.attachEvent(\'unload\', fire);\n + }\n + \n +};\n +\n +// ..........................................................\n +// Registration API\n +// \n +\n +/**\n + Sets the main moduleId on the sandbox. This module will be automatically\n + required after all other ready and main handlers have run when the document\n + is ready.\n + \n + @param {String} moduleId\n + A moduleId with packageId included ideally. Can be canonicalId.\n + \n + @returns {void}\n +*/\n +Browser.prototype.main = function(moduleId, method) {\n + if (this.sandbox) this.sandbox.main(moduleId);\n + this._setupReadyListener(); // make sure we listen for ready event\n + this._main = { id: moduleId, method: method };\n +};\n +\n +Browser.prototype._runMain = function() {\n + if (!this._main) return ;\n + \n + var moduleId = this._main.id,\n + method = this._main.method,\n + req = this.require;\n + \n + if (!moduleId || !req) return ;\n + this._main = null;\n +\n + // async load any main module dependencies if needed then require\n + req.ensure(moduleId, function(err) {\n + if (err) throw err;\n + var exp = req(moduleId);\n + if (T_STRING === typeof method) method = exp[method];\n + if (method) method.call(exp);\n + });\n +};\n +\n +\n +// creates a new action that will invoke the passed value then setup the\n +// resolve() method to wait on response\n +Browser.prototype._action = function(action) {\n + var ret;\n + \n + ret = once(function(done) {\n + ret.resolve = function(err, val) {\n + ret.resolve = null; // no more...\n + done(err, val);\n + };\n + action(); \n + });\n + return ret;\n + \n +};\n +\n +Browser.prototype._resolve = function(dict, key, value) {\n + \n + // for pushed content, just create the action function\n + if (!dict[key]) dict[key] = function(done) { done(null, value); };\n + \n + // if a value already exists, call resolve if still valid\n + else if (dict[key].resolve) dict[key].resolve(null, value);\n + return this;\n +};\n +\n +Browser.prototype._fail = function(dict, key, err) {\n + if (dict[key].resolve) dict[key].resolve(err);\n +};\n +\n +var T_SCRIPT = \'script\',\n + T_STYLESHEET = \'stylesheet\',\n + T_RESOURCE = \'resource\';\n + \n +/**\n + Normalizes package info, expanding some compacted items out to full \n + info needed.\n +*/\n +Browser.prototype._normalize = function(def, packageId) {\n + if (!isCanonicalId(packageId)) packageId = \'::\'+packageId;\n + def.id = packageId;\n + def.version = semver.normalize(def.version);\n + def[\'tiki:external\'] = !!def[\'tiki:external\']; \n + def[\'tiki:private\'] = !!def[\'tiki:private\']; // ditto\n +\n + // expand list of resources\n + var base = def[\'tiki:base\']; \n + if (def[\'tiki:resources\']) {\n +\n + def[\'tiki:resources\'] = map(def[\'tiki:resources\'], function(item) {\n + \n + // expand a simple string into a default entry\n + if (T_STRING === typeof item) {\n + item = { \n + id: packageId+\':\'+item,\n + name: item \n + };\n + }\n +\n + // must have an item name or you can\'t lookup the resource\n + if (!item.name) {\n + throw new InvalidPackageDef(def, \'resources must have a name\');\n + }\n +\n + if (!item.id) {\n + item.id = packageId+\':\'+item.name;\n + }\n + if (!isCanonicalId(item.id)) item.id = \'::\'+item.id;\n + \n + // assume type from ext if one is provided\n + if (!item.type) {\n + if (item.name.match(/\\.js$/)) item.type = T_SCRIPT;\n + else if (item.name.match(/\\.css$/)) item.type = T_STYLESHEET;\n + else item.type = T_RESOURCE;\n + }\n + \n + if (!item.url) {\n + if (base) item.url = base+\'/\'+item.name;\n + else item.url = item.id+item.name;\n + }\n + \n + return item;\n + });\n + }\n + \n + // always have a nested and dependencies hash, even if it is empty\n + if (!def.dependencies) def.dependencies = {};\n +\n + var nested = def[\'tiki:nested\'], key;\n + if (nested) {\n + for(key in nested) {\n + if (!nested.hasOwnProperty(key)) continue;\n + if (!isCanonicalId(nested[key])) nested[key] = \'::\'+nested[key];\n + }\n + \n + } else def[\'tiki:nested\'] = {};\n + \n + return def;\n +};\n +\n +/**\n + Register new package information.\n +*/\n +Browser.prototype.register = function(packageId, def) {\n + var reg, replace, name, vers, idx = -1;\n + \n + // normalize some basics...\n + def = this._normalize(def, packageId);\n + packageId = def.id; // make sure to get normalized packageId\n +\n + // see if a pkg with same id is registered. if so, replace it only if \n + // the new one is not external and the old one is\n + reg = this.packageInfoById;\n + if (!reg) reg = this.packageInfoById = {};\n + if (reg[packageId]) {\n + if (!reg[packageId][\'tiki:external\']) return this;\n + replace = reg[packageId];\n + }\n + reg[packageId] = def;\n + \n + if (def.name) {\n + name = def.name;\n + vers = def.version;\n + \n + reg = this.packageInfoByName;\n + if (!reg) reg = this.packageInfoByName = {};\n + if (!reg[name]) reg[name] = {};\n + reg = reg[name];\n + \n + // update list of packageIds matching version...\n + if (!reg[vers] || (reg[vers].length<=1)) {\n + reg[vers] = [def];\n + } else {\n + if (replace) idx = reg[vers].indexOf(replace);\n + if (idx>=0) {\n + reg[vers] = reg[vers].slice(0, idx).concat(reg[vers].slice(idx+1));\n + }\n + reg[vers].push(def);\n + }\n + \n + }\n + \n + return this;\n +};\n +\n +/**\n + Main registration API for all modules. Simply registers a module for later\n + use by a package.\n +*/\n +Browser.prototype.module = function(key, def) {\n + if (!isCanonicalId(key)) key = \'::\'+key;\n + this.factories[key] = def;\n + return this; \n +};\n +\n +/**\n + Register a script that has loaded\n +*/\n +Browser.prototype.script = function(scriptId) {\n + if (!isCanonicalId(scriptId)) scriptId = \'::\'+scriptId;\n + this._resolve(this.scriptActions, scriptId, true);\n +};\n +\n +/**\n + Register a stylesheet that has loaded.\n +*/\n +Browser.prototype.stylesheet = function(stylesheetId) {\n + if (!isCanonicalId(stylesheetId)) stylesheetId = \'::\'+stylesheetId;\n + this._resolve(this.stylesheetActions, stylesheetId, true);\n +};\n +\n +// ..........................................................\n +// Called by Loader\n +//\n +\n +var domAvailable = T_UNDEFINED !== typeof document && document.createElement;\n +var xhrAvailable = T_UNDEFINED !== typeof XMLHttpRequest;\n +\n +/**\n + Whether to use XHR by default. If true, XHR is tried first to fetch script\n + resources; script tag injection is only used as a fallback if XHR fails. If\n + false (the default if the DOM is available), script tag injection is tried\n + first, and XHR is used as the fallback.\n +*/\n +Browser.prototype.xhr = !domAvailable;\n +\n +/**\n + Whether to automatically wrap the fetched JavaScript in tiki.module() and\n + tiki.script() calls. With this on, CommonJS modules will "just work" without\n + preprocessing. Setting this to true requires, and implies, that XHR will be\n + used to fetch the files.\n +*/\n +Browser.prototype.autowrap = false;\n +\n +var findPublicPackageInfo = function(infos) {\n + if (!infos) return null;\n + \n + var loc = infos.length;\n + while(--loc>=0) {\n + if (!infos[loc][\'tiki:private\']) return infos[loc];\n + }\n + return null;\n +};\n +\n +/**\n + Find the canonical package ID for the passed package ID and optional \n + version. This will look through all the registered package infos, only\n + searching those that are not private, but including external references.\n +*/\n +Browser.prototype.canonicalPackageId = function(packageId, vers) {\n + var info = this.packageInfoByName[packageId],\n + ret, cur, cvers, rvers;\n + \n + if (vers) vers = semver.normalize(vers);\n + if (!info) return null; // not found\n + \n + // see if we have caught a lucky break\n + if (info[vers] && (info[vers].length===1)) return info[vers][0].id;\n +\n + // need to search...\n + for(cvers in info) {\n + if (!info.hasOwnProperty(cvers)) continue;\n + if (!semver.compatible(vers, cvers)) continue;\n + if (!ret || (semver.compare(rvers, cvers)<0)) {\n + ret = findPublicPackageInfo(info[cvers]);\n + if (ret) rvers = cvers; \n + }\n + }\n + \n + return ret ? ret.id : null;\n +};\n +\n +// get package for canonicalId, instantiate if needed\n +Browser.prototype.packageFor = function(canonicalId) {\n + var ret = this.packages[canonicalId];\n + if (ret) return ret ;\n +\n + // instantiate if needed\n + ret = this.packageInfoById[canonicalId];\n + if (ret && !ret[\'tiki:external\']) { // external refs can\'t be instantiated\n + ret = new this.Package(canonicalId, ret, this);\n + this.packages[canonicalId] = ret;\n + return ret ;\n + }\n +\n + return null ; // not found\n +};\n +\n +/**\n + Ensures the named canonical packageId and all of its dependent scripts are\n + loaded.\n +*/\n +Browser.prototype.ensurePackage = function(canonicalId, done) {\n + var action = this.ensureActions[canonicalId];\n + if (action) return action(done); // add another listener\n + \n + // no action get - get the package info and start one.\n + var info = this.packageInfoById[canonicalId];\n + if (!info) {\n + return done(new NotFound(canonicalId, \'browser package info\'));\n + }\n + \n + var source = this;\n + \n + action = once(function(done) {\n + var cnt = 1, ready = false, cancelled;\n + \n + // invoked when an action finishes. Will resolve this action\n + // when all of them finish.\n + var cleanup = function(err) {\n + if (cancelled) return;\n + if (err) {\n + cancelled = true;\n + return done(err);\n + }\n + \n + cnt = cnt-1;\n + if (cnt<=0 && ready) return done(null, info);\n + };\n +\n + // proactively kick off any known packages. If a dependent package\n + // is not known here just skip it for now. This is just an optimization\n + // anyway. The Loader will take care of ensuring all dependencies are\n + // really met.\n + var dependencies = info.dependencies,\n + nested = info[\'tiki:nested\'],\n + packageId, vers, depInfo, curId;\n +\n + for(packageId in dependencies) {\n + if (!dependencies.hasOwnProperty(packageId)) continue;\n + curId = nested[packageId];\n + if (!curId) {\n + vers = dependencies[packageId];\n + curId = source.canonicalPackageId(packageId, vers);\n + }\n + \n + if (curId && source.packageInfoById[canonicalId]) {\n + cnt++;\n + source.ensurePackage(curId, cleanup);\n + }\n + }\n + \n + // step through resources and kick off each script and stylesheet\n + var resources = info[\'tiki:resources\'], \n + lim = resources ? resources.length : 0,\n + loc, rsrc;\n + for(loc=0;loc<lim;loc++) {\n + rsrc = resources[loc];\n + if (rsrc.type === T_RESOURCE) continue;\n + if (rsrc.type === T_SCRIPT) {\n + cnt++;\n + source.ensureScript(rsrc.id, rsrc.url, cleanup);\n + } else if (rsrc.type === T_STYLESHEET) {\n + cnt++;\n + source.ensureStylesheet(rsrc.id, rsrc.url, cleanup);\n + }\n + }\n + \n + // done, set ready to true so that the final handler can fire\n + ready = true;\n + cleanup(); \n + \n + });\n + \n + this.ensureActions[canonicalId] = action;\n + action(done); // kick off\n +};\n +\n +Browser.prototype.ensureScript = function(id, url, done) {\n + var action = this.scriptActions[id];\n + if (action) return action(done);\n + \n + var source = this;\n + action = this._action(function() {\n + source._loadScript(id, url);\n + });\n + \n + this.scriptActions[id] = action;\n + return action(done);\n +};\n +\n +Browser.prototype.ensureStylesheet = function(id, url, done) {\n + var action = this.stylesheetActions[id];\n + if (action) return action(done);\n + \n + var source = this;\n + action = this._action(function() {\n + source._loadStylesheet(id, url);\n + });\n +\n + this.stylesheetActions[id] = action;\n + return action(done);\n +};\n +\n +Browser.prototype._injectScript = function(id, url) {\n + var body, el;\n +\n + body = document.body;\n + el = document.createElement(\'script\');\n + el.src = url;\n + body.appendChild(el);\n + body = el = null;\n +};\n +\n +Browser.prototype._xhrScript = function(id, url) {\n + var autowrap = this.autowrap;\n +\n + var req = new XMLHttpRequest();\n + req.open(\'GET\', url, true);\n + req.onreadystatechange = function(evt) {\n + // Accept 200 or 0 for local file requests.\n + if (req.readyState !== 4 || (req.status !== 200 && req.status !== 0)) {\n + return;\n + }\n +\n + var src = req.responseText;\n + if (autowrap) {\n + src = "tiki.module(\'" + id + "\', function(require, exports, module) {" +\n + src + "});" + "tiki.script(\'" + id + "\');";\n + }\n +\n + // Add a Firebug-style sourceURL parameter to help debugging.\n + eval(src + "\\n//@ sourceURL=" + url);\n +\n + // Immediately return after the eval. The script may have stomped all over\n + // our local state.\n + };\n +\n + req.send(null);\n +};\n +\n +Browser.prototype._loadScript = function(id, url) {\n + if (this.autowrap) {\n + this.xhr = true;\n + if (!xhrAvailable) {\n + DEBUG(\'Autowrap is on but XHR is not available. Danger ahead.\');\n + }\n + }\n +\n + if (xhrAvailable && domAvailable) {\n + if (this.xhr) {\n + try {\n + return this._xhrScript(id, url);\n + } catch (e) {\n + return this._injectScript(id, url);\n + }\n + } else {\n + try {\n + return this._injectScript(id, url);\n + } catch (e) {\n + return this._xhrScript(id, url);\n + }\n + }\n + } else if (xhrAvailable) {\n + return this._xhrScript(id, url);\n + } else if (domAvailable) {\n + return this._injectScript(id, url);\n + }\n +\n + DEBUG(\'Browser#_loadScript() not supported on this platform.\');\n + this.script(id);\n +};\n +\n +if (domAvailable) {\n + // actually loads the stylesheet. separated out to ease unit testing\n + Browser.prototype._loadStylesheet = function(id, url) {\n + var body, el;\n + \n + body = document.getElementsByTagName(\'head\')[0] || document.body;\n + el = document.createElement(\'link\');\n + el.rel = \'stylesheet\';\n + el.href = url;\n + el.type = \'text/css\';\n + body.appendChild(el);\n + el = body = null;\n +\n + this.stylesheet(id); // no onload support - just notify now.\n + };\n +} else {\n + // actually loads the stylesheet. separated out to ease unit testing\n + Browser.prototype._loadStylesheet = function(id, url) {\n + DEBUG(\'Browser#_loadStylesheet() not supported on this platform.\');\n + this.stylesheet(id);\n + };\n +}\n +\n +\n +\n +// ..........................................................\n +// BROWSER PACKAGE\n +// \n +\n +/**\n + Special edition of Package designed to work with the Browser source. This\n + kind of package knows how to get its data out of the Browser source on \n + demand.\n +*/\n +var BrowserPackage = Package.extend();\n +Browser.prototype.Package = BrowserPackage;\n +\n +BrowserPackage.prototype.init = function(id, config, source) {\n + Package.prototype.init.call(this, id, config);\n + this.source = source;\n +};\n +\n +// if not self, look for nested packages\n +BrowserPackage.prototype.canonicalPackageId = function(packageId, vers) {\n + var ret, nested, info;\n + \n + ret = Package.prototype.canonicalPackageId.call(this, packageId, vers);\n + if (ret) return ret ;\n + \n + nested = this.get(\'tiki:nested\') || {}; \n + ret = nested[packageId];\n + if (!ret) return null;\n +\n + info = this.source.packageInfoById[ret];\n + return info && semver.compatible(vers,info.version) ? ret : null;\n +};\n +\n +BrowserPackage.prototype.packageFor = function(canonicalId) {\n + var ret = Package.prototype.packageFor.call(this, canonicalId);\n + return ret ? ret : this.source.packageFor(canonicalId);\n +};\n +\n +BrowserPackage.prototype.ensurePackage = function(canonicalId, done) {\n + if (canonicalId === this.id) return done(); \n + this.source.ensurePackage(canonicalId, done);\n +};\n +\n +BrowserPackage.prototype.catalogPackages = function() {\n + var ret = [this], nested, key;\n +\n + nested = this.get(\'tiki:nested\') || {};\n + for(key in nested) {\n + if (!nested.hasOwnProperty(key)) continue;\n + ret.push(this.source.packageFor(nested[key]));\n + }\n + \n + return ret ;\n +};\n +\n +BrowserPackage.prototype.exists = function(moduleId) {\n + var canonicalId = this.id+\':\'+moduleId;\n + return !!this.source.factories[canonicalId];\n +};\n +\n +BrowserPackage.prototype.load = function(moduleId) {\n + var canonicalId, factory;\n + \n + canonicalId = this.id+\':\'+moduleId;\n + factory = this.source.factories[canonicalId];\n + return factory ? new this.Factory(moduleId, this, factory) : null;\n +};\n +\n +BrowserPackage.prototype.Factory = Factory;\n +\n +\n +displayNames(exports, \'tiki\');\n +\n +});\n +// ==========================================================================\n +// Project: Tiki - CommonJS Runtime\n +// Copyright: ©2009-2010 Apple Inc. All rights reserved.\n +// License: Licened under MIT license (see __preamble__.js)\n +// ==========================================================================\n +/*globals tiki ENV ARGS */\n +\n +// This postamble runs when the loader and supporting modules are all \n +// registered, allowing the real loader to replace the bootstrap version.\n +// it is not wrapped as a module so that it can run immediately.\n +"use modules false";\n +"use loader false";\n +\n +// note that the loader.start method is safe so that calling this more than\n +// once will only setup the default loader once.\n +tiki = tiki.start();\n +tiki.replay(); // replay queue\n +\n +bespin.tiki = tiki;\n +})();\n +\n +;bespin.tiki.register("::bespin", {\n + name: "bespin",\n + dependencies: { }\n +});bespin.bootLoaded = true;\n +bespin.tiki.module("bespin:plugins",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +require("globals");\n +\n +var Promise = require("promise").Promise;\n +var group = require("promise").group;\n +var builtins = require("builtins");\n +var console = require("console").console;\n +var util = require("util/util");\n +var Trace = require("util/stacktrace").Trace;\n +var proxy = require(\'proxy\');\n +\n +var r = require;\n +\n +var loader = require.loader;\n +var browser = loader.sources[0];\n +\n +var USER_DEACTIVATED = \'USER\';\n +var DEPENDS_DEACTIVATED = \'DEPENDS\';\n +\n +/**\n + * Split an extension pointer from module/path#objectName into an object of the\n + * type { modName:"module/path", objName:"objectName" } using a pluginName\n + * as the base to which roots the pointer\n + */\n +var _splitPointer = function(pluginName, pointer) {\n + if (!pointer) {\n + return undefined;\n + }\n +\n + var parts = pointer.split("#");\n + var modName;\n +\n + // this allows syntax like #foo\n + // which is equivalent to PluginName:index#foo\n + if (parts[0]) {\n + modName = pluginName + ":" + parts[0];\n + } else {\n + modName = pluginName;\n + }\n +\n + return {\n + modName: modName,\n + objName: parts[1]\n + };\n +};\n +\n +var _retrieveObject = function(pointerObj) {\n + var module = r(pointerObj.modName);\n + if (pointerObj.objName) {\n + return module[pointerObj.objName];\n + }\n + return module;\n +};\n +\n +/**\n + * An Extension represents some code that can be lazy-loaded when needed.\n + * @constructor\n + */\n +exports.Extension = function(metadata) {\n + this.pluginName = null;\n +\n + for (property in metadata) {\n + if (metadata.hasOwnProperty(property)) {\n + this[property] = metadata[property];\n + }\n + }\n +\n + this._observers = [];\n +};\n +\n +exports.Extension.prototype = {\n + /**\n + * Asynchronously load the actual code represented by this Extension\n + * @param callback Function to call when the load has finished (deprecated)\n + * @param property Extension property to load (default \'pointer\')\n + * @returns A promise to be fulfilled on completion. Preferred over using the\n + * <tt>callback</tt> parameter.\n + */\n + load: function(callback, property, catalog) {\n + catalog = catalog || exports.catalog;\n + var promise = new Promise();\n +\n + var onComplete = function(func) {\n + if (callback) {\n + callback(func);\n + }\n + promise.resolve(func);\n + };\n +\n + var pointerVal = this[property || \'pointer\'];\n + if (util.isFunction(pointerVal)) {\n + onComplete(pointerVal);\n + return promise;\n + }\n +\n + var pointerObj = _splitPointer(this.pluginName, pointerVal);\n +\n + if (!pointerObj) {\n + console.error(\'Extension cannot be loaded because it has no \\\'pointer\\\'\');\n + console.log(this);\n +\n + promise.reject(new Error(\'Extension has no \\\'pointer\\\' to call\'));\n + return promise;\n + }\n +\n + var pluginName = this.pluginName;\n + catalog.loadPlugin(pluginName).then(function() {\n + require.ensure(pointerObj.modName, function() {\n + var func = _retrieveObject(pointerObj);\n + onComplete(func);\n +\n + // TODO: consider caching \'func\' to save looking it up again\n + // Something like: this._setPointer(property, data);\n + });\n + }, function(err) {\n + console.error(\'Failed to load plugin \', pluginName, err);\n + });\n +\n + return promise;\n + },\n +\n + /**\n + * Loads this extension and passes the result to the callback.\n + * Any time this extension changes, the callback is called with the new value.\n + * Note that if this extension goes away, the callback will be called with\n + * undefined.\n + * <p>observingPlugin is required, because if that plugin is torn down,\n + * all of its observing callbacks need to be torn down as well.\n + */\n + observe: function(observingPlugin, callback, property) {\n + this._observers.push({\n + plugin: observingPlugin,\n + callback: callback,\n + property: property\n + });\n + this.load(callback, property);\n + },\n +\n + /**\n + * Returns the name of the plugin that provides this extension.\n + */\n + getPluginName: function() {\n + return this.pluginName;\n + },\n +\n + /**\n + *\n + */\n + _getLoaded: function(property) {\n + var pointerObj = this._getPointer(property);\n + return _retrieveObject(pointerObj);\n + }\n +};\n +\n +/**\n + * An ExtensionPoint is a get of Extensions grouped under the same name\n + * for fast access.\n + * @constructor\n + */\n +exports.ExtensionPoint = function(name, catalog) {\n + this.name = name;\n + this.catalog = catalog;\n +\n + this.pluginName = undefined;\n + this.indexOn = undefined;\n +\n + this.extensions = [];\n + this.handlers = [];\n +};\n +\n +/**\n + * Implementation of ExtensionPoint\n + */\n +exports.ExtensionPoint.prototype = {\n + /**\n + * Retrieves the list of plugins which provide extensions\n + * for this extension point.\n + */\n + getImplementingPlugins: function() {\n + var pluginSet = {};\n + this.extensions.forEach(function(ext) {\n + pluginSet[ext.pluginName] = true;\n + });\n + var matches = Object.keys(pluginSet);\n + matches.sort();\n + return matches;\n + },\n +\n + /**\n + * Get the name of the plugin that defines this extension point.\n + */\n + getDefiningPluginName: function() {\n + return this.pluginName;\n + },\n +\n + /**\n + * If we are keeping an index (an indexOn property is set on the\n + * extension point), you can look up an extension by key.\n + */\n + getByKey: function(key) {\n + var indexOn = this.indexOn;\n +\n + if (!indexOn) {\n + return undefined;\n + }\n +\n + for (var i = 0; i < this.extensions.length; i++) {\n + if (this.extensions[i][indexOn] == key) {\n + return this.extensions[i];\n + }\n + }\n + return undefined;\n + },\n +\n + register: function(extension) {\n + var catalog = this.catalog;\n + this.extensions.push(extension);\n + this.handlers.forEach(function(handler) {\n + if (handler.register) {\n + handler.load(function(register) {\n + if (!register) {\n + console.error(\'missing register function for pluginName=\', extension.pluginName, ", extension=", extension.name);\n + } else {\n + register(extension, catalog);\n + }\n + }, "register", catalog);\n + }\n + });\n + },\n +\n + unregister: function(extension) {\n + var catalog = this.catalog;\n + this.extensions.splice(this.extensions.indexOf(extension), 1);\n + this.handlers.forEach(function(handler) {\n + if (handler.unregister) {\n + handler.load(function(unregister) {\n + if (!unregister) {\n + console.error(\'missing unregister function for pluginName=\', extension.pluginName, ", extension=", extension.name);\n + } else {\n + unregister(extension, catalog);\n + }\n + }, "unregister", catalog);\n + }\n + });\n + },\n +\n + /**\n + * Order the extensions by a plugin order.\n + */\n + orderExtensions: function(pluginOrder) {\n + var orderedExt = [];\n +\n + for (var i = 0; i < pluginOrder.length; i++) {\n + var n = 0;\n + while (n != this.extensions.length) {\n + if (this.extensions[n].pluginName === pluginOrder[i]) {\n + orderedExt.push(this.extensions[n]);\n + this.extensions.splice(n, 1);\n + } else {\n + n ++;\n + }\n + }\n + }\n +\n + this.extensions = orderedExt.concat(this.extensions);\n + }\n +};\n +\n +/**\n + * A Plugin is a set of Extensions that are loaded as a unit\n + * @constructor\n + */\n +exports.Plugin = function(metadata) {\n + // Should be provided in the metadata\n + this.catalog = null;\n + this.name = null;\n + this.provides = [];\n + this.stylesheets = [];\n + this.reloadURL = null;\n + this.reloadPointer = null;\n +\n + for (property in metadata) {\n + if (metadata.hasOwnProperty(property)) {\n + this[property] = metadata[property];\n + }\n + }\n +};\n +\n +/**\n + * Implementation of Plugin\n + */\n +exports.Plugin.prototype = {\n + register: function() {\n + this.provides.forEach(function(extension) {\n + var ep = this.catalog.getExtensionPoint(extension.ep, true);\n + ep.register(extension);\n + }, this);\n + },\n +\n + unregister: function() {\n + this.provides.forEach(function(extension) {\n + var ep = this.catalog.getExtensionPoint(extension.ep, true);\n + ep.unregister(extension);\n + }, this);\n + },\n +\n + _getObservers: function() {\n + var result = {};\n + this.provides.forEach(function(extension) {\n + console.log(\'ep: \', extension.ep);\n + console.log(extension._observers);\n + result[extension.ep] = extension._observers;\n + });\n + return result;\n + },\n +\n + /**\n + * Figure out which plugins depend on a given plugin. This\n + * will allow the reload behavior to unregister/reregister\n + * all of the plugins that depend on the one being reloaded.\n + * If firstLevelOnly is true, only direct dependent plugins are listed.\n + */\n + _findDependents: function(pluginList, dependents, firstLevelOnly) {\n + var pluginName = this.name;\n + var self = this;\n + pluginList.forEach(function(testPluginName) {\n + if (testPluginName == pluginName) {\n + return;\n + }\n + var plugin = self.catalog.plugins[testPluginName];\n + if (plugin && plugin.dependencies) {\n + for (dependName in plugin.dependencies) {\n + if (dependName == pluginName && !dependents[testPluginName]) {\n + dependents[testPluginName] = {\n + keepModule: false\n + };\n + if (!firstLevelOnly) {\n + plugin._findDependents(pluginList, dependents);\n + }\n + }\n + }\n + }\n + });\n + },\n +\n + /**\n + * Removes the plugin from Tiki\'s registries.\n + * As with the new multiple Bespins, this only clears the current sandbox.\n + */\n + _cleanup: function(leaveLoader) {\n + // Remove the css files.\n + this.stylesheets.forEach(function(stylesheet) {\n + var links = document.getElementsByTagName(\'link\');\n + for (var i = 0; i < links.length; i++) {\n + if (links[i].href.indexOf(stylesheet.url) != -1) {\n + links[i].parentNode.removeChild(links[i]);\n + break;\n + }\n + }\n + });\n +\n + // Remove all traces of the plugin.\n + var pluginName = this.name;\n +\n + var nameMatch = new RegExp("^" + pluginName + \'$\');\n + var moduleMatch = new RegExp(\'^::\' + pluginName + \':\');\n + var packageMatch = new RegExp("^::" + pluginName + \'$\');\n +\n + var sandbox = require.sandbox;\n + var loader = require.loader;\n + var source = browser;\n +\n + if (!leaveLoader) {\n + // Clear the loader.\n + _removeFromObject(moduleMatch, loader.factories);\n + _removeFromObject(packageMatch, loader.canonicalIds);\n + _removeFromObject(packageMatch, loader.canonicalPackageIds);\n + _removeFromObject(packageMatch, loader.packageSources);\n + _removeFromObject(packageMatch, loader.packages);\n +\n + // Clear the source.\n + _removeFromObject(nameMatch, source.packageInfoByName);\n + _removeFromObject(moduleMatch, source.factories);\n + _removeFromObject(moduleMatch, source.scriptActions);\n + _removeFromObject(moduleMatch, source.stylesheetActions);\n + _removeFromObject(packageMatch, source.packages);\n + _removeFromObject(packageMatch, source.ensureActions);\n + _removeFromObject(packageMatch, source.packageInfoById);\n + }\n +\n + // Clear the sandbox.\n + _removeFromObject(moduleMatch, sandbox.exports);\n + _removeFromObject(moduleMatch, sandbox.modules);\n + _removeFromObject(moduleMatch, sandbox.usedExports);\n + },\n +\n + /**\n + * reloads the plugin and reinitializes all\n + * dependent plugins\n + */\n + reload: function(callback) {\n + // TODO: Broken. Needs to be updated to the latest Tiki.\n +\n + // All reloadable plugins will have a reloadURL\n + if (!this.reloadURL) {\n + return;\n + }\n +\n + if (this.reloadPointer) {\n + var pointer = _splitPointer(this.name, this.reloadPointer);\n + func = _retrieveObject(pointer);\n + if (func) {\n + func();\n + } else {\n + console.error("Reload function could not be loaded. Aborting reload.");\n + return;\n + }\n + }\n +\n + // find all of the dependents recursively so that\n + // they can all be unregistered\n + var dependents = {};\n +\n + var pluginList = Object.keys(this.catalog.plugins);\n +\n + this._findDependents(pluginList, dependents);\n +\n + var reloadDescription = {\n + pluginName: this.name,\n + dependents: dependents\n + };\n +\n + for (var dependName in dependents) {\n + var plugin = this.catalog.plugins[dependName];\n + if (plugin.preRefresh) {\n + var parts = _splitPointer(dependName, plugin.preRefresh);\n + func = _retrieveObject(parts);\n + if (func) {\n + // the preRefresh call can return an object\n + // that includes attributes:\n + // keepModule (true to keep the module object)\n + // callPointer (pointer to call at the end of reloading)\n + dependents[dependName] = func(reloadDescription);\n + }\n + }\n + }\n +\n + // notify everyone that this plugin is going away\n + this.unregister();\n +\n + for (dependName in dependents) {\n + this.catalog.plugins[dependName].unregister();\n + }\n +\n + this._cleanup(this.name);\n +\n + // clear the sandbox of modules from all of the dependent plugins\n + var fullModList = [];\n + var sandbox = require.sandbox;\n +\n + var modulesKey = Object.keys(sandbox.modules);\n + var i = modulesKey.length;\n + var dependRegexes = [];\n + for (dependName in dependents) {\n + // check to see if the module stated that it shouldn\'t be\n + // refreshed\n + if (!dependents[dependName].keepModule) {\n + dependRegexes.push(new RegExp("^::" + dependName + ":"));\n + }\n + }\n +\n + var nameMatch = new RegExp("^::" + this.name + ":");\n +\n + while (--i >= 0) {\n + var item = modulesKey[i];\n + if (nameMatch.exec(item)) {\n + fullModList.push(item);\n + } else {\n + var j = dependRegexes.length;\n + while (--j >= 0) {\n + if (dependRegexes[j].exec(item)) {\n + fullModList.push(item);\n + break;\n + }\n + }\n + }\n + }\n +\n + // Remove the modules of the dependent plugins from the sandbox.\n + fullModList.forEach(function(item) {\n + delete sandbox.exports[item];\n + delete sandbox.modules[item];\n + delete sandbox.usedExports[item];\n + });\n +\n + // reload the plugin metadata\n + var onLoad = function() {\n + // actually load the plugin, so that it\'s ready\n + // for any dependent plugins\n + this.catalog.loadPlugin(this.name).then(function() {\n + // re-register all of the dependent plugins\n + for (dependName in dependents) {\n + this.catalog.plugins[dependName].register();\n + }\n +\n + for (dependName in dependents) {\n + if (dependents[dependName].callPointer) {\n + var parts = _splitPointer(dependName,\n + dependents[dependName].callPointer);\n + var func = _retrieveObject(parts);\n + if (func) {\n + func(reloadDescription);\n + }\n + }\n + }\n +\n + if (callback) {\n + // at long last, reloading is done.\n + callback();\n + }\n + }.bind(this));\n + }.bind(this);\n +\n + // TODO: There should be more error handling then just logging\n + // to the command line.\n + var onError = function() {\n + console.error(\'Failed to load metadata from \' + this.reloadURL);\n + }.bind(this);\n +\n + this.catalog.loadMetadataFromURL(this.reloadURL).then(onLoad, onError);\n + }\n +};\n +\n +var _setPath = function(root, path, value) {\n + var segments = path.split(\'.\');\n + var current = root;\n + var top = segments.length - 1;\n + if (top > 0) {\n + for (var i = 0; i < top; i++) {\n + current = current[segments[i]];\n + }\n + }\n + current[top] = value;\n +};\n +\n +exports.Catalog = function() {\n + this.points = {};\n + this.plugins = {};\n + this.metadata = {};\n +\n + this.USER_DEACTIVATED = USER_DEACTIVATED;\n + this.DEPENDS_DEACTIVATED = DEPENDS_DEACTIVATED;\n +\n + // Stores the deactivated plugins. Plugins deactivated by the user have the\n + // value USER_DEACTIVATED. If a plugin is deactivated because a required\n + // plugin is deactivated, then the value is a DEPENDS_DEACTIVATED.\n + this.deactivatedPlugins = {};\n + this._extensionsOrdering = [];\n + this.instances = {};\n + this.instancesLoadPromises = {};\n + this._objectDescriptors = {};\n +\n + // Stores the child catalogs.\n + this.children = [];\n +\n + // set up the "extensionpoint" extension point.\n + // it indexes on name.\n + var ep = this.getExtensionPoint("extensionpoint", true);\n + ep.indexOn = "name";\n + this.registerMetadata(builtins.metadata);\n +};\n +\n +exports.Catalog.prototype = {\n +\n + /**\n + * Returns true if the extension is shared.\n + */\n + shareExtension: function(ext) {\n + return this.plugins[ext.pluginName].share;\n + },\n +\n + /**\n + * Returns true, if the plugin is loaded (checks if there is a module in the\n + * current sandbox).\n + */\n + isPluginLoaded: function(pluginName) {\n + var usedExports = Object.keys(require.sandbox.usedExports);\n +\n + return usedExports.some(function(item) {\n + return item.indexOf(\'::\' + pluginName + \':\') == 0;\n + });\n + },\n +\n + /**\n + * Registers information about an instance that will be tracked\n + * by the catalog. The first parameter is the name used for looking up\n + * the object. The descriptor should contain:\n + * - factory (optional): name of the factory extension used to create the\n + * object. defaults to the same value as the name\n + * property.\n + * - arguments (optional): array that is passed in if the factory is a\n + * function.\n + * - objects (optional): object that describes other objects that are\n + * required when constructing this one (see below)\n + *\n + * The objects object defines objects that must be created before this\n + * one and how they should be passed in. The key defines how they\n + * are passed in, and the value is the name of the object to pass in.\n + * You define how they are passed in relative to the arguments\n + * array, using a very simple interface of dot separated keys.\n + * For example, if you have an arguments array of [null, {foo: null}, "bar"]\n + * you can have an object array like this:\n + * {\n + * "0": "myCoolObject",\n + * "1.foo": "someOtherObject"\n + * }\n + *\n + * which will result in arguments like this:\n + * [myCoolObject, {foo: someOtherObject}, "bar"]\n + * where myCoolObject and someOtherObject are the actual objects\n + * created elsewhere.\n + *\n + * If the plugin containing the factory is reloaded, the object will\n + * be recreated. The object will also be recreated if objects passed in\n + * are reloaded.\n + *\n + * This method returns nothing and does not actually create the objects.\n + * The objects are created via the createObject method and retrieved\n + * via the getObject method.\n + */\n + registerObject: function(name, descriptor) {\n + this._objectDescriptors[name] = descriptor;\n + },\n +\n + /**\n + * Stores an object directly in the instance cache. This should\n + * not generally be used because reloading cannot work with\n + * these objects.\n + */\n + _setObject: function(name, obj) {\n + this.instances[name] = obj;\n + },\n +\n + /**\n + * Creates an object with a previously registered descriptor.\n + *\n + * Returns a promise that will be resolved (with the created object)\n + * once the object has been made. The promise will be resolved\n + * immediately if the instance is already there.\n + *\n + * throws an exception if the object is not registered or if\n + * the factory cannot be found.\n + */\n + createObject: function(name) {\n + // console.log("Creating", name);\n +\n + // If there is already a loading promise for this instance, then\n + // return this one.\n + if (this.instancesLoadPromises[name] !== undefined) {\n + // console.log("Already have one (it\'s very nice)");\n + return this.instancesLoadPromises[name];\n + }\n +\n + var descriptor = this._objectDescriptors[name];\n + if (descriptor === undefined) {\n + throw new Error(\'Tried to create object "\' + name +\n + \'" but that object is not registered.\');\n + }\n +\n + var factoryName = descriptor.factory || name;\n + var ext = this.getExtensionByKey("factory", factoryName);\n + if (ext === undefined) {\n + throw new Error(\'When creating object "\' + name +\n + \'", there is no factory called "\' + factoryName +\n + \'" available."\');\n + }\n +\n + // If this is a child catalog and the extension is shared, then\n + // as the master/parent catalog to create the object.\n + if (this.parent && this.shareExtension(ext)) {\n + return this.instancesLoadPromises[name] = this.parent.createObject(name);\n + }\n +\n + // Otherwise create a new loading promise (which is returned at the\n + // end of the function) and create the instance.\n + var pr = this.instancesLoadPromises[name] = new Promise();\n +\n + var factoryArguments = descriptor.arguments || [];\n + var argumentPromises = [];\n + if (descriptor.objects) {\n + var objects = descriptor.objects;\n + for (var key in objects) {\n + var objectName = objects[key];\n + var ropr = this.createObject(objectName);\n + argumentPromises.push(ropr);\n + // key is changing, so we need to hang onto the\n + // current value\n + ropr.location = key;\n + ropr.then(function(obj) {\n + _setPath(factoryArguments, ropr.location, obj);\n + });\n + }\n + }\n +\n + group(argumentPromises).then(function() {\n + ext.load().then(function(factory) {\n + // console.log("Got factory for ", name);\n + var action = ext.action;\n + var obj;\n +\n + if (action === "call") {\n + obj = factory.apply(factory, factoryArguments);\n + } else if (action === "new") {\n + if (factoryArguments.length > 1) {\n + pr.reject(new Error(\'For object \' + name + \', create a simple factory function and change the action to call because JS cannot handle this case.\'));\n + return;\n + }\n + obj = new factory(factoryArguments[0]);\n + } else if (action === "value") {\n + obj = factory;\n + } else {\n + pr.reject(new Error("Create action must be call|new|value. " +\n + "Found" + action));\n + return;\n + }\n +\n + this.instances[name] = obj;\n + pr.resolve(obj);\n + }.bind(this));\n + }.bind(this));\n +\n + return pr;\n + },\n +\n + /**\n + * Retrieve a registered object. Returns undefined\n + * if the instance has not been created.\n + */\n + getObject: function(name) {\n + return this.instances[name] || (this.parent ? this.parent.getObject(name) : undefined);\n + },\n +\n + /** Retrieve an extension point object by name, optionally creating it if it\n + * does not exist.\n + */\n + getExtensionPoint: function(name, create) {\n + if (create && this.points[name] === undefined) {\n + this.points[name] = new exports.ExtensionPoint(name, this);\n + }\n + return this.points[name];\n + },\n +\n + /**\n + * Retrieve the list of extensions for the named extension point.\n + * If none are defined, this will return an empty array.\n + */\n + getExtensions: function(name) {\n + var ep = this.getExtensionPoint(name);\n + if (ep === undefined) {\n + return [];\n + }\n + return ep.extensions;\n + },\n +\n + /**\n + * Sets the order of the plugin\'s extensions. Note that this orders *only*\n + * Extensions and nothing else (load order of CSS files e.g.)\n + */\n + orderExtensions: function(pluginOrder) {\n + pluginOrder = pluginOrder || this._extensionsOrdering;\n +\n + for (name in this.points) {\n + this.points[name].orderExtensions(pluginOrder);\n + }\n + this._extensionsOrdering = pluginOrder;\n + },\n +\n + /**\n + * Returns the current plugin exentions ordering.\n + */\n + getExtensionsOrdering: function() {\n + return this._extensionsOrdering;\n + },\n +\n + /**\n + * Look up an extension in an indexed extension point by the given key. If\n + * the extension point or the key are unknown, undefined will be returned.\n + */\n + getExtensionByKey: function(name, key) {\n + var ep = this.getExtensionPoint(name);\n + if (ep === undefined) {\n + return undefined;\n + }\n +\n + return ep.getByKey(key);\n + },\n +\n + // Topological sort algorithm from Wikipedia, credited to Tarjan 1976.\n + // http://en.wikipedia.org/wiki/Topological_sort\n + _toposort: function(metadata) {\n + var sorted = [];\n + var visited = {};\n + var visit = function(key) {\n + if (key in visited || !(key in metadata)) {\n + return;\n + }\n +\n + visited[key] = true;\n + var depends = metadata[key].dependencies;\n + if (!util.none(depends)) {\n + for (var dependName in depends) {\n + visit(dependName);\n + }\n + }\n +\n + sorted.push(key);\n + };\n +\n + for (var key in metadata) {\n + visit(key);\n + }\n +\n + return sorted;\n + },\n +\n + /**\n + * Register new metadata. If the current catalog is not the master catalog,\n + * then the master catalog registerMetadata function is called. The master\n + * catalog then makes some basic operations on the metadata and calls the\n + * _registerMetadata function on all the child catalogs and for itself as\n + * well.\n + */\n + registerMetadata: function(metadata) {\n + // If we are the master catalog, then store the metadata.\n + if (this.parent) {\n + this.parent.registerMetadata(metadata);\n + } else {\n + for (var pluginName in metadata) {\n + var md = metadata[pluginName];\n + if (md.errors) {\n + console.error("Plugin ", pluginName, " has errors:");\n + md.errors.forEach(function(error) {\n + console.error(error);\n + });\n + delete metadata[pluginName];\n + continue;\n + }\n +\n + if (md.dependencies) {\n + md.depends = Object.keys(md.dependencies);\n + }\n +\n + md.name = pluginName;\n + md.version = null;\n +\n + var packageId = browser.canonicalPackageId(pluginName);\n + if (packageId === null) {\n + browser.register(\'::\' + pluginName, md);\n + continue;\n + }\n + }\n +\n + // Save the new metadata.\n + util.mixin(this.metadata, util.clone(metadata, true));\n +\n + // Tell every child about the new metadata.\n + this.children.forEach(function(child) {\n + child._registerMetadata(util.clone(metadata, true));\n + });\n + // Register the metadata in the master catalog as well.\n + this._registerMetadata(util.clone(metadata, true));\n + }\n + },\n +\n + /**\n + * Registers plugin metadata. See comments inside of the function.\n + */\n + _registerMetadata: function(metadata) {\n + var pluginName, plugin;\n + var plugins = this.plugins;\n +\n + this._toposort(metadata).forEach(function(name) {\n + // If the plugin is already registered.\n + if (this.plugins[name]) {\n + // Check if the plugin is loaded.\n + if (this.isPluginLoaded(name)) {\n + // If the plugin is loaded, then the metadata/plugin/extensions\n + // have to stay the way they are at the moment.\n + return;\n + } else {\n + // If the plugin is not loaded and the plugin is already\n + // registerd, then remove the plugin.\n + //\n + // Reason: As new metadata arrives, this might also mean,\n + // that the factory in the tiki.loader has changed. If the\n + // old plugins/extensions would stay, they might not fit to\n + // the new factory. As such, the plugin has to be updated,\n + // which is achieved by unregister the plugin and then add it\n + // later in this function again.\n + var plugin = this.plugins[name];\n + plugin.unregister();\n + }\n + }\n +\n + var md = metadata[name];\n + var activated = !(this.deactivatedPlugins[name]);\n +\n + // Check if all plugins this one depends on are activated as well.\n + if (activated && md.depends && md.depends.length != 0) {\n + var works = md.depends.some(function(name) {\n + return !(this.deactivatedPlugins[name]);\n + }, this);\n + // At least one depending plugin is not activated -> this plugin\n + // can\'t be activated. Mark this plugin as deactivated.\n + if (!works) {\n + this.deactivatedPlugins[name] = DEPENDS_DEACTIVATED;\n + activated = false;\n + }\n + }\n +\n + md.catalog = this;\n + md.name = name;\n + plugin = new exports.Plugin(md);\n + plugins[name] = plugin;\n +\n + // Skip if the plugin is not activated.\n + if (md.provides) {\n + var provides = md.provides;\n + for (var i = 0; i < provides.length; i++) {\n + var extension = new exports.Extension(provides[i]);\n + extension.pluginName = name;\n + provides[i] = extension;\n +\n + var epname = extension.ep;\n + // This special treatment is required for the extension point\n + // definition. TODO: Refactor the code so that this is no\n + // longer necessary.\n + if (epname == "extensionpoint" && extension.name == \'extensionpoint\') {\n + exports.registerExtensionPoint(extension, this, false);\n + } else {\n + // Only register the extension if the plugin is activated.\n + // TODO: This should handle extension points and\n + if (activated) {\n + var ep = this.getExtensionPoint(extension.ep, true);\n + ep.register(extension);\n +\n + // Even if the plugin is deactivated, the ep need to\n + // be registered. Call the registerExtensionPoint\n + // function manually, but pass as third argument \'true\'\n + // which indicates, that the plugin is deactivated and\n + // prevents the handlers on the ep to get registered.\n + } else if (epname == "extensionpoint") {\n + exports.registerExtensionPoint(extension, this, true);\n + }\n + }\n + }\n + } else {\n + md.provides = [];\n + }\n + }, this);\n +\n + for (pluginName in metadata) {\n + this._checkLoops(pluginName, plugins, []);\n + }\n +\n + this.orderExtensions();\n + },\n +\n + /**\n + * Loads the named plugin, returning a promise called\n + * when the plugin is loaded. This function is a convenience\n + * for unusual situations and debugging only. Generally,\n + * you should load plugins by calling load() on an Extension\n + * object.\n + */\n + loadPlugin: function(pluginName) {\n + var pr = new Promise();\n + var plugin = this.plugins[pluginName];\n + if (plugin.objects) {\n + var objectPromises = [];\n + plugin.objects.forEach(function(objectName) {\n + objectPromises.push(this.createObject(objectName));\n + }.bind(this));\n + group(objectPromises).then(function() {\n + require.ensurePackage(pluginName, function() {\n + pr.resolve();\n + });\n + });\n + } else {\n + require.ensurePackage(pluginName, function(err) {\n + if (err) {\n + pr.reject(err);\n + } else {\n + pr.resolve();\n + }\n + });\n + }\n + return pr;\n + },\n +\n + /**\n + * Retrieve metadata from the server. Returns a promise that is\n + * resolved when the metadata has been loaded.\n + */\n + loadMetadataFromURL: function(url, type) {\n + var pr = new Promise();\n + proxy.xhr(\'GET\', url, true).then(function(response) {\n + this.registerMetadata(JSON.parse(response));\n + pr.resolve();\n + }.bind(this), function(err) {\n + pr.reject(err);\n + });\n +\n + return pr;\n + },\n +\n + /**\n + * Dactivates a plugin. If no plugin was deactivated, then a string is\n + * returned which contains the reason why deactivating was not possible.\n + * Otherwise the plugin is deactivated as well as all plugins that depend on\n + * this plugin and a array is returned holding all depending plugins that were\n + * deactivated.\n + *\n + * @param pluginName string Name of the plugin to deactivate\n + * @param recursion boolean True if the funciton is called recursive.\n + */\n + deactivatePlugin: function(pluginName, recursion) {\n + var plugin = this.plugins[pluginName];\n + if (!plugin) {\n + // Deactivate the plugin only if the user called the function.\n + if (!recursion) {\n + this.deactivatedPlugins[pluginName] = USER_DEACTIVATED;\n + }\n + return \'There is no plugin named "\' + pluginName + \'" in this catalog.\';\n + }\n +\n + if (this.deactivatedPlugins[pluginName]) {\n + // If the plugin is already deactivated but the user explicip wants\n + // to deactivate the plugin, then store true as deactivation reason.\n + if (!recursion) {\n + this.deactivatedPlugins[pluginName] = USER_DEACTIVATED;\n + }\n + return \'The plugin "\' + pluginName + \'" is already deactivated\';\n + }\n +\n + // If the function is called within a recursion, then mark the plugin\n + // as DEPENDS_DEACTIVATED otherwise as USER_DEACTIVATED.\n + this.deactivatedPlugins[pluginName] = (recursion ? DEPENDS_DEACTIVATED\n + : USER_DEACTIVATED);\n +\n + // Get all plugins that depend on this plugin.\n + var dependents = {};\n + var deactivated = [];\n + plugin._findDependents(Object.keys(this.plugins), dependents, true);\n +\n + // Deactivate all dependent plugins.\n + Object.keys(dependents).forEach(function(plugin) {\n + var ret = this.deactivatePlugin(plugin, true);\n + if (Array.isArray(ret)) {\n + deactivated = deactivated.concat(ret);\n + }\n + }, this);\n +\n + // Deactivate this plugin.\n + plugin.unregister();\n +\n + if (recursion) {\n + deactivated.push(pluginName);\n + }\n +\n + return deactivated;\n + },\n +\n + /**\n + * Activates a plugin. If the plugin can\'t be activated a string is returned\n + * explaining why. Otherwise the plugin is activated, all plugins that depend\n + * on this plugin are tried to activated and an array with all the activated\n + * depending plugins is returned.\n + * Note: Depending plugins are not activated if they user called\n + * deactivatePlugin on them to deactivate them explicit.\n + *\n + * @param pluginName string Name of the plugin to activate.\n + * @param recursion boolean True if the funciton is called recursive.\n + */\n + activatePlugin: function(pluginName, recursion) {\n + var plugin = this.plugins[pluginName];\n + if (!plugin) {\n + return \'There is no plugin named "\' + pluginName + \'" in this catalog.\';\n + }\n +\n + if (!this.deactivatedPlugins[pluginName]) {\n + return \'The plugin "\' + pluginName + \'" is already activated\';\n + }\n +\n + // Don\'t activate this plugin if the user explicip deactivated this one\n + // and the plugin activation call is called beacuse another plugin\n + // this one depended on was activated.\n + if (recursion && this.deactivatedPlugins[pluginName] === USER_DEACTIVATED) {\n + return;\n + }\n +\n + // Check if all dependent plugins are activated.\n + if (plugin.depends && plugin.depends.length != 0) {\n + var works = plugin.depends.some(function(plugin) {\n + return !this.deactivatedPlugins[plugin];\n + }, this);\n +\n + if (!works) {\n + // The user activated the plugin but some of the dependent\n + // plugins are still deactivated. Change the deactivation reason\n + // to DEPENDS_DEACTIVATED.\n + this.deactivatedPlugins[pluginName] = DEPENDS_DEACTIVATED;\n + return \'Can not activate plugin "\' + pluginName +\n + \'" as some of its dependent plugins are not activated\';\n + }\n + }\n +\n + // Activate this plugin.\n + plugin.register();\n + this.orderExtensions();\n + delete this.deactivatedPlugins[pluginName];\n +\n + // Try to activate all the plugins that depend on this one.\n + var activated = [];\n + var dependents = {};\n + plugin._findDependents(Object.keys(this.plugins), dependents, true);\n + Object.keys(dependents).forEach(function(pluginName) {\n + var ret = this.activatePlugin(pluginName, true);\n + if (Array.isArray(ret)) {\n + activated = activated.concat(ret);\n + }\n + }, this);\n +\n + if (recursion) {\n + activated.push(pluginName);\n + }\n +\n + return activated;\n + },\n +\n + /**\n + * Removes a plugin, unregistering it and cleaning up.\n + */\n + removePlugin: function(pluginName) {\n + var plugin = this.plugins[pluginName];\n + if (plugin == undefined) {\n + throw new Error("Attempted to remove plugin " + pluginName\n + + " which does not exist.");\n + }\n +\n + plugin.unregister();\n + plugin._cleanup(true /* leaveLoader */);\n + delete this.metadata[pluginName];\n + delete this.plugins[pluginName];\n + },\n +\n + /**\n + * for the given plugin, get the first part of the URL required to\n + * get at that plugin\'s resources (images, etc.).\n + */\n + getResourceURL: function(pluginName) {\n + var link = document.getElementById("bespin_base");\n + var base = "";\n + if (link) {\n + base += link.href;\n + if (!util.endsWith(base, "/")) {\n + base += "/";\n + }\n + }\n + var plugin = this.plugins[pluginName];\n + if (plugin == undefined) {\n + return undefined;\n + }\n + return base + plugin.resourceURL;\n + },\n +\n + /**\n + * Check the dependency graph to ensure we don\'t have cycles.\n + */\n + _checkLoops: function(pluginName, data, trail) {\n + var circular = false;\n + trail.forEach(function(node) {\n + if (pluginName === node) {\n + console.error("Circular dependency", pluginName, trail);\n + circular = true;\n + }\n + });\n + if (circular) {\n + return true;\n + }\n + trail.push(pluginName);\n + if (!data[pluginName]) {\n + console.error("Missing metadata for ", pluginName);\n + } else {\n + if (data[pluginName].dependencies) {\n + for (var dependency in data[pluginName].dependencies) {\n + var trailClone = trail.slice();\n + var errors = this._checkLoops(dependency, data, trailClone);\n + if (errors) {\n + console.error("Errors found when looking at ", pluginName);\n + return true;\n + }\n + }\n + }\n + }\n + return false;\n + },\n +\n + /**\n + * Retrieve an array of the plugin objects.\n + * The opts object can include the following options:\n + * onlyType (string): only include plugins of this type\n + * sortBy (array): list of keys to sort by (the primary sort is first).\n + * default is sorted alphabetically by name.\n + */\n + getPlugins: function(opts) {\n + var result = [];\n + var onlyType = opts.onlyType;\n +\n + for (var key in this.plugins) {\n + var plugin = this.plugins[key];\n +\n + // apply the filter\n + if ((onlyType && plugin.type && plugin.type != onlyType)\n + || plugin.name == "bespin") {\n + continue;\n + }\n +\n + result.push(plugin);\n + }\n +\n + var sortBy = opts.sortBy;\n + if (!sortBy) {\n + sortBy = ["name"];\n + }\n +\n + var sortfunc = function(a, b) {\n + for (var i = 0; i < sortBy.length; i++) {\n + key = sortBy[i];\n + if (a[key] < b[key]) {\n + return -1;\n + } else if (b[key] < a[key]) {\n + return 1;\n + }\n + }\n + return 0;\n + };\n +\n + result.sort(sortfunc);\n + return result;\n + },\n +\n + /**\n + * Returns a promise to retrieve the object at the given property path,\n + * loading the plugin if necessary.\n + */\n + loadObjectForPropertyPath: function(path, context) {\n + var promise = new Promise();\n + var parts = /^([^:]+):([^#]+)#(.*)$/.exec(path);\n + if (parts === null) {\n + throw new Error("loadObjectForPropertyPath: malformed path: \'" +\n + path + "\'");\n + }\n +\n + var pluginName = parts[1];\n + if (pluginName === "") {\n + if (util.none(context)) {\n + throw new Error("loadObjectForPropertyPath: no plugin name " +\n + "supplied and no context is present");\n + }\n +\n + pluginName = context;\n + }\n +\n + require.ensurePackage(pluginName, function() {\n + promise.resolve(this.objectForPropertyPath(path));\n + }.bind(this));\n +\n + return promise;\n + },\n +\n + /**\n + * Finds the object for the passed path or array of path components. This is\n + * the standard method used in SproutCore to traverse object paths.\n + * @param path {String} the path\n + * @param root {Object} optional root object. window is used otherwise\n + * @param stopAt {Integer} optional point to stop searching the path.\n + * @returns {Object} the found object or undefined.\n + */\n + objectForPropertyPath: function(path, root, stopAt) {\n + stopAt = (stopAt == undefined) ? path.length : stopAt;\n + if (!root) {\n + root = window;\n + }\n +\n + var hashed = path.split("#");\n + if (hashed.length !== 1) {\n + var module = require(hashed[0]);\n + if (module === undefined) {\n + return undefined;\n + }\n +\n + path = hashed[1];\n + root = module;\n + stopAt = stopAt - hashed[0].length;\n + }\n +\n + var loc = 0;\n + while (root && loc < stopAt) {\n + var nextDotAt = path.indexOf(\'.\', loc);\n + if (nextDotAt < 0 || nextDotAt > stopAt) {\n + nextDotAt = stopAt;\n + }\n + var key = path.slice(loc, nextDotAt);\n + root = root[key];\n + loc = nextDotAt + 1;\n + }\n +\n + if (loc < stopAt) {\n + root = undefined; // hit a dead end. :(\n + }\n +\n + return root;\n + },\n +\n + /**\n + * Publish <tt>value</tt> to all plugins that match both <tt>ep</tt> and\n + * <tt>key</tt>.\n + * @param source {object} The source calling the publish function.\n + * @param epName {string} An extension point (indexed by the catalog) to which\n + * we publish the information.\n + * @param key {string} A key to which we publish (linearly searched, allowing\n + * for regex matching).\n + * @param value {object} The data to be passed to the subscribing function.\n + */\n + publish: function(source, epName, key, value) {\n + var ep = this.getExtensionPoint(epName);\n +\n + if (this.shareExtension(ep)) {\n + if (this.parent) {\n + this.parent.publish(source, epName, key, value);\n + } else {\n + this.children.forEach(function(child) {\n + child._publish(source, epName, key, value);\n + });\n + this._publish(source, epName, key, value);\n + }\n + } else {\n + this._publish(source, epName, key, value);\n + }\n + },\n +\n + _publish: function(source, epName, key, value) {\n + var subscriptions = this.getExtensions(epName);\n + subscriptions.forEach(function(sub) {\n + // compile regexes only once\n + if (sub.match && !sub.regexp) {\n + sub.regexp = new RegExp(sub.match);\n + }\n + if (sub.regexp && sub.regexp.test(key)\n + || sub.key === key\n + || (util.none(sub.key) && util.none(key))) {\n + sub.load().then(function(handler) {\n + handler(source, key, value);\n + });\n + }\n + });\n + },\n +\n + /**\n + * The subscribe side of #publish for use when the object which will\n + * publishes is created dynamically.\n + * @param ep The extension point name to subscribe to\n + * @param metadata An object containing:\n + * <ul>\n + * <li>pointer: A function which should be called on matching publish().\n + * This can also be specified as a pointer string, however if you can do\n + * that, you should be placing the metadata in package.json.\n + * <li>key: A string that exactly matches the key passed to the publish()\n + * function. For smarter matching, you can use \'match\' instead...\n + * <li>match: A regexp to be used in place of key\n + * </ul>\n + */\n + registerExtension: function(ep, metadata) {\n + var extension = new exports.Extension(metadata);\n + extension.pluginName = \'__dynamic\';\n + this.getExtensionPoint(ep).register(extension);\n + }\n +};\n +\n +/**\n + * Register handler for extension points.\n + * The argument `deactivated` is set to true or false when this method is called\n + * by the _registerMetadata function.\n + */\n +exports.registerExtensionPoint = function(extension, catalog, deactivated) {\n + var ep = catalog.getExtensionPoint(extension.name, true);\n + ep.description = extension.description;\n + ep.pluginName = extension.pluginName;\n + ep.params = extension.params;\n + if (extension.indexOn) {\n + ep.indexOn = extension.indexOn;\n + }\n +\n + if (!deactivated && (extension.register || extension.unregister)) {\n + exports.registerExtensionHandler(extension, catalog);\n + }\n +};\n +\n +/**\n + * Register handler for extension handler.\n + */\n +exports.registerExtensionHandler = function(extension, catalog) {\n + // Don\'t add the extension handler if there is a master/partent catalog\n + // and this plugin is shared. The extension handlers are only added\n + // inside of the master catalog.\n + if (catalog.parent && catalog.shareExtension(extension)) {\n + return;\n + }\n +\n + var ep = catalog.getExtensionPoint(extension.name, true);\n + ep.handlers.push(extension);\n + if (extension.register) {\n + // Store the current extensions to this extension point. We can\'t\n + // use the ep.extensions array within the load-callback-function, as\n + // the array at that point in time also contains extensions that got\n + // registered by calling the handler.register function directly.\n + // As such, using the ep.extensions in the load-callback-function\n + // would result in calling the handler\'s register function on a few\n + // extensions twice.\n + var extensions = util.clone(ep.extensions);\n +\n + extension.load(function(register) {\n + if (!register) {\n + throw extension.name + " is not ready";\n + }\n + extensions.forEach(function(ext) {\n + // console.log(\'call register on:\', ext)\n + register(ext, catalog);\n + });\n + }, "register", catalog);\n + }\n +};\n +\n +/**\n + * Unregister handler for extension point.\n + */\n +exports.unregisterExtensionPoint = function(extension, catalog) {\n + // Note: When an extensionPoint is unregistered, the extension point itself\n + // stays but the handler goes away.\n + // DISCUSS: Is this alright? The other option is to remove the ep completly.\n + // The downside of this is, that when the ep arrives later again, it has\n + // to look for extension handlers bound to this ep and add them all again.\n + if (extension.register || extension.unregister) {\n + exports.unregisterExtensionHandler(extension);\n + }\n +};\n +\n +/**\n + * Unregister handler for extension handler.\n + */\n +exports.unregisterExtensionHandler = function(extension, catalog) {\n + // Don\'t remove the extension handler if there is a master/partent catalog\n + // and this plugin is shared. The extension handlers are only added\n + // inside of the master catalog.\n + if (catalog.parent && catalog.shareExtension(extension)) {\n + return;\n + }\n +\n + var ep = catalog.getExtensionPoint(extension.name, true);\n + if (ep.handlers.indexOf(extension) == -1) {\n + return;\n + }\n + ep.handlers.splice(ep.handlers.indexOf(extension), 1);\n + if (extension.unregister) {\n + // Store the current extensions to this extension point. We can\'t\n + // use the ep.extensions array within the load-callback-function, as\n + // the array at that point in time also contains extensions that got\n + // registered by calling the handler.register function directly.\n + // As such, using the ep.extensions in the load-callback-function\n + // would result in calling the handler\'s register function on a few\n + // extensions twice.\n + var extensions = util.clone(ep.extensions);\n +\n + extension.load(function(unregister) {\n + if (!unregister) {\n + throw extension.name + " is not ready";\n + }\n + extensions.forEach(function(ext) {\n + // console.log(\'call register on:\', ext)\n + unregister(ext);\n + });\n + }, "unregister");\n + }\n +};\n +\n +exports.catalog = new exports.Catalog();\n +\n +var _removeFromList = function(regex, array, matchFunc) {\n + var i = 0;\n + while (i < array.length) {\n + if (regex.exec(array[i])) {\n + var item = array.splice(i, 1);\n + if (matchFunc) {\n + matchFunc(item);\n + }\n + continue;\n + }\n + i++;\n + }\n +};\n +\n +var _removeFromObject = function(regex, obj) {\n + var keys = Object.keys(obj);\n + var i = keys.length;\n + while (--i > 0) {\n + if (regex.exec(keys[i])) {\n + delete obj[keys[i]];\n + }\n + }\n +};\n +\n +exports.getUserPlugins = function() {\n + return exports.catalog.getPlugins({ onlyType: \'user\' });\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:sandbox",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var tiki = require(\'tiki\');\n +var util = require(\'bespin:util/util\');\n +var catalog = require(\'bespin:plugins\').catalog;\n +\n +/**\n + * A sandbox can only be used from inside of the `master` catalog.\n + */\n +if (catalog.parent) {\n + throw new Error(\'The sandbox module can\\\'t be used inside of a slave catalog!\');\n +}\n +\n +/**\n + * A special Bespin subclass of the tiki sandbox class. When the sandbox is\n + * created, the catalog for the new sandbox is setup based on the catalog\n + * data that is already in the so called `master` catalog.\n + */\n +var Sandbox = function() {\n + // Call the default constructor. This creates a new tiki sandbox.\n + tiki.Sandbox.call(this, bespin.tiki.require.loader, {}, []);\n +\n + // Register the plugins from the main catalog in the sandbox catalog.\n + var sandboxCatalog = this.require(\'bespin:plugins\').catalog;\n +\n + // Set the parent catalog for the sandbox catalog. This makes the sandbox\n + // be a slave catalog of the master catalog.\n + sandboxCatalog.parent = catalog;\n + catalog.children.push(sandboxCatalog);\n +\n + // Copy over a few things from the master catalog.\n + sandboxCatalog.deactivatePlugin = util.clone(catalog.deactivatePlugin);\n + sandboxCatalog._extensionsOrdering = util.clone(catalog._extensionsOrdering);\n +\n + // Register the metadata from the master catalog.\n + sandboxCatalog._registerMetadata(util.clone(catalog.metadata, true));\n +};\n +\n +Sandbox.prototype = new tiki.Sandbox();\n +\n +/**\n + * Overrides the standard tiki.Sandbox.require function. If the requested\n + * module/plugin is shared between the sandboxes, then the require function\n + * on the `master` sandbox is called. Otherwise it calls the overridden require\n + * function.\n + */\n +Sandbox.prototype.require = function(moduleId, curModuleId, workingPackage) {\n + // assume canonical() will normalize params\n + var canonicalId = this.loader.canonical(moduleId, curModuleId, workingPackage);\n + // Get the plugin name.\n + var pluginName = canonicalId.substring(2).split(\':\')[0];\n +\n + // Check if this module should be shared.\n + if (catalog.plugins[pluginName].share) {\n + // The module is shared, so require it from the main sandbox.\n + return bespin.tiki.sandbox.require(moduleId, curModuleId, workingPackage);\n + } else {\n + // This module is not shared, so use the normal require function.\n + return tiki.Sandbox.prototype.require.call(this, moduleId,\n + curModuleId, workingPackage);\n + }\n +}\n +\n +// Expose the sandbox.\n +exports.Sandbox = Sandbox;\n +\n +});\n +\n +bespin.tiki.module("bespin:promise",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var console = require(\'bespin:console\').console;\n +var Trace = require(\'bespin:util/stacktrace\').Trace;\n +\n +/**\n + * A promise can be in one of 2 states.\n + * The ERROR and SUCCESS states are terminal, the PENDING state is the only\n + * start state.\n + */\n +var ERROR = -1;\n +var PENDING = 0;\n +var SUCCESS = 1;\n +\n +/**\n + * We give promises and ID so we can track which are outstanding\n + */\n +var _nextId = 0;\n +\n +/**\n + * Debugging help if 2 things try to complete the same promise.\n + * This can be slow (especially on chrome due to the stack trace unwinding) so\n + * we should leave this turned off in normal use.\n + */\n +var _traceCompletion = false;\n +\n +/**\n + * Outstanding promises. Handy list for debugging only.\n + */\n +exports._outstanding = [];\n +\n +/**\n + * Recently resolved promises. Also for debugging only.\n + */\n +exports._recent = [];\n +\n +/**\n + * Create an unfulfilled promise\n + */\n +exports.Promise = function () {\n + this._status = PENDING;\n + this._value = undefined;\n + this._onSuccessHandlers = [];\n + this._onErrorHandlers = [];\n +\n + // Debugging help\n + this._id = _nextId++;\n + //this._createTrace = new Trace(new Error());\n + exports._outstanding[this._id] = this;\n +};\n +\n +/**\n + * Yeay for RTTI.\n + */\n +exports.Promise.prototype.isPromise = true;\n +\n +/**\n + * Have we either been resolve()ed or reject()ed?\n + */\n +exports.Promise.prototype.isComplete = function() {\n + return this._status != PENDING;\n +};\n +\n +/**\n + * Have we resolve()ed?\n + */\n +exports.Promise.prototype.isResolved = function() {\n + return this._status == SUCCESS;\n +};\n +\n +/**\n + * Have we reject()ed?\n + */\n +exports.Promise.prototype.isRejected = function() {\n + return this._status == ERROR;\n +};\n +\n +/**\n + * Take the specified action of fulfillment of a promise, and (optionally)\n + * a different action on promise rejection.\n + */\n +exports.Promise.prototype.then = function(onSuccess, onError) {\n + if (typeof onSuccess === \'function\') {\n + if (this._status === SUCCESS) {\n + onSuccess.call(null, this._value);\n + } else if (this._status === PENDING) {\n + this._onSuccessHandlers.push(onSuccess);\n + }\n + }\n +\n + if (typeof onError === \'function\') {\n + if (this._status === ERROR) {\n + onError.call(null, this._value);\n + } else if (this._status === PENDING) {\n + this._onErrorHandlers.push(onError);\n + }\n + }\n +\n + return this;\n +};\n +\n +/**\n + * Like then() except that rather than returning <tt>this</tt> we return\n + * a promise which\n + */\n +exports.Promise.prototype.chainPromise = function(onSuccess) {\n + var chain = new exports.Promise();\n + chain._chainedFrom = this;\n + this.then(function(data) {\n + try {\n + chain.resolve(onSuccess(data));\n + } catch (ex) {\n + chain.reject(ex);\n + }\n + }, function(ex) {\n + chain.reject(ex);\n + });\n + return chain;\n +};\n +\n +/**\n + * Supply the fulfillment of a promise\n + */\n +exports.Promise.prototype.resolve = function(data) {\n + return this._complete(this._onSuccessHandlers, SUCCESS, data, \'resolve\');\n +};\n +\n +/**\n + * Renege on a promise\n + */\n +exports.Promise.prototype.reject = function(data) {\n + return this._complete(this._onErrorHandlers, ERROR, data, \'reject\');\n +};\n +\n +/**\n + * Internal method to be called on resolve() or reject().\n + * @private\n + */\n +exports.Promise.prototype._complete = function(list, status, data, name) {\n + // Complain if we\'ve already been completed\n + if (this._status != PENDING) {\n + console.group(\'Promise already closed\');\n + console.error(\'Attempted \' + name + \'() with \', data);\n + console.error(\'Previous status = \', this._status,\n + \', previous value = \', this._value);\n + console.trace();\n +\n + if (this._completeTrace) {\n + console.error(\'Trace of previous completion:\');\n + this._completeTrace.log(5);\n + }\n + console.groupEnd();\n + return this;\n + }\n +\n + if (_traceCompletion) {\n + this._completeTrace = new Trace(new Error());\n + }\n +\n + this._status = status;\n + this._value = data;\n +\n + // Call all the handlers, and then delete them\n + list.forEach(function(handler) {\n + handler.call(null, this._value);\n + }, this);\n + this._onSuccessHandlers.length = 0;\n + this._onErrorHandlers.length = 0;\n +\n + // Remove the given {promise} from the _outstanding list, and add it to the\n + // _recent list, pruning more than 20 recent promises from that list.\n + delete exports._outstanding[this._id];\n + exports._recent.push(this);\n + while (exports._recent.length > 20) {\n + exports._recent.shift();\n + }\n +\n + return this;\n +};\n +\n +\n +/**\n + * Takes an array of promises and returns a promise that that is fulfilled once\n + * all the promises in the array are fulfilled\n + * @param group The array of promises\n + * @return the promise that is fulfilled when all the array is fulfilled\n + */\n +exports.group = function(promiseList) {\n + if (!(promiseList instanceof Array)) {\n + promiseList = Array.prototype.slice.call(arguments);\n + }\n +\n + // If the original array has nothing in it, return now to avoid waiting\n + if (promiseList.length === 0) {\n + return new exports.Promise().resolve([]);\n + }\n +\n + var groupPromise = new exports.Promise();\n + var results = [];\n + var fulfilled = 0;\n +\n + var onSuccessFactory = function(index) {\n + return function(data) {\n + results[index] = data;\n + fulfilled++;\n + // If the group has already failed, silently drop extra results\n + if (groupPromise._status !== ERROR) {\n + if (fulfilled === promiseList.length) {\n + groupPromise.resolve(results);\n + }\n + }\n + };\n + };\n +\n + promiseList.forEach(function(promise, index) {\n + var onSuccess = onSuccessFactory(index);\n + var onError = groupPromise.reject.bind(groupPromise);\n + promise.then(onSuccess, onError);\n + });\n +\n + return groupPromise;\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:util/scratchcanvas",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +\n +/**\n + * A invisible singleton canvas on the page, useful whenever a canvas context\n + * is needed (e.g. for computing text sizes), but an actual canvas isn\'t handy\n + * at the moment.\n + * @constructor\n + */\n +var ScratchCanvas = function() {\n + this._canvas = document.getElementById(\'bespin-scratch-canvas\');\n +\n + // It\'s possible that another ScratchCanvas instance in another sandbox\n + // exists on the page. If so, we assume they\'re compatible, and use\n + // that one.\n + if (util.none(this._canvas)) {\n + this._canvas = document.createElement(\'canvas\');\n + this._canvas.id = \'bespin-scratch-canvas\';\n + this._canvas.width = 400;\n + this._canvas.height = 300;\n + this._canvas.style.position = \'absolute\';\n + this._canvas.style.top = "-10000px";\n + this._canvas.style.left = "-10000px";\n + document.body.appendChild(this._canvas);\n + }\n +};\n +\n +ScratchCanvas.prototype.getContext = function() {\n + return this._canvas.getContext(\'2d\');\n +};\n +\n +/**\n + * Returns the width in pixels of the given string ("M", by default) in the\n + * given font.\n + */\n +ScratchCanvas.prototype.measureStringWidth = function(font, str) {\n + if (util.none(str)) {\n + str = "M";\n + }\n +\n + var context = this.getContext();\n + context.save();\n + context.font = font;\n + var width = context.measureText(str).width;\n + context.restore();\n + return width;\n +};\n +\n +var singleton = null;\n +\n +/**\n + * Returns the instance of the scratch canvas on the page, creating it if\n + * necessary.\n + */\n +exports.get = function() {\n + if (singleton === null) {\n + singleton = new ScratchCanvas();\n + }\n + return singleton;\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:util/cookie",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +/**\n + * Adds escape sequences for special characters in regular expressions\n + * @param {String} str a String with special characters to be left unescaped\n + */\n +var escapeString = function(str, except){\n + return str.replace(/([\\.$?*|{}\\(\\)\\[\\]\\\\\\/\\+^])/g, function(ch){\n + if(except && except.indexOf(ch) != -1){\n + return ch;\n + }\n + return "\\\\" + ch;\n + });\n +};\n +\n +/**\n + * Get a cookie value by name\n + * @param {String} name The cookie value to retrieve\n + * @return The value, or undefined if the cookie was not found\n + */\n +exports.get = function(name) {\n + var matcher = new RegExp("(?:^|; )" + escapeString(name) + "=([^;]*)");\n + var matches = document.cookie.match(matcher);\n + return matches ? decodeURIComponent(matches[1]) : undefined;\n +};\n +\n +/**\n + * Set a cookie value\n + * @param {String} name The cookie value to alter\n + * @param {String} value The new value for the cookie\n + * @param {Object} props (Optional) cookie properties. One of:<ul>\n + * <li>expires: Date|String|Number|null If a number, the number of days from\n + * today at which the cookie will expire. If a date, the date past which the\n + * cookie will expire. If expires is in the past, the cookie will be deleted.\n + * If expires is omitted or is 0, the cookie will expire either directly (ff3)\n + * or when the browser closes\n + * <li>path: String|null The path to use for the cookie.\n + * <li>domain: String|null The domain to use for the cookie.\n + * <li>secure: Boolean|null Whether to only send the cookie on secure connections\n + * </ul>\n + */\n +exports.set = function(name, value, props) {\n + props = props || {};\n +\n + if (typeof props.expires == "number") {\n + var date = new Date();\n + date.setTime(date.getTime() + props.expires * 24 * 60 * 60 * 1000);\n + props.expires = date;\n + }\n + if (props.expires && props.expires.toUTCString) {\n + props.expires = props.expires.toUTCString();\n + }\n +\n + value = encodeURIComponent(value);\n + var updatedCookie = name + "=" + value, propName;\n + for (propName in props) {\n + updatedCookie += "; " + propName;\n + var propValue = props[propName];\n + if (propValue !== true) {\n + updatedCookie += "=" + propValue;\n + }\n + }\n +\n + document.cookie = updatedCookie;\n +};\n +\n +/**\n + * Remove a cookie by name. Depending on the browser, the cookie will either\n + * be deleted directly or at browser close.\n + * @param {String} name The cookie value to retrieve\n + */\n +exports.remove = function(name) {\n + exports.set(name, "", { expires: -1 });\n +};\n +\n +/**\n + * Use to determine if the current browser supports cookies or not.\n + * @return Returns true if user allows cookies, false otherwise\n + */\n +exports.isSupported = function() {\n + if (!("cookieEnabled" in navigator)) {\n + exports.set("__djCookieTest__", "CookiesAllowed");\n + navigator.cookieEnabled = exports.get("__djCookieTest__") == "CookiesAllowed";\n + if (navigator.cookieEnabled) {\n + exports.remove("__djCookieTest__");\n + }\n + }\n + return navigator.cookieEnabled;\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:util/util",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +/**\n + * Create an object representing a de-serialized query section of a URL.\n + * Query keys with multiple values are returned in an array.\n + * <p>Example: The input "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"\n + * Produces the output object:\n + * <pre>{\n + * foo: [ "bar", "baz" ],\n + * thinger: " spaces =blah",\n + * zonk: "blarg"\n + * }\n + * </pre>\n + * <p>Note that spaces and other urlencoded entities are correctly handled\n + * @see dojo.queryToObject()\n + * While dojo.queryToObject() is mainly for URL query strings, this version\n + * allows to specify a separator character\n + */\n +exports.queryToObject = function(str, seperator) {\n + var ret = {};\n + var qp = str.split(seperator || "&");\n + var dec = decodeURIComponent;\n + qp.forEach(function(item) {\n + if (item.length) {\n + var parts = item.split("=");\n + var name = dec(parts.shift());\n + var val = dec(parts.join("="));\n + if (exports.isString(ret[name])){\n + ret[name] = [ret[name]];\n + }\n + if (Array.isArray(ret[name])){\n + ret[name].push(val);\n + } else {\n + ret[name] = val;\n + }\n + }\n + });\n + return ret;\n +};\n +\n +/**\n + * Takes a name/value mapping object and returns a string representing a\n + * URL-encoded version of that object for use in a GET request\n + * <p>For example, given the input:\n + * <code>{ blah: "blah", multi: [ "thud", "thonk" ] }</code>\n + * The following string would be returned:\n + * <code>"blah=blah&multi=thud&multi=thonk"</code>\n + * @param map {Object} The object to convert\n + * @return {string} A URL-encoded version of the input\n + */\n +exports.objectToQuery = function(map) {\n + // FIXME: need to implement encodeAscii!!\n + var enc = encodeURIComponent;\n + var pairs = [];\n + var backstop = {};\n + for (var name in map) {\n + var value = map[name];\n + if (value != backstop[name]) {\n + var assign = enc(name) + "=";\n + if (value.isArray) {\n + for (var i = 0; i < value.length; i++) {\n + pairs.push(assign + enc(value[i]));\n + }\n + } else {\n + pairs.push(assign + enc(value));\n + }\n + }\n + }\n + return pairs.join("&");\n +};\n +\n +/**\n + * Holds the count to keep a unique value for setTimeout\n + * @private See rateLimit()\n + */\n +var nextRateLimitId = 0;\n +\n +/**\n + * Holds the timeouts so they can be cleared later\n + * @private See rateLimit()\n + */\n +var rateLimitTimeouts = {};\n +\n +/**\n + * Delay calling some function to check that it\'s not called again inside a\n + * maxRate. The real function is called after maxRate ms unless the return\n + * value of this function is called before, in which case the clock is restarted\n + */\n +exports.rateLimit = function(maxRate, scope, func) {\n + if (maxRate) {\n + var rateLimitId = nextRateLimitId++;\n +\n + return function() {\n + if (rateLimitTimeouts[rateLimitId]) {\n + clearTimeout(rateLimitTimeouts[rateLimitId]);\n + }\n +\n + rateLimitTimeouts[rateLimitId] = setTimeout(function() {\n + func.apply(scope, arguments);\n + delete rateLimitTimeouts[rateLimitId];\n + }, maxRate);\n + };\n + }\n +};\n +\n +/**\n + * Return true if it is a String\n + */\n +exports.isString = function(it) {\n + return (typeof it == "string" || it instanceof String);\n +};\n +\n +/**\n + * Returns true if it is a Boolean.\n + */\n +exports.isBoolean = function(it) {\n + return (typeof it == \'boolean\');\n +};\n +\n +/**\n + * Returns true if it is a Number.\n + */\n +exports.isNumber = function(it) {\n + return (typeof it == \'number\' && isFinite(it));\n +};\n +\n +/**\n + * Hack copied from dojo.\n + */\n +exports.isObject = function(it) {\n + return it !== undefined &&\n + (it === null || typeof it == "object" ||\n + Array.isArray(it) || exports.isFunction(it));\n +};\n +\n +/**\n + * Is the passed object a function?\n + * From dojo.isFunction()\n + */\n +exports.isFunction = (function() {\n + var _isFunction = function(it) {\n + var t = typeof it; // must evaluate separately due to bizarre Opera bug. See #8937\n + //Firefox thinks object HTML element is a function, so test for nodeType.\n + return it && (t == "function" || it instanceof Function) && !it.nodeType; // Boolean\n + };\n +\n + return exports.isSafari ?\n + // only slow this down w/ gratuitious casting in Safari (not WebKit)\n + function(/*anything*/ it) {\n + if (typeof it == "function" && it == "[object NodeList]") {\n + return false;\n + }\n + return _isFunction(it); // Boolean\n + } : _isFunction;\n +})();\n +\n +/**\n + * A la Prototype endsWith(). Takes a regex excluding the \'$\' end marker\n + */\n +exports.endsWith = function(str, end) {\n + if (!str) {\n + return false;\n + }\n + return str.match(new RegExp(end + "$"));\n +};\n +\n +/**\n + * A la Prototype include().\n + */\n +exports.include = function(array, item) {\n + return array.indexOf(item) > -1;\n +};\n +\n +/**\n + * Like include, but useful when you\'re checking for a specific\n + * property on each object in the list...\n + *\n + * Returns null if the item is not in the list, otherwise\n + * returns the index of the item.\n + */\n +exports.indexOfProperty = function(array, propertyName, item) {\n + for (var i = 0; i < array.length; i++) {\n + if (array[i][propertyName] == item) {\n + return i;\n + }\n + }\n + return null;\n +};\n +\n +/**\n + * A la Prototype last().\n + */\n +exports.last = function(array) {\n + if (Array.isArray(array)) {\n + return array[array.length - 1];\n + }\n +};\n +\n +/**\n + * Knock off any undefined items from the end of an array\n + */\n +exports.shrinkArray = function(array) {\n + var newArray = [];\n +\n + var stillAtBeginning = true;\n + array.reverse().forEach(function(item) {\n + if (stillAtBeginning && item === undefined) {\n + return;\n + }\n +\n + stillAtBeginning = false;\n +\n + newArray.push(item);\n + });\n +\n + return newArray.reverse();\n +};\n +\n +/**\n + * Create an array\n + * @param number The size of the new array to create\n + * @param character The item to put in the array, defaults to \' \'\n + */\n +exports.makeArray = function(number, character) {\n + if (number < 1) {\n + return []; // give us a normal number please!\n + }\n + if (!character){character = \' \';}\n +\n + var newArray = [];\n + for (var i = 0; i < number; i++) {\n + newArray.push(character);\n + }\n + return newArray;\n +};\n +\n +/**\n + * Repeat a string a given number of times.\n + * @param string String to repeat\n + * @param repeat Number of times to repeat\n + */\n +exports.repeatString = function(string, repeat) {\n + var newstring = \'\';\n +\n + for (var i = 0; i < repeat; i++) {\n + newstring += string;\n + }\n +\n + return newstring;\n +};\n +\n +/**\n + * Given a row, find the number of leading spaces.\n + * E.g. an array with the string " aposjd" would return 2\n + * @param row The row to hunt through\n + */\n +exports.leadingSpaces = function(row) {\n + var numspaces = 0;\n + for (var i = 0; i < row.length; i++) {\n + if (row[i] == \' \' || row[i] == \'\' || row[i] === undefined) {\n + numspaces++;\n + } else {\n + return numspaces;\n + }\n + }\n + return numspaces;\n +};\n +\n +/**\n + * Given a row, find the number of leading tabs.\n + * E.g. an array with the string "\\t\\taposjd" would return 2\n + * @param row The row to hunt through\n + */\n +exports.leadingTabs = function(row) {\n + var numtabs = 0;\n + for (var i = 0; i < row.length; i++) {\n + if (row[i] == \'\\t\' || row[i] == \'\' || row[i] === undefined) {\n + numtabs++;\n + } else {\n + return numtabs;\n + }\n + }\n + return numtabs;\n +};\n +\n +/**\n + * Given a row, extract a copy of the leading spaces or tabs.\n + * E.g. an array with the string "\\t \\taposjd" would return an array with the\n + * string "\\t \\t".\n + * @param row The row to hunt through\n + */\n +exports.leadingWhitespace = function(row) {\n + var leading = [];\n + for (var i = 0; i < row.length; i++) {\n + if (row[i] == \' \' || row[i] == \'\\t\' || row[i] == \'\' || row[i] === undefined) {\n + leading.push(row[i]);\n + } else {\n + return leading;\n + }\n + }\n + return leading;\n +};\n +\n +/**\n + * Given a camelCaseWord convert to "Camel Case Word"\n + */\n +exports.englishFromCamel = function(camel) {\n + camel.replace(/([A-Z])/g, function(str) {\n + return " " + str.toLowerCase();\n + }).trim();\n +};\n +\n +/**\n + * I hate doing this, but we need some way to determine if the user is on a Mac\n + * The reason is that users have different expectations of their key combinations.\n + *\n + * Take copy as an example, Mac people expect to use CMD or APPLE + C\n + * Windows folks expect to use CTRL + C\n + */\n +exports.OS = {\n + LINUX: \'LINUX\',\n + MAC: \'MAC\',\n + WINDOWS: \'WINDOWS\'\n +};\n +\n +var ua = navigator.userAgent;\n +var av = navigator.appVersion;\n +\n +/** Is the user using a browser that identifies itself as Linux */\n +exports.isLinux = av.indexOf("Linux") >= 0;\n +\n +/** Is the user using a browser that identifies itself as Windows */\n +exports.isWindows = av.indexOf("Win") >= 0;\n +\n +/** Is the user using a browser that identifies itself as WebKit */\n +exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined;\n +\n +/** Is the user using a browser that identifies itself as Chrome */\n +exports.isChrome = parseFloat(ua.split("Chrome/")[1]) || undefined;\n +\n +/** Is the user using a browser that identifies itself as Mac OS */\n +exports.isMac = av.indexOf("Macintosh") >= 0;\n +\n +/* Is this Firefox or related? */\n +exports.isMozilla = av.indexOf(\'Gecko/\') >= 0;\n +\n +if (ua.indexOf("AdobeAIR") >= 0) {\n + exports.isAIR = 1;\n +}\n +\n +/**\n + * Is the user using a browser that identifies itself as Safari\n + * See also:\n + * - http://developer.apple.com/internet/safari/faq.html#anchor2\n + * - http://developer.apple.com/internet/safari/uamatrix.html\n + */\n +var index = Math.max(av.indexOf("WebKit"), av.indexOf("Safari"), 0);\n +if (index && !exports.isChrome) {\n + // try to grab the explicit Safari version first. If we don\'t get\n + // one, look for less than 419.3 as the indication that we\'re on something\n + // "Safari 2-ish".\n + exports.isSafari = parseFloat(av.split("Version/")[1]);\n + if (!exports.isSafari || parseFloat(av.substr(index + 7)) <= 419.3) {\n + exports.isSafari = 2;\n + }\n +}\n +\n +if (ua.indexOf("Gecko") >= 0 && !exports.isWebKit) {\n + exports.isMozilla = parseFloat(av);\n +}\n +\n +/**\n + * Return a exports.OS constant\n + */\n +exports.getOS = function() {\n + if (exports.isMac) {\n + return exports.OS[\'MAC\'];\n + } else if (exports.isLinux) {\n + return exports.OS[\'LINUX\'];\n + } else {\n + return exports.OS[\'WINDOWS\'];\n + }\n +};\n +\n +/** Returns true if the DOM element "b" is inside the element "a". */\n +if (typeof(document) !== \'undefined\' && document.compareDocumentPosition) {\n + exports.contains = function(a, b) {\n + return a.compareDocumentPosition(b) & 16;\n + };\n +} else {\n + exports.contains = function(a, b) {\n + return a !== b && (a.contains ? a.contains(b) : true);\n + };\n +}\n +\n +/**\n + * Prevents propagation and clobbers the default action of the passed event\n + */\n +exports.stopEvent = function(ev) {\n + ev.preventDefault();\n + ev.stopPropagation();\n +};\n +\n +/**\n + * Create a random password of the given length (default 16 chars)\n + */\n +exports.randomPassword = function(length) {\n + length = length || 16;\n + var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";\n + var pass = "";\n + for (var x = 0; x < length; x++) {\n + var charIndex = Math.floor(Math.random() * chars.length);\n + pass += chars.charAt(charIndex);\n + }\n + return pass;\n +};\n +\n +/**\n + * Is the passed object free of members, i.e. are there any enumerable\n + * properties which the objects claims as it\'s own using hasOwnProperty()\n + */\n +exports.isEmpty = function(object) {\n + for (var x in object) {\n + if (object.hasOwnProperty(x)) {\n + return false;\n + }\n + }\n + return true;\n +};\n +\n +/**\n + * Does the name of a project indicate that it is owned by someone else\n + * TODO: This is a major hack. We really should have a File object that include\n + * separate owner information.\n + */\n +exports.isMyProject = function(project) {\n + return project.indexOf("+") == -1;\n +};\n +\n +/**\n + * Format a date as dd MMM yyyy\n + */\n +exports.formatDate = function (date) {\n + if (!date) {\n + return "Unknown";\n + }\n + return date.getDate() + " " +\n + exports.formatDate.shortMonths[date.getMonth()] + " " +\n + date.getFullYear();\n +};\n +\n +/**\n + * Month data for exports.formatDate\n + */\n +exports.formatDate.shortMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];\n +\n +/**\n + * Add a CSS class to the list of classes on the given node\n + */\n +exports.addClass = function(node, className) {\n + var parts = className.split(/\\s+/);\n + var cls = " " + node.className + " ";\n + for (var i = 0, len = parts.length, c; i < len; ++i) {\n + c = parts[i];\n + if (c && cls.indexOf(" " + c + " ") < 0) {\n + cls += c + " ";\n + }\n + }\n + node.className = cls.trim();\n +};\n +\n +/**\n + * Remove a CSS class from the list of classes on the given node\n + */\n +exports.removeClass = function(node, className) {\n + var cls;\n + if (className !== undefined) {\n + var parts = className.split(/\\s+/);\n + cls = " " + node.className + " ";\n + for (var i = 0, len = parts.length; i < len; ++i) {\n + cls = cls.replace(" " + parts[i] + " ", " ");\n + }\n + cls = cls.trim();\n + } else {\n + cls = "";\n + }\n + if (node.className != cls) {\n + node.className = cls;\n + }\n +};\n +\n +/**\n + * Add or remove a CSS class from the list of classes on the given node\n + * depending on the value of <tt>include</tt>\n + */\n +exports.setClass = function(node, className, include) {\n + if (include) {\n + exports.addClass(node, className);\n + } else {\n + exports.removeClass(node, className);\n + }\n +};\n +\n +/**\n + * Is the passed object either null or undefined (using ===)\n + */\n +exports.none = function(obj) {\n + return obj === null || obj === undefined;\n +};\n +\n +/**\n + * Creates a clone of the passed object. This function can take just about\n + * any type of object and create a clone of it, including primitive values\n + * (which are not actually cloned because they are immutable).\n + * If the passed object implements the clone() method, then this function\n + * will simply call that method and return the result.\n + * @param object {Object} the object to clone\n + * @returns {Object} the cloned object\n + */\n +exports.clone = function(object, deep) {\n + if (Array.isArray(object) && !deep) {\n + return object.slice();\n + }\n +\n + if (typeof object === \'object\' || Array.isArray(object)) {\n + if (object === null) {\n + return null;\n + }\n +\n + var reply = (Array.isArray(object) ? [] : {});\n + for (var key in object) {\n + if (deep && (typeof object[key] === \'object\'\n + || Array.isArray(object[key]))) {\n + reply[key] = exports.clone(object[key], true);\n + } else {\n + reply[key] = object[key];\n + }\n + }\n + return reply;\n + }\n +\n + if (object.clone && typeof(object.clone) === \'function\') {\n + return object.clone();\n + }\n +\n + // That leaves numbers, booleans, undefined. Doesn\'t it?\n + return object;\n +};\n +\n +\n +/**\n + * Helper method for extending one object with another\n + * Copies all properties from source to target. Returns the extended target\n + * object.\n + * Taken from John Resig, http://ejohn.org/blog/javascript-getters-and-setters/.\n + */\n +exports.mixin = function(a, b) {\n + for (var i in b) {\n + var g = b.__lookupGetter__(i);\n + var s = b.__lookupSetter__(i);\n +\n + if (g || s) {\n + if (g) {\n + a.__defineGetter__(i, g);\n + }\n + if (s) {\n + a.__defineSetter__(i, s);\n + }\n + } else {\n + a[i] = b[i];\n + }\n + }\n +\n + return a;\n +};\n +\n +/**\n + * Basically taken from Sproutcore.\n + * Replaces the count items from idx with objects.\n + */\n +exports.replace = function(arr, idx, amt, objects) {\n + return arr.slice(0, idx).concat(objects).concat(arr.slice(idx + amt));\n +};\n +\n +/**\n + * Return true if the two frames match. You can also pass only points or sizes.\n + * @param r1 {Rect} the first rect\n + * @param r2 {Rect} the second rect\n + * @param delta {Float} an optional delta that allows for rects that do not match exactly. Defaults to 0.1\n + * @returns {Boolean} true if rects match\n + */\n +exports.rectsEqual = function(r1, r2, delta) {\n + if (!r1 || !r2) {\n + return r1 == r2;\n + }\n +\n + if (!delta && delta !== 0) {\n + delta = 0.1;\n + }\n +\n + if ((r1.y != r2.y) && (Math.abs(r1.y - r2.y) > delta)) {\n + return false;\n + }\n +\n + if ((r1.x != r2.x) && (Math.abs(r1.x - r2.x) > delta)) {\n + return false;\n + }\n +\n + if ((r1.width != r2.width) && (Math.abs(r1.width - r2.width) > delta)) {\n + return false;\n + }\n +\n + if ((r1.height != r2.height) && (Math.abs(r1.height - r2.height) > delta)) {\n + return false;\n + }\n +\n + return true;\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:util/stacktrace",function(require,exports,module) {\n +// Changed to suit the specific needs of running within Bespin\n +\n +// Domain Public by Eric Wendelin http://eriwen.com/ (2008)\n +// Luke Smith http://lucassmith.name/ (2008)\n +// Loic Dachary <loic@dachary.org> (2008)\n +// Johan Euphrosine <proppy@aminche.com> (2008)\n +// Øyvind Sean Kinsey http://kinsey.no/blog\n +//\n +// Information and discussions\n +// http://jspoker.pokersource.info/skin/test-printstacktrace.html\n +// http://eriwen.com/javascript/js-stack-trace/\n +// http://eriwen.com/javascript/stacktrace-update/\n +// http://pastie.org/253058\n +// http://browsershots.org/http://jspoker.pokersource.info/skin/test-printstacktrace.html\n +//\n +\n +//\n +// guessFunctionNameFromLines comes from firebug\n +//\n +// Software License Agreement (BSD License)\n +//\n +// Copyright (c) 2007, Parakey Inc.\n +// All rights reserved.\n +//\n +// Redistribution and use of this software in source and binary forms, with or without modification,\n +// are permitted provided that the following conditions are met:\n +//\n +// * Redistributions of source code must retain the above\n +// copyright notice, this list of conditions and the\n +// following disclaimer.\n +//\n +// * Redistributions in binary form must reproduce the above\n +// copyright notice, this list of conditions and the\n +// following disclaimer in the documentation and/or other\n +// materials provided with the distribution.\n +//\n +// * Neither the name of Parakey Inc. nor the names of its\n +// contributors may be used to endorse or promote products\n +// derived from this software without specific prior\n +// written permission of Parakey Inc.\n +//\n +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR\n +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\n +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n +// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n +\n +var util = require(\'bespin:util/util\');\n +var console = require("bespin:console").console;\n +\n +/**\n + * Different browsers create stack traces in different ways.\n + * <strike>Feature</strike> Browser detection baby ;).\n + */\n +var mode = (function() {\n +\n + // We use SC\'s browser detection here to avoid the "break on error"\n + // functionality provided by Firebug. Firebug tries to do the right\n + // thing here and break, but it happens every time you load the page.\n + // bug 554105\n + if (util.isMozilla) {\n + return \'firefox\';\n + } else if (util.isOpera) {\n + return \'opera\';\n + } else if (util.isSafari) {\n + return \'other\';\n + }\n +\n + // SC doesn\'t do any detection of Chrome at this time.\n +\n + // this is the original feature detection code that is used as a\n + // fallback.\n + try {\n + (0)();\n + } catch (e) {\n + if (e.arguments) {\n + return \'chrome\';\n + }\n + if (e.stack) {\n + return \'firefox\';\n + }\n + if (window.opera && !(\'stacktrace\' in e)) { //Opera 9-\n + return \'opera\';\n + }\n + }\n + return \'other\';\n +})();\n +\n +/**\n + *\n + */\n +function stringifyArguments(args) {\n + for (var i = 0; i < args.length; ++i) {\n + var argument = args[i];\n + if (typeof argument == \'object\') {\n + args[i] = \'#object\';\n + } else if (typeof argument == \'function\') {\n + args[i] = \'#function\';\n + } else if (typeof argument == \'string\') {\n + args[i] = \'"\' + argument + \'"\';\n + }\n + }\n + return args.join(\',\');\n +}\n +\n +/**\n + * Extract a stack trace from the format emitted by each browser.\n + */\n +var decoders = {\n + chrome: function(e) {\n + var stack = e.stack;\n + if (!stack) {\n + console.log(e);\n + return [];\n + }\n + return stack.replace(/^.*?\\n/, \'\').\n + replace(/^.*?\\n/, \'\').\n + replace(/^.*?\\n/, \'\').\n + replace(/^[^\\(]+?[\\n$]/gm, \'\').\n + replace(/^\\s+at\\s+/gm, \'\').\n + replace(/^Object.<anonymous>\\s*\\(/gm, \'{anonymous}()@\').\n + split(\'\\n\');\n + },\n +\n + firefox: function(e) {\n + var stack = e.stack;\n + if (!stack) {\n + console.log(e);\n + return [];\n + }\n + // stack = stack.replace(/^.*?\\n/, \'\');\n + stack = stack.replace(/(?:\\n@:0)?\\s+$/m, \'\');\n + stack = stack.replace(/^\\(/gm, \'{anonymous}(\');\n + return stack.split(\'\\n\');\n + },\n +\n + // Opera 7.x and 8.x only!\n + opera: function(e) {\n + var lines = e.message.split(\'\\n\'), ANON = \'{anonymous}\',\n + lineRE = /Line\\s+(\\d+).*?script\\s+(http\\S+)(?:.*?in\\s+function\\s+(\\S+))?/i, i, j, len;\n +\n + for (i = 4, j = 0, len = lines.length; i < len; i += 2) {\n + if (lineRE.test(lines[i])) {\n + lines[j++] = (RegExp.$3 ? RegExp.$3 + \'()@\' + RegExp.$2 + RegExp.$1 : ANON + \'()@\' + RegExp.$2 + \':\' + RegExp.$1) +\n + \' -- \' +\n + lines[i + 1].replace(/^\\s+/, \'\');\n + }\n + }\n +\n + lines.splice(j, lines.length - j);\n + return lines;\n + },\n +\n + // Safari, Opera 9+, IE, and others\n + other: function(curr) {\n + var ANON = \'{anonymous}\', fnRE = /function\\s*([\\w\\-$]+)?\\s*\\(/i, stack = [], j = 0, fn, args;\n +\n + var maxStackSize = 10;\n + while (curr && stack.length < maxStackSize) {\n + fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;\n + args = Array.prototype.slice.call(curr[\'arguments\']);\n + stack[j++] = fn + \'(\' + stringifyArguments(args) + \')\';\n +\n + //Opera bug: if curr.caller does not exist, Opera returns curr (WTF)\n + if (curr === curr.caller && window.opera) {\n + //TODO: check for same arguments if possible\n + break;\n + }\n + curr = curr.caller;\n + }\n + return stack;\n + }\n +};\n +\n +/**\n + *\n + */\n +function NameGuesser() {\n +}\n +\n +NameGuesser.prototype = {\n +\n + sourceCache: {},\n +\n + ajax: function(url) {\n + var req = this.createXMLHTTPObject();\n + if (!req) {\n + return;\n + }\n + req.open(\'GET\', url, false);\n + req.setRequestHeader(\'User-Agent\', \'XMLHTTP/1.0\');\n + req.send(\'\');\n + return req.responseText;\n + },\n +\n + createXMLHTTPObject: function() {\n +\t // Try XHR methods in order and store XHR factory\n + var xmlhttp, XMLHttpFactories = [\n + function() {\n + return new XMLHttpRequest();\n + }, function() {\n + return new ActiveXObject(\'Msxml2.XMLHTTP\');\n + }, function() {\n + return new ActiveXObject(\'Msxml3.XMLHTTP\');\n + }, function() {\n + return new ActiveXObject(\'Microsoft.XMLHTTP\');\n + }\n + ];\n + for (var i = 0; i < XMLHttpFactories.length; i++) {\n + try {\n + xmlhttp = XMLHttpFactories[i]();\n + // Use memoization to cache the factory\n + this.createXMLHTTPObject = XMLHttpFactories[i];\n + return xmlhttp;\n + } catch (e) {}\n + }\n + },\n +\n + getSource: function(url) {\n + if (!(url in this.sourceCache)) {\n + this.sourceCache[url] = this.ajax(url).split(\'\\n\');\n + }\n + return this.sourceCache[url];\n + },\n +\n + guessFunctions: function(stack) {\n + for (var i = 0; i < stack.length; ++i) {\n + var reStack = /{anonymous}\\(.*\\)@(\\w+:\\/\\/([-\\w\\.]+)+(:\\d+)?[^:]+):(\\d+):?(\\d+)?/;\n + var frame = stack[i], m = reStack.exec(frame);\n + if (m) {\n + var file = m[1], lineno = m[4]; //m[7] is character position in Chrome\n + if (file && lineno) {\n + var functionName = this.guessFunctionName(file, lineno);\n + stack[i] = frame.replace(\'{anonymous}\', functionName);\n + }\n + }\n + }\n + return stack;\n + },\n +\n + guessFunctionName: function(url, lineNo) {\n + try {\n + return this.guessFunctionNameFromLines(lineNo, this.getSource(url));\n + } catch (e) {\n + return \'getSource failed with url: \' + url + \', exception: \' + e.toString();\n + }\n + },\n +\n + guessFunctionNameFromLines: function(lineNo, source) {\n + var reFunctionArgNames = /function ([^(]*)\\(([^)]*)\\)/;\n + var reGuessFunction = /[\'"]?([0-9A-Za-z_]+)[\'"]?\\s*[:=]\\s*(function|eval|new Function)/;\n + // Walk backwards from the first line in the function until we find the line which\n + // matches the pattern above, which is the function definition\n + var line = \'\', maxLines = 10;\n + for (var i = 0; i < maxLines; ++i) {\n + line = source[lineNo - i] + line;\n + if (line !== undefined) {\n + var m = reGuessFunction.exec(line);\n + if (m) {\n + return m[1];\n + }\n + else {\n + m = reFunctionArgNames.exec(line);\n + }\n + if (m && m[1]) {\n + return m[1];\n + }\n + }\n + }\n + return \'(?)\';\n + }\n +};\n +\n +var guesser = new NameGuesser();\n +\n +var frameIgnorePatterns = [\n + /http:\\/\\/localhost:4020\\/sproutcore.js:/\n +];\n +\n +exports.ignoreFramesMatching = function(regex) {\n + frameIgnorePatterns.push(regex);\n +};\n +\n +/**\n + * Create a stack trace from an exception\n + * @param ex {Error} The error to create a stacktrace from (optional)\n + * @param guess {Boolean} If we should try to resolve the names of anonymous functions\n + */\n +exports.Trace = function Trace(ex, guess) {\n + this._ex = ex;\n + this._stack = decoders[mode](ex);\n +\n + if (guess) {\n + this._stack = guesser.guessFunctions(this._stack);\n + }\n +};\n +\n +/**\n + * Log to the console a number of lines (default all of them)\n + * @param lines {number} Maximum number of lines to wrote to console\n + */\n +exports.Trace.prototype.log = function(lines) {\n + if (lines <= 0) {\n + // You aren\'t going to have more lines in your stack trace than this\n + // and it still fits in a 32bit integer\n + lines = 999999999;\n + }\n +\n + var printed = 0;\n + for (var i = 0; i < this._stack.length && printed < lines; i++) {\n + var frame = this._stack[i];\n + var display = true;\n + frameIgnorePatterns.forEach(function(regex) {\n + if (regex.test(frame)) {\n + display = false;\n + }\n + });\n + if (display) {\n + console.debug(frame);\n + printed++;\n + }\n + }\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +// BEGIN VERSION BLOCK\n +/** The core version of the Bespin system */\n +exports.versionNumber = \'tip\';\n +\n +/** The version number to display to users */\n +exports.versionCodename = \'DEVELOPMENT MODE\';\n +\n +/** The version number of the API (to ensure that the client and server are talking the same language) */\n +exports.apiVersion = \'dev\';\n +\n +// END VERSION BLOCK\n +\n +\n +});\n +\n +bespin.tiki.module("bespin:globals",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +/*\n +* Installs ES5 and SproutCore monkeypatches as needed.\n +*/\n +var installGlobals = function() {\n + /**\n + * Array detector.\n + * Firefox 3.5 and Safari 4 have this already. Chrome 4 however ...\n + * Note to Dojo - your isArray is still broken: instanceof doesn\'t work with\n + * Arrays taken from a different frame/window.\n + */\n + if (!Array.isArray) {\n + Array.isArray = function(data) {\n + return (data && Object.prototype.toString.call(data) == "[object Array]");\n + };\n + }\n +\n + /**\n + * Retrieves the list of keys on an object.\n + */\n + if (!Object.keys) {\n + Object.keys = function(obj) {\n + var k, ret = [];\n + for (k in obj) {\n + if (obj.hasOwnProperty(k)) {\n + ret.push(k);\n + }\n + }\n + return ret;\n + };\n + }\n +\n + if (!Function.prototype.bind) {\n + // From Narwhal\n + Function.prototype.bind = function () {\n + var args = Array.prototype.slice.call(arguments);\n + var self = this;\n + var bound = function () {\n + return self.call.apply(\n + self,\n + args.concat(\n + Array.prototype.slice.call(arguments)\n + )\n + );\n + };\n + bound.name = this.name;\n + bound.displayName = this.displayName;\n + bound.length = this.length;\n + bound.unbound = self;\n + return bound;\n + };\n + }\n +};\n +\n +// Narwhal\'s shim for ES5 defineProperty\n +\n +// ES5 15.2.3.6\n +if (!Object.defineProperty) {\n + Object.defineProperty = function(object, property, descriptor) {\n + var has = Object.prototype.hasOwnProperty;\n + if (typeof descriptor == "object" && object.__defineGetter__) {\n + if (has.call(descriptor, "value")) {\n + if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) {\n + // data property defined and no pre-existing accessors\n + object[property] = descriptor.value;\n + }\n + if (has.call(descriptor, "get") || has.call(descriptor, "set")) {\n + // descriptor has a value property but accessor already exists\n + throw new TypeError("Object doesn\'t support this action");\n + }\n + }\n + // fail silently if "writable", "enumerable", or "configurable"\n + // are requested but not supported\n + /*\n + // alternate approach:\n + if ( // can\'t implement these features; allow false but not true\n + !(has.call(descriptor, "writable") ? descriptor.writable : true) ||\n + !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) ||\n + !(has.call(descriptor, "configurable") ? descriptor.configurable : true)\n + )\n + throw new RangeError(\n + "This implementation of Object.defineProperty does not " +\n + "support configurable, enumerable, or writable."\n + );\n + */\n + else if (typeof descriptor.get == "function") {\n + object.__defineGetter__(property, descriptor.get);\n + }\n + if (typeof descriptor.set == "function") {\n + object.__defineSetter__(property, descriptor.set);\n + }\n + }\n + return object;\n + };\n +}\n +\n +// ES5 15.2.3.7\n +if (!Object.defineProperties) {\n + Object.defineProperties = function(object, properties) {\n + for (var property in properties) {\n + if (Object.prototype.hasOwnProperty.call(properties, property)) {\n + Object.defineProperty(object, property, properties[property]);\n + }\n + }\n + return object;\n + };\n +}\n +\n +\n +\n +installGlobals();\n +\n +});\n +\n +bespin.tiki.module("bespin:console",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require("util/util");\n +\n +/**\n + * This object represents a "safe console" object that forwards debugging\n + * messages appropriately without creating a dependency on Firebug in Firefox.\n + */\n +\n +// We could prefer to copy the methods on window.console to exports.console\n +// one by one because then we could be sure of using the safe subset that is\n +// implemented on all browsers, however this doesn\'t work properly everywhere\n +// ...\n +\n +var noop = function() {\n +};\n +\n +// These are the functions that are available in Chrome 4/5, Safari 4\n +// and Firefox 3.6. Don\'t add to this list without checking browser support\n +var NAMES = [\n + "assert", "count", "debug", "dir", "dirxml", "error", "group", "groupEnd",\n + "info", "log", "profile", "profileEnd", "time", "timeEnd", "trace", "warn"\n +];\n +\n +if (typeof(window) === \'undefined\') {\n + // We\'re in a web worker. Forward to the main thread so the messages\n + // will show up.\n + var console = {};\n + NAMES.forEach(function(name) {\n + console[name] = function() {\n + var args = Array.prototype.slice.call(arguments);\n + var msg = { op: \'log\', method: name, args: args };\n + postMessage(JSON.stringify(msg));\n + };\n + });\n +\n + exports.console = console;\n +} else if (util.isSafari || util.isChrome) {\n + // Webkit\'s output functions are bizarre because they get confused if \'this\'\n + // is not window.console, so we just copy it all across\n + exports.console = window.console;\n +} else {\n + // So we\'re not in Webkit, but we may still be no console object (in the\n + // case of Firefox without Firebug)\n + exports.console = { };\n +\n + // For each of the console functions, copy them if they exist, stub if not\n + NAMES.forEach(function(name) {\n + if (window.console && window.console[name]) {\n + exports.console[name] = window.console[name];\n + } else {\n + exports.console[name] = noop;\n + }\n + });\n +}\n +\n +\n +});\n +\n +bespin.tiki.module("bespin:builtins",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +exports.metadata =\n +{\n + "bespin":\n + {\n + "provides":\n + [\n + {\n + "ep": "extensionpoint",\n + "name": "extensionpoint",\n + "indexOx": "name",\n + "register": "plugins#registerExtensionPoint",\n + "unregister": "plugins#unregisterExtensionPoint",\n + "description": "Defines a new extension point",\n + "params": [\n + {\n + "name": "name",\n + "type": "string",\n + "description": "the extension point\'s name",\n + "required": true\n + },\n + {\n + "name": "description",\n + "type": "string",\n + "description": "description of what the extension point is for"\n + },\n + {\n + "name": "params",\n + "type": "array of objects",\n + "description": "parameters that provide the metadata for a given extension. Each object should have name and description, minimally. It can also have a \'type\' (eg string, pointer, or array) and required to denote whether or not this parameter must be present on the extension."\n + },\n + {\n + "name": "indexOn",\n + "type": "string",\n + "description": "You can provide an \'indexOn\' property to name a property of extensions through which you\'d like to be able to easily look up the extension."\n + },\n + {\n + "name": "register",\n + "type": "pointer",\n + "description": "function that is called when a new extension is discovered. Note that this should be used sparingly, because it will cause your plugin to be loaded whenever a matching plugin appears."\n + },\n + {\n + "name": "unregister",\n + "type": "pointer",\n + "description": "function that is called when an extension is removed. Note that this should be used sparingly, because it will cause your plugin to be loaded whenever a matching plugin appears."\n + }\n + ]\n + },\n + {\n + "ep": "extensionpoint",\n + "name": "extensionhandler",\n + "register": "plugins#registerExtensionHandler",\n + "unregister": "plugins#unregisterExtensionHandler",\n + "description": "Used to attach listeners ",\n + "params": [\n + {\n + "name": "name",\n + "type": "string",\n + "description": "name of the extension point to listen to",\n + "required": true\n + },\n + {\n + "name": "register",\n + "type": "pointer",\n + "description": "function that is called when a new extension is discovered. Note that this should be used sparingly, because it will cause your plugin to be loaded whenever a matching plugin appears."\n + },\n + {\n + "name": "unregister",\n + "type": "pointer",\n + "description": "function that is called when an extension is removed. Note that this should be used sparingly, because it will cause your plugin to be loaded whenever a matching plugin appears."\n + }\n + ]\n + },\n + {\n + "ep": "extensionpoint",\n + "name": "factory",\n + "description": "Provides a factory for singleton components. Each extension needs to provide a name, a pointer and an action. The action can be \'call\' (if the pointer refers to a function), \'new\' (if the pointer refers to a traditional JS object) or \'value\' (if the pointer refers to the object itself that is the component).",\n + "indexOn": "name"\n + },\n + {\n + "ep": "factory",\n + "name": "hub",\n + "action": "create",\n + "pointer": "util/hub#Hub"\n + },\n + {\n + "ep": "extensionpoint",\n + "name": "command",\n + "description": "Editor commands/actions. TODO: list parameters here."\n + }\n + ]\n + }\n +};\n +\n +});\n +\n +bespin.tiki.module("bespin:proxy",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require("util/util");\n +var Promise = require("promise").Promise;\n +\n +exports.xhr = function(method, url, async, beforeSendCallback) {\n + var pr = new Promise();\n +\n + if (!bespin.proxy || !bespin.proxy.xhr) {\n + var req = new XMLHttpRequest();\n + req.onreadystatechange = function() {\n + if (req.readyState !== 4) {\n + return;\n + }\n +\n + var status = req.status;\n + if (status !== 0 && status !== 200) {\n + var error = new Error(req.responseText + \' (Status \' + req.status + ")");\n + error.xhr = req;\n + pr.reject(error);\n + return;\n + }\n +\n + pr.resolve(req.responseText);\n + }.bind(this);\n +\n + req.open("GET", url, async);\n + if (beforeSendCallback) {\n + beforeSendCallback(req);\n + }\n + req.send();\n + } else {\n + bespin.proxy.xhr.call(this, method, url, async, beforeSendCallback, pr);\n + }\n +\n + return pr;\n +};\n +\n +exports.Worker = function(url) {\n + if (!bespin.proxy || !bespin.proxy.worker) {\n + return new Worker(url);\n + } else {\n + return new bespin.proxy.worker(url);\n + }\n +};\n +\n +});\n +;bespin.tiki.register("::settings", {\n + name: "settings",\n + dependencies: { "types": "0.0.0" }\n +});\n +bespin.tiki.module("settings:commands",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var env = require(\'environment\').env;\n +\n +var settings = require(\'settings\').settings;\n +\n +/**\n + * \'set\' command\n + */\n +exports.setCommand = function(args, request) {\n + var html;\n +\n + if (!args.setting) {\n + var settingsList = settings._list();\n + html = \'\';\n + // first sort the settingsList based on the key\n + settingsList.sort(function(a, b) {\n + if (a.key < b.key) {\n + return -1;\n + } else if (a.key == b.key) {\n + return 0;\n + } else {\n + return 1;\n + }\n + });\n +\n + settingsList.forEach(function(setting) {\n + html += \'<a class="setting" href="https://wiki.mozilla.org/Labs/Bespin/Settings#\' +\n + setting.key +\n + \'" title="View external documentation on setting: \' +\n + setting.key +\n + \'" target="_blank">\' +\n + setting.key +\n + \'</a> = \' +\n + setting.value +\n + \'<br/>\';\n + });\n + } else {\n + if (args.value === undefined) {\n + html = \'<strong>\' + args.setting + \'</strong> = \' + settings.get(args.setting);\n + } else {\n + html = \'Setting: <strong>\' + args.setting + \'</strong> = \' + args.value;\n + settings.set(args.setting, args.value);\n + }\n + }\n +\n + request.done(html);\n +};\n +\n +/**\n + * \'unset\' command\n + */\n +exports.unsetCommand = function(args, request) {\n + settings.resetValue(args.setting);\n + request.done(\'Reset \' + args.setting + \' to default: \' + settings.get(args.setting));\n +};\n +\n +});\n +\n +bespin.tiki.module("settings:cookie",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var cookie = require(\'bespin:util/cookie\');\n +\n +/**\n + * Save the settings in a cookie\n + * This code has not been tested since reboot\n + * @constructor\n + */\n +exports.CookiePersister = function() {\n +};\n +\n +exports.CookiePersister.prototype = {\n + loadInitialValues: function(settings) {\n + settings._loadDefaultValues().then(function() {\n + var data = cookie.get(\'settings\');\n + settings._loadFromObject(JSON.parse(data));\n + }.bind(this));\n + },\n +\n + persistValue: function(settings, key, value) {\n + try {\n + // Aggregate the settings into a file\n + var data = {};\n + settings._getSettingNames().forEach(function(key) {\n + data[key] = settings.get(key);\n + });\n +\n + var stringData = JSON.stringify(data);\n + cookie.set(\'settings\', stringData);\n + } catch (ex) {\n + console.error(\'Unable to JSONify the settings! \' + ex);\n + return;\n + }\n + }\n +};\n +\n +});\n +\n +bespin.tiki.module("settings:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +/**\n + * This plug-in manages settings.\n + *\n + * <p>Some quick terminology: A _Choice_, is something that the application\n + * offers as a way to customize how it works. For each _Choice_ there will be\n + * a number of _Options_ but ultimately the user will have a _Setting_ for each\n + * _Choice_. This _Setting_ maybe the default for that _Choice_.\n + *\n + * <p>It provides an API for controlling the known settings. This allows us to\n + * provide better GUI/CLI support. See setting.js\n + * <p>It provides 3 implementations of a setting store:<ul>\n + * <li>MemorySettings: i.e. temporary, non-persistent. Useful in textarea\n + * replacement type scenarios. See memory.js\n + * <li>CookieSettings: Stores the data in a cookie. Generally not practical as\n + * it slows client server communication (if any). See cookie.js\n + * <li>ServerSettings: Stores data on a server using the <tt>server</tt> API.\n + * See server.js\n + * </ul>\n + * <p>It is expected that an HTML5 storage option will be developed soon. This\n + * plug-in did contain a prototype Gears implementation, however this was never\n + * maintained, and has been deleted due to bit-rot.\n + * <p>This plug-in also provides commands to manipulate the settings from the\n + * command_line and canon plug-ins.\n + *\n + * <p>TODO:<ul>\n + * <li>Check what happens when we alter settings from the UI\n + * <li>Ensure that values can be bound in a SC sense\n + * <li>Convert all subscriptions to bindings.\n + * <li>Implement HTML5 storage option\n + * <li>Make all settings have a \'description\' member and use that in set|unset\n + * commands.\n + * <li>When the command system is re-worked to include more GUI interaction,\n + * expose data in settings to that system.\n + * </ul>\n + *\n + * <p>For future versions of the API it might be better to decrease the\n + * dependency on settings, and increase it on the system with a setting.\n + * e.g. Now:\n + * <pre>\n + * setting.addSetting({ name:\'foo\', ... });\n + * settings.set(\'foo\', \'bar\');\n + * </pre>\n + * <p>Vs the potentially better:\n + * <pre>\n + * var foo = setting.addSetting({ name:\'foo\', ... });\n + * foo.value = \'bar\';\n + * </pre>\n + * <p>Comparison:\n + * <ul>\n + * <li>The latter version gains by forcing access to the setting to be through\n + * the plug-in providing it, so there wouldn\'t be any hidden dependencies.\n + * <li>It\'s also more compact.\n + * <li>It could provide access to to other methods e.g. <tt>foo.reset()</tt>\n + * and <tt>foo.onChange(function(val) {...});</tt> (but see SC binding)\n + * <li>On the other hand dependencies are so spread out right now that it\'s\n + * probably hard to do this easily. We should move to this in the future.\n + * </ul>\n + */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var console = require(\'bespin:console\').console;\n +var Promise = require(\'bespin:promise\').Promise;\n +var groupPromises = require(\'bespin:promise\').group;\n +\n +var types = require(\'types:types\');\n +\n +/**\n + * Find and configure the settings object.\n + * @see MemorySettings.addSetting()\n + */\n +exports.addSetting = function(settingExt) {\n + require(\'settings\').settings.addSetting(settingExt);\n +};\n +\n +/**\n + * Fetch an array of the currently known settings\n + */\n +exports.getSettings = function() {\n + return catalog.getExtensions(\'setting\');\n +};\n +\n +/**\n + * Something of a hack to allow the set command to give a clearer definition\n + * of the type to the command line.\n + */\n +exports.getTypeSpecFromAssignment = function(typeSpec) {\n + var assignments = typeSpec.assignments;\n + var replacement = \'text\';\n +\n + if (assignments) {\n + // Find the assignment for \'setting\' so we can get it\'s value\n + var settingAssignment = null;\n + assignments.forEach(function(assignment) {\n + if (assignment.param.name === \'setting\') {\n + settingAssignment = assignment;\n + }\n + });\n +\n + if (settingAssignment) {\n + var settingName = settingAssignment.value;\n + if (settingName && settingName !== \'\') {\n + var settingExt = catalog.getExtensionByKey(\'setting\', settingName);\n + if (settingExt) {\n + replacement = settingExt.type;\n + }\n + }\n + }\n + }\n +\n + return replacement;\n +};\n +\n +/**\n + * A base class for all the various methods of storing settings.\n + * <p>Usage:\n + * <pre>\n + * // Create manually, or require \'settings\' from the container.\n + * // This is the manual version:\n + * var settings = require(\'bespin:plugins\').catalog.getObject(\'settings\');\n + * // Add a new setting\n + * settings.addSetting({ name:\'foo\', ... });\n + * // Display the default value\n + * alert(settings.get(\'foo\'));\n + * // Alter the value, which also publishes the change etc.\n + * settings.set(\'foo\', \'bar\');\n + * // Reset the value to the default\n + * settings.resetValue(\'foo\');\n + * </pre>\n + * @class\n + */\n +exports.MemorySettings = function() {\n +};\n +\n +exports.MemorySettings.prototype = {\n + /**\n + * Storage for the setting values\n + */\n + _values: {},\n +\n + /**\n + * Storage for deactivated values\n + */\n + _deactivated: {},\n +\n + /**\n + * A Persister is able to store settings. It is an object that defines\n + * two functions:\n + * loadInitialValues(settings) and persistValue(settings, key, value).\n + */\n + setPersister: function(persister) {\n + this._persister = persister;\n + if (persister) {\n + persister.loadInitialValues(this);\n + }\n + },\n +\n + /**\n + * Read accessor\n + */\n + get: function(key) {\n + return this._values[key];\n + },\n +\n + /**\n + * Override observable.set(key, value) to provide type conversion and\n + * validation.\n + */\n + set: function(key, value) {\n + var settingExt = catalog.getExtensionByKey(\'setting\', key);\n + if (!settingExt) {\n + // If there is no definition for this setting, then warn the user\n + // and store the setting in raw format. If the setting gets defined,\n + // the addSetting() function is called which then takes up the\n + // here stored setting and calls set() to convert the setting.\n + console.warn(\'Setting not defined: \', key, value);\n + this._deactivated[key] = value;\n + }\n + else if (typeof value == \'string\' && settingExt.type == \'string\') {\n + // no conversion needed\n + this._values[key] = value;\n + }\n + else {\n + var inline = false;\n +\n + types.fromString(value, settingExt.type).then(function(converted) {\n + inline = true;\n + this._values[key] = converted;\n +\n + // Inform subscriptions of the change\n + catalog.publish(this, \'settingChange\', key, converted);\n + }.bind(this), function(ex) {\n + console.error(\'Error setting\', key, \': \', ex);\n + });\n +\n + if (!inline) {\n + console.warn(\'About to set string version of \', key, \'delaying typed set.\');\n + this._values[key] = value;\n + }\n + }\n +\n + this._persistValue(key, value);\n + return this;\n + },\n +\n + /**\n + * Function to add to the list of available settings.\n + * <p>Example usage:\n + * <pre>\n + * var settings = require(\'bespin:plugins\').catalog.getObject(\'settings\');\n + * settings.addSetting({\n + * name: \'tabsize\', // For use in settings.get(\'X\')\n + * type: \'number\', // To allow value checking.\n + * defaultValue: 4 // Default value for use when none is directly set\n + * });\n + * </pre>\n + * @param {object} settingExt Object containing name/type/defaultValue members.\n + */\n + addSetting: function(settingExt) {\n + if (!settingExt.name) {\n + console.error(\'Setting.name == undefined. Ignoring.\', settingExt);\n + return;\n + }\n +\n + if (!settingExt.defaultValue === undefined) {\n + console.error(\'Setting.defaultValue == undefined\', settingExt);\n + }\n +\n + types.isValid(settingExt.defaultValue, settingExt.type).then(function(valid) {\n + if (!valid) {\n + console.warn(\'!Setting.isValid(Setting.defaultValue)\', settingExt);\n + }\n +\n + // The value can be\n + // 1) the value of a setting that is not activated at the moment\n + // OR\n + // 2) the defaultValue of the setting.\n + var value = this._deactivated[settingExt.name] ||\n + settingExt.defaultValue;\n +\n + // Set the default value up.\n + this.set(settingExt.name, value);\n + }.bind(this), function(ex) {\n + console.error(\'Type error \', ex, \' ignoring setting \', settingExt);\n + });\n + },\n +\n + /**\n + * Reset the value of the <code>key</code> setting to it\'s default\n + */\n + resetValue: function(key) {\n + var settingExt = catalog.getExtensionByKey(\'setting\', key);\n + if (settingExt) {\n + this.set(key, settingExt.defaultValue);\n + } else {\n + console.log(\'ignore resetValue on \', key);\n + }\n + },\n +\n + resetAll: function() {\n + this._getSettingNames().forEach(function(key) {\n + this.resetValue(key);\n + }.bind(this));\n + },\n +\n + /**\n + * Make a list of the valid type names\n + */\n + _getSettingNames: function() {\n + var typeNames = [];\n + catalog.getExtensions(\'setting\').forEach(function(settingExt) {\n + typeNames.push(settingExt.name);\n + });\n + return typeNames;\n + },\n +\n + /**\n + * Retrieve a list of the known settings and their values\n + */\n + _list: function() {\n + var reply = [];\n + this._getSettingNames().forEach(function(setting) {\n + reply.push({\n + \'key\': setting,\n + \'value\': this.get(setting)\n + });\n + }.bind(this));\n + return reply;\n + },\n +\n + /**\n + * delegates to the persister. no-op if there\'s no persister.\n + */\n + _persistValue: function(key, value) {\n + var persister = this._persister;\n + if (persister) {\n + persister.persistValue(this, key, value);\n + }\n + },\n +\n + /**\n + * Delegates to the persister, otherwise sets up the defaults if no\n + * persister is available.\n + */\n + _loadInitialValues: function() {\n + var persister = this._persister;\n + if (persister) {\n + persister.loadInitialValues(this);\n + } else {\n + this._loadDefaultValues();\n + }\n + },\n +\n + /**\n + * Prime the local cache with the defaults.\n + */\n + _loadDefaultValues: function() {\n + return this._loadFromObject(this._defaultValues());\n + },\n +\n + /**\n + * Utility to load settings from an object\n + */\n + _loadFromObject: function(data) {\n + var promises = [];\n + // take the promise action out of the loop to avoid closure problems\n + var setterFactory = function(keyName) {\n + return function(value) {\n + this.set(keyName, value);\n + };\n + };\n +\n + for (var key in data) {\n + if (data.hasOwnProperty(key)) {\n + var valueStr = data[key];\n + var settingExt = catalog.getExtensionByKey(\'setting\', key);\n + if (settingExt) {\n + // TODO: We shouldn\'t just ignore values without a setting\n + var promise = types.fromString(valueStr, settingExt.type);\n + var setter = setterFactory(key);\n + promise.then(setter);\n + promises.push(promise);\n + }\n + }\n + }\n +\n + // Promise.group (a.k.a groupPromises) gives you a list of all the data\n + // in the grouped promises. We don\'t want that in case we change how\n + // this works with ignored settings (see above).\n + // So we do this to hide the list of promise resolutions.\n + var replyPromise = new Promise();\n + groupPromises(promises).then(function() {\n + replyPromise.resolve();\n + });\n + return replyPromise;\n + },\n +\n + /**\n + * Utility to grab all the settings and export them into an object\n + */\n + _saveToObject: function() {\n + var promises = [];\n + var reply = {};\n +\n + this._getSettingNames().forEach(function(key) {\n + var value = this.get(key);\n + var settingExt = catalog.getExtensionByKey(\'setting\', key);\n + if (settingExt) {\n + // TODO: We shouldn\'t just ignore values without a setting\n + var promise = types.toString(value, settingExt.type);\n + promise.then(function(value) {\n + reply[key] = value;\n + });\n + promises.push(promise);\n + }\n + }.bind(this));\n +\n + var replyPromise = new Promise();\n + groupPromises(promises).then(function() {\n + replyPromise.resolve(reply);\n + });\n + return replyPromise;\n + },\n +\n + /**\n + * The default initial settings\n + */\n + _defaultValues: function() {\n + var defaultValues = {};\n + catalog.getExtensions(\'setting\').forEach(function(settingExt) {\n + defaultValues[settingExt.name] = settingExt.defaultValue;\n + });\n + return defaultValues;\n + }\n +};\n +\n +exports.settings = new exports.MemorySettings();\n +\n +});\n +;bespin.tiki.register("::canon", {\n + name: "canon",\n + dependencies: { "environment": "0.0.0", "events": "0.0.0", "settings": "0.0.0" }\n +});\n +bespin.tiki.module("canon:history",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var Trace = require(\'bespin:util/stacktrace\').Trace;\n +var catalog = require(\'bespin:plugins\').catalog;\n +\n +/**\n + * Current requirements are around displaying the command line, and provision\n + * of a \'history\' command and cursor up|down navigation of history.\n + * <p>Future requirements could include:\n + * <ul>\n + * <li>Multiple command lines\n + * <li>The ability to recall key presses (i.e. requests with no output) which\n + * will likely be needed for macro recording or similar\n + * <li>The ability to store the command history either on the server or in the\n + * browser local storage.\n + * </ul>\n + * <p>The execute() command doesn\'t really live here, except as part of that\n + * last future requirement, and because it doesn\'t really have anywhere else to\n + * live.\n + */\n +\n +/**\n + * The array of requests that wish to announce their presence\n + */\n +exports.requests = [];\n +\n +/**\n + * How many requests do we store?\n + */\n +var maxRequestLength = 100;\n +\n +/**\n + * Called by Request instances when some output (or a cell to async() happens)\n + */\n +exports.addRequestOutput = function(request) {\n + exports.requests.push(request);\n + // This could probably be optimized with some maths, but 99.99% of the\n + // time we will only be off by one, and I\'m feeling lazy.\n + while (exports.requests.length > maxRequestLength) {\n + exports.requests.shiftObject();\n + }\n +\n + catalog.publish(this, \'addedRequestOutput\', null, request);\n +};\n +\n +/**\n + * Execute a new command.\n + * This is basically an error trapping wrapper around request.command(...)\n + */\n +exports.execute = function(args, request) {\n + // Check the function pointed to in the meta-data exists\n + if (!request.command) {\n + request.doneWithError(\'Command not found.\');\n + return;\n + }\n +\n + try {\n + request.command(args, request);\n + } catch (ex) {\n + var trace = new Trace(ex, true);\n + console.group(\'Error executing command \\\'\' + request.typed + \'\\\'\');\n + console.log(\'command=\', request.commandExt);\n + console.log(\'args=\', args);\n + console.error(ex);\n + trace.log(3);\n + console.groupEnd();\n +\n + request.doneWithError(ex);\n + }\n +};\n +\n +});\n +\n +bespin.tiki.module("canon:request",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var Event = require(\'events\').Event;\n +var history = require(\'canon:history\');\n +\n +/**\n + * To create an invocation, you need to do something like this (all the ctor\n + * args are optional):\n + * <pre>\n + * var request = new Request({\n + * command: command,\n + * commandExt: commandExt,\n + * args: args,\n + * typed: typed\n + * });\n + * </pre>\n + */\n +exports.Request = function(options) {\n + options = options || {};\n +\n + // Will be used in the keyboard case and the cli case\n + this.command = options.command;\n + this.commandExt = options.commandExt;\n +\n + // Will be used only in the cli case\n + this.args = options.args;\n + this.typed = options.typed;\n +\n + // Have we been initialized?\n + this._begunOutput = false;\n +\n + this.start = new Date();\n + this.end = null;\n + this.completed = false;\n + this.error = false;\n +\n + this.changed = new Event();\n +};\n +\n +/**\n + * Lazy init to register with the history should only be done on output.\n + * init() is expensive, and won\'t be used in the majority of cases\n + */\n +exports.Request.prototype._beginOutput = function() {\n + this._begunOutput = true;\n + this.outputs = [];\n +\n + history.addRequestOutput(this);\n +};\n +\n +/**\n + * Sugar for:\n + * <pre>request.error = true; request.done(output);</pre>\n + */\n +exports.Request.prototype.doneWithError = function(content) {\n + this.error = true;\n + this.done(content);\n +};\n +\n +/**\n + * Declares that this function will not be automatically done when\n + * the command exits\n + */\n +exports.Request.prototype.async = function() {\n + if (!this._begunOutput) {\n + this._beginOutput();\n + }\n +};\n +\n +/**\n + * Complete the currently executing command with successful output.\n + * @param output Either DOM node, an SproutCore element or something that\n + * can be used in the content of a DIV to create a DOM node.\n + */\n +exports.Request.prototype.output = function(content) {\n + if (!this._begunOutput) {\n + this._beginOutput();\n + }\n +\n + if (typeof content !== \'string\' && !(content instanceof Node)) {\n + content = content.toString();\n + }\n +\n + this.outputs.push(content);\n + this.changed();\n +\n + return this;\n +};\n +\n +/**\n + * All commands that do output must call this to indicate that the command\n + * has finished execution.\n + */\n +exports.Request.prototype.done = function(content) {\n + this.completed = true;\n + this.end = new Date();\n + this.duration = this.end.getTime() - this.start.getTime();\n +\n + if (content) {\n + this.output(content);\n + } else {\n + this.changed();\n + }\n +};\n +\n +});\n +\n +bespin.tiki.module("canon:index",function(require,exports,module) {\n +\n +});\n +;bespin.tiki.register("::syntax_directory", {\n + name: "syntax_directory",\n + dependencies: { }\n +});\n +bespin.tiki.module("syntax_directory:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "Catalogs the available syntax engines",\n + "dependencies": {},\n + "environments": { "main": true, "worker": true },\n + "provides": [\n + {\n + "ep": "extensionhandler",\n + "name": "syntax",\n + "register": "#discoveredNewSyntax"\n + }\n + ]\n +});\n +"end";\n +\n +var plugins = require("bespin:plugins");\n +\n +function SyntaxInfo(ext) {\n + this.extension = ext;\n + this.name = ext.name;\n + this.fileExts = ext.hasOwnProperty(\'fileexts\') ? ext.fileexts : [];\n +}\n +\n +/**\n + * Stores metadata for all of the syntax plugins.\n + *\n + * @exports syntaxDirectory as syntax_directory:syntaxDirectory\n + */\n +var syntaxDirectory = {\n + _fileExts: {},\n + _syntaxInfo: {},\n +\n + get: function(syntaxName) {\n + return this._syntaxInfo[syntaxName];\n + },\n +\n + hasSyntax: function(syntax) {\n + return this._syntaxInfo.hasOwnProperty(syntax);\n + },\n +\n + register: function(extension) {\n + var syntaxInfo = new SyntaxInfo(extension);\n + this._syntaxInfo[syntaxInfo.name] = syntaxInfo;\n +\n + var fileExts = this._fileExts;\n + syntaxInfo.fileExts.forEach(function(fileExt) {\n + fileExts[fileExt] = syntaxInfo.name;\n + });\n + },\n +\n + syntaxForFileExt: function(fileExt) {\n + fileExt = fileExt.toLowerCase();\n + var fileExts = this._fileExts;\n + return fileExts.hasOwnProperty(fileExt) ? fileExts[fileExt] : \'plain\';\n + }\n +};\n +\n +function discoveredNewSyntax(syntaxExtension) {\n + syntaxDirectory.register(syntaxExtension);\n +}\n +\n +exports.syntaxDirectory = syntaxDirectory;\n +exports.discoveredNewSyntax = discoveredNewSyntax;\n +\n +\n +});\n +;bespin.tiki.register("::environment", {\n + name: "environment",\n + dependencies: { "settings": "0.0.0" }\n +});\n +bespin.tiki.module("environment:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "dependencies": {\n + "settings": "0.0.0"\n + }\n +});\n +"end";\n +\n +var util = require(\'bespin:util/util\');\n +var console = require(\'bespin:console\').console;\n +var catalog = require("bespin:plugins").catalog;\n +var settings = require(\'settings\').settings;\n +\n +/**\n + * The environment plays a similar role to the environment under unix.\n + * Bespin does not currently have a concept of variables, (i.e. things the user\n + * directly changes, however it does have a number of pre-defined things that\n + * are changed by the system.\n + * <p>The role of the Environment is likely to be expanded over time.\n + */\n +exports.Environment = function() {\n + // The current command line pushes this value into here\n + this.commandLine = null;\n +\n + // Fire the sizeChanged event when the window is resized.\n + window.addEventListener(\'resize\', this.dimensionsChanged.bind(this), false);\n +};\n +\n +Object.defineProperties(exports.Environment.prototype, {\n +\n + /**\n + * Provides a get() and set() function to set and get settings.\n + */\n + settings: {\n + value: {\n + set: function(key, value) {\n + if (util.none(key)) {\n + throw new Error(\'setSetting(): key must be supplied\');\n + }\n + if (util.none(value)) {\n + throw new Error(\'setSetting(): value must be supplied\');\n + }\n +\n + settings.set(key, value);\n + },\n + \n + get: function(key) {\n + if (util.none(key)) {\n + throw new Error(\'getSetting(): key must be supplied\');\n + }\n + return settings.get(key);\n + }\n + }\n + },\n +\n + dimensionsChanged: {\n + value: function() {\n + catalog.publish(this, \'dimensionsChanged\');\n + }\n + },\n +\n + /**\n + * Retrieves the EditSession\n + */\n + session: {\n + get: function() {\n + return catalog.getObject(\'session\');\n + }\n + },\n +\n + /**\n + * Gets the currentView from the session.\n + */\n + view: {\n + get: function() {\n + if (!this.session) {\n + // This can happen if the session is being reloaded.\n + return null;\n + }\n + return this.session.currentView;\n + }\n + },\n +\n + /**\n + * Gets the currentEditor from the session.\n + */\n + editor: {\n + get: function() {\n + if (!this.session) {\n + // This can happen if the session is being reloaded.\n + return null;\n + }\n + return this.session.currentView.editor;\n + }\n + },\n +\n + /**\n + * Returns the currently-active syntax contexts.\n + */\n + contexts: {\n + get: function() {\n + // when editorapp is being refreshed, the textView is not available.\n + if (!this.view) {\n + return [];\n + }\n +\n + var syntaxManager = this.view.editor.layoutManager.syntaxManager;\n + var pos = this.view.getSelectedRange().start;\n + return syntaxManager.contextsAtPosition(pos);\n + }\n + },\n +\n + /**\n + * The current Buffer from the session\n + */\n + buffer: {\n + get: function() {\n + if (!this.session) {\n + console.error("command attempted to get buffer but there\'s no session");\n + return undefined;\n + }\n + return this.view.editor.buffer;\n + }\n + },\n +\n + /**\n + * The current editor model might not always be easy to find so you should\n + * use <code>instruction.model</code> to access the view where\n + * possible.\n + */\n + model: {\n + get: function() {\n + if (!this.buffer) {\n + console.error(\'Session has no current buffer\');\n + return undefined;\n + }\n + return this.view.editor.layoutManager.textStorage;\n + }\n + },\n +\n + /**\n + * gets the current file from the session\n + */\n + file: {\n + get: function() {\n + if (!this.buffer) {\n + console.error(\'Session has no current buffer\');\n + return undefined;\n + }\n + return this.buffer.file;\n + }\n + },\n +\n + /**\n + * If files are available, this will get them. Perhaps we need some other\n + * mechanism for populating these things from the catalog?\n + */\n + files: {\n + get: function() {\n + return catalog.getObject(\'files\');\n + }\n + }\n +});\n +\n +/**\n + * The global environment used throughout this Bespin instance.\n + */\n +exports.env = new exports.Environment();\n +\n +});\n +;bespin.tiki.register("::traits", {\n + name: "traits",\n + dependencies: { }\n +});\n +bespin.tiki.module("traits:index",function(require,exports,module) {\n +// Copyright (C) 2010 Google Inc.\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 +// See http://code.google.com/p/es-lab/wiki/Traits\n +// for background on traits and a description of this library\n +\n +"define metadata";\n +({\n + "description": "Traits library, traitsjs.org",\n + "dependencies": {},\n + "provides": []\n +});\n +"end";\n +\n +// --- Begin traits-0.1.js ---\n +\n +exports.Trait = (function(){\n +\n + // == Ancillary functions ==\n + \n + // this signals that the current ES implementation supports properties,\n + // so probably also accessor properties\n + var SUPPORTS_DEFINEPROP = !!Object.defineProperty;\n +\n + var call = Function.prototype.call;\n +\n + /**\n + * An ad hoc version of bind that only binds the \'this\' parameter.\n + */\n + var bindThis = Function.prototype.bind\n + ? function(fun, self) { return Function.prototype.bind.call(fun, self); }\n + : function(fun, self) {\n + function funcBound(var_args) {\n + return fun.apply(self, arguments);\n + }\n + return funcBound;\n + };\n +\n + var hasOwnProperty = bindThis(call, Object.prototype.hasOwnProperty);\n + var slice = bindThis(call, Array.prototype.slice);\n + \n + // feature testing such that traits.js runs on both ES3 and ES5\n + var forEach = Array.prototype.forEach\n + ? bindThis(call, Array.prototype.forEach)\n + : function(arr, fun) {\n + for (var i = 0, len = arr.length; i < len; i++) { fun(arr[i]); }\n + };\n + \n + var freeze = Object.freeze || function(obj) { return obj; };\n + var getPrototypeOf = Object.getPrototypeOf || function(obj) { return Object.prototype };\n + var getOwnPropertyNames = Object.getOwnPropertyNames ||\n + function(obj) {\n + var props = [];\n + for (var p in obj) { if (hasOwnProperty(obj,p)) { props.push(p); } }\n + return props;\n + };\n + var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor ||\n + function(obj, name) {\n + return {\n + value: obj[name],\n + enumerable: true,\n + writable: true,\n + configurable: true\n + };\n + };\n + var defineProperty = Object.defineProperty ||\n + function(obj, name, pd) {\n + obj[name] = pd.value;\n + };\n + var defineProperties = Object.defineProperties ||\n + function(obj, propMap) {\n + for (var name in propMap) {\n + if (hasOwnProperty(propMap, name)) {\n + defineProperty(obj, name, propMap[name]);\n + }\n + }\n + };\n + var Object_create = Object.create ||\n + function(proto, propMap) {\n + var self;\n + function dummy() {};\n + dummy.prototype = proto || Object.prototype;\n + self = new dummy();\n + if (propMap) {\n + defineProperties(self, propMap); \n + }\n + return self;\n + };\n + var getOwnProperties = Object.getOwnProperties ||\n + function(obj) {\n + var map = {};\n + forEach(getOwnPropertyNames(obj), function (name) {\n + map[name] = getOwnPropertyDescriptor(obj, name);\n + });\n + return map;\n + };\n + \n + // end of ES3 - ES5 compatibility functions\n + \n + function makeConflictAccessor(name) {\n + var accessor = function(var_args) {\n + throw new Error("Conflicting property: "+name);\n + };\n + freeze(accessor.prototype);\n + return freeze(accessor);\n + };\n +\n + function makeRequiredPropDesc(name) {\n + return freeze({\n + value: undefined,\n + enumerable: false,\n + required: true\n + });\n + }\n + \n + function makeConflictingPropDesc(name) {\n + var conflict = makeConflictAccessor(name);\n + if (SUPPORTS_DEFINEPROP) {\n + return freeze({\n + get: conflict,\n + set: conflict,\n + enumerable: false,\n + conflict: true\n + }); \n + } else {\n + return freeze({\n + value: conflict,\n + enumerable: false,\n + conflict: true\n + });\n + }\n + }\n + \n + /**\n + * Are x and y not observably distinguishable?\n + */\n + function identical(x, y) {\n + if (x === y) {\n + // 0 === -0, but they are not identical\n + return x !== 0 || 1/x === 1/y;\n + } else {\n + // NaN !== NaN, but they are identical.\n + // NaNs are the only non-reflexive value, i.e., if x !== x,\n + // then x is a NaN.\n + return x !== x && y !== y;\n + }\n + }\n +\n + // Note: isSameDesc should return true if both\n + // desc1 and desc2 represent a \'required\' property\n + // (otherwise two composed required properties would be turned into a conflict)\n + function isSameDesc(desc1, desc2) {\n + // for conflicting properties, don\'t compare values because\n + // the conflicting property values are never equal\n + if (desc1.conflict && desc2.conflict) {\n + return true;\n + } else {\n + return ( desc1.get === desc2.get\n + && desc1.set === desc2.set\n + && identical(desc1.value, desc2.value)\n + && desc1.enumerable === desc2.enumerable\n + && desc1.required === desc2.required\n + && desc1.conflict === desc2.conflict); \n + }\n + }\n + \n + function freezeAndBind(meth, self) {\n + return freeze(bindThis(meth, self));\n + }\n +\n + /* makeSet([\'foo\', ...]) => { foo: true, ...}\n + *\n + * makeSet returns an object whose own properties represent a set.\n + *\n + * Each string in the names array is added to the set.\n + *\n + * To test whether an element is in the set, perform:\n + * hasOwnProperty(set, element)\n + */\n + function makeSet(names) {\n + var set = {};\n + forEach(names, function (name) {\n + set[name] = true;\n + });\n + return freeze(set);\n + }\n +\n + // == singleton object to be used as the placeholder for a required property ==\n + \n + var required = freeze({ toString: function() { return \'<Trait.required>\'; } });\n +\n + // == The public API methods ==\n +\n + /**\n + * var newTrait = trait({ foo:required, ... })\n + *\n + * @param object an object record (in principle an object literal)\n + * @returns a new trait describing all of the own properties of the object\n + * (both enumerable and non-enumerable)\n + *\n + * As a general rule, \'trait\' should be invoked with an\n + * object literal, since the object merely serves as a record\n + * descriptor. Both its identity and its prototype chain are irrelevant.\n + * \n + * Data properties bound to function objects in the argument will be flagged\n + * as \'method\' properties. The prototype of these function objects is frozen.\n + * \n + * Data properties bound to the \'required\' singleton exported by this module\n + * will be marked as \'required\' properties.\n + *\n + * The <tt>trait</tt> function is pure if no other code can witness the\n + * side-effects of freezing the prototypes of the methods. If <tt>trait</tt>\n + * is invoked with an object literal whose methods are represented as\n + * in-place anonymous functions, this should normally be the case.\n + */\n + function trait(obj) {\n + var map = {};\n + forEach(getOwnPropertyNames(obj), function (name) {\n + var pd = getOwnPropertyDescriptor(obj, name);\n + if (pd.value === required) {\n + pd = makeRequiredPropDesc(name);\n + } else if (typeof pd.value === \'function\') {\n + pd.method = true;\n + if (\'prototype\' in pd.value) {\n + freeze(pd.value.prototype);\n + }\n + } else {\n + if (pd.get && pd.get.prototype) { freeze(pd.get.prototype); }\n + if (pd.set && pd.set.prototype) { freeze(pd.set.prototype); }\n + }\n + map[name] = pd;\n + });\n + return map;\n + }\n +\n + /**\n + * var newTrait = compose(trait_1, trait_2, ..., trait_N)\n + *\n + * @param trait_i a trait object\n + * @returns a new trait containing the combined own properties of\n + * all the trait_i.\n + * \n + * If two or more traits have own properties with the same name, the new\n + * trait will contain a \'conflict\' property for that name. \'compose\' is\n + * a commutative and associative operation, and the order of its\n + * arguments is not significant.\n + *\n + * If \'compose\' is invoked with < 2 arguments, then:\n + * compose(trait_1) returns a trait equivalent to trait_1\n + * compose() returns an empty trait\n + */\n + function compose(var_args) {\n + var traits = slice(arguments, 0);\n + var newTrait = {};\n + \n + forEach(traits, function (trait) {\n + forEach(getOwnPropertyNames(trait), function (name) {\n + var pd = trait[name];\n + if (hasOwnProperty(newTrait, name) &&\n + !newTrait[name].required) {\n + \n + // a non-required property with the same name was previously defined\n + // this is not a conflict if pd represents a \'required\' property itself:\n + if (pd.required) {\n + return; // skip this property, the required property is now present\n + }\n + \n + if (!isSameDesc(newTrait[name], pd)) {\n + // a distinct, non-required property with the same name\n + // was previously defined by another trait => mark as conflicting property\n + newTrait[name] = makeConflictingPropDesc(name); \n + } // else,\n + // properties are not in conflict if they refer to the same value\n + \n + } else {\n + newTrait[name] = pd;\n + }\n + });\n + });\n + \n + return freeze(newTrait);\n + }\n +\n + /* var newTrait = exclude([\'name\', ...], trait)\n + *\n + * @param names a list of strings denoting property names.\n + * @param trait a trait some properties of which should be excluded.\n + * @returns a new trait with the same own properties as the original trait,\n + * except that all property names appearing in the first argument\n + * are replaced by required property descriptors.\n + *\n + * Note: exclude(A, exclude(B,t)) is equivalent to exclude(A U B, t)\n + */\n + function exclude(names, trait) {\n + var exclusions = makeSet(names);\n + var newTrait = {};\n + \n + forEach(getOwnPropertyNames(trait), function (name) {\n + // required properties are not excluded but ignored\n + if (!hasOwnProperty(exclusions, name) || trait[name].required) {\n + newTrait[name] = trait[name];\n + } else {\n + // excluded properties are replaced by required properties\n + newTrait[name] = makeRequiredPropDesc(name);\n + }\n + });\n + \n + return freeze(newTrait);\n + }\n +\n + /**\n + * var newTrait = override(trait_1, trait_2, ..., trait_N)\n + *\n + * @returns a new trait with all of the combined properties of the argument traits.\n + * In contrast to \'compose\', \'override\' immediately resolves all conflicts\n + * resulting from this composition by overriding the properties of later\n + * traits. Trait priority is from left to right. I.e. the properties of the\n + * leftmost trait are never overridden.\n + *\n + * override is associative:\n + * override(t1,t2,t3) is equivalent to override(t1, override(t2, t3)) or\n + * to override(override(t1, t2), t3)\n + * override is not commutative: override(t1,t2) is not equivalent to override(t2,t1)\n + *\n + * override() returns an empty trait\n + * override(trait_1) returns a trait equivalent to trait_1\n + */\n + function override(var_args) {\n + var traits = slice(arguments, 0);\n + var newTrait = {};\n + forEach(traits, function (trait) {\n + forEach(getOwnPropertyNames(trait), function (name) {\n + var pd = trait[name];\n + // add this trait\'s property to the composite trait only if\n + // - the trait does not yet have this property\n + // - or, the trait does have the property, but it\'s a required property\n + if (!hasOwnProperty(newTrait, name) || newTrait[name].required) {\n + newTrait[name] = pd;\n + }\n + });\n + });\n + return freeze(newTrait);\n + }\n + \n + /**\n + * var newTrait = override(dominantTrait, recessiveTrait)\n + *\n + * @returns a new trait with all of the properties of dominantTrait\n + * and all of the properties of recessiveTrait not in dominantTrait\n + *\n + * Note: override is associative:\n + * override(t1, override(t2, t3)) is equivalent to override(override(t1, t2), t3)\n + */\n + /*function override(frontT, backT) {\n + var newTrait = {};\n + // first copy all of backT\'s properties into newTrait\n + forEach(getOwnPropertyNames(backT), function (name) {\n + newTrait[name] = backT[name];\n + });\n + // now override all these properties with frontT\'s properties\n + forEach(getOwnPropertyNames(frontT), function (name) {\n + var pd = frontT[name];\n + // frontT\'s required property does not override the provided property\n + if (!(pd.required && hasOwnProperty(newTrait, name))) {\n + newTrait[name] = pd; \n + } \n + });\n + \n + return freeze(newTrait);\n + }*/\n +\n + /**\n + * var newTrait = rename(map, trait)\n + *\n + * @param map an object whose own properties serve as a mapping from\n + old names to new names.\n + * @param trait a trait object\n + * @returns a new trait with the same properties as the original trait,\n + * except that all properties whose name is an own property\n + * of map will be renamed to map[name], and a \'required\' property\n + * for name will be added instead.\n + *\n + * rename({a: \'b\'}, t) eqv compose(exclude([\'a\'],t),\n + * { a: { required: true },\n + * b: t[a] })\n + *\n + * For each renamed property, a required property is generated.\n + * If the map renames two properties to the same name, a conflict is generated.\n + * If the map renames a property to an existing unrenamed property, a conflict is generated.\n + *\n + * Note: rename(A, rename(B, t)) is equivalent to rename(\\n -> A(B(n)), t)\n + * Note: rename({...},exclude([...], t)) is not eqv to exclude([...],rename({...}, t))\n + */\n + function rename(map, trait) {\n + var renamedTrait = {};\n + forEach(getOwnPropertyNames(trait), function (name) {\n + // required props are never renamed\n + if (hasOwnProperty(map, name) && !trait[name].required) {\n + var alias = map[name]; // alias defined in map\n + if (hasOwnProperty(renamedTrait, alias) && !renamedTrait[alias].required) {\n + // could happen if 2 props are mapped to the same alias\n + renamedTrait[alias] = makeConflictingPropDesc(alias);\n + } else {\n + // add the property under an alias\n + renamedTrait[alias] = trait[name];\n + }\n + // add a required property under the original name\n + // but only if a property under the original name does not exist\n + // such a prop could exist if an earlier prop in the trait was previously\n + // aliased to this name\n + if (!hasOwnProperty(renamedTrait, name)) {\n + renamedTrait[name] = makeRequiredPropDesc(name); \n + }\n + } else { // no alias defined\n + if (hasOwnProperty(renamedTrait, name)) {\n + // could happen if another prop was previously aliased to name\n + if (!trait[name].required) {\n + renamedTrait[name] = makeConflictingPropDesc(name); \n + }\n + // else required property overridden by a previously aliased property\n + // and otherwise ignored\n + } else {\n + renamedTrait[name] = trait[name];\n + }\n + }\n + });\n + \n + return freeze(renamedTrait);\n + }\n + \n + /**\n + * var newTrait = resolve({ oldName: \'newName\', excludeName: undefined, ... }, trait)\n + *\n + * This is a convenience function combining renaming and exclusion. It can be implemented\n + * as <tt>rename(map, exclude(exclusions, trait))</tt> where map is the subset of\n + * mappings from oldName to newName and exclusions is an array of all the keys that map\n + * to undefined (or another falsy value).\n + *\n + * @param resolutions an object whose own properties serve as a mapping from\n + old names to new names, or to undefined if the property should be excluded\n + * @param trait a trait object\n + * @returns a resolved trait with the same own properties as the original trait.\n + *\n + * In a resolved trait, all own properties whose name is an own property\n + * of resolutions will be renamed to resolutions[name] if it is truthy,\n + * or their value is changed into a required property descriptor if\n + * resolutions[name] is falsy.\n + *\n + * Note, it\'s important to _first_ exclude, _then_ rename, since exclude\n + * and rename are not associative, for example:\n + * rename({a: \'b\'}, exclude([\'b\'], trait({ a:1,b:2 }))) eqv trait({b:1})\n + * exclude([\'b\'], rename({a: \'b\'}, trait({ a:1,b:2 }))) eqv trait({b:Trait.required})\n + *\n + * writing resolve({a:\'b\', b: undefined},trait({a:1,b:2})) makes it clear that\n + * what is meant is to simply drop the old \'b\' and rename \'a\' to \'b\'\n + */\n + function resolve(resolutions, trait) {\n + var renames = {};\n + var exclusions = [];\n + // preprocess renamed and excluded properties\n + for (var name in resolutions) {\n + if (hasOwnProperty(resolutions, name)) {\n + if (resolutions[name]) { // old name -> new name\n + renames[name] = resolutions[name];\n + } else { // name -> undefined\n + exclusions.push(name);\n + }\n + }\n + }\n + return rename(renames, exclude(exclusions, trait));\n + }\n +\n + /**\n + * var obj = create(proto, trait)\n + *\n + * @param proto denotes the prototype of the completed object\n + * @param trait a trait object to be turned into a complete object\n + * @returns an object with all of the properties described by the trait.\n + * @throws \'Missing required property\' the trait still contains a required property.\n + * @throws \'Remaining conflicting property\' if the trait still contains a conflicting property.\n + *\n + * Trait.create is like Object.create, except that it generates\n + * high-integrity or final objects. In addition to creating a new object\n + * from a trait, it also ensures that:\n + * - an exception is thrown if \'trait\' still contains required properties\n + * - an exception is thrown if \'trait\' still contains conflicting properties\n + * - the object is and all of its accessor and method properties are frozen\n + * - the \'this\' pseudovariable in all accessors and methods of the object is\n + * bound to the composed object.\n + *\n + * Use Object.create instead of Trait.create if you want to create\n + * abstract or malleable objects. Keep in mind that for such objects:\n + * - no exception is thrown if \'trait\' still contains required properties\n + * (the properties are simply dropped from the composite object)\n + * - no exception is thrown if \'trait\' still contains conflicting properties\n + * (these properties remain as conflicting properties in the composite object)\n + * - neither the object nor its accessor and method properties are frozen\n + * - the \'this\' pseudovariable in all accessors and methods of the object is\n + * left unbound.\n + */\n + function create(proto, trait) {\n + var self = Object_create(proto);\n + var properties = {};\n + \n + forEach(getOwnPropertyNames(trait), function (name) {\n + var pd = trait[name];\n + // check for remaining \'required\' properties\n + // Note: it\'s OK for the prototype to provide the properties\n + if (pd.required && !(name in proto)) {\n + throw new Error(\'Missing required property: \'+name);\n + } else if (pd.conflict) { // check for remaining conflicting properties\n + throw new Error(\'Remaining conflicting property: \'+name);\n + } else if (\'value\' in pd) { // data property\n + // freeze all function properties and their prototype\n + if (pd.method) { // the property is meant to be used as a method\n + // bind \'this\' in trait method to the composite object\n + properties[name] = {\n + value: freezeAndBind(pd.value, self),\n + enumerable: pd.enumerable,\n + configurable: pd.configurable,\n + writable: pd.writable\n + };\n + } else {\n + properties[name] = pd;\n + }\n + } else { // accessor property\n + properties[name] = {\n + get: pd.get ? freezeAndBind(pd.get, self) : undefined,\n + set: pd.set ? freezeAndBind(pd.set, self) : undefined,\n + enumerable: pd.enumerable,\n + configurable: pd.configurable,\n + writable: pd.writable \n + };\n + }\n + });\n +\n + defineProperties(self, properties);\n + return freeze(self);\n + }\n +\n + /** A shorthand for create(Object.prototype, trait({...}), options) */\n + function object(record, options) {\n + return create(Object.prototype, trait(record), options);\n + }\n +\n + /**\n + * Tests whether two traits are equivalent. T1 is equivalent to T2 iff\n + * both describe the same set of property names and for all property\n + * names n, T1[n] is equivalent to T2[n]. Two property descriptors are\n + * equivalent if they have the same value, accessors and attributes.\n + *\n + * @return a boolean indicating whether the two argument traits are equivalent.\n + */\n + function eqv(trait1, trait2) {\n + var names1 = getOwnPropertyNames(trait1);\n + var names2 = getOwnPropertyNames(trait2);\n + var name;\n + if (names1.length !== names2.length) {\n + return false;\n + }\n + for (var i = 0; i < names1.length; i++) {\n + name = names1[i];\n + if (!trait2[name] || !isSameDesc(trait1[name], trait2[name])) {\n + return false;\n + }\n + }\n + return true;\n + }\n + \n + // if this code is ran in ES3 without an Object.create function, this\n + // library will define it on Object:\n + if (!Object.create) {\n + Object.create = Object_create;\n + }\n + // ES5 does not by default provide Object.getOwnProperties\n + // if it\'s not defined, the Traits library defines this utility function on Object\n + if(!Object.getOwnProperties) {\n + Object.getOwnProperties = getOwnProperties;\n + }\n + \n + // expose the public API of this module\n + function Trait(record) {\n + // calling Trait as a function creates a new atomic trait\n + return trait(record);\n + }\n + Trait.required = freeze(required);\n + Trait.compose = freeze(compose);\n + Trait.resolve = freeze(resolve);\n + Trait.override = freeze(override);\n + Trait.create = freeze(create);\n + Trait.eqv = freeze(eqv);\n + Trait.object = freeze(object); // not essential, cf. create + trait\n + return freeze(Trait);\n + \n +})();\n +\n +// --- End traits-0.1.js ---\n +\n +\n +});\n +;bespin.tiki.register("::underscore", {\n + name: "underscore",\n + dependencies: { }\n +});\n +bespin.tiki.module("underscore:index",function(require,exports,module) {\n +// Underscore.js\n +// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.\n +// Underscore is freely distributable under the terms of the MIT license.\n +// Portions of Underscore are inspired by or borrowed from Prototype.js,\n +// Oliver Steele\'s Functional, and John Resig\'s Micro-Templating.\n +// For all details and documentation:\n +// http://documentcloud.github.com/underscore\n +\n +"define metadata";\n +({\n + "description": "Functional Programming Aid for Javascript. Works well with jQuery."\n +});\n +"end";\n +\n +(function() {\n + // ------------------------- Baseline setup ---------------------------------\n +\n + // Establish the root object, "window" in the browser, or "global" on the server.\n + var root = this;\n +\n + // Save the previous value of the "_" variable.\n + var previousUnderscore = root._;\n +\n + // Establish the object that gets thrown to break out of a loop iteration.\n + var breaker = typeof StopIteration !== \'undefined\' ? StopIteration : \'__break__\';\n +\n + // Quick regexp-escaping function, because JS doesn\'t have RegExp.escape().\n + var escapeRegExp = function(s) { return s.replace(/([.*+?^${}()|[\\]\\/\\\\])/g, \'\\\\$1\'); };\n +\n + // Save bytes in the minified (but not gzipped) version:\n + var ArrayProto = Array.prototype, ObjProto = Object.prototype;\n +\n + // Create quick reference variables for speed access to core prototypes.\n + var slice = ArrayProto.slice,\n + unshift = ArrayProto.unshift,\n + toString = ObjProto.toString,\n + hasOwnProperty = ObjProto.hasOwnProperty,\n + propertyIsEnumerable = ObjProto.propertyIsEnumerable;\n +\n + // All ECMA5 native implementations we hope to use are declared here.\n + var\n + nativeForEach = ArrayProto.forEach,\n + nativeMap = ArrayProto.map,\n + nativeReduce = ArrayProto.reduce,\n + nativeReduceRight = ArrayProto.reduceRight,\n + nativeFilter = ArrayProto.filter,\n + nativeEvery = ArrayProto.every,\n + nativeSome = ArrayProto.some,\n + nativeIndexOf = ArrayProto.indexOf,\n + nativeLastIndexOf = ArrayProto.lastIndexOf,\n + nativeIsArray = Array.isArray,\n + nativeKeys = Object.keys;\n +\n + // Create a safe reference to the Underscore object for use below.\n + var _ = function(obj) { return new wrapper(obj); };\n +\n + // Export the Underscore object for CommonJS.\n + if (typeof exports !== \'undefined\') exports._ = _;\n +\n + // Export underscore to global scope.\n + root._ = _;\n +\n + // Current version.\n + _.VERSION = \'1.0.2\';\n +\n + // ------------------------ Collection Functions: ---------------------------\n +\n + // The cornerstone, an each implementation.\n + // Handles objects implementing forEach, arrays, and raw objects.\n + // Delegates to JavaScript 1.6\'s native forEach if available.\n + var each = _.forEach = function(obj, iterator, context) {\n + try {\n + if (nativeForEach && obj.forEach === nativeForEach) {\n + obj.forEach(iterator, context);\n + } else if (_.isNumber(obj.length)) {\n + for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);\n + } else {\n + for (var key in obj) {\n + if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);\n + }\n + }\n + } catch(e) {\n + if (e != breaker) throw e;\n + }\n + return obj;\n + };\n +\n + // Return the results of applying the iterator to each element.\n + // Delegates to JavaScript 1.6\'s native map if available.\n + _.map = function(obj, iterator, context) {\n + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n + var results = [];\n + each(obj, function(value, index, list) {\n + results.push(iterator.call(context, value, index, list));\n + });\n + return results;\n + };\n +\n + // Reduce builds up a single result from a list of values, aka inject, or foldl.\n + // Delegates to JavaScript 1.8\'s native reduce if available.\n + _.reduce = function(obj, memo, iterator, context) {\n + if (nativeReduce && obj.reduce === nativeReduce) return obj.reduce(_.bind(iterator, context), memo);\n + each(obj, function(value, index, list) {\n + memo = iterator.call(context, memo, value, index, list);\n + });\n + return memo;\n + };\n +\n + // The right-associative version of reduce, also known as foldr. Uses\n + // Delegates to JavaScript 1.8\'s native reduceRight if available.\n + _.reduceRight = function(obj, memo, iterator, context) {\n + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo);\n + var reversed = _.clone(_.toArray(obj)).reverse();\n + return _.reduce(reversed, memo, iterator, context);\n + };\n +\n + // Return the first value which passes a truth test.\n + _.detect = function(obj, iterator, context) {\n + var result;\n + each(obj, function(value, index, list) {\n + if (iterator.call(context, value, index, list)) {\n + result = value;\n + _.breakLoop();\n + }\n + });\n + return result;\n + };\n +\n + // Return all the elements that pass a truth test.\n + // Delegates to JavaScript 1.6\'s native filter if available.\n + _.filter = function(obj, iterator, context) {\n + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n + var results = [];\n + each(obj, function(value, index, list) {\n + iterator.call(context, value, index, list) && results.push(value);\n + });\n + return results;\n + };\n +\n + // Return all the elements for which a truth test fails.\n + _.reject = function(obj, iterator, context) {\n + var results = [];\n + each(obj, function(value, index, list) {\n + !iterator.call(context, value, index, list) && results.push(value);\n + });\n + return results;\n + };\n +\n + // Determine whether all of the elements match a truth test.\n + // Delegates to JavaScript 1.6\'s native every if available.\n + _.every = function(obj, iterator, context) {\n + iterator = iterator || _.identity;\n + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n + var result = true;\n + each(obj, function(value, index, list) {\n + if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();\n + });\n + return result;\n + };\n +\n + // Determine if at least one element in the object matches a truth test.\n + // Delegates to JavaScript 1.6\'s native some if available.\n + _.some = function(obj, iterator, context) {\n + iterator = iterator || _.identity;\n + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n + var result = false;\n + each(obj, function(value, index, list) {\n + if (result = iterator.call(context, value, index, list)) _.breakLoop();\n + });\n + return result;\n + };\n +\n + // Determine if a given value is included in the array or object using \'===\'.\n + _.include = function(obj, target) {\n + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n + var found = false;\n + each(obj, function(value) {\n + if (found = value === target) _.breakLoop();\n + });\n + return found;\n + };\n +\n + // Invoke a method with arguments on every item in a collection.\n + _.invoke = function(obj, method) {\n + var args = _.rest(arguments, 2);\n + return _.map(obj, function(value) {\n + return (method ? value[method] : value).apply(value, args);\n + });\n + };\n +\n + // Convenience version of a common use case of map: fetching a property.\n + _.pluck = function(obj, key) {\n + return _.map(obj, function(value){ return value[key]; });\n + };\n +\n + // Return the maximum item or (item-based computation).\n + _.max = function(obj, iterator, context) {\n + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);\n + var result = {computed : -Infinity};\n + each(obj, function(value, index, list) {\n + var computed = iterator ? iterator.call(context, value, index, list) : value;\n + computed >= result.computed && (result = {value : value, computed : computed});\n + });\n + return result.value;\n + };\n +\n + // Return the minimum element (or element-based computation).\n + _.min = function(obj, iterator, context) {\n + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);\n + var result = {computed : Infinity};\n + each(obj, function(value, index, list) {\n + var computed = iterator ? iterator.call(context, value, index, list) : value;\n + computed < result.computed && (result = {value : value, computed : computed});\n + });\n + return result.value;\n + };\n +\n + // Sort the object\'s values by a criterion produced by an iterator.\n + _.sortBy = function(obj, iterator, context) {\n + return _.pluck(_.map(obj, function(value, index, list) {\n + return {\n + value : value,\n + criteria : iterator.call(context, value, index, list)\n + };\n + }).sort(function(left, right) {\n + var a = left.criteria, b = right.criteria;\n + return a < b ? -1 : a > b ? 1 : 0;\n + }), \'value\');\n + };\n +\n + // Use a comparator function to figure out at what index an object should\n + // be inserted so as to maintain order. Uses binary search.\n + _.sortedIndex = function(array, obj, iterator) {\n + iterator = iterator || _.identity;\n + var low = 0, high = array.length;\n + while (low < high) {\n + var mid = (low + high) >> 1;\n + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;\n + }\n + return low;\n + };\n +\n + // Convert anything iterable into a real, live array.\n + _.toArray = function(iterable) {\n + if (!iterable) return [];\n + if (iterable.toArray) return iterable.toArray();\n + if (_.isArray(iterable)) return iterable;\n + if (_.isArguments(iterable)) return slice.call(iterable);\n + return _.values(iterable);\n + };\n +\n + // Return the number of elements in an object.\n + _.size = function(obj) {\n + return _.toArray(obj).length;\n + };\n +\n + // -------------------------- Array Functions: ------------------------------\n +\n + // Get the first element of an array. Passing "n" will return the first N\n + // values in the array. Aliased as "head". The "guard" check allows it to work\n + // with _.map.\n + _.first = function(array, n, guard) {\n + return n && !guard ? slice.call(array, 0, n) : array[0];\n + };\n +\n + // Returns everything but the first entry of the array. Aliased as "tail".\n + // Especially useful on the arguments object. Passing an "index" will return\n + // the rest of the values in the array from that index onward. The "guard"\n + //check allows it to work with _.map.\n + _.rest = function(array, index, guard) {\n + return slice.call(array, _.isUndefined(index) || guard ? 1 : index);\n + };\n +\n + // Get the last element of an array.\n + _.last = function(array) {\n + return array[array.length - 1];\n + };\n +\n + // Trim out all falsy values from an array.\n + _.compact = function(array) {\n + return _.filter(array, function(value){ return !!value; });\n + };\n +\n + // Return a completely flattened version of an array.\n + _.flatten = function(array) {\n + return _.reduce(array, [], function(memo, value) {\n + if (_.isArray(value)) return memo.concat(_.flatten(value));\n + memo.push(value);\n + return memo;\n + });\n + };\n +\n + // Return a version of the array that does not contain the specified value(s).\n + _.without = function(array) {\n + var values = _.rest(arguments);\n + return _.filter(array, function(value){ return !_.include(values, value); });\n + };\n +\n + // Produce a duplicate-free version of the array. If the array has already\n + // been sorted, you have the option of using a faster algorithm.\n + _.uniq = function(array, isSorted) {\n + return _.reduce(array, [], function(memo, el, i) {\n + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);\n + return memo;\n + });\n + };\n +\n + // Produce an array that contains every item shared between all the\n + // passed-in arrays.\n + _.intersect = function(array) {\n + var rest = _.rest(arguments);\n + return _.filter(_.uniq(array), function(item) {\n + return _.every(rest, function(other) {\n + return _.indexOf(other, item) >= 0;\n + });\n + });\n + };\n +\n + // Zip together multiple lists into a single array -- elements that share\n + // an index go together.\n + _.zip = function() {\n + var args = _.toArray(arguments);\n + var length = _.max(_.pluck(args, \'length\'));\n + var results = new Array(length);\n + for (var i = 0; i < length; i++) results[i] = _.pluck(args, String(i));\n + return results;\n + };\n +\n + // If the browser doesn\'t supply us with indexOf (I\'m looking at you, MSIE),\n + // we need this function. Return the position of the first occurence of an\n + // item in an array, or -1 if the item is not included in the array.\n + // Delegates to JavaScript 1.8\'s native indexOf if available.\n + _.indexOf = function(array, item) {\n + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);\n + for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;\n + return -1;\n + };\n +\n +\n + // Delegates to JavaScript 1.6\'s native lastIndexOf if available.\n + _.lastIndexOf = function(array, item) {\n + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);\n + var i = array.length;\n + while (i--) if (array[i] === item) return i;\n + return -1;\n + };\n +\n + // Generate an integer Array containing an arithmetic progression. A port of\n + // the native Python range() function. See:\n + // http://docs.python.org/library/functions.html#range\n + _.range = function(start, stop, step) {\n + var a = _.toArray(arguments);\n + var solo = a.length <= 1;\n + var start = solo ? 0 : a[0], stop = solo ? a[0] : a[1], step = a[2] || 1;\n + var len = Math.ceil((stop - start) / step);\n + if (len <= 0) return [];\n + var range = new Array(len);\n + for (var i = start, idx = 0; true; i += step) {\n + if ((step > 0 ? i - stop : stop - i) >= 0) return range;\n + range[idx++] = i;\n + }\n + };\n +\n + // ----------------------- Function Functions: ------------------------------\n +\n + // Create a function bound to a given object (assigning \'this\', and arguments,\n + // optionally). Binding with arguments is also known as \'curry\'.\n + _.bind = function(func, obj) {\n + var args = _.rest(arguments, 2);\n + return function() {\n + return func.apply(obj || {}, args.concat(_.toArray(arguments)));\n + };\n + };\n +\n + // Bind all of an object\'s methods to that object. Useful for ensuring that\n + // all callbacks defined on an object belong to it.\n + _.bindAll = function(obj) {\n + var funcs = _.rest(arguments);\n + if (funcs.length == 0) funcs = _.functions(obj);\n + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n + return obj;\n + };\n +\n + // Delays a function for the given number of milliseconds, and then calls\n + // it with the arguments supplied.\n + _.delay = function(func, wait) {\n + var args = _.rest(arguments, 2);\n + return setTimeout(function(){ return func.apply(func, args); }, wait);\n + };\n +\n + // Defers a function, scheduling it to run after the current call stack has\n + // cleared.\n + _.defer = function(func) {\n + return _.delay.apply(_, [func, 1].concat(_.rest(arguments)));\n + };\n +\n + // Returns the first function passed as an argument to the second,\n + // allowing you to adjust arguments, run code before and after, and\n + // conditionally execute the original function.\n + _.wrap = function(func, wrapper) {\n + return function() {\n + var args = [func].concat(_.toArray(arguments));\n + return wrapper.apply(wrapper, args);\n + };\n + };\n +\n + // Returns a function that is the composition of a list of functions, each\n + // consuming the return value of the function that follows.\n + _.compose = function() {\n + var funcs = _.toArray(arguments);\n + return function() {\n + var args = _.toArray(arguments);\n + for (var i=funcs.length-1; i >= 0; i--) {\n + args = [funcs[i].apply(this, args)];\n + }\n + return args[0];\n + };\n + };\n +\n + // ------------------------- Object Functions: ------------------------------\n +\n + // Retrieve the names of an object\'s properties.\n + // Delegates to ECMA5\'s native Object.keys\n + _.keys = nativeKeys || function(obj) {\n + if (_.isArray(obj)) return _.range(0, obj.length);\n + var keys = [];\n + for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key);\n + return keys;\n + };\n +\n + // Retrieve the values of an object\'s properties.\n + _.values = function(obj) {\n + return _.map(obj, _.identity);\n + };\n +\n + // Return a sorted list of the function names available on the object.\n + _.functions = function(obj) {\n + return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();\n + };\n +\n + // Extend a given object with all the properties in passed-in object(s).\n + _.extend = function(obj) {\n + each(_.rest(arguments), function(source) {\n + for (var prop in source) obj[prop] = source[prop];\n + });\n + return obj;\n + };\n +\n + // Create a (shallow-cloned) duplicate of an object.\n + _.clone = function(obj) {\n + if (_.isArray(obj)) return obj.slice(0);\n + return _.extend({}, obj);\n + };\n +\n + // Invokes interceptor with the obj, and then returns obj.\n + // The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.\n + _.tap = function(obj, interceptor) {\n + interceptor(obj);\n + return obj;\n + };\n +\n + // Perform a deep comparison to check if two objects are equal.\n + _.isEqual = function(a, b) {\n + // Check object identity.\n + if (a === b) return true;\n + // Different types?\n + var atype = typeof(a), btype = typeof(b);\n + if (atype != btype) return false;\n + // Basic equality test (watch out for coercions).\n + if (a == b) return true;\n + // One is falsy and the other truthy.\n + if ((!a && b) || (a && !b)) return false;\n + // One of them implements an isEqual()?\n + if (a.isEqual) return a.isEqual(b);\n + // Check dates\' integer values.\n + if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();\n + // Both are NaN?\n + if (_.isNaN(a) && _.isNaN(b)) return true;\n + // Compare regular expressions.\n + if (_.isRegExp(a) && _.isRegExp(b))\n + return a.source === b.source &&\n + a.global === b.global &&\n + a.ignoreCase === b.ignoreCase &&\n + a.multiline === b.multiline;\n + // If a is not an object by this point, we can\'t handle it.\n + if (atype !== \'object\') return false;\n + // Check for different array lengths before comparing contents.\n + if (a.length && (a.length !== b.length)) return false;\n + // Nothing else worked, deep compare the contents.\n + var aKeys = _.keys(a), bKeys = _.keys(b);\n + // Different object sizes?\n + if (aKeys.length != bKeys.length) return false;\n + // Recursive comparison of contents.\n + for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;\n + return true;\n + };\n +\n + // Is a given array or object empty?\n + _.isEmpty = function(obj) {\n + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n + for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;\n + return true;\n + };\n +\n + // Is a given value a DOM element?\n + _.isElement = function(obj) {\n + return !!(obj && obj.nodeType == 1);\n + };\n +\n + // Is a given value an array?\n + // Delegates to ECMA5\'s native Array.isArray\n + _.isArray = nativeIsArray || function(obj) {\n + return !!(obj && obj.concat && obj.unshift && !obj.callee);\n + };\n +\n + // Is a given variable an arguments object?\n + _.isArguments = function(obj) {\n + return obj && obj.callee;\n + };\n +\n + // Is a given value a function?\n + _.isFunction = function(obj) {\n + return !!(obj && obj.constructor && obj.call && obj.apply);\n + };\n +\n + // Is a given value a string?\n + _.isString = function(obj) {\n + return !!(obj === \'\' || (obj && obj.charCodeAt && obj.substr));\n + };\n +\n + // Is a given value a number?\n + _.isNumber = function(obj) {\n + return (obj === +obj) || (toString.call(obj) === \'[object Number]\');\n + };\n +\n + // Is a given value a boolean?\n + _.isBoolean = function(obj) {\n + return obj === true || obj === false;\n + };\n +\n + // Is a given value a date?\n + _.isDate = function(obj) {\n + return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);\n + };\n +\n + // Is the given value a regular expression?\n + _.isRegExp = function(obj) {\n + return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));\n + };\n +\n + // Is the given value NaN -- this one is interesting. NaN != NaN, and\n + // isNaN(undefined) == true, so we make sure it\'s a number first.\n + _.isNaN = function(obj) {\n + return _.isNumber(obj) && isNaN(obj);\n + };\n +\n + // Is a given value equal to null?\n + _.isNull = function(obj) {\n + return obj === null;\n + };\n +\n + // Is a given variable undefined?\n + _.isUndefined = function(obj) {\n + return typeof obj == \'undefined\';\n + };\n +\n + // -------------------------- Utility Functions: ----------------------------\n +\n + // Run Underscore.js in noConflict mode, returning the \'_\' variable to its\n + // previous owner. Returns a reference to the Underscore object.\n + _.noConflict = function() {\n + root._ = previousUnderscore;\n + return this;\n + };\n +\n + // Keep the identity function around for default iterators.\n + _.identity = function(value) {\n + return value;\n + };\n +\n + // Run a function n times.\n + _.times = function (n, iterator, context) {\n + for (var i = 0; i < n; i++) iterator.call(context, i);\n + };\n +\n + // Break out of the middle of an iteration.\n + _.breakLoop = function() {\n + throw breaker;\n + };\n +\n + // Add your own custom functions to the Underscore object, ensuring that\n + // they\'re correctly added to the OOP wrapper as well.\n + _.mixin = function(obj) {\n + each(_.functions(obj), function(name){\n + addToWrapper(name, _[name] = obj[name]);\n + });\n + };\n +\n + // Generate a unique integer id (unique within the entire client session).\n + // Useful for temporary DOM ids.\n + var idCounter = 0;\n + _.uniqueId = function(prefix) {\n + var id = idCounter++;\n + return prefix ? prefix + id : id;\n + };\n +\n + // By default, Underscore uses ERB-style template delimiters, change the\n + // following template settings to use alternative delimiters.\n + _.templateSettings = {\n + start : \'<%\',\n + end : \'%>\',\n + interpolate : /<%=(.+?)%>/g\n + };\n +\n + // JavaScript templating a-la ERB, pilfered from John Resig\'s\n + // "Secrets of the JavaScript Ninja", page 83.\n + // Single-quote fix from Rick Strahl\'s version.\n + // With alterations for arbitrary delimiters.\n + _.template = function(str, data) {\n + var c = _.templateSettings;\n + var endMatch = new RegExp("\'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g");\n + var fn = new Function(\'obj\',\n + \'var p=[],print=function(){p.push.apply(p,arguments);};\' +\n + \'with(obj){p.push(\\\'\' +\n + str.replace(/[\\r\\t\\n]/g, " ")\n + .replace(endMatch,"\\t")\n + .split("\'").join("\\\\\'")\n + .split("\\t").join("\'")\n + .replace(c.interpolate, "\',$1,\'")\n + .split(c.start).join("\');")\n + .split(c.end).join("p.push(\'")\n + + "\');}return p.join(\'\');");\n + return data ? fn(data) : fn;\n + };\n +\n + // ------------------------------- Aliases ----------------------------------\n +\n + _.each = _.forEach;\n + _.foldl = _.inject = _.reduce;\n + _.foldr = _.reduceRight;\n + _.select = _.filter;\n + _.all = _.every;\n + _.any = _.some;\n + _.head = _.first;\n + _.tail = _.rest;\n + _.methods = _.functions;\n +\n + // ------------------------ Setup the OOP Wrapper: --------------------------\n +\n + // If Underscore is called as a function, it returns a wrapped object that\n + // can be used OO-style. This wrapper holds altered versions of all the\n + // underscore functions. Wrapped objects may be chained.\n + var wrapper = function(obj) { this._wrapped = obj; };\n +\n + // Helper function to continue chaining intermediate results.\n + var result = function(obj, chain) {\n + return chain ? _(obj).chain() : obj;\n + };\n +\n + // A method to easily add functions to the OOP wrapper.\n + var addToWrapper = function(name, func) {\n + wrapper.prototype[name] = function() {\n + var args = _.toArray(arguments);\n + unshift.call(args, this._wrapped);\n + return result(func.apply(_, args), this._chain);\n + };\n + };\n +\n + // Add all of the Underscore functions to the wrapper object.\n + _.mixin(_);\n +\n + // Add all mutator Array functions to the wrapper.\n + each([\'pop\', \'push\', \'reverse\', \'shift\', \'sort\', \'splice\', \'unshift\'], function(name) {\n + var method = ArrayProto[name];\n + wrapper.prototype[name] = function() {\n + method.apply(this._wrapped, arguments);\n + return result(this._wrapped, this._chain);\n + };\n + });\n +\n + // Add all accessor Array functions to the wrapper.\n + each([\'concat\', \'join\', \'slice\'], function(name) {\n + var method = ArrayProto[name];\n + wrapper.prototype[name] = function() {\n + return result(method.apply(this._wrapped, arguments), this._chain);\n + };\n + });\n +\n + // Start chaining a wrapped Underscore object.\n + wrapper.prototype.chain = function() {\n + this._chain = true;\n + return this;\n + };\n +\n + // Extracts the result from a wrapped and chained object.\n + wrapper.prototype.value = function() {\n + return this._wrapped;\n + };\n +\n +})();\n +\n +exports._.noConflict();\n +});\n +;bespin.tiki.register("::worker_manager", {\n + name: "worker_manager",\n + dependencies: { "canon": "0.0.0", "events": "0.0.0", "underscore": "0.0.0" }\n +});\n +bespin.tiki.module("worker_manager:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "Manages a web worker on the browser side",\n + "dependencies": {\n + "canon": "0.0.0",\n + "events": "0.0.0",\n + "underscore": "0.0.0"\n + },\n + "provides": [\n + {\n + "ep": "command",\n + "name": "worker",\n + "description": "Low-level web worker control (for plugin development)"\n + },\n + {\n + "ep": "command",\n + "name": "worker restart",\n + "description": "Restarts all web workers (for plugin development)",\n + "pointer": "#workerRestartCommand"\n + }\n + ]\n +});\n +"end";\n +\n +if (window == null) {\n + throw new Error(\'The "worker_manager" plugin can only be loaded in the \' +\n + \'browser, not a web worker. Use "worker" instead.\');\n +}\n +\n +var proxy = require(\'bespin:proxy\');\n +var plugins = require(\'bespin:plugins\');\n +var console = require(\'bespin:console\').console;\n +var _ = require(\'underscore\')._;\n +var Event = require(\'events\').Event;\n +var Promise = require(\'bespin:promise\').Promise;\n +var env = require(\'environment\').env;\n +\n +var workerManager = {\n + _workers: [],\n +\n + add: function(workerSupervisor) {\n + this._workers.push(workerSupervisor);\n + },\n +\n + remove: function(workerSupervisor) {\n + this._workers = _(this._workers).without(workerSupervisor);\n + },\n +\n + restartAll: function() {\n + var workers = this._workers;\n + _(workers).invoke(\'kill\');\n + _(workers).invoke(\'start\');\n + }\n +};\n +\n +function WorkerSupervisor(pointer) {\n + var m = /^([^#:]+)(?::([^#:]+))?#([^#:]+)$/.exec(pointer);\n + if (m == null) {\n + throw new Error(\'WorkerSupervisor: invalid pointer specification: "\' +\n + pointer + \'"\');\n + }\n +\n + var packageId = m[1], target = m[3];\n + var moduleId = packageId + ":" + (m[2] != null ? m[2] : "index");\n + var base = bespin != null && bespin.base != null ? bespin.base : "";\n +\n + this._packageId = packageId;\n + this._moduleId = moduleId;\n + this._base = base;\n + this._target = target;\n +\n + this._worker = null;\n + this._currentId = 0;\n +\n + this.started = new Event();\n +}\n +\n +WorkerSupervisor.prototype = {\n + _onError: function(ev) {\n + this._worker = null;\n + workerManager.remove(this);\n +\n + console.error("WorkerSupervisor: worker failed at file " +\n + ev.filename + ":" + ev.lineno + "; fix the worker and use " +\n + "\'worker restart\' to restart it");\n + },\n +\n + _onMessage: function(ev) {\n + var msg = JSON.parse(ev.data);\n + switch (msg.op) {\n + case \'finish\':\n + if (msg.id === this._currentId) {\n + var promise = this._promise;\n +\n + // We have to set the promise to null first, in case the user\'s\n + // then() handler on the promise decides to send another\n + // message to the object.\n + this._promise = null;\n +\n + promise.resolve(msg.result);\n + }\n + break;\n +\n + case \'log\':\n + console[msg.method].apply(console, msg.args);\n + break;\n + }\n + },\n +\n + _promise: null,\n +\n + /** An event that fires whenever the worker is started or restarted. */\n + started: null,\n +\n + /**\n + * Terminates the worker. After this call, the worker can be restarted via\n + * a call to start().\n + */\n + kill: function() {\n + var oldPromise = this._promise;\n + if (oldPromise != null) {\n + oldPromise.reject("killed");\n + this._promise = null;\n + }\n +\n + this._worker.terminate();\n + this._worker = null;\n + workerManager.remove(this);\n + },\n +\n + /**\n + * Invokes a method on the target running in the worker and returns a\n + * promise that will resolve to the result of that method.\n + */\n + send: function(method, args) {\n + var oldPromise = this._promise;\n + if (oldPromise != null) {\n + oldPromise.reject("interrupted");\n + this._currentId++;\n + }\n +\n + var id = this._currentId;\n + var promise = new Promise();\n + this._promise = promise;\n +\n + var msg = { op: \'invoke\', id: id, method: method, args: args };\n + this._worker.postMessage(JSON.stringify(msg));\n +\n + return promise;\n + },\n +\n + /**\n + * Starts the worker. Immediately after this method is called, the\n + * "started" event will fire.\n + */\n + start: function() {\n + if (this._worker != null) {\n + throw new Error("WorkerSupervisor: worker already started");\n + }\n +\n + var base = this._base, target = this._target;\n + var packageId = this._packageId, moduleId = this._moduleId;\n +\n + var worker = new proxy.Worker(base + "BespinEmbedded.js");\n +\n + worker.onmessage = this._onMessage.bind(this);\n + worker.onerror = this._onError.bind(this);\n +\n + var msg = {\n + op: \'load\',\n + base: base,\n + pkg: packageId,\n + module: moduleId,\n + target: target\n + };\n + worker.postMessage(JSON.stringify(msg));\n +\n + this._worker = worker;\n + this._currentId = 0;\n +\n + workerManager.add(this);\n +\n + this.started();\n + }\n +};\n +\n +function workerRestartCommand(args, req) {\n + workerManager.restartAll();\n +}\n +\n +exports.WorkerSupervisor = WorkerSupervisor;\n +exports.workerManager = workerManager;\n +exports.workerRestartCommand = workerRestartCommand;\n +\n +\n +});\n +;bespin.tiki.register("::events", {\n + name: "events",\n + dependencies: { "traits": "0.0.0" }\n +});\n +bespin.tiki.module("events:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +exports.Event = function() {\n + var handlers = [];\n + var evt = function() {\n + var args = arguments;\n + handlers.forEach(function(handler) { handler.func.apply(null, args); });\n + };\n +\n + /**\n + * Adds a new handler via\n + * a) evt.add(handlerFunc)\n + * b) evt.add(reference, handlerFunc)\n + */\n + evt.add = function() {\n + if (arguments.length == 1) {\n + handlers.push({\n + ref: arguments[0],\n + func: arguments[0]\n + });\n + } else {\n + handlers.push({\n + ref: arguments[0],\n + func: arguments[1]\n + });\n + }\n + };\n +\n + evt.remove = function(ref) {\n + var notEqual = function(other) { return ref !== other.ref; };\n + handlers = handlers.filter(notEqual);\n + };\n +\n + evt.removeAll = function() {\n + handlers = [];\n + };\n +\n + return evt;\n +};\n +\n +\n +});\n +;bespin.tiki.register("::types", {\n + name: "types",\n + dependencies: { }\n +});\n +bespin.tiki.module("types:basic",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var console = require(\'bespin:console\').console;\n +var Promise = require(\'bespin:promise\').Promise;\n +\n +var r = require;\n +\n +/**\n + * These are the basic types that we accept. They are vaguely based on the\n + * Jetpack settings system (https://wiki.mozilla.org/Labs/Jetpack/JEP/24)\n + * although clearly more restricted.\n + * <p>In addition to these types, Jetpack also accepts range, member, password\n + * that we are thinking of adding in the short term.\n + */\n +\n +/**\n + * \'text\' is the default if no type is given.\n + */\n +exports.text = {\n + isValid: function(value, typeExt) {\n + return typeof value == \'string\';\n + },\n +\n + toString: function(value, typeExt) {\n + return value;\n + },\n +\n + fromString: function(value, typeExt) {\n + return value;\n + }\n +};\n +\n +/**\n + * We don\'t currently plan to distinguish between integers and floats\n + */\n +exports.number = {\n + isValid: function(value, typeExt) {\n + if (isNaN(value)) {\n + return false;\n + }\n + if (value === null) {\n + return false;\n + }\n + if (value === undefined) {\n + return false;\n + }\n + if (value === Infinity) {\n + return false;\n + }\n + return typeof value == \'number\';// && !isNaN(value);\n + },\n +\n + toString: function(value, typeExt) {\n + if (!value) {\n + return null;\n + }\n + return \'\' + value;\n + },\n +\n + fromString: function(value, typeExt) {\n + if (!value) {\n + return null;\n + }\n + var reply = parseInt(value, 10);\n + if (isNaN(reply)) {\n + throw new Error(\'Can\\\'t convert "\' + value + \'" to a number.\');\n + }\n + return reply;\n + }\n +};\n +\n +/**\n + * true/false values\n + */\n +exports.bool = {\n + isValid: function(value, typeExt) {\n + return typeof value == \'boolean\';\n + },\n +\n + toString: function(value, typeExt) {\n + return \'\' + value;\n + },\n +\n + fromString: function(value, typeExt) {\n + if (value === null) {\n + return null;\n + }\n +\n + if (!value.toLowerCase) {\n + return !!value;\n + }\n +\n + var lower = value.toLowerCase();\n + if (lower == \'true\') {\n + return true;\n + } else if (lower == \'false\') {\n + return false;\n + }\n +\n + return !!value;\n + }\n +};\n +\n +/**\n + * A JSON object\n + * TODO: Check to see how this works out.\n + */\n +exports.object = {\n + isValid: function(value, typeExt) {\n + return typeof value == \'object\';\n + },\n +\n + toString: function(value, typeExt) {\n + return JSON.stringify(value);\n + },\n +\n + fromString: function(value, typeExt) {\n + return JSON.parse(value);\n + }\n +};\n +\n +/**\n + * One of a known set of options\n + */\n +exports.selection = {\n + isValid: function(value, typeExt) {\n + if (typeof value != \'string\') {\n + return false;\n + }\n +\n + if (!typeExt.data) {\n + console.error(\'Missing data on selection type extension. Skipping\');\n + return true;\n + }\n +\n + var match = false;\n + typeExt.data.forEach(function(option) {\n + if (value == option) {\n + match = true;\n + }\n + });\n +\n + return match;\n + },\n +\n + toString: function(value, typeExt) {\n + return value;\n + },\n +\n + fromString: function(value, typeExt) {\n + // TODO: should we validate and return null if invalid?\n + return value;\n + },\n +\n + resolveTypeSpec: function(extension, typeSpec) {\n + var promise = new Promise();\n +\n + if (typeSpec.data) {\n + // If we\'ve got the data already - just use it\n + extension.data = typeSpec.data;\n + promise.resolve();\n + } else if (typeSpec.pointer) {\n + catalog.loadObjectForPropertyPath(typeSpec.pointer).then(function(obj) {\n + var reply = obj(typeSpec);\n + if (typeof reply.then === \'function\') {\n + reply.then(function(data) {\n + extension.data = data;\n + promise.resolve();\n + });\n + } else {\n + extension.data = reply;\n + promise.resolve();\n + }\n + }, function(ex) {\n + promise.reject(ex);\n + });\n + } else {\n + // No extra data available\n + console.warn(\'Missing data/pointer for selection\', typeSpec);\n + promise.resolve();\n + }\n +\n + return promise;\n + }\n +};\n +\n +});\n +\n +bespin.tiki.module("types:types",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var console = require(\'bespin:console\').console;\n +var Promise = require(\'bespin:promise\').Promise;\n +\n +/**\n + * Get the simple text-only, no-param version of a typeSpec.\n + */\n +exports.getSimpleName = function(typeSpec) {\n + if (!typeSpec) {\n + throw new Error(\'null|undefined is not a valid typeSpec\');\n + }\n +\n + if (typeof typeSpec == \'string\') {\n + return typeSpec;\n + }\n +\n + if (typeof typeSpec == \'object\') {\n + if (!typeSpec.name) {\n + throw new Error(\'Missing name member to typeSpec\');\n + }\n +\n + return typeSpec.name;\n + }\n +\n + throw new Error(\'Not a typeSpec: \' + typeSpec);\n +};\n +\n +/**\n + * 2 typeSpecs are considered equal if their simple names are the same.\n + */\n +exports.equals = function(typeSpec1, typeSpec2) {\n + return exports.getSimpleName(typeSpec1) == exports.getSimpleName(typeSpec2);\n +};\n +\n +/**\n + * A deferred type is one where we hope to find out what the type is just\n + * in time to use it. For example the \'set\' command where the type of the 2nd\n + * param is defined by the 1st param.\n + * @param typeSpec An object type spec with name = \'deferred\' and a pointer\n + * which to call through catalog.loadObjectForPropertyPath (passing in the\n + * original typeSpec as a parameter). This function is expected to return either\n + * a new typeSpec, or a promise of a typeSpec.\n + * @returns A promise which resolves to the new type spec from the pointer.\n + */\n +exports.undeferTypeSpec = function(typeSpec) {\n + // Deferred types are specified by the return from the pointer\n + // function.\n + var promise = new Promise();\n + if (!typeSpec.pointer) {\n + promise.reject(new Error(\'Missing deferred pointer\'));\n + return promise;\n + }\n +\n + catalog.loadObjectForPropertyPath(typeSpec.pointer).then(function(obj) {\n + var reply = obj(typeSpec);\n + if (typeof reply.then === \'function\') {\n + reply.then(function(newTypeSpec) {\n + promise.resolve(newTypeSpec);\n + }, function(ex) {\n + promise.reject(ex);\n + });\n + } else {\n + promise.resolve(reply);\n + }\n + }, function(ex) {\n + promise.reject(ex);\n + });\n +\n + return promise;\n +};\n +\n +// Warning: These next 2 functions are virtually cut and paste from\n +// command_line:typehint.js\n +// If you change this, there are probably parallel changes to be made there\n +// There are 2 differences between the functions:\n +// - We lookup type|typehint in the catalog\n +// - There is a concept of a default typehint, where there is no similar\n +// thing for types. This is sensible, because hints are optional nice\n +// to have things. Not so for types.\n +// Whilst we could abstract out the changes, I\'m not sure this simplifies\n +// already complex code\n +\n +/**\n + * Given a string, look up the type extension in the catalog\n + * @param name The type name. Object type specs are not allowed\n + * @returns A promise that resolves to a type extension\n + */\n +function resolveObjectType(typeSpec) {\n + var promise = new Promise();\n + var ext = catalog.getExtensionByKey(\'type\', typeSpec.name);\n + if (ext) {\n + promise.resolve({ ext: ext, typeSpec: typeSpec });\n + } else {\n + promise.reject(new Error(\'Unknown type: \' + typeSpec.name));\n + }\n + return promise;\n +};\n +\n +/**\n + * Look-up a typeSpec and find a corresponding type extension. This function\n + * does not attempt to load the type or go through the resolution process,\n + * for that you probably want #resolveType()\n + * @param typeSpec A string containing the type name or an object with a name\n + * and other type parameters e.g. { name: \'selection\', data: [ \'one\', \'two\' ] }\n + * @return a promise that resolves to an object containing the resolved type\n + * extension and the typeSpec used to resolve the type (which could be different\n + * from the passed typeSpec if this was deferred). The object will be in the\n + * form { ext:... typeSpec:... }\n + */\n +function resolveTypeExt(typeSpec) {\n + if (typeof typeSpec === \'string\') {\n + return resolveObjectType({ name: typeSpec });\n + }\n +\n + if (typeof typeSpec === \'object\') {\n + if (typeSpec.name === \'deferred\') {\n + var promise = new Promise();\n + exports.undeferTypeSpec(typeSpec).then(function(newTypeSpec) {\n + resolveTypeExt(newTypeSpec).then(function(reply) {\n + promise.resolve(reply);\n + }, function(ex) {\n + promise.reject(ex);\n + });\n + });\n + return promise;\n + } else {\n + return resolveObjectType(typeSpec);\n + }\n + }\n +\n + throw new Error(\'Unknown typeSpec type: \' + typeof typeSpec);\n +};\n +\n +/**\n + * Do all the nastiness of: converting the typeSpec to an extension, then\n + * asynchronously loading the extension to a type and then calling\n + * resolveTypeSpec if the loaded type defines it.\n + * @param typeSpec a string or object defining the type to resolve\n + * @returns a promise which resolves to an object containing the type and type\n + * extension as follows: { type:... ext:... }\n + * @see #resolveTypeExt\n + */\n +exports.resolveType = function(typeSpec) {\n + var promise = new Promise();\n +\n + resolveTypeExt(typeSpec).then(function(data) {\n + data.ext.load(function(type) {\n + // We might need to resolve the typeSpec in a custom way\n + if (typeof type.resolveTypeSpec === \'function\') {\n + type.resolveTypeSpec(data.ext, data.typeSpec).then(function() {\n + promise.resolve({ type: type, ext: data.ext });\n + }, function(ex) {\n + promise.reject(ex);\n + });\n + } else {\n + // Nothing to resolve - just go\n + promise.resolve({ type: type, ext: data.ext });\n + }\n + });\n + }, function(ex) {\n + promise.reject(ex);\n + });\n +\n + return promise;\n +};\n +\n +/**\n + * Convert some data from a string to another type as specified by\n + * <tt>typeSpec</tt>.\n + */\n +exports.fromString = function(stringVersion, typeSpec) {\n + var promise = new Promise();\n + exports.resolveType(typeSpec).then(function(typeData) {\n + promise.resolve(typeData.type.fromString(stringVersion, typeData.ext));\n + });\n + return promise;\n +};\n +\n +/**\n + * Convert some data from an original type to a string as specified by\n + * <tt>typeSpec</tt>.\n + */\n +exports.toString = function(objectVersion, typeSpec) {\n + var promise = new Promise();\n + exports.resolveType(typeSpec).then(function(typeData) {\n + promise.resolve(typeData.type.toString(objectVersion, typeData.ext));\n + });\n + return promise;\n +};\n +\n +/**\n + * Convert some data from an original type to a string as specified by\n + * <tt>typeSpec</tt>.\n + */\n +exports.isValid = function(originalVersion, typeSpec) {\n + var promise = new Promise();\n + exports.resolveType(typeSpec).then(function(typeData) {\n + promise.resolve(typeData.type.isValid(originalVersion, typeData.ext));\n + });\n + return promise;\n +};\n +\n +});\n +\n +bespin.tiki.module("types:index",function(require,exports,module) {\n +\n +});\n +;bespin.tiki.register("::syntax_manager", {\n + name: "syntax_manager",\n + dependencies: { "worker_manager": "0.0.0", "events": "0.0.0", "underscore": "0.0.0", "syntax_directory": "0.0.0" }\n +});\n +bespin.tiki.module("syntax_manager:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var _ = require(\'underscore\')._;\n +var Event = require(\'events\').Event;\n +var WorkerSupervisor = require(\'worker_manager\').WorkerSupervisor;\n +var console = require(\'bespin:console\').console;\n +var rangeutils = require(\'rangeutils:utils/range\');\n +var syntaxDirectory = require(\'syntax_directory\').syntaxDirectory;\n +\n +// The number of lines to highlight at once.\n +var GRANULARITY = 100;\n +\n +// Replaces elements at position i in dest with the elements of src. If i is\n +// beyond the end of dest, expands dest with copies of fill.\n +function replace(dest, i, src, fill) {\n + while (dest.length < i) {\n + dest.push(_(fill).clone());\n + }\n +\n + var args = [ i, src.length ].concat(src);\n + Array.prototype.splice.apply(dest, args);\n + return dest;\n +}\n +\n +// A simple key-value store in which each key is paired with a corresponding\n +// line. When the syntax information is updated for a line, the symbols from\n +// those lines are wiped out and replaced with the new symbols.\n +function Symbols() {\n + this._lines = [];\n + this._syms = {};\n +}\n +\n +Symbols.prototype = {\n + get: function(sym) {\n + return this._syms["-" + sym];\n + },\n +\n + replaceLine: function(row, newSymbols) {\n + var lines = this._lines, syms = this._syms;\n + if (row < lines.length && _(lines[row]).isArray()) {\n + _(lines[row]).each(function(ident) { delete syms["-" + ident]; });\n + }\n +\n + function stripLeadingDash(s) { return s.substring(1); }\n + lines[row] = _(newSymbols).keys().map(stripLeadingDash);\n +\n + _(syms).extend(newSymbols);\n + }\n +};\n +\n +function Context(syntaxInfo, syntaxManager) {\n + this._syntaxInfo = syntaxInfo;\n + this._syntaxManager = syntaxManager;\n +\n + this._invalidRow = 0;\n + this._states = [];\n + this._active = false;\n +\n + this.symbols = new Symbols;\n +}\n +\n +Context.prototype = {\n + _annotate: function() {\n + if (this._invalidRow == null) {\n + throw new Error("syntax_manager.Context: attempt to annotate " +\n + "without any invalid row");\n + }\n + if (!this._active) {\n + throw new Error("syntax_manager.Context: attempt to annotate " +\n + "while inactive");\n + }\n +\n + if (this._worker == null) {\n + this._createWorker();\n + return;\n + }\n +\n + var lines = this._syntaxManager.getTextLines();\n + var row = this._invalidRow;\n + var state = row === 0 ? this.getName() + \':start\' : this._states[row];\n + var lastRow = Math.min(lines.length, row + GRANULARITY);\n + lines = lines.slice(row, lastRow);\n +\n + var runRange = {\n + start: { row: row, col: 0 },\n + end: { row: lastRow - 1, col: _(lines).last().length }\n + };\n +\n + var pr = this._worker.send(\'annotate\', [ state, lines, runRange ]);\n + pr.then(_(this._annotationFinished).bind(this, row, lastRow));\n + },\n +\n + _annotationFinished: function(row, lastRow, result) {\n + if (!this._active) {\n + return;\n + }\n +\n + var syntaxManager = this._syntaxManager;\n + syntaxManager.mergeAttrs(row, result.attrs);\n + syntaxManager.mergeSymbols(row, result.symbols);\n +\n + replace(this._states, row, result.states);\n +\n + if (lastRow >= this._getRowCount()) {\n + this._invalidRow = null; // We\'re done!\n + this._active = false;\n + return;\n + }\n +\n + this._invalidRow = lastRow;\n + this._annotate();\n + },\n +\n + _createWorker: function() {\n + var syntaxInfo = this._syntaxInfo;\n + if (syntaxInfo == null) {\n + return false;\n + }\n +\n + var worker = new WorkerSupervisor("syntax_worker#syntaxWorker");\n + this._worker = worker;\n +\n + worker.started.add(this._workerStarted.bind(this));\n + worker.start();\n +\n + return true;\n + },\n +\n + _getRowCount: function() {\n + return this._syntaxManager.getTextLines().length;\n + },\n +\n + _workerStarted: function() {\n + this._worker.send(\'loadSyntax\', [ this._syntaxInfo.name ]);\n + if (this._active) {\n + this._annotate();\n + }\n + },\n +\n + // Switches on this syntax context and begins annotation. It is the\n + // caller\'s responsibility to ensure that there exists an invalid row\n + // before calling this. (Typically the caller ensures this by calling cut()\n + // first.)\n + activateAndAnnotate: function() {\n + this._active = true;\n + this._annotate();\n + },\n +\n + contextsAtPosition: function(pos) {\n + var syntaxInfo = this._syntaxInfo;\n + if (syntaxInfo == null) {\n + return [ \'plain\' ];\n + }\n +\n + return [ syntaxInfo.name ]; // FIXME\n + },\n +\n + // Invalidates the syntax context at a row.\n + cut: function(row) {\n + var endRow = this._getRowCount();\n + if (row < 0 || row >= endRow) {\n + throw new Error("Attempt to cut the context at an invalid row");\n + }\n +\n + if (this._invalidRow != null && this._invalidRow < row) {\n + return;\n + }\n + this._invalidRow = row;\n +\n + // Mark ourselves as inactive, so that if the web worker was working on\n + // a series of rows we know to discard its results.\n + this._active = false;\n + },\n +\n + getName: function() {\n + return this._syntaxInfo.name;\n + },\n +\n + kill: function() {\n + var worker = this._worker;\n + if (worker == null) {\n + return;\n + }\n +\n + worker.kill();\n + this._worker = null;\n + }\n +};\n +\n +/**\n + * The syntax manager coordinates a series of syntax contexts, each run in a\n + * separate web worker. It receives text editing notifications, updates and\n + * stores the relevant syntax attributes, and provides marked-up text as the\n + * layout manager requests it.\n + *\n + * @constructor\n + * @exports SyntaxManager as syntax_manager:SyntaxManager\n + */\n +function SyntaxManager(layoutManager) {\n + this.layoutManager = layoutManager;\n +\n + /** Called whenever the attributes have been updated. */\n + this.attrsChanged = new Event;\n +\n + /** Called whenever the syntax (file type) has been changed. */\n + this.syntaxChanged = new Event;\n +\n + this._context = null;\n + this._invalidRows = null;\n + this._contextRanges = null;\n + this._attrs = [];\n + this._symbols = new Symbols;\n + this._syntax = \'plain\';\n +\n + this._reset();\n +}\n +\n +SyntaxManager.prototype = {\n + /** @lends SyntaxManager */\n +\n + _getTextStorage: function() {\n + return this.layoutManager.textStorage;\n + },\n +\n + // Invalidates all the highlighting and recreates the workers.\n + _reset: function() {\n + var ctx = this._context;\n + if (ctx != null) {\n + ctx.kill();\n + this._context = null;\n + }\n +\n + var syn = this._syntax;\n + var syntaxInfo = syn === \'plain\' ? null : syntaxDirectory.get(syn);\n +\n + ctx = new Context(syntaxInfo, this);\n + this._context = ctx;\n + ctx.activateAndAnnotate();\n + },\n +\n + attrsChanged: null,\n + syntaxChanged: null,\n +\n + /** Returns the contexts that are active at the position pos. */\n + contextsAtPosition: function(pos) {\n + return this._context.contextsAtPosition(pos);\n + },\n +\n + /**\n + * Returns the attributes most recently delivered from the syntax engine.\n + * Does not instruct the engine to perform any work; use invalidateRow()\n + * for that.\n + */\n + getAttrsForRows: function(startRow, endRow) {\n + return this._attrs.slice(startRow, endRow);\n + },\n +\n + /**\n + * Returns the metadata currently associated with the given symbol, or null\n + * if the symbol is unknown.\n + */\n + getSymbol: function(ident) {\n + return this._symbols.get(ident);\n + },\n +\n + /** Returns the current syntax. */\n + getSyntax: function() {\n + return this._syntax;\n + },\n +\n + /** A convenience function to return the lines from the text storage. */\n + getTextLines: function() {\n + return this._getTextStorage().lines;\n + },\n +\n + /** Marks the text as needing an update starting at the given row. */\n + invalidateRow: function(row) {\n + var ctx = this._context;\n + ctx.cut(row);\n + ctx.activateAndAnnotate();\n + },\n +\n + /**\n + * Merges the supplied attributes into the text, overwriting the attributes\n + * that were there previously.\n + */\n + mergeAttrs: function(startRow, newAttrs) {\n + replace(this._attrs, startRow, newAttrs, []);\n + this.attrsChanged(startRow, startRow + newAttrs.length);\n + },\n +\n + /**\n + * Merges the supplied symbols into the symbol store, overwriting any\n + * symbols previously defined on those lines.\n + */\n + mergeSymbols: function(startRow, newSymbols) {\n + var symbols = this._symbols;\n + _(newSymbols).each(function(lineSyms, i) {\n + symbols.replaceLine(startRow + i, lineSyms);\n + });\n + },\n +\n + /**\n + * Sets the syntax and invalidates all the highlighting. If no syntax\n + * plugin is available, sets the syntax to "plain".\n + */\n + setSyntax: function(syntax) {\n + this._syntax = syntaxDirectory.hasSyntax(syntax) ? syntax : \'plain\';\n + this.syntaxChanged(syntax);\n + this._reset();\n + },\n +\n + /** Sets the syntax appropriately for a file extension. */\n + setSyntaxFromFileExt: function(fileExt) {\n + return this.setSyntax(syntaxDirectory.syntaxForFileExt(fileExt));\n + }\n +};\n +\n +exports.SyntaxManager = SyntaxManager;\n +\n +\n +});\n +\n +bespin.tiki.require("bespin:plugins").catalog.registerMetadata({"traits": {"resourceURL": "resources/traits/", "description": "Traits library, traitsjs.org", "dependencies": {}, "testmodules": [], "provides": [], "type": "plugins/thirdparty", "name": "traits"}, "settings": {"resourceURL": "resources/settings/", "description": "Infrastructure and commands for managing user preferences", "share": true, "dependencies": {"types": "0.0"}, "testmodules": [], "provides": [{"description": "Storage for the customizable Bespin settings", "pointer": "index#settings", "ep": "appcomponent", "name": "settings"}, {"indexOn": "name", "description": "A setting is something that the application offers as a way to customize how it works", "register": "index#addSetting", "ep": "extensionpoint", "name": "setting"}, {"description": "A settingChange is a way to be notified of changes to a setting", "ep": "extensionpoint", "name": "settingChange"}, {"pointer": "commands#setCommand", "description": "define and show settings", "params": [{"defaultValue": null, "type": {"pointer": "settings:index#getSettings", "name": "selection"}, "name": "setting", "description": "The name of the setting to display or alter"}, {"defaultValue": null, "type": {"pointer": "settings:index#getTypeSpecFromAssignment", "name": "deferred"}, "name": "value", "description": "The new value for the chosen setting"}], "ep": "command", "name": "set"}, {"pointer": "commands#unsetCommand", "description": "unset a setting entirely", "params": [{"type": {"pointer": "settings:index#getSettings", "name": "selection"}, "name": "setting", "description": "The name of the setting to return to defaults"}], "ep": "command", "name": "unset"}], "type": "plugins/supported", "name": "settings"}, "canon": {"resourceURL": "resources/canon/", "name": "canon", "environments": {"main": true, "worker": false}, "dependencies": {"environment": "0.0.0", "events": "0.0.0", "settings": "0.0.0"}, "testmodules": [], "provides": [{"indexOn": "name", "description": "A command is a bit of functionality with optional typed arguments which can do something small like moving the cursor around the screen, or large like cloning a project from VCS.", "ep": "extensionpoint", "name": "command"}, {"description": "An extension point to be called whenever a new command begins output.", "ep": "extensionpoint", "name": "addedRequestOutput"}, {"description": "A dimensionsChanged is a way to be notified of changes to the dimension of Bespin", "ep": "extensionpoint", "name": "dimensionsChanged"}, {"description": "How many typed commands do we recall for reference?", "defaultValue": 50, "type": "number", "ep": "setting", "name": "historyLength"}, {"action": "create", "pointer": "history#InMemoryHistory", "ep": "factory", "name": "history"}], "type": "plugins/supported", "description": "Manages commands"}, "events": {"resourceURL": "resources/events/", "description": "Dead simple event implementation", "dependencies": {"traits": "0.0"}, "testmodules": ["tests/test"], "provides": [], "type": "plugins/supported", "name": "events"}, "environment": {"testmodules": [], "dependencies": {"settings": "0.0.0"}, "resourceURL": "resources/environment/", "name": "environment", "type": "plugins/supported"}, "bespin": {"testmodules": [], "resourceURL": "resources/bespin/", "name": "bespin", "environments": {"main": true, "worker": true}, "type": "plugins/boot"}, "underscore": {"testmodules": [], "type": "plugins/thirdparty", "resourceURL": "resources/underscore/", "description": "Functional Programming Aid for Javascript. Works well with jQuery.", "name": "underscore"}, "worker_manager": {"resourceURL": "resources/worker_manager/", "description": "Manages a web worker on the browser side", "dependencies": {"canon": "0.0.0", "events": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "provides": [{"description": "Low-level web worker control (for plugin development)", "ep": "command", "name": "worker"}, {"description": "Restarts all web workers (for plugin development)", "pointer": "#workerRestartCommand", "ep": "command", "name": "worker restart"}], "type": "plugins/supported", "name": "worker_manager"}, "syntax_directory": {"resourceURL": "resources/syntax_directory/", "name": "syntax_directory", "environments": {"main": true, "worker": true}, "dependencies": {}, "testmodules": [], "provides": [{"register": "#discoveredNewSyntax", "ep": "extensionhandler", "name": "syntax"}], "type": "plugins/supported", "description": "Catalogs the available syntax engines"}, "types": {"resourceURL": "resources/types/", "description": "Defines parameter types for commands", "testmodules": ["tests/testTypes", "tests/testBasic"], "provides": [{"indexOn": "name", "description": "Commands can accept various arguments that the user enters or that are automatically supplied by the environment. Those arguments have types that define how they are supplied or completed. The pointer points to an object with methods convert(str value) and getDefault(). Both functions have `this` set to the command\'s `takes` parameter. If getDefault is not defined, the default on the command\'s `takes` is used, if there is one. The object can have a noInput property that is set to true to reflect that this type is provided directly by the system. getDefault must be defined in that case.", "ep": "extensionpoint", "name": "type"}, {"description": "Text that the user needs to enter.", "pointer": "basic#text", "ep": "type", "name": "text"}, {"description": "A JavaScript number", "pointer": "basic#number", "ep": "type", "name": "number"}, {"description": "A true/false value", "pointer": "basic#bool", "ep": "type", "name": "boolean"}, {"description": "An object that converts via JavaScript", "pointer": "basic#object", "ep": "type", "name": "object"}, {"description": "A string that is constrained to be one of a number of pre-defined values", "pointer": "basic#selection", "ep": "type", "name": "selection"}, {"description": "A type which we don\'t understand from the outset, but which we hope context can help us with", "ep": "type", "name": "deferred"}], "type": "plugins/supported", "name": "types"}, "syntax_manager": {"resourceURL": "resources/syntax_manager/", "name": "syntax_manager", "environments": {"main": true, "worker": false}, "dependencies": {"worker_manager": "0.0.0", "events": "0.0.0", "underscore": "0.0.0", "syntax_directory": "0.0.0"}, "testmodules": [], "provides": [], "type": "plugins/supported", "description": "Provides syntax highlighting services for the editor"}});\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +// Responsible for loading the second script (BespinMain \n +// or BespinWorker)\n +\n +// check to see if we\'re in a worker\n +if (typeof(window) === "undefined") {\n + importScripts("BespinWorker.js");\n +} else {\n + (function() {\n + var mainscript = document.createElement("script");\n + mainscript.setAttribute("src", bespin.base + "BespinMain.js");\n + var head = document.getElementsByTagName("head")[0];\n + head.appendChild(mainscript);\n + })();\n +}\n + + +]]></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinMain.js.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinMain.js.xml new file mode 100644 index 0000000000..3ed62c65d3 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinMain.js.xml @@ -0,0 +1,17597 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="DTMLMethod" module="OFS.DTMLMethod"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>__name__</string> </key> + <value> <string>BespinMain.js</string> </value> + </item> + <item> + <key> <string>_vars</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>globals</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>raw</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +;bespin.tiki.register("::text_editor", {\n + name: "text_editor",\n + dependencies: { "completion": "0.0.0", "undomanager": "0.0.0", "settings": "0.0.0", "canon": "0.0.0", "rangeutils": "0.0.0", "traits": "0.0.0", "theme_manager": "0.0.0", "keyboard": "0.0.0", "edit_session": "0.0.0", "syntax_manager": "0.0.0" }\n +});\n +bespin.tiki.module("text_editor:views/gutter",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +\n +var CanvasView = require(\'views/canvas\').CanvasView;\n +\n +/*\n + * A view that renders the gutter for the editor.\n + *\n + * The domNode attribute contains the domNode for this view that should be\n + * added to the document appropriately.\n + */\n +exports.GutterView = function(container, editor) {\n + CanvasView.call(this, container, true /* preventDownsize */ );\n +\n + this.editor = editor;\n +};\n +\n +exports.GutterView.prototype = new CanvasView();\n +\n +util.mixin(exports.GutterView.prototype, {\n + drawRect: function(rect, context) {\n + var theme = this.editor.themeData.gutter;\n +\n + context.fillStyle = theme.backgroundColor;\n + context.fillRect(rect.x, rect.y, rect.width, rect.height);\n +\n + context.save();\n +\n + var paddingLeft = theme.paddingLeft;\n + context.translate(paddingLeft, 0);\n +\n + var layoutManager = this.editor.layoutManager;\n + var range = layoutManager.characterRangeForBoundingRect(rect);\n + var endRow = Math.min(range.end.row,\n + layoutManager.textLines.length - 1);\n + var lineAscent = layoutManager.fontDimension.lineAscent;\n +\n + context.fillStyle = theme.color;\n + context.font = this.editor.font;\n +\n + for (var row = range.start.row; row <= endRow; row++) {\n + // TODO: breakpoints\n + context.fillText(\'\' + (row + 1), -0.5,\n + layoutManager.lineRectForRow(row).y + lineAscent - 0.5);\n + }\n +\n + context.restore();\n + },\n +\n + computeWidth: function() {\n + var theme = this.editor.themeData.gutter;\n + var paddingWidth = theme.paddingLeft + theme.paddingRight;\n +\n + var lineNumberFont = this.editor.font;\n +\n + var layoutManager = this.editor.layoutManager;\n + var lineCount = layoutManager.textLines.length;\n + var lineCountStr = \'\' + lineCount;\n +\n + var characterWidth = layoutManager.fontDimension.characterWidth;\n + var strWidth = characterWidth * lineCountStr.length;\n +\n + return strWidth + paddingWidth;\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:views/scroller",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var Event = require(\'events\').Event;\n +var console = require(\'bespin:console\').console;\n +\n +var Rect = require(\'utils/rect\');\n +\n +var CanvasView = require(\'views/canvas\').CanvasView;\n +\n +var LINE_HEIGHT = 15;\n +var MINIMUM_HANDLE_SIZE = 20;\n +var NIB_ARROW_PADDING_BEFORE = 3;\n +var NIB_ARROW_PADDING_AFTER = 5;\n +var NIB_LENGTH = 15;\n +var NIB_PADDING = 8; // 15/2\n +\n +var LAYOUT_HORIZONTAL = exports.LAYOUT_HORIZONTAL = 0;\n +var LAYOUT_VERTICAL = exports.LAYOUT_VERTICAL = 1;\n +\n +exports.ScrollerCanvasView = function(editor, layoutDirection) {\n + CanvasView.call(this, editor.container, false /* preventDownsize */,\n + true /* clearOnFullInvalid */);\n + this.editor = editor;\n + this.layoutDirection = layoutDirection;\n +\n + var on = function(eventName, func, target) {\n + target = target || this.domNode;\n + target.addEventListener(eventName, function(evt) {\n + func.call(this, evt);\n + util.stopEvent(evt);\n + }.bind(this), false);\n + }.bind(this);\n +\n + on(\'mouseover\', this.mouseEntered);\n + on(\'mouseout\', this.mouseExited);\n + on(\'mousedown\', this.mouseDown);\n + // Bind the following events to the window as we want to catch them\n + // even when the mouse is outside of the scroller.\n + on(\'mouseup\', this.mouseUp, window);\n + on(\'mousemove\', this.mouseMove, window);\n +\n + this.valueChanged = new Event();\n +};\n +\n +exports.ScrollerCanvasView.prototype = new CanvasView();\n +\n +util.mixin(exports.ScrollerCanvasView.prototype, {\n + lineHeight: 20,\n +\n + proportion: 0,\n +\n + /**\n + * @property\n + * Specifies the direction of the scroll bar: one of LAYOUT_HORIZONTAL\n + * or LAYOUT_VERTICAL.\n + *\n + * Changes to this value after the view has been created have no effect.\n + */\n + layoutDirection: LAYOUT_VERTICAL,\n +\n + _isVisible: false,\n +\n + _maximum: 0,\n +\n + _value: 0,\n +\n + valueChanged: null,\n +\n + /**\n + * @property\n + * The dimensions of transparent space inside the frame, given as an object\n + * with \'left\', \'bottom\', \'top\', and \'right\' properties.\n + *\n + * Note that the scrollerThickness property includes the padding on the\n + * sides of the bar.\n + */\n + padding: { left: 0, bottom: 0, top: 0, right: 0 },\n +\n + _mouseDownScreenPoint: null,\n + _mouseDownValue: null,\n + _isMouseOver: false,\n + _scrollTimer: null,\n + _mouseEventPosition: null,\n + _mouseOverHandle: false,\n +\n + _drawNib: function(ctx, alpha) {\n + var theme = this.editor.themeData.scroller;\n + var fillStyle, arrowStyle, strokeStyle;\n +\n + fillStyle = theme.nibStyle;\n + arrowStyle = theme.nibArrowStyle;\n + strokeStyle = theme.nibStrokeStyle;\n +\n + var midpoint = Math.floor(NIB_LENGTH / 2);\n +\n + ctx.fillStyle = fillStyle;\n + ctx.beginPath();\n + ctx.arc(0, 0, Math.floor(NIB_LENGTH / 2), 0, Math.PI * 2, true);\n + ctx.closePath();\n + ctx.fill();\n + ctx.strokeStyle = strokeStyle;\n + ctx.stroke();\n +\n + ctx.fillStyle = arrowStyle;\n + ctx.beginPath();\n + ctx.moveTo(0, -midpoint + NIB_ARROW_PADDING_BEFORE);\n + ctx.lineTo(-midpoint + NIB_ARROW_PADDING_BEFORE,\n + midpoint - NIB_ARROW_PADDING_AFTER);\n + ctx.lineTo(midpoint - NIB_ARROW_PADDING_BEFORE,\n + midpoint - NIB_ARROW_PADDING_AFTER);\n + ctx.closePath();\n + ctx.fill();\n + },\n +\n + _drawNibs: function(ctx, alpha) {\n + var thickness = this._getClientThickness();\n + var parentView = this.parentView;\n + var value = this._value;\n + var maximum = this._maximum;\n + var highlighted = this._isHighlighted();\n +\n + // Starting nib\n + if (highlighted || value !== 0) {\n + ctx.save();\n + ctx.translate(NIB_PADDING, thickness / 2);\n + ctx.rotate(Math.PI * 1.5);\n + ctx.moveTo(0, 0);\n + this._drawNib(ctx, alpha);\n + ctx.restore();\n + }\n +\n + // Ending nib\n + if (highlighted || value !== maximum) {\n + ctx.save();\n + ctx.translate(this._getClientLength() - NIB_PADDING,\n + thickness / 2);\n + ctx.rotate(Math.PI * 0.5);\n + ctx.moveTo(0, 0);\n + this._drawNib(ctx, alpha);\n + ctx.restore();\n + }\n + },\n +\n + // Returns the frame of the scroll bar, not counting any padding.\n + _getClientFrame: function() {\n + var frame = this.frame;\n + var padding = this.padding;\n + return {\n + x: padding.left,\n + y: padding.top,\n + width: frame.width - (padding.left + padding.right),\n + height: frame.height - (padding.top + padding.bottom)\n + };\n + },\n +\n + // Returns the length of the scroll bar, not counting any padding. Equal to\n + // the width or height of the client frame, depending on the layout\n + // direction.\n + _getClientLength: function() {\n + var clientFrame = this._getClientFrame();\n + switch (this.layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + return clientFrame.width;\n + case LAYOUT_VERTICAL:\n + return clientFrame.height;\n + default:\n + console.error("unknown layout direction");\n + return null;\n + }\n + },\n +\n + // Returns the thickness of the scroll bar, not counting any padding.\n + _getClientThickness: function() {\n + var padding = this.padding;\n + var scrollerThickness = this.editor.themeData.scroller.thickness;\n +\n + switch (this.layoutDirection) {\n + case LAYOUT_VERTICAL:\n + return scrollerThickness - (padding.left + padding.right);\n + case LAYOUT_HORIZONTAL:\n + return scrollerThickness - (padding.top + padding.bottom);\n + default:\n + console.error("unknown layout direction");\n + return null;\n + }\n + },\n +\n + // The length of the scroll bar, counting the padding. Equal to frame.width\n + // or frame.height, depending on the layout direction of the bar.\n + // Read-only.\n + _getFrameLength: function() {\n + switch (this.layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + return this.frame.width;\n + case LAYOUT_VERTICAL:\n + return this.frame.height;\n + default:\n + console.error("unknown layout direction");\n + return null;\n + }\n + },\n +\n + // The dimensions of the gutter (the middle area between the buttons, which\n + // contains the handle or knob).\n + _getGutterFrame: function() {\n + var clientFrame = this._getClientFrame();\n + var thickness = this._getClientThickness();\n + switch (this.layoutDirection) {\n + case LAYOUT_VERTICAL:\n + return {\n + x: clientFrame.x,\n + y: clientFrame.y + NIB_LENGTH,\n + width: thickness,\n + height: Math.max(0, clientFrame.height - 2*NIB_LENGTH)\n + };\n + case LAYOUT_HORIZONTAL:\n + return {\n + x: clientFrame.x + NIB_LENGTH,\n + y: clientFrame.y,\n + width: Math.max(0, clientFrame.width - 2*NIB_LENGTH),\n + height: thickness\n + };\n + default:\n + console.error("unknown layout direction");\n + return null;\n + }\n + },\n +\n + // The length of the gutter, equal to gutterFrame.width or\n + // gutterFrame.height depending on the scroll bar\'s layout direction.\n + _getGutterLength: function() {\n + var gutterFrame = this._getGutterFrame();\n + var gutterLength;\n + switch (this.layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + gutterLength = gutterFrame.width;\n + break;\n + case LAYOUT_VERTICAL:\n + gutterLength = gutterFrame.height;\n + break;\n + default:\n + console.error("unknown layout direction");\n + break;\n + }\n + return gutterLength;\n + },\n +\n + // Returns the dimensions of the handle or knob.\n + _getHandleFrame: function() {\n + var gutterFrame = this._getGutterFrame();\n + var handleOffset = this._getHandleOffset();\n + var handleLength = this._getHandleLength();\n + switch (this.layoutDirection) {\n + case LAYOUT_VERTICAL:\n + return {\n + x: gutterFrame.x,\n + y: gutterFrame.y + handleOffset,\n + width: gutterFrame.width,\n + height: handleLength\n + };\n + case LAYOUT_HORIZONTAL:\n + return {\n + x: gutterFrame.x + handleOffset,\n + y: gutterFrame.y,\n + width: handleLength,\n + height: gutterFrame.height\n + };\n + }\n + },\n +\n + // Returns the length of the handle or knob.\n + _getHandleLength: function() {\n + var gutterLength = this._getGutterLength();\n + return Math.max(gutterLength * this.proportion, MINIMUM_HANDLE_SIZE);\n + },\n +\n + // Returns the starting offset of the handle or knob.\n + _getHandleOffset: function() {\n + var maximum = this._maximum;\n + if (maximum === 0) {\n + return 0;\n + }\n +\n + var gutterLength = this._getGutterLength();\n + var handleLength = this._getHandleLength();\n + var emptyGutterLength = gutterLength - handleLength;\n +\n + return emptyGutterLength * this._value / maximum;\n + },\n +\n + // Determines whether the scroll bar is highlighted.\n + _isHighlighted: function() {\n + return this._isMouseOver === true ||\n + this._mouseDownScreenPoint !== null;\n + },\n +\n + _segmentForMouseEvent: function(evt) {\n + var point = { x: evt.layerX, y: evt.layerY };\n + var clientFrame = this._getClientFrame();\n + var padding = this.padding;\n +\n + if (!Rect.pointInRect(point, clientFrame)) {\n + return null;\n + }\n +\n + var layoutDirection = this.layoutDirection;\n + switch (layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + if ((point.x - padding.left) < NIB_LENGTH) {\n + return \'nib-start\';\n + } else if (point.x >= clientFrame.width - NIB_LENGTH) {\n + return \'nib-end\';\n + }\n + break;\n + case LAYOUT_VERTICAL:\n + if ((point.y - padding.top) < NIB_LENGTH) {\n + return \'nib-start\';\n + } else if (point.y >= clientFrame.height - NIB_LENGTH) {\n + return \'nib-end\';\n + }\n + break;\n + default:\n + console.error("unknown layout direction");\n + break;\n + }\n +\n + var handleFrame = this._getHandleFrame();\n + if (Rect.pointInRect(point, handleFrame)) {\n + return \'handle\';\n + }\n +\n + switch (layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + if (point.x < handleFrame.x) {\n + return \'gutter-before\';\n + } else if (point.x >= handleFrame.x + handleFrame.width) {\n + return \'gutter-after\';\n + }\n + break;\n + case LAYOUT_VERTICAL:\n + if (point.y < handleFrame.y) {\n + return \'gutter-before\';\n + } else if (point.y >= handleFrame.y + handleFrame.height) {\n + return \'gutter-after\';\n + }\n + break;\n + default:\n + console.error("unknown layout direction");\n + break;\n + }\n +\n + console.error("_segmentForMouseEvent: point ", point,\n + " outside view with handle frame ", handleFrame,\n + " and client frame ", clientFrame);\n + return null;\n + },\n +\n + /**\n + * Adjusts the canvas view\'s frame to match the parent container\'s frame.\n + */\n + adjustFrame: function() {\n + var parentFrame = this.frame;\n + this.set(\'layout\', {\n + left: 0,\n + top: 0,\n + width: parentFrame.width,\n + height: parentFrame.height\n + });\n + },\n +\n + drawRect: function(rect, ctx) {\n + // Only draw when visible.\n + if (!this._isVisible) {\n + return;\n + }\n +\n + var highlighted = this._isHighlighted();\n + var theme = this.editor.themeData.scroller;\n + var alpha = (highlighted) ? theme.fullAlpha : theme.particalAlpha;\n +\n + var frame = this.frame;\n + ctx.clearRect(0, 0, frame.width, frame.height);\n +\n + // Begin master drawing context\n + ctx.save();\n +\n + // Translate so that we\'re only drawing in the padding.\n + var padding = this.padding;\n + ctx.translate(padding.left, padding.top);\n +\n + var handleFrame = this._getHandleFrame();\n + var gutterLength = this._getGutterLength();\n + var thickness = this._getClientThickness();\n + var halfThickness = thickness / 2;\n +\n + var layoutDirection = this.layoutDirection;\n + var handleOffset = this._getHandleOffset() + NIB_LENGTH;\n + var handleLength = this._getHandleLength();\n +\n + if (layoutDirection === LAYOUT_VERTICAL) {\n + // The rest of the drawing code assumes the scroll bar is\n + // horizontal. Create that fiction by installing a 90 degree\n + // rotation.\n + ctx.translate(thickness + 1, 0);\n + ctx.rotate(Math.PI * 0.5);\n + }\n +\n + if (gutterLength <= handleLength) {\n + return; // Don\'t display the scroll bar.\n + }\n +\n + ctx.globalAlpha = alpha;\n +\n + if (highlighted) {\n + // Draw the scroll track rectangle.\n + var clientLength = this._getClientLength();\n + ctx.fillStyle = theme.trackFillStyle;\n + ctx.fillRect(NIB_PADDING + 0.5, 0.5,\n + clientLength - 2*NIB_PADDING, thickness - 1);\n + ctx.strokeStyle = theme.trackStrokeStyle;\n + ctx.strokeRect(NIB_PADDING + 0.5, 0.5,\n + clientLength - 2*NIB_PADDING, thickness - 1);\n + }\n +\n + var buildHandlePath = function() {\n + ctx.beginPath();\n + ctx.arc(handleOffset + halfThickness + 0.5, // x\n + halfThickness, // y\n + halfThickness - 0.5, Math.PI / 2, 3 * Math.PI / 2, false);\n + ctx.arc(handleOffset + handleLength - halfThickness - 0.5, // x\n + halfThickness, // y\n + halfThickness - 0.5, 3 * Math.PI / 2, Math.PI / 2, false);\n + ctx.lineTo(handleOffset + halfThickness + 0.5, thickness - 0.5);\n + ctx.closePath();\n + };\n + buildHandlePath();\n +\n + // Paint the interior of the handle path.\n + var gradient = ctx.createLinearGradient(handleOffset, 0, handleOffset,\n + thickness);\n + gradient.addColorStop(0, theme.barFillGradientTopStart);\n + gradient.addColorStop(0.4, theme.barFillGradientTopStop);\n + gradient.addColorStop(0.41, theme.barFillStyle);\n + gradient.addColorStop(0.8, theme.barFillGradientBottomStart);\n + gradient.addColorStop(1, theme.barFillGradientBottomStop);\n + ctx.fillStyle = gradient;\n + ctx.fill();\n +\n + // Begin handle shine edge context\n + ctx.save();\n + ctx.clip();\n +\n + // Draw the little shines in the handle.\n + ctx.fillStyle = theme.barFillStyle;\n + ctx.beginPath();\n + ctx.moveTo(handleOffset + halfThickness * 0.4, halfThickness * 0.6);\n + ctx.lineTo(handleOffset + halfThickness * 0.9, thickness * 0.4);\n + ctx.lineTo(handleOffset, thickness * 0.4);\n + ctx.closePath();\n + ctx.fill();\n + ctx.beginPath();\n + ctx.moveTo(handleOffset + handleLength - (halfThickness * 0.4),\n + 0 + (halfThickness * 0.6));\n + ctx.lineTo(handleOffset + handleLength - (halfThickness * 0.9),\n + 0 + (thickness * 0.4));\n + ctx.lineTo(handleOffset + handleLength, 0 + (thickness * 0.4));\n + ctx.closePath();\n + ctx.fill();\n +\n + ctx.restore();\n + // End handle border context\n +\n + // Begin handle outline context\n + ctx.save();\n + buildHandlePath();\n + ctx.strokeStyle = theme.trackStrokeStyle;\n + ctx.stroke();\n + ctx.restore();\n + // End handle outline context\n +\n + this._drawNibs(ctx, alpha);\n +\n + ctx.restore();\n + // End master drawing context\n + },\n +\n + _repeatAction: function(method, interval) {\n + var repeat = method();\n + if (repeat !== false) {\n + var func = function() {\n + this._repeatAction(method, 100);\n + }.bind(this);\n + this._scrollTimer = setTimeout(func, interval);\n + }\n + },\n +\n + _scrollByDelta: function(delta) {\n + this.value = this._value + delta;\n + },\n +\n + _scrollUpOneLine: function() {\n + this._scrollByDelta(-this.lineHeight);\n + return true;\n + },\n +\n + _scrollDownOneLine: function() {\n + this._scrollByDelta(this.lineHeight);\n + return true;\n + },\n +\n + /**\n + * Scrolls the page depending on the last mouse position. Scrolling is only\n + * performed if the mouse is on the segment gutter-before or -after.\n + */\n + _scrollPage: function() {\n + switch (this._segmentForMouseEvent(this._mouseEventPosition)) {\n + case \'gutter-before\':\n + this._scrollByDelta(this._getGutterLength() * -1);\n + break;\n + case \'gutter-after\':\n + this._scrollByDelta(this._getGutterLength());\n + break;\n + case null:\n + // The mouse is outside of the scroller. Just wait, until it\n + // comes back in.\n + break;\n + default:\n + // Do not continue repeating this function.\n + return false;\n + break;\n + }\n +\n + return true;\n + },\n +\n + mouseDown: function(evt) {\n + this._mouseEventPosition = evt;\n + this._mouseOverHandle = false;\n +\n + var parentView = this.parentView;\n + var value = this._value;\n + var gutterLength = this._getGutterLength();\n +\n + switch (this._segmentForMouseEvent(evt)) {\n + case \'nib-start\':\n + this._repeatAction(this._scrollUpOneLine.bind(this), 500);\n + break;\n + case \'nib-end\':\n + this._repeatAction(this._scrollDownOneLine.bind(this), 500);\n + break;\n + case \'gutter-before\':\n + this._repeatAction(this._scrollPage.bind(this), 500);\n + break;\n + case \'gutter-after\':\n + this._repeatAction(this._scrollPage.bind(this), 500);\n + break;\n + case \'handle\':\n + break;\n + default:\n + console.error("_segmentForMouseEvent returned an unknown value");\n + break;\n + }\n +\n + // The _mouseDownScreenPoint value might be needed although the segment\n + // was not the handle at the moment.\n + switch (this.layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + this._mouseDownScreenPoint = evt.pageX;\n + break;\n + case LAYOUT_VERTICAL:\n + this._mouseDownScreenPoint = evt.pageY;\n + break;\n + default:\n + console.error("unknown layout direction");\n + break;\n + }\n + },\n +\n + mouseMove: function(evt) {\n + if (this._mouseDownScreenPoint === null) {\n + return;\n + }\n +\n + // Handle the segments. If the current segment is the handle or\n + // nothing, then drag the handle around (as null = mouse outside of\n + // scrollbar)\n + var segment = this._segmentForMouseEvent(evt);\n + if (segment == \'handle\' || this._mouseOverHandle === true) {\n + this._mouseOverHandle = true;\n + if (this._scrollTimer !== null) {\n + clearTimeout(this._scrollTimer);\n + this._scrollTimer = null;\n + }\n +\n + var eventDistance;\n + switch (this.layoutDirection) {\n + case LAYOUT_HORIZONTAL:\n + eventDistance = evt.pageX;\n + break;\n + case LAYOUT_VERTICAL:\n + eventDistance = evt.pageY;\n + break;\n + default:\n + console.error("unknown layout direction");\n + break;\n + }\n +\n + var eventDelta = eventDistance - this._mouseDownScreenPoint;\n +\n + var maximum = this._maximum;\n + var oldValue = this._value;\n + var gutterLength = this._getGutterLength();\n + var handleLength = this._getHandleLength();\n + var emptyGutterLength = gutterLength - handleLength;\n + var valueDelta = maximum * eventDelta / emptyGutterLength;\n + this.value = oldValue + valueDelta;\n +\n + this._mouseDownScreenPoint = eventDistance;\n + }\n +\n + this._mouseEventPosition = evt;\n + },\n +\n + mouseEntered: function(evt) {\n + this._isMouseOver = true;\n + this.invalidate();\n + },\n +\n + mouseExited: function(evt) {\n + this._isMouseOver = false;\n + this.invalidate();\n + },\n +\n + mouseUp: function(evt) {\n + this._mouseDownScreenPoint = null;\n + this._mouseDownValue = null;\n + if (this._scrollTimer) {\n + clearTimeout(this._scrollTimer);\n + this._scrollTimer = null;\n + }\n + this.invalidate();\n + }\n +\n + // mouseWheel: function(evt) {\n + // var parentView = this.get(\'parentView\');\n + //\n + // var delta;\n + // switch (parentView.get(\'layoutDirection\')) {\n + // case LAYOUT_HORIZONTAL:\n + // delta = evt.wheelDeltaX;\n + // break;\n + // case LAYOUT_VERTICAL:\n + // delta = evt.wheelDeltaY;\n + // break;\n + // default:\n + // console.error("unknown layout direction");\n + // return;\n + // }\n + //\n + // parentView.set(\'value\', parentView.get(\'value\') + 2*delta);\n + // }\n +});\n +\n +Object.defineProperties(exports.ScrollerCanvasView.prototype, {\n + isVisible: {\n + set: function(isVisible) {\n + if (this._isVisible === isVisible) {\n + return;\n + }\n +\n + this._isVisible = isVisible;\n + this.domNode.style.display = isVisible ? \'block\' : \'none\';\n + if (isVisible) {\n + this.invalidate();\n + }\n + }\n + },\n +\n + maximum: {\n + set: function(maximum) {\n + if (this._value > this._maximum) {\n + this._value = this._maximum;\n + }\n +\n + if (maximum === this._maximum) {\n + return;\n + }\n +\n + this._maximum = maximum;\n + this.invalidate();\n + }\n + },\n +\n + value: {\n + set: function(value) {\n + if (value < 0) {\n + value = 0;\n + } else if (value > this._maximum) {\n + value = this._maximum;\n + }\n +\n + if (value === this._value) {\n + return;\n + }\n +\n + this._value = value;\n + this.valueChanged(value);\n + this.invalidate();\n + }\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:views/editor",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var rangeutils = require(\'rangeutils:utils/range\');\n +var scroller = require(\'views/scroller\');\n +var util = require(\'bespin:util/util\');\n +\n +var Buffer = require(\'models/buffer\').Buffer;\n +var CompletionController = require(\'completion:controller\').\n + CompletionController;\n +var EditorSearchController = require(\'controllers/search\').\n + EditorSearchController;\n +var EditorUndoController = require(\'controllers/undo\').EditorUndoController;\n +var Event = require(\'events\').Event;\n +var GutterView = require(\'views/gutter\').GutterView;\n +var LayoutManager = require(\'controllers/layoutmanager\').LayoutManager;\n +var ScrollerView = scroller.ScrollerCanvasView;\n +var TextView = require(\'views/text\').TextView;\n +\n +var _ = require(\'underscore\')._;\n +var catalog = require(\'bespin:plugins\').catalog;\n +var keyboardManager = require(\'keyboard:keyboard\').keyboardManager;\n +var settings = require(\'settings\').settings;\n +\n +// Caches the theme data for the entire editor (editor, highlighter, and\n +// gutter).\n +var editorThemeData = {};\n +\n +function computeThemeData(themeManager) {\n + var plugin = catalog.plugins[\'text_editor\'];\n + var provides = plugin.provides;\n + var i = provides.length;\n + var themeData = {};\n +\n + // If a themeManager was passed, try to access the themeData for the\n + // `text_editor` plugin.\n + if (themeManager) {\n + var themestyles = themeManager.themestyles;\n +\n + if (themestyles.currentThemeVariables &&\n + themestyles.currentThemeVariables[\'text_editor\']) {\n + themeData = themestyles.currentThemeVariables[\'text_editor\'];\n + }\n + }\n +\n + while (i--) {\n + if (provides[i].ep === \'themevariable\') {\n + var value = util.mixin(util.clone(provides[i].defaultValue),\n + themeData[provides[i].name]);\n +\n + switch (provides[i].name) {\n + case \'gutter\':\n + case \'editor\':\n + case \'scroller\':\n + case \'highlighter\':\n + editorThemeData[provides[i].name] = value;\n + }\n + }\n + }\n +}\n +\n +// Compute the themeData to make sure there is one when the editor comes up.\n +computeThemeData();\n +\n +catalog.registerExtension(\'themeChange\', {\n + pointer: computeThemeData\n +});\n +\n +/**\n + * @class\n + *\n + * A view responsible for laying out a scrollable text view and its associated\n + * gutter view, as well as maintaining a layout manager.\n + */\n +exports.EditorView = function(initialContent) {\n + this.elementAppended = new Event();\n +\n + this.element = this.container = document.createElement("div");\n +\n + var container = this.container;\n + container.style.overflow = \'visible\';\n + container.style.position = \'relative\';\n +\n + this.scrollOffsetChanged = new Event();\n + this.willChangeBuffer = new Event();\n +\n + this.selectionChanged = new Event();\n + this.textChanged = new Event();\n +\n + var gutterView = this.gutterView = new GutterView(container, this);\n + var textView = this.textView = new TextView(container, this);\n + var verticalScroller = new ScrollerView(this, scroller.LAYOUT_VERTICAL);\n + var horizontalScroller = new ScrollerView(this,\n + scroller.LAYOUT_HORIZONTAL);\n + this.verticalScroller = verticalScroller;\n + this.horizontalScroller = horizontalScroller;\n +\n + this.completionController = new CompletionController(this);\n + this.editorUndoController = new EditorUndoController(this);\n + this.searchController = new EditorSearchController(this);\n +\n + this._textViewSize = this._oldSize = { width: 0, height: 0 };\n +\n + this._themeData = editorThemeData;\n +\n + // Create a buffer for the editor and use initialContent as the initial\n + // content for the textStorage object.\n + this.buffer = new Buffer(null, initialContent);\n +\n + // Create all the necessary stuff once the container has been added.\n + this.elementAppended.add(function() {\n + // Set the font property.\n + var fontSize = settings.get(\'fontsize\');\n + var fontFace = settings.get(\'fontface\');\n + this._font = fontSize + \'px \' + fontFace;\n +\n + // Repaint when the theme changes.\n + catalog.registerExtension(\'themeChange\', {\n + pointer: this._themeVariableChange.bind(this)\n + });\n +\n + // When the font changes, set our local font property, and repaint.\n + catalog.registerExtension(\'settingChange\', {\n + match: "font[size|face]",\n + pointer: this._fontSettingChanged.bind(this)\n + });\n +\n + // Likewise when the dimensions change.\n + catalog.registerExtension(\'dimensionsChanged\', {\n + pointer: this.dimensionsChanged.bind(this)\n + });\n +\n + // Allow the layout to be recomputed.\n + this._dontRecomputeLayout = false;\n + this._recomputeLayout();\n +\n + var wheelEvent = util.isMozilla ? \'DOMMouseScroll\' : \'mousewheel\';\n + container.addEventListener(wheelEvent, this._onMouseWheel.bind(this),\n + false);\n +\n + verticalScroller.valueChanged.add(function(value) {\n + this.scrollOffset = { y: value };\n + }.bind(this));\n +\n + horizontalScroller.valueChanged.add(function(value) {\n + this.scrollOffset = { x: value };\n + }.bind(this));\n +\n + this.scrollOffsetChanged.add(function(offset) {\n + this._updateScrollOffsetChanged(offset);\n + }.bind(this));\n + }.bind(this));\n +};\n +\n +\n +exports.EditorView.prototype = {\n + elementAppended: null,\n +\n + textChanged: null,\n + selectionChanged: null,\n +\n + scrollOffsetChanged: null,\n + willChangeBuffer: null,\n +\n + _textViewSize: null,\n +\n + _textLinesCount: 0,\n + _gutterViewWidth: 0,\n + _oldSize: null,\n +\n + _buffer: null,\n +\n + _dontRecomputeLayout: true,\n +\n + _themeData: null,\n +\n + _layoutManagerSizeChanged: function(size) {\n + var fontDimension = this.layoutManager.fontDimension;\n + this._textViewSize = {\n + width: size.width * fontDimension.characterWidth,\n + height: size.height * fontDimension.lineHeight\n + };\n +\n + if (this._textLinesCount !== size.height) {\n + var gutterWidth = this.gutterView.computeWidth();\n + if (gutterWidth !== this._gutterViewWidth) {\n + this._recomputeLayout(true /* force layout update */);\n + } else {\n + this.gutterView.invalidate();\n + }\n + this._textLinesLength = size.height;\n + }\n +\n + // Clamp the current scrollOffset position.\n + this._updateScrollers();\n + this.scrollOffset = {};\n + },\n +\n + _updateScrollers: function() {\n + // Don\'t change anything on the scrollers until the layout is setup.\n + if (this._dontRecomputeLayout) {\n + return;\n + }\n +\n + var frame = this.textViewPaddingFrame;\n + var width = this._textViewSize.width;\n + var height = this._textViewSize.height;\n + var scrollOffset = this.scrollOffset;\n + var verticalScroller = this.verticalScroller;\n + var horizontalScroller = this.horizontalScroller;\n +\n + if (height < frame.height) {\n + verticalScroller.isVisible = false;\n + } else {\n + verticalScroller.isVisible = true;\n + verticalScroller.proportion = frame.height / height;\n + verticalScroller.maximum = height - frame.height;\n + verticalScroller.value = scrollOffset.y;\n + }\n +\n + if (width < frame.width) {\n + horizontalScroller.isVisible = false;\n + } else {\n + horizontalScroller.isVisible = true;\n + horizontalScroller.proportion = frame.width / width;\n + horizontalScroller.maximum = width - frame.width;\n + horizontalScroller.value = scrollOffset.x;\n + }\n + },\n +\n + _onMouseWheel: function(evt) {\n + var delta = 0;\n + if (evt.wheelDelta) {\n + delta = -evt.wheelDelta;\n + } else if (evt.detail) {\n + delta = evt.detail * 40;\n + }\n +\n + var isVertical = true;\n + if (evt.axis) { // Firefox 3.1 world\n + if (evt.axis == evt.HORIZONTAL_AXIS) isVertical = false;\n + } else if (evt.wheelDeltaY || evt.wheelDeltaX) {\n + if (evt.wheelDeltaX == evt.wheelDelta) isVertical = false;\n + } else if (evt.shiftKey) isVertical = false;\n +\n + if (isVertical) {\n + this.scrollBy(0, delta);\n + } else {\n + this.scrollBy(delta * 5, 0);\n + }\n +\n + util.stopEvent(evt);\n + },\n +\n + scrollTo: function(pos) {\n + this.scrollOffset = pos;\n + },\n +\n + scrollBy: function(deltaX, deltaY) {\n + this.scrollOffset = {\n + x: this.scrollOffset.x + deltaX,\n + y: this.scrollOffset.y + deltaY\n + };\n + },\n +\n + _recomputeLayout: function(forceLayout) {\n + // This is necessary as _recomputeLayout is called sometimes when the\n + // size of the container is not yet ready (because of FlexBox).\n + if (this._dontRecomputeLayout) {\n + return;\n + }\n +\n + var width = this.container.offsetWidth;\n + var height = this.container.offsetHeight;\n +\n + // Don\'t recompute unless the size actually changed.\n + if (!forceLayout && width == this._oldSize.width\n + && height == this._oldSize.height) {\n + return;\n + }\n +\n + this._oldSize = {\n + width: width,\n + height: height\n + };\n +\n + var gutterWidth = this.gutterView.computeWidth();\n + this._gutterViewWidth = gutterWidth;\n +\n + this.gutterView.frame = {\n + x: 0,\n + y: 0,\n + width: gutterWidth,\n + height: height\n + };\n +\n + this.textView.frame = {\n + x: gutterWidth,\n + y: 0,\n + width: width - gutterWidth,\n + height: height\n + };\n +\n + // TODO: Get these values from the scroller theme.\n + var scrollerPadding = this._themeData.scroller.padding;\n + var scrollerSize = this._themeData.scroller.thickness;\n +\n + this.horizontalScroller.frame = {\n + x: gutterWidth + scrollerPadding,\n + y: height - (scrollerSize + scrollerPadding),\n + width: width - (gutterWidth + 2 * scrollerPadding + scrollerSize),\n + height: scrollerSize\n + };\n +\n + this.verticalScroller.frame = {\n + x: width - (scrollerPadding + scrollerSize),\n + y: scrollerPadding,\n + width: scrollerSize,\n + height: height - (2 * scrollerPadding + scrollerSize)\n + };\n +\n + // Calls the setter scrollOffset which then clamps the current\n + // scrollOffset as needed.\n + this.scrollOffset = {};\n +\n + this._updateScrollers();\n + this.gutterView.invalidate();\n + this.textView.invalidate();\n + this.verticalScroller.invalidate();\n + this.horizontalScroller.invalidate();\n + },\n +\n + dimensionsChanged: function() {\n + this._recomputeLayout();\n + },\n +\n + /**\n + * @property{string}\n + *\n + * The font to use for the text view and the gutter view. Typically, this\n + * value is set via the font settings.\n + */\n + _font: null,\n +\n + _fontSettingChanged: function() {\n + var fontSize = settings.get(\'fontsize\');\n + var fontFace = settings.get(\'fontface\');\n + this._font = fontSize + \'px \' + fontFace;\n +\n + // Recompute the layouts.\n + this.layoutManager._recalculateMaximumWidth();\n + this._layoutManagerSizeChanged(this.layoutManager.size);\n + this.textView.invalidate();\n + },\n +\n + _themeVariableChange: function() {\n + // Recompute the entire layout as the gutter might now have a different\n + // size. Just calling invalidate() on the gutter wouldn\'t be enough.\n + this._recomputeLayout(true);\n + },\n +\n + _updateScrollOffsetChanged: function(offset) {\n + this.verticalScroller.value = offset.y;\n + this.horizontalScroller.value = offset.x;\n +\n + this.textView.clippingFrame = { x: offset.x, y: offset.y };\n +\n + this.gutterView.clippingFrame = { y: offset.y };\n +\n + this._updateScrollers();\n + this.gutterView.invalidate();\n + this.textView.invalidate();\n + },\n +\n + /**\n + * The text view uses this function to forward key events to the keyboard\n + * manager. The editor view is used as a middleman so that it can append\n + * predicates as necessary.\n + */\n + processKeyEvent: function(evt, sender, preds) {\n + preds = _(preds).clone();\n + preds.completing = this.completionController.isCompleting();\n + return keyboardManager.processKeyEvent(evt, sender, preds);\n + },\n +\n + /**\n + * Converts a point in the coordinate system of the document being edited\n + * (i.e. of the text view) to the coordinate system of the editor (i.e. of\n + * the DOM component containing Bespin).\n + */\n + convertTextViewPoint: function(pt) {\n + var scrollOffset = this.scrollOffset;\n + return {\n + x: pt.x - scrollOffset.x + this._gutterViewWidth,\n + y: pt.y - scrollOffset.y\n + };\n + },\n +\n + // ------------------------------------------------------------------------\n + // Helper API:\n +\n + /**\n + * Replaces the text within a range, as an undoable action.\n + *\n + * @param {Range} range The range to replace.\n + * @param {string} newText The text to insert.\n + * @param {boolean} keepSelection True if the selection should be\n + * be preserved, otherwise the cursor is set after newText.\n + * @return Returns true if the replacement completed successfully,\n + * otherwise returns false.\n + */\n + replace: function(range, newText, keepSelection) {\n + if (!rangeutils.isRange(range)) {\n + throw new Error(\'replace(): expected range but found "\' + range +\n + "\'");\n + }\n + if (!util.isString(newText)) {\n + throw new Error(\'replace(): expected text string but found "\' +\n + text + \'"\');\n + }\n +\n + var normalized = rangeutils.normalizeRange(range);\n +\n + var view = this.textView;\n + var oldSelection = view.getSelectedRange(false);\n + return view.groupChanges(function() {\n + view.replaceCharacters(normalized, newText);\n + if (keepSelection) {\n + view.setSelection(oldSelection);\n + } else {\n + var lines = newText.split(\'\\n\');\n +\n + var destPosition;\n + if (lines.length > 1) {\n + destPosition = {\n + row: range.start.row + lines.length - 1,\n + col: lines[lines.length - 1].length\n + };\n + } else {\n + destPosition = rangeutils.addPositions(range.start,\n + { row: 0, col: newText.length });\n + }\n + view.moveCursorTo(destPosition);\n + }\n + });\n + },\n +\n + getText: function(range) {\n + if (!rangeutils.isRange(range)) {\n + throw new Error(\'getText(): expected range but found "\' + range +\n + \'"\');\n + }\n +\n + var textStorage = this.layoutManager.textStorage;\n + return textStorage.getCharacters(rangeutils.normalizeRange(range));\n + },\n +\n + /** Scrolls and moves the insertion point to the given line number. */\n + setLineNumber: function(lineNumber) {\n + if (!util.isNumber(lineNumber)) {\n + throw new Error(\'setLineNumber(): lineNumber must be a number\');\n + }\n +\n + var newPosition = { row: lineNumber - 1, col: 0 };\n + this.textView.moveCursorTo(newPosition);\n + },\n +\n + /** Sets the position of the cursor. */\n + setCursor: function(newPosition) {\n + if (!rangeutils.isPosition(newPosition)) {\n + throw new Error(\'setCursor(): expected position but found "\' +\n + newPosition + \'"\');\n + }\n +\n + this.textView.moveCursorTo(newPosition);\n + },\n +\n + /**\n + * Group changes so that they are only one undo/redo step.\n + * Returns true if the changes were successful.\n + */\n + changeGroup: function(func) {\n + return this.textView.groupChanges(function() {\n + func(this);\n + }.bind(this));\n + },\n +\n + /**\n + * Adds the supplied tags to the completion manager.\n + */\n + addTags: function(newTags) {\n + this.completionController.tags.add(newTags);\n + }\n +};\n +\n +Object.defineProperties(exports.EditorView.prototype, {\n + themeData: {\n + get: function() {\n + return this._themeData;\n + },\n +\n + set: function() {\n + throw new Error(\'themeData can\\\'t be changed directly.\' +\n + \' Use themeManager.\');\n + }\n + },\n +\n + font: {\n + get: function() {\n + return this._font;\n + },\n +\n + set: function() {\n + throw new Error(\'font can\\\'t be changed directly.\' +\n + \' Use settings fontsize and fontface.\');\n + }\n + },\n +\n + buffer: {\n + /**\n + * Sets a new buffer.\n + * The buffer\'s file has to be loaded when passing to this setter.\n + */\n + set: function(newBuffer) {\n + if (newBuffer === this._buffer) {\n + return;\n + }\n +\n + if (!newBuffer.loadPromise.isResolved()) {\n + throw new Error(\'buffer.set(): the new buffer must first be \' +\n + \'loaded!\');\n + }\n +\n + // Was there a former buffer? If yes, then remove some events.\n + if (this._buffer !== null) {\n + this.layoutManager.sizeChanged.remove(this);\n + this.layoutManager.textStorage.changed.remove(this);\n + this.textView.selectionChanged.remove(this);\n + }\n +\n + this.willChangeBuffer(newBuffer);\n + catalog.publish(this, \'editorChange\', \'buffer\', newBuffer);\n +\n + this.layoutManager = newBuffer.layoutManager;\n + this._buffer = newBuffer;\n +\n + var lm = this.layoutManager;\n + var tv = this.textView;\n +\n + // Watch out for changes to the layoutManager\'s internal size.\n + lm.sizeChanged.add(this,\n + this._layoutManagerSizeChanged.bind(this));\n +\n + // Map internal events so that developers can listen much easier.\n + lm.textStorage.changed.add(this, this.textChanged.bind(this));\n + tv.selectionChanged.add(this, this.selectionChanged.bind(this));\n +\n + this.textView.setSelection(newBuffer._selectedRange, false);\n + this.scrollOffsetChanged(newBuffer._scrollOffset);\n +\n + // The layoutManager changed and its size as well. Call the\n + // layoutManager.sizeChanged event manually.\n + this.layoutManager.sizeChanged(this.layoutManager.size);\n +\n + this._recomputeLayout();\n + },\n +\n + get: function() {\n + return this._buffer;\n + }\n + },\n +\n + frame: {\n + get: function() {\n + return {\n + width: this.container.offsetWidth,\n + height: this.container.offsetHeight\n + };\n + }\n + },\n +\n + textViewPaddingFrame: {\n + get: function() {\n + var frame = util.clone(this.textView.frame);\n + var padding = this.textView.padding;\n +\n + frame.width -= padding.left + padding.right;\n + frame.height -= padding.top + padding.bottom;\n + return frame;\n + }\n + },\n +\n + scrollOffset: {\n + set: function(pos) {\n + if (pos.x === undefined) pos.x = this.scrollOffset.x;\n + if (pos.y === undefined) pos.y = this.scrollOffset.y;\n +\n + var frame = this.textViewPaddingFrame;\n +\n + if (pos.y < 0) {\n + pos.y = 0;\n + } else if (this._textViewSize.height < frame.height) {\n + pos.y = 0;\n + } else if (pos.y + frame.height > this._textViewSize.height) {\n + pos.y = this._textViewSize.height - frame.height;\n + }\n +\n + if (pos.x < 0) {\n + pos.x = 0;\n + } else if (this._textViewSize.width < frame.width) {\n + pos.x = 0;\n + } else if (pos.x + frame.width > this._textViewSize.width) {\n + pos.x = this._textViewSize.width - frame.width;\n + }\n +\n + if (pos.x === this.scrollOffset.x && pos.y === this.scrollOffset.y) {\n + return;\n + }\n +\n + this.buffer._scrollOffset = pos;\n +\n + this.scrollOffsetChanged(pos);\n + catalog.publish(this, \'editorChange\', \'scrollOffset\', pos);\n + },\n +\n + get: function() {\n + return this.buffer._scrollOffset;\n + }\n + },\n +\n + // -------------------------------------------------------------------------\n + // Helper API:\n +\n + readOnly: {\n + get: function() {\n + return this._buffer.model.readOnly;\n + },\n +\n + set: function(newValue) {\n + this._buffer.model.readOnly = newValue;\n + }\n + },\n +\n + focus: {\n + get: function() {\n + return this.textView.hasFocus;\n + },\n +\n + set: function(setFocus) {\n + if (!util.isBoolean(setFocus)) {\n + throw new Error(\'set focus: expected boolean but found "\' +\n + setFocus + \'"\');\n + }\n + this.textView.hasFocus = setFocus;\n + }\n + },\n +\n + selection: {\n + /** Returns the currently-selected range. */\n + get: function() {\n + return util.clone(this.textView.getSelectedRange(false));\n + },\n +\n + /** Alters the selection. */\n + set: function(newSelection) {\n + if (!rangeutils.isRange(newSelection)) {\n + throw new Error(\'set selection: position/selection\' +\n + \' must be supplied\');\n + }\n +\n + this.textView.setSelection(newSelection);\n + }\n + },\n +\n + selectedText: {\n + /** Returns the text within the given range. */\n + get: function() {\n + return this.getText(this.selection);\n + },\n +\n + /** Replaces the current text selection with the given text. */\n + set: function(newText) {\n + if (!util.isString(newText)) {\n + throw new Error(\'set selectedText: expected string but\' +\n + \' found "\' + newText + \'"\');\n + }\n +\n + return this.replace(this.selection, newText);\n + }\n + },\n +\n + value: {\n + /** Returns the current text. */\n + get: function() {\n + return this.layoutManager.textStorage.value;\n + },\n +\n + set: function(newValue) {\n + if (!util.isString(newValue)) {\n + throw new Error(\'set value: expected string but found "\' +\n + newValue + \'"\');\n + }\n +\n + // Use the replace function and not this.model.value = newValue\n + // directly as this wouldn\'t create a new undoable action.\n + return this.replace(this.layoutManager.textStorage.range,\n + newValue, false);\n + }\n + },\n +\n + syntax: {\n + /**\n + * Returns the initial syntax highlighting context (i.e. the language).\n + */\n + get: function(newSyntax) {\n + return this.layoutManager.syntaxManager.getSyntax();\n + },\n +\n + /**\n + * Sets the initial syntax highlighting context (i.e. the language).\n + */\n + set: function(newSyntax) {\n + if (!util.isString(newSyntax)) {\n + throw new Error(\'set syntax: expected string but found "\' +\n + newValue + \'"\');\n + }\n +\n + return this.layoutManager.syntaxManager.setSyntax(newSyntax);\n + }\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:views/textinput",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var Event = require(\'events\').Event;\n +\n +var KeyUtil = require(\'keyboard:keyutil\');\n +\n +/**\n + * @namespace\n + *\n + * This class provides a hidden text input to provide events similar to those\n + * defined in the DOM Level 3 specification. It allows views to support\n + * internationalized text input via non-US keyboards, dead keys, and/or IMEs.\n + * It also provides support for copy and paste. Currently, an invisible\n + * textarea is used, but in the future this module should use\n + * DOM 3 TextInput events directly where available.\n + *\n + * To use this class, instantiate it and provide the optional functions\n + * - copy: function() { return \'text for clipboard\' }\n + * - cut: function() { \'Cut some text\'; return \'text for clipboard\'}\n + * - textInserted: function(newInsertedText) { \'handle new inserted text\'; }\n + * Note: Pasted text is provided through the textInserted(pastedText) function.\n + *\n + * You can also provide an DOM node to take focus from by providing the optional\n + * "takeFocusFrom" parameter.\n + *\n + * The DOM node created for text input is in the "domNode" attribute\n + * and that caller should add the DOM node to the document in the appropriate\n + * place.\n + */\n +exports.TextInput = function(container, delegate) {\n + var domNode = this.domNode = document.createElement(\'textarea\');\n + domNode.setAttribute(\'style\', \'position: absolute; z-index: -99999; \' +\n + \'width: 0px; height: 0px; margin: 0px; outline: none; border: 0;\');\n + // \'z-index: 100; top: 20px; left: 20px; width: 50px; \' +\n + // \'height: 50px\');\n +\n + container.appendChild(domNode);\n +\n + this.delegate = delegate;\n +\n + this._attachEvents();\n +};\n +\n +exports.TextInput.prototype = {\n + _composing: false,\n +\n + domNode: null,\n +\n + delegate: null,\n +\n + // This function doesn\'t work on WebKit! The textContent comes out empty...\n + _textFieldChanged: function() {\n + if (this._composing || this._ignore) {\n + return;\n + }\n +\n + var textField = this.domNode;\n + var text = textField.value;\n + // On FF textFieldChanged is called sometimes although nothing changed.\n + // -> don\'t call textInserted() in such a case.\n + if (text == \'\') {\n + return;\n + }\n + textField.value = \'\';\n +\n + this._textInserted(text);\n + },\n +\n + _copy: function() {\n + var copyData = false;\n + var delegate = this.delegate;\n + if (delegate && delegate.copy) {\n + copyData = delegate.copy();\n + }\n + return copyData;\n + },\n +\n + _cut: function() {\n + var cutData = false;\n + var delegate = this.delegate;\n + if (delegate && delegate.cut) {\n + cutData = delegate.cut();\n + }\n + return cutData;\n + },\n +\n + _textInserted: function(text) {\n + var delegate = this.delegate;\n + if (delegate && delegate.textInserted) {\n + delegate.textInserted(text);\n + }\n + },\n +\n + _setValueAndSelect: function(text) {\n + var textField = this.domNode;\n + textField.value = text;\n + textField.select();\n + },\n +\n + /**\n + * Gives focus to the field editor so that input events will be\n + * delivered to the view. If you override willBecomeKeyResponderFrom(),\n + * you should call this function in your implementation.\n + */\n + focus: function() {\n + this.domNode.focus();\n + },\n +\n + /**\n + * Removes focus from the invisible text input so that input events are no\n + * longer delivered to this view. If you override willLoseKeyResponderTo(),\n + * you should call this function in your implementation.\n + */\n + blur: function() {\n + this.domNode.blur();\n + },\n +\n + /**\n + * Attaches notification listeners to the text field so that your view will\n + * be notified of events. If you override this method, you should call\n + * that function as well.\n + */\n + _attachEvents: function() {\n + var textField = this.domNode, self = this;\n +\n + // Listen focus/blur event.\n + textField.addEventListener(\'focus\', function(evt) {\n + if (self.delegate && self.delegate.didFocus) {\n + self.delegate.didFocus();\n + }\n + }, false);\n + textField.addEventListener(\'blur\', function(evt) {\n + if (self.delegate && self.delegate.didBlur) {\n + self.delegate.didBlur();\n + }\n + }, false);\n +\n + KeyUtil.addKeyDownListener(textField, function(evt) {\n + if (self.delegate && self.delegate.keyDown) {\n + return self.delegate.keyDown(evt);\n + } else {\n + return false;\n + }\n + });\n +\n + // No way that I can see around this ugly browser sniffing, without\n + // more complicated hacks. No browsers have a complete enough\n + // implementation of DOM 3 events at the current time (12/2009). --pcw\n + if (util.isWebKit) { // Chrome too\n + // On Chrome the compositionend event is fired as well as the\n + // textInput event, but only one of them has to be handled.\n + if (!util.isChrome) {\n + textField.addEventListener(\'compositionend\', function(evt) {\n + self._textInserted(evt.data);\n + }, false);\n + }\n + textField.addEventListener(\'textInput\', function(evt) {\n + self._textInserted(evt.data);\n + }, false);\n + textField.addEventListener(\'paste\', function(evt) {\n + self._textInserted(evt.clipboardData.\n + getData(\'text/plain\'));\n + evt.preventDefault();\n + }, false);\n + } else {\n + var textFieldChangedFn = self._textFieldChanged.bind(self);\n +\n + // Same as above, but executes after all pending events. This\n + // ensures that content gets added to the text field before the\n + // value field is read.\n + var textFieldChangedLater = function() {\n + window.setTimeout(textFieldChangedFn, 0);\n + };\n +\n + textField.addEventListener(\'keydown\', textFieldChangedLater,\n + false);\n + textField.addEventListener(\'keypress\', textFieldChangedFn, false);\n + textField.addEventListener(\'keyup\', textFieldChangedFn, false);\n +\n + textField.addEventListener(\'compositionstart\', function(evt) {\n + self._composing = true;\n + }, false);\n + textField.addEventListener(\'compositionend\', function(evt) {\n + self._composing = false;\n + self._textFieldChanged();\n + }, false);\n +\n + textField.addEventListener(\'paste\', function(evt) {\n + // FIXME: This is ugly and could result in extraneous text\n + // being included as part of the text if extra DOMNodeInserted\n + // or DOMCharacterDataModified events happen to be in the queue\n + // when this function runs. But until Fx supports TextInput\n + // events, there\'s nothing better we can do.\n +\n + // Waits till the paste content is pasted to the textarea.\n + // Sometimes a delay of 0 is too short for Fx. In such a case\n + // the keyUp events occur a little bit later and the pasted\n + // content is detected there.\n + self._setValueAndSelect(\'\');\n + window.setTimeout(function() {\n + self._textFieldChanged();\n + }, 0);\n + }, false);\n + }\n +\n + // Here comes the code for copy and cut...\n +\n + // This is the basic copy and cut function. Depending on the\n + // OS and browser this function needs to be extended.\n + var copyCutBaseFn = function(evt) {\n + // Get the data that should be copied/cutted.\n + var copyCutData = evt.type.indexOf(\'copy\') != -1 ?\n + self._copy() :\n + self._cut();\n + // Set the textField\'s value equal to the copyCutData.\n + // After this function is called, the real copy or cut\n + // event takes place and the selected text in the\n + // textField is pushed to the OS\'s clipboard.\n + self._setValueAndSelect(copyCutData);\n + };\n +\n + // For all browsers that are not Safari running on Mac.\n + if (!(util.isWebKit && !util.isChrome && util.isMac)) {\n + var copyCutMozillaFn = false;\n + if (util.isMozilla) {\n + // If the browser is Mozilla like, the copyCut function has to\n + // be extended.\n + copyCutMozillaFn = function(evt) {\n + // Call the basic copyCut function.\n + copyCutBaseFn(evt);\n +\n + self._ignore = true;\n + window.setTimeout(function() {\n + self._setValueAndSelect(\'\');\n + self._ignore = false;\n + }, 0);\n + };\n + }\n + textField.addEventListener(\'copy\', copyCutMozillaFn ||\n + copyCutBaseFn, false);\n + textField.addEventListener(\'cut\', copyCutMozillaFn ||\n + copyCutBaseFn, false);\n + } else {\n + // For Safari on Mac (only!) the copy and cut event only occurs if\n + // you have some text selected. Fortunately, the beforecopy and\n + // beforecut event occurs before the copy or cut event does so we\n + // can put the to be copied or cutted text in the textarea.\n +\n + // Also, the cut event is fired twice. If it\'s fired twice within a\n + // certain time period, the second call will be skipped.\n + var lastCutCall = new Date().getTime();\n + var copyCutSafariMacFn = function(evt) {\n + var doCut = evt.type.indexOf(\'cut\') != -1;\n + if (doCut && new Date().getTime() - lastCutCall < 10) {\n + return;\n + }\n +\n + // Call the basic copyCut function.\n + copyCutBaseFn(evt);\n +\n + if (doCut) {\n + lastCutCall = new Date().getTime();\n + }\n + };\n +\n + textField.addEventListener(\'beforecopy\', copyCutSafariMacFn,\n + false);\n + textField.addEventListener(\'beforecut\', copyCutSafariMacFn,\n + false);\n + }\n + }\n +};\n +\n +\n +});\n +\n +bespin.tiki.module("text_editor:views/canvas",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var Rect = require(\'utils/rect\');\n +var Event = require(\'events\').Event;\n +\n +/**\n + * @class\n + *\n + * This class provides support for manual scrolling and positioning for canvas-\n + * based elements. Getting these elements to play nicely with SproutCore is\n + * tricky and error-prone, so all canvas-based views should consider deriving\n + * from this class. Derived views should implement drawRect() in order to\n + * perform the appropriate canvas drawing logic.\n + *\n + * The actual size of the canvas is always the size of the container the canvas\n + * view is placed in.\n + *\n + * The canvas that is created is available in the domNode attribute and should\n + * be added to the document by the caller.\n + */\n +exports.CanvasView = function(container, preventDownsize, clearOnFullInvalid) {\n + if (!container) {\n + return;\n + }\n +\n + this._preventDownsize = preventDownsize || false;\n + this._clearOnFullInvalid = clearOnFullInvalid || false;\n + this._clippingFrame = this._frame = {\n + x: 0,\n + y: 0,\n + width: 0,\n + height: 0\n + };\n + this._invalidRects = [];\n +\n + var canvas = document.createElement(\'canvas\');\n + canvas.setAttribute(\'style\', \'position: absolute\');\n + canvas.innerHTML = \'canvas tag not supported by your browser\';\n + container.appendChild(canvas);\n + this.domNode = canvas;\n +\n + this.clippingChanged = new Event();\n + this.clippingChanged.add(this.clippingFrameChanged.bind(this));\n +};\n +\n +exports.CanvasView.prototype = {\n + domNode: null,\n +\n + clippingChanged: null,\n +\n + _canvasContext: null,\n + _canvasId: null,\n + _invalidRects: null,\n + _lastRedrawTime: null,\n + _redrawTimer: null,\n + _clippingFrame: null,\n + _preventDownsize: false,\n + _clearOnFullInvalid: false,\n +\n + _frame: null,\n +\n + _getContext: function() {\n + if (this._canvasContext === null) {\n + this._canvasContext = this.domNode.getContext(\'2d\');\n + }\n + return this._canvasContext;\n + },\n +\n + computeWithClippingFrame: function(x, y) {\n + var clippingFrame = this.clippingFrame;\n + return {\n + x: x + clippingFrame.x,\n + y: y + clippingFrame.y\n + };\n + },\n +\n + /**\n + * @property{Number}\n + *\n + * The minimum delay between canvas redraws in milliseconds, equal to 1000\n + * divided by the desired number of frames per second.\n + */\n + minimumRedrawDelay: 1000.0 / 30.0,\n +\n + /**\n + * Subclasses can override this method to provide custom behavior whenever\n + * the clipping frame changes. The default implementation simply\n + * invalidates the entire visible area.\n + */\n + clippingFrameChanged: function() {\n + this.invalidate();\n + },\n +\n + drawRect: function(rect, context) { },\n +\n + /**\n + * Render the canvas. Rendering is delayed by a few ms to empty the call\n + * stack first before rendering. If the canvas was rendered in less then\n + * this.minimumRedrawDelay ms, then the next rendering will take in\n + * this.minimumRedrawDelay - now + lastRendering ms.\n + */\n + render: function() {\n + // Don\'t continue if there is a rendering or redraw timer already.\n + if (this._renderTimer || this._redrawTimer) {\n + return;\n + }\n +\n + // Queue the redraw at the end of the current event queue to make sure\n + // everyting is done when redrawing.\n + this._renderTimer = setTimeout(this._tryRedraw.bind(this), 0);\n + },\n +\n + /**\n + * Invalidates the entire visible region of the canvas.\n + */\n + invalidate: function(rect) {\n + this._invalidRects = \'all\';\n + this.render();\n + },\n +\n + /**\n + * Invalidates the given rect of the canvas, and schedules that portion of\n + * the canvas to be redrawn at the end of the run loop.\n + */\n + invalidateRect: function(rect) {\n + var invalidRects = this._invalidRects;\n + if (invalidRects !== \'all\') {\n + invalidRects.push(rect);\n + this.render();\n + }\n + },\n +\n + _tryRedraw: function(context) {\n + this._renderTimer = null;\n +\n + var now = new Date().getTime();\n + var lastRedrawTime = this._lastRedrawTime;\n + var minimumRedrawDelay = this.minimumRedrawDelay;\n +\n + if (lastRedrawTime === null ||\n + now - lastRedrawTime >= minimumRedrawDelay) {\n + this._redraw();\n + return;\n + }\n +\n + var redrawTimer = this._redrawTimer;\n + if (redrawTimer !== null) {\n + return; // already scheduled\n + }\n +\n + // TODO This is not as good as SC.Timer... Will it work?\n + this._redrawTimer = window.setTimeout(this._redraw.bind(this),\n + minimumRedrawDelay);\n + },\n +\n + /**\n + * Calls drawRect() on all the invalid rects to redraw the canvas contents.\n + * Generally, you should not need to call this function unless you override\n + * the default implementations of didCreateLayer() or render().\n + */\n + _redraw: function() {\n + var clippingFrame = this.clippingFrame;\n + clippingFrame = {\n + x: Math.round(clippingFrame.x),\n + y: Math.round(clippingFrame.y),\n + width: clippingFrame.width,\n + height: clippingFrame.height\n + };\n +\n + var context = this._getContext();\n + context.save();\n + context.translate(-clippingFrame.x, -clippingFrame.y);\n +\n + var invalidRects = this._invalidRects;\n + if (invalidRects === \'all\') {\n + if (this._clearOnFullInvalid) {\n + context.clearRect(0, 0, this.domNode.width, this.domNode.height);\n + }\n + this.drawRect(clippingFrame, context);\n + } else {\n + Rect.merge(invalidRects).forEach(function(rect) {\n + rect = Rect.intersectRects(rect, clippingFrame);\n + if (rect.width !== 0 && rect.height !== 0) {\n + context.save();\n +\n + var x = rect.x, y = rect.y;\n + var width = rect.width, height = rect.height;\n + context.beginPath();\n + context.moveTo(x, y);\n + context.lineTo(x + width, y);\n + context.lineTo(x + width, y + height);\n + context.lineTo(x, y + height);\n + context.closePath();\n + context.clip();\n +\n + this.drawRect(rect, context);\n +\n + context.restore();\n + }\n +\n + }, this);\n + }\n +\n + context.restore();\n +\n + this._invalidRects = [];\n + this._redrawTimer = null;\n + this._lastRedrawTime = new Date().getTime();\n + }\n +};\n +\n +Object.defineProperties(exports.CanvasView.prototype, {\n + clippingFrame: {\n + get: function() {\n + return this._clippingFrame;\n + },\n +\n + set: function(clippingFrame) {\n + clippingFrame = util.mixin(util.clone(this._clippingFrame), clippingFrame);\n +\n + if (this._clippingFrame === null ||\n + !Rect.rectsEqual(clippingFrame, this._clippingFrame)) {\n + this._clippingFrame = clippingFrame;\n + this.clippingChanged();\n + }\n + }\n + },\n +\n + frame: {\n + get: function() {\n + return this._frame;\n + },\n + \n + set: function(frame) {\n + var domNode = this.domNode;\n + var domStyle = domNode.style;\n + var preventDownsize = this._preventDownsize;\n + var domWidth = domNode.width;\n + var domHeight = domNode.height;\n + var domStyle = domNode.style;\n + domStyle.left = frame.x + \'px\';\n + domStyle.top = frame.y + \'px\';\n +\n + var widthChanged, heightChanged;\n + if (frame.width !== domWidth) {\n + if (frame.width < domWidth) {\n + if (!preventDownsize) {\n + widthChanged = true;\n + }\n + } else {\n + widthChanged = true;\n + }\n + }\n + if (frame.height !== domHeight) {\n + if (frame.height < domHeight) {\n + if (!preventDownsize) {\n + heightChanged = true;\n + }\n + } else {\n + heightChanged = true;\n + }\n + }\n +\n + if (widthChanged) {\n + this.domNode.width = frame.width;\n + }\n + if (heightChanged) {\n + this.domNode.height = frame.height;\n + }\n +\n + this._frame = frame;\n +\n + // The clipping frame might have changed if the size changed.\n + this.clippingFrame = {\n + width: frame.width,\n + height: frame.height\n + };\n + }\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:views/text",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var util = require(\'bespin:util/util\');\n +\n +var Event = require(\'events\').Event;\n +var CanvasView = require(\'views/canvas\').CanvasView;\n +var LayoutManager = require(\'controllers/layoutmanager\').LayoutManager;\n +var Range = require(\'rangeutils:utils/range\');\n +var Rect = require(\'utils/rect\');\n +var TextInput = require(\'views/textinput\').TextInput;\n +var console = require(\'bespin:console\').console;\n +var settings = require(\'settings\').settings;\n +\n +// Set this to true to outline all text ranges with a box. This may be useful\n +// when optimizing syntax highlighting engines.\n +var DEBUG_TEXT_RANGES = false;\n +\n +\n +exports.TextView = function(container, editor) {\n + CanvasView.call(this, container, true /* preventDownsize */ );\n + this.editor = editor;\n +\n + // Takes the layoutManager of the editor and uses it.\n + var textInput = this.textInput = new TextInput(container, this);\n +\n + this.padding = {\n + top: 0,\n + bottom: 30,\n + left: 0,\n + right: 30\n + };\n +\n + this.clippingChanged.add(this.clippingFrameChanged.bind(this));\n +\n + var dom = this.domNode;\n + dom.style.cursor = "text";\n + dom.addEventListener(\'mousedown\', this.mouseDown.bind(this), false);\n + dom.addEventListener(\'mousemove\', this.mouseMove.bind(this), false);\n + window.addEventListener(\'mouseup\', this.mouseUp.bind(this), false);\n +\n + editor.willChangeBuffer.add(this.editorWillChangeBuffer.bind(this));\n +\n + // Changeevents.\n + this.selectionChanged = new Event();\n + this.beganChangeGroup = new Event();\n + this.endedChangeGroup = new Event();\n + this.willReplaceRange = new Event();\n + this.replacedCharacters = new Event();\n +};\n +\n +exports.TextView.prototype = new CanvasView();\n +\n +util.mixin(exports.TextView.prototype, {\n + _dragPoint: null,\n + _dragTimer: null,\n + _enclosingScrollView: null,\n + _inChangeGroup: false,\n + _insertionPointBlinkTimer: null,\n + _insertionPointVisible: true,\n +\n +\n + // FIXME: These should be public, not private.\n + _keyBuffer: \'\',\n + _keyMetaBuffer: \'\',\n + _keyState: \'start\',\n +\n + _hasFocus: false,\n + _mouseIsDown: false,\n +\n + selectionChanged: null,\n + beganChangeGroup: null,\n + endedChangeGroup: null,\n + willReplaceRange: null,\n + replacedCharacters: null,\n +\n + editorWillChangeBuffer: function(newBuffer) {\n + if (this.editor.layoutManager) {\n + // Remove events from the old layoutManager.\n + var layoutManager = this.editor.layoutManager;\n + layoutManager.invalidatedRects.remove(this);\n + layoutManager.changedTextAtRow.remove(this);\n + }\n +\n + // Add the events to the new layoutManager.\n + layoutManager = newBuffer.layoutManager;\n + layoutManager.invalidatedRects.add(this,\n + this.layoutManagerInvalidatedRects.bind(this));\n + layoutManager.changedTextAtRow.add(this,\n + this.layoutManagerChangedTextAtRow.bind(this));\n + },\n +\n + /**\n + * Called by the textInput whenever the textInput gained the focus.\n + */\n + didFocus: function() {\n + // Call _setFocus and not this.hasFocus as we have to pass the\n + // \'isFromTextInput\' flag.\n + this._setFocus(true, true /* fromTextInput */);\n + },\n +\n + /**\n + * Called by the textInput whenever the textinput lost the focus.\n + */\n + didBlur: function() {\n + // Call _setFocus and not this.hasFocus as we have to pass the\n + // \'isFromTextInput\' flag.\n + this._setFocus(false, true /* fromTextInput */);\n + },\n +\n + _drag: function() {\n + var point = this._dragPoint;\n + var offset = Rect.offsetFromRect(this.clippingFrame, point);\n +\n + this.moveCursorTo(this._selectionPositionForPoint({\n + x: point.x - offset.x,\n + y: point.y - offset.y\n + }), true);\n + },\n +\n + // Draws a single insertion point.\n + _drawInsertionPoint: function(rect, context) {\n + if (!this._insertionPointVisible) {\n + return;\n + }\n +\n + var range = this.editor.buffer._selectedRange;\n + var characterRect = this.editor.layoutManager.\n + characterRectForPosition(range.start);\n + var x = Math.floor(characterRect.x), y = characterRect.y;\n + var width = Math.ceil(characterRect.width);\n + var height = characterRect.height;\n +\n + context.save();\n +\n + var theme = this.editor.themeData.editor;\n + if (this._hasFocus) {\n + context.strokeStyle = theme.cursorColor;\n + context.beginPath();\n + context.moveTo(x + 0.5, y);\n + context.lineTo(x + 0.5, y + height);\n + context.closePath();\n + context.stroke();\n + } else {\n + context.fillStyle = theme.unfocusedCursorBackgroundColor;\n + context.fillRect(x + 0.5, y, width - 0.5, height);\n + context.strokeStyle = theme.unfocusedCursorColor;\n + context.strokeRect(x + 0.5, y + 0.5, width - 1, height - 1);\n + }\n +\n + context.restore();\n + },\n +\n + _drawLines: function(rect, context) {\n + var layoutManager = this.editor.layoutManager;\n + var textLines = layoutManager.textLines;\n + var lineAscent = layoutManager.fontDimension.lineAscent;\n + var themeHighlighter = this.editor.themeData.highlighter\n +\n + context.save();\n + context.font = this.editor.font;\n +\n + var range = layoutManager.characterRangeForBoundingRect(rect);\n + var rangeStart = range.start, rangeEnd = range.end;\n + var startRow = rangeStart.row, endRow = rangeEnd.row;\n + for (var row = startRow; row <= endRow; row++) {\n + var textLine = textLines[row];\n + if (util.none(textLine)) {\n + continue;\n + }\n +\n + // Clamp the start column and end column to fit within the line\n + // text.\n + var characters = textLine.characters;\n + var length = characters.length;\n + var endCol = Math.min(rangeEnd.col, length);\n + var startCol = rangeStart.col;\n + if (startCol >= length) {\n + continue;\n + }\n +\n + // Get the color ranges, or synthesize one if it doesn\'t exist. We\n + // have to be tolerant of bad data, because we may be drawing ahead\n + // of the syntax highlighter.\n + var colorRanges = textLine.colors;\n + if (colorRanges == null) {\n + colorRanges = [];\n + }\n +\n + // Figure out which color range to start in.\n + var colorIndex = 0;\n + while (colorIndex < colorRanges.length &&\n + startCol < colorRanges[colorIndex].start) {\n + colorIndex++;\n + }\n +\n + var col = (colorIndex < colorRanges.length)\n + ? colorRanges[colorIndex].start\n + : startCol;\n +\n + // And finally draw the line.\n + while (col < endCol) {\n + var colorRange = colorRanges[colorIndex];\n + var end = colorRange != null ? colorRange.end : endCol;\n + var tag = colorRange != null ? colorRange.tag : \'plain\';\n +\n + var color = themeHighlighter.hasOwnProperty(tag)\n + ? themeHighlighter[tag]\n + : \'red\';\n + context.fillStyle = color;\n +\n + var pos = { row: row, col: col };\n + var rect = layoutManager.characterRectForPosition(pos);\n +\n + var snippet = characters.substring(col, end);\n + context.fillText(snippet, rect.x, rect.y + lineAscent);\n +\n + if (DEBUG_TEXT_RANGES) {\n + context.strokeStyle = color;\n + context.strokeRect(rect.x + 0.5, rect.y + 0.5,\n + rect.width * snippet.length - 1, rect.height - 1);\n + }\n +\n + col = end;\n + colorIndex++;\n + }\n + }\n +\n + context.restore();\n + },\n +\n + // Draws the background highlight for selections.\n + _drawSelectionHighlight: function(rect, context) {\n + var theme = this.editor.themeData.editor;\n + var fillStyle = this._hasFocus ?\n + theme.selectedTextBackgroundColor :\n + theme.unfocusedCursorBackgroundColor;\n + var layoutManager = this.editor.layoutManager;\n +\n + context.save();\n +\n + var range = Range.normalizeRange(this.editor.buffer._selectedRange);\n + context.fillStyle = fillStyle;\n + layoutManager.rectsForRange(range).forEach(function(rect) {\n + context.fillRect(rect.x, rect.y, rect.width, rect.height);\n + });\n +\n + context.restore();\n + },\n +\n + // Draws either the selection or the insertion point.\n + _drawSelection: function(rect, context) {\n + if (this._rangeIsInsertionPoint(this.editor.buffer._selectedRange)) {\n + this._drawInsertionPoint(rect, context);\n + } else {\n + this._drawSelectionHighlight(rect, context);\n + }\n + },\n +\n + _getVirtualSelection: function(startPropertyAsWell) {\n + var selectedRange = this.editor.buffer._selectedRange;\n + var selectedRangeEndVirtual = this.editor.buffer._selectedRangeEndVirtual;\n +\n + return {\n + start: startPropertyAsWell && selectedRangeEndVirtual ?\n + selectedRangeEndVirtual : selectedRange.start,\n + end: selectedRangeEndVirtual || selectedRange.end\n + };\n + },\n +\n + _invalidateSelection: function() {\n + var adjustRect = function(rect) {\n + return {\n + x: rect.x - 1,\n + y: rect.y,\n + width: rect.width + 2,\n + height: rect.height\n + };\n + };\n +\n + var layoutManager = this.editor.layoutManager;\n + var range = Range.normalizeRange(this.editor.buffer._selectedRange);\n + if (!this._rangeIsInsertionPoint(range)) {\n + var rects = layoutManager.rectsForRange(range);\n + rects.forEach(function(rect) {\n + this.invalidateRect(adjustRect(rect));\n + }, this);\n +\n + return;\n + }\n +\n + var rect = layoutManager.characterRectForPosition(range.start);\n + this.invalidateRect(adjustRect(rect));\n + },\n +\n + _isReadOnly: function() {\n + return this.editor.layoutManager.textStorage.readOnly;\n + },\n +\n + _keymappingChanged: function() {\n + this._keyBuffer = \'\';\n + this._keyState = \'start\';\n + },\n +\n + _performVerticalKeyboardSelection: function(offset) {\n + var textStorage = this.editor.layoutManager.textStorage;\n + var selectedRangeEndVirtual = this.editor.buffer._selectedRangeEndVirtual;\n + var oldPosition = selectedRangeEndVirtual !== null ?\n + selectedRangeEndVirtual : this.editor.buffer._selectedRange.end;\n + var newPosition = Range.addPositions(oldPosition,\n + { row: offset, col: 0 });\n +\n + this.moveCursorTo(newPosition, true, true);\n + },\n +\n + _rangeIsInsertionPoint: function(range) {\n + return Range.isZeroLength(range);\n + },\n +\n + _rearmInsertionPointBlinkTimer: function() {\n + if (!this._insertionPointVisible) {\n + // Make sure it ends up visible.\n + this.blinkInsertionPoint();\n + }\n +\n + if (this._insertionPointBlinkTimer !== null) {\n + clearInterval(this._insertionPointBlinkTimer);\n + }\n +\n + this._insertionPointBlinkTimer = setInterval(\n + this.blinkInsertionPoint.bind(this),\n + 750);\n + },\n +\n + // Moves the selection, if necessary, to keep all the positions pointing to\n + // actual characters.\n + _repositionSelection: function() {\n + var textLines = this.editor.layoutManager.textLines;\n + var textLineLength = textLines.length;\n +\n + var range = this.editor.buffer._selectedRange;\n + var newStartRow = Math.min(range.start.row, textLineLength - 1);\n + var newEndRow = Math.min(range.end.row, textLineLength - 1);\n + var startLine = textLines[newStartRow];\n + var endLine = textLines[newEndRow];\n + this.setSelection({\n + start: {\n + row: newStartRow,\n + col: Math.min(range.start.col, startLine.characters.length)\n + },\n + end: {\n + row: newEndRow,\n + col: Math.min(range.end.col, endLine.characters.length)\n + }\n + });\n + },\n +\n + _scrollPage: function(scrollUp) {\n + var clippingFrame = this.clippingFrame;\n + var lineAscent = this.editor.layoutManager.fontDimension.lineAscent;\n + this.editor.scrollBy(0,\n + (clippingFrame.height + lineAscent) * (scrollUp ? -1 : 1));\n + },\n +\n + _scrollWhileDragging: function() {\n + var point = this._dragPoint;\n + var newPoint = this.computeWithClippingFrame(point.layerX, point.layerY);\n + util.mixin(this._dragPoint, newPoint);\n + this._drag();\n + },\n +\n + // Returns the character closest to the given point, obeying the selection\n + // rules (including the partialFraction field).\n + _selectionPositionForPoint: function(point) {\n + var position = this.editor.layoutManager.characterAtPoint(point);\n + return position.partialFraction < 0.5 ? position :\n + Range.addPositions(position, { row: 0, col: 1 });\n + },\n +\n + _syntaxManagerUpdatedSyntaxForRows: function(startRow, endRow) {\n + if (startRow === endRow) {\n + return;\n + }\n +\n + var layoutManager = this.editor.layoutManager;\n + layoutManager.updateTextRows(startRow, endRow);\n +\n + layoutManager.rectsForRange({\n + start: { row: startRow, col: 0 },\n + end: { row: endRow, col: 0 }\n + }).forEach(this.invalidateRect, this);\n + },\n +\n + /**\n + * Toggles the visible state of the insertion point.\n + */\n + blinkInsertionPoint: function() {\n + this._insertionPointVisible = !this._insertionPointVisible;\n + this._invalidateSelection();\n + },\n +\n + /**\n + * Returns the selected characters.\n + */\n + copy: function() {\n + return this.getSelectedCharacters();\n + },\n +\n + /**\n + * Removes the selected characters from the text buffer and returns them.\n + */\n + cut: function() {\n + var cutData = this.getSelectedCharacters();\n +\n + if (cutData != \'\') {\n + this.performBackspaceOrDelete(false);\n + }\n +\n + return cutData;\n + },\n +\n + /**\n + * This is where the editor is painted from head to toe. Pitiful tricks are\n + * used to draw as little as possible.\n + */\n + drawRect: function(rect, context) {\n + context.fillStyle = this.editor.themeData.editor.backgroundColor;\n + context.fillRect(rect.x, rect.y, rect.width, rect.height);\n +\n + this._drawSelection(rect, context);\n + this._drawLines(rect, context);\n + },\n +\n + /**\n + * Directs keyboard input to this text view.\n + */\n + focus: function() {\n + this.textInput.focus();\n + },\n +\n + /** Returns the location of the insertion point in pixels. */\n + getInsertionPointPosition: function() {\n + var editor = this.editor;\n + var range = editor.buffer._selectedRange;\n + var rect = editor.layoutManager.characterRectForPosition(range.start);\n + return { x: rect.x, y: rect.y };\n + },\n +\n + /**\n + * Returns the characters that are currently selected as a string, or the\n + * empty string if none are selected.\n + */\n + getSelectedCharacters: function() {\n + return this._rangeIsInsertionPoint(this.editor.buffer._selectedRange) ? \'\' :\n + this.editor.layoutManager.textStorage.getCharacters(Range.\n + normalizeRange(this.editor.buffer._selectedRange));\n + },\n +\n + /*\n + * Returns the currently selected range.\n + *\n + * @param raw If true, the direction of the selection is preserved: the\n + * \'start\' field will be the selection origin, and the \'end\'\n + * field will always be the selection tail.\n + */\n + getSelectedRange: function(raw) {\n + if (!raw) {\n + return Range.normalizeRange(this.editor.buffer._selectedRange);\n + } else {\n + return this.editor.buffer._selectedRange;\n + }\n + },\n +\n + /**\n + * Groups all the changes in the callback into a single undoable action.\n + * Nested change groups are supported; one undoable action is created for\n + * the entire group of changes.\n + */\n + groupChanges: function(performChanges) {\n + if (this._isReadOnly()) {\n + return false;\n + }\n +\n + if (this._inChangeGroup) {\n + performChanges();\n + return true;\n + }\n +\n + this._inChangeGroup = true;\n + this.beganChangeGroup(this, this.editor.buffer._selectedRange);\n +\n + try {\n + performChanges();\n + } catch (e) {\n + console.error("Error in groupChanges(): " + e);\n + this._inChangeGroup = false;\n + this.endedChangeGroup(this, this.editor.buffer._selectedRange);\n + return false;\n + } finally {\n + this._inChangeGroup = false;\n + this.endedChangeGroup(this, this.editor.buffer._selectedRange);\n + return true;\n + }\n + },\n +\n + /**\n + * Replaces the selection with the given text and updates the selection\n + * boundaries appropriately.\n + *\n + * @return True if the text view was successfully updated; false if the\n + * change couldn\'t be made because the text view is read-only.\n + */\n + insertText: function(text) {\n + if (this._isReadOnly()) {\n + return false;\n + }\n +\n + this.groupChanges(function() {\n + var textStorage = this.editor.layoutManager.textStorage;\n + var range = Range.normalizeRange(this.editor.buffer._selectedRange);\n +\n + this.replaceCharacters(range, text);\n +\n + // Update the selection to point immediately after the inserted\n + // text.\n + var lines = text.split(\'\\n\');\n +\n + var destPosition;\n + if (lines.length > 1) {\n + destPosition = {\n + row: range.start.row + lines.length - 1,\n + col: lines[lines.length - 1].length\n + };\n + } else {\n + destPosition = Range.addPositions(range.start,\n + { row: 0, col: text.length });\n + }\n +\n + this.moveCursorTo(destPosition);\n + }.bind(this));\n +\n + return true;\n + },\n +\n + /**\n + * Returns true if the given character is a word separator.\n + */\n + isDelimiter: function(character) {\n + return \'"\\\',;.!~@#$%^&*?[]<>():/\\\\-+ \\t\'.indexOf(character) !== -1;\n + },\n +\n + keyDown: function(evt) {\n + if (evt.charCode === 0 || evt._charCode === 0) { // hack for Fx\n + var preds = { isTextView: true };\n + return this.editor.processKeyEvent(evt, this, preds);\n + } else if (evt.keyCode === 9) {\n + // Stops the tab. Otherwise the editor can lose focus.\n + evt.preventDefault();\n + } else {\n + // This is a real keyPress event. This should not be handled,\n + // otherwise the textInput mixin can\'t detect the key events.\n + return false;\n + }\n + },\n +\n + /**\n + * Runs the syntax highlighter from the given row to the end of the visible\n + * range, and repositions the selection.\n + */\n + layoutManagerChangedTextAtRow: function(sender, row) {\n + this._repositionSelection();\n + },\n +\n + /**\n + * Marks the given rectangles as invalid.\n + */\n + layoutManagerInvalidatedRects: function(sender, rects) {\n + rects.forEach(this.invalidateRect, this);\n + },\n +\n + mouseDown: function(evt) {\n + util.stopEvent(evt);\n +\n + this.hasFocus = true;\n + this._mouseIsDown = true;\n +\n + var point = this.computeWithClippingFrame(evt.layerX, evt.layerY);\n + util.mixin(point, { layerX: evt.layerX, layerY: evt.layerY});\n +\n + switch (evt.detail) {\n + case 1:\n + var pos = this._selectionPositionForPoint(point);\n + this.moveCursorTo(pos, evt.shiftKey);\n + break;\n +\n + // Select the word under the cursor.\n + case 2:\n + var pos = this._selectionPositionForPoint(point);\n + var line = this.editor.layoutManager.textStorage.lines[pos.row];\n +\n + // If there is nothing to select in this line, then skip.\n + if (line.length === 0) {\n + return true;\n + }\n +\n + pos.col -= (pos.col == line.length ? 1 : 0);\n + var skipOnDelimiter = !this.isDelimiter(line[pos.col]);\n +\n + var thisTextView = this;\n + var searchForDelimiter = function(pos, dir) {\n + for (pos; pos > -1 && pos < line.length; pos += dir) {\n + if (thisTextView.isDelimiter(line[pos]) ===\n + skipOnDelimiter) {\n + break;\n + }\n + }\n + return pos + (dir == 1 ? 0 : 1);\n + };\n +\n + var colFrom = searchForDelimiter(pos.col, -1);\n + var colTo = searchForDelimiter(pos.col, 1);\n +\n + this.moveCursorTo({ row: pos.row, col: colFrom });\n + this.moveCursorTo({ row: pos.row, col: colTo }, true);\n +\n + break;\n +\n + case 3:\n + var lines = this.editor.layoutManager.textStorage.lines;\n + var pos = this._selectionPositionForPoint(point);\n + this.setSelection({\n + start: {\n + row: pos.row,\n + col: 0\n + },\n + end: {\n + row: pos.row,\n + col: lines[pos.row].length\n + }\n + });\n + break;\n + }\n +\n + this._dragPoint = point;\n + this._dragTimer = setInterval(this._scrollWhileDragging.bind(this), 100);\n + },\n +\n + mouseMove: function(evt) {\n + if (this._mouseIsDown) {\n + this._dragPoint = this.computeWithClippingFrame(evt.layerX, evt.layerY);\n + util.mixin(this._dragPoint, { layerX: evt.layerX, layerY: evt.layerY});\n + this._drag();\n + }\n + },\n +\n + mouseUp: function(evt) {\n + this._mouseIsDown = false;\n + if (this._dragTimer !== null) {\n + clearInterval(this._dragTimer);\n + this._dragTimer = null;\n + }\n + },\n +\n + /**\n + * Moves the cursor.\n + *\n + * @param position{Position} The position to move the cursor to.\n + *\n + * @param select{bool} Whether to preserve the selection origin. If this\n + * parameter is false, the selection is removed, and the insertion\n + * point moves to @position. Typically, this parameter is set when\n + * the mouse is being dragged or the shift key is held down.\n + *\n + * @param virtual{bool} Whether to save the current end position as the\n + * virtual insertion point. Typically, this parameter is set when\n + * moving vertically.\n + */\n + moveCursorTo: function(position, select, virtual) {\n + var textStorage = this.editor.layoutManager.textStorage;\n + var positionToUse = textStorage.clampPosition(position);\n +\n + this.setSelection({\n + start: select ? this.editor.buffer._selectedRange.start : positionToUse,\n + end: positionToUse\n + });\n +\n + if (virtual) {\n + var lineCount = textStorage.lines.length;\n + var row = position.row, col = position.col;\n + if (row > 0 && row < lineCount) {\n + this.editor.buffer._selectedRangeEndVirtual = position;\n + } else {\n + this.editor.buffer._selectedRangeEndVirtual = {\n + row: row < 1 ? 0 : lineCount - 1,\n + col: col\n + };\n + }\n + } else {\n + this.editor.buffer._selectedRangeEndVirtual = null;\n + }\n +\n + this.scrollToPosition(this.editor.buffer._selectedRange.end);\n + },\n +\n + moveDown: function() {\n + var selection = this._getVirtualSelection();\n + var range = Range.normalizeRange(selection);\n + var position;\n + if (this._rangeIsInsertionPoint(this.editor.buffer._selectedRange)) {\n + position = range.end;\n + } else {\n + // Yes, this is actually what Cocoa does... weird, huh?\n + position = { row: range.end.row, col: range.start.col };\n + }\n + position = Range.addPositions(position, { row: 1, col: 0 });\n +\n + this.moveCursorTo(position, false, true);\n + },\n +\n + moveLeft: function() {\n + var range = Range.normalizeRange(this.editor.buffer._selectedRange);\n + if (this._rangeIsInsertionPoint(range)) {\n + this.moveCursorTo(this.editor.layoutManager.textStorage.\n + displacePosition(range.start, -1));\n + } else {\n + this.moveCursorTo(range.start);\n + }\n + },\n +\n + moveRight: function() {\n + var range = Range.normalizeRange(this.editor.buffer._selectedRange);\n + if (this._rangeIsInsertionPoint(range)) {\n + this.moveCursorTo(this.editor.layoutManager.textStorage.\n + displacePosition(range.end, 1));\n + } else {\n + this.moveCursorTo(range.end);\n + }\n + },\n +\n + moveUp: function() {\n + var range = Range.normalizeRange(this._getVirtualSelection(true));\n + position = Range.addPositions({\n + row: range.start.row,\n + col: this._getVirtualSelection().end.col\n + }, { row: -1, col: 0 });\n +\n + this.moveCursorTo(position, false, true);\n + },\n +\n + parentViewFrameChanged: function() {\n + arguments.callee.base.apply(this, arguments);\n + this._resize();\n + },\n +\n + /**\n + * As an undoable action, replaces the characters within the old range with\n + * the supplied characters.\n + *\n + * TODO: Factor this out into the undo controller. The fact that commands\n + * have to go through the view in order to make undoable changes is\n + * counterintuitive.\n + *\n + * @param oldRange{Range} The range of characters to modify.\n + * @param characters{string} The string to replace the characters with.\n + *\n + * @return True if the changes were successfully made; false if the changes\n + * couldn\'t be made because the editor is read-only.\n + */\n + replaceCharacters: function(oldRange, characters) {\n + if (this._isReadOnly()) {\n + return false;\n + }\n +\n + this.groupChanges(function() {\n + oldRange = Range.normalizeRange(oldRange);\n + this.willReplaceRange(this, oldRange);\n +\n + var textStorage = this.editor.layoutManager.textStorage;\n + textStorage.replaceCharacters(oldRange, characters);\n + this.replacedCharacters(this, oldRange, characters);\n + }.bind(this));\n +\n + return true;\n + },\n +\n + /**\n + * Performs a delete-backward or delete-forward operation.\n + *\n + * @param isBackspace{boolean} If true, the deletion proceeds backward (as if\n + * the backspace key were pressed); otherwise, deletion proceeds forward.\n + *\n + * @return True if the operation was successfully performed; false if the\n + * operation failed because the editor is read-only.\n + */\n + performBackspaceOrDelete: function(isBackspace) {\n + if (this._isReadOnly()) {\n + return false;\n + }\n +\n + var model = this.editor.layoutManager.textStorage;\n +\n + var lines = model.lines;\n + var line = \'\', count = 0;\n + var tabstop = settings.get(\'tabstop\');\n + var range = this.getSelectedRange();\n +\n + if (Range.isZeroLength(range)) {\n + if (isBackspace) {\n + var start = range.start;\n + line = lines[start.row];\n + var preWhitespaces = line.substring(0, start.col).\n + match(/\\s*$/)[0].length;\n +\n + // If there are less then n-tabstop whitespaces in front, OR\n + // the current cursor position is not n times tabstop, THEN\n + // delete only 1 character.\n + if (preWhitespaces < tabstop\n + || (start.col - tabstop) % tabstop != 0) {\n + count = 1;\n + } else {\n + // Otherwise delete tabstop whitespaces.\n + count = tabstop;\n + }\n +\n + range = {\n + start: model.displacePosition(start, count * -1),\n + end: range.end\n + };\n + } else {\n + var end = range.end;\n + line = lines[end.row];\n + var trailingWhitespaces = line.substring(end.col).\n + match(/^\\s*/)[0].length;\n +\n + // If there are less then n-tabstop whitespaces after the cursor\n + // position, then delete only 1 character. Otherwise delete\n + // tabstop whitespaces.\n + if (trailingWhitespaces < tabstop) {\n + count = 1;\n + } else {\n + count = tabstop;\n + }\n +\n + range = {\n + start: range.start,\n + end: model.displacePosition(range.end, count)\n + };\n + }\n + }\n +\n + this.groupChanges(function() {\n + this.replaceCharacters(range, \'\');\n +\n + // Position the insertion point at the start of all the ranges that\n + // were just deleted.\n + this.moveCursorTo(range.start);\n + }.bind(this));\n +\n + return true;\n + },\n +\n + /** Removes all buffered keys. */\n + resetKeyBuffers: function() {\n + this._keyBuffer = \'\';\n + this._keyMetaBuffer = \'\';\n + },\n +\n + /**\n + * If the text view is inside a scrollable view, scrolls down by one page.\n + */\n + scrollPageDown: function() {\n + this._scrollPage(false);\n + },\n +\n + /**\n + * If the text view is inside a scrollable view, scrolls up by one page.\n + */\n + scrollPageUp: function() {\n + this._scrollPage(true);\n + },\n +\n + /**\n + * If this view is in a scrollable container, scrolls to the given\n + * character position.\n + */\n + scrollToPosition: function(position) {\n + var rect = this.editor.layoutManager.characterRectForPosition(position);\n + var rectX = rect.x, rectY = rect.y;\n + var rectWidth = rect.width, rectHeight = rect.height;\n +\n + var frame = this.clippingFrame;\n + var frameX = frame.x, frameY = frame.y;\n +\n + var padding = this.padding;\n + var width = frame.width - padding.right;\n + var height = frame.height - padding.bottom;\n +\n + var x;\n + if (rectX >= frameX + 30 /* This is a hack to allow dragging to the left */\n + && rectX + rectWidth < frameX + width) {\n + x = frameX;\n + } else {\n + x = rectX - width / 2 + rectWidth / 2;\n + }\n +\n + var y;\n + if (rectY >= frameY && rectY + rectHeight < frameY + height) {\n + y = frameY;\n + } else {\n + y = rectY - height / 2 + rectHeight / 2;\n + }\n +\n + this.editor.scrollTo({ x: x, y: y });\n + },\n +\n + /**\n + * Selects all characters in the buffer.\n + */\n + selectAll: function() {\n + var lines = this.editor.layoutManager.textStorage.lines;\n + var lastRow = lines.length - 1;\n + this.setSelection({\n + start: { row: 0, col: 0 },\n + end: { row: lastRow, col: lines[lastRow].length }\n + });\n + },\n +\n + selectDown: function() {\n + this._performVerticalKeyboardSelection(1);\n + },\n +\n + selectLeft: function() {\n + this.moveCursorTo((this.editor.layoutManager.textStorage.\n + displacePosition(this.editor.buffer._selectedRange.end, -1)), true);\n + },\n +\n + selectRight: function() {\n + this.moveCursorTo((this.editor.layoutManager.textStorage.\n + displacePosition(this.editor.buffer._selectedRange.end, 1)), true);\n + },\n +\n + selectUp: function() {\n + this._performVerticalKeyboardSelection(-1);\n + },\n +\n + /**\n + * Directly replaces the current selection with a new one.\n + */\n + setSelection: function(newRange, ensureVisible) {\n + var textStorage = this.editor.layoutManager.textStorage;\n +\n + newRange = textStorage.clampRange(newRange);\n + if (Range.equal(newRange, this.editor.buffer._selectedRange)) {\n + return;\n + }\n +\n + // Invalidate the old selection.\n + this._invalidateSelection();\n +\n + // Set the new selection and invalidate it.\n + this.editor.buffer._selectedRange = newRange =\n + textStorage.clampRange(newRange);\n + this._invalidateSelection();\n +\n + if (this._hasFocus) {\n + this._rearmInsertionPointBlinkTimer();\n + }\n +\n + if (ensureVisible) {\n + this.scrollToPosition(newRange.end);\n + }\n +\n + this.selectionChanged(newRange);\n + catalog.publish(this.editor, \'editorChange\', \'selection\', newRange);\n + },\n +\n + textInserted: function(text) {\n + // We don\'t handle the new line char at this point.\n + if (text === \'\\n\') {\n + return;\n + }\n +\n + var preds = { isTextView: true, isCommandKey: false };\n + if (!this.editor.processKeyEvent(text, this, preds)) {\n + this.insertText(text);\n + this.resetKeyBuffers();\n + }\n + },\n +\n + /**\n + * Changes the internal hasFocus flag if the current hasFocus value is not\n + * equal to the parameter \'value\'. If \'fromTextInput\' is true, then\n + * the textInput.focus() and textInput.blur() is not called. This is\n + * necessary as otherwise the textInput detects the blur event, calls\n + * hasFocus = false and the _setFocus function calls textInput.blur() again.\n + * If the textInput was blured, because the entire page lost the focus, then\n + * the foucs is not reset to the textInput when the page gains the focus again.\n + */\n + _setFocus: function(value, fromTextInput) {\n + if (value == this._hasFocus) {\n + return;\n + }\n +\n + this._hasFocus = value;\n +\n + if (this._hasFocus) {\n + this._rearmInsertionPointBlinkTimer();\n + this._invalidateSelection();\n + if (!fromTextInput) {\n + this.textInput.focus();\n + }\n + } else {\n + if (this._insertionPointBlinkTimer) {\n + clearInterval(this._insertionPointBlinkTimer);\n + this._insertionPointBlinkTimer = null;\n + }\n + this._insertionPointVisible = true;\n + this._invalidateSelection();\n + if (!fromTextInput) {\n + this.textInput.blur();\n + }\n + }\n + }\n +});\n +\n +Object.defineProperties(exports.TextView.prototype, {\n + hasFocus: {\n + get: function() {\n + return this._hasFocus;\n + },\n +\n + set: function(value) {\n + this._setFocus(value, false /* fromTextInput*/);\n + }\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:models/buffer",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var env = require(\'environment\').env;\n +\n +var util = require(\'bespin:util/util\');\n +\n +var Promise = require(\'bespin:promise\').Promise;\n +var TextStorage = require(\'models/textstorage\').TextStorage;\n +var LayoutManager = require(\'controllers/layoutmanager\').LayoutManager;\n +var UndoManager = require(\'undomanager\').UndoManager;\n +\n +/**\n + * A Buffer connects a model and file together. It also holds the layoutManager\n + * that is bound to the model. The syntaxManager can get accessed via the\n + * layoutManager as well.\n + *\n + * Per opened file there is one buffer which means that one buffer is\n + * corresponding to one file on the disk. If you open different file, you have\n + * to create a new buffer for that file.\n + *\n + * To create a buffer that is (not yet) bound to a file, just create the Buffer\n + * without a file passed.\n + */\n +exports.Buffer = function(file, initialContent) {\n + this._file = file;\n + this._model = new TextStorage(initialContent);\n + this._layoutManager = new LayoutManager({\n + textStorage: this._model\n + });\n +\n + this.undoManager = new UndoManager();\n +\n + // If a file is passed, then load it. This is the same as calling reload.\n + if (file) {\n + this.reload().then(function() {\n + this._updateSyntaxManagerInitialContext();\n + }.bind(this));\n + } else {\n + this.loadPromise = new Promise();\n + this.loadPromise.resolve();\n + }\n +\n + // Restore the state of the buffer (selection + scrollOffset).\n + // TODO: Refactor this code into the ViewState.\n + var history = (env.session ? env.session.history : null);\n + var item, selection, scrollOffset;\n +\n + // If\n + // 1. Check if a history exists and the buffer has a file (-> path)\n + // 2. Ask the history object for the history for the current file.\n + // If no history is found, null is returned.\n + if (history && file && // 1.\n + (item = history.getHistoryForPath(file.path)) // 2.\n + ) {\n + // There is no state saved in the buffer and the history object\n + // has a state saved.\n + selection = item.selection;\n + scrollOffset = item.scroll;\n + }\n +\n + // Use the saved values from the history or the default values.\n + this._selectedRange = selection || {\n + start: { row: 0, col: 0 },\n + end: { row: 0, col: 0 }\n + };\n +\n + this._scrollOffset = scrollOffset || { x: 0, y: 0 };\n +};\n +\n +exports.Buffer.prototype = {\n + /**\n + * The undoManager where the undo/redo stack is stored and handled.\n + */\n + undoManager: null,\n +\n + loadPromise: null,\n +\n + _scrollOffset: null,\n + _selectedRange: null,\n + _selectedRangeEndVirtual: null,\n +\n + /**\n + * The syntax manager associated with this file.\n + */\n + _layoutManager: null,\n +\n + /**\n + * The file object associated with this buffer. The file instance can only\n + * be assigned when constructing the buffer or calling saveAs.\n + */\n + _file: null,\n +\n + /**\n + * The text model that is holding the content of the file.\n + */\n + _model: null,\n +\n + /**\n + * Save the contents of this buffer. Returns a promise that resolves\n + * once the file is saved.\n + */\n + save: function() {\n + return this._file.saveContents(this._model.value);\n + },\n +\n + /**\n + * Saves the contents of this buffer to a new file, and updates the file\n + * field of this buffer to point to the result.\n + *\n + * @param dir{Directory} The directory to save in.\n + * @param filename{string} The name of the file in the directory.\n + * @return A promise to return the newly-saved file.\n + */\n + saveAs: function(newFile) {\n + var promise = new Promise();\n +\n + newFile.saveContents(this._model.value).then(function() {\n + this._file = newFile;\n + this._updateSyntaxManagerInitialContext();\n + promise.resolve();\n + }.bind(this), function(error) {\n + promise.reject(error);\n + });\n +\n + return promise;\n + },\n +\n + /**\n + * Reload the existing file contents from the server.\n + */\n + reload: function() {\n + var file = this._file;\n + var self = this;\n +\n + var pr;\n + pr = file.loadContents().then(function(contents) {\n + self._model.value = contents;\n + });\n + this.loadPromise = pr;\n + return pr;\n + },\n +\n + _updateSyntaxManagerInitialContext: function() {\n + var ext = this._file.extension();\n + var syntaxManager = this._layoutManager.syntaxManager;\n + syntaxManager.setSyntaxFromFileExt(ext === null ? \'\' : ext);\n + },\n +\n + /**\n + * Returns true if the file is untitled (i.e. it is new and has not yet\n + * been saved with @saveAs) or false otherwise.\n + */\n + untitled: function() {\n + return util.none(this._file);\n + }\n +};\n +\n +Object.defineProperties(exports.Buffer.prototype, {\n + layoutManager: {\n + get: function() {\n + return this._layoutManager;\n + }\n + },\n +\n + syntaxManager: {\n + get: function() {\n + this._layoutManager.syntaxManager;\n + }\n + },\n +\n + file: {\n + get: function() {\n + return this._file;\n + }\n + },\n +\n + model: {\n + get: function() {\n + return this._model;\n + }\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:models/textstorage",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var Event = require(\'events\').Event;\n +var util = require(\'bespin:util/util\');\n +\n +var TextStorage;\n +\n +/**\n + * Creates a new text storage object holding the given string (if supplied).\n + *\n + * @constructor\n + * @exports TextStorage as text_editor:models.textstorage.TextStorage\n + */\n +TextStorage = function(initialValue) {\n + if (initialValue !== null && initialValue !== undefined) {\n + this._lines = initialValue.split("\\n");\n + } else {\n + this._lines = [ \'\' ];\n + }\n +\n + /**\n + * Called whenever the text changes with the old and new ranges supplied.\n + */\n + this.changed = new Event();\n +\n + return this;\n +};\n +\n +TextStorage.prototype = {\n + /** @lends TextStorage */\n +\n + _lines: null,\n +\n + /**\n + * Whether this model is read-only. Attempts to modify a read-only model\n + * result in exceptions.\n + *\n + * @type {boolean}\n + */\n + readOnly: false,\n +\n + /**\n + * Returns the position of the nearest character to the given position,\n + * according to the selection rules.\n + *\n + * @param {position} pos The position to clamp.\n + */\n + clampPosition: function(pos) {\n + var lines = this._lines;\n +\n + var row = pos.row;\n + if (row < 0) {\n + return { row: 0, col: 0 };\n + } else if (row >= lines.length) {\n + return this.range.end;\n + }\n +\n + var col = Math.max(0, Math.min(pos.col, lines[row].length));\n + return { row: row, col: col };\n + },\n +\n + /**\n + * Returns the actual range closest to the given range, according to the\n + * selection rules.\n + */\n + clampRange: function(range) {\n + var start = this.clampPosition(range.start);\n + var end = this.clampPosition(range.end);\n + return { start: start, end: end };\n + },\n +\n + /** Deletes all characters in the range. */\n + deleteCharacters: function(range) {\n + this.replaceCharacters(range, \'\');\n + },\n +\n + /**\n + * Returns the result of displacing the given position by count characters\n + * forward (if count > 0) or backward (if count < 0).\n + */\n + displacePosition: function(pos, count) {\n + var forward = count > 0;\n + var lines = this._lines;\n + var lineCount = lines.length;\n +\n + for (var i = Math.abs(count); i !== 0; i--) {\n + if (forward) {\n + var rowLength = lines[pos.row].length;\n + if (pos.row === lineCount - 1 && pos.col === rowLength) {\n + return pos;\n + }\n + pos = pos.col === rowLength ?\n + { row: pos.row + 1, col: 0 } :\n + { row: pos.row, col: pos.col + 1 };\n + } else {\n + if (pos.row === 0 && pos.col == 0) {\n + return pos;\n + }\n +\n + if (pos.col === 0) {\n + lines = this._lines;\n + pos = {\n + row: pos.row - 1,\n + col: lines[pos.row - 1].length\n + };\n + } else {\n + pos = { row: pos.row, col: pos.col - 1 };\n + }\n + }\n + }\n + return pos;\n + },\n +\n + /**\n + * Returns the characters in the given range as a string.\n + */\n + getCharacters: function(range) {\n + var lines = this._lines;\n + var start = range.start, end = range.end;\n + var startRow = start.row, endRow = end.row;\n + var startCol = start.col, endCol = end.col;\n +\n + if (startRow === endRow) {\n + return lines[startRow].substring(startCol, endCol);\n + }\n +\n + var firstLine = lines[startRow].substring(startCol);\n + var middleLines = lines.slice(startRow + 1, endRow);\n + var endLine = lines[endRow].substring(0, endCol);\n + return [ firstLine ].concat(middleLines, endLine).join(\'\\n\');\n + },\n +\n + /** Returns the lines of the text storage as a read-only array. */\n + getLines: function() {\n + return this._lines;\n + },\n +\n + /** Returns the span of the entire text content. */\n + getRange: function() {\n + var lines = this._lines;\n + var endRow = lines.length - 1;\n + var endCol = lines[endRow].length;\n + var start = { row: 0, col: 0 }, end = { row: endRow, col: endCol };\n + return { start: start, end: end };\n + },\n +\n + /** Returns the text in the text storage as a string. */\n + getValue: function() {\n + return this._lines.join(\'\\n\');\n + },\n +\n + /** Inserts characters at the supplied position. */\n + insertCharacters: function(pos, chars) {\n + this.replaceCharacters({ start: pos, end: pos }, chars);\n + },\n +\n + /** Replaces the characters within the supplied range. */\n + replaceCharacters: function(oldRange, characters) {\n + if (this.readOnly) {\n + throw new Error("Attempt to modify a read-only text storage " +\n + "object");\n + }\n +\n + var addedLines = characters.split(\'\\n\');\n + var addedLineCount = addedLines.length;\n +\n + var newRange = this.resultingRangeForReplacement(oldRange, addedLines);\n +\n + var oldStart = oldRange.start, oldEnd = oldRange.end;\n + var oldStartRow = oldStart.row, oldEndRow = oldEnd.row;\n + var oldStartColumn = oldStart.col;\n +\n + var lines = this._lines;\n + addedLines[0] = lines[oldStartRow].substring(0, oldStartColumn) +\n + addedLines[0];\n + addedLines[addedLineCount - 1] +=\n + lines[oldEndRow].substring(oldEnd.col);\n +\n + this._lines = util.replace(lines, oldStartRow, oldEndRow - oldStartRow + 1, addedLines);\n +\n + this.changed(oldRange, newRange, characters);\n + },\n +\n + /**\n + * Returns the character range that would be modified if the range were\n + * replaced with the given lines.\n + */\n + resultingRangeForReplacement: function(range, lines) {\n + var lineCount = lines.length;\n + var lastLineLength = lines[lineCount - 1].length;\n + var start = range.start;\n + var endRow = start.row + lineCount - 1;\n + var endCol = (lineCount === 1 ? start.col : 0) + lastLineLength;\n + return { start: start, end: { row: endRow, col: endCol } };\n + },\n +\n + setLines: function(newLines) {\n + this.setValue(newLines.join(\'\\n\'));\n + },\n +\n + setValue: function(newValue) {\n + this.replaceCharacters(this.range, newValue);\n + }\n +};\n +\n +exports.TextStorage = TextStorage;\n +\n +Object.defineProperties(exports.TextStorage.prototype, {\n + lines: {\n + get: function() {\n + return this.getLines();\n + },\n + set: function(newLines) {\n + return this.setLines(newLines);\n + }\n + },\n + \n + range: {\n + get: function() {\n + return this.getRange();\n + }\n + },\n + \n + value: {\n + get: function() {\n + return this.getValue();\n + },\n + set: function(newValue) {\n + this.setValue(newValue);\n + }\n + }\n +});\n +\n +});\n +\n +bespin.tiki.module("text_editor:utils/rect",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +/**\n + * @private\n + *\n + * Returns the distance between the given value and the given inclusive upper\n + * and lower bounds, or 0 if the value lies between them.\n + *\n + * Exported so that the function can be unit tested.\n + */\n +exports._distanceFromBounds = function(value, low, high) {\n + if (value < low) {\n + return value - low;\n + }\n + if (value >= high) {\n + return value - high;\n + }\n + return 0;\n +};\n +\n +/**\n + * Merges the rectangles in a given set and returns the resulting set of non-\n + * overlapping rectanlges.\n + */\n +exports.merge = function(set) {\n + var modified;\n + do {\n + modified = false;\n + var newSet = [];\n +\n + for (var i = 0; i < set.length; i++) {\n + var rectA = set[i];\n + newSet.push(rectA);\n + for (var j = i+1; j < set.length; j++) {\n + var rectB = set[j];\n + if (exports.rectsSideBySide(rectA, rectB) ||\n + exports.rectsIntersect(rectA, rectB)) {\n + set.splice(j, 1);\n +\n + // There\'s room for optimization here...\n + newSet[newSet.length - 1] = exports.unionRects(rectA, rectB);\n +\n + modified = true;\n + break;\n + }\n + }\n + }\n +\n + set = newSet;\n + } while (modified);\n +\n + return set;\n +};\n +\n +/**\n + * Returns the vector representing the shortest offset between the given\n + * rectangle and the given point.\n + */\n +exports.offsetFromRect = function(rect, point) {\n + return {\n + x: exports._distanceFromBounds(point.x, rect.x, exports.maxX(rect)),\n + y: exports._distanceFromBounds(point.y, rect.y, exports.maxY(rect))\n + };\n +};\n +\n +/**\n + * Returns true if the rectanges intersect or false otherwise. Adjacent\n + * rectangles don\'t count; they must actually overlap some region.\n + */\n +exports.rectsIntersect = function(a, b) {\n + var intersection = exports.intersectRects(a, b);\n + return intersection.width !== 0 && intersection.height !== 0;\n +};\n +\n +/**\n + * Checks if two rects lay side by side. Returns true if this is true.\n + * For example:\n + * +------------+---------------+\n + * | A | B |\n + * +------------+---------------+\n + * will be true, but if B is only one pixel shifted up,\n + * then it would return false.\n + */\n +exports.rectsSideBySide = function(a, b) {\n + if (a.x == b.x && a.width == b.width) {\n + if (a.y < b.y) {\n + return (a.y + a.height) == b.y;\n + } else {\n + return (b.y + b.height) == a.y;\n + }\n + } else if (a.y == b.y && a.height == b.height) {\n + if (a.x < b.x) {\n + return (a.x + a.width) == b.x;\n + } else {\n + return (b.x + b.width) == a.x;\n + }\n + }\n + return false;\n +};\n +\n +// extracted from SproutCore\n +exports.intersectRects = function(r1, r2) {\n + // find all four edges\n + var ret = {\n + x: Math.max(exports.minX(r1), exports.minX(r2)),\n + y: Math.max(exports.minY(r1), exports.minY(r2)),\n + width: Math.min(exports.maxX(r1), exports.maxX(r2)),\n + height: Math.min(exports.maxY(r1), exports.maxY(r2))\n + } ;\n +\n + // convert edges to w/h\n + ret.width = Math.max(0, ret.width - ret.x) ;\n + ret.height = Math.max(0, ret.height - ret.y) ;\n + return ret ;\n +};\n +\n +/** Return the left edge of the frame */\n +exports.minX = function(frame) {\n + return frame.x || 0;\n +};\n +\n +/** Return the right edge of the frame. */\n +exports.maxX = function(frame) {\n + return (frame.x || 0) + (frame.width || 0);\n +};\n +\n +/** Return the top edge of the frame */\n +exports.minY = function(frame) {\n + return frame.y || 0 ;\n +};\n +\n +/** Return the bottom edge of the frame */\n +exports.maxY = function(frame) {\n + return (frame.y || 0) + (frame.height || 0) ;\n +};\n +\n +/** Check if the given point is inside the rect. */\n +exports.pointInRect = function(point, f) {\n + return (point.x >= exports.minX(f)) &&\n + (point.y >= exports.minY(f)) &&\n + (point.x <= exports.maxX(f)) &&\n + (point.y <= exports.maxY(f)) ;\n +};\n +\n +/** Returns the union between two rectangles\n +\n + @param r1 {Rect} The first rect\n + @param r2 {Rect} The second rect\n + @returns {Rect} The union rect.\n +*/\n +exports.unionRects = function(r1, r2) {\n + // find all four edges\n + var ret = {\n + x: Math.min(exports.minX(r1), exports.minX(r2)),\n + y: Math.min(exports.minY(r1), exports.minY(r2)),\n + width: Math.max(exports.maxX(r1), exports.maxX(r2)),\n + height: Math.max(exports.maxY(r1), exports.maxY(r2))\n + } ;\n +\n + // convert edges to w/h\n + ret.width = Math.max(0, ret.width - ret.x) ;\n + ret.height = Math.max(0, ret.height - ret.y) ;\n + return ret ;\n +};\n +\n +/** Return true if the two frames match. You can also pass only points or sizes.\n +\n + @param r1 {Rect} the first rect\n + @param r2 {Rect} the second rect\n + @param delta {Float} an optional delta that allows for rects that do not match exactly. Defaults to 0.1\n + @returns {Boolean} true if rects match\n + */\n +exports.rectsEqual = function(r1, r2, delta) {\n + if (!r1 || !r2) return (r1 == r2) ;\n + if (!delta && delta !== 0) delta = 0.1;\n + if ((r1.y != r2.y) && (Math.abs(r1.y - r2.y) > delta)) return false ;\n + if ((r1.x != r2.x) && (Math.abs(r1.x - r2.x) > delta)) return false ;\n + if ((r1.width != r2.width) && (Math.abs(r1.width - r2.width) > delta)) return false ;\n + if ((r1.height != r2.height) && (Math.abs(r1.height - r2.height) > delta)) return false ;\n + return true ;\n +};\n +\n +});\n +\n +bespin.tiki.module("text_editor:controllers/layoutmanager",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var Event = require("events").Event;\n +var Range = require(\'rangeutils:utils/range\');\n +var SyntaxManager = require(\'syntax_manager\').SyntaxManager;\n +var TextStorage = require(\'models/textstorage\').TextStorage;\n +var catalog = require(\'bespin:plugins\').catalog;\n +var settings = require(\'settings\').settings;\n +var m_scratchcanvas = require(\'bespin:util/scratchcanvas\');\n +\n +var fontDimension = {};\n +\n +var computeFontDimension = function() {\n + var fontSize = settings.get(\'fontsize\');\n + var fontFace = settings.get(\'fontface\');\n + var font = fontSize + \'px \' + fontFace;\n +\n + var canvas = m_scratchcanvas.get();\n +\n + // Measure a large string to work around the fact that width and height\n + // are truncated to the nearest integer in the canvas API.\n + var str = \'\';\n + for (var i = 0; i < 100; i++) {\n + str += \'M\';\n + }\n +\n + var width = canvas.measureStringWidth(font, str) / 100;\n +\n + fontDimension.characterWidth = width;\n +\n + fontDimension.lineHeight = Math.floor(fontSize * 1.6);\n + fontDimension.lineAscent = Math.floor(fontSize * 1.3);\n +};\n +\n +computeFontDimension();\n +\n +catalog.registerExtension(\'settingChange\', {\n + match: "font[size|face]",\n + pointer: computeFontDimension\n +});\n +\n +exports.LayoutManager = function(opts) {\n + this.changedTextAtRow = new Event();\n + this.invalidatedRects = new Event();\n +\n + // Put the global variable on the instance.\n + this.fontDimension = fontDimension;\n +\n + // There is no setter for textStorage so we have to change it to\n + // _textStorage to make things work with util.mixin().\n + if (opts.textStorage) {\n + opts._textStorage = opts.textStorage;\n + delete opts.textStorage;\n + } else {\n + this._textStorage = new TextStorage();\n + }\n +\n + util.mixin(this, opts);\n +\n + this._textStorage.changed.add(this.textStorageChanged.bind(this));\n +\n + this.textLines = [\n + {\n + characters: \'\',\n + colors: [\n + {\n + start: 0,\n + end: 0,\n + color: \'plain\'\n + }\n + ]\n + }\n + ];\n +\n + var syntaxManager = new SyntaxManager(this);\n + this.syntaxManager = syntaxManager;\n + syntaxManager.attrsChanged.add(this._attrsChanged.bind(this));\n +\n + this._size = { width: 0, height: 0 };\n + this.sizeChanged = new Event();\n +\n + this._height = 0;\n +\n + // Now that the syntax manager is set up, we can recompute the layout.\n + // (See comments in _textStorageChanged().)\n + this._recomputeEntireLayout();\n +};\n +\n +exports.LayoutManager.prototype = {\n + _maximumWidth: 0,\n + _textStorage: null,\n +\n + _size: null,\n + sizeChanged: null,\n +\n + /**\n + * Theme colors. Value is set by editorView class. Don\'t change this\n + * property directly. Use the editorView function to adjust it.\n + */\n + _theme: { },\n +\n + /**\n + * @property\n + *\n + * The margins on each edge in pixels, expressed as an object with \'left\',\n + * \'bottom\', \'top\', and \'right\' properties.\n + *\n + * Do not modify the properties of this object directly; clone, adjust, and\n + * reset the margin property of the layout manager instead.\n + */\n + margin: { left: 5, bottom: 6, top: 0, right: 12 },\n +\n + /**\n + * @property\n + *\n + * The plugin catalog to use. Typically this will be plugins.catalog, but\n + * for testing this may be replaced with a mock object.\n + */\n + pluginCatalog: catalog,\n +\n + /** The syntax manager in use. */\n + syntaxManager: null,\n +\n + /**\n + * @property{Array<object>}\n + *\n + * The marked-up lines of text. Each line has the properties \'characters\',\n + * \'colors\', and \'lineHeight\'.\n + */\n + textLines: null,\n +\n + // Called whenever the text attributes (which usually consist of syntax\n + // highlighting) change.\n + _attrsChanged: function(startRow, endRow) {\n + this.updateTextRows(startRow, endRow);\n +\n + var invalidRects = this.rectsForRange({\n + start: { row: startRow, col: 0 },\n + end: { row: endRow, col: 0 }\n + });\n +\n + this.invalidatedRects(this, invalidRects);\n + },\n +\n + _computeInvalidRects: function(oldRange, newRange) {\n + var startRect = this.characterRectForPosition(oldRange.start);\n +\n + var lineRect = {\n + x: startRect.x,\n + y: startRect.y,\n + width: Number.MAX_VALUE,\n + height: startRect.height\n + };\n +\n + return oldRange.end.row === newRange.end.row ?\n + [ lineRect ] :\n + [\n + lineRect,\n + {\n + x: 0,\n + y: startRect.y + fontDimension.lineHeight,\n + width: Number.MAX_VALUE,\n + height: Number.MAX_VALUE\n + }\n + ];\n + },\n +\n + // Returns the last valid position in the buffer.\n + _lastCharacterPosition: function() {\n + return {\n + row: this.textLines.length - 1,\n + col: this._maximumWidth\n + };\n + },\n +\n + _recalculateMaximumWidth: function() {\n + // Lots of room for optimization here if this turns out to be slow. But\n + // for now...\n + var textLines = this.textLines;\n + var max = 0;\n + textLines.forEach(function(line) {\n + var width = line.characters.length;\n + if (max < width) {\n + max = width;\n + }\n + });\n + this._maximumWidth = max;\n +\n + this.size = { width: max, height: this.textLines.length };\n + },\n +\n + _recomputeEntireLayout: function() {\n + var entireRange = this._textStorage.range;\n + this._recomputeLayoutForRanges(entireRange, entireRange);\n + },\n +\n + _recomputeLayoutForRanges: function(oldRange, newRange) {\n + var oldStartRow = oldRange.start.row, oldEndRow = oldRange.end.row;\n + var newEndRow = newRange.end.row;\n + var newRowCount = newEndRow - oldStartRow + 1;\n +\n + var lines = this._textStorage.lines;\n + var theme = this._theme;\n + var plainColor = theme.plain;\n +\n + var newTextLines = [];\n + for (var i = 0; i < newRowCount; i++) {\n + var line = lines[oldStartRow + i];\n + newTextLines[i] = {\n + characters: line,\n + colors: [ { start: 0, end: null, color: plainColor } ]\n + };\n + }\n +\n + this.textLines = util.replace(this.textLines, oldStartRow,\n + oldEndRow - oldStartRow + 1, newTextLines);\n + this._recalculateMaximumWidth();\n +\n + // Resize if necessary.\n + var newHeight = this.textLines.length;\n + var syntaxManager = this.syntaxManager;\n + if (this._height !== newHeight) {\n + this._height = newHeight;\n + }\n +\n + // Invalidate the start row (starting the syntax highlighting).\n + syntaxManager.invalidateRow(oldStartRow);\n +\n + // Take the cached attributes from the syntax manager.\n + this.updateTextRows(oldStartRow, newEndRow + 1);\n +\n + this.changedTextAtRow(this, oldStartRow);\n +\n + var invalidRects = this._computeInvalidRects(oldRange, newRange);\n + this.invalidatedRects(this, invalidRects);\n + },\n +\n + /**\n + * Determines the boundaries of the entire text area.\n + *\n + * TODO: Unit test.\n + */\n + boundingRect: function() {\n + return this.rectsForRange({\n + start: { row: 0, col: 0 },\n + end: {\n + row: this.textLines.length - 1,\n + col: this._maximumWidth\n + }\n + })[0];\n + },\n +\n + /**\n + * Determines the location of the character underneath the given point.\n + *\n + * @return Returns an object with three properties:\n + * * row: The row of the character nearest the point.\n + * * col: The col of the character nearest the point.\n + * * partialFraction: The fraction of the horizontal distance between\n + * this character and the next character. The extreme left of the\n + * character is 0.0, while the extreme right of the character is 1.0.\n + * If you are calling this function to determine where to place the\n + * cursor, then you should place the cursor after the returned\n + * character if this value is greater than 0.5.\n + *\n + * If there is no character under the point, then the character nearest the\n + * given point is returned, according to the selection rules.\n + */\n + characterAtPoint: function(point) {\n + var margin = this.margin;\n + var x = point.x - margin.left, y = point.y - margin.top;\n +\n + var characterWidth = fontDimension.characterWidth;\n + var textStorage = this._textStorage;\n + var clampedPosition = textStorage.clampPosition({\n + row: Math.floor(y / fontDimension.lineHeight),\n + col: Math.floor(x / characterWidth)\n + });\n +\n + var lineLength = textStorage.lines[clampedPosition.row].length;\n + clampedPosition.partialFraction = x < 0 ||\n + clampedPosition.col === lineLength ? 0.0 :\n + x % characterWidth / characterWidth;\n +\n + return clampedPosition;\n + },\n +\n + /**\n + * Given a rectangle expressed in pixels, returns the range of characters\n + * that lie at least partially within the rectangle as an object.\n + *\n + * TODO: Write unit tests for this method.\n + */\n + characterRangeForBoundingRect: function(rect) {\n + // TODO: variable line heights, needed for word wrap and perhaps\n + // extensions as well\n + var lineHeight = fontDimension.lineHeight;\n + var characterWidth = fontDimension.characterWidth;\n + var margin = this.margin;\n + var x = rect.x - margin.left, y = rect.y - margin.top;\n + return {\n + start: {\n + row: Math.max(Math.floor(y / lineHeight), 0),\n + col: Math.max(Math.floor(x / characterWidth), 0)\n + },\n + end: {\n + row: Math.floor((y + rect.height - 1) / lineHeight),\n + col: Math.floor((x + rect.width - 1) / characterWidth) + 1\n + }\n + };\n + },\n +\n + /**\n + * Returns the boundaries of the character at the given position.\n + */\n + characterRectForPosition: function(position) {\n + return this.rectsForRange({\n + start: position,\n + end: { row: position.row, col: position.col + 1 }\n + })[0];\n + },\n +\n + /**\n + * Returns the pixel boundaries of the given line.\n + *\n + * TODO: Unit test.\n + */\n + lineRectForRow: function(row) {\n + return this.rectsForRange({\n + start: { row: row, col: 0 },\n + end: { row: row, col: this._maximumWidth }\n + })[0];\n + },\n +\n + rectForPosition: function(position) {\n + var margin = this.margin;\n + var characterWidth = fontDimension.characterWidth;\n + var lineHeight = fontDimension.lineHeight;\n + return {\n + x: margin.left + characterWidth * position.col,\n + y: margin.top + lineHeight * position.row,\n + width: characterWidth,\n + height: lineHeight\n + };\n + },\n +\n + /**\n + * Returns the 1, 2, or 3 rectangles that make up the given range.\n + */\n + rectsForRange: function(range) {\n + var characterWidth = fontDimension.characterWidth;\n + var lineHeight = fontDimension.lineHeight;\n + var maximumWidth = this._maximumWidth;\n + var margin = this.margin;\n +\n + var start = range.start, end = range.end;\n + var startRow = start.row, startColumn = start.col;\n + var endRow = end.row, endColumn = end.col;\n +\n + if (startRow === endRow) {\n + // The simple rectangle case.\n + return [\n + {\n + x: margin.left + characterWidth * startColumn,\n + y: margin.top + lineHeight * startRow,\n + width: characterWidth * (endColumn - startColumn),\n + height: lineHeight\n + }\n + ];\n + }\n +\n + var rects = [];\n +\n + // Top line\n + var middleStartRow;\n + if (startColumn === 0) {\n + middleStartRow = startRow;\n + } else {\n + middleStartRow = startRow + 1;\n + rects.push({\n + x: margin.left + characterWidth * startColumn,\n + y: margin.top + lineHeight * startRow,\n + width: 99999, // < Number.MAX_VALUE is not working here.\n + height: lineHeight\n + });\n + }\n +\n + // Bottom line\n + var middleEndRow;\n + if (endColumn === 0) {\n + middleEndRow = endRow - 1;\n + } else if (endColumn === maximumWidth) {\n + middleEndRow = endRow;\n + } else {\n + middleEndRow = endRow - 1;\n + rects.push({\n + x: margin.left,\n + y: margin.top + lineHeight * endRow,\n + width: characterWidth * endColumn,\n + height: lineHeight\n + });\n + }\n +\n + // Middle area\n + rects.push({\n + x: margin.left,\n + y: margin.top + lineHeight * middleStartRow,\n + width: 99999, // < Number.MAX_VALUE is not working here.\n + height: lineHeight * (middleEndRow - middleStartRow + 1)\n + });\n +\n + return rects;\n + },\n +\n + textStorageChanged: function(oldRange, newRange) {\n + this._recomputeLayoutForRanges(oldRange, newRange);\n + },\n +\n + /**\n + * Updates the text lines in the given range to correspond to the current\n + * state of the syntax highlighter. Does not actually run the syntax\n + * highlighters.\n + */\n + updateTextRows: function(startRow, endRow) {\n + var textLines = this.textLines;\n + var attrs = this.syntaxManager.getAttrsForRows(startRow, endRow);\n + var theme = this._theme;\n +\n + for (var i = 0; i < attrs.length; i++) {\n + textLines[startRow + i].colors = attrs[i];\n + }\n + }\n +};\n +\n +Object.defineProperties(exports.LayoutManager.prototype, {\n + size: {\n + set: function(size) {\n + if (size.width !== this._size.width || size.height !== this._size.height) {\n + this.sizeChanged(size);\n + this._size = size;\n + }\n + },\n +\n + get: function() {\n + return this._size;\n + }\n + },\n +\n + textStorage: {\n + get: function() {\n + return this._textStorage;\n + }\n + }\n +})\n +\n +});\n +\n +bespin.tiki.module("text_editor:controllers/search",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var Range = require(\'rangeutils:utils/range\');\n +var console = require(\'bespin:console\').console;\n +\n +/**\n + * @class\n + *\n + * Manages the Find functionality.\n + */\n +exports.EditorSearchController = function(editor) {\n + this.editor = editor;\n +};\n +\n +exports.EditorSearchController.prototype = {\n +\n + /**\n + * The editor holding the buffer object to search in.\n + */\n + editor: null,\n +\n + /**\n + * This is based on the idea from:\n + * http://simonwillison.net/2006/Jan/20/escape/.\n + */\n + _escapeString: /(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\)/g,\n +\n + _findMatchesInString: function(str) {\n + var result = [];\n + var searchRegExp = this.searchRegExp;\n + var searchResult;\n + var endIndex;\n +\n + searchRegExp.lastIndex = 0;\n +\n + while (true) {\n + searchResult = searchRegExp.exec(str);\n + if (searchResult === null) {\n + break;\n + }\n +\n + result.push(searchResult);\n +\n + var index = searchResult.index;\n + searchRegExp.lastIndex = index + searchResult[0].length;\n + }\n +\n + return result;\n + },\n +\n + _makeRange: function(searchResult, row) {\n + return {\n + start: { row: row, col: searchResult.index },\n + end: {\n + row: row,\n + col: searchResult.index + searchResult[0].length\n + }\n + };\n + },\n +\n + /**\n + * @property{boolean}\n + *\n + * True if the search query is a regular expression, false if it\'s a\n + * literal string.\n + */\n + isRegExp: null,\n +\n + /**\n + * @property{RegExp}\n + *\n + * The current search query as a regular expression.\n + */\n + searchRegExp: null,\n +\n + /**\n + * @property{String}\n + *\n + * The current search text.\n + */\n + searchText: null,\n +\n + /**\n + * Sets the search query.\n + *\n + * @param text The search query to set.\n + * @param isRegExp True if the text is a regex, false if it\'s a literal\n + * string.\n + */\n + setSearchText: function(text, isRegExp) {\n + var regExp;\n + // If the search string is not a RegExp make sure to escape the\n + if (!isRegExp) {\n + regExp = new RegExp(text.replace(this._escapeString, \'\\\\$1\'), \'gi\');\n + } else {\n + regExp = new RegExp(text);\n + }\n + this.searchRegExp = regExp;\n + this.isRegExp = isRegExp;\n + this.searchText = text;\n + },\n +\n + /**\n + * Finds the next occurrence of the search query.\n + *\n + * @param startPos The position at which to restart the search.\n + * @param allowFromStart True if the search is allowed to wrap.\n + */\n + findNext: function(startPos, allowFromStart) {\n + var searchRegExp = this.searchRegExp;\n + if (util.none(searchRegExp)) {\n + return null;\n + }\n +\n + startPos = startPos || this.editor.textView.getSelectedRange().end;\n +\n + var lines = this.editor.layoutManager.textStorage.lines;\n + var searchResult;\n +\n + searchRegExp.lastIndex = startPos.col;\n +\n + var row;\n + for (row = startPos.row; row < lines.length; row++) {\n + searchResult = searchRegExp.exec(lines[row]);\n + if (!util.none(searchResult)) {\n + return this._makeRange(searchResult, row);\n + }\n + }\n +\n + if (!allowFromStart) {\n + return null;\n + }\n +\n + // Wrap around.\n + for (row = 0; row <= startPos.row; row++) {\n + searchResult = searchRegExp.exec(lines[row]);\n + if (!util.none(searchResult)) {\n + return this._makeRange(searchResult, row);\n + }\n + }\n +\n + return null;\n + },\n +\n + /**\n + * Finds the previous occurrence of the search query.\n + *\n + * @param startPos The position at which to restart the search.\n + * @param allowFromStart True if the search is allowed to wrap.\n + */\n + findPrevious: function(startPos, allowFromEnd) {\n + var searchRegExp = this.searchRegExp;\n + if (util.none(searchRegExp)) {\n + return null;\n + }\n +\n + startPos = startPos || this.editor.textView.getSelectedRange().start;\n +\n + var lines = this.editor.buffer.layoutManager.textStorage.lines;\n + var searchResults;\n +\n + // Treat the first line specially.\n + var firstLine = lines[startPos.row].substring(0, startPos.col);\n + searchResults = this._findMatchesInString(firstLine);\n +\n + if (searchResults.length !== 0) {\n + return this._makeRange(searchResults[searchResults.length - 1],\n + startPos.row);\n + }\n +\n + // Loop over all other lines.\n + var row;\n + for (row = startPos.row - 1; row !== -1; row--) {\n + searchResults = this._findMatchesInString(lines[row]);\n + if (searchResults.length !== 0) {\n + return this._makeRange(searchResults[searchResults.length - 1],\n + row);\n + }\n + }\n +\n + if (!allowFromEnd) {\n + return null;\n + }\n +\n + // Wrap around.\n + for (row = lines.length - 1; row >= startPos.row; row--) {\n + searchResults = this._findMatchesInString(lines[row]);\n + if (searchResults.length !== 0) {\n + return this._makeRange(searchResults[searchResults.length - 1],\n + row);\n + }\n + }\n +\n + return null;\n + }\n +};\n +\n +\n +});\n +\n +bespin.tiki.module("text_editor:controllers/undo",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var console = require(\'bespin:console\').console;\n +var env = require(\'environment\').env;\n +\n +/**\n + * @class\n + *\n + * The editor undo controller is a delegate of the text view that groups\n + * changes into patches and saves them with the undo manager.\n + *\n + * This object does not assume that it has exclusive write access to the text\n + * storage object, and as such it tries to maintain sensible behavior in the\n + * presence of direct modification to the text storage by other objects. This\n + * is important for collaboration.\n + */\n +exports.EditorUndoController = function(editor) {\n + this.editor = editor;\n + var textView = this.textView = editor.textView;\n +\n + textView.beganChangeGroup.add(function(sender, selection) {\n + this._beginTransaction();\n + this._record.selectionBefore = selection;\n + }.bind(this));\n +\n + textView.endedChangeGroup.add(function(sender, selection) {\n + this._record.selectionAfter = selection;\n + this._endTransaction();\n + }.bind(this));\n +\n + textView.replacedCharacters.add(function(sender, oldRange, characters) {\n + if (!this._inTransaction) {\n + throw new Error(\'UndoController.textViewReplacedCharacters()\' +\n + \' called outside a transaction\');\n + }\n +\n + this._record.patches.push({\n + oldCharacters: this._deletedCharacters,\n + oldRange: oldRange,\n + newCharacters: characters,\n + newRange: this.editor.layoutManager.textStorage.\n + resultingRangeForReplacement(oldRange,\n + characters.split(\'\\n\'))\n + });\n +\n + this._deletedCharacters = null;\n + }.bind(this));\n +\n + textView.willReplaceRange.add(function(sender, oldRange) {\n + if (!this._inTransaction) {\n + throw new Error(\'UndoController.textViewWillReplaceRange() called\' +\n + \' outside a transaction\');\n + }\n +\n + this._deletedCharacters = this.editor.layoutManager.textStorage.\n + getCharacters(oldRange);\n + }.bind(this));\n +};\n +\n +exports.EditorUndoController.prototype = {\n + _inTransaction: false,\n + _record: null,\n +\n + /**\n + * @property{TextView}\n + *\n + * The view object to forward changes to. This property must be set upon\n + * instantiating the undo controller.\n + */\n + textView: null,\n +\n + _beginTransaction: function() {\n + if (this._inTransaction) {\n + console.trace();\n + throw new Error(\'UndoController._beginTransaction() called with a \' +\n + \'transaction already in place\');\n + }\n +\n + this._inTransaction = true;\n + this._record = { patches: [] };\n + },\n +\n + _endTransaction: function() {\n + if (!this._inTransaction) {\n + throw new Error(\'UndoController._endTransaction() called without a \' +\n + \'transaction in place\');\n + }\n +\n + this.editor.buffer.undoManager.registerUndo(this, this._record);\n + this._record = null;\n +\n + this._inTransaction = false;\n + },\n +\n + _tryApplyingPatches: function(patches) {\n + var textStorage = this.editor.layoutManager.textStorage;\n + patches.forEach(function(patch) {\n + textStorage.replaceCharacters(patch.oldRange, patch.newCharacters);\n + });\n + return true;\n + },\n +\n + _undoOrRedo: function(patches, selection) {\n + if (this._inTransaction) {\n + // Can\'t think of any reason why this should be supported, and it\'s\n + // often an indication that someone forgot an endTransaction()\n + // call somewhere...\n + throw new Error(\'UndoController._undoOrRedo() called while in a transaction\');\n + }\n +\n + if (!this._tryApplyingPatches(patches)) {\n + return false;\n + }\n +\n + this.textView.setSelection(selection, true);\n + return true;\n + },\n +\n + redo: function(record) {\n + var patches = record.patches.concat();\n + patches.reverse();\n + return this._undoOrRedo(patches, record.selectionAfter);\n + },\n +\n + undo: function(record) {\n + return this._undoOrRedo(record.patches.map(function(patch) {\n + return {\n + oldCharacters: patch.newCharacters,\n + oldRange: patch.newRange,\n + newCharacters: patch.oldCharacters,\n + newRange: patch.oldRange\n + };\n + }), record.selectionBefore);\n + }\n +};\n +\n +exports.undoManagerCommand = function(args, request) {\n + var editor = env.editor;\n + editor.buffer.undoManager[request.commandExt.name]()\n +};\n +\n +});\n +\n +bespin.tiki.module("text_editor:commands/scrolling",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n + \n +var env = require(\'environment\').env;\n +\n +// Scrolling commands.\n +\n +/**\n + * Scrolls to the start of the document.\n + */\n +exports.scrollDocStart = function(args, request) {\n + env.view.scrollToPosition({ col: 0, row: 0 });\n +};\n +\n +/**\n + * Scrolls to the end of the document.\n + */\n +exports.scrollDocEnd = function(args, request) {\n + env.view.scrollToPosition(env.model.range.end);\n +};\n +\n +/**\n + * Scrolls down by one screenful of text.\n + */\n +exports.scrollPageDown = function(args, request) {\n + env.view.scrollPageDown();\n +};\n +\n +/**\n + * Scrolls up by one screenful of text.\n + */\n +exports.scrollPageUp = function(args, request) {\n + env.view.scrollPageUp();\n +};\n +\n +\n +});\n +\n +bespin.tiki.module("text_editor:commands/editing",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var settings = require(\'settings\').settings;\n +var env = require(\'environment\').env;\n +var m_range = require(\'rangeutils:utils/range\');\n +\n +/*\n + * Commands that delete text.\n + */\n +\n +/**\n + * Deletes the selection or the previous character, if the selection is an\n + * insertion point.\n + */\n +exports.backspace = function(args, request) {\n + var view = env.view;\n + view.performBackspaceOrDelete(true);\n +};\n +\n +/**\n + * Deletes the selection or the next character, if the selection is an\n + * insertion point.\n + */\n +exports.deleteCommand = function(args, request) {\n + var view = env.view;\n + view.performBackspaceOrDelete(false);\n +};\n +\n +/**\n + * Deletes all lines that are partially or fully selected, and position the\n + * insertion point at the end of the deleted range.\n + */\n +exports.deleteLines = function(args, request) {\n + if (env.model.readOnly) {\n + return;\n + }\n +\n + // In the case of just one line, do nothing.\n + if (env.model.lines.length == 1) {\n + return;\n + }\n +\n + var view = env.view;\n + view.groupChanges(function() {\n + var range = view.getSelectedRange();\n + var lines = env.model.lines;\n + var lastLine = lines.length - 1;\n + var startPos, endPos;\n +\n + // Last row gets special treatment.\n + if (range.start.row == lastLine) {\n + startPos = { col: lines[lastLine - 1].length, row: lastLine - 1 };\n + } else {\n + startPos = { col: 0, row: range.start.row };\n + }\n +\n + // Last row gets special treatment.\n + if (range.end.row == lastLine) {\n + endPos = { col: lines[lastLine].length, row: lastLine};\n + } else {\n + endPos = { col: 0, row: range.end.row + 1 };\n + }\n +\n + view.replaceCharacters({\n + start: startPos,\n + end: endPos\n + }, \'\');\n +\n + view.moveCursorTo(startPos);\n + });\n +};\n +\n +/*\n + * Commands that insert text.\n + */\n +\n +// Inserts a newline, and copies the spaces at the beginning of the current row\n +// to autoindent.\n +var newline = function(model, view) {\n + var selection = view.getSelectedRange();\n + var position = selection.start;\n + var row = position.row, col = position.col;\n +\n + var lines = model.lines;\n + var prefix = lines[row].substring(0, col);\n +\n + var spaces = /^\\s*/.exec(prefix);\n + view.insertText(\'\\n\' + spaces);\n +};\n +\n +/**\n + * Replaces the selection with the given text and updates the selection\n + * boundaries appropriately.\n + */\n +exports.insertText = function(args, request) {\n + var view = env.view;\n + var text = args.text;\n + view.insertText(text);\n +};\n +\n +/**\n + * Inserts a newline at the insertion point.\n + */\n +exports.newline = function(args, request) {\n + var model = env.model, view = env.view;\n + newline(model, view);\n +};\n +\n +/**\n + * Join the following line with the current one. Removes trailing whitespaces.\n + */\n +exports.joinLines = function(args, request) {\n + var model = env.model;\n + if (model.readOnly) {\n + return;\n + }\n +\n + var view = env.view;\n + var selection = view.getSelectedRange();\n + var lines = model.lines;\n + var row = selection.end.row;\n +\n + // Last line selected, which can\'t get joined.\n + if (lines.length == row) {\n + return;\n + }\n +\n + view.groupChanges(function() {\n + var endCol = lines[row].length;\n +\n + view.replaceCharacters({\n + start: {\n + col: endCol,\n + row: row\n + },\n + end: {\n + col: /^\\s*/.exec(lines[row + 1])[0].length,\n + row: row + 1\n + }}, \'\');\n + });\n +};\n +\n +/**\n + * Creates a new, empty line below the current one, and places the insertion\n + * point there.\n + */\n +exports.openLine = function(args, request) {\n + if (env.model.readOnly) {\n + return;\n + }\n +\n + var model = env.model, view = env.view;\n +\n + var selection = view.getSelectedRange();\n + var row = selection.end.row;\n + var lines = model.lines;\n + view.moveCursorTo({ row: row, col: lines[row].length });\n +\n + newline(model, view);\n +};\n +\n +/**\n + * Inserts a new tab. This is smart about the current inserted whitespaces and\n + * the current position of the cursor. If some text is selected, the selected\n + * lines will be indented by tabstop spaces.\n + */\n +exports.tab = function(args, request) {\n + var view = env.view;\n +\n + view.groupChanges(function() {\n + var tabstop = settings.get(\'tabstop\');\n + var selection = view.getSelectedRange();\n + var str = \'\';\n +\n + if (m_range.isZeroLength(selection)){\n + var line = env.model.lines[selection.start.row];\n + var trailspaces = line.substring(selection.start.col).\n + match(/^\\s*/)[0].length;\n + var count = tabstop - (selection.start.col + trailspaces) % tabstop;\n +\n + for (var i = 0; i < count; i++) {\n + str += \' \';\n + }\n +\n + view.replaceCharacters({\n + start: selection.start,\n + end: selection.start\n + }, str);\n +\n + view.moveCursorTo({\n + col: selection.start.col + count + trailspaces,\n + row: selection.end.row\n + });\n + } else {\n + for (var i = 0; i < tabstop; i++) {\n + str += \' \';\n + }\n +\n + var startCol;\n + var row = selection.start.row - 1;\n + while (row++ < selection.end.row) {\n + startCol = row == selection.start.row ? selection.start.col : 0;\n +\n + view.replaceCharacters({\n + start: { row: row, col: startCol},\n + end: { row: row, col: startCol}\n + }, str);\n + }\n +\n + view.setSelection({\n + start: selection.start,\n + end: {\n + col: selection.end.col + tabstop,\n + row: selection.end.row\n + }\n + });\n + }\n + }.bind(this));\n +};\n +\n +/**\n + * Removes a tab of whitespaces. If there is no selection, whitespaces in front\n + * of the cursor will be removed. The number of removed whitespaces depends on\n + * the setting tabstop and the current cursor position. If there is a selection,\n + * then the selected lines are unindented by tabstop spaces.\n + */\n +exports.untab = function(args, request) {\n + var view = env.view;\n +\n + view.groupChanges(function() {\n + var tabstop = settings.get(\'tabstop\');\n + var selection = view.getSelectedRange();\n + var lines = env.model.lines;\n + var count = 0;\n +\n + if (m_range.isZeroLength(selection)){\n + count = Math.min(\n + lines[selection.start.row].substring(0, selection.start.col).\n + match(/\\s*$/)[0].length,\n + (selection.start.col - tabstop) % tabstop || tabstop);\n +\n + view.replaceCharacters({\n + start: {\n + col: selection.start.col - count,\n + row: selection.start.row\n + },\n + end: selection.start\n + }, \'\');\n +\n + view.moveCursorTo({\n + row: selection.start.row,\n + col: selection.end.col - count\n + });\n + } else {\n + var startCol;\n + var row = selection.start.row - 1;\n + while (row++ < selection.end.row) {\n + startCol = row == selection.start.row ? selection.start.col : 0;\n +\n + count = Math.min(\n + lines[row].substring(startCol).match(/^\\s*/)[0].length,\n + tabstop);\n +\n + view.replaceCharacters({\n + start: { row: row, col: startCol},\n + end: { row: row, col: startCol + count}\n + }, \'\');\n + }\n +\n + view.setSelection({\n + start: { row: selection.start.row, col: selection.start.col},\n + end: { row: selection.end.row, col: selection.end.col - count}\n + });\n + }\n + }.bind(this));\n +};\n +\n +});\n +\n +bespin.tiki.module("text_editor:commands/editor",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var settings = require(\'settings\').settings;\n +var env = require(\'environment\').env;\n +\n +exports.findNextCommand = function(args, request) {\n + var view = env.view, search = view.editor.searchController;\n + var sel = view.getSelectedRange();\n + var match = search.findNext(sel.end, true);\n + if (match) {\n + view.setSelection(match, true);\n + view.focus();\n + }\n +};\n +\n +exports.findPrevCommand = function(args, request) {\n + var view = env.view, search = view.editor.searchController;\n + var sel = view.getSelectedRange();\n + var match = search.findPrevious(sel.start, true);\n + if (match) {\n + view.setSelection(match, true);\n + view.focus();\n + }\n +};\n +\n +/**\n + * Utility to allow us to alter the current selection\n + * TODO: If the selection is empty, broaden the scope to the whole file?\n + */\n +var withSelection = function(action) {\n + var view = env.view;\n + var selection = view.getSelectedCharacters();\n +\n + var replacement = action(selection);\n +\n + var range = view.getSelectedRange();\n + var model = env.model;\n + model.replaceCharacters(range, replacement);\n +};\n +\n +/**\n + * \'replace\' command\n + */\n +exports.replaceCommand = function(args, request) {\n + withSelection(function(selected) {\n + return selected.replace(args.search + \'/g\', args.replace);\n + });\n +};\n +\n +/**\n + * \'entab\' command\n + */\n +exports.entabCommand = function(args, request) {\n + tabstop = settings.get(\'tabstop\');\n + withSelection(function(selected) {\n + return selected.replace(\' {\' + tabstop + \'}\', \'\\t\');\n + });\n +};\n +\n +/**\n + * \'detab\' command\n + */\n +exports.detabCommand = function(args, request) {\n + tabstop = settings.get(\'tabstop\');\n + withSelection(function(selected) {\n + return selected.replace(\'\\t\', new Array(tabstop + 1).join(\' \'));\n + });\n +};\n +\n +/**\n + * \'trim\' command\n + */\n +exports.trimCommand = function(args, request) {\n + withSelection(function(selected) {\n + var lines = selected.split(\'\\n\');\n + lines = lines.map(function(line) {\n + if (args.side === \'left\' || args.side === \'both\') {\n + line = line.replace(/^\\s+/, \'\');\n + }\n + if (args.side === \'right\' || args.side === \'both\') {\n + line = line.replace(/\\s+$/, \'\');\n + }\n + return line;\n + });\n + return lines.join(\'\\n\');\n + });\n +};\n +\n +/**\n + * \'uc\' command\n + */\n +exports.ucCommand = function(args, request) {\n + withSelection(function(selected) {\n + return selected.toUpperCase();\n + });\n +};\n +\n +/**\n + * \'lc\' command\n + */\n +exports.lcCommand = function(args, request) {\n + withSelection(function(selected) {\n + return selected.toLowerCase();\n + });\n +};\n +\n +});\n +\n +bespin.tiki.module("text_editor:commands/movement",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var Range = require(\'rangeutils:utils/range\');\n +var env = require(\'environment\').env;\n +\n +// TODO: These should not be using private APIs of the view.\n +\n +//\n +// Simple movement.\n +//\n +// These simply delegate to the text view, because they take the text view\'s\n +// private virtual selection into account.\n +//\n +\n +exports.moveDown = function(args, request) {\n + var view = env.view;\n + view.moveDown();\n +};\n +\n +exports.moveLeft = function(args, request) {\n + var view = env.view;\n + view.moveLeft();\n +};\n +\n +exports.moveRight = function(args, request) {\n + var view = env.view;\n + view.moveRight();\n +};\n +\n +exports.moveUp = function(args, request) {\n + var view = env.view;\n + view.moveUp();\n +};\n +\n +//\n +// Simple selection.\n +//\n +\n +exports.selectDown = function(args, request) {\n + var view = env.view;\n + view.selectDown();\n +};\n +\n +exports.selectLeft = function(args, request) {\n + var view = env.view;\n + view.selectLeft();\n +};\n +\n +exports.selectRight = function(args, request) {\n + var view = env.view;\n + view.selectRight();\n +};\n +\n +exports.selectUp = function(args, request) {\n + var view = env.view;\n + view.selectUp();\n +};\n +\n +//\n +// Move or select to the end of the line or document.\n +//\n +\n +var moveOrSelectEnd = function(shift, inLine) {\n + var view = env.view, model = env.model;\n + var lines = model.lines;\n + var selectedRange = view.getSelectedRange(true);\n + var row = inLine ? selectedRange.end.row : lines.length - 1;\n + view.moveCursorTo({ row: row, col: lines[row].length }, shift);\n +};\n +\n +exports.moveLineEnd = function(args, request) {\n + moveOrSelectEnd(false, true);\n +};\n +\n +exports.selectLineEnd = function(args, request) {\n + moveOrSelectEnd(true, true);\n +};\n +\n +exports.moveDocEnd = function(args, request) {\n + moveOrSelectEnd(false, false);\n +};\n +\n +exports.selectDocEnd = function(args, request) {\n + moveOrSelectEnd(true, false);\n +};\n +\n +//\n +// Move or select to the beginning of the line or document.\n +//\n +\n +var moveOrSelectStart = function(shift, inLine) {\n + var view = env.view;\n + var range = view.getSelectedRange(true);\n + var row = inLine ? range.end.row : 0;\n + var position = { row: row, col: 0 };\n + view.moveCursorTo(position, shift);\n +};\n +\n +exports.moveLineStart = function (args, request) {\n + moveOrSelectStart(false, true);\n +};\n +\n +exports.selectLineStart = function(args, request) {\n + moveOrSelectStart(true, true);\n +};\n +\n +exports.moveDocStart = function(args, request) {\n + moveOrSelectStart(false, false);\n +};\n +\n +exports.selectDocStart = function(args, request) {\n + moveOrSelectStart(true, false);\n +};\n +\n +//\n +// Move or select to the next or previous word.\n +//\n +\n +var seekNextStop = function(view, text, col, dir, rowChanged) {\n + var isDelim;\n + var countDelim = 0;\n + var wasOverNonDelim = false;\n +\n + if (dir < 0) {\n + col--;\n + if (rowChanged) {\n + countDelim = 1;\n + }\n + }\n +\n + while (col < text.length && col > -1) {\n + isDelim = view.isDelimiter(text[col]);\n + if (isDelim) {\n + countDelim++;\n + } else {\n + wasOverNonDelim = true;\n + }\n + if ((isDelim || countDelim > 1) && wasOverNonDelim) {\n + break;\n + }\n + col += dir;\n + }\n +\n + if (dir < 0) {\n + col++;\n + }\n +\n + return col;\n +};\n +\n +var moveOrSelectNextWord = function(shiftDown) {\n + var view = env.view, model = env.model;\n + var lines = model.lines;\n +\n + var selectedRange = view.getSelectedRange(true);\n + var end = selectedRange.end;\n + var row = end.row, col = end.col;\n +\n + var currentLine = lines[row];\n + var changedRow = false;\n +\n + if (col >= currentLine.length) {\n + row++;\n + changedRow = true;\n + if (row < lines.length) {\n + col = 0;\n + currentLine = lines[row];\n + } else {\n + currentLine = \'\';\n + }\n + }\n +\n + col = seekNextStop(view, currentLine, col, 1, changedRow);\n +\n + view.moveCursorTo({ row: row, col: col }, shiftDown);\n +};\n +\n +var moveOrSelectPreviousWord = function(shiftDown) {\n + var view = env.view, model = env.model;\n +\n + var lines = model.lines;\n + var selectedRange = view.getSelectedRange(true);\n + var end = selectedRange.end;\n + var row = end.row, col = end.col;\n +\n + var currentLine = lines[row];\n + var changedRow = false;\n +\n + if (col > currentLine.length) {\n + col = currentLine.length;\n + } else if (col == 0) {\n + row--;\n + changedRow = true;\n + if (row > -1) {\n + currentLine = lines[row];\n + col = currentLine.length;\n + } else {\n + currentLine = \'\';\n + }\n + }\n +\n + col = seekNextStop(view, currentLine, col, -1, changedRow);\n +\n + view.moveCursorTo({ row: row, col: col }, shiftDown);\n +};\n +\n +exports.moveNextWord = function(args, request) {\n + moveOrSelectNextWord(false);\n +};\n +\n +exports.selectNextWord = function(args, request) {\n + moveOrSelectNextWord(true);\n +};\n +\n +exports.movePreviousWord = function(args, request) {\n + moveOrSelectPreviousWord(false);\n +};\n +\n +exports.selectPreviousWord = function(args, request) {\n + moveOrSelectPreviousWord(true);\n +};\n +\n +//\n +// Miscellaneous.\n +//\n +\n +/**\n + * Selects all characters in the buffer.\n + */\n +exports.selectAll = function(args, request) {\n + var view = env.view;\n + view.selectAll();\n +};\n +\n +});\n +\n +bespin.tiki.module("text_editor:index",function(require,exports,module) {\n +\n +});\n +;bespin.tiki.register("::less", {\n + name: "less",\n + dependencies: { }\n +});\n +bespin.tiki.module("less:index",function(require,exports,module) {\n +"define metadata";\n +({\n + "description": "Leaner CSS",\n + "url": "http://lesscss.org",\n + "dependencies": {},\n + "provides": [],\n + "keywords": ["css", "parser", "lesscss", "browser"],\n + "author": "Alexis Sellier <self@cloudhead.net>",\n + "contributors": [],\n + "version": "1.0.11"\n +});\n +"end";\n +\n +// --- Begin less.js ---\n +\n +//\n +// LESS - Leaner CSS v1.0.11\n +// http://lesscss.org\n +// \n +// Copyright (c) 2010, Alexis Sellier\n +// Licensed under the MIT license.\n +//\n +\n +// Tell the LESS library that this is a dist build. Important when using the\n +// dist build as a one-file CommonJS package.\n +var __LESS_DIST__ = true;\n +\n +// ecma-5.js\n +//\n +// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License\n +// -- tlrobinson Tom Robinson\n +// dantman Daniel Friesen\n +\n +//\n +// Array\n +//\n +if (!Array.isArray) {\n + Array.isArray = function(obj) {\n + return Object.prototype.toString.call(obj) === "[object Array]" ||\n + (obj instanceof Array);\n + };\n +}\n +if (!Array.prototype.forEach) {\n + Array.prototype.forEach = function(block, thisObject) {\n + var len = this.length >>> 0;\n + for (var i = 0; i < len; i++) {\n + if (i in this) {\n + block.call(thisObject, this[i], i, this);\n + }\n + }\n + };\n +}\n +if (!Array.prototype.map) {\n + Array.prototype.map = function(fun /*, thisp*/) {\n + var len = this.length >>> 0;\n + var res = new Array(len);\n + var thisp = arguments[1];\n +\n + for (var i = 0; i < len; i++) {\n + if (i in this) {\n + res[i] = fun.call(thisp, this[i], i, this);\n + }\n + }\n + return res;\n + };\n +}\n +if (!Array.prototype.filter) {\n + Array.prototype.filter = function (block /*, thisp */) {\n + var values = [];\n + var thisp = arguments[1];\n + for (var i = 0; i < this.length; i++) {\n + if (block.call(thisp, this[i])) {\n + values.push(this[i]);\n + }\n + }\n + return values;\n + };\n +}\n +if (!Array.prototype.reduce) {\n + Array.prototype.reduce = function(fun /*, initial*/) {\n + var len = this.length >>> 0;\n + var i = 0;\n +\n + // no value to return if no initial value and an empty array\n + if (len === 0 && arguments.length === 1) throw new TypeError();\n +\n + if (arguments.length >= 2) {\n + var rv = arguments[1];\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) throw new TypeError();\n + } while (true);\n + }\n + for (; i < len; i++) {\n + if (i in this) {\n + rv = fun.call(null, rv, this[i], i, this);\n + }\n + }\n + return rv;\n + };\n +}\n +if (!Array.prototype.indexOf) {\n + Array.prototype.indexOf = function (value /*, fromIndex */ ) {\n + var length = this.length;\n + var i = arguments[1] || 0;\n +\n + if (!length) return -1;\n + if (i >= length) return -1;\n + if (i < 0) i += length;\n +\n + for (; i < length; i++) {\n + if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }\n + if (value === this[i]) return i;\n + }\n + return -1;\n + };\n +}\n +\n +//\n +// Object\n +//\n +if (!Object.keys) {\n + Object.keys = function (object) {\n + var keys = [];\n + for (var name in object) {\n + if (Object.prototype.hasOwnProperty.call(object, name)) {\n + keys.push(name);\n + }\n + }\n + return keys;\n + };\n +}\n +\n +//\n +// String\n +//\n +if (!String.prototype.trim) {\n + String.prototype.trim = function () {\n + return String(this).replace(/^\\s\\s*/, \'\').replace(/\\s\\s*$/, \'\');\n + };\n +}\n +if (typeof(require) !== \'undefined\') {\n + var less = exports;\n +\n + if (typeof(__LESS_DIST__) === \'undefined\') {\n + var tree = require(\'less/tree\');\n + } else {\n + var tree = {};\n + }\n +} else {\n + var less = tree = {};\n +}\n +//\n +// less.js - parser\n +//\n +// A relatively straight-forward recursive-descent parser.\n +// There is no tokenization/lexing stage, the input is parsed\n +// in one sweep.\n +//\n +// To make the parser fast enough to run in the browser, several\n +// optimization had to be made:\n +//\n +// - Instead of the more commonly used technique of slicing the\n +// input string on every match, we use global regexps (/g),\n +// and move the `lastIndex` pointer on match, foregoing `slice()`\n +// completely. This gives us a 3x speed-up.\n +//\n +// - Matching on a huge input is often cause of slowdowns,\n +// especially with the /g flag. The solution to that is to\n +// chunkify the input: we split it by /\\n\\n/, just to be on\n +// the safe side. The chunks are stored in the `chunks` var,\n +// `j` holds the current chunk index, and `current` holds\n +// the index of the current chunk in relation to `input`.\n +// This gives us an almost 4x speed-up.\n +//\n +// - In many cases, we don\'t need to match individual tokens;\n +// for example, if a value doesn\'t hold any variables, operations\n +// or dynamic references, the parser can effectively \'skip\' it,\n +// treating it as a literal.\n +// An example would be \'1px solid #000\' - which evaluates to itself,\n +// we don\'t need to know what the individual components are.\n +// The drawback, of course is that you don\'t get the benefits of\n +// syntax-checking on the CSS. This gives us a 50% speed-up in the parser,\n +// and a smaller speed-up in the code-gen.\n +//\n +//\n +// Token matching is done with the `$` function, which either takes\n +// a terminal string or regexp, or a non-terminal function to call.\n +// It also takes care of moving all the indices forwards.\n +//\n +//\n +less.Parser = function Parser(env) {\n + var input, // LeSS input string\n + i, // current index in `input`\n + j, // current chunk\n + furthest, // furthest index the parser has gone to\n + chunks, // chunkified input\n + current, // index of current chunk, in `input`\n + inputLength,\n + parser;\n +\n + var that = this;\n +\n + // This function is called after all files\n + // have been imported through `@import`.\n + var finish = function () {};\n +\n + var imports = this.imports = {\n + paths: env && env.paths || [], // Search paths, when importing\n + queue: [], // Files which haven\'t been imported yet\n + files: {}, // Holds the imported parse trees\n + push: function (path, callback) {\n + var that = this;\n + this.queue.push(path);\n +\n + //\n + // Import a file asynchronously\n + //\n + less.Parser.importer(path, this.paths, function (root) {\n + that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue\n + that.files[path] = root; // Store the root\n +\n + callback(root);\n +\n + if (that.queue.length === 0) { finish() } // Call `finish` if we\'re done importing\n + });\n + }\n + };\n +\n + //\n + // Parse from a token, regexp or string, and move forward if match\n + //\n + function $(tok) {\n + var match, args, length, c, index, endIndex;\n +\n + //\n + // Non-terminal\n + //\n + if (tok instanceof Function) {\n + return tok.call(parser.parsers);\n + //\n + // Terminal\n + //\n + // Either match a single character in the input,\n + // or match a regexp in the current chunk (chunk[j]).\n + //\n + } else if (typeof(tok) === \'string\') {\n + match = input.charAt(i) === tok ? tok : null;\n + length = 1;\n +\n + // 1. We move to the next chunk, if necessary.\n + // 2. Set the `lastIndex` to be relative\n + // to the current chunk, and try to match in it.\n + // 3. Make sure we matched at `index`. Because we use\n + // the /g flag, the match could be anywhere in the\n + // chunk. We have to make sure it\'s at our previous\n + // index, which we stored in [2].\n + //\n + } else {\n + if (i >= current + chunks[j].length &&\n + j < chunks.length - 1) { // 1.\n + current += chunks[j++].length;\n + }\n + tok.lastIndex = index = i - current; // 2.\n + match = tok.exec(chunks[j]);\n +\n + if (match) {\n + length = match[0].length;\n + if (tok.lastIndex - length !== index) { return } // 3.\n + }\n + }\n +\n + // The match is confirmed, add the match length to `i`,\n + // and consume any extra white-space characters (\' \' || \'\\n\')\n + // which come after that. The reason for this is that LeSS\'s\n + // grammar is mostly white-space insensitive.\n + //\n + if (match) {\n + i += length;\n + endIndex = current + chunks[j].length;\n +\n + while (i <= endIndex) {\n + c = input.charCodeAt(i);\n + if (! (c === 32 || c === 10 || c === 9)) { break }\n + i++;\n + }\n +\n + if(typeof(match) === \'string\') {\n + return match;\n + } else {\n + return match.length === 1 ? match[0] : match;\n + }\n + }\n + }\n +\n + // Same as $(), but don\'t change the state of the parser,\n + // just return the match.\n + function peek(tok) {\n + var match;\n +\n + if (typeof(tok) === \'string\') {\n + return input.charAt(i) === tok;\n + } else {\n + tok.lastIndex = i;\n +\n + if ((match = tok.exec(input)) &&\n + (tok.lastIndex - match[0].length === i)) {\n + return match;\n + }\n + }\n + }\n +\n + this.env = env || {};\n +\n + // The optimization level dictates the thoroughness of the parser,\n + // the lower the number, the less nodes it will create in the tree.\n + // This could matter for debugging, or if you want to access\n + // the individual nodes in the tree.\n + this.optimization = (\'optimization\' in this.env) ? this.env.optimization : 1;\n +\n + //\n + // The Parser\n + //\n + return parser = {\n +\n + imports: imports,\n + //\n + // Parse an input string into an abstract syntax tree,\n + // call `callback` when done.\n + //\n + parse: function (str, callback) {\n + var root, start, end, zone, line, lines, buff = [], c, error = null;\n +\n + i = j = current = furthest = 0;\n + chunks = [];\n + input = str.replace(/\\r\\n/g, \'\\n\');\n +\n + // Split the input into chunks,\n + // delimited by /\\n\\n/ and \n + // removing comments (see rationale above),\n + // depending on the level of optimization.\n + if (that.optimization > 0) {\n + input = input.replace(/\\/\\*(?:[^*]|\\*+[^\\/*])*\\*+\\//g, function (comment) {\n + return that.optimization > 1 ? \'\' : comment.replace(/\\n(\\s*\\n)+/g, \'\\n\');\n + });\n + chunks = input.split(/^(?=\\n)/mg);\n + } else {\n + chunks = [input];\n + }\n + inputLength = input.length;\n +\n + // Start with the primary rule.\n + // The whole syntax tree is held under a Ruleset node,\n + // with the `root` property set to true, so no `{}` are\n + // output. The callback is called when the input is parsed.\n + root = new(tree.Ruleset)([], $(this.parsers.primary));\n + root.root = true;\n +\n + root.toCSS = (function (toCSS) {\n + var line, lines, column;\n +\n + return function () {\n + try {\n + return toCSS.call(this);\n + } catch (e) {\n + lines = input.split(\'\\n\');\n + line = (input.slice(0, e.index).match(/\\n/g) || "").length + 1;\n + for (var n = e.index, column = -1;\n + n >= 0 && input.charAt(n) !== \'\\n\';\n + n--) { column++ }\n +\n + throw {\n + name: "NameError",\n + message: e.message,\n + line: line,\n + column: column,\n + extract: [\n + lines[line - 2],\n + lines[line - 1],\n + lines[line]\n + ]\n + };\n + }\n + };\n + })(root.toCSS);\n +\n + // If `i` is smaller than the `input.length - 1`,\n + // it means the parser wasn\'t able to parse the whole\n + // string, so we\'ve got a parsing error.\n + //\n + // We try to extract a \\n delimited string,\n + // showing the line where the parse error occured.\n + // We split it up into two parts (the part which parsed,\n + // and the part which didn\'t), so we can color them differently.\n + if (i < input.length - 1) {\n + i = furthest;\n + lines = input.split(\'\\n\');\n + line = (input.slice(0, i).match(/\\n/g) || "").length + 1;\n +\n + for (var n = i, column = -1; n >= 0 && input.charAt(n) !== \'\\n\'; n--) { column++ }\n +\n + error = {\n + name: "ParseError",\n + message: "Syntax Error on line " + line,\n + filename: env.filename,\n + line: line,\n + column: column,\n + extract: [\n + lines[line - 2],\n + lines[line - 1],\n + lines[line]\n + ]\n + };\n + }\n +\n + if (this.imports.queue.length > 0) {\n + finish = function () { callback(error, root) };\n + } else {\n + callback(error, root);\n + }\n + },\n +\n + //\n + // Here in, the parsing rules/functions\n + //\n + // The basic structure of the syntax tree generated is as follows:\n + //\n + // Ruleset -> Rule -> Value -> Expression -> Entity\n + //\n + // Here\'s some LESS code:\n + //\n + // .class {\n + // color: #fff;\n + // border: 1px solid #000;\n + // width: @w + 4px;\n + // > .child {...}\n + // }\n + //\n + // And here\'s what the parse tree might look like:\n + //\n + // Ruleset (Selector \'.class\', [\n + // Rule ("color", Value ([Expression [Color #fff]]))\n + // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))\n + // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))\n + // Ruleset (Selector [Element \'>\', \'.child\'], [...])\n + // ])\n + //\n + // In general, most rules will try to parse a token with the `$()` function, and if the return\n + // value is truly, will return a new node, of the relevant type. Sometimes, we need to check\n + // first, before parsing, that\'s when we use `peek()`.\n + //\n + parsers: {\n + //\n + // The `primary` rule is the *entry* and *exit* point of the parser.\n + // The rules here can appear at any level of the parse tree.\n + //\n + // The recursive nature of the grammar is an interplay between the `block`\n + // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,\n + // as represented by this simplified grammar:\n + //\n + // primary → (ruleset | rule)+\n + // ruleset → selector+ block\n + // block → \'{\' primary \'}\'\n + //\n + // Only at one point is the primary rule not called from the\n + // block rule: at the root level.\n + //\n + primary: function () {\n + var node, root = [];\n +\n + while (node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||\n + $(this.mixin.call) || $(this.comment) ||\n + $(/[\\n\\s]+/g) || $(this.directive)) {\n + root.push(node);\n + }\n + return root;\n + },\n +\n + // We create a Comment node for CSS comments `/* */`,\n + // but keep the LeSS comments `//` silent, by just skipping\n + // over them.\n + comment: function () {\n + var comment;\n +\n + if (input.charAt(i) !== \'/\') return;\n +\n + if (comment = $(/\\/\\*(?:[^*]|\\*+[^\\/*])*\\*+\\/\\n?/g)) {\n + return new(tree.Comment)(comment);\n + } else {\n + return $(/\\/\\/.*/g);\n + }\n + },\n +\n + //\n + // Entities are tokens which can be found inside an Expression\n + //\n + entities: {\n + //\n + // A string, which supports escaping " and \'\n + //\n + // "milky way" \'he\\\'s the one!\'\n + //\n + quoted: function () {\n + var str;\n + if (input.charAt(i) !== \'"\' && input.charAt(i) !== "\'") return;\n +\n + if (str = $(/"((?:[^"\\\\\\r\\n]|\\\\.)*)"|\'((?:[^\'\\\\\\r\\n]|\\\\.)*)\'/g)) {\n + return new(tree.Quoted)(str[0], str[1] || str[2]);\n + }\n + },\n +\n + //\n + // A catch-all word, such as:\n + //\n + // black border-collapse\n + //\n + keyword: function () {\n + var k;\n + if (k = $(/[A-Za-z-]+/g)) { return new(tree.Keyword)(k) }\n + },\n +\n + //\n + // A function call\n + //\n + // rgb(255, 0, 255)\n + //\n + // We also try to catch IE\'s `alpha()`, but let the `alpha` parser\n + // deal with the details.\n + //\n + // The arguments are parsed with the `entities.arguments` parser.\n + //\n + call: function () {\n + var name, args;\n +\n + if (! (name = $(/([a-zA-Z0-9_-]+|%)\\(/g))) return;\n +\n + if (name[1].toLowerCase() === \'alpha\') { return $(this.alpha) }\n +\n + args = $(this.entities.arguments);\n +\n + if (! $(\')\')) return;\n +\n + if (name) { return new(tree.Call)(name[1], args) }\n + },\n + arguments: function () {\n + var args = [], arg;\n +\n + while (arg = $(this.expression)) {\n + args.push(arg);\n + if (! $(\',\')) { break }\n + }\n + return args;\n + },\n + literal: function () {\n + return $(this.entities.dimension) ||\n + $(this.entities.color) ||\n + $(this.entities.quoted);\n + },\n +\n + //\n + // Parse url() tokens\n + //\n + // We use a specific rule for urls, because they don\'t really behave like\n + // standard function calls. The difference is that the argument doesn\'t have\n + // to be enclosed within a string, so it can\'t be parsed as an Expression.\n + //\n + url: function () {\n + var value;\n +\n + if (input.charAt(i) !== \'u\' || !$(/url\\(/g)) return;\n + value = $(this.entities.quoted) || $(/[-a-zA-Z0-9_%@$\\/.&=:;#+?]+/g);\n + if (! $(\')\')) throw new(Error)("missing closing ) for url()");\n +\n + return new(tree.URL)(value.value ? value : new(tree.Anonymous)(value));\n + },\n +\n + //\n + // A Variable entity, such as `@fink`, in\n + //\n + // width: @fink + 2px\n + //\n + // We use a different parser for variable definitions,\n + // see `parsers.variable`.\n + //\n + variable: function () {\n + var name, index = i;\n +\n + if (input.charAt(i) === \'@\' && (name = $(/@[a-zA-Z0-9_-]+/g))) {\n + return new(tree.Variable)(name, index);\n + }\n + },\n +\n + //\n + // A Hexadecimal color\n + //\n + // #4F3C2F\n + //\n + // `rgb` and `hsl` colors are parsed through the `entities.call` parser.\n + //\n + color: function () {\n + var rgb;\n +\n + if (input.charAt(i) === \'#\' && (rgb = $(/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/g))) {\n + return new(tree.Color)(rgb[1]);\n + }\n + },\n +\n + //\n + // A Dimension, that is, a number and a unit\n + //\n + // 0.5em 95%\n + //\n + dimension: function () {\n + var value, c = input.charCodeAt(i);\n + if ((c > 57 || c < 45) || c === 47) return;\n +\n + if (value = $(/(-?[0-9]*\\.?[0-9]+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm)?/g)) {\n + return new(tree.Dimension)(value[1], value[2]);\n + }\n + }\n + },\n +\n + //\n + // The variable part of a variable definition. Used in the `rule` parser\n + //\n + // @fink:\n + //\n + variable: function () {\n + var name;\n +\n + if (input.charAt(i) === \'@\' && (name = $(/(@[a-zA-Z0-9_-]+)\\s*:/g))) { return name[1] }\n + },\n +\n + //\n + // A font size/line-height shorthand\n + //\n + // small/12px\n + //\n + // We need to peek first, or we\'ll match on keywords and dimensions\n + //\n + shorthand: function () {\n + var a, b;\n +\n + if (! peek(/[@\\w.-]+\\/[@\\w.-]+/g)) return;\n +\n + if ((a = $(this.entity)) && $(\'/\') && (b = $(this.entity))) {\n + return new(tree.Shorthand)(a, b);\n + }\n + },\n +\n + //\n + // Mixins\n + //\n + mixin: {\n + //\n + // A Mixin call, with an optional argument list\n + //\n + // #mixins > .square(#fff);\n + // .rounded(4px, black);\n + // .button;\n + //\n + // The `while` loop is there because mixins can be\n + // namespaced, but we only support the child and descendant\n + // selector for now.\n + //\n + call: function () {\n + var elements = [], e, c, args, index = i;\n +\n + while (e = $(/[#.][a-zA-Z0-9_-]+/g)) {\n + elements.push(new(tree.Element)(c, e));\n + c = $(\'>\');\n + }\n + $(\'(\') && (args = $(this.entities.arguments)) && $(\')\');\n +\n + if (elements.length > 0 && ($(\';\') || peek(\'}\'))) {\n + return new(tree.mixin.Call)(elements, args, index);\n + }\n + },\n +\n + //\n + // A Mixin definition, with a list of parameters\n + //\n + // .rounded (@radius: 2px, @color) {\n + // ...\n + // }\n + //\n + // Until we have a finer grained state-machine, we have to\n + // do a look-ahead, to make sure we don\'t have a mixin call.\n + // See the `rule` function for more information.\n + //\n + // We start by matching `.rounded (`, and then proceed on to\n + // the argument list, which has optional default values.\n + // We store the parameters in `params`, with a `value` key,\n + // if there is a value, such as in the case of `@radius`.\n + //\n + // Once we\'ve got our params list, and a closing `)`, we parse\n + // the `{...}` block.\n + //\n + definition: function () {\n + var name, params = [], match, ruleset, param, value;\n +\n + if (input.charAt(i) !== \'.\' || peek(/[^{]*(;|})/g)) return;\n +\n + if (match = $(/([#.][a-zA-Z0-9_-]+)\\s*\\(/g)) {\n + name = match[1];\n +\n + while (param = $(/@[\\w-]+/g) || $(this.entities.literal)\n + || $(this.entities.keyword)) {\n + // Variable\n + if (param[0] === \'@\') {\n + if ($(\':\')) {\n + if (value = $(this.expression)) {\n + params.push({ name: param, value: value });\n + } else {\n + throw new(Error)("Expected value");\n + }\n + } else {\n + params.push({ name: param });\n + }\n + } else {\n + params.push({ value: param });\n + }\n + if (! $(\',\')) { break }\n + }\n + if (! $(\')\')) throw new(Error)("Expected )");\n +\n + ruleset = $(this.block);\n +\n + if (ruleset) {\n + return new(tree.mixin.Definition)(name, params, ruleset);\n + }\n + }\n + }\n + },\n +\n + //\n + // Entities are the smallest recognized token,\n + // and can be found inside a rule\'s value.\n + //\n + entity: function () {\n + return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||\n + $(this.entities.call) || $(this.entities.keyword);\n + },\n +\n + //\n + // A Rule terminator. Note that we use `peek()` to check for \'}\',\n + // because the `block` rule will be expecting it, but we still need to make sure\n + // it\'s there, if \';\' was ommitted.\n + //\n + end: function () {\n + return $(\';\') || peek(\'}\');\n + },\n +\n + //\n + // IE\'s alpha function\n + //\n + // alpha(opacity=88)\n + //\n + alpha: function () {\n + var value;\n +\n + if (! $(/opacity=/gi)) return;\n + if (value = $(/[0-9]+/g) || $(this.entities.variable)) {\n + if (! $(\')\')) throw new(Error)("missing closing ) for alpha()");\n + return new(tree.Alpha)(value);\n + }\n + },\n +\n + //\n + // A Selector Element\n + //\n + // div\n + // + h1\n + // #socks\n + // input[type="text"]\n + //\n + // Elements are the building blocks for Selectors,\n + // they are made out of a `Combinator` (see combinator rule),\n + // and an element name, such as a tag a class, or `*`.\n + //\n + element: function () {\n + var e, t;\n +\n + c = $(this.combinator);\n + e = $(/[.#:]?[a-zA-Z0-9_-]+/g) || $(\'*\') || $(this.attribute) || $(/\\([^)@]+\\)/g);\n +\n + if (e) { return new(tree.Element)(c, e) }\n + },\n +\n + //\n + // Combinators combine elements together, in a Selector.\n + //\n + // Because our parser isn\'t white-space sensitive, special care\n + // has to be taken, when parsing the descendant combinator, ` `,\n + // as it\'s an empty space. We have to check the previous character\n + // in the input, to see if it\'s a ` ` character. More info on how\n + // we deal with this in *combinator.js*.\n + //\n + combinator: function () {\n + var match;\n + if (match = $(/[+>~]/g) || $(\'&\') || $(/::/g)) {\n + return new(tree.Combinator)(match);\n + } else {\n + return new(tree.Combinator)(input.charAt(i - 1) === " " ? " " : null);\n + }\n + },\n +\n + //\n + // A CSS Selector\n + //\n + // .class > div + h1\n + // li a:hover\n + //\n + // Selectors are made out of one or more Elements, see above.\n + //\n + selector: function () {\n + var sel, e, elements = [], match;\n +\n + while (e = $(this.element)) { elements.push(e) }\n +\n + if (elements.length > 0) { return new(tree.Selector)(elements) }\n + },\n + tag: function () {\n + return $(/[a-zA-Z][a-zA-Z-]*[0-9]?/g) || $(\'*\');\n + },\n + attribute: function () {\n + var attr = \'\', key, val, op;\n +\n + if (! $(\'[\')) return;\n +\n + if (key = $(/[a-z-]+/g) || $(this.entities.quoted)) {\n + if ((op = $(/[|~*$^]?=/g)) &&\n + (val = $(this.entities.quoted) || $(/[\\w-]+/g))) {\n + attr = [key, op, val.toCSS ? val.toCSS() : val].join(\'\');\n + } else { attr = key }\n + }\n +\n + if (! $(\']\')) return;\n +\n + if (attr) { return "[" + attr + "]" }\n + },\n +\n + //\n + // The `block` rule is used by `ruleset` and `mixin.definition`.\n + // It\'s a wrapper around the `primary` rule, with added `{}`.\n + //\n + block: function () {\n + var content;\n +\n + if ($(\'{\') && (content = $(this.primary)) && $(\'}\')) {\n + return content;\n + }\n + },\n +\n + //\n + // div, .class, body > p {...}\n + //\n + ruleset: function () {\n + var selectors = [], s, rules, match, memo = i;\n +\n + if (match = peek(/([a-z.#: _-]+)[\\s\\n]*\\{/g)) {\n + i += match[0].length - 1;\n + selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])];\n + } else {\n + while (s = $(this.selector)) {\n + selectors.push(s);\n + if (! $(\',\')) { break }\n + }\n + if (s) $(this.comment);\n + }\n +\n + if (selectors.length > 0 && (rules = $(this.block))) {\n + return new(tree.Ruleset)(selectors, rules);\n + } else {\n + // Backtrack\n + furthest = i;\n + i = memo;\n + }\n + },\n + rule: function () {\n + var value;\n + var memo = i;\n +\n + if (name = $(this.property) || $(this.variable)) {\n + if ((name.charAt(0) != \'@\') && (match = peek(/([^@+\\/*(;{}-]*);/g))) {\n + i += match[0].length - 1;\n + value = new(tree.Anonymous)(match[1]);\n + } else if (name === "font") {\n + value = $(this.font);\n + } else {\n + value = $(this.value);\n + }\n +\n + if ($(this.end)) {\n + return new(tree.Rule)(name, value, memo);\n + } else {\n + furthest = i;\n + i = memo;\n + }\n + }\n + },\n +\n + //\n + // An @import directive\n + //\n + // @import "lib";\n + //\n + // Depending on our environemnt, importing is done differently:\n + // In the browser, it\'s an XHR request, in Node, it would be a\n + // file-system operation. The function used for importing is\n + // stored in `import`, which we pass to the Import constructor.\n + //\n + "import": function () {\n + var path;\n + if ($(/@import\\s+/g) &&\n + (path = $(this.entities.quoted) || $(this.entities.url)) &&\n + $(\';\')) {\n + return new(tree.Import)(path, imports);\n + }\n + },\n +\n + //\n + // A CSS Directive\n + //\n + // @charset "utf-8";\n + //\n + directive: function () {\n + var name, value, rules, types;\n +\n + if (input.charAt(i) !== \'@\') return;\n +\n + if (value = $(this[\'import\'])) {\n + return value;\n + } else if (name = $(/@media|@page/g)) {\n + types = $(/[^{]+/g).trim();\n + if (rules = $(this.block)) {\n + return new(tree.Directive)(name + " " + types, rules);\n + }\n + } else if (name = $(/@[-a-z]+/g)) {\n + if (name === \'@font-face\') {\n + if (rules = $(this.block)) {\n + return new(tree.Directive)(name, rules);\n + }\n + } else if ((value = $(this.entity)) && $(\';\')) {\n + return new(tree.Directive)(name, value);\n + }\n + }\n + },\n + font: function () {\n + var value = [], expression = [], weight, shorthand, font, e;\n +\n + while (e = $(this.shorthand) || $(this.entity)) {\n + expression.push(e);\n + }\n + value.push(new(tree.Expression)(expression));\n +\n + if ($(\',\')) {\n + while (e = $(this.expression)) {\n + value.push(e);\n + if (! $(\',\')) { break }\n + }\n + }\n + return new(tree.Value)(value, $(this.important));\n + },\n +\n + //\n + // A Value is a comma-delimited list of Expressions\n + //\n + // font-family: Baskerville, Georgia, serif;\n + //\n + // In a Rule, a Value represents everything after the `:`,\n + // and before the `;`.\n + //\n + value: function () {\n + var e, expressions = [], important;\n +\n + while (e = $(this.expression)) {\n + expressions.push(e);\n + if (! $(\',\')) { break }\n + }\n + important = $(this.important);\n +\n + if (expressions.length > 0) {\n + return new(tree.Value)(expressions, important);\n + }\n + },\n + important: function () {\n + return $(/!\\s*important/g);\n + },\n + sub: function () {\n + var e;\n +\n + if ($(\'(\') && (e = $(this.expression)) && $(\')\')) {\n + return e;\n + }\n + },\n + multiplication: function () {\n + var m, a, op, operation;\n + if (m = $(this.operand)) {\n + while ((op = $(/[\\/*]/g)) && (a = $(this.operand))) {\n + operation = new(tree.Operation)(op, [operation || m, a]);\n + }\n + return operation || m;\n + }\n + },\n + addition: function () {\n + var m, a, op, operation;\n + if (m = $(this.multiplication)) {\n + while ((op = $(/[-+]\\s+/g) || (input.charAt(i - 1) != \' \' && $(/[-+]/g))) &&\n + (a = $(this.multiplication))) {\n + operation = new(tree.Operation)(op, [operation || m, a]);\n + }\n + return operation || m;\n + }\n + },\n +\n + //\n + // An operand is anything that can be part of an operation,\n + // such as a Color, or a Variable\n + //\n + operand: function () {\n + return $(this.sub) || $(this.entities.dimension) ||\n + $(this.entities.color) || $(this.entities.variable);\n + },\n +\n + //\n + // Expressions either represent mathematical operations,\n + // or white-space delimited Entities.\n + //\n + // 1px solid black\n + // @var * 2\n + //\n + expression: function () {\n + var e, delim, entities = [], d;\n +\n + while (e = $(this.addition) || $(this.entity)) {\n + entities.push(e);\n + }\n + if (entities.length > 0) {\n + return new(tree.Expression)(entities);\n + }\n + },\n + property: function () {\n + var name;\n +\n + if (name = $(/(\\*?-?[-a-z_0-9]+)\\s*:/g)) {\n + return name[1];\n + }\n + }\n + }\n + };\n +};\n +\n +less.Parser.importer = null;\n +\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.functions = {\n + rgb: function (r, g, b) {\n + return this.rgba(r, g, b, 1.0);\n + },\n + rgba: function (r, g, b, a) {\n + var rgb = [r, g, b].map(function (c) { return number(c) }),\n + a = number(a);\n + return new(tree.Color)(rgb, a);\n + },\n + hsl: function (h, s, l) {\n + return this.hsla(h, s, l, 1.0);\n + },\n + hsla: function (h, s, l, a) {\n + h = (((number(h) % 360) + 360) % 360) / 360;\n + s = number(s); l = number(l); a = number(a);\n +\n + //require(\'sys\').puts(h, s, l)\n +\n + var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n + var m1 = l * 2 - m2;\n +\n + return this.rgba(hue(h + 1/3) * 255,\n + hue(h) * 255,\n + hue(h - 1/3) * 255,\n + a);\n +\n + function hue(h) {\n + h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);\n + if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;\n + else if (h * 2 < 1) return m2;\n + else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;\n + else return m1;\n + }\n + },\n + opacity: function(color, amount) {\n + var alpha = number(amount) * (color.alpha || 1.0);\n + return new(tree.Color)(color.rgb, number(amount));\n + },\n + saturate: function (color, amount) {\n + var hsl = color.toHSL();\n +\n + hsl.s += amount.value / 100;\n + hsl.s = clamp(hsl.s);\n + return this.hsl(hsl.h, hsl.s, hsl.l);\n + },\n + desaturate: function (color, amount) {\n + var hsl = color.toHSL();\n +\n + hsl.s -= amount.value / 100;\n + hsl.s = clamp(hsl.s);\n + return this.hsl(hsl.h, hsl.s, hsl.l);\n + },\n + lighten: function (color, amount) {\n + var hsl = color.toHSL();\n +\n + hsl.l *= (1 + amount.value / 100);\n + hsl.l = clamp(hsl.l);\n + return this.hsl(hsl.h, hsl.s, hsl.l);\n + },\n + darken: function (color, amount) {\n + var hsl = color.toHSL();\n +\n + hsl.l *= (1 - amount.value / 100);\n + hsl.l = clamp(hsl.l);\n + return this.hsl(hsl.h, hsl.s, hsl.l);\n + },\n + greyscale: function (color, amount) {\n + return this.desaturate(color, new(tree.Dimension)(100));\n + },\n + e: function (str) {\n + return new(tree.Anonymous)(str);\n + },\n + \'%\': function (quoted /* arg, arg, ...*/) {\n + var args = Array.prototype.slice.call(arguments, 1),\n + str = quoted.content;\n +\n + for (var i = 0; i < args.length; i++) {\n + str = str.replace(/%s/, args[i].content)\n + .replace(/%[da]/, args[i].toCSS());\n + }\n + str = str.replace(/%%/g, \'%\');\n + return new(tree.Quoted)(\'"\' + str + \'"\', str);\n + }\n +};\n +\n +function number(n) {\n + if (n instanceof tree.Dimension) {\n + return parseFloat(n.unit == \'%\' ? n.value / 100 : n.value);\n + } else if (typeof(n) === \'number\') {\n + return n;\n + } else {\n + throw {\n + error: "RuntimeError",\n + message: "color functions take numbers as parameters"\n + };\n + }\n +}\n +\n +function clamp(val) {\n + return Math.min(1, Math.max(0, val));\n +}\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Alpha = function Alpha(val) {\n + this.value = val;\n +};\n +tree.Alpha.prototype = {\n + toCSS: function () {\n + return "alpha(opacity=" + this.value.toCSS() + ")";\n + },\n + eval: function () { return this }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Anonymous = function Anonymous(string) {\n + this.value = string.content || string;\n +};\n +tree.Anonymous.prototype = {\n + toCSS: function () {\n + return this.value;\n + },\n + eval: function () { return this }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +//\n +// A function call node.\n +//\n +tree.Call = function Call(name, args) {\n + this.name = name;\n + this.args = args;\n +};\n +tree.Call.prototype = {\n + //\n + // When evaluating a function call,\n + // we either find the function in `tree.functions` [1],\n + // in which case we call it, passing the evaluated arguments,\n + // or we simply print it out as it appeared originally [2].\n + //\n + // The *functions.js* file contains the built-in functions.\n + //\n + // The reason why we evaluate the arguments, is in the case where\n + // we try to pass a variable to a function, like: `saturate(@color)`.\n + // The function should receive the value, not the variable.\n + //\n + eval: function (env) {\n + var args = this.args.map(function (a) { return a.eval(env) });\n +\n + if (this.name in tree.functions) { // 1.\n + return tree.functions[this.name].apply(tree.functions, args);\n + } else { // 2.\n + return new(tree.Anonymous)(this.name +\n + "(" + args.map(function (a) { return a.toCSS() }).join(\', \') + ")");\n + }\n + },\n +\n + toCSS: function (env) {\n + return this.eval(env).toCSS();\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +//\n +// RGB Colors - #ff0014, #eee\n +//\n +tree.Color = function Color(rgb, a) {\n + //\n + // The end goal here, is to parse the arguments\n + // into an integer triplet, such as `128, 255, 0`\n + //\n + // This facilitates operations and conversions.\n + //\n + if (Array.isArray(rgb)) {\n + this.rgb = rgb;\n + this.alpha = a;\n + } else if (rgb.length == 6) {\n + this.rgb = rgb.match(/.{2}/g).map(function (c) {\n + return parseInt(c, 16);\n + });\n + } else {\n + this.rgb = rgb.split(\'\').map(function (c) {\n + return parseInt(c + c, 16);\n + });\n + }\n +};\n +tree.Color.prototype = {\n + eval: function () { return this },\n +\n + //\n + // If we have some transparency, the only way to represent it\n + // is via `rgba`. Otherwise, we use the hex representation,\n + // which has better compatibility with older browsers.\n + // Values are capped between `0` and `255`, rounded and zero-padded.\n + //\n + toCSS: function () {\n + if (this.alpha && this.alpha < 1.0) {\n + return "rgba(" + this.rgb.concat(this.alpha).join(\', \') + ")";\n + } else {\n + return \'#\' + this.rgb.map(function (i) {\n + i = Math.round(i);\n + i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);\n + return i.length === 1 ? \'0\' + i : i;\n + }).join(\'\');\n + }\n + },\n +\n + //\n + // Operations have to be done per-channel, if not,\n + // channels will spill onto each other. Once we have\n + // our result, in the form of an integer triplet,\n + // we create a new Color node to hold the result.\n + //\n + operate: function (op, other) {\n + var result = [];\n +\n + if (! (other instanceof tree.Color)) {\n + other = other.toColor();\n + }\n +\n + for (var c = 0; c < 3; c++) {\n + result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);\n + }\n + return new(tree.Color)(result);\n + },\n +\n + toHSL: function () {\n + var r = this.rgb[0] / 255,\n + g = this.rgb[1] / 255,\n + b = this.rgb[2] / 255;\n +\n + var max = Math.max(r, g, b), min = Math.min(r, g, b);\n + var h, s, l = (max + min) / 2, d = max - min;\n +\n + if (max === min) {\n + h = s = 0;\n + } else {\n + s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n +\n + switch (max) {\n + case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n + case g: h = (b - r) / d + 2; break;\n + case b: h = (r - g) / d + 4; break;\n + }\n + h /= 6;\n + }\n + return { h: h * 360, s: s, l: l };\n + }\n +};\n +\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Comment = function Comment(value) {\n + this.value = value;\n +};\n +tree.Comment.prototype = {\n + toCSS: function () {\n + return this.value;\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +//\n +// A number with a unit\n +//\n +tree.Dimension = function Dimension(value, unit) {\n + this.value = parseFloat(value);\n + this.unit = unit || null;\n +};\n +\n +tree.Dimension.prototype = {\n + eval: function () { return this },\n + toColor: function () {\n + return new(tree.Color)([this.value, this.value, this.value]);\n + },\n + toCSS: function () {\n + var css = this.value + this.unit;\n + return css;\n + },\n +\n + // In an operation between two Dimensions,\n + // we default to the first Dimension\'s unit,\n + // so `1px + 2em` will yield `3px`.\n + // In the future, we could implement some unit\n + // conversions such that `100cm + 10mm` would yield\n + // `101cm`.\n + operate: function (op, other) {\n + return new(tree.Dimension)\n + (tree.operate(op, this.value, other.value),\n + this.unit || other.unit);\n + }\n +};\n +\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Directive = function Directive(name, value) {\n + this.name = name;\n + if (Array.isArray(value)) {\n + this.ruleset = new(tree.Ruleset)([], value);\n + } else {\n + this.value = value;\n + }\n +};\n +tree.Directive.prototype = {\n + toCSS: function (ctx, env) {\n + if (this.ruleset) {\n + this.ruleset.root = true;\n + return this.name + \' {\\n \' +\n + this.ruleset.toCSS(ctx, env).trim().replace(/\\n/g, \'\\n \') + \'\\n}\\n\';\n + } else {\n + return this.name + \' \' + this.value.toCSS() + \';\\n\';\n + }\n + },\n + eval: function (env) {\n + env.frames.unshift(this);\n + this.ruleset && this.ruleset.evalRules(env);\n + env.frames.shift();\n + return this;\n + },\n + variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },\n + find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },\n + rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Element = function Element(combinator, value) {\n + this.combinator = combinator instanceof tree.Combinator ?\n + combinator : new(tree.Combinator)(combinator);\n + this.value = value.trim();\n +};\n +tree.Element.prototype.toCSS = function () {\n + return this.combinator.toCSS() + this.value;\n +};\n +\n +tree.Combinator = function Combinator(value) {\n + if (value === \' \') {\n + this.value = \' \';\n + } else {\n + this.value = value ? value.trim() : "";\n + }\n +};\n +tree.Combinator.prototype.toCSS = function () {\n + switch (this.value) {\n + case \'\' : return \'\';\n + case \' \' : return \' \';\n + case \'&\' : return \'\';\n + case \':\' : return \' :\';\n + case \'::\': return \'::\';\n + case \'+\' : return \' + \';\n + case \'~\' : return \' ~ \';\n + case \'>\' : return \' > \';\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Expression = function Expression(value) { this.value = value };\n +tree.Expression.prototype = {\n + eval: function (env) {\n + if (this.value.length > 1) {\n + return new(tree.Expression)(this.value.map(function (e) {\n + return e.eval(env);\n + }));\n + } else {\n + return this.value[0].eval(env);\n + }\n + },\n + toCSS: function () {\n + return this.value.map(function (e) {\n + return e.toCSS();\n + }).join(\' \');\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +//\n +// CSS @import node\n +//\n +// The general strategy here is that we don\'t want to wait\n +// for the parsing to be completed, before we start importing\n +// the file. That\'s because in the context of a browser,\n +// most of the time will be spent waiting for the server to respond.\n +//\n +// On creation, we push the import path to our import queue, though\n +// `import,push`, we also pass it a callback, which it\'ll call once\n +// the file has been fetched, and parsed.\n +//\n +tree.Import = function Import(path, imports) {\n + var that = this;\n +\n + this._path = path;\n +\n + // The \'.less\' extension is optional\n + if (path instanceof tree.Quoted) {\n + this.path = /\\.(le?|c)ss$/.test(path.content) ? path.content : path.content + \'.less\';\n + } else {\n + this.path = path.value.content || path.value;\n + }\n +\n + this.css = /css$/.test(this.path);\n +\n + // Only pre-compile .less files\n + if (! this.css) {\n + imports.push(this.path, function (root) {\n + that.root = root;\n + });\n + }\n +};\n +\n +//\n +// The actual import node doesn\'t return anything, when converted to CSS.\n +// The reason is that it\'s used at the evaluation stage, so that the rules\n +// it imports can be treated like any other rules.\n +//\n +// In `eval`, we make sure all Import nodes get evaluated, recursively, so\n +// we end up with a flat structure, which can easily be imported in the parent\n +// ruleset.\n +//\n +tree.Import.prototype = {\n + toCSS: function () {\n + if (this.css) {\n + return "@import " + this._path.toCSS() + \';\\n\';\n + } else {\n + return "";\n + }\n + },\n + eval: function () {\n + if (this.css) {\n + return this;\n + } else {\n + for (var i = 0; i < this.root.rules.length; i++) {\n + if (this.root.rules[i] instanceof tree.Import) {\n + Array.prototype\n + .splice\n + .apply(this.root.rules,\n + [i, 1].concat(this.root.rules[i].eval()));\n + }\n + }\n + return this.root.rules;\n + }\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Keyword = function Keyword(value) { this.value = value };\n +tree.Keyword.prototype = {\n + eval: function () { return this },\n + toCSS: function () { return this.value }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.mixin = {};\n +tree.mixin.Call = function MixinCall(elements, args, index) {\n + this.selector = new(tree.Selector)(elements);\n + this.arguments = args;\n + this.index = index;\n +};\n +tree.mixin.Call.prototype = {\n + eval: function (env) {\n + var mixins, rules = [], match = false;\n +\n + for (var i = 0; i < env.frames.length; i++) {\n + if ((mixins = env.frames[i].find(this.selector)).length > 0) {\n + for (var m = 0; m < mixins.length; m++) {\n + if (mixins[m].match(this.arguments, env)) {\n + try {\n + Array.prototype.push.apply(\n + rules, mixins[m].eval(this.arguments, env).rules);\n + match = true;\n + } catch (e) {\n + throw { message: e.message, index: this.index };\n + }\n + }\n + }\n + if (match) {\n + return rules;\n + } else {\n + throw { message: \'No matching definition was found for `\' +\n + this.selector.toCSS().trim() + \'(\' +\n + this.arguments.map(function (a) {\n + return a.toCSS();\n + }).join(\', \') + ")`",\n + index: this.index };\n + }\n + }\n + }\n + throw { message: this.selector.toCSS().trim() + " is undefined",\n + index: this.index };\n + }\n +};\n +\n +tree.mixin.Definition = function MixinDefinition(name, params, rules) {\n + this.name = name;\n + this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];\n + this.params = params;\n + this.arity = params.length;\n + this.rules = rules;\n + this._lookups = {};\n + this.required = params.reduce(function (count, p) {\n + if (p.name && !p.value) { return count + 1 }\n + else { return count }\n + }, 0);\n +};\n +tree.mixin.Definition.prototype = {\n + toCSS: function () { return "" },\n + variable: function (name) { return tree.Ruleset.prototype.variable.call(this, name) },\n + find: function () { return tree.Ruleset.prototype.find.apply(this, arguments) },\n + rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this) },\n +\n + eval: function (args, env) {\n + var frame = new(tree.Ruleset)(null, []), context;\n +\n + for (var i = 0, val; i < this.params.length; i++) {\n + if (this.params[i].name) {\n + if (val = (args && args[i]) || this.params[i].value) {\n + frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));\n + } else {\n + throw { message: "wrong number of arguments for " + this.name +\n + \' (\' + args.length + \' for \' + this.arity + \')\' };\n + }\n + }\n + }\n + return new(tree.Ruleset)(null, this.rules).evalRules({\n + frames: [this, frame].concat(env.frames)\n + });\n + },\n + match: function (args, env) {\n + var argsLength = (args && args.length) || 0;\n +\n + if (argsLength < this.required) {\n + return false;\n + }\n +\n + for (var i = 0; i < Math.min(argsLength, this.arity); i++) {\n + if (!this.params[i].name) {\n + if (args[i].wildcard) { continue }\n + else if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {\n + return false;\n + }\n + }\n + }\n + return true;\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Operation = function Operation(op, operands) {\n + this.op = op.trim();\n + this.operands = operands;\n +};\n +tree.Operation.prototype.eval = function (env) {\n + var a = this.operands[0].eval(env),\n + b = this.operands[1].eval(env),\n + temp;\n +\n + if (a instanceof tree.Dimension && b instanceof tree.Color) {\n + if (this.op === \'*\' || this.op === \'+\') {\n + temp = b, b = a, a = temp;\n + } else {\n + throw { name: "OperationError",\n + message: "Can\'t substract or divide a color from a number" };\n + }\n + }\n + return a.operate(this.op, b);\n +};\n +\n +tree.operate = function (op, a, b) {\n + switch (op) {\n + case \'+\': return a + b;\n + case \'-\': return a - b;\n + case \'*\': return a * b;\n + case \'/\': return a / b;\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Quoted = function Quoted(value, content) {\n + this.value = value;\n + this.content = content;\n +};\n +tree.Quoted.prototype = {\n + toCSS: function () {\n + var css = this.value;\n + return css;\n + },\n + eval: function () {\n + return this;\n + }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Rule = function Rule(name, value, index) {\n + this.name = name;\n + this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);\n + this.index = index;\n +\n + if (name.charAt(0) === \'@\') {\n + this.variable = true;\n + } else { this.variable = false }\n +};\n +tree.Rule.prototype.toCSS = function () {\n + if (this.variable) { return "" }\n + else {\n + return this.name + ": " + this.value.toCSS() + ";";\n + }\n +};\n +\n +tree.Rule.prototype.eval = function (context) {\n + return new(tree.Rule)(this.name, this.value.eval(context));\n +};\n +\n +tree.Value = function Value(value) {\n + this.value = value;\n + this.is = \'value\';\n +};\n +tree.Value.prototype = {\n + eval: function (env) {\n + if (this.value.length === 1) {\n + return this.value[0].eval(env);\n + } else {\n + return new(tree.Value)(this.value.map(function (v) {\n + return v.eval(env);\n + }));\n + }\n + },\n + toCSS: function () {\n + return this.value.map(function (e) {\n + return e.toCSS();\n + }).join(\', \');\n + }\n +};\n +\n +tree.Shorthand = function Shorthand(a, b) {\n + this.a = a;\n + this.b = b;\n +};\n +\n +tree.Shorthand.prototype = {\n + toCSS: function (env) {\n + return this.a.toCSS(env) + "/" + this.b.toCSS(env);\n + },\n + eval: function () { return this }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Ruleset = function Ruleset(selectors, rules) {\n + this.selectors = selectors;\n + this.rules = rules;\n + this._lookups = {};\n +};\n +tree.Ruleset.prototype = {\n + eval: function () { return this },\n + evalRules: function (context) {\n + var rules = [];\n +\n + this.rules.forEach(function (rule) {\n + if (rule.evalRules) {\n + rules.push(rule.evalRules(context));\n + } else if (rule instanceof tree.mixin.Call) {\n + Array.prototype.push.apply(rules, rule.eval(context));\n + } else {\n + rules.push(rule.eval(context));\n + }\n + });\n + this.rules = rules;\n + return this;\n + },\n + match: function (args) {\n + return !args || args.length === 0;\n + },\n + variable: function (name) {\n + if (this._variables) { return this._variables[name] }\n + else {\n + return (this._variables = this.rules.reduce(function (hash, r) {\n + if (r instanceof tree.Rule && r.variable === true) {\n + hash[r.name] = r;\n + }\n + return hash;\n + }, {}))[name];\n + }\n + },\n + rulesets: function () {\n + if (this._rulesets) { return this._rulesets }\n + else {\n + return this._rulesets = this.rules.filter(function (r) {\n + if (r instanceof tree.Ruleset || r instanceof tree.mixin.Definition) { return r }\n + });\n + }\n + },\n + find: function (selector, self) {\n + self = self || this;\n + var rules = [], rule, match,\n + key = selector.toCSS();\n +\n + if (key in this._lookups) { return this._lookups[key] }\n +\n + this.rulesets().forEach(function (rule) {\n + if (rule !== self) {\n + for (var j = 0; j < rule.selectors.length; j++) {\n + if (match = selector.match(rule.selectors[j])) {\n + if (selector.elements.length > 1) {\n + Array.prototype.push.apply(rules, rule.find(\n + new(tree.Selector)(selector.elements.slice(1)), self));\n + } else {\n + rules.push(rule);\n + }\n + break;\n + }\n + }\n + }\n + });\n + return this._lookups[key] = rules;\n + },\n + //\n + // Entry point for code generation\n + //\n + // `context` holds an array of arrays.\n + //\n + toCSS: function (context, env) {\n + var css = [], // The CSS output\n + rules = [], // node.Rule instances\n + rulesets = [], // node.Ruleset instances\n + paths = [], // Current selectors\n + selector, // The fully rendered selector\n + rule;\n +\n + if (! this.root) {\n + if (context.length === 0) {\n + paths = this.selectors.map(function (s) { return [s] });\n + } else {\n + for (var s = 0; s < this.selectors.length; s++) {\n + for (var c = 0; c < context.length; c++) {\n + paths.push(context[c].concat([this.selectors[s]]));\n + }\n + }\n + }\n + } else {\n + context = [], env = { frames: [] }\n + for (var i = 0; i < this.rules.length; i++) {\n + if (this.rules[i] instanceof tree.Import) {\n + Array.prototype.splice\n + .apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));\n + }\n + }\n + }\n +\n + // push the current ruleset to the frames stack\n + env.frames.unshift(this);\n +\n + // Evaluate mixins\n + for (var i = 0; i < this.rules.length; i++) {\n + if (this.rules[i] instanceof tree.mixin.Call) {\n + Array.prototype.splice\n + .apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));\n + }\n + }\n +\n + // Evaluate rules and rulesets\n + for (var i = 0; i < this.rules.length; i++) {\n + rule = this.rules[i];\n +\n + if (rule instanceof tree.Directive) {\n + rulesets.push(rule.eval(env).toCSS(paths, env));\n + } else if (rule.rules) {\n + rulesets.push(rule.toCSS(paths, env));\n + } else if (rule instanceof tree.Comment) {\n + if (this.root) {\n + rulesets.push(rule.toCSS());\n + } else {\n + rules.push(rule.toCSS());\n + }\n + } else {\n + if (rule.toCSS && !rule.variable) {\n + rules.push(rule.eval(env).toCSS());\n + } else if (rule.value && !rule.variable) {\n + rules.push(rule.value.toString());\n + }\n + }\n + } \n +\n + rulesets = rulesets.join(\'\');\n +\n + // If this is the root node, we don\'t render\n + // a selector, or {}.\n + // Otherwise, only output if this ruleset has rules.\n + if (this.root) {\n + css.push(rules.join(\'\\n\'));\n + } else {\n + if (rules.length > 0) {\n + selector = paths.map(function (p) {\n + return p.map(function (s) {\n + return s.toCSS();\n + }).join(\'\').trim();\n + }).join(paths.length > 3 ? \',\\n\' : \', \');\n + css.push(selector, " {\\n " + rules.join(\'\\n \') + "\\n}\\n");\n + }\n + }\n + css.push(rulesets);\n +\n + // Pop the stack\n + env.frames.shift();\n +\n + return css.join(\'\');\n + }\n +};\n +\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Selector = function Selector(elements) {\n + this.elements = elements;\n + if (this.elements[0].combinator.value === "") {\n + this.elements[0].combinator.value = \' \';\n + }\n +};\n +tree.Selector.prototype.match = function (other) {\n + if (this.elements[0].value === other.elements[0].value) {\n + return true;\n + } else {\n + return false;\n + }\n +};\n +tree.Selector.prototype.toCSS = function () {\n + if (this._css) { return this._css }\n +\n + return this._css = this.elements.map(function (e) {\n + if (typeof(e) === \'string\') {\n + return \' \' + e.trim();\n + } else {\n + return e.toCSS();\n + }\n + }).join(\'\');\n +};\n +\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.URL = function URL(val) {\n + this.value = val;\n +};\n +tree.URL.prototype = {\n + toCSS: function () {\n + return "url(" + this.value.toCSS() + ")";\n + },\n + eval: function () { return this }\n +};\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.Variable = function Variable(name, index) { this.name = name, this.index = index };\n +tree.Variable.prototype = {\n + eval: function (env) {\n + var variable, v, name = this.name;\n +\n + if (variable = tree.find(env.frames, function (frame) {\n + if (v = frame.variable(name)) {\n + return v.value.eval(env);\n + }\n + })) { return variable }\n + else {\n + throw { message: "variable " + this.name + " is undefined",\n + index: this.index };\n + }\n + }\n +};\n +\n +if (typeof(require) !== \'undefined\' && typeof(__LESS_DIST__) === \'undefined\') { var tree = require(\'less/tree\') }\n +\n +tree.find = function (obj, fun) {\n + for (var i = 0, r; i < obj.length; i++) {\n + if (r = fun.call(obj, obj[i])) { return r }\n + }\n + return null;\n +};\n +(function () {\n +//\n +// Select all links with the \'rel\' attribute set to "less"\n +//\n +var sheets = [];\n +\n +less.env = location.hostname == \'127.0.0.1\' ||\n + location.hostname == \'0.0.0.0\' ||\n + location.hostname == \'localhost\' ||\n + location.protocol == \'file:\' ? \'development\'\n + : \'production\';\n +\n +\n +// Load the stylesheets when the body is ready\n +var readyTimer = setInterval(function () {\n + if (document.body) {\n + if (!document.querySelectorAll && typeof(jQuery) === "undefined") {\n + log("No selector method found");\n + } else {\n + sheets = (document.querySelectorAll || jQuery).call(document, \'link[rel="stylesheet/less"]\');\n + }\n + clearInterval(readyTimer);\n +\n + loadStyleSheets(function (root, sheet, env) {\n + createCSS(root.toCSS(), sheet, env.lastModified);\n +\n + if (env.local) {\n + log("less: loading " + sheet.href + " from local storage.");\n + } else {\n + log("less: parsed " + sheet.href + " successfully.");\n + }\n + });\n + }\n +}, 10);\n +\n +//\n +// Auto-refresh\n +//\n +if (less.env === \'development\') {\n + refreshTimer = setInterval(function () {\n + if (/!refresh/.test(location.hash)) {\n + loadStyleSheets(function (root, sheet, lastModified) {\n + createCSS(root.toCSS(), sheet, lastModified);\n + });\n + }\n + }, 1000);\n +}\n +\n +function loadStyleSheets(callback) {\n + for (var i = 0; i < sheets.length; i++) {\n + loadStyleSheet(sheets[i], callback);\n + }\n +}\n +\n +function loadStyleSheet(sheet, callback) {\n + var css = typeof(localStorage) !== "undefined" && localStorage.getItem(sheet.href);\n + var styles = css && JSON.parse(css);\n +\n + xhr(sheet.href, function (data, lastModified) {\n + if (styles && (new(Date)(lastModified).valueOf() ===\n + new(Date)(styles.timestamp).valueOf())) {\n + // Use local copy\n + createCSS(styles.css, sheet);\n + callback(null, sheet, { local: true });\n + } else {\n + // Use remote copy (re-parse)\n + new(less.Parser)({ optimization: 3 }).parse(data, function (e, root) {\n + if (e) { return error(e, sheet.href) }\n + try {\n + callback(root, sheet, { local: false, lastModified: lastModified });\n + } catch (e) {\n + error(e, sheet.href);\n + }\n + });\n + }\n + }, function (status) {\n + throw new(Error)("Couldn\'t load " + sheet.href + " (" + status + ")");\n + });\n +}\n +\n +function createCSS(styles, sheet, lastModified) {\n + var css = document.createElement(\'style\');\n + css.type = \'text/css\';\n + css.media = \'screen\';\n + css.title = \'less-sheet\';\n +\n + if (sheet) {\n + css.title = sheet.title || sheet.href.match(/(?:^|\\/)([-\\w]+)\\.[a-z]+$/i)[1];\n +\n + // Don\'t update the local store if the file wasn\'t modified\n + if (lastModified && typeof(localStorage) !== "undefined") {\n + localStorage.setItem(sheet.href, JSON.stringify({ timestamp: lastModified, css: styles }));\n + }\n + }\n +\n + if (css.styleSheet) {\n + css.styleSheet.cssText = styles;\n + } else {\n + css.appendChild(document.createTextNode(styles));\n + }\n + document.getElementsByTagName(\'head\')[0].appendChild(css);\n +}\n +\n +function xhr(url, callback, errback) {\n + var xhr = getXMLHttpRequest();\n +\n + if (window.location.protocol === "file:") {\n + xhr.open(\'GET\', url, false);\n + xhr.send(null);\n + if (xhr.status === 0) {\n + callback(xhr.responseText);\n + } else {\n + errback(xhr.status);\n + }\n + } else {\n + xhr.open(\'GET\', url, true);\n + xhr.onreadystatechange = function () {\n + if (xhr.readyState == 4) {\n + if (xhr.status >= 200 && xhr.status < 300) {\n + callback(xhr.responseText,\n + xhr.getResponseHeader("Last-Modified"));\n + } else if (typeof(errback) === \'function\') {\n + errback(xhr.status);\n + }\n + }\n + };\n + xhr.send(null);\n + }\n +}\n +\n +function getXMLHttpRequest() {\n + if (window.XMLHttpRequest) {\n + return new(XMLHttpRequest);\n + } else {\n + try {\n + return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");\n + } catch (e) {\n + log("less: browser doesn\'t support AJAX.");\n + return null;\n + }\n + }\n +}\n +\n +function log(str) {\n + if (less.env == \'development\' && typeof(console) !== "undefined") { console.log(str) }\n +}\n +\n +function error(e, href) {\n + var template = [\'<div>\',\n + \'<pre class="ctx"><span>[-1]</span>{0}</pre>\',\n + \'<pre><span>[0]</span>{current}</pre>\',\n + \'<pre class="ctx"><span>[1]</span>{2}</pre>\',\n + \'</div>\'].join(\'\\n\');\n +\n + var elem = document.createElement(\'div\'), timer;\n + elem.id = "less-error-message";\n + elem.innerHTML = \'<h3>\' + (e.message || \'There is an error in your .less file\') + \'</h3>\' +\n + \'<p><a href="\' + href + \'">\' + href + "</a> " +\n + \'on line \' + e.line + \', column \' + (e.column + 1) + \':</p>\' +\n + template.replace(/\\[(-?\\d)\\]/g, function (_, i) {\n + return e.line + parseInt(i);\n + }).replace(/\\{(\\d)\\}/g, function (_, i) {\n + return e.extract[parseInt(i)];\n + }).replace(/\\{current\\}/, e.extract[1].slice(0, e.column) +\n + \'<span class="error">\' +\n + e.extract[1].slice(e.column) +\n + \'</span>\');\n + // CSS for error messages\n + createCSS([\n + \'#less-error-message span {\',\n + \'margin-right: 15px;\',\n + \'}\',\n + \'#less-error-message pre {\',\n + \'color: #ee4444;\',\n + \'padding: 4px 0;\',\n + \'margin: 0;\',\n + \'}\',\n + \'#less-error-message pre.ctx {\',\n + \'color: #dd7777;\',\n + \'}\',\n + \'#less-error-message h3 {\',\n + \'padding: 15px 0 5px 0;\',\n + \'margin: 0;\',\n + \'}\',\n + \'#less-error-message a {\',\n + \'color: #10a\',\n + \'}\',\n + \'#less-error-message .error {\',\n + \'color: red;\',\n + \'font-weight: bold;\',\n + \'padding-bottom: 2px;\',\n + \'border-bottom: 1px dashed red;\',\n + \'}\'\n + ].join(\'\'));\n +\n + elem.style.cssText = [\n + "font-family: Arial, sans-serif",\n + "border: 1px solid #e00",\n + "background-color: #eee",\n + "border-radius: 5px",\n + "color: #e00",\n + "padding: 15px",\n + "margin-bottom: 15px"\n + ].join(\';\');\n +\n + if (less.env == \'development\') {\n + timer = setInterval(function () {\n + if (document.body) {\n + document.body.insertBefore(elem, document.body.childNodes[0]);\n + clearInterval(timer);\n + }\n + }, 10);\n + }\n +}\n +\n +less.Parser.importer = function (path, paths, callback) {\n + loadStyleSheet({ href: path, title: path }, function (root) {\n + callback(root);\n + });\n +};\n +\n +})();\n +\n +// --- End less.js ---\n +\n +});\n +;bespin.tiki.register("::theme_manager_base", {\n + name: "theme_manager_base",\n + dependencies: { }\n +});\n +bespin.tiki.module("theme_manager_base:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "Defines extension points required for theming",\n + "dependencies": { },\n + "environments": { "main": true },\n + "share": true,\n + "provides": [\n + {\n + "ep": "extensionpoint",\n + "name": "themestyles",\n + "description": "(Less)files holding the CSS style information for the UI.",\n +\n + "params": [\n + {\n + "name": "url",\n + "required": true,\n + "description": "Name of the ThemeStylesFile - can also be an array of files."\n + }\n + ]\n + },\n + {\n + "ep": "extensionpoint",\n + "name": "themeChange",\n + "description": "Event: Notify when the theme(styles) changed.",\n +\n + "params": [\n + {\n + "name": "pointer",\n + "required": true,\n + "description": "Function that is called whenever the theme is changed."\n + }\n + ]\n +\n + },\n + {\n + "ep": "extensionpoint",\n + "name": "theme",\n + "indexOn": "name",\n + "description": "A theme is a way change the look of the application.",\n +\n + "params": [\n + {\n + "name": "url",\n + "required": false,\n + "description": "Name of a ThemeStylesFile that holds theme specific CSS rules - can also be an array of files."\n + },\n + {\n + "name": "pointer",\n + "required": true,\n + "description": "Function that returns the ThemeData"\n + }\n + ]\n + }\n + ]\n +})\n +"end";\n +\n +});\n +;bespin.tiki.register("::keyboard", {\n + name: "keyboard",\n + dependencies: { "canon": "0.0.0", "settings": "0.0.0" }\n +});\n +bespin.tiki.module("keyboard:keyboard",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var catalog = require(\'bespin:plugins\').catalog;\n +var console = require(\'bespin:console\').console;\n +var Trace = require(\'bespin:util/stacktrace\').Trace;\n +var util = require(\'bespin:util/util\');\n +\n +var settings = require(\'settings\').settings;\n +\n +var keyutil = require(\'keyboard:keyutil\');\n +var history = require(\'canon:history\');\n +var Request = require(\'canon:request\').Request;\n +var env = require(\'environment\').env;\n +\n +/*\n + * Things to do to sanitize this code:\n + * - \'no command\' is a bizarre special value at the very least it should be a\n + * constant to make typos more obvious, but it would be better to refactor\n + * so that a natural value like null worked.\n + * - sender seems to be totally customized to the editor case, and the functions\n + * that we assume that it has make no sense for the commandLine case. We\n + * should either document and implement the same function set for both cases\n + * or admit that the cases are different enough to have separate\n + * implementations.\n + * - remove remaining sproutcore-isms\n + * - fold buildFlags into processKeyEvent or something better, preferably the\n + * latter. We don\'t want the environment to become a singleton\n + */\n +\n +/**\n + * Every time we call processKeyEvent, we pass in some flags that require the\n + * same processing to set them up. This function can be called to do that\n + * setup.\n + * @param env Probably environment.env\n + * @param flags Probably {} (but check other places where this is called)\n + */\n +exports.buildFlags = function(flags) {\n + flags.context = env.contexts[0];\n + return flags;\n +};\n +\n +/**\n + * The canon, or the repository of commands, contains functions to process\n + * events and dispatch command messages to targets.\n + * @class\n + */\n +var KeyboardManager = function() { };\n +\n +util.mixin(KeyboardManager.prototype, {\n + _customKeymappingCache: { states: {} },\n +\n + /**\n + * Searches through the command canon for an event matching the given flags\n + * with a key equivalent matching the given SproutCore event, and, if the\n + * command is found, sends a message to the appropriate target.\n + *\n + * This will get a couple of upgrades in the not-too-distant future:\n + * 1. caching in the Canon for fast lookup based on key\n + * 2. there will be an extra layer in between to allow remapping via\n + * user preferences and keyboard mapping plugins\n + *\n + * @return True if a matching command was found, false otherwise.\n + */\n + processKeyEvent: function(evt, sender, flags) {\n + // Use our modified commandCodes function to detect the meta key in\n + // more circumstances than SproutCore alone does.\n + var symbolicName = keyutil.commandCodes(evt, true)[0];\n + if (util.none(symbolicName)) {\n + return false;\n + }\n +\n + // TODO: Maybe it should be the job of our caller to do this?\n + exports.buildFlags(flags);\n +\n + flags.isCommandKey = true;\n + return this._matchCommand(symbolicName, sender, flags);\n + },\n +\n + _matchCommand: function(symbolicName, sender, flags) {\n + var match = this._findCommandExtension(symbolicName, sender, flags);\n + if (match && match.commandExt !== \'no command\') {\n + if (flags.isTextView) {\n + sender.resetKeyBuffers();\n + }\n +\n + var commandExt = match.commandExt;\n + commandExt.load(function(command) {\n + var request = new Request({\n + command: command,\n + commandExt: commandExt\n + });\n + history.execute(match.args, request);\n + });\n + return true;\n + }\n +\n + // \'no command\' is returned if a keyevent is handled but there is no\n + // command executed (for example when switchting the keyboard state).\n + if (match && match.commandExt === \'no command\') {\n + return true;\n + } else {\n + return false;\n + }\n + },\n +\n + _buildBindingsRegex: function(bindings) {\n + // Escape a given Regex string.\n + bindings.forEach(function(binding) {\n + if (!util.none(binding.key)) {\n + binding.key = new RegExp(\'^\' + binding.key + \'$\');\n + } else if (Array.isArray(binding.regex)) {\n + binding.key = new RegExp(\'^\' + binding.regex[1] + \'$\');\n + binding.regex = new RegExp(binding.regex.join(\'\') + \'$\');\n + } else {\n + binding.regex = new RegExp(binding.regex + \'$\');\n + }\n + });\n + },\n +\n + /**\n + * Build the RegExp from the keymapping as RegExp can\'t stored directly\n + * in the metadata JSON and as the RegExp used to match the keys/buffer\n + * need to be adapted.\n + */\n + _buildKeymappingRegex: function(keymapping) {\n + for (state in keymapping.states) {\n + this._buildBindingsRegex(keymapping.states[state]);\n + }\n + keymapping._convertedRegExp = true;\n + },\n +\n + /**\n + * Loop through the commands in the canon, looking for something that\n + * matches according to #_commandMatches, and return that.\n + */\n + _findCommandExtension: function(symbolicName, sender, flags) {\n + // If the flags indicate that we handle the textView\'s input then take\n + // a look at keymappings as well.\n + if (flags.isTextView) {\n + var currentState = sender._keyState;\n +\n + // Don\'t add the symbolic name to the key buffer if the alt_ key is\n + // part of the symbolic name. If it starts with alt_, this means\n + // that the user hit an alt keycombo and there will be a single,\n + // new character detected after this event, which then will be\n + // added to the buffer (e.g. alt_j will result in ∆).\n + if (!flags.isCommandKey || symbolicName.indexOf(\'alt_\') === -1) {\n + sender._keyBuffer +=\n + symbolicName.replace(/ctrl_meta|meta/,\'ctrl\');\n + sender._keyMetaBuffer += symbolicName;\n + }\n +\n + // List of all the keymappings to look at.\n + var ak = [ this._customKeymappingCache ];\n +\n + // Get keymapping extension points.\n + ak = ak.concat(catalog.getExtensions(\'keymapping\'));\n +\n + for (var i = 0; i < ak.length; i++) {\n + // Check if the keymapping has the current state.\n + if (util.none(ak[i].states[currentState])) {\n + continue;\n + }\n +\n + if (util.none(ak[i]._convertedRegExp)) {\n + this._buildKeymappingRegex(ak[i]);\n + }\n +\n + // Try to match the current mapping.\n + var result = this._bindingsMatch(\n + symbolicName,\n + flags,\n + sender,\n + ak[i]);\n +\n + if (!util.none(result)) {\n + return result;\n + }\n + }\n + }\n +\n + var commandExts = catalog.getExtensions(\'command\');\n + var reply = null;\n + var args = {};\n +\n + symbolicName = symbolicName.replace(/ctrl_meta|meta/,\'ctrl\');\n +\n + commandExts.some(function(commandExt) {\n + if (this._commandMatches(commandExt, symbolicName, flags)) {\n + reply = commandExt;\n + return true;\n + }\n + return false;\n + }.bind(this));\n +\n + return util.none(reply) ? null : { commandExt: reply, args: args };\n + },\n +\n +\n + /**\n + * Checks if the given parameters fit to one binding in the given bindings.\n + * Returns the command and arguments if a command was matched.\n + */\n + _bindingsMatch: function(symbolicName, flags, sender, keymapping) {\n + var match;\n + var commandExt = null;\n + var args = {};\n + var bufferToUse;\n +\n + if (!util.none(keymapping.hasMetaKey)) {\n + bufferToUse = sender._keyBuffer;\n + } else {\n + bufferToUse = sender._keyMetaBuffer;\n + }\n +\n + // Add the alt_key to the buffer as we don\'t want it to be in the buffer\n + // that is saved but for matching, it needs to be there.\n + if (symbolicName.indexOf(\'alt_\') === 0 && flags.isCommandKey) {\n + bufferToUse += symbolicName;\n + }\n +\n + // Loop over all the bindings of the keymapp until a match is found.\n + keymapping.states[sender._keyState].some(function(binding) {\n + // Check if the key matches.\n + if (binding.key && !binding.key.test(symbolicName)) {\n + return false;\n + }\n +\n + // Check if the regex matches.\n + if (binding.regex && !(match = binding.regex.exec(bufferToUse))) {\n + return false;\n + }\n +\n + // Check for disallowed matches.\n + if (binding.disallowMatches) {\n + for (var i = 0; i < binding.disallowMatches.length; i++) {\n + if (!!match[binding.disallowMatches[i]]) {\n + return true;\n + }\n + }\n + }\n +\n + // Check predicates.\n + if (!exports.flagsMatch(binding.predicates, flags)) {\n + return false;\n + }\n +\n + // If there is a command to execute, then figure out the\n + // comand and the arguments.\n + if (binding.exec) {\n + // Get the command.\n + commandExt = catalog.getExtensionByKey(\'command\', binding.exec);\n + if (util.none(commandExt)) {\n + throw new Error(\'Can\\\'t find command \' + binding.exec +\n + \' in state=\' + sender._keyState +\n + \', symbolicName=\' + symbolicName);\n + }\n +\n + // Bulid the arguments.\n + if (binding.params) {\n + var value;\n + binding.params.forEach(function(param) {\n + if (!util.none(param.match) && !util.none(match)) {\n + value = match[param.match] || param.defaultValue;\n + } else {\n + value = param.defaultValue;\n + }\n +\n + if (param.type === \'number\') {\n + value = parseInt(value);\n + }\n +\n + args[param.name] = value;\n + });\n + }\n + sender.resetKeyBuffers();\n + }\n +\n + // Handle the \'then\' property.\n + if (binding.then) {\n + sender._keyState = binding.then;\n + sender.resetKeyBuffers();\n + }\n +\n + // If there is no command matched now, then return a \'false\'\n + // command to stop matching.\n + if (util.none(commandExt)) {\n + commandExt = \'no command\';\n + }\n +\n + return true;\n + });\n +\n + if (util.none(commandExt)) {\n + return null;\n + }\n +\n + return { commandExt: commandExt, args: args };\n + },\n +\n + /**\n + * Check that the given command fits the given key name and flags.\n + */\n + _commandMatches: function(commandExt, symbolicName, flags) {\n + var mappedKeys = commandExt.key;\n + if (!mappedKeys) {\n + return false;\n + }\n +\n + // Check predicates\n + if (!exports.flagsMatch(commandExt.predicates, flags)) {\n + return false;\n + }\n +\n + if (typeof(mappedKeys) === \'string\') {\n + if (mappedKeys != symbolicName) {\n + return false;\n + }\n + return true;\n + }\n +\n + if (!Array.isArray(mappedKeys)) {\n + mappedKeys = [mappedKeys];\n + commandExt.key = mappedKeys;\n + }\n +\n + for (var i = 0; i < mappedKeys.length; i++) {\n + var keymap = mappedKeys[i];\n + if (typeof(keymap) === \'string\') {\n + if (keymap == symbolicName) {\n + return true;\n + }\n + continue;\n + }\n +\n + if (keymap.key != symbolicName) {\n + continue;\n + }\n +\n + return exports.flagsMatch(keymap.predicates, flags);\n + }\n + return false;\n + },\n +\n + /**\n + * Build a cache of custom keymappings whenever the associated setting\n + * changes.\n + */\n + _customKeymappingChanged: function() {\n + var ckc = this._customKeymappingCache =\n + JSON.parse(settings.get(\'customKeymapping\'));\n +\n + ckc.states = ckc.states || {};\n +\n + for (state in ckc.states) {\n + this._buildBindingsRegex(ckc.states[state]);\n + }\n + ckc._convertedRegExp = true;\n + }\n +});\n +\n +/**\n + *\n + */\n +exports.flagsMatch = function(predicates, flags) {\n + if (util.none(predicates)) {\n + return true;\n + }\n +\n + if (!flags) {\n + return false;\n + }\n +\n + for (var flagName in predicates) {\n + if (flags[flagName] !== predicates[flagName]) {\n + return false;\n + }\n + }\n +\n + return true;\n +};\n +\n +/**\n + * The global exported KeyboardManager\n + */\n +exports.keyboardManager = new KeyboardManager();\n +\n +catalog.registerExtension(\'settingChange\', {\n + match: "customKeymapping",\n + pointer: exports.keyboardManager._customKeymappingChanged\n + .bind(exports.keyboardManager)\n +});\n +\n +});\n +\n +bespin.tiki.module("keyboard:keyutil",function(require,exports,module) {\n +/*! @license\n +==========================================================================\n +SproutCore -- JavaScript Application Framework\n +copyright 2006-2009, Sprout Systems Inc., Apple Inc. and contributors.\n +\n +Permission is hereby granted, free of charge, to any person obtaining a\n +copy of this software and associated documentation files (the "Software"),\n +to deal in the Software without restriction, including without limitation\n +the rights to use, copy, modify, merge, publish, distribute, sublicense,\n +and/or sell copies of the Software, and to permit persons to whom the\n +Software is furnished to do so, subject to the following conditions:\n +\n +The above copyright notice and this permission notice shall be included in\n +all copies or substantial portions of the Software.\n +\n +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n +DEALINGS IN THE SOFTWARE.\n +\n +SproutCore and the SproutCore logo are trademarks of Sprout Systems, Inc.\n +\n +For more information about SproutCore, visit http://www.sproutcore.com\n +\n +\n +==========================================================================\n +@license */\n +\n +// Most of the following code is taken from SproutCore with a few changes.\n +\n +var util = require(\'bespin:util/util\');\n +\n +/**\n + * Helper functions and hashes for key handling.\n + */\n +exports.KeyHelper = function() {\n + var ret = {\n + MODIFIER_KEYS: {\n + 16: \'shift\', 17: \'ctrl\', 18: \'alt\', 224: \'meta\'\n + },\n +\n + FUNCTION_KEYS : {\n + 8: \'backspace\', 9: \'tab\', 13: \'return\', 19: \'pause\',\n + 27: \'escape\', 33: \'pageup\', 34: \'pagedown\', 35: \'end\',\n + 36: \'home\', 37: \'left\', 38: \'up\', 39: \'right\',\n + 40: \'down\', 44: \'printscreen\', 45: \'insert\', 46: \'delete\',\n + 112: \'f1\', 113: \'f2\', 114: \'f3\', 115: \'f4\',\n + 116: \'f5\', 117: \'f7\', 119: \'f8\', 120: \'f9\',\n + 121: \'f10\', 122: \'f11\', 123: \'f12\', 144: \'numlock\',\n + 145: \'scrolllock\'\n + },\n +\n + PRINTABLE_KEYS: {\n + 32: \' \', 48: \'0\', 49: \'1\', 50: \'2\', 51: \'3\', 52: \'4\', 53: \'5\',\n + 54: \'6\', 55: \'7\', 56: \'8\', 57: \'9\', 59: \';\', 61: \'=\', 65: \'a\',\n + 66: \'b\', 67: \'c\', 68: \'d\', 69: \'e\', 70: \'f\', 71: \'g\', 72: \'h\',\n + 73: \'i\', 74: \'j\', 75: \'k\', 76: \'l\', 77: \'m\', 78: \'n\', 79: \'o\',\n + 80: \'p\', 81: \'q\', 82: \'r\', 83: \'s\', 84: \'t\', 85: \'u\', 86: \'v\',\n + 87: \'w\', 88: \'x\', 89: \'y\', 90: \'z\', 107: \'+\', 109: \'-\', 110: \'.\',\n + 188: \',\', 190: \'.\', 191: \'/\', 192: \'`\', 219: \'[\', 220: \'\\\\\',\n + 221: \']\', 222: \'\\"\'\n + },\n +\n + /**\n + * Create the lookup table for Firefox to convert charCodes to keyCodes\n + * in the keyPress event.\n + */\n + PRINTABLE_KEYS_CHARCODE: {},\n +\n + /**\n + * Allow us to lookup keyCodes by symbolic name rather than number\n + */\n + KEY: {}\n + };\n +\n + // Create the PRINTABLE_KEYS_CHARCODE hash.\n + for (var i in ret.PRINTABLE_KEYS) {\n + var k = ret.PRINTABLE_KEYS[i];\n + ret.PRINTABLE_KEYS_CHARCODE[k.charCodeAt(0)] = i;\n + if (k.toUpperCase() != k) {\n + ret.PRINTABLE_KEYS_CHARCODE[k.toUpperCase().charCodeAt(0)] = i;\n + }\n + }\n +\n + // A reverse map of FUNCTION_KEYS\n + for (i in ret.FUNCTION_KEYS) {\n + var name = ret.FUNCTION_KEYS[i].toUpperCase();\n + ret.KEY[name] = parseInt(i, 10);\n + }\n +\n + return ret;\n +}();\n +\n +/**\n + * Determines if the keyDown event is a non-printable or function key.\n + * These kinds of events are processed as keyboard shortcuts.\n + * If no shortcut handles the event, then it will be sent as a regular\n + * keyDown event.\n + * @private\n + */\n +var isFunctionOrNonPrintableKey = function(evt) {\n + return !!(evt.altKey || evt.ctrlKey || evt.metaKey ||\n + ((evt.charCode !== evt.which) &&\n + exports.KeyHelper.FUNCTION_KEYS[evt.which]));\n +};\n +\n +/**\n + * Returns character codes for the event.\n + * The first value is the normalized code string, with any Shift or Ctrl\n + * characters added to the beginning.\n + * The second value is the char string by itself.\n + * @return {Array}\n + */\n +exports.commandCodes = function(evt, dontIgnoreMeta) {\n + var code = evt._keyCode || evt.keyCode;\n + var charCode = (evt._charCode === undefined ? evt.charCode : evt._charCode);\n + var ret = null;\n + var key = null;\n + var modifiers = \'\';\n + var lowercase;\n + var allowShift = true;\n +\n + // Absent a value for \'keyCode\' or \'which\', we can\'t compute the\n + // command codes. Bail out.\n + if (code === 0 && evt.which === 0) {\n + return false;\n + }\n +\n + // If the charCode is not zero, then we do not handle a command key\n + // here. Bail out.\n + if (charCode !== 0) {\n + return false;\n + }\n +\n + // Check for modifier keys.\n + if (exports.KeyHelper.MODIFIER_KEYS[charCode]) {\n + return [exports.KeyHelper.MODIFIER_KEYS[charCode], null];\n + }\n +\n + // handle function keys.\n + if (code) {\n + ret = exports.KeyHelper.FUNCTION_KEYS[code];\n + if (!ret && (evt.altKey || evt.ctrlKey || evt.metaKey)) {\n + ret = exports.KeyHelper.PRINTABLE_KEYS[code];\n + // Don\'t handle the shift key if the combo is\n + // (meta_|ctrl_)<number>\n + // This is necessary for the French keyboard. On that keyboard,\n + // you have to hold down the shift key to access the number\n + // characters.\n + if (code > 47 && code < 58) {\n + allowShift = evt.altKey;\n + }\n + }\n +\n + if (ret) {\n + if (evt.altKey) {\n + modifiers += \'alt_\';\n + }\n + if (evt.ctrlKey) {\n + modifiers += \'ctrl_\';\n + }\n + if (evt.metaKey) {\n + modifiers += \'meta_\';\n + }\n + } else if (evt.ctrlKey || evt.metaKey) {\n + return false;\n + }\n + }\n +\n + // otherwise just go get the right key.\n + if (!ret) {\n + code = evt.which;\n + key = ret = String.fromCharCode(code);\n + lowercase = ret.toLowerCase();\n +\n + if (evt.metaKey) {\n + modifiers = \'meta_\';\n + ret = lowercase;\n +\n + } else ret = null;\n + }\n +\n + if (evt.shiftKey && ret && allowShift) {\n + modifiers += \'shift_\';\n + }\n +\n + if (ret) {\n + ret = modifiers + ret;\n + }\n +\n + if (!dontIgnoreMeta && ret) {\n + ret = ret.replace(/ctrl_meta|meta/,\'ctrl\');\n + }\n +\n + return [ret, key];\n +};\n +\n +// Note: Most of the following code is taken from SproutCore with a few changes.\n +\n +/**\n + * Firefox sends a few key events twice: the first time to the keydown event\n + * and then later again to the keypress event. To handle them correct, they\n + * should be processed only once. Due to this, we will skip these events\n + * in keydown and handle them then in keypress.\n + */\n +exports.addKeyDownListener = function(element, boundFunction) {\n +\n + var handleBoundFunction = function(ev) {\n + var handled = boundFunction(ev);\n + // If the boundFunction returned true, then stop the event.\n + if (handled) {\n + util.stopEvent(ev);\n + }\n + return handled;\n + };\n +\n + element.addEventListener(\'keydown\', function(ev) {\n + if (util.isMozilla) {\n + // Check for function keys (like DELETE, TAB, LEFT, RIGHT...)\n + if (exports.KeyHelper.FUNCTION_KEYS[ev.keyCode]) {\n + return true;\n + // Check for command keys (like ctrl_c, ctrl_z...)\n + } else if ((ev.ctrlKey || ev.metaKey) &&\n + exports.KeyHelper.PRINTABLE_KEYS[ev.keyCode]) {\n + return true;\n + }\n + }\n +\n + if (isFunctionOrNonPrintableKey(ev)) {\n + return handleBoundFunction(ev);\n + }\n +\n + return true;\n + }, false);\n +\n + element.addEventListener(\'keypress\', function(ev) {\n + if (util.isMozilla) {\n + // If this is a function key, we have to use the keyCode.\n + if (exports.KeyHelper.FUNCTION_KEYS[ev.keyCode]) {\n + return handleBoundFunction(ev);\n + } else if ((ev.ctrlKey || ev.metaKey) &&\n + exports.KeyHelper.PRINTABLE_KEYS_CHARCODE[ev.charCode]){\n + // Check for command keys (like ctrl_c, ctrl_z...).\n + // For command keys have to convert the charCode to a keyCode\n + // as it has been sent from the keydown event to be in line\n + // with the other browsers implementations.\n +\n + // FF does not allow let you change the keyCode or charCode\n + // property. Store to a custom keyCode/charCode variable.\n + // The getCommandCodes() function takes care of these\n + // special variables.\n + ev._keyCode = exports.KeyHelper.PRINTABLE_KEYS_CHARCODE[ev.charCode];\n + ev._charCode = 0;\n + return handleBoundFunction(ev);\n + }\n + }\n +\n + // normal processing: send keyDown for printable keys.\n + if (ev.charCode !== undefined && ev.charCode === 0) {\n + return true;\n + }\n +\n + return handleBoundFunction(ev);\n + }, false);\n +};\n +\n +});\n +\n +bespin.tiki.module("keyboard:index",function(require,exports,module) {\n +\n +});\n +;bespin.tiki.register("::edit_session", {\n + name: "edit_session",\n + dependencies: { "events": "0.0.0" }\n +});\n +bespin.tiki.module("edit_session:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var Promise = require(\'bespin:promise\').Promise;\n +var catalog = require(\'bespin:plugins\').catalog;\n +var util = require(\'bespin:util/util\');\n +\n +var Event = require("events").Event;\n +\n +exports.EditSession = function() { };\n +\n +exports.EditSession.prototype = {\n + /**\n + * @property{TextView}\n + *\n + * The \'current\' view is the editor component that most recently had\n + * the focus.\n + */\n + _currentView: null,\n +\n +\n + /**\n + * @type{string}\n + * The name of the user, or null if no user is logged in.\n + */\n + currentUser: null,\n +\n + /**\n + * The history object to store file history in.\n + */\n + history: null,\n +\n + /**\n + * figures out the full path, taking into account the current file\n + * being edited.\n + */\n + getCompletePath: function(path) {\n + if (path == null) {\n + path = \'\';\n + }\n +\n + if (path == null || path.substring(0, 1) != \'/\') {\n + var buffer;\n + if (this._currentView && this._currentView.buffer) {\n + buffer = this._currentView.buffer;\n + }\n + var file;\n + if (buffer) {\n + file = buffer.file;\n + }\n + if (!file) {\n + path = \'/\' + path;\n + } else {\n + path = file.parentdir() + path;\n + }\n + }\n +\n + return path;\n + }\n +};\n +\n +Object.defineProperties(exports.EditSession.prototype, {\n + currentView: {\n + set: function(newView) {\n + var oldView = this._currentView;\n + if (newView !== oldView) {\n + this._currentView = newView;\n + }\n + },\n + \n + get: function() {\n + return this._currentView;\n + }\n + }\n +});\n +\n +/*\n + * set up a session based on a view. This seems a bit convoluted and is\n + * likely to change.\n + */\n +exports.createSession = function(view, user) {\n + var session = new exports.EditSession();\n + if (view) {\n + session.currentView = view.textView;\n + }\n + if (user) {\n + session.currentUser = user;\n + }\n + return session;\n +};\n +\n +});\n +;bespin.tiki.register("::completion", {\n + name: "completion",\n + dependencies: { "jquery": "0.0.0", "ctags": "0.0.0", "rangeutils": "0.0.0", "canon": "0.0.0", "underscore": "0.0.0" }\n +});\n +bespin.tiki.module("completion:ui",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var $ = require(\'jquery\').$;\n +var _ = require(\'underscore\')._;\n +\n +var ANIMATION_SPEED = 100; // in ms\n +\n +var populate_container_template =\n + _.template(\'<span class="bespin-completion-container"> — \' +\n + \'<%= container %></span>\');\n +var populate_second_row_template =\n + _.template(\'<div class="bespin-completion-second-row"><%= type %></div>\');\n +var populate_item_template =\n + _.template(\'<li><div class="bespin-completion-top-row">\' +\n + \'<span class="bespin-completion-kind bespin-completion-kind-\' +\n + \'<%= kind %>"><%= kind %></span>\' +\n + \'<span class="bespin-completion-ident"><%= ident %></span>\' +\n + \'<%= container %></div><%= second_row %></li>\');\n +\n +function CompletionUI(parent) {\n + var id = _.uniqueId(\'bespin-completion-panel\');\n +\n + var panel = document.createElement("div");\n + panel.id = id;\n + panel.className = "bespin-completion-panel";\n + panel.style.display = \'none\';\n + panel.innerHTML =\n + \'<div class="bespin-completion-pointer"></div>\' +\n + \'<div class="bespin-completion-bubble-outer">\' +\n + \'<div class="bespin-completion-bubble-inner">\' +\n + \'<div class="bespin-completion-highlight"></div>\' +\n + \'<ul></ul>\' +\n + \'</div>\' +\n + \'</div>\';\n +\n + $(parent).append(panel);\n +\n + this.panel = $(panel);\n + this.parent = $(parent);\n +}\n +\n +CompletionUI.prototype = {\n + _fromBottom: false,\n + _index: 0,\n + _tags: null,\n +\n + _getHighlightDimensions: function(elem) {\n + var pos = elem.position();\n + var height = elem.outerHeight() - 2;\n + var width = elem.outerWidth() - 2;\n + return { left: pos.left, top: pos.top, height: height, width: width };\n + },\n +\n + _listItemForIndex: function(idx) {\n + return this.panel.find("li:eq(" + idx + ")");\n + },\n +\n + _populate: function() {\n + var html = _(this._tags).map(function(tag) {\n + var klass = tag[\'class\'], module = tag.module, ns = tag.namespace;\n +\n + var container;\n + if (klass != null) {\n + container = klass;\n + } else if (ns != null) {\n + container = ns;\n + } else {\n + container = "";\n + }\n +\n + if (module != null) {\n + container = module + (container != "" ? "#" + container : "");\n + }\n +\n + var container_html = (container == "") ? "" :\n + populate_container_template({ container: container });\n +\n + var type = tag.type;\n + var second_row_html = (type == null) ? "" :\n + populate_second_row_template({ type: type });\n +\n + return populate_item_template({\n + kind: tag.kind,\n + ident: tag.name,\n + container: container_html,\n + second_row: second_row_html\n + });\n + });\n +\n + this.panel.find("ul").html(html.join("\\n"));\n + },\n +\n + panel: null,\n + visible: false,\n +\n + getCompletion: function() {\n + return this.visible ? this._tags[this._index] : null;\n + },\n +\n + hide: function() {\n + if (!this.visible) {\n + return;\n + }\n +\n + this.panel.fadeOut(ANIMATION_SPEED);\n + this.visible = false;\n + },\n +\n + move: function(dir) {\n + var index = this._index;\n +\n + var sel = this._listItemForIndex(index);\n +\n + var unsel = (dir === \'up\') ? sel.prev() : sel.next();\n + if (unsel.length === 0) {\n + return;\n + }\n +\n + index = (dir === \'up\') ? index - 1 : index + 1;\n + this._index = index;\n +\n + var selFirstRow = $(sel).find(\'.bespin-completion-top-row\');\n + var selSecondRow = $(sel).find(\'.bespin-completion-second-row\');\n + var unselFirstRow = $(unsel).find(\'.bespin-completion-top-row\');\n + var unselSecondRow = $(unsel).find(\'.bespin-completion-second-row\');\n +\n + selSecondRow.hide();\n + unselSecondRow.show();\n +\n + var highlight = this.panel.find(".bespin-completion-highlight");\n + highlight.stop(true, true);\n + var highlightDimensions = this._getHighlightDimensions(unsel);\n + highlight.animate(highlightDimensions, ANIMATION_SPEED);\n + unselSecondRow.hide();\n +\n + if (dir === \'down\') {\n + var height = selSecondRow.height();\n + unselFirstRow.css(\'top\', height);\n + unselFirstRow.animate({ top: 0 }, ANIMATION_SPEED);\n + } else {\n + var height = unselSecondRow.height();\n + selFirstRow.css(\'top\', -height);\n + selFirstRow.animate({ top: 0 }, ANIMATION_SPEED);\n + }\n +\n + unselSecondRow.fadeIn();\n + },\n +\n + show: function(tags, point, lineHeight) {\n + var tags = _(tags).clone();\n + this._tags = tags;\n +\n + this._populate();\n +\n + var visible = this.visible;\n + var panel = this.panel;\n + panel.stop(true, true);\n + if (!visible) {\n + panel.show();\n + }\n +\n + var parentOffset = this.parent.offset();\n + var parentX = parentOffset.left, parentY = parentOffset.top;\n + var absX = parentX + point.x, absY = parentY + point.y;\n +\n + var panelWidth = panel.outerWidth(), panelHeight = panel.outerHeight();\n + var windowWidth = $(window).width(), windowHeight = $(window).height();\n +\n + var fromBottom = absY + panelHeight + lineHeight > windowHeight;\n + this._fromBottom = fromBottom;\n +\n + if (this._index >= tags.length) {\n + this._index = tags.length - 1;\n + }\n +\n + var pointer;\n + if (fromBottom) {\n + pointer = panel.find(\'.bespin-completion-pointer\');\n + pointer.removeClass(\'bespin-completion-pointer-up\');\n + pointer.addClass(\'bespin-completion-pointer-down\');\n + panel.css({ bottom: -point.y, top: "" });\n +\n + // Reverse the list.\n + this._tags.reverse();\n + this._populate();\n +\n + if (!visible) {\n + this._index = tags.length - 1;\n + }\n + } else {\n + pointer = panel.find(\'.bespin-completion-pointer\');\n + pointer.removeClass(\'bespin-completion-pointer-down\');\n + pointer.addClass(\'bespin-completion-pointer-up\');\n + panel.css({ top: point.y + lineHeight, bottom: "" });\n +\n + if (!visible) {\n + this._index = 0;\n + }\n + }\n +\n + if (!visible) {\n + var fromRight = absX + point.x + panelWidth > windowWidth;\n + if (fromRight) {\n + pointer.css({ left: "", right: 32 });\n + panel.css(\'left\', Math.min(windowWidth - panelWidth - parentX,\n + point.x - panelWidth + 43));\n + } else {\n + pointer.css({ left: 32, right: "" });\n + panel.css(\'left\', Math.max(parentX, point.x - 43));\n + }\n +\n + panel.hide().animate({ opacity: \'show\' }, ANIMATION_SPEED);\n + }\n +\n + var highlight = panel.find(".bespin-completion-highlight");\n + highlight.stop(true, true);\n + var sel = this._listItemForIndex(this._index);\n + sel.find(".bespin-completion-second-row").show();\n +\n + var highlightDimensions = this._getHighlightDimensions(sel);\n + var highlightWidth = highlightDimensions.width;\n + var highlightHeight = highlightDimensions.height;\n + highlight.css(highlightDimensions);\n +\n + this.visible = true;\n + }\n +};\n +\n +exports.CompletionUI = CompletionUI;\n +\n +\n +});\n +\n +bespin.tiki.module("completion:controller",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var ctags = require(\'ctags\');\n +var range = require(\'rangeutils:utils/range\');\n +var CompletionUI = require(\'completion:ui\').CompletionUI;\n +var catalog = require(\'bespin:plugins\').catalog;\n +var env = require(\'environment\').env;\n +\n +function CompletionController(editorView) {\n + this._editorView = editorView;\n + editorView.selectionChanged.add(this._selectionChanged.bind(this));\n + editorView.willChangeBuffer.add(this._willChangeBuffer.bind(this));\n +\n + // Prebind _syntaxChanged so that we can attach and detach it.\n + this._syntaxChanged = this._syntaxChanged.bind(this);\n +\n + this.tags = new ctags.Tags();\n + this.ui = new CompletionUI(editorView.element);\n +}\n +\n +CompletionController.prototype = {\n + _buffer: null,\n + _completionEngine: null,\n + _completions: null,\n + _stem: null,\n +\n + _hideCompletions: function() {\n + this.ui.hide();\n + },\n +\n + _selectionChanged: function(newRange) {\n + var engine = this._completionEngine;\n + if (engine == null || !range.isZeroLength(newRange)) {\n + return;\n + }\n +\n + var layoutManager = this._buffer.layoutManager;\n + var textStorage = layoutManager.textStorage;\n + var syntaxManager = layoutManager.syntaxManager;\n +\n + var pos = newRange.start;\n + var row = pos.row, col = pos.col;\n + var line = textStorage.lines[row];\n + var prefix = line.substring(0, col), suffix = line.substring(col);\n +\n + var completions = engine.getCompletions(prefix, suffix, syntaxManager);\n + if (completions == null) {\n + this._hideCompletions();\n + return;\n + }\n +\n + var tags = completions.tags;\n + this._stem = completions.stem;\n + this._showCompletions(tags);\n + },\n +\n + _showCompletions: function(completions) {\n + var editorView = this._editorView;\n + var cursorPt = editorView.textView.getInsertionPointPosition();\n + var pt = editorView.convertTextViewPoint(cursorPt);\n + var lineHeight = editorView.layoutManager.fontDimension.lineHeight;\n + this.ui.show(completions, pt, lineHeight);\n + },\n +\n + _syntaxChanged: function(newSyntax) {\n + var ext = catalog.getExtensionByKey(\'completion\', newSyntax);\n + if (ext == null) {\n + this._completionEngine = null;\n + return;\n + }\n +\n + ext.load().then(function(engine) {\n + this._completionEngine = new engine(this.tags);\n + }.bind(this));\n + },\n +\n + _willChangeBuffer: function(newBuffer) {\n + var oldBuffer = this._buffer;\n + if (oldBuffer != null) {\n + var oldSyntaxManager = oldBuffer.layoutManager.syntaxManager;\n + oldSyntaxManager.syntaxChanged.remove(this._syntaxChanged);\n + }\n +\n + var newSyntaxManager = newBuffer.layoutManager.syntaxManager;\n + newSyntaxManager.syntaxChanged.add(this._syntaxChanged);\n +\n + this._buffer = newBuffer;\n + },\n +\n + cancel: function(env) {\n + this.ui.hide();\n + },\n +\n + complete: function(env) {\n + var ui = this.ui;\n + var tag = ui.getCompletion();\n + var ident = tag.name;\n + env.view.insertText(ident.substring(this._stem.length));\n + ui.hide();\n + },\n +\n + isCompleting: function() {\n + return this.ui.visible;\n + },\n +\n + moveDown: function(env) {\n + this.ui.move(\'down\');\n + },\n +\n + moveUp: function(env) {\n + this.ui.move(\'up\');\n + },\n +\n + /** The current store of tags. */\n + tags: null\n +};\n +\n +function makeCommand(name) {\n + return function(args, req) {\n + return env.editor.completionController[name](env);\n + };\n +}\n +\n +exports.CompletionController = CompletionController;\n +exports.completeCommand = makeCommand(\'complete\');\n +exports.completeCancelCommand = makeCommand(\'cancel\');\n +exports.completeDownCommand = makeCommand(\'moveDown\');\n +exports.completeUpCommand = makeCommand(\'moveUp\');\n +\n +\n +});\n +\n +bespin.tiki.module("completion:index",function(require,exports,module) {\n +\n +});\n +;bespin.tiki.register("::rangeutils", {\n + name: "rangeutils",\n + dependencies: { }\n +});\n +bespin.tiki.module("rangeutils:utils/range",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +\n +/**\n + * Returns the result of adding the two positions.\n + */\n +exports.addPositions = function(a, b) {\n + return { row: a.row + b.row, col: a.col + b.col };\n +};\n +\n +/** Returns a copy of the given range. */\n +exports.cloneRange = function(range) {\n + var oldStart = range.start, oldEnd = range.end;\n + var newStart = { row: oldStart.row, col: oldStart.col };\n + var newEnd = { row: oldEnd.row, col: oldEnd.col };\n + return { start: newStart, end: newEnd };\n +};\n +\n +/**\n + * Given two positions a and b, returns a negative number if a < b, 0 if a = b,\n + * or a positive number if a > b.\n + */\n +exports.comparePositions = function(positionA, positionB) {\n + var rowDiff = positionA.row - positionB.row;\n + return rowDiff === 0 ? positionA.col - positionB.col : rowDiff;\n +};\n +\n +/**\n + * Returns true if the two ranges are equal and false otherwise.\n + */\n +exports.equal = function(rangeA, rangeB) {\n + return (exports.comparePositions(rangeA.start, rangeB.start) === 0 &&\n + exports.comparePositions(rangeA.end, rangeB.end) === 0);\n +};\n +\n +exports.extendRange = function(range, delta) {\n + var end = range.end;\n + return {\n + start: range.start,\n + end: {\n + row: end.row + delta.row,\n + col: end.col + delta.col\n + }\n + };\n +};\n +\n +/**\n + * Given two sets of ranges, returns the ranges of characters that exist in one\n + * of the sets but not both.\n + */\n +exports.intersectRangeSets = function(setA, setB) {\n + var stackA = util.clone(setA), stackB = util.clone(setB);\n + var result = [];\n + while (stackA.length > 0 && stackB.length > 0) {\n + var rangeA = stackA.shift(), rangeB = stackB.shift();\n + var startDiff = exports.comparePositions(rangeA.start, rangeB.start);\n + var endDiff = exports.comparePositions(rangeA.end, rangeB.end);\n +\n + if (exports.comparePositions(rangeA.end, rangeB.start) < 0) {\n + // A is completely before B\n + result.push(rangeA);\n + stackB.unshift(rangeB);\n + } else if (exports.comparePositions(rangeB.end, rangeA.start) < 0) {\n + // B is completely before A\n + result.push(rangeB);\n + stackA.unshift(rangeA);\n + } else if (startDiff < 0) { // A starts before B\n + result.push({ start: rangeA.start, end: rangeB.start });\n + stackA.unshift({ start: rangeB.start, end: rangeA.end });\n + stackB.unshift(rangeB);\n + } else if (startDiff === 0) { // A and B start at the same place\n + if (endDiff < 0) { // A ends before B\n + stackB.unshift({ start: rangeA.end, end: rangeB.end });\n + } else if (endDiff > 0) { // A ends after B\n + stackA.unshift({ start: rangeB.end, end: rangeA.end });\n + }\n + } else if (startDiff > 0) { // A starts after B\n + result.push({ start: rangeB.start, end: rangeA.start });\n + stackA.unshift(rangeA);\n + stackB.unshift({ start: rangeA.start, end: rangeB.end });\n + }\n + }\n + return result.concat(stackA, stackB);\n +};\n +\n +exports.isZeroLength = function(range) {\n + return range.start.row === range.end.row &&\n + range.start.col === range.end.col;\n +};\n +\n +/**\n + * Returns the greater of the two positions.\n + */\n +exports.maxPosition = function(a, b) {\n + return exports.comparePositions(a, b) > 0 ? a : b;\n +};\n +\n +/**\n + * Converts a range with swapped \'end\' and \'start\' values into one with the\n + * values in the correct order.\n + *\n + * TODO: Unit test.\n + */\n +exports.normalizeRange = function(range) {\n + return this.comparePositions(range.start, range.end) < 0 ? range :\n + { start: range.end, end: range.start };\n +};\n +\n +/**\n + * Returns a single range that spans the entire given set of ranges.\n + */\n +exports.rangeSetBoundaries = function(rangeSet) {\n + return {\n + start: rangeSet[0].start,\n + end: rangeSet[rangeSet.length - 1].end\n + };\n +};\n +\n +exports.toString = function(range) {\n + var start = range.start, end = range.end;\n + return \'[ \' + start.row + \', \' + start.col + \' \' + end.row + \',\' + + end.col +\' ]\';\n +};\n +\n +/**\n + * Returns the union of the two ranges.\n + */\n +exports.unionRanges = function(a, b) {\n + return {\n + start: a.start.row < b.start.row ||\n + (a.start.row === b.start.row && a.start.col < b.start.col) ?\n + a.start : b.start,\n + end: a.end.row > b.end.row ||\n + (a.end.row === b.end.row && a.end.col > b.end.col) ?\n + a.end : b.end\n + };\n +};\n +\n +exports.isPosition = function(pos) {\n + return !util.none(pos) && !util.none(pos.row) && !util.none(pos.col);\n +};\n +\n +exports.isRange = function(range) {\n + return (!util.none(range) && exports.isPosition(range.start) &&\n + exports.isPosition(range.end));\n +};\n +\n +});\n +\n +bespin.tiki.module("rangeutils:index",function(require,exports,module) {\n +\n +});\n +;bespin.tiki.register("::undomanager", {\n + name: "undomanager",\n + dependencies: { }\n +});\n +bespin.tiki.module("undomanager:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var env = require(\'environment\').env;\n +\n +/**\n + * This simple undo manager coordinates undo for the app that embeds Bespin.\n + * It\'s similar to SproutCore\'s UndoManager class, but it separates undo and\n + * redo and correctly flushes the redo stack when an action is performed.\n + */\n +exports.UndoManager = function() {};\n +\n +util.mixin(exports.UndoManager.prototype, {\n + _redoStack: [],\n + _undoStack: [],\n +\n + _undoOrRedo: function(method, stack, otherStack) {\n + if (stack.length === 0) {\n + return false;\n + }\n +\n + var record = stack.pop();\n + if (!record.target[method](record.context)) {\n + this._redoStack = [];\n + this._undoStack = [];\n + return false;\n + }\n +\n + otherStack.push(record);\n + return true;\n + },\n +\n + /**\n + * Redo the last undone action.\n + * @return{boolean} True if the action was successfully redone, false\n + * otherwise.\n + */\n + redo: function() {\n + return this._undoOrRedo(\'redo\', this._redoStack, this._undoStack);\n + },\n +\n + /**\n + * Notifies the undo manager that an action was performed. When the action\n + * is to be undone, the \'undo\' message will be sent to the target with the\n + * given context. When the action is to be redone, the \'redo\' message is\n + * sent in the same way.\n + */\n + registerUndo: function(target, context) {\n + this._redoStack = [];\n + this._undoStack.push({ target: target, context: context });\n + },\n +\n + /**\n + * Undoes the last action.\n + *\n + * @return{boolean} True if the action was successfully undone, false\n + * otherwise.\n + */\n + undo: function() {\n + return this._undoOrRedo(\'undo\', this._undoStack, this._redoStack);\n + }\n +});\n +\n +exports.global = new exports.UndoManager();\n +\n +/**\n + *\n + */\n +exports.undoManagerCommand = function(args, request) {\n + exports.global[request.commandExt.name]();\n +};\n +\n +});\n +;bespin.tiki.register("::ctags", {\n + name: "ctags",\n + dependencies: { "traits": "0.0.0", "underscore": "0.0.0" }\n +});\n +bespin.tiki.module("ctags:reader",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var _ = require(\'underscore\')._;\n +var Trait = require(\'traits\').Trait;\n +\n +exports.TagReader = Trait({\n + readLines: function(lines) {\n + var tags = [];\n +\n + _(lines).each(function(line) {\n + var parts = line.split("\\t");\n + if (parts.length < 3) {\n + return;\n + }\n +\n + var name = parts[0];\n + if (/^!_TAG_/.test(name)) {\n + return;\n + }\n +\n + // TODO: cope with tab characters in the addr\n + var tag = { name: name, tagfile: parts[1], addr: parts[2] };\n +\n + var fieldIndex;\n + if (parts.length > 3 && parts[3].indexOf(":") === -1) {\n + tag.kind = parts[3];\n + fieldIndex = 4;\n + } else {\n + fieldIndex = 3;\n + }\n +\n + var fields = {};\n + _(parts.slice(fieldIndex)).each(function(field) {\n + var match = /^([^:]+):(.*)/.exec(field);\n + fields[match[1]] = match[2];\n + });\n + tag.fields = fields;\n +\n + tags.push(tag);\n + });\n +\n + this.add(tags);\n + },\n +\n + readString: function(str) {\n + this.readLines(str.split("\\n"));\n + }\n +});\n +\n +\n +});\n +\n +bespin.tiki.module("ctags:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var _ = require(\'underscore\')._;\n +var TagReader = require(\'./reader\').TagReader;\n +var Trait = require(\'traits\').Trait;\n +\n +exports.Tags = function() {\n + this.tags = [];\n +};\n +\n +exports.Tags.prototype = Object.create(Object.prototype, Trait.compose(Trait({\n + _search: function(id, pred) {\n + var shadowTag = { name: id };\n + var tags = this.tags;\n + var index = _(tags).sortedIndex(shadowTag, function(tag) {\n + return tag.name;\n + });\n +\n + var start = index, end = index;\n + while (start >= 0 && start < tags.length && pred(tags[start])) {\n + start--;\n + }\n + while (end >= 0 && end < tags.length && pred(tags[end])) {\n + end++;\n + }\n +\n + return tags.slice(start + 1, end);\n + },\n +\n + add: function(newTags) {\n + var tags = this.tags;\n + Array.prototype.push.apply(tags, newTags);\n +\n + tags.sort(function(a, b) {\n + var nameA = a.name, nameB = b.name;\n + if (nameA < nameB) {\n + return -1;\n + }\n + if (nameA === nameB) {\n + return 0;\n + }\n + return 1;\n + });\n + },\n +\n + /** Returns all the tags that match the given identifier. */\n + get: function(id) {\n + return this._search(id, function(tag) { return tag.name === id; });\n + },\n +\n + /**\n + * Adds the tags from the supplied JavaScript file to the internal store of\n + * tags.\n + */\n + scan: function(src, file, opts) {\n + if (opts === null || opts === undefined) {\n + opts = {};\n + }\n +\n + var lines = src.split("\\n");\n + var ast = parse(src, file, 1);\n +\n + var interp = new Interpreter(ast, file, lines, opts);\n + interp.interpret();\n + this.add(interp.tags);\n + },\n +\n + /** Returns all the tags that begin with the given prefix. */\n + stem: function(prefix) {\n + var len = prefix.length;\n + return this._search(prefix, function(tag) {\n + return tag.name.substring(0, len) === prefix;\n + });\n + }\n +}), TagReader));\n +\n +\n +});\n +;bespin.tiki.register("::theme_manager", {\n + name: "theme_manager",\n + dependencies: { "theme_manager_base": "0.0.0", "settings": "0.0.0", "events": "0.0.0", "less": "0.0.0" }\n +});\n +bespin.tiki.module("theme_manager:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var Promise = require(\'bespin:promise\').Promise;\n +var catalog = require(\'bespin:plugins\').catalog;\n +var Event = require(\'events\').Event;\n +var themestyles = require(\'themestyles\');\n +var settings = require(\'settings\').settings;\n +\n +// The current themeExt used on the page.\n +var currentThemeExt = null;\n +\n +// Name of the themePlugin that is used as standard theme. This is not the\n +// base theme.\n +var standardThemeName = null;\n +\n +// Load promise for the basePlugin.\n +var basePluginLoadPromise = null;\n +\n +// Export the themeStyles object. This is necessary, as in some cases you want\n +// to access the themeStyles object when the `themeChange` event was fired.\n +exports.themestyles = themestyles;\n +\n +exports.themeSettingChanged = function(source, settingName, themeName) {\n + // Get the themeExtensionPoint for \'themeName\'\n + var themeExt = catalog.getExtensionByKey(\'theme\', themeName);\n +\n + // \'themeName\' === standard : Remove the current set theme.\n + // !themeName || !themeExt : The named theme couldn\'t get found\n + if (themeName === \'standard\' || !themeName || !themeExt) {\n + themeExt = null;\n + // If a standardTheme is given, try to get it.\n + if (standardThemeName !== null) {\n + themeExt = catalog.getExtensionByKey(\'theme\', standardThemeName);\n +\n + }\n + }\n +\n + // If no theme should get applied (including no standardTheme).\n + if (!themeExt) {\n + // If there is a currentTheme before switching to \'standard\' which means\n + // removing the currentTheme as applied on the page.\n + if (currentThemeExt) {\n + // There might be a themeStyle file to remove.\n + themestyles.unregisterThemeStyles(currentThemeExt);\n +\n + currentThemeExt = null;\n +\n + // Reset the themeVariables applied by the theme.\n + themestyles.currentThemeVariables = null;\n +\n + // Update the globalVariables.\n + themestyles.parseGlobalVariables();\n +\n + // Reparse all the applied themeStyles.\n + themestyles.reparse();\n +\n + // Publish the \'themeChange\' event.\n + catalog.publish(this, \'themeChange\');\n + }\n + return;\n + } else {\n + themeExt.load().then(function(theme) {\n + // Remove the former themeStyle file, if the former extension has\n + // one declaired.\n + if (currentThemeExt) {\n + themestyles.unregisterThemeStyles(currentThemeExt);\n + }\n +\n + // The theme is a function. Execute it to get the themeData.\n + themestyles.currentThemeVariables = theme();\n +\n + // Store the data for later use.\n + currentThemeExt = themeExt;\n +\n + // Update the globalVariables.\n + themestyles.parseGlobalVariables();\n +\n + // Reparse all the applied themeStyles.\n + themestyles.reparse();\n +\n + // If the theme has a url that points to a themeStyles file, then\n + // register it.\n + if (themeExt.url) {\n + themestyles.registerThemeStyles(themeExt);\n + }\n +\n + // Publish the \'themeChange\' event.\n + catalog.publish(exports, \'themeChange\');\n + });\n + }\n +};\n +\n +catalog.registerExtension(\'settingChange\', {\n + match: "theme",\n + pointer: exports.themeSettingChanged.bind(exports)\n +});\n +\n +/**\n + * Sets the standard theme that is used when no other theme is specified or\n + * the specified theme is not around.\n + */\n +exports.setStandardTheme = function(themeName) {\n + standardThemeName = themeName;\n +\n + // If the current theme is equal to themeName, then the theme is already\n + // applied. Otherwise, call themeSttingChanged which handles the standard-\n + // theme change then.\n + if (themeName !== settings.get(\'theme\')) {\n + exports.themeSettingChanged(this);\n + }\n +};\n +\n +/**\n + * Sets the plugin that should get treated as \'basePlugin\'. BasePlugins contains\n + * the generic theming for buttons, inputs, panes etc.\n + */\n +exports.setBasePlugin = function(pluginName) {\n + // Set the basePlugin.\n + themestyles.basePluginName = pluginName;\n +};\n +\n +/**\n + * This function has to be called to enable parsing. Before calling this\n + * function, parsing is prevented. This allows the developer to prevent parsing\n + * until certain basic theme plugins are loaded.\n + * Returns a promise that is resolved after all currently applied themeStyles\n + * are parsed.\n + */\n +exports.startParsing = function() {\n + // Allow the parsing.\n + themestyles.preventParsing = false;\n +\n + // Reparse all the applied themeStyles.\n + return themestyles.reparse();\n +};\n +\n +exports.registerTheme = function(extension) {\n + var currentThemeName = settings.get(\'theme\');\n + if (extension.name === currentThemeName) {\n + exports.themeSettingChanged(this, \'theme\', extension.name);\n + }\n +};\n +\n +exports.unregisterTheme = function(extension) {\n + if (extension.name === settings.get(\'theme\')) {\n + exports.themeSettingChanged(this);\n + }\n +};\n +\n +// Called when the app is launched.\n +exports.appLaunched = function() {\n + // Fire the `themeChange` event as some plugins might haven\'t triggered it\n + // during the launch of the app.\n + catalog.publish(exports, \'themeChange\');\n +};\n +\n +});\n +\n +bespin.tiki.module("theme_manager:themestyles",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var util = require(\'bespin:util/util\');\n +var catalog = require(\'bespin:plugins\').catalog;\n +var console = require(\'bespin:console\').console;\n +var Promise = require(\'bespin:promise\').Promise;\n +var group = require(\'bespin:promise\').group;\n +\n +var proxy = require(\'bespin:proxy\');\n +\n +var less = require(\'less\');\n +\n +// The less parser to use.\n +var lessParser = new less.Parser({ optimization: 3 });\n +\n +// The incremented styleID number.\n +var styleID = 1;\n +\n +// The theme variables as set by the current theme.\n +exports.currentThemeVariables = null;\n +\n +// The plugin that should get applied before any other plugins get applied.\n +exports.basePluginName = null;\n +\n +// If true, no less file is parsed.\n +exports.preventParsing = true;\n +\n +// Stores the variableHeader used by every themeStyleFile for the global\n +// ThemeVariables.\n +var globalVariableHeader = \'\';\n +\n +// The globalThemeVariables as a combination of the build in once and variables\n +// defined in a custom theme plugin.\n +exports.globalThemeVariables = {};\n +\n +// Stores the internal styleID used with a extension.\n +var extensionStyleID = {};\n +\n +// Stores the ThemeStyleFiles\' content per plugin - somewhat like a par plugin\n +// themeStyle cache.\n +var extensionStyleData = {};\n +\n +// Takes an JS object that and makes it \'linear\'. Every item gets prefixed with\n +// \'global\':\n +//\n +// globalValues = {\n +// a: {\n +// b: \'test\'\n +// }\n +// }\n +//\n +// returns: { \'global_a_b\': \'test\' }\n +var parseGlobalThemeVariables = function(globalValues) {\n + var ret = {};\n + var nameStack = [];\n +\n + var parseSub = function(name, key) {\n + nameStack.push(name);\n + if (typeof key != \'object\') {\n + ret[nameStack.join(\'_\')] = key;\n + } else {\n + for (prop in key) {\n + parseSub(prop, key[prop]);\n + }\n + }\n + nameStack.pop();\n + };\n +\n + parseSub(\'global\', globalValues);\n + return ret;\n +};\n +\n +//------------------------------------------------------------------------------\n +// BEGIN: THIS PART IS OVERRIDDEN BY dryice\n +\n +// Stores the StyleFiles content per plugin during the build of Bespin.\n +// The variable scheme looks like: { pluginName: { "fileName": data } };\n +var extensionStyleBuildData = {};\n +\n +// Stores the default globalTheme ThemeVariables, that are available to every\n +// ThemeStyleFile.\n +var defaultGlobalTheme = {\n + // standard font.\n + font: \'arial, lucida, helvetica, sans-serif\',\n + // standard font size.\n + font_size: \'14px\',\n + // standard line_height.\n + line_height: \'1.8em\',\n + // text color.\n + color: \'#DAD4BA\',\n +\n + text_shadow: \'1px 1px rgba(0, 0, 0, 0.4)\',\n + // text error color.\n + error_color: \'#F99\',\n + // the color for headers (<h1> etc).\n + header_color: \'white\',\n + // the color for links.\n + link_color: \'#ACF\',\n +\n + // Basic colors for a controller: textInput, tree etc.\n + control: {\n + color: \'#E1B41F\',\n + border: \'1px solid rgba(0, 0, 0, 0.2)\',\n + border_radius: \'0.25em\',\n + background: \'rgba(0, 0, 0, 0.2)\',\n +\n + active: {\n + color: \'#FF9600\',\n + border: \'1px solid #E1B41F\',\n + inset_color: \'#ff9600\',\n + background: \'rgba(0, 0, 0, 0.2)\'\n + }\n + },\n +\n + pane: {\n + h1: {\n + font: "\'MuseoSans\', Helvetica",\n + font_size: \'2.8em\',\n + color: "white"\n + },\n +\n + color: \'#DAD4BA\',\n + text_shadow: \'1px 1px rgba(0, 0, 0, 0.4)\',\n +\n + link_color: \'white\',\n +\n + background: \'#45443C\',\n + border_radius: \'.5em\'\n + },\n +\n + form: {\n + color: \'white\',\n + text_shadow: \'1px 1px rgba(0, 0, 0, 0.4)\',\n +\n + font: "\'Lucida Sans\',\'Lucida Grande\',Verdana,Arial,sans-serif",\n + font_size: \'@global_font_size\',\n + line_height: \'@global_line_height\'\n + },\n +\n + button: {\n + color: \'white\',\n + background: \'#3E6CB9\'\n + },\n +\n + container: {\n + background: \'#1E1916\',\n + border: \'1px solid black\'\n + },\n +\n + // The items in the command line menu or something else,\n + // that can get selected.\n + selectable: {\n + color: \'white\',\n + border: \'0px solid transparent\',\n + background: \'transparent\',\n +\n + active: {\n + color: \'black\',\n + border: \'0px solid transparent\',\n + background: \'#FF8E00\'\n + },\n +\n + hover: {\n + color: \'black\',\n + border: \'0px solid transparent\',\n + background: \'#FF8E00\'\n + }\n + },\n +\n + // A small hint text.\n + hint: {\n + color: \'#AAA\',\n +\n + active: {\n + color: \'black\'\n + },\n +\n + hover: {\n + color: \'black\'\n + }\n + },\n +\n + // E.g. in the command line menu, the \'ALT+2\'.\n + accelerator: {\n + color: \'#996633\',\n +\n + active: {\n + color: \'black\'\n + },\n +\n + hover: {\n + color: \'black\'\n + }\n + },\n +\n + menu: {\n + border_color: \'black\',\n + inset_color_right: \'#1E1916\',\n + inset_color_top_left: \'#3E3936\',\n + background: \'transparent\'\n + }\n +};\n +\n +defaultGlobalTheme = parseGlobalThemeVariables(defaultGlobalTheme);\n +\n +// END: THIS PART IS OVERRIDDEN BY dryice\n +//------------------------------------------------------------------------------\n +\n +/**\n + * Returns an object with all the themeVariables value for a given plugin.\n + */\n +exports.getPluginThemeVariables = function(pluginName) {\n + var plugin = catalog.plugins[pluginName];\n +\n + if (!plugin) {\n + return null;\n + }\n +\n + // Hash to look for custom theme variables.\n + var themeVariables = {};\n + if (exports.currentThemeVariables &&\n + exports.currentThemeVariables[pluginName]) {\n + themeVariables = exports.currentThemeVariables[pluginName];\n + }\n +\n + // Set the value for all themeVariables in this plugin.\n + plugin.provides.forEach(function(ext) {\n + if (ext.ep === \'themevariable\') {\n + var value = ext.name;\n + // The value is the customThemeVariable OR the defaultValue if the\n + // customThemeVariable is not given.\n + themeVariables[value] = themeVariables[value] || ext.defaultValue;\n + }\n + });\n +\n + return themeVariables;\n +};\n +\n +/**\n + * Update the globalThemeVariables. This is called whenever the theme changes.\n + */\n +exports.parseGlobalVariables = function() {\n + var globalObj = {};\n + var globalHeader = \'\';\n + var currentThemeVariables = exports.currentThemeVariables;\n +\n + util.mixin(globalObj, defaultGlobalTheme);\n +\n + if (currentThemeVariables && currentThemeVariables[\'global\']) {\n + util.mixin(globalObj,\n + parseGlobalThemeVariables(currentThemeVariables[\'global\']));\n + }\n +\n + exports.globalThemeVariables = globalObj;\n +\n + for (prop in globalObj) {\n + globalHeader += \'@\' + prop + \':\' + globalObj[prop] + \';\';\n + }\n +\n + globalVariableHeader = globalHeader;\n +};\n +\n +// Parse the globalThemeVariables.\n +exports.parseGlobalVariables();\n +\n +/**\n + * Parse one less files.\n + */\n +var parseLess = function(pr, pluginName, variableHeader) {\n + // Use already existing DOM style element or create a new one on the page.\n + if (extensionStyleID[pluginName]) {\n + styleElem = document.getElementById(\'_bespin_theme_style_\' +\n + extensionStyleID[pluginName]);\n + } else {\n + styleElem = document.createElement(\'style\');\n + styleElem.setAttribute(\'id\', \'_bespin_theme_style_\' + styleID);\n + extensionStyleID[pluginName] = styleID;\n + styleID ++;\n + document.body.appendChild(styleElem);\n + }\n +\n + // DEBUG ONLY.\n + // var timer = new Date();\n +\n + // Parse the data.\n + var dataToParse = globalVariableHeader + // global ThemeVariables\n + variableHeader + // plugin specific ThemeVariables\n + extensionStyleData[pluginName]; // and the data\n + lessParser.parse(dataToParse, function(e, tree) {\n + var errMsg;\n + if (e) {\n + errMsg = \'Error less parsing \' + pluginName + \' \' + e.message;\n + console.error(errMsg);\n + pr.reject(errMsg);\n + return;\n + }\n +\n + try {\n + var css = tree.toCSS();\n +\n + // DEBUG ONLY.\n + // console.log(\' parsing took: \', (new Date()) - timer, \'ms\');\n + } catch (e) {\n + errMsg = \'Error less parsing \' + pluginName + \' \' + e;\n + console.error(errMsg);\n + pr.reject(errMsg);\n + return;\n + }\n +\n + // Add the parsed CSS content in the styleElement.\n + if (styleElem && styleElem.firstChild) {\n + styleElem.firstChild.textContent = css;\n + } else {\n + var cssContentNode = document.createTextNode(css);\n + styleElem.appendChild(cssContentNode);\n + }\n + pr.resolve();\n + });\n +};\n +\n +// Queue with all the plugins waiting to get updated.\n +var parseQueue = {};\n +\n +/**\n + * Parse the less files for a entire plugin. The plugin is not parsed directly,\n + * but with a small delay. Otherwise it could happen that the plugin is parsed\n + * although not all themeVariables are available.\n + * Returns a promise that is resolved after the plugin is successfully parsed.\n + * An error during parsing rejects the promise.\n + */\n +exports.parsePlugin = function(pluginName) {\n + // Parse only if this is permitted.\n + if (exports.preventParsing) {\n + return (new Promise).resolve();\n + }\n +\n + var plugin = catalog.plugins[pluginName];\n +\n + if (!plugin) {\n + throw "reparsePlugin: plugin " + pluginName + " is not defined!";\n + }\n +\n + // Start parsing only if it isn\'t started already.\n + if (!parseQueue[pluginName]) {\n + // Mark that the plugin is queued.\n + parseQueue[pluginName] = new Promise();\n +\n + setTimeout(function() {\n + // DEBUG ONLY:\n + // console.log(\'=== Parse Plugin: \' + pluginName + \' ===\');\n + // var time = new Date();\n +\n + var themeVariables = exports.getPluginThemeVariables(pluginName);\n +\n + // Store the StyleVariables for the StyleData to parse.\n + var variableHeader = \'\';\n +\n + for (prop in themeVariables) {\n + variableHeader += \'@\' + prop + \':\' + themeVariables[prop] + \';\';\n + }\n +\n + // DEBUG ONLY:\n + // console.log(\' variables: \', variableHeader, globalVariableHeader);\n +\n + var parsePr = new Promise;\n + parsePr.then(function(data) {\n + parseQueue[this.name].resolve(data);\n + parseQueue[this.name] = null;\n + }.bind(this), function() {\n + parseQueue[this.name].reject(data);\n + parseQueue[this.name] = null;\n + }.bind(this))\n +\n + parseLess(parsePr, pluginName, variableHeader);\n +\n + // DEBUG ONLY:\n + // console.log(\'everything took: \', (new Date()) - time, \'ms\');\n + }.bind(plugin), 0);\n + }\n +\n + return parseQueue[pluginName];\n +};\n +\n +// Function that pocesses the loaded StyleFile content.\n +var processStyleContent = function(resourceURL, pluginName, data, p) {\n + // Convert url(something) to url(resourceURL/something).\n + data = data.replace(/url\\([\'"]*([^\'")]*)([\'"]*)\\)/g,\n + \'url(\' + resourceURL + \'$1)\');\n + extensionStyleData[pluginName] += data;\n +\n + // Resolve the promise when given.\n + if (p) {\n + p.resolve();\n + }\n +};\n +\n +var themeDataLoadPromise = null;\n +\n +exports.registerThemeStyles = function(extension) {\n + var pluginName = extension.getPluginName();\n + var resourceURL = catalog.getResourceURL(pluginName);\n +\n + // Make the extension.url parameter an array if it isn\'t yet.\n + if (!(extension.url instanceof Array)) {\n + extension.url = [ extension.url ];\n + }\n +\n + // (Re)set the loaded StyleData for the plugin.\n + extensionStyleData[pluginName] = \'\';\n +\n + var loadPromises = [];\n +\n + var preventParsing = exports.preventParsing;\n +\n + // Load the StyleFiles.\n + extension.url.forEach(function(styleFile) {\n + if (extensionStyleBuildData[pluginName] &&\n + extensionStyleBuildData[pluginName][styleFile]) {\n + // Process the StyleContent.\n + processStyleContent(resourceURL, pluginName,\n + extensionStyleBuildData[pluginName][styleFile]);\n + } else {\n + var p = new Promise();\n + loadPromises.push(p);\n +\n + var url = resourceURL + styleFile + \'?\' + (new Date).getTime();\n + proxy.xhr(\'GET\', url, true, function(xhr) {\n + xhr.overrideMimeType(\'text/plain\');\n + }).then(function(response) {\n + processStyleContent(resourceURL, pluginName, response, p);\n + }, function(err) {\n + console.error(\'registerLessFile: Could not load \' +\n + resourceURL + styleFile);\n +\n + // The file couldn\'t get loaded but to make the group\n + // work we have to mark this loadPromise as resolved so that\n + // at least the other sucessfully loaded files can get\n + // proceeded.\n + p.resolve();\n + });\n + }\n + });\n +\n + if (loadPromises.length === 0) {\n + exports.parsePlugin(pluginName);\n + } else {\n + // If parsing is allowed, then wait until all the styleFiles are loaded\n + // and parse the plugin.\n + if (!preventParsing) {\n + group(loadPromises).then(function() {\n + exports.parsePlugin(pluginName);\n + });\n + }\n +\n + if (themeDataLoadPromise !== null) {\n + loadPromises = loadPromises.concat(themeDataLoadPromise);\n + }\n + themeDataLoadPromise = group(loadPromises);\n + }\n +};\n +\n +/**\n + * Call this function to reparse all the ThemeStyles files.\n + * Returns a promise. The promise is resolved after all themeStyles are reparsed.\n + */\n +exports.reparse = function() {\n + var pr = new Promise();\n +\n + // Reparse only if this is permitted.\n + if (exports.preventParsing) {\n + return pr.resolve();\n + }\n +\n + // Reparsing makes only sense if there is a themeDataLoadPromise.\n + // If the value is null, then no styleFile was loaded and there is nothing\n + // to reparse.\n + if (themeDataLoadPromise) {\n + // When all the styleFiles are loaded.\n + themeDataLoadPromise.then(function() {\n + var parsePromises = [];\n +\n + // Reparese all the themeStyles. Instead of loading the themeStyles\n + // again from the server, the cache extensionStyleData is used.\n + // Every plugin in this cache is reparsed.\n +\n + // Check if a basePlugin is set and parse this one first.\n + var basePluginName = exports.basePluginName;\n + if (basePluginName !== null && extensionStyleData[basePluginName]) {\n + parsePromises.push(exports.parsePlugin(basePluginName));\n + }\n +\n + // Parse the other plugins.\n + for (var pluginName in extensionStyleData) {\n + // Skip the basePlugin as this is already parsed.\n + if (pluginName === basePluginName) {\n + continue;\n + }\n + parsePromises.push(exports.parsePlugin(pluginName));\n + }\n +\n + // After all themeStyles are parsed, resolve the returned promise.\n + group(parsePromises).then(pr.resolve.bind(pr), pr.reject.bind(pr));\n + }, function(err) {\n + pr.reject(err);\n + });\n + } else {\n + pr.resolve();\n + }\n + return pr;\n +};\n +\n +/**\n + * Unregister a themeStyle.\n + * @param The extension to unregister.\n + */\n +exports.unregisterThemeStyles = function(extension) {\n + var pluginName = extension.getPluginName();\n + if (!extensionStyleID[pluginName]) {\n + return;\n + }\n +\n + // Remove the style element from the page.\n + var styleID = \'_bespin_theme_style_\' + extensionStyleID[pluginName];\n + var styleElement = document.getElementById(styleID);\n + styleElement.parentNode.removeChild(styleElement);\n +\n + // Remove the style reference.\n + delete extensionStyleID[pluginName];\n + // Remove the themeStyle cache.\n + delete extensionStyleData[pluginName];\n +};\n +\n +});\n +;bespin.tiki.register("::jquery", {\n + name: "jquery",\n + dependencies: { }\n +});\n +bespin.tiki.module("jquery:index",function(require,exports,module) {\n +"define metadata";\n +({});\n +"end";\n +\n +/*!\n + * jQuery JavaScript Library v1.4.2\n + * http://jquery.com/\n + *\n + * Copyright 2010, John Resig\n + * Dual licensed under the MIT or GPL Version 2 licenses.\n + * http://jquery.org/license\n + *\n + * Includes Sizzle.js\n + * http://sizzlejs.com/\n + * Copyright 2010, The Dojo Foundation\n + * Released under the MIT, BSD, and GPL Licenses.\n + *\n + * Date: Sat Feb 13 22:33:48 2010 -0500\n + */\n +\n +// Define a local copy of jQuery\n +var jQuery = function( selector, context ) {\n +\t\t// The jQuery object is actually just the init constructor \'enhanced\'\n +\t\treturn new jQuery.fn.init( selector, context );\n +\t},\n +\n +\t// Map over jQuery in case of overwrite\n +\t_jQuery = window.jQuery,\n +\n +\t// Map over the $ in case of overwrite\n +\t_$ = window.$,\n +\n +\t// Use the correct document accordingly with window argument (sandbox)\n +\tdocument = window.document,\n +\n +\t// A central reference to the root jQuery(document)\n +\trootjQuery,\n +\n +\t// A simple way to check for HTML strings or ID strings\n +\t// (both of which we optimize for)\n +\tquickExpr = /^[^<]*(<[\\w\\W]+>)[^>]*$|^#([\\w-]+)$/,\n +\n +\t// Is it a simple selector\n +\tisSimple = /^.[^:#\\[\\.,]*$/,\n +\n +\t// Check if a string has a non-whitespace character in it\n +\trnotwhite = /\\S/,\n +\n +\t// Used for trimming whitespace\n +\trtrim = /^(\\s|\\u00A0)+|(\\s|\\u00A0)+$/g,\n +\n +\t// Match a standalone tag\n +\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\n +\n +\t// Keep a UserAgent string for use with jQuery.browser\n +\tuserAgent = navigator.userAgent,\n +\n +\t// For matching the engine and version of the browser\n +\tbrowserMatch,\n +\t\n +\t// Has the ready events already been bound?\n +\treadyBound = false,\n +\t\n +\t// The functions to execute on DOM ready\n +\treadyList = [],\n +\n +\t// The ready event handler\n +\tDOMContentLoaded,\n +\n +\t// Save a reference to some core methods\n +\ttoString = Object.prototype.toString,\n +\thasOwnProperty = Object.prototype.hasOwnProperty,\n +\tpush = Array.prototype.push,\n +\tslice = Array.prototype.slice,\n +\tindexOf = Array.prototype.indexOf;\n +\n +jQuery.fn = jQuery.prototype = {\n +\tinit: function( selector, context ) {\n +\t\tvar match, elem, ret, doc;\n +\n +\t\t// Handle $(""), $(null), or $(undefined)\n +\t\tif ( !selector ) {\n +\t\t\treturn this;\n +\t\t}\n +\n +\t\t// Handle $(DOMElement)\n +\t\tif ( selector.nodeType ) {\n +\t\t\tthis.context = this[0] = selector;\n +\t\t\tthis.length = 1;\n +\t\t\treturn this;\n +\t\t}\n +\t\t\n +\t\t// The body element only exists once, optimize finding it\n +\t\tif ( selector === "body" && !context ) {\n +\t\t\tthis.context = document;\n +\t\t\tthis[0] = document.body;\n +\t\t\tthis.selector = "body";\n +\t\t\tthis.length = 1;\n +\t\t\treturn this;\n +\t\t}\n +\n +\t\t// Handle HTML strings\n +\t\tif ( typeof selector === "string" ) {\n +\t\t\t// Are we dealing with HTML string or an ID?\n +\t\t\tmatch = quickExpr.exec( selector );\n +\n +\t\t\t// Verify a match, and that no context was specified for #id\n +\t\t\tif ( match && (match[1] || !context) ) {\n +\n +\t\t\t\t// HANDLE: $(html) -> $(array)\n +\t\t\t\tif ( match[1] ) {\n +\t\t\t\t\tdoc = (context ? context.ownerDocument || context : document);\n +\n +\t\t\t\t\t// If a single string is passed in and it\'s a single tag\n +\t\t\t\t\t// just do a createElement and skip the rest\n +\t\t\t\t\tret = rsingleTag.exec( selector );\n +\n +\t\t\t\t\tif ( ret ) {\n +\t\t\t\t\t\tif ( jQuery.isPlainObject( context ) ) {\n +\t\t\t\t\t\t\tselector = [ document.createElement( ret[1] ) ];\n +\t\t\t\t\t\t\tjQuery.fn.attr.call( selector, context, true );\n +\n +\t\t\t\t\t\t} else {\n +\t\t\t\t\t\t\tselector = [ doc.createElement( ret[1] ) ];\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\tret = buildFragment( [ match[1] ], [ doc ] );\n +\t\t\t\t\t\tselector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;\n +\t\t\t\t\t}\n +\t\t\t\t\t\n +\t\t\t\t\treturn jQuery.merge( this, selector );\n +\t\t\t\t\t\n +\t\t\t\t// HANDLE: $("#id")\n +\t\t\t\t} else {\n +\t\t\t\t\telem = document.getElementById( match[2] );\n +\n +\t\t\t\t\tif ( elem ) {\n +\t\t\t\t\t\t// Handle the case where IE and Opera return items\n +\t\t\t\t\t\t// by name instead of ID\n +\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n +\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\t// Otherwise, we inject the element directly into the jQuery object\n +\t\t\t\t\t\tthis.length = 1;\n +\t\t\t\t\t\tthis[0] = elem;\n +\t\t\t\t\t}\n +\n +\t\t\t\t\tthis.context = document;\n +\t\t\t\t\tthis.selector = selector;\n +\t\t\t\t\treturn this;\n +\t\t\t\t}\n +\n +\t\t\t// HANDLE: $("TAG")\n +\t\t\t} else if ( !context && /^\\w+$/.test( selector ) ) {\n +\t\t\t\tthis.selector = selector;\n +\t\t\t\tthis.context = document;\n +\t\t\t\tselector = document.getElementsByTagName( selector );\n +\t\t\t\treturn jQuery.merge( this, selector );\n +\n +\t\t\t// HANDLE: $(expr, $(...))\n +\t\t\t} else if ( !context || context.jquery ) {\n +\t\t\t\treturn (context || rootjQuery).find( selector );\n +\n +\t\t\t// HANDLE: $(expr, context)\n +\t\t\t// (which is just equivalent to: $(context).find(expr)\n +\t\t\t} else {\n +\t\t\t\treturn jQuery( context ).find( selector );\n +\t\t\t}\n +\n +\t\t// HANDLE: $(function)\n +\t\t// Shortcut for document ready\n +\t\t} else if ( jQuery.isFunction( selector ) ) {\n +\t\t\treturn rootjQuery.ready( selector );\n +\t\t}\n +\n +\t\tif (selector.selector !== undefined) {\n +\t\t\tthis.selector = selector.selector;\n +\t\t\tthis.context = selector.context;\n +\t\t}\n +\n +\t\treturn jQuery.makeArray( selector, this );\n +\t},\n +\n +\t// Start with an empty selector\n +\tselector: "",\n +\n +\t// The current version of jQuery being used\n +\tjquery: "1.4.2",\n +\n +\t// The default length of a jQuery object is 0\n +\tlength: 0,\n +\n +\t// The number of elements contained in the matched element set\n +\tsize: function() {\n +\t\treturn this.length;\n +\t},\n +\n +\ttoArray: function() {\n +\t\treturn slice.call( this, 0 );\n +\t},\n +\n +\t// Get the Nth element in the matched element set OR\n +\t// Get the whole matched element set as a clean array\n +\tget: function( num ) {\n +\t\treturn num == null ?\n +\n +\t\t\t// Return a \'clean\' array\n +\t\t\tthis.toArray() :\n +\n +\t\t\t// Return just the object\n +\t\t\t( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );\n +\t},\n +\n +\t// Take an array of elements and push it onto the stack\n +\t// (returning the new matched element set)\n +\tpushStack: function( elems, name, selector ) {\n +\t\t// Build a new jQuery matched element set\n +\t\tvar ret = jQuery();\n +\n +\t\tif ( jQuery.isArray( elems ) ) {\n +\t\t\tpush.apply( ret, elems );\n +\t\t\n +\t\t} else {\n +\t\t\tjQuery.merge( ret, elems );\n +\t\t}\n +\n +\t\t// Add the old object onto the stack (as a reference)\n +\t\tret.prevObject = this;\n +\n +\t\tret.context = this.context;\n +\n +\t\tif ( name === "find" ) {\n +\t\t\tret.selector = this.selector + (this.selector ? " " : "") + selector;\n +\t\t} else if ( name ) {\n +\t\t\tret.selector = this.selector + "." + name + "(" + selector + ")";\n +\t\t}\n +\n +\t\t// Return the newly-formed element set\n +\t\treturn ret;\n +\t},\n +\n +\t// Execute a callback for every element in the matched set.\n +\t// (You can seed the arguments with an array of args, but this is\n +\t// only used internally.)\n +\teach: function( callback, args ) {\n +\t\treturn jQuery.each( this, callback, args );\n +\t},\n +\t\n +\tready: function( fn ) {\n +\t\t// Attach the listeners\n +\t\tjQuery.bindReady();\n +\n +\t\t// If the DOM is already ready\n +\t\tif ( jQuery.isReady ) {\n +\t\t\t// Execute the function immediately\n +\t\t\tfn.call( document, jQuery );\n +\n +\t\t// Otherwise, remember the function for later\n +\t\t} else if ( readyList ) {\n +\t\t\t// Add the function to the wait list\n +\t\t\treadyList.push( fn );\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\t\n +\teq: function( i ) {\n +\t\treturn i === -1 ?\n +\t\t\tthis.slice( i ) :\n +\t\t\tthis.slice( i, +i + 1 );\n +\t},\n +\n +\tfirst: function() {\n +\t\treturn this.eq( 0 );\n +\t},\n +\n +\tlast: function() {\n +\t\treturn this.eq( -1 );\n +\t},\n +\n +\tslice: function() {\n +\t\treturn this.pushStack( slice.apply( this, arguments ),\n +\t\t\t"slice", slice.call(arguments).join(",") );\n +\t},\n +\n +\tmap: function( callback ) {\n +\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n +\t\t\treturn callback.call( elem, i, elem );\n +\t\t}));\n +\t},\n +\t\n +\tend: function() {\n +\t\treturn this.prevObject || jQuery(null);\n +\t},\n +\n +\t// For internal use only.\n +\t// Behaves like an Array\'s method, not like a jQuery method.\n +\tpush: push,\n +\tsort: [].sort,\n +\tsplice: [].splice\n +};\n +\n +// Give the init function the jQuery prototype for later instantiation\n +jQuery.fn.init.prototype = jQuery.fn;\n +\n +jQuery.extend = jQuery.fn.extend = function() {\n +\t// copy reference to target object\n +\tvar target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;\n +\n +\t// Handle a deep copy situation\n +\tif ( typeof target === "boolean" ) {\n +\t\tdeep = target;\n +\t\ttarget = arguments[1] || {};\n +\t\t// skip the boolean and the target\n +\t\ti = 2;\n +\t}\n +\n +\t// Handle case when target is a string or something (possible in deep copy)\n +\tif ( typeof target !== "object" && !jQuery.isFunction(target) ) {\n +\t\ttarget = {};\n +\t}\n +\n +\t// extend jQuery itself if only one argument is passed\n +\tif ( length === i ) {\n +\t\ttarget = this;\n +\t\t--i;\n +\t}\n +\n +\tfor ( ; i < length; i++ ) {\n +\t\t// Only deal with non-null/undefined values\n +\t\tif ( (options = arguments[ i ]) != null ) {\n +\t\t\t// Extend the base object\n +\t\t\tfor ( name in options ) {\n +\t\t\t\tsrc = target[ name ];\n +\t\t\t\tcopy = options[ name ];\n +\n +\t\t\t\t// Prevent never-ending loop\n +\t\t\t\tif ( target === copy ) {\n +\t\t\t\t\tcontinue;\n +\t\t\t\t}\n +\n +\t\t\t\t// Recurse if we\'re merging object literal values or arrays\n +\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {\n +\t\t\t\t\tvar clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src\n +\t\t\t\t\t\t: jQuery.isArray(copy) ? [] : {};\n +\n +\t\t\t\t\t// Never move original objects, clone them\n +\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n +\n +\t\t\t\t// Don\'t bring in undefined values\n +\t\t\t\t} else if ( copy !== undefined ) {\n +\t\t\t\t\ttarget[ name ] = copy;\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t}\n +\n +\t// Return the modified object\n +\treturn target;\n +};\n +\n +jQuery.extend({\n +\tnoConflict: function( deep ) {\n +\t\twindow.$ = _$;\n +\n +\t\tif ( deep ) {\n +\t\t\twindow.jQuery = _jQuery;\n +\t\t}\n +\n +\t\treturn jQuery;\n +\t},\n +\t\n +\t// Is the DOM ready to be used? Set to true once it occurs.\n +\tisReady: false,\n +\t\n +\t// Handle when the DOM is ready\n +\tready: function() {\n +\t\t// Make sure that the DOM is not already loaded\n +\t\tif ( !jQuery.isReady ) {\n +\t\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n +\t\t\tif ( !document.body ) {\n +\t\t\t\treturn setTimeout( jQuery.ready, 13 );\n +\t\t\t}\n +\n +\t\t\t// Remember that the DOM is ready\n +\t\t\tjQuery.isReady = true;\n +\n +\t\t\t// If there are functions bound, to execute\n +\t\t\tif ( readyList ) {\n +\t\t\t\t// Execute all of them\n +\t\t\t\tvar fn, i = 0;\n +\t\t\t\twhile ( (fn = readyList[ i++ ]) ) {\n +\t\t\t\t\tfn.call( document, jQuery );\n +\t\t\t\t}\n +\n +\t\t\t\t// Reset the list of functions\n +\t\t\t\treadyList = null;\n +\t\t\t}\n +\n +\t\t\t// Trigger any bound ready events\n +\t\t\tif ( jQuery.fn.triggerHandler ) {\n +\t\t\t\tjQuery( document ).triggerHandler( "ready" );\n +\t\t\t}\n +\t\t}\n +\t},\n +\t\n +\tbindReady: function() {\n +\t\tif ( readyBound ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\treadyBound = true;\n +\n +\t\t// Catch cases where $(document).ready() is called after the\n +\t\t// browser event has already occurred.\n +\t\tif ( document.readyState === "complete" ) {\n +\t\t\treturn jQuery.ready();\n +\t\t}\n +\n +\t\t// Mozilla, Opera and webkit nightlies currently support this event\n +\t\tif ( document.addEventListener ) {\n +\t\t\t// Use the handy event callback\n +\t\t\tdocument.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );\n +\t\t\t\n +\t\t\t// A fallback to window.onload, that will always work\n +\t\t\twindow.addEventListener( "load", jQuery.ready, false );\n +\n +\t\t// If IE event model is used\n +\t\t} else if ( document.attachEvent ) {\n +\t\t\t// ensure firing before onload,\n +\t\t\t// maybe late but safe also for iframes\n +\t\t\tdocument.attachEvent("onreadystatechange", DOMContentLoaded);\n +\t\t\t\n +\t\t\t// A fallback to window.onload, that will always work\n +\t\t\twindow.attachEvent( "onload", jQuery.ready );\n +\n +\t\t\t// If IE and not a frame\n +\t\t\t// continually check to see if the document is ready\n +\t\t\tvar toplevel = false;\n +\n +\t\t\ttry {\n +\t\t\t\ttoplevel = window.frameElement == null;\n +\t\t\t} catch(e) {}\n +\n +\t\t\tif ( document.documentElement.doScroll && toplevel ) {\n +\t\t\t\tdoScrollCheck();\n +\t\t\t}\n +\t\t}\n +\t},\n +\n +\t// See test/unit/core.js for details concerning isFunction.\n +\t// Since version 1.3, DOM methods and functions like alert\n +\t// aren\'t supported. They return false on IE (#2968).\n +\tisFunction: function( obj ) {\n +\t\treturn toString.call(obj) === "[object Function]";\n +\t},\n +\n +\tisArray: function( obj ) {\n +\t\treturn toString.call(obj) === "[object Array]";\n +\t},\n +\n +\tisPlainObject: function( obj ) {\n +\t\t// Must be an Object.\n +\t\t// Because of IE, we also have to check the presence of the constructor property.\n +\t\t// Make sure that DOM nodes and window objects don\'t pass through, as well\n +\t\tif ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {\n +\t\t\treturn false;\n +\t\t}\n +\t\t\n +\t\t// Not own constructor property must be Object\n +\t\tif ( obj.constructor\n +\t\t\t&& !hasOwnProperty.call(obj, "constructor")\n +\t\t\t&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {\n +\t\t\treturn false;\n +\t\t}\n +\t\t\n +\t\t// Own properties are enumerated firstly, so to speed up,\n +\t\t// if last one is own, then all properties are own.\n +\t\n +\t\tvar key;\n +\t\tfor ( key in obj ) {}\n +\t\t\n +\t\treturn key === undefined || hasOwnProperty.call( obj, key );\n +\t},\n +\n +\tisEmptyObject: function( obj ) {\n +\t\tfor ( var name in obj ) {\n +\t\t\treturn false;\n +\t\t}\n +\t\treturn true;\n +\t},\n +\t\n +\terror: function( msg ) {\n +\t\tthrow msg;\n +\t},\n +\t\n +\tparseJSON: function( data ) {\n +\t\tif ( typeof data !== "string" || !data ) {\n +\t\t\treturn null;\n +\t\t}\n +\n +\t\t// Make sure leading/trailing whitespace is removed (IE can\'t handle it)\n +\t\tdata = jQuery.trim( data );\n +\t\t\n +\t\t// Make sure the incoming data is actual JSON\n +\t\t// Logic borrowed from http://json.org/json2.js\n +\t\tif ( /^[\\],:{}\\s]*$/.test(data.replace(/\\\\(?:["\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")\n +\t\t\t.replace(/"[^"\\\\\\n\\r]*"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g, "]")\n +\t\t\t.replace(/(?:^|:|,)(?:\\s*\\[)+/g, "")) ) {\n +\n +\t\t\t// Try to use the native JSON parser first\n +\t\t\treturn window.JSON && window.JSON.parse ?\n +\t\t\t\twindow.JSON.parse( data ) :\n +\t\t\t\t(new Function("return " + data))();\n +\n +\t\t} else {\n +\t\t\tjQuery.error( "Invalid JSON: " + data );\n +\t\t}\n +\t},\n +\n +\tnoop: function() {},\n +\n +\t// Evalulates a script in a global context\n +\tglobalEval: function( data ) {\n +\t\tif ( data && rnotwhite.test(data) ) {\n +\t\t\t// Inspired by code by Andrea Giammarchi\n +\t\t\t// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html\n +\t\t\tvar head = document.getElementsByTagName("head")[0] || document.documentElement,\n +\t\t\t\tscript = document.createElement("script");\n +\n +\t\t\tscript.type = "text/javascript";\n +\n +\t\t\tif ( jQuery.support.scriptEval ) {\n +\t\t\t\tscript.appendChild( document.createTextNode( data ) );\n +\t\t\t} else {\n +\t\t\t\tscript.text = data;\n +\t\t\t}\n +\n +\t\t\t// Use insertBefore instead of appendChild to circumvent an IE6 bug.\n +\t\t\t// This arises when a base node is used (#2709).\n +\t\t\thead.insertBefore( script, head.firstChild );\n +\t\t\thead.removeChild( script );\n +\t\t}\n +\t},\n +\n +\tnodeName: function( elem, name ) {\n +\t\treturn elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();\n +\t},\n +\n +\t// args is for internal usage only\n +\teach: function( object, callback, args ) {\n +\t\tvar name, i = 0,\n +\t\t\tlength = object.length,\n +\t\t\tisObj = length === undefined || jQuery.isFunction(object);\n +\n +\t\tif ( args ) {\n +\t\t\tif ( isObj ) {\n +\t\t\t\tfor ( name in object ) {\n +\t\t\t\t\tif ( callback.apply( object[ name ], args ) === false ) {\n +\t\t\t\t\t\tbreak;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t} else {\n +\t\t\t\tfor ( ; i < length; ) {\n +\t\t\t\t\tif ( callback.apply( object[ i++ ], args ) === false ) {\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// A special, fast, case for the most common use of each\n +\t\t} else {\n +\t\t\tif ( isObj ) {\n +\t\t\t\tfor ( name in object ) {\n +\t\t\t\t\tif ( callback.call( object[ name ], name, object[ name ] ) === false ) {\n +\t\t\t\t\t\tbreak;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t} else {\n +\t\t\t\tfor ( var value = object[0];\n +\t\t\t\t\ti < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn object;\n +\t},\n +\n +\ttrim: function( text ) {\n +\t\treturn (text || "").replace( rtrim, "" );\n +\t},\n +\n +\t// results is for internal usage only\n +\tmakeArray: function( array, results ) {\n +\t\tvar ret = results || [];\n +\n +\t\tif ( array != null ) {\n +\t\t\t// The window, strings (and functions) also have \'length\'\n +\t\t\t// The extra typeof function check is to prevent crashes\n +\t\t\t// in Safari 2 (See: #3039)\n +\t\t\tif ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {\n +\t\t\t\tpush.call( ret, array );\n +\t\t\t} else {\n +\t\t\t\tjQuery.merge( ret, array );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret;\n +\t},\n +\n +\tinArray: function( elem, array ) {\n +\t\tif ( array.indexOf ) {\n +\t\t\treturn array.indexOf( elem );\n +\t\t}\n +\n +\t\tfor ( var i = 0, length = array.length; i < length; i++ ) {\n +\t\t\tif ( array[ i ] === elem ) {\n +\t\t\t\treturn i;\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn -1;\n +\t},\n +\n +\tmerge: function( first, second ) {\n +\t\tvar i = first.length, j = 0;\n +\n +\t\tif ( typeof second.length === "number" ) {\n +\t\t\tfor ( var l = second.length; j < l; j++ ) {\n +\t\t\t\tfirst[ i++ ] = second[ j ];\n +\t\t\t}\n +\t\t\n +\t\t} else {\n +\t\t\twhile ( second[j] !== undefined ) {\n +\t\t\t\tfirst[ i++ ] = second[ j++ ];\n +\t\t\t}\n +\t\t}\n +\n +\t\tfirst.length = i;\n +\n +\t\treturn first;\n +\t},\n +\n +\tgrep: function( elems, callback, inv ) {\n +\t\tvar ret = [];\n +\n +\t\t// Go through the array, only saving the items\n +\t\t// that pass the validator function\n +\t\tfor ( var i = 0, length = elems.length; i < length; i++ ) {\n +\t\t\tif ( !inv !== !callback( elems[ i ], i ) ) {\n +\t\t\t\tret.push( elems[ i ] );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret;\n +\t},\n +\n +\t// arg is for internal usage only\n +\tmap: function( elems, callback, arg ) {\n +\t\tvar ret = [], value;\n +\n +\t\t// Go through the array, translating each of the items to their\n +\t\t// new value (or values).\n +\t\tfor ( var i = 0, length = elems.length; i < length; i++ ) {\n +\t\t\tvalue = callback( elems[ i ], i, arg );\n +\n +\t\t\tif ( value != null ) {\n +\t\t\t\tret[ ret.length ] = value;\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret.concat.apply( [], ret );\n +\t},\n +\n +\t// A global GUID counter for objects\n +\tguid: 1,\n +\n +\tproxy: function( fn, proxy, thisObject ) {\n +\t\tif ( arguments.length === 2 ) {\n +\t\t\tif ( typeof proxy === "string" ) {\n +\t\t\t\tthisObject = fn;\n +\t\t\t\tfn = thisObject[ proxy ];\n +\t\t\t\tproxy = undefined;\n +\n +\t\t\t} else if ( proxy && !jQuery.isFunction( proxy ) ) {\n +\t\t\t\tthisObject = proxy;\n +\t\t\t\tproxy = undefined;\n +\t\t\t}\n +\t\t}\n +\n +\t\tif ( !proxy && fn ) {\n +\t\t\tproxy = function() {\n +\t\t\t\treturn fn.apply( thisObject || this, arguments );\n +\t\t\t};\n +\t\t}\n +\n +\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n +\t\tif ( fn ) {\n +\t\t\tproxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;\n +\t\t}\n +\n +\t\t// So proxy can be declared as an argument\n +\t\treturn proxy;\n +\t},\n +\n +\t// Use of jQuery.browser is frowned upon.\n +\t// More details: http://docs.jquery.com/Utilities/jQuery.browser\n +\tuaMatch: function( ua ) {\n +\t\tua = ua.toLowerCase();\n +\n +\t\tvar match = /(webkit)[ \\/]([\\w.]+)/.exec( ua ) ||\n +\t\t\t/(opera)(?:.*version)?[ \\/]([\\w.]+)/.exec( ua ) ||\n +\t\t\t/(msie) ([\\w.]+)/.exec( ua ) ||\n +\t\t\t!/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\\w.]+))?/.exec( ua ) ||\n +\t\t \t[];\n +\n +\t\treturn { browser: match[1] || "", version: match[2] || "0" };\n +\t},\n +\n +\tbrowser: {}\n +});\n +\n +browserMatch = jQuery.uaMatch( userAgent );\n +if ( browserMatch.browser ) {\n +\tjQuery.browser[ browserMatch.browser ] = true;\n +\tjQuery.browser.version = browserMatch.version;\n +}\n +\n +// Deprecated, use jQuery.browser.webkit instead\n +if ( jQuery.browser.webkit ) {\n +\tjQuery.browser.safari = true;\n +}\n +\n +if ( indexOf ) {\n +\tjQuery.inArray = function( elem, array ) {\n +\t\treturn indexOf.call( array, elem );\n +\t};\n +}\n +\n +// All jQuery objects should point back to these\n +rootjQuery = jQuery(document);\n +\n +// Cleanup functions for the document ready method\n +if ( document.addEventListener ) {\n +\tDOMContentLoaded = function() {\n +\t\tdocument.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );\n +\t\tjQuery.ready();\n +\t};\n +\n +} else if ( document.attachEvent ) {\n +\tDOMContentLoaded = function() {\n +\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n +\t\tif ( document.readyState === "complete" ) {\n +\t\t\tdocument.detachEvent( "onreadystatechange", DOMContentLoaded );\n +\t\t\tjQuery.ready();\n +\t\t}\n +\t};\n +}\n +\n +// The DOM ready check for Internet Explorer\n +function doScrollCheck() {\n +\tif ( jQuery.isReady ) {\n +\t\treturn;\n +\t}\n +\n +\ttry {\n +\t\t// If IE is used, use the trick by Diego Perini\n +\t\t// http://javascript.nwbox.com/IEContentLoaded/\n +\t\tdocument.documentElement.doScroll("left");\n +\t} catch( error ) {\n +\t\tsetTimeout( doScrollCheck, 1 );\n +\t\treturn;\n +\t}\n +\n +\t// and execute any waiting functions\n +\tjQuery.ready();\n +}\n +\n +function evalScript( i, elem ) {\n +\tif ( elem.src ) {\n +\t\tjQuery.ajax({\n +\t\t\turl: elem.src,\n +\t\t\tasync: false,\n +\t\t\tdataType: "script"\n +\t\t});\n +\t} else {\n +\t\tjQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );\n +\t}\n +\n +\tif ( elem.parentNode ) {\n +\t\telem.parentNode.removeChild( elem );\n +\t}\n +}\n +\n +// Mutifunctional method to get and set values to a collection\n +// The value/s can be optionally by executed if its a function\n +function access( elems, key, value, exec, fn, pass ) {\n +\tvar length = elems.length;\n +\t\n +\t// Setting many attributes\n +\tif ( typeof key === "object" ) {\n +\t\tfor ( var k in key ) {\n +\t\t\taccess( elems, k, key[k], exec, fn, value );\n +\t\t}\n +\t\treturn elems;\n +\t}\n +\t\n +\t// Setting one attribute\n +\tif ( value !== undefined ) {\n +\t\t// Optionally, function values get executed if exec is true\n +\t\texec = !pass && exec && jQuery.isFunction(value);\n +\t\t\n +\t\tfor ( var i = 0; i < length; i++ ) {\n +\t\t\tfn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );\n +\t\t}\n +\t\t\n +\t\treturn elems;\n +\t}\n +\t\n +\t// Getting an attribute\n +\treturn length ? fn( elems[0], key ) : undefined;\n +}\n +\n +function now() {\n +\treturn (new Date).getTime();\n +}\n +(function() {\n +\n +\tjQuery.support = {};\n +\n +\tvar root = document.documentElement,\n +\t\tscript = document.createElement("script"),\n +\t\tdiv = document.createElement("div"),\n +\t\tid = "script" + now();\n +\n +\tdiv.style.display = "none";\n +\tdiv.innerHTML = " <link/><table></table><a href=\'/a\' style=\'color:red;float:left;opacity:.55;\'>a</a><input type=\'checkbox\'/>";\n +\n +\tvar all = div.getElementsByTagName("*"),\n +\t\ta = div.getElementsByTagName("a")[0];\n +\n +\t// Can\'t get basic test support\n +\tif ( !all || !all.length || !a ) {\n +\t\treturn;\n +\t}\n +\n +\tjQuery.support = {\n +\t\t// IE strips leading whitespace when .innerHTML is used\n +\t\tleadingWhitespace: div.firstChild.nodeType === 3,\n +\n +\t\t// Make sure that tbody elements aren\'t automatically inserted\n +\t\t// IE will insert them into empty tables\n +\t\ttbody: !div.getElementsByTagName("tbody").length,\n +\n +\t\t// Make sure that link elements get serialized correctly by innerHTML\n +\t\t// This requires a wrapper element in IE\n +\t\thtmlSerialize: !!div.getElementsByTagName("link").length,\n +\n +\t\t// Get the style information from getAttribute\n +\t\t// (IE uses .cssText insted)\n +\t\tstyle: /red/.test( a.getAttribute("style") ),\n +\n +\t\t// Make sure that URLs aren\'t manipulated\n +\t\t// (IE normalizes it by default)\n +\t\threfNormalized: a.getAttribute("href") === "/a",\n +\n +\t\t// Make sure that element opacity exists\n +\t\t// (IE uses filter instead)\n +\t\t// Use a regex to work around a WebKit issue. See #5145\n +\t\topacity: /^0.55$/.test( a.style.opacity ),\n +\n +\t\t// Verify style float existence\n +\t\t// (IE uses styleFloat instead of cssFloat)\n +\t\tcssFloat: !!a.style.cssFloat,\n +\n +\t\t// Make sure that if no value is specified for a checkbox\n +\t\t// that it defaults to "on".\n +\t\t// (WebKit defaults to "" instead)\n +\t\tcheckOn: div.getElementsByTagName("input")[0].value === "on",\n +\n +\t\t// Make sure that a selected-by-default option has a working selected property.\n +\t\t// (WebKit defaults to false instead of true, IE too, if it\'s in an optgroup)\n +\t\toptSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,\n +\n +\t\tparentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null,\n +\n +\t\t// Will be defined later\n +\t\tdeleteExpando: true,\n +\t\tcheckClone: false,\n +\t\tscriptEval: false,\n +\t\tnoCloneEvent: true,\n +\t\tboxModel: null\n +\t};\n +\n +\tscript.type = "text/javascript";\n +\ttry {\n +\t\tscript.appendChild( document.createTextNode( "window." + id + "=1;" ) );\n +\t} catch(e) {}\n +\n +\troot.insertBefore( script, root.firstChild );\n +\n +\t// Make sure that the execution of code works by injecting a script\n +\t// tag with appendChild/createTextNode\n +\t// (IE doesn\'t support this, fails, and uses .text instead)\n +\tif ( window[ id ] ) {\n +\t\tjQuery.support.scriptEval = true;\n +\t\tdelete window[ id ];\n +\t}\n +\n +\t// Test to see if it\'s possible to delete an expando from an element\n +\t// Fails in Internet Explorer\n +\ttry {\n +\t\tdelete script.test;\n +\t\n +\t} catch(e) {\n +\t\tjQuery.support.deleteExpando = false;\n +\t}\n +\n +\troot.removeChild( script );\n +\n +\tif ( div.attachEvent && div.fireEvent ) {\n +\t\tdiv.attachEvent("onclick", function click() {\n +\t\t\t// Cloning a node shouldn\'t copy over any\n +\t\t\t// bound event handlers (IE does this)\n +\t\t\tjQuery.support.noCloneEvent = false;\n +\t\t\tdiv.detachEvent("onclick", click);\n +\t\t});\n +\t\tdiv.cloneNode(true).fireEvent("onclick");\n +\t}\n +\n +\tdiv = document.createElement("div");\n +\tdiv.innerHTML = "<input type=\'radio\' name=\'radiotest\' checked=\'checked\'/>";\n +\n +\tvar fragment = document.createDocumentFragment();\n +\tfragment.appendChild( div.firstChild );\n +\n +\t// WebKit doesn\'t clone checked state correctly in fragments\n +\tjQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;\n +\n +\t// Figure out if the W3C box model works as expected\n +\t// document.body must exist before we can do this\n +\tjQuery(function() {\n +\t\tvar div = document.createElement("div");\n +\t\tdiv.style.width = div.style.paddingLeft = "1px";\n +\n +\t\tdocument.body.appendChild( div );\n +\t\tjQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;\n +\t\tdocument.body.removeChild( div ).style.display = \'none\';\n +\n +\t\tdiv = null;\n +\t});\n +\n +\t// Technique from Juriy Zaytsev\n +\t// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/\n +\tvar eventSupported = function( eventName ) { \n +\t\tvar el = document.createElement("div"); \n +\t\teventName = "on" + eventName; \n +\n +\t\tvar isSupported = (eventName in el); \n +\t\tif ( !isSupported ) { \n +\t\t\tel.setAttribute(eventName, "return;"); \n +\t\t\tisSupported = typeof el[eventName] === "function"; \n +\t\t} \n +\t\tel = null; \n +\n +\t\treturn isSupported; \n +\t};\n +\t\n +\tjQuery.support.submitBubbles = eventSupported("submit");\n +\tjQuery.support.changeBubbles = eventSupported("change");\n +\n +\t// release memory in IE\n +\troot = script = div = all = a = null;\n +})();\n +\n +jQuery.props = {\n +\t"for": "htmlFor",\n +\t"class": "className",\n +\treadonly: "readOnly",\n +\tmaxlength: "maxLength",\n +\tcellspacing: "cellSpacing",\n +\trowspan: "rowSpan",\n +\tcolspan: "colSpan",\n +\ttabindex: "tabIndex",\n +\tusemap: "useMap",\n +\tframeborder: "frameBorder"\n +};\n +var expando = "jQuery" + now(), uuid = 0, windowData = {};\n +\n +jQuery.extend({\n +\tcache: {},\n +\t\n +\texpando:expando,\n +\n +\t// The following elements throw uncatchable exceptions if you\n +\t// attempt to add expando properties to them.\n +\tnoData: {\n +\t\t"embed": true,\n +\t\t"object": true,\n +\t\t"applet": true\n +\t},\n +\n +\tdata: function( elem, name, data ) {\n +\t\tif ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\telem = elem == window ?\n +\t\t\twindowData :\n +\t\t\telem;\n +\n +\t\tvar id = elem[ expando ], cache = jQuery.cache, thisCache;\n +\n +\t\tif ( !id && typeof name === "string" && data === undefined ) {\n +\t\t\treturn null;\n +\t\t}\n +\n +\t\t// Compute a unique ID for the element\n +\t\tif ( !id ) { \n +\t\t\tid = ++uuid;\n +\t\t}\n +\n +\t\t// Avoid generating a new cache unless none exists and we\n +\t\t// want to manipulate it.\n +\t\tif ( typeof name === "object" ) {\n +\t\t\telem[ expando ] = id;\n +\t\t\tthisCache = cache[ id ] = jQuery.extend(true, {}, name);\n +\n +\t\t} else if ( !cache[ id ] ) {\n +\t\t\telem[ expando ] = id;\n +\t\t\tcache[ id ] = {};\n +\t\t}\n +\n +\t\tthisCache = cache[ id ];\n +\n +\t\t// Prevent overriding the named cache with undefined values\n +\t\tif ( data !== undefined ) {\n +\t\t\tthisCache[ name ] = data;\n +\t\t}\n +\n +\t\treturn typeof name === "string" ? thisCache[ name ] : thisCache;\n +\t},\n +\n +\tremoveData: function( elem, name ) {\n +\t\tif ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\telem = elem == window ?\n +\t\t\twindowData :\n +\t\t\telem;\n +\n +\t\tvar id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];\n +\n +\t\t// If we want to remove a specific section of the element\'s data\n +\t\tif ( name ) {\n +\t\t\tif ( thisCache ) {\n +\t\t\t\t// Remove the section of cache data\n +\t\t\t\tdelete thisCache[ name ];\n +\n +\t\t\t\t// If we\'ve removed all the data, remove the element\'s cache\n +\t\t\t\tif ( jQuery.isEmptyObject(thisCache) ) {\n +\t\t\t\t\tjQuery.removeData( elem );\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t// Otherwise, we want to remove all of the element\'s data\n +\t\t} else {\n +\t\t\tif ( jQuery.support.deleteExpando ) {\n +\t\t\t\tdelete elem[ jQuery.expando ];\n +\n +\t\t\t} else if ( elem.removeAttribute ) {\n +\t\t\t\telem.removeAttribute( jQuery.expando );\n +\t\t\t}\n +\n +\t\t\t// Completely remove the data cache\n +\t\t\tdelete cache[ id ];\n +\t\t}\n +\t}\n +});\n +\n +jQuery.fn.extend({\n +\tdata: function( key, value ) {\n +\t\tif ( typeof key === "undefined" && this.length ) {\n +\t\t\treturn jQuery.data( this[0] );\n +\n +\t\t} else if ( typeof key === "object" ) {\n +\t\t\treturn this.each(function() {\n +\t\t\t\tjQuery.data( this, key );\n +\t\t\t});\n +\t\t}\n +\n +\t\tvar parts = key.split(".");\n +\t\tparts[1] = parts[1] ? "." + parts[1] : "";\n +\n +\t\tif ( value === undefined ) {\n +\t\t\tvar data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);\n +\n +\t\t\tif ( data === undefined && this.length ) {\n +\t\t\t\tdata = jQuery.data( this[0], key );\n +\t\t\t}\n +\t\t\treturn data === undefined && parts[1] ?\n +\t\t\t\tthis.data( parts[0] ) :\n +\t\t\t\tdata;\n +\t\t} else {\n +\t\t\treturn this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {\n +\t\t\t\tjQuery.data( this, key, value );\n +\t\t\t});\n +\t\t}\n +\t},\n +\n +\tremoveData: function( key ) {\n +\t\treturn this.each(function() {\n +\t\t\tjQuery.removeData( this, key );\n +\t\t});\n +\t}\n +});\n +jQuery.extend({\n +\tqueue: function( elem, type, data ) {\n +\t\tif ( !elem ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\ttype = (type || "fx") + "queue";\n +\t\tvar q = jQuery.data( elem, type );\n +\n +\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n +\t\tif ( !data ) {\n +\t\t\treturn q || [];\n +\t\t}\n +\n +\t\tif ( !q || jQuery.isArray(data) ) {\n +\t\t\tq = jQuery.data( elem, type, jQuery.makeArray(data) );\n +\n +\t\t} else {\n +\t\t\tq.push( data );\n +\t\t}\n +\n +\t\treturn q;\n +\t},\n +\n +\tdequeue: function( elem, type ) {\n +\t\ttype = type || "fx";\n +\n +\t\tvar queue = jQuery.queue( elem, type ), fn = queue.shift();\n +\n +\t\t// If the fx queue is dequeued, always remove the progress sentinel\n +\t\tif ( fn === "inprogress" ) {\n +\t\t\tfn = queue.shift();\n +\t\t}\n +\n +\t\tif ( fn ) {\n +\t\t\t// Add a progress sentinel to prevent the fx queue from being\n +\t\t\t// automatically dequeued\n +\t\t\tif ( type === "fx" ) {\n +\t\t\t\tqueue.unshift("inprogress");\n +\t\t\t}\n +\n +\t\t\tfn.call(elem, function() {\n +\t\t\t\tjQuery.dequeue(elem, type);\n +\t\t\t});\n +\t\t}\n +\t}\n +});\n +\n +jQuery.fn.extend({\n +\tqueue: function( type, data ) {\n +\t\tif ( typeof type !== "string" ) {\n +\t\t\tdata = type;\n +\t\t\ttype = "fx";\n +\t\t}\n +\n +\t\tif ( data === undefined ) {\n +\t\t\treturn jQuery.queue( this[0], type );\n +\t\t}\n +\t\treturn this.each(function( i, elem ) {\n +\t\t\tvar queue = jQuery.queue( this, type, data );\n +\n +\t\t\tif ( type === "fx" && queue[0] !== "inprogress" ) {\n +\t\t\t\tjQuery.dequeue( this, type );\n +\t\t\t}\n +\t\t});\n +\t},\n +\tdequeue: function( type ) {\n +\t\treturn this.each(function() {\n +\t\t\tjQuery.dequeue( this, type );\n +\t\t});\n +\t},\n +\n +\t// Based off of the plugin by Clint Helfers, with permission.\n +\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n +\tdelay: function( time, type ) {\n +\t\ttime = jQuery.fx ? jQuery.fx.speeds[time] || time : time;\n +\t\ttype = type || "fx";\n +\n +\t\treturn this.queue( type, function() {\n +\t\t\tvar elem = this;\n +\t\t\tsetTimeout(function() {\n +\t\t\t\tjQuery.dequeue( elem, type );\n +\t\t\t}, time );\n +\t\t});\n +\t},\n +\n +\tclearQueue: function( type ) {\n +\t\treturn this.queue( type || "fx", [] );\n +\t}\n +});\n +var rclass = /[\\n\\t]/g,\n +\trspace = /\\s+/,\n +\trreturn = /\\r/g,\n +\trspecialurl = /href|src|style/,\n +\trtype = /(button|input)/i,\n +\trfocusable = /(button|input|object|select|textarea)/i,\n +\trclickable = /^(a|area)$/i,\n +\trradiocheck = /radio|checkbox/;\n +\n +jQuery.fn.extend({\n +\tattr: function( name, value ) {\n +\t\treturn access( this, name, value, true, jQuery.attr );\n +\t},\n +\n +\tremoveAttr: function( name, fn ) {\n +\t\treturn this.each(function(){\n +\t\t\tjQuery.attr( this, name, "" );\n +\t\t\tif ( this.nodeType === 1 ) {\n +\t\t\t\tthis.removeAttribute( name );\n +\t\t\t}\n +\t\t});\n +\t},\n +\n +\taddClass: function( value ) {\n +\t\tif ( jQuery.isFunction(value) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tvar self = jQuery(this);\n +\t\t\t\tself.addClass( value.call(this, i, self.attr("class")) );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( value && typeof value === "string" ) {\n +\t\t\tvar classNames = (value || "").split( rspace );\n +\n +\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\tvar elem = this[i];\n +\n +\t\t\t\tif ( elem.nodeType === 1 ) {\n +\t\t\t\t\tif ( !elem.className ) {\n +\t\t\t\t\t\telem.className = value;\n +\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\tvar className = " " + elem.className + " ", setClass = elem.className;\n +\t\t\t\t\t\tfor ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n +\t\t\t\t\t\t\tif ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {\n +\t\t\t\t\t\t\t\tsetClass += " " + classNames[c];\n +\t\t\t\t\t\t\t}\n +\t\t\t\t\t\t}\n +\t\t\t\t\t\telem.className = jQuery.trim( setClass );\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\n +\tremoveClass: function( value ) {\n +\t\tif ( jQuery.isFunction(value) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tvar self = jQuery(this);\n +\t\t\t\tself.removeClass( value.call(this, i, self.attr("class")) );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( (value && typeof value === "string") || value === undefined ) {\n +\t\t\tvar classNames = (value || "").split(rspace);\n +\n +\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\tvar elem = this[i];\n +\n +\t\t\t\tif ( elem.nodeType === 1 && elem.className ) {\n +\t\t\t\t\tif ( value ) {\n +\t\t\t\t\t\tvar className = (" " + elem.className + " ").replace(rclass, " ");\n +\t\t\t\t\t\tfor ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n +\t\t\t\t\t\t\tclassName = className.replace(" " + classNames[c] + " ", " ");\n +\t\t\t\t\t\t}\n +\t\t\t\t\t\telem.className = jQuery.trim( className );\n +\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\telem.className = "";\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\n +\ttoggleClass: function( value, stateVal ) {\n +\t\tvar type = typeof value, isBool = typeof stateVal === "boolean";\n +\n +\t\tif ( jQuery.isFunction( value ) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tvar self = jQuery(this);\n +\t\t\t\tself.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );\n +\t\t\t});\n +\t\t}\n +\n +\t\treturn this.each(function() {\n +\t\t\tif ( type === "string" ) {\n +\t\t\t\t// toggle individual class names\n +\t\t\t\tvar className, i = 0, self = jQuery(this),\n +\t\t\t\t\tstate = stateVal,\n +\t\t\t\t\tclassNames = value.split( rspace );\n +\n +\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n +\t\t\t\t\t// check each className given, space seperated list\n +\t\t\t\t\tstate = isBool ? state : !self.hasClass( className );\n +\t\t\t\t\tself[ state ? "addClass" : "removeClass" ]( className );\n +\t\t\t\t}\n +\n +\t\t\t} else if ( type === "undefined" || type === "boolean" ) {\n +\t\t\t\tif ( this.className ) {\n +\t\t\t\t\t// store className if set\n +\t\t\t\t\tjQuery.data( this, "__className__", this.className );\n +\t\t\t\t}\n +\n +\t\t\t\t// toggle whole className\n +\t\t\t\tthis.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";\n +\t\t\t}\n +\t\t});\n +\t},\n +\n +\thasClass: function( selector ) {\n +\t\tvar className = " " + selector + " ";\n +\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\tif ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {\n +\t\t\t\treturn true;\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn false;\n +\t},\n +\n +\tval: function( value ) {\n +\t\tif ( value === undefined ) {\n +\t\t\tvar elem = this[0];\n +\n +\t\t\tif ( elem ) {\n +\t\t\t\tif ( jQuery.nodeName( elem, "option" ) ) {\n +\t\t\t\t\treturn (elem.attributes.value || {}).specified ? elem.value : elem.text;\n +\t\t\t\t}\n +\n +\t\t\t\t// We need to handle select boxes special\n +\t\t\t\tif ( jQuery.nodeName( elem, "select" ) ) {\n +\t\t\t\t\tvar index = elem.selectedIndex,\n +\t\t\t\t\t\tvalues = [],\n +\t\t\t\t\t\toptions = elem.options,\n +\t\t\t\t\t\tone = elem.type === "select-one";\n +\n +\t\t\t\t\t// Nothing was selected\n +\t\t\t\t\tif ( index < 0 ) {\n +\t\t\t\t\t\treturn null;\n +\t\t\t\t\t}\n +\n +\t\t\t\t\t// Loop through all the selected options\n +\t\t\t\t\tfor ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {\n +\t\t\t\t\t\tvar option = options[ i ];\n +\n +\t\t\t\t\t\tif ( option.selected ) {\n +\t\t\t\t\t\t\t// Get the specifc value for the option\n +\t\t\t\t\t\t\tvalue = jQuery(option).val();\n +\n +\t\t\t\t\t\t\t// We don\'t need an array for one selects\n +\t\t\t\t\t\t\tif ( one ) {\n +\t\t\t\t\t\t\t\treturn value;\n +\t\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\t\t// Multi-Selects return an array\n +\t\t\t\t\t\t\tvalues.push( value );\n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\n +\t\t\t\t\treturn values;\n +\t\t\t\t}\n +\n +\t\t\t\t// Handle the case where in Webkit "" is returned instead of "on" if a value isn\'t specified\n +\t\t\t\tif ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {\n +\t\t\t\t\treturn elem.getAttribute("value") === null ? "on" : elem.value;\n +\t\t\t\t}\n +\t\t\t\t\n +\n +\t\t\t\t// Everything else, we just grab the value\n +\t\t\t\treturn (elem.value || "").replace(rreturn, "");\n +\n +\t\t\t}\n +\n +\t\t\treturn undefined;\n +\t\t}\n +\n +\t\tvar isFunction = jQuery.isFunction(value);\n +\n +\t\treturn this.each(function(i) {\n +\t\t\tvar self = jQuery(this), val = value;\n +\n +\t\t\tif ( this.nodeType !== 1 ) {\n +\t\t\t\treturn;\n +\t\t\t}\n +\n +\t\t\tif ( isFunction ) {\n +\t\t\t\tval = value.call(this, i, self.val());\n +\t\t\t}\n +\n +\t\t\t// Typecast each time if the value is a Function and the appended\n +\t\t\t// value is therefore different each time.\n +\t\t\tif ( typeof val === "number" ) {\n +\t\t\t\tval += "";\n +\t\t\t}\n +\n +\t\t\tif ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {\n +\t\t\t\tthis.checked = jQuery.inArray( self.val(), val ) >= 0;\n +\n +\t\t\t} else if ( jQuery.nodeName( this, "select" ) ) {\n +\t\t\t\tvar values = jQuery.makeArray(val);\n +\n +\t\t\t\tjQuery( "option", this ).each(function() {\n +\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n +\t\t\t\t});\n +\n +\t\t\t\tif ( !values.length ) {\n +\t\t\t\t\tthis.selectedIndex = -1;\n +\t\t\t\t}\n +\n +\t\t\t} else {\n +\t\t\t\tthis.value = val;\n +\t\t\t}\n +\t\t});\n +\t}\n +});\n +\n +jQuery.extend({\n +\tattrFn: {\n +\t\tval: true,\n +\t\tcss: true,\n +\t\thtml: true,\n +\t\ttext: true,\n +\t\tdata: true,\n +\t\twidth: true,\n +\t\theight: true,\n +\t\toffset: true\n +\t},\n +\t\t\n +\tattr: function( elem, name, value, pass ) {\n +\t\t// don\'t set attributes on text and comment nodes\n +\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n +\t\t\treturn undefined;\n +\t\t}\n +\n +\t\tif ( pass && name in jQuery.attrFn ) {\n +\t\t\treturn jQuery(elem)[name](value);\n +\t\t}\n +\n +\t\tvar notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),\n +\t\t\t// Whether we are setting (or getting)\n +\t\t\tset = value !== undefined;\n +\n +\t\t// Try to normalize/fix the name\n +\t\tname = notxml && jQuery.props[ name ] || name;\n +\n +\t\t// Only do all the following if this is a node (faster for style)\n +\t\tif ( elem.nodeType === 1 ) {\n +\t\t\t// These attributes require special treatment\n +\t\t\tvar special = rspecialurl.test( name );\n +\n +\t\t\t// Safari mis-reports the default selected property of an option\n +\t\t\t// Accessing the parent\'s selectedIndex property fixes it\n +\t\t\tif ( name === "selected" && !jQuery.support.optSelected ) {\n +\t\t\t\tvar parent = elem.parentNode;\n +\t\t\t\tif ( parent ) {\n +\t\t\t\t\tparent.selectedIndex;\n +\t\n +\t\t\t\t\t// Make sure that it also works with optgroups, see #5701\n +\t\t\t\t\tif ( parent.parentNode ) {\n +\t\t\t\t\t\tparent.parentNode.selectedIndex;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\t// If applicable, access the attribute via the DOM 0 way\n +\t\t\tif ( name in elem && notxml && !special ) {\n +\t\t\t\tif ( set ) {\n +\t\t\t\t\t// We can\'t allow the type property to be changed (since it causes problems in IE)\n +\t\t\t\t\tif ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {\n +\t\t\t\t\t\tjQuery.error( "type property can\'t be changed" );\n +\t\t\t\t\t}\n +\n +\t\t\t\t\telem[ name ] = value;\n +\t\t\t\t}\n +\n +\t\t\t\t// browsers index elements by id/name on forms, give priority to attributes.\n +\t\t\t\tif ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {\n +\t\t\t\t\treturn elem.getAttributeNode( name ).nodeValue;\n +\t\t\t\t}\n +\n +\t\t\t\t// elem.tabIndex doesn\'t always return the correct value when it hasn\'t been explicitly set\n +\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n +\t\t\t\tif ( name === "tabIndex" ) {\n +\t\t\t\t\tvar attributeNode = elem.getAttributeNode( "tabIndex" );\n +\n +\t\t\t\t\treturn attributeNode && attributeNode.specified ?\n +\t\t\t\t\t\tattributeNode.value :\n +\t\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n +\t\t\t\t\t\t\t0 :\n +\t\t\t\t\t\t\tundefined;\n +\t\t\t\t}\n +\n +\t\t\t\treturn elem[ name ];\n +\t\t\t}\n +\n +\t\t\tif ( !jQuery.support.style && notxml && name === "style" ) {\n +\t\t\t\tif ( set ) {\n +\t\t\t\t\telem.style.cssText = "" + value;\n +\t\t\t\t}\n +\n +\t\t\t\treturn elem.style.cssText;\n +\t\t\t}\n +\n +\t\t\tif ( set ) {\n +\t\t\t\t// convert the value to a string (all browsers do this but IE) see #1070\n +\t\t\t\telem.setAttribute( name, "" + value );\n +\t\t\t}\n +\n +\t\t\tvar attr = !jQuery.support.hrefNormalized && notxml && special ?\n +\t\t\t\t\t// Some attributes require a special call on IE\n +\t\t\t\t\telem.getAttribute( name, 2 ) :\n +\t\t\t\t\telem.getAttribute( name );\n +\n +\t\t\t// Non-existent attributes return null, we normalize to undefined\n +\t\t\treturn attr === null ? undefined : attr;\n +\t\t}\n +\n +\t\t// elem is actually elem.style ... set the style\n +\t\t// Using attr for specific style information is now deprecated. Use style instead.\n +\t\treturn jQuery.style( elem, name, value );\n +\t}\n +});\n +var rnamespaces = /\\.(.*)$/,\n +\tfcleanup = function( nm ) {\n +\t\treturn nm.replace(/[^\\w\\s\\.\\|`]/g, function( ch ) {\n +\t\t\treturn "\\\\" + ch;\n +\t\t});\n +\t};\n +\n +/*\n + * A number of helper functions used for managing events.\n + * Many of the ideas behind this code originated from\n + * Dean Edwards\' addEvent library.\n + */\n +jQuery.event = {\n +\n +\t// Bind an event to an element\n +\t// Original by Dean Edwards\n +\tadd: function( elem, types, handler, data ) {\n +\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\t// For whatever reason, IE has trouble passing the window object\n +\t\t// around, causing it to be cloned in the process\n +\t\tif ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {\n +\t\t\telem = window;\n +\t\t}\n +\n +\t\tvar handleObjIn, handleObj;\n +\n +\t\tif ( handler.handler ) {\n +\t\t\thandleObjIn = handler;\n +\t\t\thandler = handleObjIn.handler;\n +\t\t}\n +\n +\t\t// Make sure that the function being executed has a unique ID\n +\t\tif ( !handler.guid ) {\n +\t\t\thandler.guid = jQuery.guid++;\n +\t\t}\n +\n +\t\t// Init the element\'s event structure\n +\t\tvar elemData = jQuery.data( elem );\n +\n +\t\t// If no elemData is found then we must be trying to bind to one of the\n +\t\t// banned noData elements\n +\t\tif ( !elemData ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\tvar events = elemData.events = elemData.events || {},\n +\t\t\teventHandle = elemData.handle, eventHandle;\n +\n +\t\tif ( !eventHandle ) {\n +\t\t\telemData.handle = eventHandle = function() {\n +\t\t\t\t// Handle the second event of a trigger and when\n +\t\t\t\t// an event is called after a page has unloaded\n +\t\t\t\treturn typeof jQuery !== "undefined" && !jQuery.event.triggered ?\n +\t\t\t\t\tjQuery.event.handle.apply( eventHandle.elem, arguments ) :\n +\t\t\t\t\tundefined;\n +\t\t\t};\n +\t\t}\n +\n +\t\t// Add elem as a property of the handle function\n +\t\t// This is to prevent a memory leak with non-native events in IE.\n +\t\teventHandle.elem = elem;\n +\n +\t\t// Handle multiple events separated by a space\n +\t\t// jQuery(...).bind("mouseover mouseout", fn);\n +\t\ttypes = types.split(" ");\n +\n +\t\tvar type, i = 0, namespaces;\n +\n +\t\twhile ( (type = types[ i++ ]) ) {\n +\t\t\thandleObj = handleObjIn ?\n +\t\t\t\tjQuery.extend({}, handleObjIn) :\n +\t\t\t\t{ handler: handler, data: data };\n +\n +\t\t\t// Namespaced event handlers\n +\t\t\tif ( type.indexOf(".") > -1 ) {\n +\t\t\t\tnamespaces = type.split(".");\n +\t\t\t\ttype = namespaces.shift();\n +\t\t\t\thandleObj.namespace = namespaces.slice(0).sort().join(".");\n +\n +\t\t\t} else {\n +\t\t\t\tnamespaces = [];\n +\t\t\t\thandleObj.namespace = "";\n +\t\t\t}\n +\n +\t\t\thandleObj.type = type;\n +\t\t\thandleObj.guid = handler.guid;\n +\n +\t\t\t// Get the current list of functions bound to this event\n +\t\t\tvar handlers = events[ type ],\n +\t\t\t\tspecial = jQuery.event.special[ type ] || {};\n +\n +\t\t\t// Init the event handler queue\n +\t\t\tif ( !handlers ) {\n +\t\t\t\thandlers = events[ type ] = [];\n +\n +\t\t\t\t// Check for a special event handler\n +\t\t\t\t// Only use addEventListener/attachEvent if the special\n +\t\t\t\t// events handler returns false\n +\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n +\t\t\t\t\t// Bind the global event handler to the element\n +\t\t\t\t\tif ( elem.addEventListener ) {\n +\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n +\n +\t\t\t\t\t} else if ( elem.attachEvent ) {\n +\t\t\t\t\t\telem.attachEvent( "on" + type, eventHandle );\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t}\n +\t\t\t\n +\t\t\tif ( special.add ) { \n +\t\t\t\tspecial.add.call( elem, handleObj ); \n +\n +\t\t\t\tif ( !handleObj.handler.guid ) {\n +\t\t\t\t\thandleObj.handler.guid = handler.guid;\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\t// Add the function to the element\'s handler list\n +\t\t\thandlers.push( handleObj );\n +\n +\t\t\t// Keep track of which events have been used, for global triggering\n +\t\t\tjQuery.event.global[ type ] = true;\n +\t\t}\n +\n +\t\t// Nullify elem to prevent memory leaks in IE\n +\t\telem = null;\n +\t},\n +\n +\tglobal: {},\n +\n +\t// Detach an event or set of events from an element\n +\tremove: function( elem, types, handler, pos ) {\n +\t\t// don\'t do events on text and comment nodes\n +\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\tvar ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,\n +\t\t\telemData = jQuery.data( elem ),\n +\t\t\tevents = elemData && elemData.events;\n +\n +\t\tif ( !elemData || !events ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\t// types is actually an event object here\n +\t\tif ( types && types.type ) {\n +\t\t\thandler = types.handler;\n +\t\t\ttypes = types.type;\n +\t\t}\n +\n +\t\t// Unbind all events for the element\n +\t\tif ( !types || typeof types === "string" && types.charAt(0) === "." ) {\n +\t\t\ttypes = types || "";\n +\n +\t\t\tfor ( type in events ) {\n +\t\t\t\tjQuery.event.remove( elem, type + types );\n +\t\t\t}\n +\n +\t\t\treturn;\n +\t\t}\n +\n +\t\t// Handle multiple events separated by a space\n +\t\t// jQuery(...).unbind("mouseover mouseout", fn);\n +\t\ttypes = types.split(" ");\n +\n +\t\twhile ( (type = types[ i++ ]) ) {\n +\t\t\torigType = type;\n +\t\t\thandleObj = null;\n +\t\t\tall = type.indexOf(".") < 0;\n +\t\t\tnamespaces = [];\n +\n +\t\t\tif ( !all ) {\n +\t\t\t\t// Namespaced event handlers\n +\t\t\t\tnamespaces = type.split(".");\n +\t\t\t\ttype = namespaces.shift();\n +\n +\t\t\t\tnamespace = new RegExp("(^|\\\\.)" + \n +\t\t\t\t\tjQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\\\.(?:.*\\\\.)?") + "(\\\\.|$)")\n +\t\t\t}\n +\n +\t\t\teventType = events[ type ];\n +\n +\t\t\tif ( !eventType ) {\n +\t\t\t\tcontinue;\n +\t\t\t}\n +\n +\t\t\tif ( !handler ) {\n +\t\t\t\tfor ( var j = 0; j < eventType.length; j++ ) {\n +\t\t\t\t\thandleObj = eventType[ j ];\n +\n +\t\t\t\t\tif ( all || namespace.test( handleObj.namespace ) ) {\n +\t\t\t\t\t\tjQuery.event.remove( elem, origType, handleObj.handler, j );\n +\t\t\t\t\t\teventType.splice( j--, 1 );\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\tcontinue;\n +\t\t\t}\n +\n +\t\t\tspecial = jQuery.event.special[ type ] || {};\n +\n +\t\t\tfor ( var j = pos || 0; j < eventType.length; j++ ) {\n +\t\t\t\thandleObj = eventType[ j ];\n +\n +\t\t\t\tif ( handler.guid === handleObj.guid ) {\n +\t\t\t\t\t// remove the given handler for the given type\n +\t\t\t\t\tif ( all || namespace.test( handleObj.namespace ) ) {\n +\t\t\t\t\t\tif ( pos == null ) {\n +\t\t\t\t\t\t\teventType.splice( j--, 1 );\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\tif ( special.remove ) {\n +\t\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\n +\t\t\t\t\tif ( pos != null ) {\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\t// remove generic event handler if no more handlers exist\n +\t\t\tif ( eventType.length === 0 || pos != null && eventType.length === 1 ) {\n +\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {\n +\t\t\t\t\tremoveEvent( elem, type, elemData.handle );\n +\t\t\t\t}\n +\n +\t\t\t\tret = null;\n +\t\t\t\tdelete events[ type ];\n +\t\t\t}\n +\t\t}\n +\n +\t\t// Remove the expando if it\'s no longer used\n +\t\tif ( jQuery.isEmptyObject( events ) ) {\n +\t\t\tvar handle = elemData.handle;\n +\t\t\tif ( handle ) {\n +\t\t\t\thandle.elem = null;\n +\t\t\t}\n +\n +\t\t\tdelete elemData.events;\n +\t\t\tdelete elemData.handle;\n +\n +\t\t\tif ( jQuery.isEmptyObject( elemData ) ) {\n +\t\t\t\tjQuery.removeData( elem );\n +\t\t\t}\n +\t\t}\n +\t},\n +\n +\t// bubbling is internal\n +\ttrigger: function( event, data, elem /*, bubbling */ ) {\n +\t\t// Event object or event type\n +\t\tvar type = event.type || event,\n +\t\t\tbubbling = arguments[3];\n +\n +\t\tif ( !bubbling ) {\n +\t\t\tevent = typeof event === "object" ?\n +\t\t\t\t// jQuery.Event object\n +\t\t\t\tevent[expando] ? event :\n +\t\t\t\t// Object literal\n +\t\t\t\tjQuery.extend( jQuery.Event(type), event ) :\n +\t\t\t\t// Just the event type (string)\n +\t\t\t\tjQuery.Event(type);\n +\n +\t\t\tif ( type.indexOf("!") >= 0 ) {\n +\t\t\t\tevent.type = type = type.slice(0, -1);\n +\t\t\t\tevent.exclusive = true;\n +\t\t\t}\n +\n +\t\t\t// Handle a global trigger\n +\t\t\tif ( !elem ) {\n +\t\t\t\t// Don\'t bubble custom events when global (to avoid too much overhead)\n +\t\t\t\tevent.stopPropagation();\n +\n +\t\t\t\t// Only trigger if we\'ve ever bound an event for it\n +\t\t\t\tif ( jQuery.event.global[ type ] ) {\n +\t\t\t\t\tjQuery.each( jQuery.cache, function() {\n +\t\t\t\t\t\tif ( this.events && this.events[type] ) {\n +\t\t\t\t\t\t\tjQuery.event.trigger( event, data, this.handle.elem );\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// Handle triggering a single element\n +\n +\t\t\t// don\'t do events on text and comment nodes\n +\t\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n +\t\t\t\treturn undefined;\n +\t\t\t}\n +\n +\t\t\t// Clean up in case it is reused\n +\t\t\tevent.result = undefined;\n +\t\t\tevent.target = elem;\n +\n +\t\t\t// Clone the incoming data, if any\n +\t\t\tdata = jQuery.makeArray( data );\n +\t\t\tdata.unshift( event );\n +\t\t}\n +\n +\t\tevent.currentTarget = elem;\n +\n +\t\t// Trigger the event, it is assumed that "handle" is a function\n +\t\tvar handle = jQuery.data( elem, "handle" );\n +\t\tif ( handle ) {\n +\t\t\thandle.apply( elem, data );\n +\t\t}\n +\n +\t\tvar parent = elem.parentNode || elem.ownerDocument;\n +\n +\t\t// Trigger an inline bound script\n +\t\ttry {\n +\t\t\tif ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {\n +\t\t\t\tif ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {\n +\t\t\t\t\tevent.result = false;\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t// prevent IE from throwing an error for some elements with some event types, see #3533\n +\t\t} catch (e) {}\n +\n +\t\tif ( !event.isPropagationStopped() && parent ) {\n +\t\t\tjQuery.event.trigger( event, data, parent, true );\n +\n +\t\t} else if ( !event.isDefaultPrevented() ) {\n +\t\t\tvar target = event.target, old,\n +\t\t\t\tisClick = jQuery.nodeName(target, "a") && type === "click",\n +\t\t\t\tspecial = jQuery.event.special[ type ] || {};\n +\n +\t\t\tif ( (!special._default || special._default.call( elem, event ) === false) && \n +\t\t\t\t!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {\n +\n +\t\t\t\ttry {\n +\t\t\t\t\tif ( target[ type ] ) {\n +\t\t\t\t\t\t// Make sure that we don\'t accidentally re-trigger the onFOO events\n +\t\t\t\t\t\told = target[ "on" + type ];\n +\n +\t\t\t\t\t\tif ( old ) {\n +\t\t\t\t\t\t\ttarget[ "on" + type ] = null;\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\tjQuery.event.triggered = true;\n +\t\t\t\t\t\ttarget[ type ]();\n +\t\t\t\t\t}\n +\n +\t\t\t\t// prevent IE from throwing an error for some elements with some event types, see #3533\n +\t\t\t\t} catch (e) {}\n +\n +\t\t\t\tif ( old ) {\n +\t\t\t\t\ttarget[ "on" + type ] = old;\n +\t\t\t\t}\n +\n +\t\t\t\tjQuery.event.triggered = false;\n +\t\t\t}\n +\t\t}\n +\t},\n +\n +\thandle: function( event ) {\n +\t\tvar all, handlers, namespaces, namespace, events;\n +\n +\t\tevent = arguments[0] = jQuery.event.fix( event || window.event );\n +\t\tevent.currentTarget = this;\n +\n +\t\t// Namespaced event handlers\n +\t\tall = event.type.indexOf(".") < 0 && !event.exclusive;\n +\n +\t\tif ( !all ) {\n +\t\t\tnamespaces = event.type.split(".");\n +\t\t\tevent.type = namespaces.shift();\n +\t\t\tnamespace = new RegExp("(^|\\\\.)" + namespaces.slice(0).sort().join("\\\\.(?:.*\\\\.)?") + "(\\\\.|$)");\n +\t\t}\n +\n +\t\tvar events = jQuery.data(this, "events"), handlers = events[ event.type ];\n +\n +\t\tif ( events && handlers ) {\n +\t\t\t// Clone the handlers to prevent manipulation\n +\t\t\thandlers = handlers.slice(0);\n +\n +\t\t\tfor ( var j = 0, l = handlers.length; j < l; j++ ) {\n +\t\t\t\tvar handleObj = handlers[ j ];\n +\n +\t\t\t\t// Filter the functions by class\n +\t\t\t\tif ( all || namespace.test( handleObj.namespace ) ) {\n +\t\t\t\t\t// Pass in a reference to the handler function itself\n +\t\t\t\t\t// So that we can later remove it\n +\t\t\t\t\tevent.handler = handleObj.handler;\n +\t\t\t\t\tevent.data = handleObj.data;\n +\t\t\t\t\tevent.handleObj = handleObj;\n +\t\n +\t\t\t\t\tvar ret = handleObj.handler.apply( this, arguments );\n +\n +\t\t\t\t\tif ( ret !== undefined ) {\n +\t\t\t\t\t\tevent.result = ret;\n +\t\t\t\t\t\tif ( ret === false ) {\n +\t\t\t\t\t\t\tevent.preventDefault();\n +\t\t\t\t\t\t\tevent.stopPropagation();\n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\n +\t\t\t\t\tif ( event.isImmediatePropagationStopped() ) {\n +\t\t\t\t\t\tbreak;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn event.result;\n +\t},\n +\n +\tprops: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),\n +\n +\tfix: function( event ) {\n +\t\tif ( event[ expando ] ) {\n +\t\t\treturn event;\n +\t\t}\n +\n +\t\t// store a copy of the original event object\n +\t\t// and "clone" to set read-only properties\n +\t\tvar originalEvent = event;\n +\t\tevent = jQuery.Event( originalEvent );\n +\n +\t\tfor ( var i = this.props.length, prop; i; ) {\n +\t\t\tprop = this.props[ --i ];\n +\t\t\tevent[ prop ] = originalEvent[ prop ];\n +\t\t}\n +\n +\t\t// Fix target property, if necessary\n +\t\tif ( !event.target ) {\n +\t\t\tevent.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either\n +\t\t}\n +\n +\t\t// check if target is a textnode (safari)\n +\t\tif ( event.target.nodeType === 3 ) {\n +\t\t\tevent.target = event.target.parentNode;\n +\t\t}\n +\n +\t\t// Add relatedTarget, if necessary\n +\t\tif ( !event.relatedTarget && event.fromElement ) {\n +\t\t\tevent.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;\n +\t\t}\n +\n +\t\t// Calculate pageX/Y if missing and clientX/Y available\n +\t\tif ( event.pageX == null && event.clientX != null ) {\n +\t\t\tvar doc = document.documentElement, body = document.body;\n +\t\t\tevent.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);\n +\t\t\tevent.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);\n +\t\t}\n +\n +\t\t// Add which for key events\n +\t\tif ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {\n +\t\t\tevent.which = event.charCode || event.keyCode;\n +\t\t}\n +\n +\t\t// Add metaKey to non-Mac browsers (use ctrl for PC\'s and Meta for Macs)\n +\t\tif ( !event.metaKey && event.ctrlKey ) {\n +\t\t\tevent.metaKey = event.ctrlKey;\n +\t\t}\n +\n +\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n +\t\t// Note: button is not normalized, so don\'t use it\n +\t\tif ( !event.which && event.button !== undefined ) {\n +\t\t\tevent.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));\n +\t\t}\n +\n +\t\treturn event;\n +\t},\n +\n +\t// Deprecated, use jQuery.guid instead\n +\tguid: 1E8,\n +\n +\t// Deprecated, use jQuery.proxy instead\n +\tproxy: jQuery.proxy,\n +\n +\tspecial: {\n +\t\tready: {\n +\t\t\t// Make sure the ready event is setup\n +\t\t\tsetup: jQuery.bindReady,\n +\t\t\tteardown: jQuery.noop\n +\t\t},\n +\n +\t\tlive: {\n +\t\t\tadd: function( handleObj ) {\n +\t\t\t\tjQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); \n +\t\t\t},\n +\n +\t\t\tremove: function( handleObj ) {\n +\t\t\t\tvar remove = true,\n +\t\t\t\t\ttype = handleObj.origType.replace(rnamespaces, "");\n +\t\t\t\t\n +\t\t\t\tjQuery.each( jQuery.data(this, "events").live || [], function() {\n +\t\t\t\t\tif ( type === this.origType.replace(rnamespaces, "") ) {\n +\t\t\t\t\t\tremove = false;\n +\t\t\t\t\t\treturn false;\n +\t\t\t\t\t}\n +\t\t\t\t});\n +\n +\t\t\t\tif ( remove ) {\n +\t\t\t\t\tjQuery.event.remove( this, handleObj.origType, liveHandler );\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t},\n +\n +\t\tbeforeunload: {\n +\t\t\tsetup: function( data, namespaces, eventHandle ) {\n +\t\t\t\t// We only want to do this special case on windows\n +\t\t\t\tif ( this.setInterval ) {\n +\t\t\t\t\tthis.onbeforeunload = eventHandle;\n +\t\t\t\t}\n +\n +\t\t\t\treturn false;\n +\t\t\t},\n +\t\t\tteardown: function( namespaces, eventHandle ) {\n +\t\t\t\tif ( this.onbeforeunload === eventHandle ) {\n +\t\t\t\t\tthis.onbeforeunload = null;\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t}\n +};\n +\n +var removeEvent = document.removeEventListener ?\n +\tfunction( elem, type, handle ) {\n +\t\telem.removeEventListener( type, handle, false );\n +\t} : \n +\tfunction( elem, type, handle ) {\n +\t\telem.detachEvent( "on" + type, handle );\n +\t};\n +\n +jQuery.Event = function( src ) {\n +\t// Allow instantiation without the \'new\' keyword\n +\tif ( !this.preventDefault ) {\n +\t\treturn new jQuery.Event( src );\n +\t}\n +\n +\t// Event object\n +\tif ( src && src.type ) {\n +\t\tthis.originalEvent = src;\n +\t\tthis.type = src.type;\n +\t// Event type\n +\t} else {\n +\t\tthis.type = src;\n +\t}\n +\n +\t// timeStamp is buggy for some events on Firefox(#3843)\n +\t// So we won\'t rely on the native value\n +\tthis.timeStamp = now();\n +\n +\t// Mark it as fixed\n +\tthis[ expando ] = true;\n +};\n +\n +function returnFalse() {\n +\treturn false;\n +}\n +function returnTrue() {\n +\treturn true;\n +}\n +\n +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\n +jQuery.Event.prototype = {\n +\tpreventDefault: function() {\n +\t\tthis.isDefaultPrevented = returnTrue;\n +\n +\t\tvar e = this.originalEvent;\n +\t\tif ( !e ) {\n +\t\t\treturn;\n +\t\t}\n +\t\t\n +\t\t// if preventDefault exists run it on the original event\n +\t\tif ( e.preventDefault ) {\n +\t\t\te.preventDefault();\n +\t\t}\n +\t\t// otherwise set the returnValue property of the original event to false (IE)\n +\t\te.returnValue = false;\n +\t},\n +\tstopPropagation: function() {\n +\t\tthis.isPropagationStopped = returnTrue;\n +\n +\t\tvar e = this.originalEvent;\n +\t\tif ( !e ) {\n +\t\t\treturn;\n +\t\t}\n +\t\t// if stopPropagation exists run it on the original event\n +\t\tif ( e.stopPropagation ) {\n +\t\t\te.stopPropagation();\n +\t\t}\n +\t\t// otherwise set the cancelBubble property of the original event to true (IE)\n +\t\te.cancelBubble = true;\n +\t},\n +\tstopImmediatePropagation: function() {\n +\t\tthis.isImmediatePropagationStopped = returnTrue;\n +\t\tthis.stopPropagation();\n +\t},\n +\tisDefaultPrevented: returnFalse,\n +\tisPropagationStopped: returnFalse,\n +\tisImmediatePropagationStopped: returnFalse\n +};\n +\n +// Checks if an event happened on an element within another element\n +// Used in jQuery.event.special.mouseenter and mouseleave handlers\n +var withinElement = function( event ) {\n +\t// Check if mouse(over|out) are still within the same parent element\n +\tvar parent = event.relatedTarget;\n +\n +\t// Firefox sometimes assigns relatedTarget a XUL element\n +\t// which we cannot access the parentNode property of\n +\ttry {\n +\t\t// Traverse up the tree\n +\t\twhile ( parent && parent !== this ) {\n +\t\t\tparent = parent.parentNode;\n +\t\t}\n +\n +\t\tif ( parent !== this ) {\n +\t\t\t// set the correct event type\n +\t\t\tevent.type = event.data;\n +\n +\t\t\t// handle event if we actually just moused on to a non sub-element\n +\t\t\tjQuery.event.handle.apply( this, arguments );\n +\t\t}\n +\n +\t// assuming we\'ve left the element since we most likely mousedover a xul element\n +\t} catch(e) { }\n +},\n +\n +// In case of event delegation, we only need to rename the event.type,\n +// liveHandler will take care of the rest.\n +delegate = function( event ) {\n +\tevent.type = event.data;\n +\tjQuery.event.handle.apply( this, arguments );\n +};\n +\n +// Create mouseenter and mouseleave events\n +jQuery.each({\n +\tmouseenter: "mouseover",\n +\tmouseleave: "mouseout"\n +}, function( orig, fix ) {\n +\tjQuery.event.special[ orig ] = {\n +\t\tsetup: function( data ) {\n +\t\t\tjQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );\n +\t\t},\n +\t\tteardown: function( data ) {\n +\t\t\tjQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );\n +\t\t}\n +\t};\n +});\n +\n +// submit delegation\n +if ( !jQuery.support.submitBubbles ) {\n +\n +\tjQuery.event.special.submit = {\n +\t\tsetup: function( data, namespaces ) {\n +\t\t\tif ( this.nodeName.toLowerCase() !== "form" ) {\n +\t\t\t\tjQuery.event.add(this, "click.specialSubmit", function( e ) {\n +\t\t\t\t\tvar elem = e.target, type = elem.type;\n +\n +\t\t\t\t\tif ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {\n +\t\t\t\t\t\treturn trigger( "submit", this, arguments );\n +\t\t\t\t\t}\n +\t\t\t\t});\n +\t \n +\t\t\t\tjQuery.event.add(this, "keypress.specialSubmit", function( e ) {\n +\t\t\t\t\tvar elem = e.target, type = elem.type;\n +\n +\t\t\t\t\tif ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {\n +\t\t\t\t\t\treturn trigger( "submit", this, arguments );\n +\t\t\t\t\t}\n +\t\t\t\t});\n +\n +\t\t\t} else {\n +\t\t\t\treturn false;\n +\t\t\t}\n +\t\t},\n +\n +\t\tteardown: function( namespaces ) {\n +\t\t\tjQuery.event.remove( this, ".specialSubmit" );\n +\t\t}\n +\t};\n +\n +}\n +\n +// change delegation, happens here so we have bind.\n +if ( !jQuery.support.changeBubbles ) {\n +\n +\tvar formElems = /textarea|input|select/i,\n +\n +\tchangeFilters,\n +\n +\tgetVal = function( elem ) {\n +\t\tvar type = elem.type, val = elem.value;\n +\n +\t\tif ( type === "radio" || type === "checkbox" ) {\n +\t\t\tval = elem.checked;\n +\n +\t\t} else if ( type === "select-multiple" ) {\n +\t\t\tval = elem.selectedIndex > -1 ?\n +\t\t\t\tjQuery.map( elem.options, function( elem ) {\n +\t\t\t\t\treturn elem.selected;\n +\t\t\t\t}).join("-") :\n +\t\t\t\t"";\n +\n +\t\t} else if ( elem.nodeName.toLowerCase() === "select" ) {\n +\t\t\tval = elem.selectedIndex;\n +\t\t}\n +\n +\t\treturn val;\n +\t},\n +\n +\ttestChange = function testChange( e ) {\n +\t\tvar elem = e.target, data, val;\n +\n +\t\tif ( !formElems.test( elem.nodeName ) || elem.readOnly ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\tdata = jQuery.data( elem, "_change_data" );\n +\t\tval = getVal(elem);\n +\n +\t\t// the current data will be also retrieved by beforeactivate\n +\t\tif ( e.type !== "focusout" || elem.type !== "radio" ) {\n +\t\t\tjQuery.data( elem, "_change_data", val );\n +\t\t}\n +\t\t\n +\t\tif ( data === undefined || val === data ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\tif ( data != null || val ) {\n +\t\t\te.type = "change";\n +\t\t\treturn jQuery.event.trigger( e, arguments[1], elem );\n +\t\t}\n +\t};\n +\n +\tjQuery.event.special.change = {\n +\t\tfilters: {\n +\t\t\tfocusout: testChange, \n +\n +\t\t\tclick: function( e ) {\n +\t\t\t\tvar elem = e.target, type = elem.type;\n +\n +\t\t\t\tif ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {\n +\t\t\t\t\treturn testChange.call( this, e );\n +\t\t\t\t}\n +\t\t\t},\n +\n +\t\t\t// Change has to be called before submit\n +\t\t\t// Keydown will be called before keypress, which is used in submit-event delegation\n +\t\t\tkeydown: function( e ) {\n +\t\t\t\tvar elem = e.target, type = elem.type;\n +\n +\t\t\t\tif ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||\n +\t\t\t\t\t(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||\n +\t\t\t\t\ttype === "select-multiple" ) {\n +\t\t\t\t\treturn testChange.call( this, e );\n +\t\t\t\t}\n +\t\t\t},\n +\n +\t\t\t// Beforeactivate happens also before the previous element is blurred\n +\t\t\t// with this event you can\'t trigger a change event, but you can store\n +\t\t\t// information/focus[in] is not needed anymore\n +\t\t\tbeforeactivate: function( e ) {\n +\t\t\t\tvar elem = e.target;\n +\t\t\t\tjQuery.data( elem, "_change_data", getVal(elem) );\n +\t\t\t}\n +\t\t},\n +\n +\t\tsetup: function( data, namespaces ) {\n +\t\t\tif ( this.type === "file" ) {\n +\t\t\t\treturn false;\n +\t\t\t}\n +\n +\t\t\tfor ( var type in changeFilters ) {\n +\t\t\t\tjQuery.event.add( this, type + ".specialChange", changeFilters[type] );\n +\t\t\t}\n +\n +\t\t\treturn formElems.test( this.nodeName );\n +\t\t},\n +\n +\t\tteardown: function( namespaces ) {\n +\t\t\tjQuery.event.remove( this, ".specialChange" );\n +\n +\t\t\treturn formElems.test( this.nodeName );\n +\t\t}\n +\t};\n +\n +\tchangeFilters = jQuery.event.special.change.filters;\n +}\n +\n +function trigger( type, elem, args ) {\n +\targs[0].type = type;\n +\treturn jQuery.event.handle.apply( elem, args );\n +}\n +\n +// Create "bubbling" focus and blur events\n +if ( document.addEventListener ) {\n +\tjQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {\n +\t\tjQuery.event.special[ fix ] = {\n +\t\t\tsetup: function() {\n +\t\t\t\tthis.addEventListener( orig, handler, true );\n +\t\t\t}, \n +\t\t\tteardown: function() { \n +\t\t\t\tthis.removeEventListener( orig, handler, true );\n +\t\t\t}\n +\t\t};\n +\n +\t\tfunction handler( e ) { \n +\t\t\te = jQuery.event.fix( e );\n +\t\t\te.type = fix;\n +\t\t\treturn jQuery.event.handle.call( this, e );\n +\t\t}\n +\t});\n +}\n +\n +jQuery.each(["bind", "one"], function( i, name ) {\n +\tjQuery.fn[ name ] = function( type, data, fn ) {\n +\t\t// Handle object literals\n +\t\tif ( typeof type === "object" ) {\n +\t\t\tfor ( var key in type ) {\n +\t\t\t\tthis[ name ](key, data, type[key], fn);\n +\t\t\t}\n +\t\t\treturn this;\n +\t\t}\n +\t\t\n +\t\tif ( jQuery.isFunction( data ) ) {\n +\t\t\tfn = data;\n +\t\t\tdata = undefined;\n +\t\t}\n +\n +\t\tvar handler = name === "one" ? jQuery.proxy( fn, function( event ) {\n +\t\t\tjQuery( this ).unbind( event, handler );\n +\t\t\treturn fn.apply( this, arguments );\n +\t\t}) : fn;\n +\n +\t\tif ( type === "unload" && name !== "one" ) {\n +\t\t\tthis.one( type, data, fn );\n +\n +\t\t} else {\n +\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\tjQuery.event.add( this[i], type, handler, data );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn this;\n +\t};\n +});\n +\n +jQuery.fn.extend({\n +\tunbind: function( type, fn ) {\n +\t\t// Handle object literals\n +\t\tif ( typeof type === "object" && !type.preventDefault ) {\n +\t\t\tfor ( var key in type ) {\n +\t\t\t\tthis.unbind(key, type[key]);\n +\t\t\t}\n +\n +\t\t} else {\n +\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\tjQuery.event.remove( this[i], type, fn );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\t\n +\tdelegate: function( selector, types, data, fn ) {\n +\t\treturn this.live( types, data, fn, selector );\n +\t},\n +\t\n +\tundelegate: function( selector, types, fn ) {\n +\t\tif ( arguments.length === 0 ) {\n +\t\t\t\treturn this.unbind( "live" );\n +\t\t\n +\t\t} else {\n +\t\t\treturn this.die( types, null, fn, selector );\n +\t\t}\n +\t},\n +\t\n +\ttrigger: function( type, data ) {\n +\t\treturn this.each(function() {\n +\t\t\tjQuery.event.trigger( type, data, this );\n +\t\t});\n +\t},\n +\n +\ttriggerHandler: function( type, data ) {\n +\t\tif ( this[0] ) {\n +\t\t\tvar event = jQuery.Event( type );\n +\t\t\tevent.preventDefault();\n +\t\t\tevent.stopPropagation();\n +\t\t\tjQuery.event.trigger( event, data, this[0] );\n +\t\t\treturn event.result;\n +\t\t}\n +\t},\n +\n +\ttoggle: function( fn ) {\n +\t\t// Save reference to arguments for access in closure\n +\t\tvar args = arguments, i = 1;\n +\n +\t\t// link all the functions, so any of them can unbind this click handler\n +\t\twhile ( i < args.length ) {\n +\t\t\tjQuery.proxy( fn, args[ i++ ] );\n +\t\t}\n +\n +\t\treturn this.click( jQuery.proxy( fn, function( event ) {\n +\t\t\t// Figure out which function to execute\n +\t\t\tvar lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;\n +\t\t\tjQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );\n +\n +\t\t\t// Make sure that clicks stop\n +\t\t\tevent.preventDefault();\n +\n +\t\t\t// and execute the function\n +\t\t\treturn args[ lastToggle ].apply( this, arguments ) || false;\n +\t\t}));\n +\t},\n +\n +\thover: function( fnOver, fnOut ) {\n +\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n +\t}\n +});\n +\n +var liveMap = {\n +\tfocus: "focusin",\n +\tblur: "focusout",\n +\tmouseenter: "mouseover",\n +\tmouseleave: "mouseout"\n +};\n +\n +jQuery.each(["live", "die"], function( i, name ) {\n +\tjQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {\n +\t\tvar type, i = 0, match, namespaces, preType,\n +\t\t\tselector = origSelector || this.selector,\n +\t\t\tcontext = origSelector ? this : jQuery( this.context );\n +\n +\t\tif ( jQuery.isFunction( data ) ) {\n +\t\t\tfn = data;\n +\t\t\tdata = undefined;\n +\t\t}\n +\n +\t\ttypes = (types || "").split(" ");\n +\n +\t\twhile ( (type = types[ i++ ]) != null ) {\n +\t\t\tmatch = rnamespaces.exec( type );\n +\t\t\tnamespaces = "";\n +\n +\t\t\tif ( match ) {\n +\t\t\t\tnamespaces = match[0];\n +\t\t\t\ttype = type.replace( rnamespaces, "" );\n +\t\t\t}\n +\n +\t\t\tif ( type === "hover" ) {\n +\t\t\t\ttypes.push( "mouseenter" + namespaces, "mouseleave" + namespaces );\n +\t\t\t\tcontinue;\n +\t\t\t}\n +\n +\t\t\tpreType = type;\n +\n +\t\t\tif ( type === "focus" || type === "blur" ) {\n +\t\t\t\ttypes.push( liveMap[ type ] + namespaces );\n +\t\t\t\ttype = type + namespaces;\n +\n +\t\t\t} else {\n +\t\t\t\ttype = (liveMap[ type ] || type) + namespaces;\n +\t\t\t}\n +\n +\t\t\tif ( name === "live" ) {\n +\t\t\t\t// bind live handler\n +\t\t\t\tcontext.each(function(){\n +\t\t\t\t\tjQuery.event.add( this, liveConvert( type, selector ),\n +\t\t\t\t\t\t{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );\n +\t\t\t\t});\n +\n +\t\t\t} else {\n +\t\t\t\t// unbind live handler\n +\t\t\t\tcontext.unbind( liveConvert( type, selector ), fn );\n +\t\t\t}\n +\t\t}\n +\t\t\n +\t\treturn this;\n +\t}\n +});\n +\n +function liveHandler( event ) {\n +\tvar stop, elems = [], selectors = [], args = arguments,\n +\t\trelated, match, handleObj, elem, j, i, l, data,\n +\t\tevents = jQuery.data( this, "events" );\n +\n +\t// Make sure we avoid non-left-click bubbling in Firefox (#3861)\n +\tif ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {\n +\t\treturn;\n +\t}\n +\n +\tevent.liveFired = this;\n +\n +\tvar live = events.live.slice(0);\n +\n +\tfor ( j = 0; j < live.length; j++ ) {\n +\t\thandleObj = live[j];\n +\n +\t\tif ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {\n +\t\t\tselectors.push( handleObj.selector );\n +\n +\t\t} else {\n +\t\t\tlive.splice( j--, 1 );\n +\t\t}\n +\t}\n +\n +\tmatch = jQuery( event.target ).closest( selectors, event.currentTarget );\n +\n +\tfor ( i = 0, l = match.length; i < l; i++ ) {\n +\t\tfor ( j = 0; j < live.length; j++ ) {\n +\t\t\thandleObj = live[j];\n +\n +\t\t\tif ( match[i].selector === handleObj.selector ) {\n +\t\t\t\telem = match[i].elem;\n +\t\t\t\trelated = null;\n +\n +\t\t\t\t// Those two events require additional checking\n +\t\t\t\tif ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {\n +\t\t\t\t\trelated = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];\n +\t\t\t\t}\n +\n +\t\t\t\tif ( !related || related !== elem ) {\n +\t\t\t\t\telems.push({ elem: elem, handleObj: handleObj });\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t}\n +\n +\tfor ( i = 0, l = elems.length; i < l; i++ ) {\n +\t\tmatch = elems[i];\n +\t\tevent.currentTarget = match.elem;\n +\t\tevent.data = match.handleObj.data;\n +\t\tevent.handleObj = match.handleObj;\n +\n +\t\tif ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {\n +\t\t\tstop = false;\n +\t\t\tbreak;\n +\t\t}\n +\t}\n +\n +\treturn stop;\n +}\n +\n +function liveConvert( type, selector ) {\n +\treturn "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\\./g, "`").replace(/ /g, "&");\n +}\n +\n +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +\n +\t"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +\n +\t"change select submit keydown keypress keyup error").split(" "), function( i, name ) {\n +\n +\t// Handle event binding\n +\tjQuery.fn[ name ] = function( fn ) {\n +\t\treturn fn ? this.bind( name, fn ) : this.trigger( name );\n +\t};\n +\n +\tif ( jQuery.attrFn ) {\n +\t\tjQuery.attrFn[ name ] = true;\n +\t}\n +});\n +\n +// Prevent memory leaks in IE\n +// Window isn\'t included so as not to unbind existing unload events\n +// More info:\n +// - http://isaacschlueter.com/2006/10/msie-memory-leaks/\n +if ( window.attachEvent && !window.addEventListener ) {\n +\twindow.attachEvent("onunload", function() {\n +\t\tfor ( var id in jQuery.cache ) {\n +\t\t\tif ( jQuery.cache[ id ].handle ) {\n +\t\t\t\t// Try/Catch is to handle iframes being unloaded, see #4280\n +\t\t\t\ttry {\n +\t\t\t\t\tjQuery.event.remove( jQuery.cache[ id ].handle.elem );\n +\t\t\t\t} catch(e) {}\n +\t\t\t}\n +\t\t}\n +\t});\n +}\n +/*!\n + * Sizzle CSS Selector Engine - v1.0\n + * Copyright 2009, The Dojo Foundation\n + * Released under the MIT, BSD, and GPL Licenses.\n + * More information: http://sizzlejs.com/\n + */\n +(function(){\n +\n +var chunker = /((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^[\\]]*\\]|[\'"][^\'"]*[\'"]|[^[\\]\'"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,\n +\tdone = 0,\n +\ttoString = Object.prototype.toString,\n +\thasDuplicate = false,\n +\tbaseHasDuplicate = true;\n +\n +// Here we check if the JavaScript engine is using some sort of\n +// optimization where it does not always call our comparision\n +// function. If that is the case, discard the hasDuplicate value.\n +// Thus far that includes Google Chrome.\n +[0, 0].sort(function(){\n +\tbaseHasDuplicate = false;\n +\treturn 0;\n +});\n +\n +var Sizzle = function(selector, context, results, seed) {\n +\tresults = results || [];\n +\tvar origContext = context = context || document;\n +\n +\tif ( context.nodeType !== 1 && context.nodeType !== 9 ) {\n +\t\treturn [];\n +\t}\n +\t\n +\tif ( !selector || typeof selector !== "string" ) {\n +\t\treturn results;\n +\t}\n +\n +\tvar parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),\n +\t\tsoFar = selector;\n +\t\n +\t// Reset the position of the chunker regexp (start from head)\n +\twhile ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {\n +\t\tsoFar = m[3];\n +\t\t\n +\t\tparts.push( m[1] );\n +\t\t\n +\t\tif ( m[2] ) {\n +\t\t\textra = m[3];\n +\t\t\tbreak;\n +\t\t}\n +\t}\n +\n +\tif ( parts.length > 1 && origPOS.exec( selector ) ) {\n +\t\tif ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\n +\t\t\tset = posProcess( parts[0] + parts[1], context );\n +\t\t} else {\n +\t\t\tset = Expr.relative[ parts[0] ] ?\n +\t\t\t\t[ context ] :\n +\t\t\t\tSizzle( parts.shift(), context );\n +\n +\t\t\twhile ( parts.length ) {\n +\t\t\t\tselector = parts.shift();\n +\n +\t\t\t\tif ( Expr.relative[ selector ] ) {\n +\t\t\t\t\tselector += parts.shift();\n +\t\t\t\t}\n +\t\t\t\t\n +\t\t\t\tset = posProcess( selector, set );\n +\t\t\t}\n +\t\t}\n +\t} else {\n +\t\t// Take a shortcut and set the context if the root selector is an ID\n +\t\t// (but not if it\'ll be faster if the inner selector is an ID)\n +\t\tif ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\n +\t\t\t\tExpr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\n +\t\t\tvar ret = Sizzle.find( parts.shift(), context, contextXML );\n +\t\t\tcontext = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];\n +\t\t}\n +\n +\t\tif ( context ) {\n +\t\t\tvar ret = seed ?\n +\t\t\t\t{ expr: parts.pop(), set: makeArray(seed) } :\n +\t\t\t\tSizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );\n +\t\t\tset = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;\n +\n +\t\t\tif ( parts.length > 0 ) {\n +\t\t\t\tcheckSet = makeArray(set);\n +\t\t\t} else {\n +\t\t\t\tprune = false;\n +\t\t\t}\n +\n +\t\t\twhile ( parts.length ) {\n +\t\t\t\tvar cur = parts.pop(), pop = cur;\n +\n +\t\t\t\tif ( !Expr.relative[ cur ] ) {\n +\t\t\t\t\tcur = "";\n +\t\t\t\t} else {\n +\t\t\t\t\tpop = parts.pop();\n +\t\t\t\t}\n +\n +\t\t\t\tif ( pop == null ) {\n +\t\t\t\t\tpop = context;\n +\t\t\t\t}\n +\n +\t\t\t\tExpr.relative[ cur ]( checkSet, pop, contextXML );\n +\t\t\t}\n +\t\t} else {\n +\t\t\tcheckSet = parts = [];\n +\t\t}\n +\t}\n +\n +\tif ( !checkSet ) {\n +\t\tcheckSet = set;\n +\t}\n +\n +\tif ( !checkSet ) {\n +\t\tSizzle.error( cur || selector );\n +\t}\n +\n +\tif ( toString.call(checkSet) === "[object Array]" ) {\n +\t\tif ( !prune ) {\n +\t\t\tresults.push.apply( results, checkSet );\n +\t\t} else if ( context && context.nodeType === 1 ) {\n +\t\t\tfor ( var i = 0; checkSet[i] != null; i++ ) {\n +\t\t\t\tif ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {\n +\t\t\t\t\tresults.push( set[i] );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t} else {\n +\t\t\tfor ( var i = 0; checkSet[i] != null; i++ ) {\n +\t\t\t\tif ( checkSet[i] && checkSet[i].nodeType === 1 ) {\n +\t\t\t\t\tresults.push( set[i] );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t} else {\n +\t\tmakeArray( checkSet, results );\n +\t}\n +\n +\tif ( extra ) {\n +\t\tSizzle( extra, origContext, results, seed );\n +\t\tSizzle.uniqueSort( results );\n +\t}\n +\n +\treturn results;\n +};\n +\n +Sizzle.uniqueSort = function(results){\n +\tif ( sortOrder ) {\n +\t\thasDuplicate = baseHasDuplicate;\n +\t\tresults.sort(sortOrder);\n +\n +\t\tif ( hasDuplicate ) {\n +\t\t\tfor ( var i = 1; i < results.length; i++ ) {\n +\t\t\t\tif ( results[i] === results[i-1] ) {\n +\t\t\t\t\tresults.splice(i--, 1);\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t}\n +\n +\treturn results;\n +};\n +\n +Sizzle.matches = function(expr, set){\n +\treturn Sizzle(expr, null, null, set);\n +};\n +\n +Sizzle.find = function(expr, context, isXML){\n +\tvar set, match;\n +\n +\tif ( !expr ) {\n +\t\treturn [];\n +\t}\n +\n +\tfor ( var i = 0, l = Expr.order.length; i < l; i++ ) {\n +\t\tvar type = Expr.order[i], match;\n +\t\t\n +\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\n +\t\t\tvar left = match[1];\n +\t\t\tmatch.splice(1,1);\n +\n +\t\t\tif ( left.substr( left.length - 1 ) !== "\\\\" ) {\n +\t\t\t\tmatch[1] = (match[1] || "").replace(/\\\\/g, "");\n +\t\t\t\tset = Expr.find[ type ]( match, context, isXML );\n +\t\t\t\tif ( set != null ) {\n +\t\t\t\t\texpr = expr.replace( Expr.match[ type ], "" );\n +\t\t\t\t\tbreak;\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t}\n +\n +\tif ( !set ) {\n +\t\tset = context.getElementsByTagName("*");\n +\t}\n +\n +\treturn {set: set, expr: expr};\n +};\n +\n +Sizzle.filter = function(expr, set, inplace, not){\n +\tvar old = expr, result = [], curLoop = set, match, anyFound,\n +\t\tisXMLFilter = set && set[0] && isXML(set[0]);\n +\n +\twhile ( expr && set.length ) {\n +\t\tfor ( var type in Expr.filter ) {\n +\t\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\n +\t\t\t\tvar filter = Expr.filter[ type ], found, item, left = match[1];\n +\t\t\t\tanyFound = false;\n +\n +\t\t\t\tmatch.splice(1,1);\n +\n +\t\t\t\tif ( left.substr( left.length - 1 ) === "\\\\" ) {\n +\t\t\t\t\tcontinue;\n +\t\t\t\t}\n +\n +\t\t\t\tif ( curLoop === result ) {\n +\t\t\t\t\tresult = [];\n +\t\t\t\t}\n +\n +\t\t\t\tif ( Expr.preFilter[ type ] ) {\n +\t\t\t\t\tmatch = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\n +\n +\t\t\t\t\tif ( !match ) {\n +\t\t\t\t\t\tanyFound = found = true;\n +\t\t\t\t\t} else if ( match === true ) {\n +\t\t\t\t\t\tcontinue;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\tif ( match ) {\n +\t\t\t\t\tfor ( var i = 0; (item = curLoop[i]) != null; i++ ) {\n +\t\t\t\t\t\tif ( item ) {\n +\t\t\t\t\t\t\tfound = filter( item, match, i, curLoop );\n +\t\t\t\t\t\t\tvar pass = not ^ !!found;\n +\n +\t\t\t\t\t\t\tif ( inplace && found != null ) {\n +\t\t\t\t\t\t\t\tif ( pass ) {\n +\t\t\t\t\t\t\t\t\tanyFound = true;\n +\t\t\t\t\t\t\t\t} else {\n +\t\t\t\t\t\t\t\t\tcurLoop[i] = false;\n +\t\t\t\t\t\t\t\t}\n +\t\t\t\t\t\t\t} else if ( pass ) {\n +\t\t\t\t\t\t\t\tresult.push( item );\n +\t\t\t\t\t\t\t\tanyFound = true;\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 +\n +\t\t\t\tif ( found !== undefined ) {\n +\t\t\t\t\tif ( !inplace ) {\n +\t\t\t\t\t\tcurLoop = result;\n +\t\t\t\t\t}\n +\n +\t\t\t\t\texpr = expr.replace( Expr.match[ type ], "" );\n +\n +\t\t\t\t\tif ( !anyFound ) {\n +\t\t\t\t\t\treturn [];\n +\t\t\t\t\t}\n +\n +\t\t\t\t\tbreak;\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\n +\t\t// Improper expression\n +\t\tif ( expr === old ) {\n +\t\t\tif ( anyFound == null ) {\n +\t\t\t\tSizzle.error( expr );\n +\t\t\t} else {\n +\t\t\t\tbreak;\n +\t\t\t}\n +\t\t}\n +\n +\t\told = expr;\n +\t}\n +\n +\treturn curLoop;\n +};\n +\n +Sizzle.error = function( msg ) {\n +\tthrow "Syntax error, unrecognized expression: " + msg;\n +};\n +\n +var Expr = Sizzle.selectors = {\n +\torder: [ "ID", "NAME", "TAG" ],\n +\tmatch: {\n +\t\tID: /#((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)/,\n +\t\tCLASS: /\\.((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)/,\n +\t\tNAME: /\\[name=[\'"]*((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)[\'"]*\\]/,\n +\t\tATTR: /\\[\\s*((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)\\s*(?:(\\S?=)\\s*([\'"]*)(.*?)\\3|)\\s*\\]/,\n +\t\tTAG: /^((?:[\\w\\u00c0-\\uFFFF\\*-]|\\\\.)+)/,\n +\t\tCHILD: /:(only|nth|last|first)-child(?:\\((even|odd|[\\dn+-]*)\\))?/,\n +\t\tPOS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^-]|$)/,\n +\t\tPSEUDO: /:((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)(?:\\(([\'"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/\n +\t},\n +\tleftMatch: {},\n +\tattrMap: {\n +\t\t"class": "className",\n +\t\t"for": "htmlFor"\n +\t},\n +\tattrHandle: {\n +\t\thref: function(elem){\n +\t\t\treturn elem.getAttribute("href");\n +\t\t}\n +\t},\n +\trelative: {\n +\t\t"+": function(checkSet, part){\n +\t\t\tvar isPartStr = typeof part === "string",\n +\t\t\t\tisTag = isPartStr && !/\\W/.test(part),\n +\t\t\t\tisPartStrNotTag = isPartStr && !isTag;\n +\n +\t\t\tif ( isTag ) {\n +\t\t\t\tpart = part.toLowerCase();\n +\t\t\t}\n +\n +\t\t\tfor ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\n +\t\t\t\tif ( (elem = checkSet[i]) ) {\n +\t\t\t\t\twhile ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\n +\n +\t\t\t\t\tcheckSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\n +\t\t\t\t\t\telem || false :\n +\t\t\t\t\t\telem === part;\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\tif ( isPartStrNotTag ) {\n +\t\t\t\tSizzle.filter( part, checkSet, true );\n +\t\t\t}\n +\t\t},\n +\t\t">": function(checkSet, part){\n +\t\t\tvar isPartStr = typeof part === "string";\n +\n +\t\t\tif ( isPartStr && !/\\W/.test(part) ) {\n +\t\t\t\tpart = part.toLowerCase();\n +\n +\t\t\t\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n +\t\t\t\t\tvar elem = checkSet[i];\n +\t\t\t\t\tif ( elem ) {\n +\t\t\t\t\t\tvar parent = elem.parentNode;\n +\t\t\t\t\t\tcheckSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t} else {\n +\t\t\t\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n +\t\t\t\t\tvar elem = checkSet[i];\n +\t\t\t\t\tif ( elem ) {\n +\t\t\t\t\t\tcheckSet[i] = isPartStr ?\n +\t\t\t\t\t\t\telem.parentNode :\n +\t\t\t\t\t\t\telem.parentNode === part;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\tif ( isPartStr ) {\n +\t\t\t\t\tSizzle.filter( part, checkSet, true );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t},\n +\t\t"": function(checkSet, part, isXML){\n +\t\t\tvar doneName = done++, checkFn = dirCheck;\n +\n +\t\t\tif ( typeof part === "string" && !/\\W/.test(part) ) {\n +\t\t\t\tvar nodeCheck = part = part.toLowerCase();\n +\t\t\t\tcheckFn = dirNodeCheck;\n +\t\t\t}\n +\n +\t\t\tcheckFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);\n +\t\t},\n +\t\t"~": function(checkSet, part, isXML){\n +\t\t\tvar doneName = done++, checkFn = dirCheck;\n +\n +\t\t\tif ( typeof part === "string" && !/\\W/.test(part) ) {\n +\t\t\t\tvar nodeCheck = part = part.toLowerCase();\n +\t\t\t\tcheckFn = dirNodeCheck;\n +\t\t\t}\n +\n +\t\t\tcheckFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);\n +\t\t}\n +\t},\n +\tfind: {\n +\t\tID: function(match, context, isXML){\n +\t\t\tif ( typeof context.getElementById !== "undefined" && !isXML ) {\n +\t\t\t\tvar m = context.getElementById(match[1]);\n +\t\t\t\treturn m ? [m] : [];\n +\t\t\t}\n +\t\t},\n +\t\tNAME: function(match, context){\n +\t\t\tif ( typeof context.getElementsByName !== "undefined" ) {\n +\t\t\t\tvar ret = [], results = context.getElementsByName(match[1]);\n +\n +\t\t\t\tfor ( var i = 0, l = results.length; i < l; i++ ) {\n +\t\t\t\t\tif ( results[i].getAttribute("name") === match[1] ) {\n +\t\t\t\t\t\tret.push( results[i] );\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\treturn ret.length === 0 ? null : ret;\n +\t\t\t}\n +\t\t},\n +\t\tTAG: function(match, context){\n +\t\t\treturn context.getElementsByTagName(match[1]);\n +\t\t}\n +\t},\n +\tpreFilter: {\n +\t\tCLASS: function(match, curLoop, inplace, result, not, isXML){\n +\t\t\tmatch = " " + match[1].replace(/\\\\/g, "") + " ";\n +\n +\t\t\tif ( isXML ) {\n +\t\t\t\treturn match;\n +\t\t\t}\n +\n +\t\t\tfor ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\n +\t\t\t\tif ( elem ) {\n +\t\t\t\t\tif ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\\t\\n]/g, " ").indexOf(match) >= 0) ) {\n +\t\t\t\t\t\tif ( !inplace ) {\n +\t\t\t\t\t\t\tresult.push( elem );\n +\t\t\t\t\t\t}\n +\t\t\t\t\t} else if ( inplace ) {\n +\t\t\t\t\t\tcurLoop[i] = false;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\treturn false;\n +\t\t},\n +\t\tID: function(match){\n +\t\t\treturn match[1].replace(/\\\\/g, "");\n +\t\t},\n +\t\tTAG: function(match, curLoop){\n +\t\t\treturn match[1].toLowerCase();\n +\t\t},\n +\t\tCHILD: function(match){\n +\t\t\tif ( match[1] === "nth" ) {\n +\t\t\t\t// parse equations like \'even\', \'odd\', \'5\', \'2n\', \'3n+2\', \'4n-1\', \'-n+6\'\n +\t\t\t\tvar test = /(-?)(\\d*)n((?:\\+|-)?\\d*)/.exec(\n +\t\t\t\t\tmatch[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||\n +\t\t\t\t\t!/\\D/.test( match[2] ) && "0n+" + match[2] || match[2]);\n +\n +\t\t\t\t// calculate the numbers (first)n+(last) including if they are negative\n +\t\t\t\tmatch[2] = (test[1] + (test[2] || 1)) - 0;\n +\t\t\t\tmatch[3] = test[3] - 0;\n +\t\t\t}\n +\n +\t\t\t// TODO: Move to normal caching system\n +\t\t\tmatch[0] = done++;\n +\n +\t\t\treturn match;\n +\t\t},\n +\t\tATTR: function(match, curLoop, inplace, result, not, isXML){\n +\t\t\tvar name = match[1].replace(/\\\\/g, "");\n +\t\t\t\n +\t\t\tif ( !isXML && Expr.attrMap[name] ) {\n +\t\t\t\tmatch[1] = Expr.attrMap[name];\n +\t\t\t}\n +\n +\t\t\tif ( match[2] === "~=" ) {\n +\t\t\t\tmatch[4] = " " + match[4] + " ";\n +\t\t\t}\n +\n +\t\t\treturn match;\n +\t\t},\n +\t\tPSEUDO: function(match, curLoop, inplace, result, not){\n +\t\t\tif ( match[1] === "not" ) {\n +\t\t\t\t// If we\'re dealing with a complex expression, or a simple one\n +\t\t\t\tif ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\\w/.test(match[3]) ) {\n +\t\t\t\t\tmatch[3] = Sizzle(match[3], null, null, curLoop);\n +\t\t\t\t} else {\n +\t\t\t\t\tvar ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\n +\t\t\t\t\tif ( !inplace ) {\n +\t\t\t\t\t\tresult.push.apply( result, ret );\n +\t\t\t\t\t}\n +\t\t\t\t\treturn false;\n +\t\t\t\t}\n +\t\t\t} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\n +\t\t\t\treturn true;\n +\t\t\t}\n +\t\t\t\n +\t\t\treturn match;\n +\t\t},\n +\t\tPOS: function(match){\n +\t\t\tmatch.unshift( true );\n +\t\t\treturn match;\n +\t\t}\n +\t},\n +\tfilters: {\n +\t\tenabled: function(elem){\n +\t\t\treturn elem.disabled === false && elem.type !== "hidden";\n +\t\t},\n +\t\tdisabled: function(elem){\n +\t\t\treturn elem.disabled === true;\n +\t\t},\n +\t\tchecked: function(elem){\n +\t\t\treturn elem.checked === true;\n +\t\t},\n +\t\tselected: function(elem){\n +\t\t\t// Accessing this property makes selected-by-default\n +\t\t\t// options in Safari work properly\n +\t\t\telem.parentNode.selectedIndex;\n +\t\t\treturn elem.selected === true;\n +\t\t},\n +\t\tparent: function(elem){\n +\t\t\treturn !!elem.firstChild;\n +\t\t},\n +\t\tempty: function(elem){\n +\t\t\treturn !elem.firstChild;\n +\t\t},\n +\t\thas: function(elem, i, match){\n +\t\t\treturn !!Sizzle( match[3], elem ).length;\n +\t\t},\n +\t\theader: function(elem){\n +\t\t\treturn /h\\d/i.test( elem.nodeName );\n +\t\t},\n +\t\ttext: function(elem){\n +\t\t\treturn "text" === elem.type;\n +\t\t},\n +\t\tradio: function(elem){\n +\t\t\treturn "radio" === elem.type;\n +\t\t},\n +\t\tcheckbox: function(elem){\n +\t\t\treturn "checkbox" === elem.type;\n +\t\t},\n +\t\tfile: function(elem){\n +\t\t\treturn "file" === elem.type;\n +\t\t},\n +\t\tpassword: function(elem){\n +\t\t\treturn "password" === elem.type;\n +\t\t},\n +\t\tsubmit: function(elem){\n +\t\t\treturn "submit" === elem.type;\n +\t\t},\n +\t\timage: function(elem){\n +\t\t\treturn "image" === elem.type;\n +\t\t},\n +\t\treset: function(elem){\n +\t\t\treturn "reset" === elem.type;\n +\t\t},\n +\t\tbutton: function(elem){\n +\t\t\treturn "button" === elem.type || elem.nodeName.toLowerCase() === "button";\n +\t\t},\n +\t\tinput: function(elem){\n +\t\t\treturn /input|select|textarea|button/i.test(elem.nodeName);\n +\t\t}\n +\t},\n +\tsetFilters: {\n +\t\tfirst: function(elem, i){\n +\t\t\treturn i === 0;\n +\t\t},\n +\t\tlast: function(elem, i, match, array){\n +\t\t\treturn i === array.length - 1;\n +\t\t},\n +\t\teven: function(elem, i){\n +\t\t\treturn i % 2 === 0;\n +\t\t},\n +\t\todd: function(elem, i){\n +\t\t\treturn i % 2 === 1;\n +\t\t},\n +\t\tlt: function(elem, i, match){\n +\t\t\treturn i < match[3] - 0;\n +\t\t},\n +\t\tgt: function(elem, i, match){\n +\t\t\treturn i > match[3] - 0;\n +\t\t},\n +\t\tnth: function(elem, i, match){\n +\t\t\treturn match[3] - 0 === i;\n +\t\t},\n +\t\teq: function(elem, i, match){\n +\t\t\treturn match[3] - 0 === i;\n +\t\t}\n +\t},\n +\tfilter: {\n +\t\tPSEUDO: function(elem, match, i, array){\n +\t\t\tvar name = match[1], filter = Expr.filters[ name ];\n +\n +\t\t\tif ( filter ) {\n +\t\t\t\treturn filter( elem, i, match, array );\n +\t\t\t} else if ( name === "contains" ) {\n +\t\t\t\treturn (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;\n +\t\t\t} else if ( name === "not" ) {\n +\t\t\t\tvar not = match[3];\n +\n +\t\t\t\tfor ( var i = 0, l = not.length; i < l; i++ ) {\n +\t\t\t\t\tif ( not[i] === elem ) {\n +\t\t\t\t\t\treturn false;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\treturn true;\n +\t\t\t} else {\n +\t\t\t\tSizzle.error( "Syntax error, unrecognized expression: " + name );\n +\t\t\t}\n +\t\t},\n +\t\tCHILD: function(elem, match){\n +\t\t\tvar type = match[1], node = elem;\n +\t\t\tswitch (type) {\n +\t\t\t\tcase \'only\':\n +\t\t\t\tcase \'first\':\n +\t\t\t\t\twhile ( (node = node.previousSibling) )\t {\n +\t\t\t\t\t\tif ( node.nodeType === 1 ) { \n +\t\t\t\t\t\t\treturn false; \n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\t\t\t\t\tif ( type === "first" ) { \n +\t\t\t\t\t\treturn true; \n +\t\t\t\t\t}\n +\t\t\t\t\tnode = elem;\n +\t\t\t\tcase \'last\':\n +\t\t\t\t\twhile ( (node = node.nextSibling) )\t {\n +\t\t\t\t\t\tif ( node.nodeType === 1 ) { \n +\t\t\t\t\t\t\treturn false; \n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\t\t\t\t\treturn true;\n +\t\t\t\tcase \'nth\':\n +\t\t\t\t\tvar first = match[2], last = match[3];\n +\n +\t\t\t\t\tif ( first === 1 && last === 0 ) {\n +\t\t\t\t\t\treturn true;\n +\t\t\t\t\t}\n +\t\t\t\t\t\n +\t\t\t\t\tvar doneName = match[0],\n +\t\t\t\t\t\tparent = elem.parentNode;\n +\t\n +\t\t\t\t\tif ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {\n +\t\t\t\t\t\tvar count = 0;\n +\t\t\t\t\t\tfor ( node = parent.firstChild; node; node = node.nextSibling ) {\n +\t\t\t\t\t\t\tif ( node.nodeType === 1 ) {\n +\t\t\t\t\t\t\t\tnode.nodeIndex = ++count;\n +\t\t\t\t\t\t\t}\n +\t\t\t\t\t\t} \n +\t\t\t\t\t\tparent.sizcache = doneName;\n +\t\t\t\t\t}\n +\t\t\t\t\t\n +\t\t\t\t\tvar diff = elem.nodeIndex - last;\n +\t\t\t\t\tif ( first === 0 ) {\n +\t\t\t\t\t\treturn diff === 0;\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\treturn ( diff % first === 0 && diff / first >= 0 );\n +\t\t\t\t\t}\n +\t\t\t}\n +\t\t},\n +\t\tID: function(elem, match){\n +\t\t\treturn elem.nodeType === 1 && elem.getAttribute("id") === match;\n +\t\t},\n +\t\tTAG: function(elem, match){\n +\t\t\treturn (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;\n +\t\t},\n +\t\tCLASS: function(elem, match){\n +\t\t\treturn (" " + (elem.className || elem.getAttribute("class")) + " ")\n +\t\t\t\t.indexOf( match ) > -1;\n +\t\t},\n +\t\tATTR: function(elem, match){\n +\t\t\tvar name = match[1],\n +\t\t\t\tresult = Expr.attrHandle[ name ] ?\n +\t\t\t\t\tExpr.attrHandle[ name ]( elem ) :\n +\t\t\t\t\telem[ name ] != null ?\n +\t\t\t\t\t\telem[ name ] :\n +\t\t\t\t\t\telem.getAttribute( name ),\n +\t\t\t\tvalue = result + "",\n +\t\t\t\ttype = match[2],\n +\t\t\t\tcheck = match[4];\n +\n +\t\t\treturn result == null ?\n +\t\t\t\ttype === "!=" :\n +\t\t\t\ttype === "=" ?\n +\t\t\t\tvalue === check :\n +\t\t\t\ttype === "*=" ?\n +\t\t\t\tvalue.indexOf(check) >= 0 :\n +\t\t\t\ttype === "~=" ?\n +\t\t\t\t(" " + value + " ").indexOf(check) >= 0 :\n +\t\t\t\t!check ?\n +\t\t\t\tvalue && result !== false :\n +\t\t\t\ttype === "!=" ?\n +\t\t\t\tvalue !== check :\n +\t\t\t\ttype === "^=" ?\n +\t\t\t\tvalue.indexOf(check) === 0 :\n +\t\t\t\ttype === "$=" ?\n +\t\t\t\tvalue.substr(value.length - check.length) === check :\n +\t\t\t\ttype === "|=" ?\n +\t\t\t\tvalue === check || value.substr(0, check.length + 1) === check + "-" :\n +\t\t\t\tfalse;\n +\t\t},\n +\t\tPOS: function(elem, match, i, array){\n +\t\t\tvar name = match[2], filter = Expr.setFilters[ name ];\n +\n +\t\t\tif ( filter ) {\n +\t\t\t\treturn filter( elem, i, match, array );\n +\t\t\t}\n +\t\t}\n +\t}\n +};\n +\n +var origPOS = Expr.match.POS;\n +\n +for ( var type in Expr.match ) {\n +\tExpr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\\[]*\\])(?![^\\(]*\\))/.source );\n +\tExpr.leftMatch[ type ] = new RegExp( /(^(?:.|\\r|\\n)*?)/.source + Expr.match[ type ].source.replace(/\\\\(\\d+)/g, function(all, num){\n +\t\treturn "\\\\" + (num - 0 + 1);\n +\t}));\n +}\n +\n +var makeArray = function(array, results) {\n +\tarray = Array.prototype.slice.call( array, 0 );\n +\n +\tif ( results ) {\n +\t\tresults.push.apply( results, array );\n +\t\treturn results;\n +\t}\n +\t\n +\treturn array;\n +};\n +\n +// Perform a simple check to determine if the browser is capable of\n +// converting a NodeList to an array using builtin methods.\n +// Also verifies that the returned array holds DOM nodes\n +// (which is not the case in the Blackberry browser)\n +try {\n +\tArray.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;\n +\n +// Provide a fallback method if it does not work\n +} catch(e){\n +\tmakeArray = function(array, results) {\n +\t\tvar ret = results || [];\n +\n +\t\tif ( toString.call(array) === "[object Array]" ) {\n +\t\t\tArray.prototype.push.apply( ret, array );\n +\t\t} else {\n +\t\t\tif ( typeof array.length === "number" ) {\n +\t\t\t\tfor ( var i = 0, l = array.length; i < l; i++ ) {\n +\t\t\t\t\tret.push( array[i] );\n +\t\t\t\t}\n +\t\t\t} else {\n +\t\t\t\tfor ( var i = 0; array[i]; i++ ) {\n +\t\t\t\t\tret.push( array[i] );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret;\n +\t};\n +}\n +\n +var sortOrder;\n +\n +if ( document.documentElement.compareDocumentPosition ) {\n +\tsortOrder = function( a, b ) {\n +\t\tif ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {\n +\t\t\tif ( a == b ) {\n +\t\t\t\thasDuplicate = true;\n +\t\t\t}\n +\t\t\treturn a.compareDocumentPosition ? -1 : 1;\n +\t\t}\n +\n +\t\tvar ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;\n +\t\tif ( ret === 0 ) {\n +\t\t\thasDuplicate = true;\n +\t\t}\n +\t\treturn ret;\n +\t};\n +} else if ( "sourceIndex" in document.documentElement ) {\n +\tsortOrder = function( a, b ) {\n +\t\tif ( !a.sourceIndex || !b.sourceIndex ) {\n +\t\t\tif ( a == b ) {\n +\t\t\t\thasDuplicate = true;\n +\t\t\t}\n +\t\t\treturn a.sourceIndex ? -1 : 1;\n +\t\t}\n +\n +\t\tvar ret = a.sourceIndex - b.sourceIndex;\n +\t\tif ( ret === 0 ) {\n +\t\t\thasDuplicate = true;\n +\t\t}\n +\t\treturn ret;\n +\t};\n +} else if ( document.createRange ) {\n +\tsortOrder = function( a, b ) {\n +\t\tif ( !a.ownerDocument || !b.ownerDocument ) {\n +\t\t\tif ( a == b ) {\n +\t\t\t\thasDuplicate = true;\n +\t\t\t}\n +\t\t\treturn a.ownerDocument ? -1 : 1;\n +\t\t}\n +\n +\t\tvar aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();\n +\t\taRange.setStart(a, 0);\n +\t\taRange.setEnd(a, 0);\n +\t\tbRange.setStart(b, 0);\n +\t\tbRange.setEnd(b, 0);\n +\t\tvar ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);\n +\t\tif ( ret === 0 ) {\n +\t\t\thasDuplicate = true;\n +\t\t}\n +\t\treturn ret;\n +\t};\n +}\n +\n +// Utility function for retreiving the text value of an array of DOM nodes\n +function getText( elems ) {\n +\tvar ret = "", elem;\n +\n +\tfor ( var i = 0; elems[i]; i++ ) {\n +\t\telem = elems[i];\n +\n +\t\t// Get the text from text nodes and CDATA nodes\n +\t\tif ( elem.nodeType === 3 || elem.nodeType === 4 ) {\n +\t\t\tret += elem.nodeValue;\n +\n +\t\t// Traverse everything else, except comment nodes\n +\t\t} else if ( elem.nodeType !== 8 ) {\n +\t\t\tret += getText( elem.childNodes );\n +\t\t}\n +\t}\n +\n +\treturn ret;\n +}\n +\n +// Check to see if the browser returns elements by name when\n +// querying by getElementById (and provide a workaround)\n +(function(){\n +\t// We\'re going to inject a fake input element with a specified name\n +\tvar form = document.createElement("div"),\n +\t\tid = "script" + (new Date).getTime();\n +\tform.innerHTML = "<a name=\'" + id + "\'/>";\n +\n +\t// Inject it into the root element, check its status, and remove it quickly\n +\tvar root = document.documentElement;\n +\troot.insertBefore( form, root.firstChild );\n +\n +\t// The workaround has to do additional checks after a getElementById\n +\t// Which slows things down for other browsers (hence the branching)\n +\tif ( document.getElementById( id ) ) {\n +\t\tExpr.find.ID = function(match, context, isXML){\n +\t\t\tif ( typeof context.getElementById !== "undefined" && !isXML ) {\n +\t\t\t\tvar m = context.getElementById(match[1]);\n +\t\t\t\treturn m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];\n +\t\t\t}\n +\t\t};\n +\n +\t\tExpr.filter.ID = function(elem, match){\n +\t\t\tvar node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");\n +\t\t\treturn elem.nodeType === 1 && node && node.nodeValue === match;\n +\t\t};\n +\t}\n +\n +\troot.removeChild( form );\n +\troot = form = null; // release memory in IE\n +})();\n +\n +(function(){\n +\t// Check to see if the browser returns only elements\n +\t// when doing getElementsByTagName("*")\n +\n +\t// Create a fake element\n +\tvar div = document.createElement("div");\n +\tdiv.appendChild( document.createComment("") );\n +\n +\t// Make sure no comments are found\n +\tif ( div.getElementsByTagName("*").length > 0 ) {\n +\t\tExpr.find.TAG = function(match, context){\n +\t\t\tvar results = context.getElementsByTagName(match[1]);\n +\n +\t\t\t// Filter out possible comments\n +\t\t\tif ( match[1] === "*" ) {\n +\t\t\t\tvar tmp = [];\n +\n +\t\t\t\tfor ( var i = 0; results[i]; i++ ) {\n +\t\t\t\t\tif ( results[i].nodeType === 1 ) {\n +\t\t\t\t\t\ttmp.push( results[i] );\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\tresults = tmp;\n +\t\t\t}\n +\n +\t\t\treturn results;\n +\t\t};\n +\t}\n +\n +\t// Check to see if an attribute returns normalized href attributes\n +\tdiv.innerHTML = "<a href=\'#\'></a>";\n +\tif ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&\n +\t\t\tdiv.firstChild.getAttribute("href") !== "#" ) {\n +\t\tExpr.attrHandle.href = function(elem){\n +\t\t\treturn elem.getAttribute("href", 2);\n +\t\t};\n +\t}\n +\n +\tdiv = null; // release memory in IE\n +})();\n +\n +if ( document.querySelectorAll ) {\n +\t(function(){\n +\t\tvar oldSizzle = Sizzle, div = document.createElement("div");\n +\t\tdiv.innerHTML = "<p class=\'TEST\'></p>";\n +\n +\t\t// Safari can\'t handle uppercase or unicode characters when\n +\t\t// in quirks mode.\n +\t\tif ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {\n +\t\t\treturn;\n +\t\t}\n +\t\n +\t\tSizzle = function(query, context, extra, seed){\n +\t\t\tcontext = context || document;\n +\n +\t\t\t// Only use querySelectorAll on non-XML documents\n +\t\t\t// (ID selectors don\'t work in non-HTML documents)\n +\t\t\tif ( !seed && context.nodeType === 9 && !isXML(context) ) {\n +\t\t\t\ttry {\n +\t\t\t\t\treturn makeArray( context.querySelectorAll(query), extra );\n +\t\t\t\t} catch(e){}\n +\t\t\t}\n +\t\t\n +\t\t\treturn oldSizzle(query, context, extra, seed);\n +\t\t};\n +\n +\t\tfor ( var prop in oldSizzle ) {\n +\t\t\tSizzle[ prop ] = oldSizzle[ prop ];\n +\t\t}\n +\n +\t\tdiv = null; // release memory in IE\n +\t})();\n +}\n +\n +(function(){\n +\tvar div = document.createElement("div");\n +\n +\tdiv.innerHTML = "<div class=\'test e\'></div><div class=\'test\'></div>";\n +\n +\t// Opera can\'t find a second classname (in 9.6)\n +\t// Also, make sure that getElementsByClassName actually exists\n +\tif ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {\n +\t\treturn;\n +\t}\n +\n +\t// Safari caches class attributes, doesn\'t catch changes (in 3.2)\n +\tdiv.lastChild.className = "e";\n +\n +\tif ( div.getElementsByClassName("e").length === 1 ) {\n +\t\treturn;\n +\t}\n +\t\n +\tExpr.order.splice(1, 0, "CLASS");\n +\tExpr.find.CLASS = function(match, context, isXML) {\n +\t\tif ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {\n +\t\t\treturn context.getElementsByClassName(match[1]);\n +\t\t}\n +\t};\n +\n +\tdiv = null; // release memory in IE\n +})();\n +\n +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n +\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n +\t\tvar elem = checkSet[i];\n +\t\tif ( elem ) {\n +\t\t\telem = elem[dir];\n +\t\t\tvar match = false;\n +\n +\t\t\twhile ( elem ) {\n +\t\t\t\tif ( elem.sizcache === doneName ) {\n +\t\t\t\t\tmatch = checkSet[elem.sizset];\n +\t\t\t\t\tbreak;\n +\t\t\t\t}\n +\n +\t\t\t\tif ( elem.nodeType === 1 && !isXML ){\n +\t\t\t\t\telem.sizcache = doneName;\n +\t\t\t\t\telem.sizset = i;\n +\t\t\t\t}\n +\n +\t\t\t\tif ( elem.nodeName.toLowerCase() === cur ) {\n +\t\t\t\t\tmatch = elem;\n +\t\t\t\t\tbreak;\n +\t\t\t\t}\n +\n +\t\t\t\telem = elem[dir];\n +\t\t\t}\n +\n +\t\t\tcheckSet[i] = match;\n +\t\t}\n +\t}\n +}\n +\n +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n +\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n +\t\tvar elem = checkSet[i];\n +\t\tif ( elem ) {\n +\t\t\telem = elem[dir];\n +\t\t\tvar match = false;\n +\n +\t\t\twhile ( elem ) {\n +\t\t\t\tif ( elem.sizcache === doneName ) {\n +\t\t\t\t\tmatch = checkSet[elem.sizset];\n +\t\t\t\t\tbreak;\n +\t\t\t\t}\n +\n +\t\t\t\tif ( elem.nodeType === 1 ) {\n +\t\t\t\t\tif ( !isXML ) {\n +\t\t\t\t\t\telem.sizcache = doneName;\n +\t\t\t\t\t\telem.sizset = i;\n +\t\t\t\t\t}\n +\t\t\t\t\tif ( typeof cur !== "string" ) {\n +\t\t\t\t\t\tif ( elem === cur ) {\n +\t\t\t\t\t\t\tmatch = true;\n +\t\t\t\t\t\t\tbreak;\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\n +\t\t\t\t\t\tmatch = elem;\n +\t\t\t\t\t\tbreak;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\telem = elem[dir];\n +\t\t\t}\n +\n +\t\t\tcheckSet[i] = match;\n +\t\t}\n +\t}\n +}\n +\n +var contains = document.compareDocumentPosition ? function(a, b){\n +\treturn !!(a.compareDocumentPosition(b) & 16);\n +} : function(a, b){\n +\treturn a !== b && (a.contains ? a.contains(b) : true);\n +};\n +\n +var isXML = function(elem){\n +\t// documentElement is verified for cases where it doesn\'t yet exist\n +\t// (such as loading iframes in IE - #4833) \n +\tvar documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;\n +\treturn documentElement ? documentElement.nodeName !== "HTML" : false;\n +};\n +\n +var posProcess = function(selector, context){\n +\tvar tmpSet = [], later = "", match,\n +\t\troot = context.nodeType ? [context] : context;\n +\n +\t// Position selectors must be done after the filter\n +\t// And so must :not(positional) so we move all PSEUDOs to the end\n +\twhile ( (match = Expr.match.PSEUDO.exec( selector )) ) {\n +\t\tlater += match[0];\n +\t\tselector = selector.replace( Expr.match.PSEUDO, "" );\n +\t}\n +\n +\tselector = Expr.relative[selector] ? selector + "*" : selector;\n +\n +\tfor ( var i = 0, l = root.length; i < l; i++ ) {\n +\t\tSizzle( selector, root[i], tmpSet );\n +\t}\n +\n +\treturn Sizzle.filter( later, tmpSet );\n +};\n +\n +// EXPOSE\n +jQuery.find = Sizzle;\n +jQuery.expr = Sizzle.selectors;\n +jQuery.expr[":"] = jQuery.expr.filters;\n +jQuery.unique = Sizzle.uniqueSort;\n +jQuery.text = getText;\n +jQuery.isXMLDoc = isXML;\n +jQuery.contains = contains;\n +\n +return;\n +\n +window.Sizzle = Sizzle;\n +\n +})();\n +var runtil = /Until$/,\n +\trparentsprev = /^(?:parents|prevUntil|prevAll)/,\n +\t// Note: This RegExp should be improved, or likely pulled from Sizzle\n +\trmultiselector = /,/,\n +\tslice = Array.prototype.slice;\n +\n +// Implement the identical functionality for filter and not\n +var winnow = function( elements, qualifier, keep ) {\n +\tif ( jQuery.isFunction( qualifier ) ) {\n +\t\treturn jQuery.grep(elements, function( elem, i ) {\n +\t\t\treturn !!qualifier.call( elem, i, elem ) === keep;\n +\t\t});\n +\n +\t} else if ( qualifier.nodeType ) {\n +\t\treturn jQuery.grep(elements, function( elem, i ) {\n +\t\t\treturn (elem === qualifier) === keep;\n +\t\t});\n +\n +\t} else if ( typeof qualifier === "string" ) {\n +\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n +\t\t\treturn elem.nodeType === 1;\n +\t\t});\n +\n +\t\tif ( isSimple.test( qualifier ) ) {\n +\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n +\t\t} else {\n +\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n +\t\t}\n +\t}\n +\n +\treturn jQuery.grep(elements, function( elem, i ) {\n +\t\treturn (jQuery.inArray( elem, qualifier ) >= 0) === keep;\n +\t});\n +};\n +\n +jQuery.fn.extend({\n +\tfind: function( selector ) {\n +\t\tvar ret = this.pushStack( "", "find", selector ), length = 0;\n +\n +\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\tlength = ret.length;\n +\t\t\tjQuery.find( selector, this[i], ret );\n +\n +\t\t\tif ( i > 0 ) {\n +\t\t\t\t// Make sure that the results are unique\n +\t\t\t\tfor ( var n = length; n < ret.length; n++ ) {\n +\t\t\t\t\tfor ( var r = 0; r < length; r++ ) {\n +\t\t\t\t\t\tif ( ret[r] === ret[n] ) {\n +\t\t\t\t\t\t\tret.splice(n--, 1);\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}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret;\n +\t},\n +\n +\thas: function( target ) {\n +\t\tvar targets = jQuery( target );\n +\t\treturn this.filter(function() {\n +\t\t\tfor ( var i = 0, l = targets.length; i < l; i++ ) {\n +\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n +\t\t\t\t\treturn true;\n +\t\t\t\t}\n +\t\t\t}\n +\t\t});\n +\t},\n +\n +\tnot: function( selector ) {\n +\t\treturn this.pushStack( winnow(this, selector, false), "not", selector);\n +\t},\n +\n +\tfilter: function( selector ) {\n +\t\treturn this.pushStack( winnow(this, selector, true), "filter", selector );\n +\t},\n +\t\n +\tis: function( selector ) {\n +\t\treturn !!selector && jQuery.filter( selector, this ).length > 0;\n +\t},\n +\n +\tclosest: function( selectors, context ) {\n +\t\tif ( jQuery.isArray( selectors ) ) {\n +\t\t\tvar ret = [], cur = this[0], match, matches = {}, selector;\n +\n +\t\t\tif ( cur && selectors.length ) {\n +\t\t\t\tfor ( var i = 0, l = selectors.length; i < l; i++ ) {\n +\t\t\t\t\tselector = selectors[i];\n +\n +\t\t\t\t\tif ( !matches[selector] ) {\n +\t\t\t\t\t\tmatches[selector] = jQuery.expr.match.POS.test( selector ) ? \n +\t\t\t\t\t\t\tjQuery( selector, context || this.context ) :\n +\t\t\t\t\t\t\tselector;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\twhile ( cur && cur.ownerDocument && cur !== context ) {\n +\t\t\t\t\tfor ( selector in matches ) {\n +\t\t\t\t\t\tmatch = matches[selector];\n +\n +\t\t\t\t\t\tif ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {\n +\t\t\t\t\t\t\tret.push({ selector: selector, elem: cur });\n +\t\t\t\t\t\t\tdelete matches[selector];\n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\t\t\t\t\tcur = cur.parentNode;\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\treturn ret;\n +\t\t}\n +\n +\t\tvar pos = jQuery.expr.match.POS.test( selectors ) ? \n +\t\t\tjQuery( selectors, context || this.context ) : null;\n +\n +\t\treturn this.map(function( i, cur ) {\n +\t\t\twhile ( cur && cur.ownerDocument && cur !== context ) {\n +\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {\n +\t\t\t\t\treturn cur;\n +\t\t\t\t}\n +\t\t\t\tcur = cur.parentNode;\n +\t\t\t}\n +\t\t\treturn null;\n +\t\t});\n +\t},\n +\t\n +\t// Determine the position of an element within\n +\t// the matched set of elements\n +\tindex: function( elem ) {\n +\t\tif ( !elem || typeof elem === "string" ) {\n +\t\t\treturn jQuery.inArray( this[0],\n +\t\t\t\t// If it receives a string, the selector is used\n +\t\t\t\t// If it receives nothing, the siblings are used\n +\t\t\t\telem ? jQuery( elem ) : this.parent().children() );\n +\t\t}\n +\t\t// Locate the position of the desired element\n +\t\treturn jQuery.inArray(\n +\t\t\t// If it receives a jQuery object, the first element is used\n +\t\t\telem.jquery ? elem[0] : elem, this );\n +\t},\n +\n +\tadd: function( selector, context ) {\n +\t\tvar set = typeof selector === "string" ?\n +\t\t\t\tjQuery( selector, context || this.context ) :\n +\t\t\t\tjQuery.makeArray( selector ),\n +\t\t\tall = jQuery.merge( this.get(), set );\n +\n +\t\treturn this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?\n +\t\t\tall :\n +\t\t\tjQuery.unique( all ) );\n +\t},\n +\n +\tandSelf: function() {\n +\t\treturn this.add( this.prevObject );\n +\t}\n +});\n +\n +// A painfully simple check to see if an element is disconnected\n +// from a document (should be improved, where feasible).\n +function isDisconnected( node ) {\n +\treturn !node || !node.parentNode || node.parentNode.nodeType === 11;\n +}\n +\n +jQuery.each({\n +\tparent: function( elem ) {\n +\t\tvar parent = elem.parentNode;\n +\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n +\t},\n +\tparents: function( elem ) {\n +\t\treturn jQuery.dir( elem, "parentNode" );\n +\t},\n +\tparentsUntil: function( elem, i, until ) {\n +\t\treturn jQuery.dir( elem, "parentNode", until );\n +\t},\n +\tnext: function( elem ) {\n +\t\treturn jQuery.nth( elem, 2, "nextSibling" );\n +\t},\n +\tprev: function( elem ) {\n +\t\treturn jQuery.nth( elem, 2, "previousSibling" );\n +\t},\n +\tnextAll: function( elem ) {\n +\t\treturn jQuery.dir( elem, "nextSibling" );\n +\t},\n +\tprevAll: function( elem ) {\n +\t\treturn jQuery.dir( elem, "previousSibling" );\n +\t},\n +\tnextUntil: function( elem, i, until ) {\n +\t\treturn jQuery.dir( elem, "nextSibling", until );\n +\t},\n +\tprevUntil: function( elem, i, until ) {\n +\t\treturn jQuery.dir( elem, "previousSibling", until );\n +\t},\n +\tsiblings: function( elem ) {\n +\t\treturn jQuery.sibling( elem.parentNode.firstChild, elem );\n +\t},\n +\tchildren: function( elem ) {\n +\t\treturn jQuery.sibling( elem.firstChild );\n +\t},\n +\tcontents: function( elem ) {\n +\t\treturn jQuery.nodeName( elem, "iframe" ) ?\n +\t\t\telem.contentDocument || elem.contentWindow.document :\n +\t\t\tjQuery.makeArray( elem.childNodes );\n +\t}\n +}, function( name, fn ) {\n +\tjQuery.fn[ name ] = function( until, selector ) {\n +\t\tvar ret = jQuery.map( this, fn, until );\n +\t\t\n +\t\tif ( !runtil.test( name ) ) {\n +\t\t\tselector = until;\n +\t\t}\n +\n +\t\tif ( selector && typeof selector === "string" ) {\n +\t\t\tret = jQuery.filter( selector, ret );\n +\t\t}\n +\n +\t\tret = this.length > 1 ? jQuery.unique( ret ) : ret;\n +\n +\t\tif ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {\n +\t\t\tret = ret.reverse();\n +\t\t}\n +\n +\t\treturn this.pushStack( ret, name, slice.call(arguments).join(",") );\n +\t};\n +});\n +\n +jQuery.extend({\n +\tfilter: function( expr, elems, not ) {\n +\t\tif ( not ) {\n +\t\t\texpr = ":not(" + expr + ")";\n +\t\t}\n +\n +\t\treturn jQuery.find.matches(expr, elems);\n +\t},\n +\t\n +\tdir: function( elem, dir, until ) {\n +\t\tvar matched = [], cur = elem[dir];\n +\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n +\t\t\tif ( cur.nodeType === 1 ) {\n +\t\t\t\tmatched.push( cur );\n +\t\t\t}\n +\t\t\tcur = cur[dir];\n +\t\t}\n +\t\treturn matched;\n +\t},\n +\n +\tnth: function( cur, result, dir, elem ) {\n +\t\tresult = result || 1;\n +\t\tvar num = 0;\n +\n +\t\tfor ( ; cur; cur = cur[dir] ) {\n +\t\t\tif ( cur.nodeType === 1 && ++num === result ) {\n +\t\t\t\tbreak;\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn cur;\n +\t},\n +\n +\tsibling: function( n, elem ) {\n +\t\tvar r = [];\n +\n +\t\tfor ( ; n; n = n.nextSibling ) {\n +\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n +\t\t\t\tr.push( n );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn r;\n +\t}\n +});\n +var rinlinejQuery = / jQuery\\d+="(?:\\d+|null)"/g,\n +\trleadingWhitespace = /^\\s+/,\n +\trxhtmlTag = /(<([\\w:]+)[^>]*?)\\/>/g,\n +\trselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,\n +\trtagName = /<([\\w:]+)/,\n +\trtbody = /<tbody/i,\n +\trhtml = /<|&#?\\w+;/,\n +\trnocache = /<script|<object|<embed|<option|<style/i,\n +\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i, // checked="checked" or checked (html5)\n +\tfcloseTag = function( all, front, tag ) {\n +\t\treturn rselfClosing.test( tag ) ?\n +\t\t\tall :\n +\t\t\tfront + "></" + tag + ">";\n +\t},\n +\twrapMap = {\n +\t\toption: [ 1, "<select multiple=\'multiple\'>", "</select>" ],\n +\t\tlegend: [ 1, "<fieldset>", "</fieldset>" ],\n +\t\tthead: [ 1, "<table>", "</table>" ],\n +\t\ttr: [ 2, "<table><tbody>", "</tbody></table>" ],\n +\t\ttd: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],\n +\t\tcol: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],\n +\t\tarea: [ 1, "<map>", "</map>" ],\n +\t\t_default: [ 0, "", "" ]\n +\t};\n +\n +wrapMap.optgroup = wrapMap.option;\n +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\n +wrapMap.th = wrapMap.td;\n +\n +// IE can\'t serialize <link> and <script> tags normally\n +if ( !jQuery.support.htmlSerialize ) {\n +\twrapMap._default = [ 1, "div<div>", "</div>" ];\n +}\n +\n +jQuery.fn.extend({\n +\ttext: function( text ) {\n +\t\tif ( jQuery.isFunction(text) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tvar self = jQuery(this);\n +\t\t\t\tself.text( text.call(this, i, self.text()) );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( typeof text !== "object" && text !== undefined ) {\n +\t\t\treturn this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );\n +\t\t}\n +\n +\t\treturn jQuery.text( this );\n +\t},\n +\n +\twrapAll: function( html ) {\n +\t\tif ( jQuery.isFunction( html ) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tjQuery(this).wrapAll( html.call(this, i) );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( this[0] ) {\n +\t\t\t// The elements to wrap the target around\n +\t\t\tvar wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n +\n +\t\t\tif ( this[0].parentNode ) {\n +\t\t\t\twrap.insertBefore( this[0] );\n +\t\t\t}\n +\n +\t\t\twrap.map(function() {\n +\t\t\t\tvar elem = this;\n +\n +\t\t\t\twhile ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n +\t\t\t\t\telem = elem.firstChild;\n +\t\t\t\t}\n +\n +\t\t\t\treturn elem;\n +\t\t\t}).append(this);\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\n +\twrapInner: function( html ) {\n +\t\tif ( jQuery.isFunction( html ) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tjQuery(this).wrapInner( html.call(this, i) );\n +\t\t\t});\n +\t\t}\n +\n +\t\treturn this.each(function() {\n +\t\t\tvar self = jQuery( this ), contents = self.contents();\n +\n +\t\t\tif ( contents.length ) {\n +\t\t\t\tcontents.wrapAll( html );\n +\n +\t\t\t} else {\n +\t\t\t\tself.append( html );\n +\t\t\t}\n +\t\t});\n +\t},\n +\n +\twrap: function( html ) {\n +\t\treturn this.each(function() {\n +\t\t\tjQuery( this ).wrapAll( html );\n +\t\t});\n +\t},\n +\n +\tunwrap: function() {\n +\t\treturn this.parent().each(function() {\n +\t\t\tif ( !jQuery.nodeName( this, "body" ) ) {\n +\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n +\t\t\t}\n +\t\t}).end();\n +\t},\n +\n +\tappend: function() {\n +\t\treturn this.domManip(arguments, true, function( elem ) {\n +\t\t\tif ( this.nodeType === 1 ) {\n +\t\t\t\tthis.appendChild( elem );\n +\t\t\t}\n +\t\t});\n +\t},\n +\n +\tprepend: function() {\n +\t\treturn this.domManip(arguments, true, function( elem ) {\n +\t\t\tif ( this.nodeType === 1 ) {\n +\t\t\t\tthis.insertBefore( elem, this.firstChild );\n +\t\t\t}\n +\t\t});\n +\t},\n +\n +\tbefore: function() {\n +\t\tif ( this[0] && this[0].parentNode ) {\n +\t\t\treturn this.domManip(arguments, false, function( elem ) {\n +\t\t\t\tthis.parentNode.insertBefore( elem, this );\n +\t\t\t});\n +\t\t} else if ( arguments.length ) {\n +\t\t\tvar set = jQuery(arguments[0]);\n +\t\t\tset.push.apply( set, this.toArray() );\n +\t\t\treturn this.pushStack( set, "before", arguments );\n +\t\t}\n +\t},\n +\n +\tafter: function() {\n +\t\tif ( this[0] && this[0].parentNode ) {\n +\t\t\treturn this.domManip(arguments, false, function( elem ) {\n +\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n +\t\t\t});\n +\t\t} else if ( arguments.length ) {\n +\t\t\tvar set = this.pushStack( this, "after", arguments );\n +\t\t\tset.push.apply( set, jQuery(arguments[0]).toArray() );\n +\t\t\treturn set;\n +\t\t}\n +\t},\n +\t\n +\t// keepData is for internal use only--do not document\n +\tremove: function( selector, keepData ) {\n +\t\tfor ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n +\t\t\tif ( !selector || jQuery.filter( selector, [ elem ] ).length ) {\n +\t\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n +\t\t\t\t\tjQuery.cleanData( elem.getElementsByTagName("*") );\n +\t\t\t\t\tjQuery.cleanData( [ elem ] );\n +\t\t\t\t}\n +\n +\t\t\t\tif ( elem.parentNode ) {\n +\t\t\t\t\t elem.parentNode.removeChild( elem );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t\t\n +\t\treturn this;\n +\t},\n +\n +\tempty: function() {\n +\t\tfor ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n +\t\t\t// Remove element nodes and prevent memory leaks\n +\t\t\tif ( elem.nodeType === 1 ) {\n +\t\t\t\tjQuery.cleanData( elem.getElementsByTagName("*") );\n +\t\t\t}\n +\n +\t\t\t// Remove any remaining nodes\n +\t\t\twhile ( elem.firstChild ) {\n +\t\t\t\telem.removeChild( elem.firstChild );\n +\t\t\t}\n +\t\t}\n +\t\t\n +\t\treturn this;\n +\t},\n +\n +\tclone: function( events ) {\n +\t\t// Do the clone\n +\t\tvar ret = this.map(function() {\n +\t\t\tif ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {\n +\t\t\t\t// IE copies events bound via attachEvent when\n +\t\t\t\t// using cloneNode. Calling detachEvent on the\n +\t\t\t\t// clone will also remove the events from the orignal\n +\t\t\t\t// In order to get around this, we use innerHTML.\n +\t\t\t\t// Unfortunately, this means some modifications to\n +\t\t\t\t// attributes in IE that are actually only stored\n +\t\t\t\t// as properties will not be copied (such as the\n +\t\t\t\t// the name attribute on an input).\n +\t\t\t\tvar html = this.outerHTML, ownerDocument = this.ownerDocument;\n +\t\t\t\tif ( !html ) {\n +\t\t\t\t\tvar div = ownerDocument.createElement("div");\n +\t\t\t\t\tdiv.appendChild( this.cloneNode(true) );\n +\t\t\t\t\thtml = div.innerHTML;\n +\t\t\t\t}\n +\n +\t\t\t\treturn jQuery.clean([html.replace(rinlinejQuery, "")\n +\t\t\t\t\t// Handle the case in IE 8 where action=/test/> self-closes a tag\n +\t\t\t\t\t.replace(/=([^="\'>\\s]+\\/)>/g, \'="$1">\')\n +\t\t\t\t\t.replace(rleadingWhitespace, "")], ownerDocument)[0];\n +\t\t\t} else {\n +\t\t\t\treturn this.cloneNode(true);\n +\t\t\t}\n +\t\t});\n +\n +\t\t// Copy the events from the original to the clone\n +\t\tif ( events === true ) {\n +\t\t\tcloneCopyEvent( this, ret );\n +\t\t\tcloneCopyEvent( this.find("*"), ret.find("*") );\n +\t\t}\n +\n +\t\t// Return the cloned set\n +\t\treturn ret;\n +\t},\n +\n +\thtml: function( value ) {\n +\t\tif ( value === undefined ) {\n +\t\t\treturn this[0] && this[0].nodeType === 1 ?\n +\t\t\t\tthis[0].innerHTML.replace(rinlinejQuery, "") :\n +\t\t\t\tnull;\n +\n +\t\t// See if we can take a shortcut and just use innerHTML\n +\t\t} else if ( typeof value === "string" && !rnocache.test( value ) &&\n +\t\t\t(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&\n +\t\t\t!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {\n +\n +\t\t\tvalue = value.replace(rxhtmlTag, fcloseTag);\n +\n +\t\t\ttry {\n +\t\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\t\t// Remove element nodes and prevent memory leaks\n +\t\t\t\t\tif ( this[i].nodeType === 1 ) {\n +\t\t\t\t\t\tjQuery.cleanData( this[i].getElementsByTagName("*") );\n +\t\t\t\t\t\tthis[i].innerHTML = value;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t// If using innerHTML throws an exception, use the fallback method\n +\t\t\t} catch(e) {\n +\t\t\t\tthis.empty().append( value );\n +\t\t\t}\n +\n +\t\t} else if ( jQuery.isFunction( value ) ) {\n +\t\t\tthis.each(function(i){\n +\t\t\t\tvar self = jQuery(this), old = self.html();\n +\t\t\t\tself.empty().append(function(){\n +\t\t\t\t\treturn value.call( this, i, old );\n +\t\t\t\t});\n +\t\t\t});\n +\n +\t\t} else {\n +\t\t\tthis.empty().append( value );\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\n +\treplaceWith: function( value ) {\n +\t\tif ( this[0] && this[0].parentNode ) {\n +\t\t\t// Make sure that the elements are removed from the DOM before they are inserted\n +\t\t\t// this can help fix replacing a parent with child elements\n +\t\t\tif ( jQuery.isFunction( value ) ) {\n +\t\t\t\treturn this.each(function(i) {\n +\t\t\t\t\tvar self = jQuery(this), old = self.html();\n +\t\t\t\t\tself.replaceWith( value.call( this, i, old ) );\n +\t\t\t\t});\n +\t\t\t}\n +\n +\t\t\tif ( typeof value !== "string" ) {\n +\t\t\t\tvalue = jQuery(value).detach();\n +\t\t\t}\n +\n +\t\t\treturn this.each(function() {\n +\t\t\t\tvar next = this.nextSibling, parent = this.parentNode;\n +\n +\t\t\t\tjQuery(this).remove();\n +\n +\t\t\t\tif ( next ) {\n +\t\t\t\t\tjQuery(next).before( value );\n +\t\t\t\t} else {\n +\t\t\t\t\tjQuery(parent).append( value );\n +\t\t\t\t}\n +\t\t\t});\n +\t\t} else {\n +\t\t\treturn this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );\n +\t\t}\n +\t},\n +\n +\tdetach: function( selector ) {\n +\t\treturn this.remove( selector, true );\n +\t},\n +\n +\tdomManip: function( args, table, callback ) {\n +\t\tvar results, first, value = args[0], scripts = [], fragment, parent;\n +\n +\t\t// We can\'t cloneNode fragments that contain checked, in WebKit\n +\t\tif ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {\n +\t\t\treturn this.each(function() {\n +\t\t\t\tjQuery(this).domManip( args, table, callback, true );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( jQuery.isFunction(value) ) {\n +\t\t\treturn this.each(function(i) {\n +\t\t\t\tvar self = jQuery(this);\n +\t\t\t\targs[0] = value.call(this, i, table ? self.html() : undefined);\n +\t\t\t\tself.domManip( args, table, callback );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( this[0] ) {\n +\t\t\tparent = value && value.parentNode;\n +\n +\t\t\t// If we\'re in a fragment, just use that instead of building a new one\n +\t\t\tif ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {\n +\t\t\t\tresults = { fragment: parent };\n +\n +\t\t\t} else {\n +\t\t\t\tresults = buildFragment( args, this, scripts );\n +\t\t\t}\n +\t\t\t\n +\t\t\tfragment = results.fragment;\n +\t\t\t\n +\t\t\tif ( fragment.childNodes.length === 1 ) {\n +\t\t\t\tfirst = fragment = fragment.firstChild;\n +\t\t\t} else {\n +\t\t\t\tfirst = fragment.firstChild;\n +\t\t\t}\n +\n +\t\t\tif ( first ) {\n +\t\t\t\ttable = table && jQuery.nodeName( first, "tr" );\n +\n +\t\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\t\tcallback.call(\n +\t\t\t\t\t\ttable ?\n +\t\t\t\t\t\t\troot(this[i], first) :\n +\t\t\t\t\t\t\tthis[i],\n +\t\t\t\t\t\ti > 0 || results.cacheable || this.length > 1 ?\n +\t\t\t\t\t\t\tfragment.cloneNode(true) :\n +\t\t\t\t\t\t\tfragment\n +\t\t\t\t\t);\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\tif ( scripts.length ) {\n +\t\t\t\tjQuery.each( scripts, evalScript );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn this;\n +\n +\t\tfunction root( elem, cur ) {\n +\t\t\treturn jQuery.nodeName(elem, "table") ?\n +\t\t\t\t(elem.getElementsByTagName("tbody")[0] ||\n +\t\t\t\telem.appendChild(elem.ownerDocument.createElement("tbody"))) :\n +\t\t\t\telem;\n +\t\t}\n +\t}\n +});\n +\n +function cloneCopyEvent(orig, ret) {\n +\tvar i = 0;\n +\n +\tret.each(function() {\n +\t\tif ( this.nodeName !== (orig[i] && orig[i].nodeName) ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\tvar oldData = jQuery.data( orig[i++] ), curData = jQuery.data( this, oldData ), events = oldData && oldData.events;\n +\n +\t\tif ( events ) {\n +\t\t\tdelete curData.handle;\n +\t\t\tcurData.events = {};\n +\n +\t\t\tfor ( var type in events ) {\n +\t\t\t\tfor ( var handler in events[ type ] ) {\n +\t\t\t\t\tjQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\t});\n +}\n +\n +function buildFragment( args, nodes, scripts ) {\n +\tvar fragment, cacheable, cacheresults,\n +\t\tdoc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);\n +\n +\t// Only cache "small" (1/2 KB) strings that are associated with the main document\n +\t// Cloning options loses the selected state, so don\'t cache them\n +\t// IE 6 doesn\'t like it when you put <object> or <embed> elements in a fragment\n +\t// Also, WebKit does not clone \'checked\' attributes on cloneNode, so don\'t cache\n +\tif ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&\n +\t\t!rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {\n +\n +\t\tcacheable = true;\n +\t\tcacheresults = jQuery.fragments[ args[0] ];\n +\t\tif ( cacheresults ) {\n +\t\t\tif ( cacheresults !== 1 ) {\n +\t\t\t\tfragment = cacheresults;\n +\t\t\t}\n +\t\t}\n +\t}\n +\n +\tif ( !fragment ) {\n +\t\tfragment = doc.createDocumentFragment();\n +\t\tjQuery.clean( args, doc, fragment, scripts );\n +\t}\n +\n +\tif ( cacheable ) {\n +\t\tjQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;\n +\t}\n +\n +\treturn { fragment: fragment, cacheable: cacheable };\n +}\n +\n +jQuery.fragments = {};\n +\n +jQuery.each({\n +\tappendTo: "append",\n +\tprependTo: "prepend",\n +\tinsertBefore: "before",\n +\tinsertAfter: "after",\n +\treplaceAll: "replaceWith"\n +}, function( name, original ) {\n +\tjQuery.fn[ name ] = function( selector ) {\n +\t\tvar ret = [], insert = jQuery( selector ),\n +\t\t\tparent = this.length === 1 && this[0].parentNode;\n +\t\t\n +\t\tif ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {\n +\t\t\tinsert[ original ]( this[0] );\n +\t\t\treturn this;\n +\t\t\t\n +\t\t} else {\n +\t\t\tfor ( var i = 0, l = insert.length; i < l; i++ ) {\n +\t\t\t\tvar elems = (i > 0 ? this.clone(true) : this).get();\n +\t\t\t\tjQuery.fn[ original ].apply( jQuery(insert[i]), elems );\n +\t\t\t\tret = ret.concat( elems );\n +\t\t\t}\n +\t\t\n +\t\t\treturn this.pushStack( ret, name, insert.selector );\n +\t\t}\n +\t};\n +});\n +\n +jQuery.extend({\n +\tclean: function( elems, context, fragment, scripts ) {\n +\t\tcontext = context || document;\n +\n +\t\t// !context.createElement fails in IE with an error but returns typeof \'object\'\n +\t\tif ( typeof context.createElement === "undefined" ) {\n +\t\t\tcontext = context.ownerDocument || context[0] && context[0].ownerDocument || document;\n +\t\t}\n +\n +\t\tvar ret = [];\n +\n +\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n +\t\t\tif ( typeof elem === "number" ) {\n +\t\t\t\telem += "";\n +\t\t\t}\n +\n +\t\t\tif ( !elem ) {\n +\t\t\t\tcontinue;\n +\t\t\t}\n +\n +\t\t\t// Convert html string into DOM nodes\n +\t\t\tif ( typeof elem === "string" && !rhtml.test( elem ) ) {\n +\t\t\t\telem = context.createTextNode( elem );\n +\n +\t\t\t} else if ( typeof elem === "string" ) {\n +\t\t\t\t// Fix "XHTML"-style tags in all browsers\n +\t\t\t\telem = elem.replace(rxhtmlTag, fcloseTag);\n +\n +\t\t\t\t// Trim whitespace, otherwise indexOf won\'t work as expected\n +\t\t\t\tvar tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),\n +\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default,\n +\t\t\t\t\tdepth = wrap[0],\n +\t\t\t\t\tdiv = context.createElement("div");\n +\n +\t\t\t\t// Go to html and back, then peel off extra wrappers\n +\t\t\t\tdiv.innerHTML = wrap[1] + elem + wrap[2];\n +\n +\t\t\t\t// Move to the right depth\n +\t\t\t\twhile ( depth-- ) {\n +\t\t\t\t\tdiv = div.lastChild;\n +\t\t\t\t}\n +\n +\t\t\t\t// Remove IE\'s autoinserted <tbody> from table fragments\n +\t\t\t\tif ( !jQuery.support.tbody ) {\n +\n +\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n +\t\t\t\t\tvar hasBody = rtbody.test(elem),\n +\t\t\t\t\t\ttbody = tag === "table" && !hasBody ?\n +\t\t\t\t\t\t\tdiv.firstChild && div.firstChild.childNodes :\n +\n +\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n +\t\t\t\t\t\t\twrap[1] === "<table>" && !hasBody ?\n +\t\t\t\t\t\t\t\tdiv.childNodes :\n +\t\t\t\t\t\t\t\t[];\n +\n +\t\t\t\t\tfor ( var j = tbody.length - 1; j >= 0 ; --j ) {\n +\t\t\t\t\t\tif ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {\n +\t\t\t\t\t\t\ttbody[ j ].parentNode.removeChild( tbody[ j ] );\n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\n +\t\t\t\t}\n +\n +\t\t\t\t// IE completely kills leading whitespace when innerHTML is used\n +\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n +\t\t\t\t\tdiv.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );\n +\t\t\t\t}\n +\n +\t\t\t\telem = div.childNodes;\n +\t\t\t}\n +\n +\t\t\tif ( elem.nodeType ) {\n +\t\t\t\tret.push( elem );\n +\t\t\t} else {\n +\t\t\t\tret = jQuery.merge( ret, elem );\n +\t\t\t}\n +\t\t}\n +\n +\t\tif ( fragment ) {\n +\t\t\tfor ( var i = 0; ret[i]; i++ ) {\n +\t\t\t\tif ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {\n +\t\t\t\t\tscripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );\n +\t\t\t\t\n +\t\t\t\t} else {\n +\t\t\t\t\tif ( ret[i].nodeType === 1 ) {\n +\t\t\t\t\t\tret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );\n +\t\t\t\t\t}\n +\t\t\t\t\tfragment.appendChild( ret[i] );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret;\n +\t},\n +\t\n +\tcleanData: function( elems ) {\n +\t\tvar data, id, cache = jQuery.cache,\n +\t\t\tspecial = jQuery.event.special,\n +\t\t\tdeleteExpando = jQuery.support.deleteExpando;\n +\t\t\n +\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n +\t\t\tid = elem[ jQuery.expando ];\n +\t\t\t\n +\t\t\tif ( id ) {\n +\t\t\t\tdata = cache[ id ];\n +\t\t\t\t\n +\t\t\t\tif ( data.events ) {\n +\t\t\t\t\tfor ( var type in data.events ) {\n +\t\t\t\t\t\tif ( special[ type ] ) {\n +\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n +\n +\t\t\t\t\t\t} else {\n +\t\t\t\t\t\t\tremoveEvent( elem, type, data.handle );\n +\t\t\t\t\t\t}\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t\t\n +\t\t\t\tif ( deleteExpando ) {\n +\t\t\t\t\tdelete elem[ jQuery.expando ];\n +\n +\t\t\t\t} else if ( elem.removeAttribute ) {\n +\t\t\t\t\telem.removeAttribute( jQuery.expando );\n +\t\t\t\t}\n +\t\t\t\t\n +\t\t\t\tdelete cache[ id ];\n +\t\t\t}\n +\t\t}\n +\t}\n +});\n +// exclude the following css properties to add px\n +var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,\n +\tralpha = /alpha\\([^)]*\\)/,\n +\tropacity = /opacity=([^)]*)/,\n +\trfloat = /float/i,\n +\trdashAlpha = /-([a-z])/ig,\n +\trupper = /([A-Z])/g,\n +\trnumpx = /^-?\\d+(?:px)?$/i,\n +\trnum = /^-?\\d/,\n +\n +\tcssShow = { position: "absolute", visibility: "hidden", display:"block" },\n +\tcssWidth = [ "Left", "Right" ],\n +\tcssHeight = [ "Top", "Bottom" ],\n +\n +\t// cache check for defaultView.getComputedStyle\n +\tgetComputedStyle = document.defaultView && document.defaultView.getComputedStyle,\n +\t// normalize float css property\n +\tstyleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",\n +\tfcamelCase = function( all, letter ) {\n +\t\treturn letter.toUpperCase();\n +\t};\n +\n +jQuery.fn.css = function( name, value ) {\n +\treturn access( this, name, value, true, function( elem, name, value ) {\n +\t\tif ( value === undefined ) {\n +\t\t\treturn jQuery.curCSS( elem, name );\n +\t\t}\n +\t\t\n +\t\tif ( typeof value === "number" && !rexclude.test(name) ) {\n +\t\t\tvalue += "px";\n +\t\t}\n +\n +\t\tjQuery.style( elem, name, value );\n +\t});\n +};\n +\n +jQuery.extend({\n +\tstyle: function( elem, name, value ) {\n +\t\t// don\'t set styles on text and comment nodes\n +\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n +\t\t\treturn undefined;\n +\t\t}\n +\n +\t\t// ignore negative width and height values #1599\n +\t\tif ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {\n +\t\t\tvalue = undefined;\n +\t\t}\n +\n +\t\tvar style = elem.style || elem, set = value !== undefined;\n +\n +\t\t// IE uses filters for opacity\n +\t\tif ( !jQuery.support.opacity && name === "opacity" ) {\n +\t\t\tif ( set ) {\n +\t\t\t\t// IE has trouble with opacity if it does not have layout\n +\t\t\t\t// Force it by setting the zoom level\n +\t\t\t\tstyle.zoom = 1;\n +\n +\t\t\t\t// Set the alpha filter to set the opacity\n +\t\t\t\tvar opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";\n +\t\t\t\tvar filter = style.filter || jQuery.curCSS( elem, "filter" ) || "";\n +\t\t\t\tstyle.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;\n +\t\t\t}\n +\n +\t\t\treturn style.filter && style.filter.indexOf("opacity=") >= 0 ?\n +\t\t\t\t(parseFloat( ropacity.exec(style.filter)[1] ) / 100) + "":\n +\t\t\t\t"";\n +\t\t}\n +\n +\t\t// Make sure we\'re using the right name for getting the float value\n +\t\tif ( rfloat.test( name ) ) {\n +\t\t\tname = styleFloat;\n +\t\t}\n +\n +\t\tname = name.replace(rdashAlpha, fcamelCase);\n +\n +\t\tif ( set ) {\n +\t\t\tstyle[ name ] = value;\n +\t\t}\n +\n +\t\treturn style[ name ];\n +\t},\n +\n +\tcss: function( elem, name, force, extra ) {\n +\t\tif ( name === "width" || name === "height" ) {\n +\t\t\tvar val, props = cssShow, which = name === "width" ? cssWidth : cssHeight;\n +\n +\t\t\tfunction getWH() {\n +\t\t\t\tval = name === "width" ? elem.offsetWidth : elem.offsetHeight;\n +\n +\t\t\t\tif ( extra === "border" ) {\n +\t\t\t\t\treturn;\n +\t\t\t\t}\n +\n +\t\t\t\tjQuery.each( which, function() {\n +\t\t\t\t\tif ( !extra ) {\n +\t\t\t\t\t\tval -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;\n +\t\t\t\t\t}\n +\n +\t\t\t\t\tif ( extra === "margin" ) {\n +\t\t\t\t\t\tval += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\tval -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;\n +\t\t\t\t\t}\n +\t\t\t\t});\n +\t\t\t}\n +\n +\t\t\tif ( elem.offsetWidth !== 0 ) {\n +\t\t\t\tgetWH();\n +\t\t\t} else {\n +\t\t\t\tjQuery.swap( elem, props, getWH );\n +\t\t\t}\n +\n +\t\t\treturn Math.max(0, Math.round(val));\n +\t\t}\n +\n +\t\treturn jQuery.curCSS( elem, name, force );\n +\t},\n +\n +\tcurCSS: function( elem, name, force ) {\n +\t\tvar ret, style = elem.style, filter;\n +\n +\t\t// IE uses filters for opacity\n +\t\tif ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {\n +\t\t\tret = ropacity.test(elem.currentStyle.filter || "") ?\n +\t\t\t\t(parseFloat(RegExp.$1) / 100) + "" :\n +\t\t\t\t"";\n +\n +\t\t\treturn ret === "" ?\n +\t\t\t\t"1" :\n +\t\t\t\tret;\n +\t\t}\n +\n +\t\t// Make sure we\'re using the right name for getting the float value\n +\t\tif ( rfloat.test( name ) ) {\n +\t\t\tname = styleFloat;\n +\t\t}\n +\n +\t\tif ( !force && style && style[ name ] ) {\n +\t\t\tret = style[ name ];\n +\n +\t\t} else if ( getComputedStyle ) {\n +\n +\t\t\t// Only "float" is needed here\n +\t\t\tif ( rfloat.test( name ) ) {\n +\t\t\t\tname = "float";\n +\t\t\t}\n +\n +\t\t\tname = name.replace( rupper, "-$1" ).toLowerCase();\n +\n +\t\t\tvar defaultView = elem.ownerDocument.defaultView;\n +\n +\t\t\tif ( !defaultView ) {\n +\t\t\t\treturn null;\n +\t\t\t}\n +\n +\t\t\tvar computedStyle = defaultView.getComputedStyle( elem, null );\n +\n +\t\t\tif ( computedStyle ) {\n +\t\t\t\tret = computedStyle.getPropertyValue( name );\n +\t\t\t}\n +\n +\t\t\t// We should always get a number back from opacity\n +\t\t\tif ( name === "opacity" && ret === "" ) {\n +\t\t\t\tret = "1";\n +\t\t\t}\n +\n +\t\t} else if ( elem.currentStyle ) {\n +\t\t\tvar camelCase = name.replace(rdashAlpha, fcamelCase);\n +\n +\t\t\tret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];\n +\n +\t\t\t// From the awesome hack by Dean Edwards\n +\t\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n +\n +\t\t\t// If we\'re not dealing with a regular pixel number\n +\t\t\t// but a number that has a weird ending, we need to convert it to pixels\n +\t\t\tif ( !rnumpx.test( ret ) && rnum.test( ret ) ) {\n +\t\t\t\t// Remember the original values\n +\t\t\t\tvar left = style.left, rsLeft = elem.runtimeStyle.left;\n +\n +\t\t\t\t// Put in the new values to get a computed value out\n +\t\t\t\telem.runtimeStyle.left = elem.currentStyle.left;\n +\t\t\t\tstyle.left = camelCase === "fontSize" ? "1em" : (ret || 0);\n +\t\t\t\tret = style.pixelLeft + "px";\n +\n +\t\t\t\t// Revert the changed values\n +\t\t\t\tstyle.left = left;\n +\t\t\t\telem.runtimeStyle.left = rsLeft;\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn ret;\n +\t},\n +\n +\t// A method for quickly swapping in/out CSS properties to get correct calculations\n +\tswap: function( elem, options, callback ) {\n +\t\tvar old = {};\n +\n +\t\t// Remember the old values, and insert the new ones\n +\t\tfor ( var name in options ) {\n +\t\t\told[ name ] = elem.style[ name ];\n +\t\t\telem.style[ name ] = options[ name ];\n +\t\t}\n +\n +\t\tcallback.call( elem );\n +\n +\t\t// Revert the old values\n +\t\tfor ( var name in options ) {\n +\t\t\telem.style[ name ] = old[ name ];\n +\t\t}\n +\t}\n +});\n +\n +if ( jQuery.expr && jQuery.expr.filters ) {\n +\tjQuery.expr.filters.hidden = function( elem ) {\n +\t\tvar width = elem.offsetWidth, height = elem.offsetHeight,\n +\t\t\tskip = elem.nodeName.toLowerCase() === "tr";\n +\n +\t\treturn width === 0 && height === 0 && !skip ?\n +\t\t\ttrue :\n +\t\t\twidth > 0 && height > 0 && !skip ?\n +\t\t\t\tfalse :\n +\t\t\t\tjQuery.curCSS(elem, "display") === "none";\n +\t};\n +\n +\tjQuery.expr.filters.visible = function( elem ) {\n +\t\treturn !jQuery.expr.filters.hidden( elem );\n +\t};\n +}\n +var jsc = now(),\n +\trscript = /<script(.|\\s)*?\\/script>/gi,\n +\trselectTextarea = /select|textarea/i,\n +\trinput = /color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,\n +\tjsre = /=\\?(&|$)/,\n +\trquery = /\\?/,\n +\trts = /(\\?|&)_=.*?(&|$)/,\n +\trurl = /^(\\w+:)?\\/\\/([^\\/?#]+)/,\n +\tr20 = /%20/g,\n +\n +\t// Keep a copy of the old load method\n +\t_load = jQuery.fn.load;\n +\n +jQuery.fn.extend({\n +\tload: function( url, params, callback ) {\n +\t\tif ( typeof url !== "string" ) {\n +\t\t\treturn _load.call( this, url );\n +\n +\t\t// Don\'t do a request if no elements are being requested\n +\t\t} else if ( !this.length ) {\n +\t\t\treturn this;\n +\t\t}\n +\n +\t\tvar off = url.indexOf(" ");\n +\t\tif ( off >= 0 ) {\n +\t\t\tvar selector = url.slice(off, url.length);\n +\t\t\turl = url.slice(0, off);\n +\t\t}\n +\n +\t\t// Default to a GET request\n +\t\tvar type = "GET";\n +\n +\t\t// If the second parameter was provided\n +\t\tif ( params ) {\n +\t\t\t// If it\'s a function\n +\t\t\tif ( jQuery.isFunction( params ) ) {\n +\t\t\t\t// We assume that it\'s the callback\n +\t\t\t\tcallback = params;\n +\t\t\t\tparams = null;\n +\n +\t\t\t// Otherwise, build a param string\n +\t\t\t} else if ( typeof params === "object" ) {\n +\t\t\t\tparams = jQuery.param( params, jQuery.ajaxSettings.traditional );\n +\t\t\t\ttype = "POST";\n +\t\t\t}\n +\t\t}\n +\n +\t\tvar self = this;\n +\n +\t\t// Request the remote document\n +\t\tjQuery.ajax({\n +\t\t\turl: url,\n +\t\t\ttype: type,\n +\t\t\tdataType: "html",\n +\t\t\tdata: params,\n +\t\t\tcomplete: function( res, status ) {\n +\t\t\t\t// If successful, inject the HTML into all the matched elements\n +\t\t\t\tif ( status === "success" || status === "notmodified" ) {\n +\t\t\t\t\t// See if a selector was specified\n +\t\t\t\t\tself.html( selector ?\n +\t\t\t\t\t\t// Create a dummy div to hold the results\n +\t\t\t\t\t\tjQuery("<div />")\n +\t\t\t\t\t\t\t// inject the contents of the document in, removing the scripts\n +\t\t\t\t\t\t\t// to avoid any \'Permission Denied\' errors in IE\n +\t\t\t\t\t\t\t.append(res.responseText.replace(rscript, ""))\n +\n +\t\t\t\t\t\t\t// Locate the specified elements\n +\t\t\t\t\t\t\t.find(selector) :\n +\n +\t\t\t\t\t\t// If not, just inject the full result\n +\t\t\t\t\t\tres.responseText );\n +\t\t\t\t}\n +\n +\t\t\t\tif ( callback ) {\n +\t\t\t\t\tself.each( callback, [res.responseText, status, res] );\n +\t\t\t\t}\n +\t\t\t}\n +\t\t});\n +\n +\t\treturn this;\n +\t},\n +\n +\tserialize: function() {\n +\t\treturn jQuery.param(this.serializeArray());\n +\t},\n +\tserializeArray: function() {\n +\t\treturn this.map(function() {\n +\t\t\treturn this.elements ? jQuery.makeArray(this.elements) : this;\n +\t\t})\n +\t\t.filter(function() {\n +\t\t\treturn this.name && !this.disabled &&\n +\t\t\t\t(this.checked || rselectTextarea.test(this.nodeName) ||\n +\t\t\t\t\trinput.test(this.type));\n +\t\t})\n +\t\t.map(function( i, elem ) {\n +\t\t\tvar val = jQuery(this).val();\n +\n +\t\t\treturn val == null ?\n +\t\t\t\tnull :\n +\t\t\t\tjQuery.isArray(val) ?\n +\t\t\t\t\tjQuery.map( val, function( val, i ) {\n +\t\t\t\t\t\treturn { name: elem.name, value: val };\n +\t\t\t\t\t}) :\n +\t\t\t\t\t{ name: elem.name, value: val };\n +\t\t}).get();\n +\t}\n +});\n +\n +// Attach a bunch of functions for handling common AJAX events\n +jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function( i, o ) {\n +\tjQuery.fn[o] = function( f ) {\n +\t\treturn this.bind(o, f);\n +\t};\n +});\n +\n +jQuery.extend({\n +\n +\tget: function( url, data, callback, type ) {\n +\t\t// shift arguments if data argument was omited\n +\t\tif ( jQuery.isFunction( data ) ) {\n +\t\t\ttype = type || callback;\n +\t\t\tcallback = data;\n +\t\t\tdata = null;\n +\t\t}\n +\n +\t\treturn jQuery.ajax({\n +\t\t\ttype: "GET",\n +\t\t\turl: url,\n +\t\t\tdata: data,\n +\t\t\tsuccess: callback,\n +\t\t\tdataType: type\n +\t\t});\n +\t},\n +\n +\tgetScript: function( url, callback ) {\n +\t\treturn jQuery.get(url, null, callback, "script");\n +\t},\n +\n +\tgetJSON: function( url, data, callback ) {\n +\t\treturn jQuery.get(url, data, callback, "json");\n +\t},\n +\n +\tpost: function( url, data, callback, type ) {\n +\t\t// shift arguments if data argument was omited\n +\t\tif ( jQuery.isFunction( data ) ) {\n +\t\t\ttype = type || callback;\n +\t\t\tcallback = data;\n +\t\t\tdata = {};\n +\t\t}\n +\n +\t\treturn jQuery.ajax({\n +\t\t\ttype: "POST",\n +\t\t\turl: url,\n +\t\t\tdata: data,\n +\t\t\tsuccess: callback,\n +\t\t\tdataType: type\n +\t\t});\n +\t},\n +\n +\tajaxSetup: function( settings ) {\n +\t\tjQuery.extend( jQuery.ajaxSettings, settings );\n +\t},\n +\n +\tajaxSettings: {\n +\t\turl: location.href,\n +\t\tglobal: true,\n +\t\ttype: "GET",\n +\t\tcontentType: "application/x-www-form-urlencoded",\n +\t\tprocessData: true,\n +\t\tasync: true,\n +\t\t/*\n +\t\ttimeout: 0,\n +\t\tdata: null,\n +\t\tusername: null,\n +\t\tpassword: null,\n +\t\ttraditional: false,\n +\t\t*/\n +\t\t// Create the request object; Microsoft failed to properly\n +\t\t// implement the XMLHttpRequest in IE7 (can\'t request local files),\n +\t\t// so we use the ActiveXObject when it is available\n +\t\t// This function can be overriden by calling jQuery.ajaxSetup\n +\t\txhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?\n +\t\t\tfunction() {\n +\t\t\t\treturn new window.XMLHttpRequest();\n +\t\t\t} :\n +\t\t\tfunction() {\n +\t\t\t\ttry {\n +\t\t\t\t\treturn new window.ActiveXObject("Microsoft.XMLHTTP");\n +\t\t\t\t} catch(e) {}\n +\t\t\t},\n +\t\taccepts: {\n +\t\t\txml: "application/xml, text/xml",\n +\t\t\thtml: "text/html",\n +\t\t\tscript: "text/javascript, application/javascript",\n +\t\t\tjson: "application/json, text/javascript",\n +\t\t\ttext: "text/plain",\n +\t\t\t_default: "*/*"\n +\t\t}\n +\t},\n +\n +\t// Last-Modified header cache for next request\n +\tlastModified: {},\n +\tetag: {},\n +\n +\tajax: function( origSettings ) {\n +\t\tvar s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);\n +\t\t\n +\t\tvar jsonp, status, data,\n +\t\t\tcallbackContext = origSettings && origSettings.context || s,\n +\t\t\ttype = s.type.toUpperCase();\n +\n +\t\t// convert data if not already a string\n +\t\tif ( s.data && s.processData && typeof s.data !== "string" ) {\n +\t\t\ts.data = jQuery.param( s.data, s.traditional );\n +\t\t}\n +\n +\t\t// Handle JSONP Parameter Callbacks\n +\t\tif ( s.dataType === "jsonp" ) {\n +\t\t\tif ( type === "GET" ) {\n +\t\t\t\tif ( !jsre.test( s.url ) ) {\n +\t\t\t\t\ts.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";\n +\t\t\t\t}\n +\t\t\t} else if ( !s.data || !jsre.test(s.data) ) {\n +\t\t\t\ts.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";\n +\t\t\t}\n +\t\t\ts.dataType = "json";\n +\t\t}\n +\n +\t\t// Build temporary JSONP function\n +\t\tif ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {\n +\t\t\tjsonp = s.jsonpCallback || ("jsonp" + jsc++);\n +\n +\t\t\t// Replace the =? sequence both in the query string and the data\n +\t\t\tif ( s.data ) {\n +\t\t\t\ts.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");\n +\t\t\t}\n +\n +\t\t\ts.url = s.url.replace(jsre, "=" + jsonp + "$1");\n +\n +\t\t\t// We need to make sure\n +\t\t\t// that a JSONP style response is executed properly\n +\t\t\ts.dataType = "script";\n +\n +\t\t\t// Handle JSONP-style loading\n +\t\t\twindow[ jsonp ] = window[ jsonp ] || function( tmp ) {\n +\t\t\t\tdata = tmp;\n +\t\t\t\tsuccess();\n +\t\t\t\tcomplete();\n +\t\t\t\t// Garbage collect\n +\t\t\t\twindow[ jsonp ] = undefined;\n +\n +\t\t\t\ttry {\n +\t\t\t\t\tdelete window[ jsonp ];\n +\t\t\t\t} catch(e) {}\n +\n +\t\t\t\tif ( head ) {\n +\t\t\t\t\thead.removeChild( script );\n +\t\t\t\t}\n +\t\t\t};\n +\t\t}\n +\n +\t\tif ( s.dataType === "script" && s.cache === null ) {\n +\t\t\ts.cache = false;\n +\t\t}\n +\n +\t\tif ( s.cache === false && type === "GET" ) {\n +\t\t\tvar ts = now();\n +\n +\t\t\t// try replacing _= if it is there\n +\t\t\tvar ret = s.url.replace(rts, "$1_=" + ts + "$2");\n +\n +\t\t\t// if nothing was replaced, add timestamp to the end\n +\t\t\ts.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");\n +\t\t}\n +\n +\t\t// If data is available, append data to url for get requests\n +\t\tif ( s.data && type === "GET" ) {\n +\t\t\ts.url += (rquery.test(s.url) ? "&" : "?") + s.data;\n +\t\t}\n +\n +\t\t// Watch for a new set of requests\n +\t\tif ( s.global && ! jQuery.active++ ) {\n +\t\t\tjQuery.event.trigger( "ajaxStart" );\n +\t\t}\n +\n +\t\t// Matches an absolute URL, and saves the domain\n +\t\tvar parts = rurl.exec( s.url ),\n +\t\t\tremote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);\n +\n +\t\t// If we\'re requesting a remote document\n +\t\t// and trying to load JSON or Script with a GET\n +\t\tif ( s.dataType === "script" && type === "GET" && remote ) {\n +\t\t\tvar head = document.getElementsByTagName("head")[0] || document.documentElement;\n +\t\t\tvar script = document.createElement("script");\n +\t\t\tscript.src = s.url;\n +\t\t\tif ( s.scriptCharset ) {\n +\t\t\t\tscript.charset = s.scriptCharset;\n +\t\t\t}\n +\n +\t\t\t// Handle Script loading\n +\t\t\tif ( !jsonp ) {\n +\t\t\t\tvar done = false;\n +\n +\t\t\t\t// Attach handlers for all browsers\n +\t\t\t\tscript.onload = script.onreadystatechange = function() {\n +\t\t\t\t\tif ( !done && (!this.readyState ||\n +\t\t\t\t\t\t\tthis.readyState === "loaded" || this.readyState === "complete") ) {\n +\t\t\t\t\t\tdone = true;\n +\t\t\t\t\t\tsuccess();\n +\t\t\t\t\t\tcomplete();\n +\n +\t\t\t\t\t\t// Handle memory leak in IE\n +\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n +\t\t\t\t\t\tif ( head && script.parentNode ) {\n +\t\t\t\t\t\t\thead.removeChild( script );\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// Use insertBefore instead of appendChild to circumvent an IE6 bug.\n +\t\t\t// This arises when a base node is used (#2709 and #4378).\n +\t\t\thead.insertBefore( script, head.firstChild );\n +\n +\t\t\t// We handle everything using the script element injection\n +\t\t\treturn undefined;\n +\t\t}\n +\n +\t\tvar requestDone = false;\n +\n +\t\t// Create the request object\n +\t\tvar xhr = s.xhr();\n +\n +\t\tif ( !xhr ) {\n +\t\t\treturn;\n +\t\t}\n +\n +\t\t// Open the socket\n +\t\t// Passing null username, generates a login popup on Opera (#2865)\n +\t\tif ( s.username ) {\n +\t\t\txhr.open(type, s.url, s.async, s.username, s.password);\n +\t\t} else {\n +\t\t\txhr.open(type, s.url, s.async);\n +\t\t}\n +\n +\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n +\t\ttry {\n +\t\t\t// Set the correct header, if data is being sent\n +\t\t\tif ( s.data || origSettings && origSettings.contentType ) {\n +\t\t\t\txhr.setRequestHeader("Content-Type", s.contentType);\n +\t\t\t}\n +\n +\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n +\t\t\tif ( s.ifModified ) {\n +\t\t\t\tif ( jQuery.lastModified[s.url] ) {\n +\t\t\t\t\txhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);\n +\t\t\t\t}\n +\n +\t\t\t\tif ( jQuery.etag[s.url] ) {\n +\t\t\t\t\txhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\t// Set header so the called script knows that it\'s an XMLHttpRequest\n +\t\t\t// Only send the header if it\'s not a remote XHR\n +\t\t\tif ( !remote ) {\n +\t\t\t\txhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");\n +\t\t\t}\n +\n +\t\t\t// Set the Accepts header for the server, depending on the dataType\n +\t\t\txhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?\n +\t\t\t\ts.accepts[ s.dataType ] + ", */*" :\n +\t\t\t\ts.accepts._default );\n +\t\t} catch(e) {}\n +\n +\t\t// Allow custom headers/mimetypes and early abort\n +\t\tif ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {\n +\t\t\t// Handle the global AJAX counter\n +\t\t\tif ( s.global && ! --jQuery.active ) {\n +\t\t\t\tjQuery.event.trigger( "ajaxStop" );\n +\t\t\t}\n +\n +\t\t\t// close opended socket\n +\t\t\txhr.abort();\n +\t\t\treturn false;\n +\t\t}\n +\n +\t\tif ( s.global ) {\n +\t\t\ttrigger("ajaxSend", [xhr, s]);\n +\t\t}\n +\n +\t\t// Wait for a response to come back\n +\t\tvar onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {\n +\t\t\t// The request was aborted\n +\t\t\tif ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {\n +\t\t\t\t// Opera doesn\'t call onreadystatechange before this point\n +\t\t\t\t// so we simulate the call\n +\t\t\t\tif ( !requestDone ) {\n +\t\t\t\t\tcomplete();\n +\t\t\t\t}\n +\n +\t\t\t\trequestDone = true;\n +\t\t\t\tif ( xhr ) {\n +\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n +\t\t\t\t}\n +\n +\t\t\t// The transfer is complete and the data is available, or the request timed out\n +\t\t\t} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {\n +\t\t\t\trequestDone = true;\n +\t\t\t\txhr.onreadystatechange = jQuery.noop;\n +\n +\t\t\t\tstatus = isTimeout === "timeout" ?\n +\t\t\t\t\t"timeout" :\n +\t\t\t\t\t!jQuery.httpSuccess( xhr ) ?\n +\t\t\t\t\t\t"error" :\n +\t\t\t\t\t\ts.ifModified && jQuery.httpNotModified( xhr, s.url ) ?\n +\t\t\t\t\t\t\t"notmodified" :\n +\t\t\t\t\t\t\t"success";\n +\n +\t\t\t\tvar errMsg;\n +\n +\t\t\t\tif ( status === "success" ) {\n +\t\t\t\t\t// Watch for, and catch, XML document parse errors\n +\t\t\t\t\ttry {\n +\t\t\t\t\t\t// process the data (runs the xml through httpData regardless of callback)\n +\t\t\t\t\t\tdata = jQuery.httpData( xhr, s.dataType, s );\n +\t\t\t\t\t} catch(err) {\n +\t\t\t\t\t\tstatus = "parsererror";\n +\t\t\t\t\t\terrMsg = err;\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\t// Make sure that the request was successful or notmodified\n +\t\t\t\tif ( status === "success" || status === "notmodified" ) {\n +\t\t\t\t\t// JSONP handles its own success callback\n +\t\t\t\t\tif ( !jsonp ) {\n +\t\t\t\t\t\tsuccess();\n +\t\t\t\t\t}\n +\t\t\t\t} else {\n +\t\t\t\t\tjQuery.handleError(s, xhr, status, errMsg);\n +\t\t\t\t}\n +\n +\t\t\t\t// Fire the complete handlers\n +\t\t\t\tcomplete();\n +\n +\t\t\t\tif ( isTimeout === "timeout" ) {\n +\t\t\t\t\txhr.abort();\n +\t\t\t\t}\n +\n +\t\t\t\t// Stop memory leaks\n +\t\t\t\tif ( s.async ) {\n +\t\t\t\t\txhr = null;\n +\t\t\t\t}\n +\t\t\t}\n +\t\t};\n +\n +\t\t// Override the abort handler, if we can (IE doesn\'t allow it, but that\'s OK)\n +\t\t// Opera doesn\'t fire onreadystatechange at all on abort\n +\t\ttry {\n +\t\t\tvar oldAbort = xhr.abort;\n +\t\t\txhr.abort = function() {\n +\t\t\t\tif ( xhr ) {\n +\t\t\t\t\toldAbort.call( xhr );\n +\t\t\t\t}\n +\n +\t\t\t\tonreadystatechange( "abort" );\n +\t\t\t};\n +\t\t} catch(e) { }\n +\n +\t\t// Timeout checker\n +\t\tif ( s.async && s.timeout > 0 ) {\n +\t\t\tsetTimeout(function() {\n +\t\t\t\t// Check to see if the request is still happening\n +\t\t\t\tif ( xhr && !requestDone ) {\n +\t\t\t\t\tonreadystatechange( "timeout" );\n +\t\t\t\t}\n +\t\t\t}, s.timeout);\n +\t\t}\n +\n +\t\t// Send the data\n +\t\ttry {\n +\t\t\txhr.send( type === "POST" || type === "PUT" || type === "DELETE" ? s.data : null );\n +\t\t} catch(e) {\n +\t\t\tjQuery.handleError(s, xhr, null, e);\n +\t\t\t// Fire the complete handlers\n +\t\t\tcomplete();\n +\t\t}\n +\n +\t\t// firefox 1.5 doesn\'t fire statechange for sync requests\n +\t\tif ( !s.async ) {\n +\t\t\tonreadystatechange();\n +\t\t}\n +\n +\t\tfunction success() {\n +\t\t\t// If a local callback was specified, fire it and pass it the data\n +\t\t\tif ( s.success ) {\n +\t\t\t\ts.success.call( callbackContext, data, status, xhr );\n +\t\t\t}\n +\n +\t\t\t// Fire the global callback\n +\t\t\tif ( s.global ) {\n +\t\t\t\ttrigger( "ajaxSuccess", [xhr, s] );\n +\t\t\t}\n +\t\t}\n +\n +\t\tfunction complete() {\n +\t\t\t// Process result\n +\t\t\tif ( s.complete ) {\n +\t\t\t\ts.complete.call( callbackContext, xhr, status);\n +\t\t\t}\n +\n +\t\t\t// The request was completed\n +\t\t\tif ( s.global ) {\n +\t\t\t\ttrigger( "ajaxComplete", [xhr, s] );\n +\t\t\t}\n +\n +\t\t\t// Handle the global AJAX counter\n +\t\t\tif ( s.global && ! --jQuery.active ) {\n +\t\t\t\tjQuery.event.trigger( "ajaxStop" );\n +\t\t\t}\n +\t\t}\n +\t\t\n +\t\tfunction trigger(type, args) {\n +\t\t\t(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);\n +\t\t}\n +\n +\t\t// return XMLHttpRequest to allow aborting the request etc.\n +\t\treturn xhr;\n +\t},\n +\n +\thandleError: function( s, xhr, status, e ) {\n +\t\t// If a local callback was specified, fire it\n +\t\tif ( s.error ) {\n +\t\t\ts.error.call( s.context || s, xhr, status, e );\n +\t\t}\n +\n +\t\t// Fire the global callback\n +\t\tif ( s.global ) {\n +\t\t\t(s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );\n +\t\t}\n +\t},\n +\n +\t// Counter for holding the number of active queries\n +\tactive: 0,\n +\n +\t// Determines if an XMLHttpRequest was successful or not\n +\thttpSuccess: function( xhr ) {\n +\t\ttry {\n +\t\t\t// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450\n +\t\t\treturn !xhr.status && location.protocol === "file:" ||\n +\t\t\t\t// Opera returns 0 when status is 304\n +\t\t\t\t( xhr.status >= 200 && xhr.status < 300 ) ||\n +\t\t\t\txhr.status === 304 || xhr.status === 1223 || xhr.status === 0;\n +\t\t} catch(e) {}\n +\n +\t\treturn false;\n +\t},\n +\n +\t// Determines if an XMLHttpRequest returns NotModified\n +\thttpNotModified: function( xhr, url ) {\n +\t\tvar lastModified = xhr.getResponseHeader("Last-Modified"),\n +\t\t\tetag = xhr.getResponseHeader("Etag");\n +\n +\t\tif ( lastModified ) {\n +\t\t\tjQuery.lastModified[url] = lastModified;\n +\t\t}\n +\n +\t\tif ( etag ) {\n +\t\t\tjQuery.etag[url] = etag;\n +\t\t}\n +\n +\t\t// Opera returns 0 when status is 304\n +\t\treturn xhr.status === 304 || xhr.status === 0;\n +\t},\n +\n +\thttpData: function( xhr, type, s ) {\n +\t\tvar ct = xhr.getResponseHeader("content-type") || "",\n +\t\t\txml = type === "xml" || !type && ct.indexOf("xml") >= 0,\n +\t\t\tdata = xml ? xhr.responseXML : xhr.responseText;\n +\n +\t\tif ( xml && data.documentElement.nodeName === "parsererror" ) {\n +\t\t\tjQuery.error( "parsererror" );\n +\t\t}\n +\n +\t\t// Allow a pre-filtering function to sanitize the response\n +\t\t// s is checked to keep backwards compatibility\n +\t\tif ( s && s.dataFilter ) {\n +\t\t\tdata = s.dataFilter( data, type );\n +\t\t}\n +\n +\t\t// The filter can actually parse the response\n +\t\tif ( typeof data === "string" ) {\n +\t\t\t// Get the JavaScript object, if JSON is used.\n +\t\t\tif ( type === "json" || !type && ct.indexOf("json") >= 0 ) {\n +\t\t\t\tdata = jQuery.parseJSON( data );\n +\n +\t\t\t// If the type is "script", eval it in global context\n +\t\t\t} else if ( type === "script" || !type && ct.indexOf("javascript") >= 0 ) {\n +\t\t\t\tjQuery.globalEval( data );\n +\t\t\t}\n +\t\t}\n +\n +\t\treturn data;\n +\t},\n +\n +\t// Serialize an array of form elements or a set of\n +\t// key/values into a query string\n +\tparam: function( a, traditional ) {\n +\t\tvar s = [];\n +\t\t\n +\t\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n +\t\tif ( traditional === undefined ) {\n +\t\t\ttraditional = jQuery.ajaxSettings.traditional;\n +\t\t}\n +\t\t\n +\t\t// If an array was passed in, assume that it is an array of form elements.\n +\t\tif ( jQuery.isArray(a) || a.jquery ) {\n +\t\t\t// Serialize the form elements\n +\t\t\tjQuery.each( a, function() {\n +\t\t\t\tadd( this.name, this.value );\n +\t\t\t});\n +\t\t\t\n +\t\t} else {\n +\t\t\t// If traditional, encode the "old" way (the way 1.3.2 or older\n +\t\t\t// did it), otherwise encode params recursively.\n +\t\t\tfor ( var prefix in a ) {\n +\t\t\t\tbuildParams( prefix, a[prefix] );\n +\t\t\t}\n +\t\t}\n +\n +\t\t// Return the resulting serialization\n +\t\treturn s.join("&").replace(r20, "+");\n +\n +\t\tfunction buildParams( prefix, obj ) {\n +\t\t\tif ( jQuery.isArray(obj) ) {\n +\t\t\t\t// Serialize array item.\n +\t\t\t\tjQuery.each( obj, function( i, v ) {\n +\t\t\t\t\tif ( traditional || /\\[\\]$/.test( prefix ) ) {\n +\t\t\t\t\t\t// Treat each array item as a scalar.\n +\t\t\t\t\t\tadd( prefix, v );\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\t// If array item is non-scalar (array or object), encode its\n +\t\t\t\t\t\t// numeric index to resolve deserialization ambiguity issues.\n +\t\t\t\t\t\t// Note that rack (as of 1.0.0) can\'t currently deserialize\n +\t\t\t\t\t\t// nested arrays properly, and attempting to do so may cause\n +\t\t\t\t\t\t// a server error. Possible fixes are to modify rack\'s\n +\t\t\t\t\t\t// deserialization algorithm or to provide an option or flag\n +\t\t\t\t\t\t// to force array serialization to be shallow.\n +\t\t\t\t\t\tbuildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v );\n +\t\t\t\t\t}\n +\t\t\t\t});\n +\t\t\t\t\t\n +\t\t\t} else if ( !traditional && obj != null && typeof obj === "object" ) {\n +\t\t\t\t// Serialize object item.\n +\t\t\t\tjQuery.each( obj, function( k, v ) {\n +\t\t\t\t\tbuildParams( prefix + "[" + k + "]", v );\n +\t\t\t\t});\n +\t\t\t\t\t\n +\t\t\t} else {\n +\t\t\t\t// Serialize scalar item.\n +\t\t\t\tadd( prefix, obj );\n +\t\t\t}\n +\t\t}\n +\n +\t\tfunction add( key, value ) {\n +\t\t\t// If value is a function, invoke it and return its value\n +\t\t\tvalue = jQuery.isFunction(value) ? value() : value;\n +\t\t\ts[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);\n +\t\t}\n +\t}\n +});\n +var elemdisplay = {},\n +\trfxtypes = /toggle|show|hide/,\n +\trfxnum = /^([+-]=)?([\\d+-.]+)(.*)$/,\n +\ttimerId,\n +\tfxAttrs = [\n +\t\t// height animations\n +\t\t[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],\n +\t\t// width animations\n +\t\t[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],\n +\t\t// opacity animations\n +\t\t[ "opacity" ]\n +\t];\n +\n +jQuery.fn.extend({\n +\tshow: function( speed, callback ) {\n +\t\tif ( speed || speed === 0) {\n +\t\t\treturn this.animate( genFx("show", 3), speed, callback);\n +\n +\t\t} else {\n +\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\tvar old = jQuery.data(this[i], "olddisplay");\n +\n +\t\t\t\tthis[i].style.display = old || "";\n +\n +\t\t\t\tif ( jQuery.css(this[i], "display") === "none" ) {\n +\t\t\t\t\tvar nodeName = this[i].nodeName, display;\n +\n +\t\t\t\t\tif ( elemdisplay[ nodeName ] ) {\n +\t\t\t\t\t\tdisplay = elemdisplay[ nodeName ];\n +\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\tvar elem = jQuery("<" + nodeName + " />").appendTo("body");\n +\n +\t\t\t\t\t\tdisplay = elem.css("display");\n +\n +\t\t\t\t\t\tif ( display === "none" ) {\n +\t\t\t\t\t\t\tdisplay = "block";\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\telem.remove();\n +\n +\t\t\t\t\t\telemdisplay[ nodeName ] = display;\n +\t\t\t\t\t}\n +\n +\t\t\t\t\tjQuery.data(this[i], "olddisplay", display);\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\t// Set the display of the elements in a second loop\n +\t\t\t// to avoid the constant reflow\n +\t\t\tfor ( var j = 0, k = this.length; j < k; j++ ) {\n +\t\t\t\tthis[j].style.display = jQuery.data(this[j], "olddisplay") || "";\n +\t\t\t}\n +\n +\t\t\treturn this;\n +\t\t}\n +\t},\n +\n +\thide: function( speed, callback ) {\n +\t\tif ( speed || speed === 0 ) {\n +\t\t\treturn this.animate( genFx("hide", 3), speed, callback);\n +\n +\t\t} else {\n +\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n +\t\t\t\tvar old = jQuery.data(this[i], "olddisplay");\n +\t\t\t\tif ( !old && old !== "none" ) {\n +\t\t\t\t\tjQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\t// Set the display of the elements in a second loop\n +\t\t\t// to avoid the constant reflow\n +\t\t\tfor ( var j = 0, k = this.length; j < k; j++ ) {\n +\t\t\t\tthis[j].style.display = "none";\n +\t\t\t}\n +\n +\t\t\treturn this;\n +\t\t}\n +\t},\n +\n +\t// Save the old toggle function\n +\t_toggle: jQuery.fn.toggle,\n +\n +\ttoggle: function( fn, fn2 ) {\n +\t\tvar bool = typeof fn === "boolean";\n +\n +\t\tif ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {\n +\t\t\tthis._toggle.apply( this, arguments );\n +\n +\t\t} else if ( fn == null || bool ) {\n +\t\t\tthis.each(function() {\n +\t\t\t\tvar state = bool ? fn : jQuery(this).is(":hidden");\n +\t\t\t\tjQuery(this)[ state ? "show" : "hide" ]();\n +\t\t\t});\n +\n +\t\t} else {\n +\t\t\tthis.animate(genFx("toggle", 3), fn, fn2);\n +\t\t}\n +\n +\t\treturn this;\n +\t},\n +\n +\tfadeTo: function( speed, to, callback ) {\n +\t\treturn this.filter(":hidden").css("opacity", 0).show().end()\n +\t\t\t\t\t.animate({opacity: to}, speed, callback);\n +\t},\n +\n +\tanimate: function( prop, speed, easing, callback ) {\n +\t\tvar optall = jQuery.speed(speed, easing, callback);\n +\n +\t\tif ( jQuery.isEmptyObject( prop ) ) {\n +\t\t\treturn this.each( optall.complete );\n +\t\t}\n +\n +\t\treturn this[ optall.queue === false ? "each" : "queue" ](function() {\n +\t\t\tvar opt = jQuery.extend({}, optall), p,\n +\t\t\t\thidden = this.nodeType === 1 && jQuery(this).is(":hidden"),\n +\t\t\t\tself = this;\n +\n +\t\t\tfor ( p in prop ) {\n +\t\t\t\tvar name = p.replace(rdashAlpha, fcamelCase);\n +\n +\t\t\t\tif ( p !== name ) {\n +\t\t\t\t\tprop[ name ] = prop[ p ];\n +\t\t\t\t\tdelete prop[ p ];\n +\t\t\t\t\tp = name;\n +\t\t\t\t}\n +\n +\t\t\t\tif ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) {\n +\t\t\t\t\treturn opt.complete.call(this);\n +\t\t\t\t}\n +\n +\t\t\t\tif ( ( p === "height" || p === "width" ) && this.style ) {\n +\t\t\t\t\t// Store display property\n +\t\t\t\t\topt.display = jQuery.css(this, "display");\n +\n +\t\t\t\t\t// Make sure that nothing sneaks out\n +\t\t\t\t\topt.overflow = this.style.overflow;\n +\t\t\t\t}\n +\n +\t\t\t\tif ( jQuery.isArray( prop[p] ) ) {\n +\t\t\t\t\t// Create (if needed) and add to specialEasing\n +\t\t\t\t\t(opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];\n +\t\t\t\t\tprop[p] = prop[p][0];\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\tif ( opt.overflow != null ) {\n +\t\t\t\tthis.style.overflow = "hidden";\n +\t\t\t}\n +\n +\t\t\topt.curAnim = jQuery.extend({}, prop);\n +\n +\t\t\tjQuery.each( prop, function( name, val ) {\n +\t\t\t\tvar e = new jQuery.fx( self, opt, name );\n +\n +\t\t\t\tif ( rfxtypes.test(val) ) {\n +\t\t\t\t\te[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop );\n +\n +\t\t\t\t} else {\n +\t\t\t\t\tvar parts = rfxnum.exec(val),\n +\t\t\t\t\t\tstart = e.cur(true) || 0;\n +\n +\t\t\t\t\tif ( parts ) {\n +\t\t\t\t\t\tvar end = parseFloat( parts[2] ),\n +\t\t\t\t\t\t\tunit = parts[3] || "px";\n +\n +\t\t\t\t\t\t// We need to compute starting value\n +\t\t\t\t\t\tif ( unit !== "px" ) {\n +\t\t\t\t\t\t\tself.style[ name ] = (end || 1) + unit;\n +\t\t\t\t\t\t\tstart = ((end || 1) / e.cur(true)) * start;\n +\t\t\t\t\t\t\tself.style[ name ] = start + unit;\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\t// If a +=/-= token was provided, we\'re doing a relative animation\n +\t\t\t\t\t\tif ( parts[1] ) {\n +\t\t\t\t\t\t\tend = ((parts[1] === "-=" ? -1 : 1) * end) + start;\n +\t\t\t\t\t\t}\n +\n +\t\t\t\t\t\te.custom( start, end, unit );\n +\n +\t\t\t\t\t} else {\n +\t\t\t\t\t\te.custom( start, val, "" );\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\t\t\t});\n +\n +\t\t\t// For JS strict compliance\n +\t\t\treturn true;\n +\t\t});\n +\t},\n +\n +\tstop: function( clearQueue, gotoEnd ) {\n +\t\tvar timers = jQuery.timers;\n +\n +\t\tif ( clearQueue ) {\n +\t\t\tthis.queue([]);\n +\t\t}\n +\n +\t\tthis.each(function() {\n +\t\t\t// go in reverse order so anything added to the queue during the loop is ignored\n +\t\t\tfor ( var i = timers.length - 1; i >= 0; i-- ) {\n +\t\t\t\tif ( timers[i].elem === this ) {\n +\t\t\t\t\tif (gotoEnd) {\n +\t\t\t\t\t\t// force the next step to be the last\n +\t\t\t\t\t\ttimers[i](true);\n +\t\t\t\t\t}\n +\n +\t\t\t\t\ttimers.splice(i, 1);\n +\t\t\t\t}\n +\t\t\t}\n +\t\t});\n +\n +\t\t// start the next in the queue if the last step wasn\'t forced\n +\t\tif ( !gotoEnd ) {\n +\t\t\tthis.dequeue();\n +\t\t}\n +\n +\t\treturn this;\n +\t}\n +\n +});\n +\n +// Generate shortcuts for custom animations\n +jQuery.each({\n +\tslideDown: genFx("show", 1),\n +\tslideUp: genFx("hide", 1),\n +\tslideToggle: genFx("toggle", 1),\n +\tfadeIn: { opacity: "show" },\n +\tfadeOut: { opacity: "hide" }\n +}, function( name, props ) {\n +\tjQuery.fn[ name ] = function( speed, callback ) {\n +\t\treturn this.animate( props, speed, callback );\n +\t};\n +});\n +\n +jQuery.extend({\n +\tspeed: function( speed, easing, fn ) {\n +\t\tvar opt = speed && typeof speed === "object" ? speed : {\n +\t\t\tcomplete: fn || !fn && easing ||\n +\t\t\t\tjQuery.isFunction( speed ) && speed,\n +\t\t\tduration: speed,\n +\t\t\teasing: fn && easing || easing && !jQuery.isFunction(easing) && easing\n +\t\t};\n +\n +\t\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :\n +\t\t\tjQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;\n +\n +\t\t// Queueing\n +\t\topt.old = opt.complete;\n +\t\topt.complete = function() {\n +\t\t\tif ( opt.queue !== false ) {\n +\t\t\t\tjQuery(this).dequeue();\n +\t\t\t}\n +\t\t\tif ( jQuery.isFunction( opt.old ) ) {\n +\t\t\t\topt.old.call( this );\n +\t\t\t}\n +\t\t};\n +\n +\t\treturn opt;\n +\t},\n +\n +\teasing: {\n +\t\tlinear: function( p, n, firstNum, diff ) {\n +\t\t\treturn firstNum + diff * p;\n +\t\t},\n +\t\tswing: function( p, n, firstNum, diff ) {\n +\t\t\treturn ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;\n +\t\t}\n +\t},\n +\n +\ttimers: [],\n +\n +\tfx: function( elem, options, prop ) {\n +\t\tthis.options = options;\n +\t\tthis.elem = elem;\n +\t\tthis.prop = prop;\n +\n +\t\tif ( !options.orig ) {\n +\t\t\toptions.orig = {};\n +\t\t}\n +\t}\n +\n +});\n +\n +jQuery.fx.prototype = {\n +\t// Simple function for setting a style value\n +\tupdate: function() {\n +\t\tif ( this.options.step ) {\n +\t\t\tthis.options.step.call( this.elem, this.now, this );\n +\t\t}\n +\n +\t\t(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );\n +\n +\t\t// Set display property to block for height/width animations\n +\t\tif ( ( this.prop === "height" || this.prop === "width" ) && this.elem.style ) {\n +\t\t\tthis.elem.style.display = "block";\n +\t\t}\n +\t},\n +\n +\t// Get the current size\n +\tcur: function( force ) {\n +\t\tif ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {\n +\t\t\treturn this.elem[ this.prop ];\n +\t\t}\n +\n +\t\tvar r = parseFloat(jQuery.css(this.elem, this.prop, force));\n +\t\treturn r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;\n +\t},\n +\n +\t// Start an animation from one number to another\n +\tcustom: function( from, to, unit ) {\n +\t\tthis.startTime = now();\n +\t\tthis.start = from;\n +\t\tthis.end = to;\n +\t\tthis.unit = unit || this.unit || "px";\n +\t\tthis.now = this.start;\n +\t\tthis.pos = this.state = 0;\n +\n +\t\tvar self = this;\n +\t\tfunction t( gotoEnd ) {\n +\t\t\treturn self.step(gotoEnd);\n +\t\t}\n +\n +\t\tt.elem = this.elem;\n +\n +\t\tif ( t() && jQuery.timers.push(t) && !timerId ) {\n +\t\t\ttimerId = setInterval(jQuery.fx.tick, 13);\n +\t\t}\n +\t},\n +\n +\t// Simple \'show\' function\n +\tshow: function() {\n +\t\t// Remember where we started, so that we can go back to it later\n +\t\tthis.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n +\t\tthis.options.show = true;\n +\n +\t\t// Begin the animation\n +\t\t// Make sure that we start at a small width/height to avoid any\n +\t\t// flash of content\n +\t\tthis.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());\n +\n +\t\t// Start by showing the element\n +\t\tjQuery( this.elem ).show();\n +\t},\n +\n +\t// Simple \'hide\' function\n +\thide: function() {\n +\t\t// Remember where we started, so that we can go back to it later\n +\t\tthis.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n +\t\tthis.options.hide = true;\n +\n +\t\t// Begin the animation\n +\t\tthis.custom(this.cur(), 0);\n +\t},\n +\n +\t// Each step of an animation\n +\tstep: function( gotoEnd ) {\n +\t\tvar t = now(), done = true;\n +\n +\t\tif ( gotoEnd || t >= this.options.duration + this.startTime ) {\n +\t\t\tthis.now = this.end;\n +\t\t\tthis.pos = this.state = 1;\n +\t\t\tthis.update();\n +\n +\t\t\tthis.options.curAnim[ this.prop ] = true;\n +\n +\t\t\tfor ( var i in this.options.curAnim ) {\n +\t\t\t\tif ( this.options.curAnim[i] !== true ) {\n +\t\t\t\t\tdone = false;\n +\t\t\t\t}\n +\t\t\t}\n +\n +\t\t\tif ( done ) {\n +\t\t\t\tif ( this.options.display != null ) {\n +\t\t\t\t\t// Reset the overflow\n +\t\t\t\t\tthis.elem.style.overflow = this.options.overflow;\n +\n +\t\t\t\t\t// Reset the display\n +\t\t\t\t\tvar old = jQuery.data(this.elem, "olddisplay");\n +\t\t\t\t\tthis.elem.style.display = old ? old : this.options.display;\n +\n +\t\t\t\t\tif ( jQuery.css(this.elem, "display") === "none" ) {\n +\t\t\t\t\t\tthis.elem.style.display = "block";\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\t// Hide the element if the "hide" operation was done\n +\t\t\t\tif ( this.options.hide ) {\n +\t\t\t\t\tjQuery(this.elem).hide();\n +\t\t\t\t}\n +\n +\t\t\t\t// Reset the properties, if the item has been hidden or shown\n +\t\t\t\tif ( this.options.hide || this.options.show ) {\n +\t\t\t\t\tfor ( var p in this.options.curAnim ) {\n +\t\t\t\t\t\tjQuery.style(this.elem, p, this.options.orig[p]);\n +\t\t\t\t\t}\n +\t\t\t\t}\n +\n +\t\t\t\t// Execute the complete function\n +\t\t\t\tthis.options.complete.call( this.elem );\n +\t\t\t}\n +\n +\t\t\treturn false;\n +\n +\t\t} else {\n +\t\t\tvar n = t - this.startTime;\n +\t\t\tthis.state = n / this.options.duration;\n +\n +\t\t\t// Perform the easing function, defaults to swing\n +\t\t\tvar specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];\n +\t\t\tvar defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear");\n +\t\t\tthis.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);\n +\t\t\tthis.now = this.start + ((this.end - this.start) * this.pos);\n +\n +\t\t\t// Perform the next step of the animation\n +\t\t\tthis.update();\n +\t\t}\n +\n +\t\treturn true;\n +\t}\n +};\n +\n +jQuery.extend( jQuery.fx, {\n +\ttick: function() {\n +\t\tvar timers = jQuery.timers;\n +\n +\t\tfor ( var i = 0; i < timers.length; i++ ) {\n +\t\t\tif ( !timers[i]() ) {\n +\t\t\t\ttimers.splice(i--, 1);\n +\t\t\t}\n +\t\t}\n +\n +\t\tif ( !timers.length ) {\n +\t\t\tjQuery.fx.stop();\n +\t\t}\n +\t},\n +\t\t\n +\tstop: function() {\n +\t\tclearInterval( timerId );\n +\t\ttimerId = null;\n +\t},\n +\t\n +\tspeeds: {\n +\t\tslow: 600,\n + \t\tfast: 200,\n + \t\t// Default speed\n + \t\t_default: 400\n +\t},\n +\n +\tstep: {\n +\t\topacity: function( fx ) {\n +\t\t\tjQuery.style(fx.elem, "opacity", fx.now);\n +\t\t},\n +\n +\t\t_default: function( fx ) {\n +\t\t\tif ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {\n +\t\t\t\tfx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;\n +\t\t\t} else {\n +\t\t\t\tfx.elem[ fx.prop ] = fx.now;\n +\t\t\t}\n +\t\t}\n +\t}\n +});\n +\n +if ( jQuery.expr && jQuery.expr.filters ) {\n +\tjQuery.expr.filters.animated = function( elem ) {\n +\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n +\t\t\treturn elem === fn.elem;\n +\t\t}).length;\n +\t};\n +}\n +\n +function genFx( type, num ) {\n +\tvar obj = {};\n +\n +\tjQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {\n +\t\tobj[ this ] = type;\n +\t});\n +\n +\treturn obj;\n +}\n +if ( "getBoundingClientRect" in document.documentElement ) {\n +\tjQuery.fn.offset = function( options ) {\n +\t\tvar elem = this[0];\n +\n +\t\tif ( options ) { \n +\t\t\treturn this.each(function( i ) {\n +\t\t\t\tjQuery.offset.setOffset( this, options, i );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( !elem || !elem.ownerDocument ) {\n +\t\t\treturn null;\n +\t\t}\n +\n +\t\tif ( elem === elem.ownerDocument.body ) {\n +\t\t\treturn jQuery.offset.bodyOffset( elem );\n +\t\t}\n +\n +\t\tvar box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,\n +\t\t\tclientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,\n +\t\t\ttop = box.top + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ) - clientTop,\n +\t\t\tleft = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;\n +\n +\t\treturn { top: top, left: left };\n +\t};\n +\n +} else {\n +\tjQuery.fn.offset = function( options ) {\n +\t\tvar elem = this[0];\n +\n +\t\tif ( options ) { \n +\t\t\treturn this.each(function( i ) {\n +\t\t\t\tjQuery.offset.setOffset( this, options, i );\n +\t\t\t});\n +\t\t}\n +\n +\t\tif ( !elem || !elem.ownerDocument ) {\n +\t\t\treturn null;\n +\t\t}\n +\n +\t\tif ( elem === elem.ownerDocument.body ) {\n +\t\t\treturn jQuery.offset.bodyOffset( elem );\n +\t\t}\n +\n +\t\tjQuery.offset.initialize();\n +\n +\t\tvar offsetParent = elem.offsetParent, prevOffsetParent = elem,\n +\t\t\tdoc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,\n +\t\t\tbody = doc.body, defaultView = doc.defaultView,\n +\t\t\tprevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,\n +\t\t\ttop = elem.offsetTop, left = elem.offsetLeft;\n +\n +\t\twhile ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {\n +\t\t\tif ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {\n +\t\t\t\tbreak;\n +\t\t\t}\n +\n +\t\t\tcomputedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;\n +\t\t\ttop -= elem.scrollTop;\n +\t\t\tleft -= elem.scrollLeft;\n +\n +\t\t\tif ( elem === offsetParent ) {\n +\t\t\t\ttop += elem.offsetTop;\n +\t\t\t\tleft += elem.offsetLeft;\n +\n +\t\t\t\tif ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {\n +\t\t\t\t\ttop += parseFloat( computedStyle.borderTopWidth ) || 0;\n +\t\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n +\t\t\t\t}\n +\n +\t\t\t\tprevOffsetParent = offsetParent, offsetParent = elem.offsetParent;\n +\t\t\t}\n +\n +\t\t\tif ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {\n +\t\t\t\ttop += parseFloat( computedStyle.borderTopWidth ) || 0;\n +\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n +\t\t\t}\n +\n +\t\t\tprevComputedStyle = computedStyle;\n +\t\t}\n +\n +\t\tif ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {\n +\t\t\ttop += body.offsetTop;\n +\t\t\tleft += body.offsetLeft;\n +\t\t}\n +\n +\t\tif ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {\n +\t\t\ttop += Math.max( docElem.scrollTop, body.scrollTop );\n +\t\t\tleft += Math.max( docElem.scrollLeft, body.scrollLeft );\n +\t\t}\n +\n +\t\treturn { top: top, left: left };\n +\t};\n +}\n +\n +jQuery.offset = {\n +\tinitialize: function() {\n +\t\tvar body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0,\n +\t\t\thtml = "<div style=\'position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;\'><div></div></div><table style=\'position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;\' cellpadding=\'0\' cellspacing=\'0\'><tr><td></td></tr></table>";\n +\n +\t\tjQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );\n +\n +\t\tcontainer.innerHTML = html;\n +\t\tbody.insertBefore( container, body.firstChild );\n +\t\tinnerDiv = container.firstChild;\n +\t\tcheckDiv = innerDiv.firstChild;\n +\t\ttd = innerDiv.nextSibling.firstChild.firstChild;\n +\n +\t\tthis.doesNotAddBorder = (checkDiv.offsetTop !== 5);\n +\t\tthis.doesAddBorderForTableAndCells = (td.offsetTop === 5);\n +\n +\t\tcheckDiv.style.position = "fixed", checkDiv.style.top = "20px";\n +\t\t// safari subtracts parent border width here which is 5px\n +\t\tthis.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);\n +\t\tcheckDiv.style.position = checkDiv.style.top = "";\n +\n +\t\tinnerDiv.style.overflow = "hidden", innerDiv.style.position = "relative";\n +\t\tthis.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);\n +\n +\t\tthis.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);\n +\n +\t\tbody.removeChild( container );\n +\t\tbody = container = innerDiv = checkDiv = table = td = null;\n +\t\tjQuery.offset.initialize = jQuery.noop;\n +\t},\n +\n +\tbodyOffset: function( body ) {\n +\t\tvar top = body.offsetTop, left = body.offsetLeft;\n +\n +\t\tjQuery.offset.initialize();\n +\n +\t\tif ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {\n +\t\t\ttop += parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0;\n +\t\t\tleft += parseFloat( jQuery.curCSS(body, "marginLeft", true) ) || 0;\n +\t\t}\n +\n +\t\treturn { top: top, left: left };\n +\t},\n +\t\n +\tsetOffset: function( elem, options, i ) {\n +\t\t// set position first, in-case top/left are set even on static elem\n +\t\tif ( /static/.test( jQuery.curCSS( elem, "position" ) ) ) {\n +\t\t\telem.style.position = "relative";\n +\t\t}\n +\t\tvar curElem = jQuery( elem ),\n +\t\t\tcurOffset = curElem.offset(),\n +\t\t\tcurTop = parseInt( jQuery.curCSS( elem, "top", true ), 10 ) || 0,\n +\t\t\tcurLeft = parseInt( jQuery.curCSS( elem, "left", true ), 10 ) || 0;\n +\n +\t\tif ( jQuery.isFunction( options ) ) {\n +\t\t\toptions = options.call( elem, i, curOffset );\n +\t\t}\n +\n +\t\tvar props = {\n +\t\t\ttop: (options.top - curOffset.top) + curTop,\n +\t\t\tleft: (options.left - curOffset.left) + curLeft\n +\t\t};\n +\t\t\n +\t\tif ( "using" in options ) {\n +\t\t\toptions.using.call( elem, props );\n +\t\t} else {\n +\t\t\tcurElem.css( props );\n +\t\t}\n +\t}\n +};\n +\n +\n +jQuery.fn.extend({\n +\tposition: function() {\n +\t\tif ( !this[0] ) {\n +\t\t\treturn null;\n +\t\t}\n +\n +\t\tvar elem = this[0],\n +\n +\t\t// Get *real* offsetParent\n +\t\toffsetParent = this.offsetParent(),\n +\n +\t\t// Get correct offsets\n +\t\toffset = this.offset(),\n +\t\tparentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();\n +\n +\t\t// Subtract element margins\n +\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n +\t\t// are the same in Safari causing offset.left to incorrectly be 0\n +\t\toffset.top -= parseFloat( jQuery.curCSS(elem, "marginTop", true) ) || 0;\n +\t\toffset.left -= parseFloat( jQuery.curCSS(elem, "marginLeft", true) ) || 0;\n +\n +\t\t// Add offsetParent borders\n +\t\tparentOffset.top += parseFloat( jQuery.curCSS(offsetParent[0], "borderTopWidth", true) ) || 0;\n +\t\tparentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], "borderLeftWidth", true) ) || 0;\n +\n +\t\t// Subtract the two offsets\n +\t\treturn {\n +\t\t\ttop: offset.top - parentOffset.top,\n +\t\t\tleft: offset.left - parentOffset.left\n +\t\t};\n +\t},\n +\n +\toffsetParent: function() {\n +\t\treturn this.map(function() {\n +\t\t\tvar offsetParent = this.offsetParent || document.body;\n +\t\t\twhile ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {\n +\t\t\t\toffsetParent = offsetParent.offsetParent;\n +\t\t\t}\n +\t\t\treturn offsetParent;\n +\t\t});\n +\t}\n +});\n +\n +\n +// Create scrollLeft and scrollTop methods\n +jQuery.each( ["Left", "Top"], function( i, name ) {\n +\tvar method = "scroll" + name;\n +\n +\tjQuery.fn[ method ] = function(val) {\n +\t\tvar elem = this[0], win;\n +\t\t\n +\t\tif ( !elem ) {\n +\t\t\treturn null;\n +\t\t}\n +\n +\t\tif ( val !== undefined ) {\n +\t\t\t// Set the scroll offset\n +\t\t\treturn this.each(function() {\n +\t\t\t\twin = getWindow( this );\n +\n +\t\t\t\tif ( win ) {\n +\t\t\t\t\twin.scrollTo(\n +\t\t\t\t\t\t!i ? val : jQuery(win).scrollLeft(),\n +\t\t\t\t\t\t i ? val : jQuery(win).scrollTop()\n +\t\t\t\t\t);\n +\n +\t\t\t\t} else {\n +\t\t\t\t\tthis[ method ] = val;\n +\t\t\t\t}\n +\t\t\t});\n +\t\t} else {\n +\t\t\twin = getWindow( elem );\n +\n +\t\t\t// Return the scroll offset\n +\t\t\treturn win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :\n +\t\t\t\tjQuery.support.boxModel && win.document.documentElement[ method ] ||\n +\t\t\t\t\twin.document.body[ method ] :\n +\t\t\t\telem[ method ];\n +\t\t}\n +\t};\n +});\n +\n +function getWindow( elem ) {\n +\treturn ("scrollTo" in elem && elem.document) ?\n +\t\telem :\n +\t\telem.nodeType === 9 ?\n +\t\t\telem.defaultView || elem.parentWindow :\n +\t\t\tfalse;\n +}\n +// Create innerHeight, innerWidth, outerHeight and outerWidth methods\n +jQuery.each([ "Height", "Width" ], function( i, name ) {\n +\n +\tvar type = name.toLowerCase();\n +\n +\t// innerHeight and innerWidth\n +\tjQuery.fn["inner" + name] = function() {\n +\t\treturn this[0] ?\n +\t\t\tjQuery.css( this[0], type, false, "padding" ) :\n +\t\t\tnull;\n +\t};\n +\n +\t// outerHeight and outerWidth\n +\tjQuery.fn["outer" + name] = function( margin ) {\n +\t\treturn this[0] ?\n +\t\t\tjQuery.css( this[0], type, false, margin ? "margin" : "border" ) :\n +\t\t\tnull;\n +\t};\n +\n +\tjQuery.fn[ type ] = function( size ) {\n +\t\t// Get window width or height\n +\t\tvar elem = this[0];\n +\t\tif ( !elem ) {\n +\t\t\treturn size == null ? null : this;\n +\t\t}\n +\t\t\n +\t\tif ( jQuery.isFunction( size ) ) {\n +\t\t\treturn this.each(function( i ) {\n +\t\t\t\tvar self = jQuery( this );\n +\t\t\t\tself[ type ]( size.call( this, i, self[ type ]() ) );\n +\t\t\t});\n +\t\t}\n +\n +\t\treturn ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?\n +\t\t\t// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode\n +\t\t\telem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||\n +\t\t\telem.document.body[ "client" + name ] :\n +\n +\t\t\t// Get document width or height\n +\t\t\t(elem.nodeType === 9) ? // is it a document\n +\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height], whichever is greater\n +\t\t\t\tMath.max(\n +\t\t\t\t\telem.documentElement["client" + name],\n +\t\t\t\t\telem.body["scroll" + name], elem.documentElement["scroll" + name],\n +\t\t\t\t\telem.body["offset" + name], elem.documentElement["offset" + name]\n +\t\t\t\t) :\n +\n +\t\t\t\t// Get or set width or height on the element\n +\t\t\t\tsize === undefined ?\n +\t\t\t\t\t// Get width or height on the element\n +\t\t\t\t\tjQuery.css( elem, type ) :\n +\n +\t\t\t\t\t// Set the width or height on the element (default to pixels if value is unitless)\n +\t\t\t\t\tthis.css( type, typeof size === "string" ? size : size + "px" );\n +\t};\n +\n +});\n +\n +exports.$ = exports.jQuery = jQuery;\n +\n +});\n +;bespin.tiki.register("::embedded", {\n + name: "embedded",\n + dependencies: { "theme_manager": "0.0.0", "text_editor": "0.0.0", "appconfig": "0.0.0", "edit_session": "0.0.0", "screen_theme": "0.0.0" }\n +});\n +bespin.tiki.module("embedded:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "dependencies": {\n + "appconfig": "0.0.0",\n + "edit_session": "0.0.0",\n + "theme_manager": "0.0.0",\n + "screen_theme": "0.0.0",\n + "text_editor": "0.0.0"\n + }\n +});\n +"end";\n +\n +// This plugin is artificial as a convenience. It\'s just here to collect up\n +// the common dependencies for embedded use\n +\n +});\n +;bespin.tiki.register("::appconfig", {\n + name: "appconfig",\n + dependencies: { "jquery": "0.0.0", "canon": "0.0.0", "settings": "0.0.0" }\n +});\n +bespin.tiki.module("appconfig:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +var $ = require(\'jquery\').$;\n +var settings = require(\'settings\').settings;\n +var group = require("bespin:promise").group;\n +var Promise = require("bespin:promise").Promise;\n +var console = require("bespin:console").console;\n +var Trace = require("bespin:util/stacktrace").Trace;\n +var util = require(\'bespin:util/util\');\n +\n +var firstBespin = true;\n +\n +/*\n + * launch Bespin with the configuration provided. The configuration is\n + * an object with the following properties:\n + * - theme: an object with the basePlugin as string and the standardTheme as\n + * string. Both are optional. If no basePlugin is given, screen_theme\n + * is used if this exists.\n + * - objects: an object with a collection of named objects that will be\n + * registered with the plugin catalog (see PluginCatalog.registerObject)\n + * This will automatically be augmented with sane defaults (for\n + * example, most Bespin users want a text editor!)\n + * - gui: instructions on how to build a GUI. Specifically, the current border\n + * layout positions will be filled in. Again this provides sane defaults.\n + * - container: node to attach to (optional). If not provided a node will be\n + * created. and added to the body.\n + * - settings: settings to preconfigure\n + */\n +exports.launch = function(config) {\n + var launchPromise = new Promise();\n +\n + // Remove the "Loading..." hint.\n + $(\'#_bespin_loading\').remove();\n +\n + // This will hold the require function to get the catalog.\n + var require;\n +\n + // Is this the fist Bespin?\n + if (firstBespin) {\n + // Use the global require.\n + require = bespin.tiki.require;\n + firstBespin = false;\n + } else {\n + // Otherwise create a new tiki-bespin sandbox and a new require function.\n + var sandbox = new (bespin.tiki.require(\'bespin:sandbox\').Sandbox);\n + require = sandbox.createRequire({\n + id: \'index\',\n + ownerPackage: bespin.tiki.loader.anonymousPackage\n + });\n + }\n +\n + // Here we go: Require the catalog that is used for this Bespin instance.\n + var catalog = require(\'bespin:plugins\').catalog;\n +\n + // Launch Bespin!\n + config = config || {};\n + exports.normalizeConfig(catalog, config);\n + var objects = config.objects;\n + for (var key in objects) {\n + catalog.registerObject(key, objects[key]);\n + }\n +\n + for (var setting in config.settings) {\n + settings.set(setting, config.settings[setting]);\n + }\n +\n + // Resolve the launchPromise and pass the env variable along.\n + var resolveLaunchPromise = function() {\n + var env = require("environment").env;\n +\n + var editor = env.editor;\n + if (editor) {\n + if (config.lineNumber) {\n + editor.setLineNumber(config.lineNumber);\n + }\n + if (config.stealFocus) {\n + editor.focus = true;\n + }\n + if (config.readOnly) {\n + editor.readOnly = config.readOnly;\n + }\n + if (config.syntax) {\n + editor.syntax = config.syntax;\n + }\n + }\n + var commandLine = catalog.getObject(\'commandLine\');\n + if (commandLine) {\n + env.commandLine = commandLine;\n + }\n +\n + catalog.publish(this, \'appLaunched\');\n +\n + launchPromise.resolve(env);\n + }.bind(this);\n +\n + var themeLoadingPromise = new Promise();\n +\n + themeLoadingPromise.then(function() {\n + if (objects.loginController) {\n + catalog.createObject("loginController").then(\n + function(loginController) {\n + var pr = loginController.showLogin();\n + pr.then(function(username) {\n + // Add the username as constructor argument.\n + config.objects.session.arguments.push(username);\n +\n + exports.launchEditor(catalog, config).then(resolveLaunchPromise,\n + launchPromise.reject.bind(launchPromise));\n + });\n + });\n + } else {\n + exports.launchEditor(catalog, config).then(resolveLaunchPromise,\n + launchPromise.reject.bind(launchPromise));\n + }\n + }, function(error) {\n + launchPromise.reject(error);\n + });\n +\n + // If the themeManager plugin is there, then check for theme configuration.\n + if (catalog.plugins.theme_manager) {\n + bespin.tiki.require.ensurePackage(\'::theme_manager\', function() {\n + var themeManager = require(\'theme_manager\');\n + if (config.theme.basePlugin) {\n + themeManager.setBasePlugin(config.theme.basePlugin);\n + }\n + if (config.theme.standard) {\n + themeManager.setStandardTheme(config.theme.standard);\n + }\n + themeManager.startParsing().then(function() {\n + themeLoadingPromise.resolve();\n + }, function(error) {\n + themeLoadingPromise.reject(error);\n + });\n + });\n + } else {\n + themeLoadingPromise.resolve();\n + }\n +\n + return launchPromise;\n +};\n +\n +exports.normalizeConfig = function(catalog, config) {\n + if (config.objects === undefined) {\n + config.objects = {};\n + }\n + if (config.autoload === undefined) {\n + config.autoload = [];\n + }\n + if (config.theme === undefined) {\n + config.theme = {};\n + }\n + if (!config.theme.basePlugin && catalog.plugins.screen_theme) {\n + config.theme.basePlugin = \'screen_theme\';\n + }\n + if (!config.initialContent) {\n + config.initialContent = \'\';\n + }\n + if (!config.settings) {\n + config.settings = {};\n + }\n +\n + if (!config.objects.notifier && catalog.plugins.notifier) {\n + config.objects.notifier = {\n + };\n + }\n +\n + if (!config.objects.loginController && catalog.plugins.userident) {\n + config.objects.loginController = {\n + };\n + }\n + if (!config.objects.fileHistory && catalog.plugins.file_history) {\n + config.objects.fileHistory = {\n + factory: \'file_history\',\n + arguments: [\n + "session"\n + ],\n + objects: {\n + "0": "session"\n + }\n + };\n + }\n + if (!config.objects.server && catalog.plugins.bespin_server) {\n + config.objects.server = {\n + factory: "bespin_server"\n + };\n + config.objects.filesource = {\n + factory: "bespin_filesource",\n + arguments: [\n + "server"\n + ],\n + objects: {\n + "0": "server"\n + }\n + };\n + }\n + if (!config.objects.files && catalog.plugins.filesystem &&\n + config.objects.filesource) {\n + config.objects.files = {\n + arguments: [\n + "filesource"\n + ],\n + "objects": {\n + "0": "filesource"\n + }\n + };\n + }\n + if (!config.objects.editor) {\n + config.objects.editor = {\n + factory: "text_editor",\n + arguments: [\n + config.initialContent\n + ]\n + };\n + }\n + if (!config.objects.session) {\n + config.objects.session = {\n + arguments: [\n + "editor"\n + ],\n + "objects": {\n + "0": "editor"\n + }\n + };\n + }\n + if (!config.objects.commandLine && catalog.plugins.command_line) {\n + config.objects.commandLine = {\n + };\n + }\n +\n + if (config.gui === undefined) {\n + config.gui = {};\n + }\n +\n + var alreadyRegistered = {};\n + for (var key in config.gui) {\n + var desc = config.gui[key];\n + if (desc.component) {\n + alreadyRegistered[desc.component] = true;\n + }\n + }\n +\n + if (!config.gui.center && config.objects.editor\n + && !alreadyRegistered.editor) {\n + config.gui.center = { component: "editor" };\n + }\n + if (!config.gui.south && config.objects.commandLine\n + && !alreadyRegistered.commandLine) {\n + config.gui.south = { component: "commandLine" };\n + }\n +};\n +\n +exports.launchEditor = function(catalog, config) {\n + var retPr = new Promise();\n +\n + if (config === null) {\n + var message = \'Cannot start editor without a configuration!\';\n + console.error(message);\n + retPr.reject(message);\n + return retPr;\n + }\n +\n + var pr = createAllObjects(catalog, config);\n + pr.then(function() {\n + generateGUI(catalog, config, retPr);\n + }, function(error) {\n + console.error(\'Error while creating objects\');\n + new Trace(error).log();\n + retPr.reject(error);\n + });\n +\n + return retPr;\n +};\n +\n +var createAllObjects = function(catalog, config) {\n + var promises = [];\n + for (var objectName in config.objects) {\n + promises.push(catalog.createObject(objectName));\n + }\n + return group(promises);\n +};\n +\n +var generateGUI = function(catalog, config, pr) {\n + var error;\n +\n + var container = document.createElement(\'div\');\n + container.setAttribute(\'class\', \'container\');\n +\n + var centerContainer = document.createElement(\'div\');\n + centerContainer.setAttribute(\'class\', \'center-container\');\n + container.appendChild(centerContainer);\n +\n + var element = config.element || document.body;\n + // Add the \'bespin\' class to the element in case it doesn\'t have this already.\n + util.addClass(element, \'bespin\');\n + element.appendChild(container);\n +\n + for (var place in config.gui) {\n + var descriptor = config.gui[place];\n +\n + var component = catalog.getObject(descriptor.component);\n + if (!component) {\n + error = \'Cannot find object \' + descriptor.component +\n + \' to attach to the Bespin UI\';\n + console.error(error);\n + pr.reject(error);\n + return;\n + }\n +\n + element = component.element;\n + if (!element) {\n + error = \'Component \' + descriptor.component + \' does not have\' +\n + \' an "element" attribute to attach to the Bespin UI\';\n + console.error(error);\n + pr.reject(error);\n + return;\n + }\n +\n + $(element).addClass(place);\n +\n + if (place == \'west\' || place == \'east\' || place == \'center\') {\n + centerContainer.appendChild(element);\n + } else {\n + container.appendChild(element);\n + }\n +\n + // Call the elementAppended event if there is one.\n + if (component.elementAppended) {\n + component.elementAppended();\n + }\n + }\n +\n + pr.resolve();\n +};\n +\n +});\n +;bespin.tiki.register("::screen_theme", {\n + name: "screen_theme",\n + dependencies: { "theme_manager": "0.0.0" }\n +});\n +bespin.tiki.module("screen_theme:index",function(require,exports,module) {\n +\n +});\n +\n +(function() {\n +var $ = bespin.tiki.require("jquery").$;\n +$(document).ready(function() {\n + bespin.tiki.require("bespin:plugins").catalog.registerMetadata({"text_editor": {"resourceURL": "resources/text_editor/", "description": "Canvas-based text editor component and many common editing commands", "dependencies": {"completion": "0.0.0", "undomanager": "0.0.0", "settings": "0.0.0", "canon": "0.0.0", "rangeutils": "0.0.0", "traits": "0.0.0", "theme_manager": "0.0.0", "keyboard": "0.0.0", "edit_session": "0.0.0", "syntax_manager": "0.0.0"}, "testmodules": ["tests/testScratchcanvas", "tests/models/testTextstorage", "tests/utils/testRect", "tests/controllers/testLayoutmanager"], "provides": [{"action": "new", "pointer": "views/editor#EditorView", "ep": "factory", "name": "text_editor"}, {"pointer": "views/editor#EditorView", "ep": "appcomponent", "name": "editor_view"}, {"predicates": {"isTextView": true}, "pointer": "commands/editing#backspace", "ep": "command", "key": "backspace", "name": "backspace"}, {"predicates": {"isTextView": true}, "pointer": "commands/editing#deleteCommand", "ep": "command", "key": "delete", "name": "delete"}, {"description": "Delete all lines currently selected", "key": "ctrl_d", "predicates": {"isTextView": true}, "pointer": "commands/editing#deleteLines", "ep": "command", "name": "deletelines"}, {"description": "Create a new, empty line below the current one", "key": "ctrl_return", "predicates": {"isTextView": true}, "pointer": "commands/editing#openLine", "ep": "command", "name": "openline"}, {"description": "Join the current line with the following", "key": "ctrl_shift_j", "predicates": {"isTextView": true}, "pointer": "commands/editing#joinLines", "ep": "command", "name": "joinline"}, {"params": [{"defaultValue": "", "type": "text", "name": "text", "description": "The text to insert"}], "pointer": "commands/editing#insertText", "ep": "command", "name": "insertText"}, {"predicates": {"completing": false, "isTextView": true}, "pointer": "commands/editing#newline", "ep": "command", "key": "return", "name": "newline"}, {"predicates": {"completing": false, "isTextView": true}, "pointer": "commands/editing#tab", "ep": "command", "key": "tab", "name": "tab"}, {"predicates": {"isTextView": true}, "pointer": "commands/editing#untab", "ep": "command", "key": "shift_tab", "name": "untab"}, {"predicates": {"isTextView": true}, "ep": "command", "name": "move"}, {"description": "Repeat the last search (forward)", "pointer": "commands/editor#findNextCommand", "ep": "command", "key": "ctrl_g", "name": "findnext"}, {"description": "Repeat the last search (backward)", "pointer": "commands/editor#findPrevCommand", "ep": "command", "key": "ctrl_shift_g", "name": "findprev"}, {"predicates": {"completing": false, "isTextView": true}, "pointer": "commands/movement#moveDown", "ep": "command", "key": "down", "name": "move down"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveLeft", "ep": "command", "key": "left", "name": "move left"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveRight", "ep": "command", "key": "right", "name": "move right"}, {"predicates": {"completing": false, "isTextView": true}, "pointer": "commands/movement#moveUp", "ep": "command", "key": "up", "name": "move up"}, {"predicates": {"isTextView": true}, "ep": "command", "name": "select"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectDown", "ep": "command", "key": "shift_down", "name": "select down"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectLeft", "ep": "command", "key": "shift_left", "name": "select left"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectRight", "ep": "command", "key": "shift_right", "name": "select right"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectUp", "ep": "command", "key": "shift_up", "name": "select up"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveLineEnd", "ep": "command", "key": ["end", "ctrl_right"], "name": "move lineend"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectLineEnd", "ep": "command", "key": ["shift_end", "ctrl_shift_right"], "name": "select lineend"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveDocEnd", "ep": "command", "key": "ctrl_down", "name": "move docend"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectDocEnd", "ep": "command", "key": "ctrl_shift_down", "name": "select docend"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveLineStart", "ep": "command", "key": ["home", "ctrl_left"], "name": "move linestart"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectLineStart", "ep": "command", "key": ["shift_home", "ctrl_shift_left"], "name": "select linestart"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveDocStart", "ep": "command", "key": "ctrl_up", "name": "move docstart"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectDocStart", "ep": "command", "key": "ctrl_shift_up", "name": "select docstart"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#moveNextWord", "ep": "command", "key": ["alt_right"], "name": "move nextword"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectNextWord", "ep": "command", "key": ["alt_shift_right"], "name": "select nextword"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#movePreviousWord", "ep": "command", "key": ["alt_left"], "name": "move prevword"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectPreviousWord", "ep": "command", "key": ["alt_shift_left"], "name": "select prevword"}, {"predicates": {"isTextView": true}, "pointer": "commands/movement#selectAll", "ep": "command", "key": ["ctrl_a", "meta_a"], "name": "select all"}, {"predicates": {"isTextView": true}, "ep": "command", "name": "scroll"}, {"predicates": {"isTextView": true}, "pointer": "commands/scrolling#scrollDocStart", "ep": "command", "key": "ctrl_home", "name": "scroll start"}, {"predicates": {"isTextView": true}, "pointer": "commands/scrolling#scrollDocEnd", "ep": "command", "key": "ctrl_end", "name": "scroll end"}, {"predicates": {"isTextView": true}, "pointer": "commands/scrolling#scrollPageDown", "ep": "command", "key": "pagedown", "name": "scroll down"}, {"predicates": {"isTextView": true}, "pointer": "commands/scrolling#scrollPageUp", "ep": "command", "key": "pageup", "name": "scroll up"}, {"pointer": "commands/editor#lcCommand", "description": "Change all selected text to lowercase", "withKey": "CMD SHIFT L", "ep": "command", "name": "lc"}, {"pointer": "commands/editor#detabCommand", "description": "Convert tabs to spaces.", "params": [{"defaultValue": null, "type": "text", "name": "tabsize", "description": "Optionally, specify a tab size. (Defaults to setting.)"}], "ep": "command", "name": "detab"}, {"pointer": "commands/editor#entabCommand", "description": "Convert spaces to tabs.", "params": [{"defaultValue": null, "type": "text", "name": "tabsize", "description": "Optionally, specify a tab size. (Defaults to setting.)"}], "ep": "command", "name": "entab"}, {"pointer": "commands/editor#trimCommand", "description": "trim trailing or leading whitespace from each line in selection", "params": [{"defaultValue": "both", "type": {"data": [{"name": "left"}, {"name": "right"}, {"name": "both"}], "name": "selection"}, "name": "side", "description": "Do we trim from the left, right or both"}], "ep": "command", "name": "trim"}, {"pointer": "commands/editor#ucCommand", "description": "Change all selected text to uppercase", "withKey": "CMD SHIFT U", "ep": "command", "name": "uc"}, {"predicates": {"isTextView": true}, "pointer": "controllers/undo#undoManagerCommand", "ep": "command", "key": ["ctrl_shift_z"], "name": "redo"}, {"predicates": {"isTextView": true}, "pointer": "controllers/undo#undoManagerCommand", "ep": "command", "key": ["ctrl_z"], "name": "undo"}, {"description": "The distance in characters between each tab", "defaultValue": 8, "type": "number", "ep": "setting", "name": "tabstop"}, {"description": "Customize the keymapping", "defaultValue": "{}", "type": "text", "ep": "setting", "name": "customKeymapping"}, {"description": "The keymapping to use", "defaultValue": "standard", "type": "text", "ep": "setting", "name": "keymapping"}, {"description": "The editor font size in pixels", "defaultValue": 14, "type": "number", "ep": "setting", "name": "fontsize"}, {"description": "The editor font face", "defaultValue": "Monaco, Lucida Console, monospace", "type": "text", "ep": "setting", "name": "fontface"}, {"defaultValue": {"color": "#e5c138", "paddingLeft": 5, "backgroundColor": "#4c4a41", "paddingRight": 10}, "ep": "themevariable", "name": "gutter"}, {"defaultValue": {"color": "#e6e6e6", "selectedTextBackgroundColor": "#526da5", "backgroundColor": "#2a211c", "cursorColor": "#879aff", "unfocusedCursorBackgroundColor": "#73171e", "unfocusedCursorColor": "#ff0033"}, "ep": "themevariable", "name": "editor"}, {"defaultValue": {"comment": "#666666", "directive": "#999999", "keyword": "#42A8ED", "plain": "#e6e6e6", "error": "#ff0000", "operator": "#88BBFF", "identifier": "#D841FF", "string": "#039A0A"}, "ep": "themevariable", "name": "highlighter"}, {"defaultValue": {"nibStrokeStyle": "rgb(150, 150, 150)", "fullAlpha": 1.0, "barFillStyle": "rgb(0, 0, 0)", "particalAlpha": 0.29999999999999999, "barFillGradientBottomStop": "rgb(44, 44, 44)", "backgroundStyle": "#2A211C", "thickness": 17, "padding": 5, "trackStrokeStyle": "rgb(150, 150, 150)", "nibArrowStyle": "rgb(255, 255, 255)", "barFillGradientBottomStart": "rgb(22, 22, 22)", "barFillGradientTopStop": "rgb(40, 40, 40)", "barFillGradientTopStart": "rgb(90, 90, 90)", "nibStyle": "rgb(100, 100, 100)", "trackFillStyle": "rgba(50, 50, 50, 0.8)"}, "ep": "themevariable", "name": "scroller"}, {"description": "Event: Notify when something within the editor changed.", "params": [{"required": true, "name": "pointer", "description": "Function that is called whenever a change happened."}], "ep": "extensionpoint", "name": "editorChange"}], "type": "plugins/supported", "name": "text_editor"}, "completion": {"resourceURL": "resources/completion/", "description": "Code completion support", "dependencies": {"jquery": "0.0.0", "ctags": "0.0.0", "rangeutils": "0.0.0", "canon": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "provides": [{"indexOn": "name", "description": "Code completion support for specific languages", "ep": "extensionpoint", "name": "completion"}, {"description": "Accept the chosen completion", "key": ["return", "tab"], "predicates": {"completing": true}, "pointer": "controller#completeCommand", "ep": "command", "name": "complete"}, {"description": "Abandon the completion", "key": "escape", "predicates": {"completing": true}, "pointer": "controller#completeCancelCommand", "ep": "command", "name": "complete cancel"}, {"description": "Choose the completion below", "key": "down", "predicates": {"completing": true}, "pointer": "controller#completeDownCommand", "ep": "command", "name": "complete down"}, {"description": "Choose the completion above", "key": "up", "predicates": {"completing": true}, "pointer": "controller#completeUpCommand", "ep": "command", "name": "complete up"}], "type": "plugins/supported", "name": "completion"}, "syntax_worker": {"resourceURL": "resources/syntax_worker/", "description": "Coordinates multiple syntax engines", "environments": {"worker": true}, "dependencies": {"syntax_directory": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "type": "plugins/supported", "name": "syntax_worker"}, "undomanager": {"resourceURL": "resources/undomanager/", "description": "Manages undoable events", "testmodules": ["tests/testUndomanager"], "provides": [{"pointer": "#undoManagerCommand", "ep": "command", "key": ["ctrl_shift_z"], "name": "redo"}, {"pointer": "#undoManagerCommand", "ep": "command", "key": ["ctrl_z"], "name": "undo"}], "type": "plugins/supported", "name": "undomanager"}, "embedded": {"testmodules": [], "dependencies": {"theme_manager": "0.0.0", "text_editor": "0.0.0", "appconfig": "0.0.0", "edit_session": "0.0.0", "screen_theme": "0.0.0"}, "resourceURL": "resources/embedded/", "name": "embedded", "type": "plugins/supported"}, "less": {"resourceURL": "resources/less/", "description": "Leaner CSS", "contributors": [], "author": "Alexis Sellier <self@cloudhead.net>", "url": "http://lesscss.org", "version": "1.0.11", "dependencies": {}, "testmodules": [], "provides": [], "keywords": ["css", "parser", "lesscss", "browser"], "type": "plugins/thirdparty", "name": "less"}, "python": {"resourceURL": "resources/python/", "name": "python", "environments": {"worker": true}, "dependencies": {"syntax_manager": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#PySyntax", "ep": "syntax", "fileexts": ["py"], "name": "py"}], "type": "plugins/thirdparty", "description": "Python syntax highlighter"}, "jquery": {"testmodules": [], "resourceURL": "resources/jquery/", "name": "jquery", "type": "plugins/thirdparty"}, "theme_manager_base": {"resourceURL": "resources/theme_manager_base/", "name": "theme_manager_base", "share": true, "environments": {"main": true}, "dependencies": {}, "testmodules": [], "provides": [{"description": "(Less)files holding the CSS style information for the UI.", "params": [{"required": true, "name": "url", "description": "Name of the ThemeStylesFile - can also be an array of files."}], "ep": "extensionpoint", "name": "themestyles"}, {"description": "Event: Notify when the theme(styles) changed.", "params": [{"required": true, "name": "pointer", "description": "Function that is called whenever the theme is changed."}], "ep": "extensionpoint", "name": "themeChange"}, {"indexOn": "name", "description": "A theme is a way change the look of the application.", "params": [{"required": false, "name": "url", "description": "Name of a ThemeStylesFile that holds theme specific CSS rules - can also be an array of files."}, {"required": true, "name": "pointer", "description": "Function that returns the ThemeData"}], "ep": "extensionpoint", "name": "theme"}], "type": "plugins/supported", "description": "Defines extension points required for theming"}, "stylesheet": {"resourceURL": "resources/stylesheet/", "name": "stylesheet", "environments": {"worker": true}, "dependencies": {"standard_syntax": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#CSSSyntax", "ep": "syntax", "fileexts": ["css", "less"], "name": "css"}], "type": "plugins/supported", "description": "CSS syntax highlighter"}, "rangeutils": {"testmodules": ["tests/test"], "type": "plugins/supported", "resourceURL": "resources/rangeutils/", "description": "Utility functions for dealing with ranges of text", "name": "rangeutils"}, "theme_manager": {"resourceURL": "resources/theme_manager/", "name": "theme_manager", "share": true, "environments": {"main": true, "worker": false}, "dependencies": {"theme_manager_base": "0.0.0", "settings": "0.0.0", "events": "0.0.0", "less": "0.0.0"}, "testmodules": [], "provides": [{"unregister": "themestyles#unregisterThemeStyles", "register": "themestyles#registerThemeStyles", "ep": "extensionhandler", "name": "themestyles"}, {"unregister": "index#unregisterTheme", "register": "index#registerTheme", "ep": "extensionhandler", "name": "theme"}, {"defaultValue": "standard", "description": "The theme plugin\'s name to use. If set to \'standard\' no theme will be used", "type": "text", "ep": "setting", "name": "theme"}, {"pointer": "#appLaunched", "ep": "appLaunched"}], "type": "plugins/supported", "description": "Handles colors in Bespin"}, "html": {"resourceURL": "resources/html/", "name": "html", "environments": {"worker": true}, "dependencies": {"standard_syntax": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#HTMLSyntax", "ep": "syntax", "fileexts": ["htm", "html"], "name": "html"}], "type": "plugins/supported", "description": "HTML syntax highlighter"}, "appconfig": {"resourceURL": "resources/appconfig/", "description": "Instantiates components and displays the GUI based on configuration.", "dependencies": {"jquery": "0.0.0", "canon": "0.0.0", "settings": "0.0.0"}, "testmodules": [], "provides": [{"description": "Event: Fired when the app is completely launched.", "ep": "extensionpoint", "name": "appLaunched"}], "type": "plugins/supported", "name": "appconfig"}, "keyboard": {"resourceURL": "resources/keyboard/", "description": "Keyboard shortcuts", "dependencies": {"canon": "0.0", "settings": "0.0"}, "testmodules": ["tests/testKeyboard"], "provides": [{"description": "A keymapping defines how keystrokes are interpreted.", "params": [{"required": true, "name": "states", "description": "Holds the states and all the informations about the keymapping. See docs: pluginguide/keymapping"}], "ep": "extensionpoint", "name": "keymapping"}], "type": "plugins/supported", "name": "keyboard"}, "js_syntax": {"resourceURL": "resources/js_syntax/", "name": "js_syntax", "environments": {"worker": true}, "dependencies": {"standard_syntax": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#JSSyntax", "ep": "syntax", "fileexts": ["js", "json"], "name": "js"}], "type": "plugins/supported", "description": "JavaScript syntax highlighter"}, "ctags": {"resourceURL": "resources/ctags/", "description": "Reads and writes tag files", "dependencies": {"traits": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "type": "plugins/supported", "name": "ctags"}, "standard_syntax": {"resourceURL": "resources/standard_syntax/", "description": "Easy-to-use basis for syntax engines", "environments": {"worker": true}, "dependencies": {"syntax_worker": "0.0.0", "syntax_directory": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "type": "plugins/supported", "name": "standard_syntax"}, "edit_session": {"resourceURL": "resources/edit_session/", "description": "Ties together the files being edited with the views on screen", "dependencies": {"events": "0.0.0"}, "testmodules": ["tests/testSession"], "provides": [{"action": "call", "pointer": "#createSession", "ep": "factory", "name": "session"}], "type": "plugins/supported", "name": "edit_session"}, "screen_theme": {"resourceURL": "resources/screen_theme/", "description": "Bespins standard theme basePlugin", "dependencies": {"theme_manager": "0.0.0"}, "testmodules": [], "provides": [{"url": ["theme.less"], "ep": "themestyles"}, {"defaultValue": "@global_font", "ep": "themevariable", "name": "container_font"}, {"defaultValue": "@global_font_size", "ep": "themevariable", "name": "container_font_size"}, {"defaultValue": "@global_container_background", "ep": "themevariable", "name": "container_bg"}, {"defaultValue": "@global_color", "ep": "themevariable", "name": "container_color"}, {"defaultValue": "@global_line_height", "ep": "themevariable", "name": "container_line_height"}, {"defaultValue": "@global_pane_background", "ep": "themevariable", "name": "pane_bg"}, {"defaultValue": "@global_pane_border_radius", "ep": "themevariable", "name": "pane_border_radius"}, {"defaultValue": "@global_form_font", "ep": "themevariable", "name": "form_font"}, {"defaultValue": "@global_form_font_size", "ep": "themevariable", "name": "form_font_size"}, {"defaultValue": "@global_form_line_height", "ep": "themevariable", "name": "form_line_height"}, {"defaultValue": "@global_form_color", "ep": "themevariable", "name": "form_color"}, {"defaultValue": "@global_form_text_shadow", "ep": "themevariable", "name": "form_text_shadow"}, {"defaultValue": "@global_pane_link_color", "ep": "themevariable", "name": "pane_a_color"}, {"defaultValue": "@global_font", "ep": "themevariable", "name": "pane_font"}, {"defaultValue": "@global_font_size", "ep": "themevariable", "name": "pane_font_size"}, {"defaultValue": "@global_pane_text_shadow", "ep": "themevariable", "name": "pane_text_shadow"}, {"defaultValue": "@global_pane_h1_font", "ep": "themevariable", "name": "pane_h1_font"}, {"defaultValue": "@global_pane_h1_font_size", "ep": "themevariable", "name": "pane_h1_font_size"}, {"defaultValue": "@global_pane_h1_color", "ep": "themevariable", "name": "pane_h1_color"}, {"defaultValue": "@global_font_size * 1.8", "ep": "themevariable", "name": "pane_line_height"}, {"defaultValue": "@global_pane_color", "ep": "themevariable", "name": "pane_color"}, {"defaultValue": "@global_text_shadow", "ep": "themevariable", "name": "pane_text_shadow"}, {"defaultValue": "@global_font", "ep": "themevariable", "name": "button_font"}, {"defaultValue": "@global_font_size", "ep": "themevariable", "name": "button_font_size"}, {"defaultValue": "@global_button_color", "ep": "themevariable", "name": "button_color"}, {"defaultValue": "@global_button_background", "ep": "themevariable", "name": "button_bg"}, {"defaultValue": "@button_bg - #063A27", "ep": "themevariable", "name": "button_bg2"}, {"defaultValue": "@button_bg - #194A5E", "ep": "themevariable", "name": "button_border"}, {"defaultValue": "@global_control_background", "ep": "themevariable", "name": "control_bg"}, {"defaultValue": "@global_control_color", "ep": "themevariable", "name": "control_color"}, {"defaultValue": "@global_control_border", "ep": "themevariable", "name": "control_border"}, {"defaultValue": "@global_control_border_radius", "ep": "themevariable", "name": "control_border_radius"}, {"defaultValue": "@global_control_active_background", "ep": "themevariable", "name": "control_active_bg"}, {"defaultValue": "@global_control_active_border", "ep": "themevariable", "name": "control_active_border"}, {"defaultValue": "@global_control_active_color", "ep": "themevariable", "name": "control_active_color"}, {"defaultValue": "@global_control_active_inset_color", "ep": "themevariable", "name": "control_active_inset_color"}], "type": "plugins/supported", "name": "screen_theme"}});;\n +});\n +})();\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +// This script appears at the end of BespinEmbeddedMain and is responsible\n +// for firing up Bespin on the page.\n +// This module depends only on Tiki.\n +\n +\n +(function() {\n +\n +var $ = bespin.tiki.require("jquery").$;\n +/**\n + * Returns the CSS property of element.\n + * 1) If the CSS property is on the style object of the element, use it, OR\n + * 2) Compute the CSS property\n + *\n + * If the property can\'t get computed, is \'auto\' or \'intrinsic\', the former\n + * calculated property is uesd (this can happen in cases where the textarea\n + * is hidden and has no dimension styles).\n + */\n +var getCSSProperty = function(element, container, property) {\n + var ret = element.style[property]\n + || document.defaultView.getComputedStyle(element, \'\').\n + getPropertyValue(property);\n +\n + if (!ret || ret == \'auto\' || ret == \'intrinsic\') {\n + ret = container.style[property];\n + }\n + return ret;\n +};\n +\n +/**\n + * Returns the sum of all passed property values. Calls internal getCSSProperty\n + * to get the value of the individual peroperties.\n + */\n +// var sumCSSProperties = function(element, container, props) {\n +// var ret = document.defaultView.getComputedStyle(element, \'\').\n +// getPropertyValue(props[0]);\n +//\n +// if (!ret || ret == \'auto\' || ret == \'intrinsic\') {\n +// return container.style[props[0]];\n +// }\n +//\n +// var sum = props.map(function(item) {\n +// var cssProp = getCSSProperty(element, container, item);\n +// // Remove the \'px; and parse the property to a floating point.\n +// return parseFloat(cssProp.replace(\'px\', \'\'));\n +// }).reduce(function(a, b) {\n +// return a + b;\n +// });\n +//\n +// return sum;\n +// };\n +\n +bespin.useBespin = function(element, options) {\n + var util = bespin.tiki.require(\'bespin:util/util\');\n +\n + var baseConfig = {};\n + var baseSettings = baseConfig.settings;\n + options = options || {};\n + for (var key in options) {\n + baseConfig[key] = options[key];\n + }\n +\n + // we need to separately merge the configured settings\n + var configSettings = baseConfig.settings;\n + if (baseSettings !== undefined) {\n + for (key in baseSettings) {\n + if (configSettings[key] === undefined) {\n + baseConfig.settings[key] = baseSettings[key];\n + }\n + }\n + }\n +\n + var Promise = bespin.tiki.require(\'bespin:promise\').Promise;\n + var prEnv = null;\n + var pr = new Promise();\n +\n + bespin.tiki.require.ensurePackage("::appconfig", function() {\n + var appconfig = bespin.tiki.require("appconfig");\n + if (util.isString(element)) {\n + element = document.getElementById(element);\n + }\n +\n + if (util.none(baseConfig.initialContent)) {\n + baseConfig.initialContent = element.value || element.innerHTML;\n + }\n +\n + element.innerHTML = \'\';\n +\n + if (element.type == \'textarea\') {\n + var parentNode = element.parentNode;\n + // This will hold the Bespin editor.\n + var container = document.createElement(\'div\');\n +\n + // To put Bespin in the place of the textarea, we have to copy a\n + // few of the textarea\'s style attributes to the div container.\n + //\n + // The problem is, that the properties have to get computed (they\n + // might be defined by a CSS file on the page - you can\'t access\n + // such rules that apply to an element via elm.style). Computed\n + // properties are converted to pixels although the dimension might\n + // be given as percentage. When the window resizes, the dimensions\n + // defined by percentages changes, so the properties have to get\n + // recomputed to get the new/true pixels.\n + var resizeEvent = function() {\n + var style = \'position:relative;\';\n + [\n + \'margin-top\', \'margin-left\', \'margin-right\', \'margin-bottom\'\n + ].forEach(function(item) {\n + style += item + \':\' +\n + getCSSProperty(element, container, item) + \';\';\n + });\n +\n + // Calculating the width/height of the textarea is somewhat\n + // tricky. To do it right, you have to include the paddings\n + // to the sides as well (eg. width = width + padding-left, -right).\n + // This works well, as long as the width of the element is not\n + // set or given in pixels. In this case and after the textarea\n + // is hidden, getCSSProperty(element, container, \'width\') will\n + // still return pixel value. If the element has realtiv dimensions\n + // (e.g. width=\'95<percent>\') getCSSProperty(...) will return pixel values\n + // only as long as the textarea is visible. After it is hidden\n + // getCSSProperty will return the relativ dimensions as they\n + // are set on the element (in the case of width, 95<percent>).\n + // Making the sum of pixel vaules (e.g. padding) and realtive\n + // values (e.g. <percent>) is not possible. As such the padding styles\n + // are ignored.\n +\n + // The complete width is the width of the textarea + the padding\n + // to the left and right.\n + // var width = sumCSSProperties(element, container, [\n + // \'width\', \'padding-left\', \'padding-right\'\n + // ]) + \'px\';\n + // var height = sumCSSProperties(element, container, [\n + // \'height\', \'padding-top\', \'padding-bottom\'\n + // ]) + \'px\';\n + var width = getCSSProperty(element, container, \'width\');\n + var height = getCSSProperty(element, container, \'height\');\n + style += \'height:\' + height + \';width:\' + width + \';\';\n +\n + // Set the display property to \'inline-block\'.\n + style += \'display:inline-block;\';\n + container.setAttribute(\'style\', style);\n + };\n + window.addEventListener(\'resize\', resizeEvent, false);\n +\n + // Call the resizeEvent once, so that the size of the container is\n + // calculated.\n + resizeEvent();\n +\n + // Insert the div container after the element.\n + if (element.nextSibling) {\n + parentNode.insertBefore(container, element.nextSibling);\n + } else {\n + parentNode.appendChild(container);\n + }\n +\n + // Override the forms onsubmit function. Set the innerHTML and value\n + // of the textarea before submitting.\n + while (parentNode !== document) {\n + if (parentNode.tagName.toUpperCase() === \'FORM\') {\n + var oldSumit = parentNode.onsubmit;\n + // Override the onsubmit function of the form.\n + parentNode.onsubmit = function(evt) {\n + element.value = prEnv.editor.value;\n + element.innerHTML = prEnv.editor.value;\n + // If there is a onsubmit function already, then call\n + // it with the current context and pass the event.\n + if (oldSumit) {\n + oldSumit.call(this, evt);\n + }\n + }\n + break;\n + }\n + parentNode = parentNode.parentNode;\n + }\n +\n + // Hide the element.\n + element.style.display = \'none\';\n +\n + // The div container is the new element that is passed to appconfig.\n + baseConfig.element = container;\n +\n + // Check if the textarea has the \'readonly\' flag and set it\n + // on the config object so that the editor is readonly.\n + if (!util.none(element.getAttribute(\'readonly\'))) {\n + baseConfig.readOnly = true;\n + }\n + } else {\n + baseConfig.element = element;\n + }\n +\n + appconfig.launch(baseConfig).then(function(env) {\n + prEnv = env;\n + pr.resolve(env);\n + });\n + });\n +\n + return pr;\n +};\n +\n +$(document).ready(function() {\n + // Holds the lauch promises of all launched Bespins.\n + var launchBespinPromises = [];\n +\n + var nodes = document.querySelectorAll(".bespin");\n + for (var i = 0; i < nodes.length; i++) {\n + var node = nodes[i];\n + var options = node.getAttribute(\'data-bespinoptions\') || \'{}\';\n + var pr = bespin.useBespin(node, JSON.parse(options));\n + pr.then(function(env) {\n + node.bespin = env;\n + }, function(error) {\n + throw new Error(\'Launch failed: \' + error);\n + });\n + launchBespinPromises.push(pr);\n + }\n +\n + // If users want a custom startup\n + if (window.onBespinLoad) {\n + // group-promise function.\n + var group = bespin.tiki.require("bespin:promise").group;\n +\n + // Call the window.onBespinLoad() function after all launched Bespins\n + // are ready or throw an error otherwise.\n + group(launchBespinPromises).then(function() {\n + window.onBespinLoad();\n + }, function() {\n + throw new Error(\'At least one Bespin failed to launch!\');\n + });\n + }\n +});\n +\n +})();\n + + +]]></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinWorker.js.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinWorker.js.xml new file mode 100644 index 0000000000..68cc05e196 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/BespinWorker.js.xml @@ -0,0 +1,1691 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="DTMLMethod" module="OFS.DTMLMethod"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>__name__</string> </key> + <value> <string>BespinWorker.js</string> </value> + </item> + <item> + <key> <string>_vars</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>globals</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>raw</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +;bespin.tiki.register("::python", {\n + name: "python",\n + dependencies: { "syntax_manager": "0.0.0" }\n +});\n +bespin.tiki.module("python:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + * Scott Ellis (mail@scottellis.com.au)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "Python syntax highlighter",\n + "dependencies": { "syntax_manager": "0.0.0" },\n + "environments": { "worker": true },\n + "provides": [\n + {\n + "ep": "syntax",\n + "name": "py",\n + "pointer": "#PySyntax",\n + "fileexts": [ "py" ]\n + }\n + ]\n +});\n +"end";\n +\n +//var SC = require(\'sproutcore/runtime\').SC;\n +//var Promise = require(\'bespin:promise\').Promise;\n +//var StandardSyntax = require(\'syntax_manager:controllers/standardsyntax\').StandardSyntax;\n +var StandardSyntax = require(\'standard_syntax\').StandardSyntax;\n +\n +var states = {\n + start: [\n + {\n +\t regex: /^(?:and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield)(?![a-zA-Z0-9_])/,\n +\t tag: \'keyword\'\n + },\n + {\n +\t regex: /^[A-Za-z_][A-Za-z0-9_]*/,\n +\t tag: \'identifier\'\n + },\n + {\n +\t regex: /^[^\'"#\\/ \\tA-Za-z0-9_]+/,\n +\t tag: \'plain\'\n + },\n + {\n +\t regex: /^[ \\t]+/,\n +\t tag: \'plain\'\n + },\n + {\n +\t regex: /^"""/,\n +\t tag: \'string\',\n +\t then: \'qqqstring\'\n + },\n + {\n +\t regex: /^\'/,\n +\t tag: \'string\',\n +\t then: \'qstring\'\n + },\n + {\n +\t regex: /^"/,\n +\t tag: \'string\',\n +\t then: \'qqstring\'\n + },\n + {\n +\t regex: /^#.*/,\n +\t tag: \'comment\'\n + },\n + {\n +\t regex: /^./,\n +\t tag: \'plain\'\n + }\n + ],\n +\n + qstring: [\n + {\n +\t regex: /^\'/,\n +\t tag: \'string\',\n +\t then: \'start\'\n + },\n + {\n +\t regex: /^(?:\\\\.|[^\'\\\\])+/,\n +\t tag: \'string\'\n + }\n + ],\n +\n + qqstring: [\n + {\n +\t regex: /^"/,\n +\t tag: \'string\',\n +\t then: \'start\'\n + },\n + {\n +\t regex: /^(?:\\\\.|[^"\\\\])+/,\n +\t tag: \'string\'\n + }\n + ],\n +\n + qqqstring: [\n + {\n +\t regex: /^"""/,\n +\t tag: \'string\',\n +\t then: \'start\'\n + },\n + {\n +\t regex: /^./,\n +\t tag: \'string\'\n + }\n + ]\n +\n +};\n +\n +exports.PySyntax = new StandardSyntax(states);\n +\n +\n +\n +});\n +;bespin.tiki.register("::syntax_worker", {\n + name: "syntax_worker",\n + dependencies: { "syntax_directory": "0.0.0", "underscore": "0.0.0" }\n +});\n +bespin.tiki.module("syntax_worker:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "Coordinates multiple syntax engines",\n + "environments": { "worker": true },\n + "dependencies": { "syntax_directory": "0.0.0", "underscore": "0.0.0" }\n +});\n +"end";\n +\n +var promise = require(\'bespin:promise\');\n +var _ = require(\'underscore\')._;\n +var console = require(\'bespin:console\').console;\n +var syntaxDirectory = require(\'syntax_directory\').syntaxDirectory;\n +\n +var syntaxWorker = {\n + engines: {},\n +\n + annotate: function(state, lines, range) {\n + function splitParts(str) { return str.split(":"); }\n + function saveState() {\n + states.push(_(stateStack).invoke(\'join\', ":").join(" "));\n + }\n +\n + var engines = this.engines;\n + var states = [], attrs = [], symbols = [];\n + var stateStack = _(state.split(" ")).map(splitParts);\n +\n + _(lines).each(function(line, offset) {\n + saveState();\n +\n + var lineAttrs = [], lineSymbols = {};\n + var col = 0;\n + while (col < line.length) {\n + // Check for the terminator string.\n + // FIXME: This is wrong. It should check *inside* the token\n + // that was just parsed as well.\n + var curState;\n + while (true) {\n + curState = _(stateStack).last();\n + if (curState.length < 3) {\n + break;\n + }\n +\n + var term = curState[2];\n + if (line.substring(col, col + term.length) !== term) {\n + break;\n + }\n +\n + stateStack.pop();\n + }\n +\n + var context = curState[0];\n + var result = engines[context].get(curState, line, col);\n + var token;\n + if (result == null) {\n + token = {\n + state: \'plain\',\n + tag: \'plain\',\n + start: col,\n + end: line.length\n + };\n + } else {\n + stateStack[stateStack.length - 1] = result.state;\n + if (result.hasOwnProperty(\'newContext\')) {\n + stateStack.push(result.newContext);\n + }\n +\n + token = result.token;\n +\n + var sym = result.symbol;\n + if (sym != null) {\n + lineSymbols["-" + sym[0]] = sym[1];\n + }\n + }\n +\n + lineAttrs.push(token);\n + col = token.end;\n + }\n +\n + attrs.push(lineAttrs);\n + symbols.push(lineSymbols);\n + });\n +\n + saveState();\n +\n + return { states: states, attrs: attrs, symbols: symbols };\n + },\n +\n + loadSyntax: function(syntaxName) {\n + var pr = new promise.Promise;\n +\n + var engines = this.engines;\n + if (engines.hasOwnProperty(syntaxName)) {\n + pr.resolve();\n + return pr;\n + }\n +\n + var info = syntaxDirectory.get(syntaxName);\n + if (info == null) {\n + throw new Error(\'No syntax engine installed for syntax "\' +\n + syntaxName + \'".\');\n + }\n +\n + info.extension.load().then(function(engine) {\n + engines[syntaxName] = engine;\n +\n + var subsyntaxes = engine.subsyntaxes;\n + if (subsyntaxes == null) {\n + pr.resolve();\n + return;\n + }\n +\n + var pr2 = promise.group(_(subsyntaxes).map(this.loadSyntax, this));\n + pr2.then(_(pr.resolve).bind(pr));\n + }.bind(this));\n +\n + return pr;\n + }\n +};\n +\n +exports.syntaxWorker = syntaxWorker;\n +\n +\n +});\n +;bespin.tiki.register("::stylesheet", {\n + name: "stylesheet",\n + dependencies: { "standard_syntax": "0.0.0" }\n +});\n +bespin.tiki.module("stylesheet:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "CSS syntax highlighter",\n + "dependencies": {\n + "standard_syntax": "0.0.0"\n + },\n + "environments": {\n + "worker": true\n + },\n + "provides": [\n + {\n + "ep": "syntax",\n + "name": "css",\n + "pointer": "#CSSSyntax",\n + "fileexts": [ "css", "less" ]\n + }\n + ]\n +});\n +"end";\n +\n +var Promise = require(\'bespin:promise\').Promise;\n +var StandardSyntax = require(\'standard_syntax\').StandardSyntax;\n +\n +var COMMENT_REGEXP = {\n + regex: /^\\/\\/.*/,\n + tag: \'comment\'\n +};\n +\n +var createCommentState = function(jumpBackState) {\n + return [\n + {\n + regex: /^[^*\\/]+/,\n + tag: \'comment\'\n + },\n + {\n + regex: /^\\*\\//,\n + tag: \'comment\',\n + then: jumpBackState\n + },\n + {\n + regex: /^[*\\/]/,\n + tag: \'comment\'\n + }\n + ];\n +};\n +\n +var states = {\n + start: [\n + {\n + //style names\n + regex: /^([a-zA-Z-\\s]*)(?:\\:)/,\n + tag: \'identifier\',\n + then: \'style\'\n + },\n + {\n + //tags\n + regex: /^([\\w]+)(?![a-zA-Z0-9_:])([,|{]*?)(?!;)(?!(;|%))/,\n + tag: \'keyword\',\n + then: \'header\'\n + },\n + {\n + //id\n + regex: /^#([a-zA-Z]*)(?=.*{*?)/,\n + tag: \'keyword\',\n + then: \'header\'\n + },\n + {\n + //classes\n + regex: /^\\.([a-zA-Z]*)(?=.*{*?)/,\n + tag: \'keyword\',\n + then: \'header\'\n + },\n + COMMENT_REGEXP,\n + {\n + regex: /^\\/\\*/,\n + tag: \'comment\',\n + then: \'comment\'\n + },\n + {\n + regex: /^./,\n + tag: \'plain\'\n + }\n + ],\n +\n + header: [\n + {\n + regex: /^[^{|\\/\\/|\\/\\*]*/,\n + tag: \'keyword\',\n + then: \'start\'\n + },\n + COMMENT_REGEXP,\n + {\n + regex: /^\\/\\*/,\n + tag: \'comment\',\n + then: \'comment_header\'\n + }\n + ],\n +\n + style: [\n + {\n + regex: /^[^;|}|\\/\\/|\\/\\*]+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^;|}/,\n + tag: \'plain\',\n + then: \'start\'\n + },\n + COMMENT_REGEXP,\n + {\n + regex: /^\\/\\*/,\n + tag: \'comment\',\n + then: \'comment_style\'\n + }\n + ],\n +\n + comment: createCommentState(\'start\'),\n + comment_header: createCommentState(\'header\'),\n + comment_style: createCommentState(\'style\')\n +};\n +\n +exports.CSSSyntax = new StandardSyntax(states);\n +\n +});\n +;bespin.tiki.register("::html", {\n + name: "html",\n + dependencies: { "standard_syntax": "0.0.0" }\n +});\n +bespin.tiki.module("html:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "HTML syntax highlighter",\n + "dependencies": { "standard_syntax": "0.0.0" },\n + "environments": { "worker": true },\n + "provides": [\n + {\n + "ep": "syntax",\n + "name": "html",\n + "pointer": "#HTMLSyntax",\n + "fileexts": [ "htm", "html" ]\n + }\n + ]\n +});\n +"end";\n +\n +var StandardSyntax = require(\'standard_syntax\').StandardSyntax;\n +\n +var states = {};\n +\n +//\n +// This parser is modeled on the WHATWG HTML 5 specification, with some\n +// simplifications to improve performance. See the relevant spec here:\n +//\n +// http://www.whatwg.org/specs/web-apps/current-work/\n +//\n +\n +var createTagStates = function(prefix, interiorActions) {\n + states[prefix + \'_beforeAttrName\'] = [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^\\//,\n + tag: \'operator\',\n + then: prefix + \'_selfClosingStartTag\'\n + },\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: interiorActions\n + },\n + {\n + regex: /^./,\n + tag: \'keyword\',\n + then: prefix + \'_attrName\'\n + }\n + ];\n +\n + // 10.2.4.35 Attribute name state\n + states[prefix + \'_attrName\'] = [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\',\n + then: prefix + \'_afterAttrName\'\n + },\n + {\n + regex: /^\\//,\n + tag: \'operator\',\n + then: prefix + \'_selfClosingStartTag\'\n + },\n + {\n + regex: /^=/,\n + tag: \'operator\',\n + then: prefix + \'_beforeAttrValue\'\n + },\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: interiorActions\n + },\n + {\n + regex: /^["\'<]+/,\n + tag: \'error\'\n + },\n + {\n + regex: /^[^ \\t\\n\\/=>"\'<]+/,\n + tag: \'keyword\'\n + }\n + ];\n +\n + states[prefix + \'_afterAttrName\'] = [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^\\//,\n + tag: \'operator\',\n + then: prefix + \'_selfClosingStartTag\'\n + },\n + {\n + regex: /^=/,\n + tag: \'operator\',\n + then: prefix + \'_beforeAttrValue\'\n + },\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: interiorActions\n + },\n + {\n + regex: /^./,\n + tag: \'keyword\',\n + then: prefix + \'_attrName\'\n + }\n + ];\n +\n + states[prefix + \'_beforeAttrValue\'] = [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: prefix + \'_attrValueQQ\'\n + },\n + {\n + regex: /^(?=&)/,\n + tag: \'plain\',\n + then: prefix + \'_attrValueU\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: prefix + \'_attrValueQ\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: interiorActions\n + },\n + {\n + regex: /^./,\n + tag: \'string\',\n + then: prefix + \'_attrValueU\'\n + }\n + ];\n +\n + states[prefix + \'_attrValueQQ\'] = [\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: prefix + \'_afterAttrValueQ\'\n + },\n + {\n + regex: /^[^"]+/,\n + tag: \'string\'\n + }\n + ];\n +\n + states[prefix + \'_attrValueQ\'] = [\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: prefix + \'_afterAttrValueQ\'\n + },\n + {\n + regex: /^[^\']+/,\n + tag: \'string\'\n + }\n + ];\n +\n + states[prefix + \'_attrValueU\'] = [\n + {\n + regex: /^\\s/,\n + tag: \'string\',\n + then: prefix + \'_beforeAttrName\'\n + },\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: interiorActions\n + },\n + {\n + regex: /[^ \\t\\n>]+/,\n + tag: \'string\'\n + }\n + ];\n +\n + states[prefix + \'_afterAttrValueQ\'] = [\n + {\n + regex: /^\\s/,\n + tag: \'plain\',\n + then: prefix + \'_beforeAttrName\'\n + },\n + {\n + regex: /^\\//,\n + tag: \'operator\',\n + then: prefix + \'_selfClosingStartTag\'\n + },\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: interiorActions\n + },\n + {\n + regex: /^(?=.)/,\n + tag: \'operator\',\n + then: prefix + \'_beforeAttrName\'\n + }\n + ];\n +\n + // 10.2.4.43 Self-closing start tag state\n + states[prefix + \'_selfClosingStartTag\'] = [\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: prefix + \'_beforeAttrName\'\n + }\n + ];\n +};\n +\n +states = {\n + // 10.2.4.1 Data state\n + start: [\n + {\n + regex: /^[^<]+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^<!--/,\n + tag: \'comment\',\n + then: \'commentStart\'\n + },\n + {\n + regex: /^<!/,\n + tag: \'directive\',\n + then: \'markupDeclarationOpen\'\n + },\n + {\n + regex: /^<\\?/,\n + tag: \'comment\',\n + then: \'bogusComment\'\n + },\n + {\n + regex: /^</,\n + tag: \'operator\',\n + then: \'tagOpen\'\n + }\n + ],\n +\n + // 10.2.4.8 Tag open state\n + tagOpen: [\n + {\n + regex: /^\\//,\n + tag: \'operator\',\n + then: \'endTagOpen\'\n + },\n + {\n + regex: /^script/i,\n + tag: \'keyword\',\n + then: \'script_beforeAttrName\'\n + },\n + {\n + regex: /^[a-zA-Z]/,\n + tag: \'keyword\',\n + then: \'tagName\'\n + },\n + {\n + regex: /^(?=.)/,\n + tag: \'plain\',\n + then: \'start\'\n + }\n + ],\n +\n + // 10.2.4.6 Script data state\n + scriptData: [\n + {\n + regex: /^<(?=\\/script>)/i,\n + tag: \'operator\',\n + then: \'tagOpen\'\n + },\n + {\n + regex: /^[^<]+/,\n + tag: \'plain\'\n + }\n + ],\n +\n + // 10.2.4.9 End tag open state\n + endTagOpen: [\n + {\n + regex: /^[a-zA-Z]/,\n + tag: \'keyword\',\n + then: \'tagName\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusComment\'\n + }\n + ],\n +\n + // 10.2.4.10 Tag name state\n + tagName: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\',\n + then: \'normal_beforeAttrName\'\n + },\n + {\n + regex: /^\\//,\n + tag: \'operator\',\n + then: \'normal_selfClosingStartTag\'\n + },\n + {\n + regex: /^>/,\n + tag: \'operator\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^ \\t\\n\\/>]+/,\n + tag: \'keyword\'\n + }\n + ],\n +\n + // 10.2.4.44 Bogus comment state\n + bogusComment: [\n + {\n + regex: /^[^>]+/,\n + tag: \'comment\'\n + },\n + {\n + regex: /^>/,\n + tag: \'comment\',\n + then: \'start\'\n + }\n + ],\n +\n + // 10.2.4.45 Markup declaration open state\n + markupDeclarationOpen: [\n + {\n + regex: /^doctype/i,\n + tag: \'directive\',\n + then: \'doctype\'\n + },\n + {\n + regex: /^(?=.)/,\n + tag: \'comment\',\n + then: \'bogusComment\'\n + }\n + ],\n +\n + // 10.2.4.46 Comment start state\n + commentStart: [\n + {\n + regex: /^-->/,\n + tag: \'comment\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^-]+/,\n + tag: \'comment\'\n + }\n + ],\n +\n + // 10.2.4.53 DOCTYPE state\n + doctype: [\n + {\n + regex: /^\\s/,\n + tag: \'plain\',\n + then: \'beforeDoctypeName\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'beforeDoctypeName\'\n + }\n + ],\n +\n + // 10.2.4.54 Before DOCTYPE name state\n + beforeDoctypeName: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'directive\',\n + then: \'doctypeName\'\n + }\n + ],\n +\n + // 10.2.4.55 DOCTYPE name state\n + doctypeName: [\n + {\n + regex: /^\\s/,\n + tag: \'plain\',\n + then: \'afterDoctypeName\'\n + },\n + {\n + regex: /^>/,\n + tag: \'directive\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^ \\t\\n>]+/,\n + tag: \'directive\'\n + }\n + ],\n +\n + // 10.2.4.56 After DOCTYPE name state\n + afterDoctypeName: [\n + {\n + regex: /^\\s+/,\n + tag: \'directive\'\n + },\n + {\n + regex: /^>/,\n + tag: \'directive\',\n + then: \'start\'\n + },\n + {\n + regex: /^public/i,\n + tag: \'directive\',\n + then: \'afterDoctypePublicKeyword\'\n + },\n + {\n + regex: /^system/i,\n + tag: \'directive\',\n + then: \'afterDoctypeSystemKeyword\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.57 After DOCTYPE public keyword state\n + afterDoctypePublicKeyword: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\',\n + then: \'beforeDoctypePublicId\'\n + },\n + {\n + regex: /^"/,\n + tag: \'error\',\n + then: \'doctypePublicIdQQ\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'error\',\n + then: \'doctypePublicIdQ\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.58 Before DOCTYPE public identifier\n + beforeDoctypePublicId: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: \'doctypePublicIdQQ\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: \'doctypePublicIdQ\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.59 DOCTYPE public identifier (double-quoted) state\n + doctypePublicIdQQ: [\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: \'afterDoctypePublicId\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^>"]+/,\n + tag: \'string\'\n + }\n + ],\n +\n + // 10.2.4.60 DOCTYPE public identifier (single-quoted) state\n + doctypePublicIdQ: [\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: \'afterDoctypePublicId\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^>\']+/,\n + tag: \'string\'\n + }\n + ],\n +\n + // 10.2.4.61 After DOCTYPE public identifier state\n + afterDoctypePublicId: [\n + {\n + regex: /^\\s/,\n + tag: \'plain\',\n + then: \'betweenDoctypePublicAndSystemIds\'\n + },\n + {\n + regex: /^>/,\n + tag: \'directive\',\n + then: \'start\'\n + },\n + {\n + regex: /^"/,\n + tag: \'error\',\n + then: \'doctypeSystemIdQQ\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'error\',\n + then: \'doctypeSystemIdQ\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.62 Between DOCTYPE public and system identifiers state\n + betweenDoctypePublicAndSystemIds: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\',\n + then: \'betweenDoctypePublicAndSystemIds\'\n + },\n + {\n + regex: /^>/,\n + tag: \'directive\',\n + then: \'start\'\n + },\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: \'doctypeSystemIdQQ\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: \'doctypeSystemIdQ\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.63 After DOCTYPE system keyword state\n + afterDoctypeSystemKeyword: [\n + {\n + regex: /^\\s/,\n + tag: \'plain\',\n + then: \'beforeDoctypeSystemId\'\n + },\n + {\n + regex: /^"/,\n + tag: \'error\',\n + then: \'doctypeSystemIdQQ\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'error\',\n + then: \'doctypeSystemIdQ\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.64 Before DOCTYPE system identifier state\n + beforeDoctypeSystemId: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\',\n + then: \'beforeDoctypeSystemId\'\n + },\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: \'doctypeSystemIdQQ\'\n + },\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: \'doctypeSystemIdQ\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.65 DOCTYPE system identifier (double-quoted) state\n + doctypeSystemIdQQ: [\n + {\n + regex: /^"/,\n + tag: \'string\',\n + then: \'afterDoctypeSystemId\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^">]+/,\n + tag: \'string\'\n + }\n + ],\n +\n + // 10.2.4.66 DOCTYPE system identifier (single-quoted) state\n + doctypeSystemIdQ: [\n + {\n + regex: /^\'/,\n + tag: \'string\',\n + then: \'afterDoctypeSystemId\'\n + },\n + {\n + regex: /^>/,\n + tag: \'error\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^\'>]+/,\n + tag: \'string\'\n + }\n + ],\n +\n + // 10.2.4.67 After DOCTYPE system identifier state\n + afterDoctypeSystemId: [\n + {\n + regex: /^\\s+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^>/,\n + tag: \'directive\',\n + then: \'start\'\n + },\n + {\n + regex: /^./,\n + tag: \'error\',\n + then: \'bogusDoctype\'\n + }\n + ],\n +\n + // 10.2.4.68 Bogus DOCTYPE state\n + bogusDoctype: [\n + {\n + regex: /^>/,\n + tag: \'directive\',\n + then: \'start\'\n + },\n + {\n + regex: /^[^>]+/,\n + tag: \'directive\'\n + }\n + ]\n +};\n +\n +createTagStates(\'normal\', \'start\');\n +createTagStates(\'script\', \'start js:start:</script>\');\n +\n +/**\n + * This syntax engine exposes an HTML parser modeled on the WHATWG HTML 5\n + * specification.\n + */\n +exports.HTMLSyntax = new StandardSyntax(states, [ \'js\' ]);\n +\n +\n +});\n +;bespin.tiki.register("::js_syntax", {\n + name: "js_syntax",\n + dependencies: { "standard_syntax": "0.0.0" }\n +});\n +bespin.tiki.module("js_syntax:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "JavaScript syntax highlighter",\n + "dependencies": { "standard_syntax": "0.0.0" },\n + "environments": { "worker": true },\n + "provides": [\n + {\n + "ep": "syntax",\n + "name": "js",\n + "pointer": "#JSSyntax",\n + "fileexts": [ "js", "json" ]\n + }\n + ]\n +});\n +"end";\n +\n +var StandardSyntax = require(\'standard_syntax\').StandardSyntax;\n +\n +var states = {\n + start: [\n + {\n + regex: /^var(?=\\s*([A-Za-z_$][A-Za-z0-9_$]*)\\s*=\\s*require\\s*\\(\\s*[\'"]([^\'"]*)[\'"]\\s*\\)\\s*[;,])/,\n + tag: \'keyword\',\n + symbol: \'$1:$2\'\n + },\n + {\n + regex: /^(?:break|case|catch|continue|default|delete|do|else|false|finally|for|function|if|in|instanceof|let|new|null|return|switch|this|throw|true|try|typeof|var|void|while|with)(?![a-zA-Z0-9_])/,\n + tag: \'keyword\'\n + },\n + {\n + regex: /^[A-Za-z_][A-Za-z0-9_]*/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^[^\'"\\/ \\tA-Za-z0-9_]+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^[ \\t]+/,\n + tag: \'plain\'\n + },\n + {\n + regex: /^\'(?=.)/,\n + tag: \'string\',\n + then: \'qstring\'\n + },\n + {\n + regex: /^"(?=.)/,\n + tag: \'string\',\n + then: \'qqstring\'\n + },\n + {\n + regex: /^\\/\\/.*/,\n + tag: \'comment\'\n + },\n + {\n + regex: /^\\/\\*/,\n + tag: \'comment\',\n + then: \'comment\'\n + },\n + {\n + regex: /^./,\n + tag: \'plain\'\n + }\n + ],\n +\n + qstring: [\n + {\n + regex: /^(?:\\\\.|[^\'\\\\])*\'?/,\n + tag: \'string\',\n + then: \'start\'\n + }\n + ],\n +\n + qqstring: [\n + {\n + regex: /^(?:\\\\.|[^"\\\\])*"?/,\n + tag: \'string\',\n + then: \'start\'\n + }\n + ],\n +\n + comment: [\n + {\n + regex: /^[^*\\/]+/,\n + tag: \'comment\'\n + },\n + {\n + regex: /^\\*\\//,\n + tag: \'comment\',\n + then: \'start\'\n + },\n + {\n + regex: /^[*\\/]/,\n + tag: \'comment\'\n + }\n + ]\n +};\n +\n +exports.JSSyntax = new StandardSyntax(states);\n +\n +});\n +;bespin.tiki.register("::standard_syntax", {\n + name: "standard_syntax",\n + dependencies: { "syntax_worker": "0.0.0", "syntax_directory": "0.0.0", "underscore": "0.0.0" }\n +});\n +bespin.tiki.module("standard_syntax:index",function(require,exports,module) {\n +/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +"define metadata";\n +({\n + "description": "Easy-to-use basis for syntax engines",\n + "environments": { "worker": true },\n + "dependencies": { \n + "syntax_directory": "0.0.0", \n + "underscore": "0.0.0",\n + "syntax_worker": "0.0.0"\n + }\n +});\n +"end";\n +\n +var promise = require(\'bespin:promise\');\n +var _ = require(\'underscore\')._;\n +var console = require(\'bespin:console\').console;\n +var syntaxDirectory = require(\'syntax_directory\').syntaxDirectory;\n +\n +exports.StandardSyntax = function(states, subsyntaxes) {\n + this.states = states;\n + this.subsyntaxes = subsyntaxes;\n +};\n +\n +/** This syntax controller exposes a simple regex- and line-based parser. */\n +exports.StandardSyntax.prototype = {\n + get: function(fullState, line, col) {\n + var context = fullState[0], state = fullState[1];\n +\n + if (!this.states.hasOwnProperty(state)) {\n + throw new Error(\'StandardSyntax: no such state "\' + state + \'"\');\n + }\n +\n + var str = line.substring(col); // TODO: sticky flag where available\n + var token = { start: col, state: fullState };\n +\n + var result = null;\n + _(this.states[state]).each(function(alt) {\n + var regex = alt.regex;\n + var match = regex.exec(str);\n + if (match == null) {\n + return;\n + }\n +\n + var len = match[0].length;\n + token.end = col + len;\n + token.tag = alt.tag;\n +\n + var newSymbol = null;\n + if (alt.hasOwnProperty(\'symbol\')) {\n + var replace = function(_, n) { return match[n]; };\n + var symspec = alt.symbol.replace(/\\$([0-9]+)/g, replace);\n + var symMatch = /^([^:]+):(.*)/.exec(symspec);\n + newSymbol = [ symMatch[1], symMatch[2] ];\n + }\n +\n + var nextState, newContext = null;\n + if (alt.hasOwnProperty(\'then\')) {\n + var then = alt.then.split(" ");\n + nextState = [ context, then[0] ];\n + if (then.length > 1) {\n + newContext = then[1].split(":");\n + }\n + } else if (len === 0) {\n + throw new Error("StandardSyntax: Infinite loop detected: " +\n + "zero-length match that didn\'t change state");\n + } else {\n + nextState = fullState;\n + }\n +\n + result = { state: nextState, token: token, symbol: newSymbol };\n + if (newContext != null) {\n + result.newContext = newContext;\n + }\n +\n + _.breakLoop();\n + });\n +\n + return result;\n + }\n +};\n +\n +\n +});\n +bespin.metadata = {"python": {"resourceURL": "resources/python/", "name": "python", "environments": {"worker": true}, "dependencies": {"syntax_manager": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#PySyntax", "ep": "syntax", "fileexts": ["py"], "name": "py"}], "type": "plugins/thirdparty", "description": "Python syntax highlighter"}, "syntax_worker": {"resourceURL": "resources/syntax_worker/", "description": "Coordinates multiple syntax engines", "environments": {"worker": true}, "dependencies": {"syntax_directory": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "type": "plugins/supported", "name": "syntax_worker"}, "stylesheet": {"resourceURL": "resources/stylesheet/", "name": "stylesheet", "environments": {"worker": true}, "dependencies": {"standard_syntax": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#CSSSyntax", "ep": "syntax", "fileexts": ["css", "less"], "name": "css"}], "type": "plugins/supported", "description": "CSS syntax highlighter"}, "html": {"resourceURL": "resources/html/", "name": "html", "environments": {"worker": true}, "dependencies": {"standard_syntax": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#HTMLSyntax", "ep": "syntax", "fileexts": ["htm", "html"], "name": "html"}], "type": "plugins/supported", "description": "HTML syntax highlighter"}, "js_syntax": {"resourceURL": "resources/js_syntax/", "name": "js_syntax", "environments": {"worker": true}, "dependencies": {"standard_syntax": "0.0.0"}, "testmodules": [], "provides": [{"pointer": "#JSSyntax", "ep": "syntax", "fileexts": ["js", "json"], "name": "js"}], "type": "plugins/supported", "description": "JavaScript syntax highlighter"}, "standard_syntax": {"resourceURL": "resources/standard_syntax/", "description": "Easy-to-use basis for syntax engines", "environments": {"worker": true}, "dependencies": {"syntax_worker": "0.0.0", "syntax_directory": "0.0.0", "underscore": "0.0.0"}, "testmodules": [], "type": "plugins/supported", "name": "standard_syntax"}};/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +if (typeof(window) !== \'undefined\') {\n + throw new Error(\'"worker.js can only be loaded in a web worker. Use the \' +\n + \'"worker_manager" plugin to instantiate web workers.\');\n +}\n +\n +var messageQueue = [];\n +var target = null;\n +\n +if (typeof(bespin) === \'undefined\') {\n + bespin = {};\n +}\n +\n +function pump() {\n + if (messageQueue.length === 0) {\n + return;\n + }\n +\n + var msg = messageQueue[0];\n + switch (msg.op) {\n + case \'load\':\n + var base = msg.base;\n + bespin.base = base;\n + if (!bespin.hasOwnProperty(\'tiki\')) {\n + importScripts(base + "tiki.js");\n + }\n + if (!bespin.bootLoaded) {\n + importScripts(base + "plugin/register/boot");\n + bespin.bootLoaded = true;\n + }\n +\n + var require = bespin.tiki.require;\n + require.loader.sources[0].xhr = true;\n + require.ensurePackage(\'::bespin\', function() {\n + var catalog = require(\'bespin:plugins\').catalog;\n + var Promise = require(\'bespin:promise\').Promise;\n +\n + var pr;\n + if (!bespin.hasOwnProperty(\'metadata\')) {\n + pr = catalog.loadMetadataFromURL("plugin/register/worker");\n + } else {\n + catalog.registerMetadata(bespin.metadata);\n + pr = new Promise();\n + pr.resolve();\n + }\n +\n + pr.then(function() {\n + require.ensurePackage(msg.pkg, function() {\n + var module = require(msg.module);\n + target = module[msg.target];\n + messageQueue.shift();\n + pump();\n + });\n + });\n + });\n + break;\n +\n + case \'invoke\':\n + function finish(result) {\n + var resp = { op: \'finish\', id: msg.id, result: result };\n + postMessage(JSON.stringify(resp));\n + messageQueue.shift();\n + pump();\n + }\n +\n + if (!target.hasOwnProperty(msg.method)) {\n + throw new Error("No such method: " + msg.method);\n + }\n +\n + var rv = target[msg.method].apply(target, msg.args);\n + if (typeof(rv) === \'object\' && rv.isPromise) {\n + rv.then(finish, function(e) { throw e; });\n + } else {\n + finish(rv);\n + }\n +\n + break;\n + }\n +}\n +\n +onmessage = function(ev) {\n + messageQueue.push(JSON.parse(ev.data));\n + if (messageQueue.length === 1) {\n + pump();\n + }\n +};\n +\n + + +]]></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/bespin_support.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/bespin_support.xml new file mode 100644 index 0000000000..8d243cddee --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/bespin_support.xml @@ -0,0 +1,83 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary> + <item> + <key> <string>name_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_text</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +<tal:block tal:define=\'cleaninput python: inputvalue;\n + name python: inputname;\n + site_root python: here.getWebSiteValue() or here.getPortalObject();\n + portal_url python: site_root.absolute_url();\n + cols python: field.get_value("width");\n + rows python: field.get_value("height");\n + extra python: "%s" % field.get_value("extra")\n + \'>\n + <script type="text/javascript" tal:attributes="src string:${portal_url}/BespinEmbedded.js" />\n + <script type="text/javascript" tal:attributes="src string:${portal_url}/BespinPython.js" />\n + <textarea class="bespin" \n + tal:attributes="cols cols; \n + rows rows; \n + name name;\n + data-bespinoptions extra"\n + tal:content="cleaninput">\n + \n + </textarea>\n +</tal:block> + +]]></string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>text/html</string> </value> + </item> + <item> + <key> <string>expand</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>bespin_support</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources.xml new file mode 100644 index 0000000000..2e3ed76b76 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Folder" module="OFS.Folder"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_objects</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>resources</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/completion.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/completion.xml new file mode 100644 index 0000000000..71922e3c32 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/completion.xml @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Folder" module="OFS.Folder"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>id</string> </key> + <value> <string>completion</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme.xml new file mode 100644 index 0000000000..09d45a7a91 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Folder" module="OFS.Folder"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_objects</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>screen_theme</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images.xml new file mode 100644 index 0000000000..ac684bc2d2 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Folder" module="OFS.Folder"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_objects</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>images</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/bespin-s.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/bespin-s.png.xml new file mode 100644 index 0000000000..16174e97ae --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/bespin-s.png.xml @@ -0,0 +1,186 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210751.06</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>bespin-s.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAEkAAABGCAYAAACAJbkJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ +bWFnZVJlYWR5ccllPAAAHbZJREFUeNrsXGu0XVV1nms/zvuc+743yc07gYQkvCSKCIqCYDXIQCyl +wzbgqPVBH0LHwKo/OqzDZ6tW1KG26hCxDosPqCJYoWKtRSnybCAQCQSSEO4j99x73o/9Wp1zrrX3 +2efk3JsEE/unO+x7ztlnn73X+tac3/zmXGsjpJTw/9vSm0V/PveTB6MDBBrBtvWUjdHnpTZTAAT4 +WvckJAyAIfwzkDThQM0DH39bsAQk8KS0ZfD5biCh6UpwJCwzIXgPHr7EFOJVdB3TEOocP4BGy5mu +N9sPVavVhwIZbAiCgBr0UxnIf8TPLwohutpm2TY4kABhGDCYtiDe6vzgMMw8sxvOOetMaLg+lNo+ +2PpebWx81pTYLgGGwL5L0dW/CzeMKJBO5NYD6QW4fwA7tCN26yns34MJCC4XngODqTSkEhbYJjXS +gAef2scdwfOXgRCX4etldFxgp/zAPw+/+Bu8yV/hdW7qvbcQJ9GSTgI4tO0cTxnfXJZDOHwPZhaq +UG600Urk8oVa4/JolFNJOHfzahjIJNmSArcN9WoDsvkCGF0ACPwebS8IQJjis/j6Mjz8TjIG/v5k +u9uJQgmtnzr/FWzyxIaBBMxhZx/+zYuwUG2yJRiGshbD6HS/2mrDL57YB687fR2MFbIMlOM4EJTL +kMvnwDRVEwkEdQ2TLApBM3YGfrAdXe4i/Gr6ZHKScQIxevNE2vjhqaPpiVMncrA8n4A9z+yDuVIF +kEMQQNwD4i/Jn8kyeMd/rufDPY8+A89MF/kYbT5aXwWBchEwPqZNhV4sBMpEsE3TOM00jOfx6/Nj +p5xws+oLkoj5t1jC0WXHzc7PmPDJYSTMfDKJpGjAvY/sgVbbRfdAMgwCHRAIJfoswUMQ6Bh3TgP2 +66cPQanpRZZG39eqFWg1mwxmBCzulmWCbVmQTCbwv8R9aGTXi7DtJxinJdxN9GeaI7drMqa8xbRN +SGsCrrcceGG2yJEmCBScdLVAqmFht8EjgfTZ/cgqwi2FHGXhtaoVtECffwyNRg2v44FnZqHUkvD8 +nANtjJCzJVeDCbB2Weqmczckz0Ebveb4mv9SQKKh1aE1fNsbbmNE/eaUIW8ZwpA/lk9DJmkzpxya +W+iMJVkQ7kS4BAW5m8GgGEo7iICvlUyl+IYEbBIE37dSKkX3c1oteGhGwv883YxaICBqKkxPN2HP +/trOay5avoCXuf5Eyj9rMfvZ/fRe3QAJm07ZwB1t+US8GE58pS3Spvh+BnVQIWVDAQFKJUy+Rqne +hJAjGFwEKCDA8Z/JpgT8OZ1OwUwd4DfTLizUSlCqejC/4MDQoA03XjYJbbSgtuN1NUwGysl54Hqi +xkKxDfc/XXnvG88a/gQemD657qZNKGZUR3ATHt5hG5BImgbkECTb6rhMEBw5jJJZWyjjIWK20/C9 +X1ZgZqYJ8VFnCKQFy4YHYNuqMfjJA7ug1mh3hC75r+inOyRfZ8/+Klz72lV/Z1r2tV5AAtWAsiOX +FisvlbgX+6Rvs7MdiPe3JarrTAKytsWnedgBxw2g6XiRe3aBK9kUwEhl4Dv3l9BFGvo8qTuJu+8z +oB7yUSGTgre8ZjvkUEPxGYHUgQBf9XnkxmrX1jTXRIkQEC/dEuLB15UngbgjHhLd+OOhp9bmzM0j +aRNySYxmqQSFYiTSAPbN17lztbanGyYjkMKIaeG5Dz7voWu0OgYh9fUDxU9E/pUmkrOniD2LfEXW +9LL1Gdi4Ig0bx2ygAHj/Pgd+9sBcl8sRgLmEDemkec1cwydyvOFoqveEikm8/vnrEKANo1kYSNvc +dfKihbYDT0xVYSAhYBhHvZS0ohH0ccRN04yukUxnkHwXuDMy1rlTNxbgNVuHYPPyLBv4UDbJgAuh +dBWda7bLMIykuFBUed7LV+XgkacTUJpvqQFVvoryAMk/kYCU61yPeeAgHv4qfv/Ll4jRcYCE+Svy +6VcoWbVYx4hoYJ6YrkHORoCwY0PpJByyjS6LJHcgaxOc4KJEqDldw/rKs0bhPZeshVMnBhmYlofJ +MWspn6Nd6Coy/EPEjwcddOsEBo6AwQy9OQDiybVDGVgzmEZrDK49VG5ciyy+E4H6VtxyxW/DSb3b +oakZsIXx/bwFW2jEivUW847nS3iu1MA7+igiLXY/NPMom49v1BH67VTFV+TLCpw4KIANy1OwbXIY +XUswr/nMPcRxZIkSFN3IqHMyDP3apek18DuitdH2ogFKoeaaHMjABdvP+md1JtxJRY7jsapjsaTr +cf/9lCUvoHIHAZHBG1MZxEBwqOxBZYcMWk8GxaSpFXG/aEAdSCRTKoyHXIfvN6GLUYnCRcshS2Ii +lkoJsVOKPlJfhGApHgoDBb2vt52u05OozlcN55jrqm13x8H5xqWHm/7Z2Mzdv5UlaZT/Fi90UyGX +vSCB3ECkm0CgsqiJskiOSUwLSBfahkoRDGEcE7GFFsAjj/ueQzVwME0hog6tiNwp0Jw2PJCPJcWy +m39DWaAtin68d4qu53NdSmkqAspgSx1IJmAcRR3GnU8qcF86SFvx2k/itT+UxZFPJ5M8mORFabSi +BI5MaCx5/ExESaNkmbpo5iku6betHkurkQ/zOU3gLZcAQlejsK41T6C/Wz0xohob48KOlQh9vdCi +kB6KNcwDDyLoHvRKNg9PcMk1QZ6NAL4JDyXkUVyvX0+24g8exZ+dRuCkMUpQsQ6vCyTO1A06W6np +wigmthm0LGr+3hdn4bFnD/GodWsk9ZJJGNqCiI+0mxD/4MiTCwvoJLyK2gQP0jmnbcBBMHVFoHPd +ybFMF0jEdSZa/fOz8/Afu56FKkoJ2VVJFRyZl+dTk+MZ+66RhKjgCd/EPXU8nHQbSZUkaw2VatCI +1jAlyVMCipYT8nIZ8xMHR6vlCtg304DnpoqYt5W5lEpij/YwuoVbu63CNWcZ7CYKQSp/GETmAl23 +QztsPbR7A1lIZ9JQrysByiSP9wZpREI0TKlK9QDWjiagjOnRjx9+Ci7cth5WDBWiZILErz1A2s6H +huslK013Z6nlXd3y4WX4+93iKCCl8KRNJOXT2NEE8gzxEI49DGHLR7IInG1xA0PTpff3PvQkJ6jU +adMymIQps/epCoBAGRzGg1iok2ydUv1hFyF3pXSEuylUlYDLIXh/ipZ3/moXBgkXbLRsH8GRgY6S +gcERMp7f/fhnBwBetwq2rsmBie3+z6cOwBvO3IgSJRVFPSJz4lcadOIrlCiJ+YbzSN0FqnjuXgqk +9YyUTbmYDuV4U8ui8G4yWVux8D6UsuAp34BWo8GNzmRzLPy446Dcgv5RJdGQMdKNYnkQWQCVZoV2 +LyFUzmWxFQnYPzMHlVodBwCjKoGHAxX4gsvCmaTBbiY0QBQPnVYAP/jxPrg9UPdasSIHF29b1yfg +CgYKhM3c5XpBwgvcr9Z98SoRK5obPYFnL42cAshgNe2HEUAemcrRj1cNpqjwxSXXWrXKFhCWaMmq +LCZ2k4mcrM7xRRTVZKhvIODEl++NvEPWyxasB2S2VNOJc8DRznN9LuNadhJOW52CBIlXtipV1BPM +c/SqjoklaRlB15ZFQQnfn4d33aKqpv2J+zHbtJSilh0N0kTdUXZQCbsexOiFtzUDCRjKZ/h833Oh +WikzAAZ1UhDYeD0LLRNHP5vPw659FUWwIXHjucuH0xwxyaYIGLIqo4/WUjyGXBf4XNmkUzKWD+++ ++hTYtGEQVq/MwwRGTwZGymg3tJwIFon3XOmkQTVUBG+12+se27MXaO8F6Rp0ry2UPnQyZ33xVhMO +1VyYxXSCgDqC/WMuSL+pVivgIrBkSdTpBLrpwPAQTFVNuOveA7qEq0Z5JbrC5slB5gUqt5iGmv/q +LrN0xCLoxJt+T8Tt4cAMZSVcfO4yGEerLi+0ouuHip4+k7zweNdgSYgMweXv1XF6f3CmSMErGUZn +K+Zq7zYZTSPmUSolIL/LoUnPtZDAUfIT2VlmB9+xwTy8cHiBfTyMSs1mnTN1mSjA3v0VePDxQ3Dw +YDVWUUT1jZHzykvWwNbJEc0QS5VnZBTVQuDIopC94Ml9TbjtzmejqMuNYJoIYHwsC9vPGOf0xqfU +yCD+0iYjQNfOSaW7UGl5UPOQElyXAPoafr2zl7i3U0SKGkEABepCFJYT2OPJLKYlCesID3/NGaei +VLDh/t3PKtPU16BOPLDrMPz8vhcYvnBkNp0yBNs2DcPp+HrxlpUYFBJHFelikaqCZafgtjt2KYjD +VAUBGZ/IwA3vOBtOXzsCo7k0t4mLcFQ+Jox4sFR76GpkxfQ9upriNIA/Bg2SAR3xNh8nq3jBis1Q +qoTTEmEVoHt7xeZ1cPn5ZyGJWl31cOYF5ojwvYRVy7JQKrXh0HQdHj9URBNXRTNKIzBrZ6VMKYrj +dXK53qpCaG/7DzVBZ8DavXyYmEjDJ268AC7cOslhP9BlX2V9qs7eW4klD8qgZefQbKjSGrdoKwQC +LegZbMAy6MmQpCbkOja4jqKx5qBWsVQ06N3WLRuFP7hwO9z90G6YK9eiqMgh2pAR8Pf+fD/f86d4 +/MzTxyG504Sz14yzOwQytGOhUyHBQB1RVeCZXAOmZp2oIhCWQV573irYvGLwCHcNuJ+dNE/omQTK +InwNfCAsFrZUyu+Nbqfhfk4PW+qLqRFoVGpQdNSNLGPxRHaokIXXnr0pgnmkkIS1qwswkEt0EtFA +WRRZ16OPzcBTB+Y5ILAFoWCM7y3cvT4182iSQchOkGGL9GHlRE7lfRK66u7KwjUVSGW5DRp8lC/V +lssV1SbNHlMGYJp3yx4x+Snc0/FStGqIjOo3LhJx1hxgLdGvXhTfmCDJAtH0z9hUgG2npFFLJaGO +xH/zt5+Eqala2HQGbAFdr9po8XUVhlILUWVJPP+22CRpmLMJGdXAm46vZon5MqSmlTsx/5DEEIKj +WQsBqiFh0/llBGgWRWi71WbbwVNoyp48azo0iR0yvswmNmXcxB9RBZBinodft7wAZB9xJvVoeVxR +VF7voGvOzc7CQnEeZqemwG+V4Lq3n65EH3OI+mWr6fFItjkP9Dinoqmktqv2WsuJOtkv9qkUpcNL +bdZzkpPyQB+jaJyinM1kAKCJAC1gcj6Lech0IwBU2TBoBGgE6ntd9vnD7ugW1niYbNWhBjZuECPD +SDbBqcUCdmSq3MSOBDA5kFaSXoNDPh1AR3cwF8WKpPRdq9mCwqCe2RBBZAkvTFWZpA3NG+FYUcmF +1PaL8+WoVBK1MTIkJUpBdCqYTz+zAHAJRNNiRpgLsgZTaU8KU610QjK3ZpGwXQT2cDVAozDZ0nSU +H+oCKYBOocvQORuN7Gghgxch7YAhsl2FZ4M8bInVk3wdmXypGhmmDjIWYlUAEDqpBVi7pgDPPV/q +zNFR3sRrAzAwoNsdPFzCc5XUCBCoBKYfnnA4se0ApeqW6aTFbRYy1E6Km6R2VcPQnTZ0LqlBormK +EcPmyEoA+j4tNtPJrnb73nrSTKfDQeS79COyJgCFrEWJp9dm5apCNaYqjh8BFCa2lPsVMmlOjMMI +CVEhzVck6od1aRlFGAr7DXTR+fkSNGo1dU9yEdRgdiLJFYD4ogm63srJHKtqrqFHNSVmFXZRBZQR +ozR5BE+EClxZnRau6rz5uCV9B/f30snEKTn0W6pjUzSqNZpsjiplMCCBIO0vt3l0knhOHr+jaW7m +DKFIcXJ0CM7cuApqzTaUqnUoVurQaDs80g696jKSoc2fQG2iueeTNodfyuMCH2UHpjeFQgHTG4sH +zdXgqDqSWr5DREtqmqqjGWxHJm3B+FCa9ZqqLhh6yl1E9SYR6XsFDlVDQ48IoskHBunWOEifxJ+8 +G09I0vAQKHUkzg0rRmEoY0MdO0ucIRlE9Nt6Gfa6DiwbyKFvd6IGdTp0sY2T4yoxRpDnSlWYKpZh +DmUE5YZZ7MhAPsk1JPo8kEuiK6EVYbto0UU+k4pmRrx2EzKZLAi0JB8tqt02OSC4bputslzyYOOa +QVi3cgiWj2ahgPy5ZcsYV0rjel0sMk1NFkORzg06IlYJWK67LMRBmsL9fXjw8wQEoU+jm8eRSesZ +kAaGStDCjpDOmB7khIsjmFFL9UzR1RSaos6lkzxFncW0I4N7Fj870sDvkjCUd7jEQffKp20mUBW+ +0ZKzGa4Vkeuya3p4rpXkkgxFKMelpTc2ZFMZmHn+MFzxuk2wGhPlsZEs3sOG0bEMUoWhgZaxKk93 +SVnoGRwqHasKK7m7x4DpSE/R7Zvx3O1hrjYGPpNok4WVz65Ep5M5JwKMAqS0BfD0diZJ6hT0xOOR +OoZcKYv6yIgRZsXBZBk7MpClwp7NkwdZug6DRBEOyXNgABPkhgoAYSUCO0GcFBgJTGk8QLhQXrRg ++9ZlsGpFAcYRoAJapG0LDvfqfjpgxBendUksFXAcBKfZRlGJ0dvxfB2pORHf0LEkha5BuRWZXg1P +HsllYO/UHI7oII88qWwqxFPt2/QN9nniKUt2z6z22xKmhflQEmAQlTde//WvXA3NhseN87BRLiaG +mWQKR9TVnUNNg5ZYnp/vmlujcvLXv7EbFXUeNm8Ygk1rhxmgiZEcWpnZf+mH6Eiabj2q+kqaikSl +Uvw0j+irmWPR8QwrtvJjX6ixSdjlUz6M5VPcSGpcaJogLfB5/s1UpRGpIktgKi3St6hFc3NI8lmR +BHRO2LJ+hEql7GrcULxfs+jwzOv0XA1m5xqwdds4DCJvtdoqN5M8SAJWI0Cnrh+C9auHMFEmgLKL +ABSjnj7NooyfrIYGisWrq4QsBZAgWugh90UgkZbAAy/id1/A178kZOdqTUg7NgwX8uxqFP7xL48y +uWQ4OmyupGh9ra9Ev3krwROYdDf6/arlA0jUVL0UbNoOmnqt7sB8qQVuCxtaUXy1afUyODgzh9Gx +piIVDs7y8Sy71jCK2QLmg4nE8S8gJu1JeSHlaQoYF7lI8RGRN6jyszu1f99tANsVSIH2fQTorw3L +vhQMuamCIxhQ3gRKZ7Ba5aKcz3VqNZGoxCOZKZVQTFtZk+xas6iIk8q5SVNpm6TdbXNeBtMB5D4m +clNNNubTaknPxskJdvFDhxf42lTGIAFJ5xrm8S4elqpmhNGR1nVSoU3tlBY5UGm5nDHxFJbb/vTH +//SttY+9g0vA8oi5+0/f8ctPJNLpDxAw21Ytg9Xo8wUkakMTu6+nkCnycLJLNWl0yUE0exKgIBZb +GCYWzVNJO9EapOJ8E6ZmalAYS8HkeJ6jHrnrfLkGU5iiNCuA4X6AZUNar9FcaovUeASQowHyeM0A +8S/Ry2H0nBKtqKMF955/zw1vfPmblKP0B4k+JP7hrgfuMG370hVDA3Da5DDmbxjKE5ZeRUv1ZT0l +radzakjmpJmGMXKFSeSRy56PUj0IlIInXqBO0ZoDK1aFNCBcMH8MNiM7tewg1EF4XdJ8Vcr8GSSX +qwBlBK1YbyrP8P1f33nzF99y73dvodVhLl5HGotMfRu3/9On34GdcmbLVTg0X2VTbHDjaerH4udB +KOJRlKOODFJ+h8AVmx5XCoKoHnXsK9CJyLPoTqMYMEbzadZE5FG0K3cHDutLzdyH+Zuv1bOrIxel +V1UEgh7dKNVbsIA5Yknv9J6qMZT5Hz508AsIUPloawF4VcJ9d3yv4jQbPyJifna6CPtmS1CstREs +h8mNACESTmJHqDMUAccy5HKGtopO2A010jE/o4LaRkjBDaEYGtbejSgsi/6lmnAlis5BCaA2A6Tq +VVRyqTY1SLUWr7MqNtqqL4ZaHl06PHOgV1IZS0RO8d93//DjNJ9IpQ/STE8cmIWDxSrMVlvID1Xm +J7ImBiphsSygVWa00kM9daQBOg5qFZ1lprEFW3LRxaEytoyH61l6VoTCexMJuoYAETiUMdBrBUEq +IkBzVbQqfE8WFz7z4rZbP/vSB/9s1/GsdBPf/+Lf768Ui1829JK8qYUK7No/Dbuem4bnZso4Em1o +IYnzOkVDJaqknHl6OhyKJSYF+7tLJyKGVcrONFlnkjEIyyJaAHs8kaCyBVpO2GDecXlFXstRJE2L +VefRG+aRpImLZDgJoqLZw7d+7qPvjBtmaNj9iJuYMqF3kgjmTXc/dL9pmOsDPTPKy/7QekYKWdg8 +OQqDSOpc1hUdwlYVkCB6bIK01tFsSsbWCwSyZ1IyJpnD+raMEXRYR/L0WktONdCSCCACjJbgkOUU +0YIqeBx4UC0GqFGt3v6BKy+8jliCAjgRNhVW1ZoQ2deSgu5nawD+/davv40eJuJFntjQuuuxOU8j +oe+dmmfTJZ3R1NKe6kxs7m7ADeR1kDwTEhx1pWLELYEqX/iahJmIfXUdTrKD2K6nncJzCCRqh6un +p1qhmubkVblXuNaJ3OzAnif+Jdbn0IqCpdYnyV6g7rr5SwcGhscuP+/3rrgDgbKpQWXsPPHPvpl5 +9PEmrBkbxHwvDemEmsfnxyxwxEhTDWZTvFLF0osxDKN/rBM6z6JQ7McqjIu6pHZFP4xoOAiuHkCy +pJar3I0sivY2iWYCRgOkXE3A/ff8cFes377eg6MtLA3NzgzB+vZnPvwEZulXnL/jrT9ApctANSn/ +opmHWgNKlMagMqbFpVRe4edu8ZXEIIk3qhNx6SSJqYRt8uoRo5/gYZUvteV1L5gPuSpyrcjN9Gf8 +jcukrXiIAKJKJ6UbTU8vVhU6eupEulmr/eujP79nIWY9IVBwLCCFu6kJXt762Y8+UZx64eId1173 +DdNOrpdCRRTSRazGZcCjZ7UMrudYvEJEhfAcphkF3HNcV7K5hEKghhVPod2MOkqLQrk6SLMgoGcu +RGdyge5JluJq1wqtjvNAj0K/qg01XVXuobyMznU10QvmToP56Ff/dvvHYsB4eu+aDe2blsQiHy0N +s+MkTvvmc84b+qMbP/y+ofGJt8lwPXZEsp1QbegntLnMgo2i2tQAApXPJDkHI+tioHiZjhFNGFLy +SRqHR1FXL6ncEj7KQeTcRgthl6KVJX7IXcqaHM2LZE1tbV1tDb5KXsnNTKjOF2/64FUXfUSDEids +GZcYS4EkYgDZerdiYBlXXnfjGee/6coPJTPZM2Vs4bmE2JRSrJZDrkm1c8oDKeUg11RPcndmKDg1 +4cjkceeoEVzSTauqJNe4fU+XODyu/4R5JAFEQYKtxpfR+7YGLw5Qq167/cbLz39XzGMIpHavFR0N +pNCa7B5JEIIUvoor3nXD6We/5g1XDY6NXmJaieH4DEkIVnwFP6UZacvmBfJJuwOSmv2VPOJEtHXX +59/RAzXZlMWg2nqSkqzJ4ZRDzdYGEiIpEOomR69JivSQdjEN0Dt73MzVr3C8IEUrU2IWZfWAFXIW +v172J3++dWLlulUTK9ds4QdngkBk8oUVhZHRcyw7OdJRz4r07bAMo2c01EIq5Rqer54GsPT0lm2q +dZQRf+knB4R+0jLQYtOXQWf9tuiQNIniSnGOXOyjPRbUF6DjAakfUGYMMLMHrBAwETvGac7rr377 +5le/+aq3jSxfeWkXl2mLE30n0OOFFogReKe4r9O9zlkiVvQPp6Gc9iO/uOM777r9y5957lgs6KWA +FAcqzk92j+sZfcAyehJGcdVfvP/l2y/ecV22MLC1l8eOFJuiu4iw6NciqtWGK2cD3y+2m437/utH +3/3YHV/7/PM9UduL7XCiQIpzlN3H9YwlwDJieWJ0s1dcumPFqy+7+qJla9ZfjC65rZOCdC/1pebV +y5XHa+WFJ0dXrLwSxaDd6YTvzs9Mf89z3bJhmJKIGbXP/hee3fP4tz71occ0IHIR9wqOpS51vCDF +o57VJ+L14ykRA2mxR/ZZ4u14+3Wn5YdG8/EvaqVi5c6bv/RkPGXa+f6PnEuAYLuDb3z8g/f3CMEg +ppj9JaznmLLulwoSxPjGWoTIzUUsCmJg9avE9T7N3/u+N7fq/dwLTBCzmNB6/OOqilOF4yU+uytj +I2L3qHNzETKPW5OxyHzhYuwj+4Akj9GCjol7TtgzuItsbqwx1jGAFHe7XpBE/8fujgqSv4gleTFO +gv9LkKCngcYSLieOAai+jxH2KeMsZUXH7Va/C5D6gQWxqNcPqKWsSS4C1GIAxbnnhP//1074/4mr +x03cHiB6rWgpbloMoF7i9uEkbxac/C3uLn6/CYejzDnJPtf5nW7/K8AApe+Lw1SaFQIAAAAASUVO +RK5CYII=</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>70</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>7700</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>73</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/check-selected.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/check-selected.png.xml new file mode 100644 index 0000000000..749c57c63e --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/check-selected.png.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210769.7</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>check-selected.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ +bWFnZVJlYWR5ccllPAAAAvBJREFUeNq8lb9rFEEUx9/M7h5nTkEJItaKrWCljWBhYxotPCXEXwFF +RJSUxotETby7/8BCQSGEIwpiITaxUkG00CagIbamEIxocjF3uzO+92Z2b3b3thHicu/ezuzM5/vm +1xuhtYbNfIQrsG/36T3oJtFG/pE3Q/0Xl1tfcwIIP6m0mguFBu17AJ4HWgpsgWa9Fm5k+Ed9lTY+ +ikB2I/AVNZdVFHmSCFDkCF8KEaQD34A9AkuGclmKfLwIF2QkppAc4XsYQtBVJLKXRuLbphMUOZTK +4JW3gVcaAO0hnETQc/Q8Co6JQuefSKJXIBCuOm2INn5BqNahpGACG56XVuAclCsQVHYivIKjwOnx +8RN7D5T1bIFM3uN6arf0sQkSGaWBXaAHthomPrEABOVBjpYB7BHgSxZiC5z3THnx7TQNAr58aHB9 +actgMouJAPjCgGkd/DQMyLy4bEfnmfrP87chjCCxhXcN5iTYnpSdc994bRcZrCi4a0xrgm7hWQ26 +Ufoc7T9SMxskK2B2DsGkARfB7fPp6U2Ep+sOHJsEgf2EpwsE7G6Jt2UR/H1rHDphOvJD1emknxCi +zxokQNPodavWF/5mhuCQsoPDdT5v4ASZF4i3ONr8bA02MMJXj26kPlOZ6l07fBbhSE9OuWX0F8Av +L2ZvpaJ7+cCIkM9GfnS0wfB44XvwohHg3hgavpMDPb+fhw9dcuBg85I2h9z+9RGwDY6PTvEiFtmJ +Kxl4nPwcRl7AJq44Q1Yv34MObsOsnbrWzMEhk1mF6jMC4Xzkd7SRq3U+SLGdGesPj9sLN8jcCDCf +c1aktBsbli9cb3AKGG8+LIZHvT7UX2PKzgo81r9XOOVirmXP71bk4lgdlr99t1Ngp5PbqASe9KH+ +P1eY6QrcFX/aAO1VM0xq5Bh14tFxOTJ1kanPtV1bA7G+ysz8lSnEnC5jLt++g69MTnxS9k646N03 +8cKaecdp6YYY+Q8QGKTUOn1l/pdLf7OevwIMAAwmFRODEQ87AAAAAElFTkSuQmCC</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>24</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>846</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>24</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/lines.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/lines.png.xml new file mode 100644 index 0000000000..c7a8f5bc5b --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/lines.png.xml @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210938.71</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>lines.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAASwAAADICAYAAABS39xVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ +bWFnZVJlYWR5ccllPAAADZtJREFUeNrsneluFEcURidjY8y+Zyd5/8ci7FkgCdmMMUqHSJFRZty1 +3LXqILV0fiLP6NN3bt2u+eTZs6fbzWbzfvPvPy8+WJ4zAT5cnneNfGl5Tlf4aHneVvDl5TlZ4ePl ++WuFryzPnyt8dXn+WOFry/P7Cl9fnt8q+MbyvFnhm8vz6wrfWp5fVvj28vy8wneW5/UK312eVzv4 +3vL8tML3l+fHHfxgeX5Y4U+X5/sV/mx5Xq7w58vzYgd/sTzPd/CXy/Nshb9anqc7+OvlebLCD5fn +8Q7+Znm+E+Bvl+eRZ0BphNWBclhdqgyrI6GwOi4IqytCYXWtMqyuC4XVzYKwulUQVrcLwurOnrC6 +ey6U7l4QXD/uCa4fCoLr+4LgelkQXC/2BNfzPcH1rCC4nu4JricFwfV4T3CJhtU/vB0orHpa1mlF +cEm2rL8qgqu3Zf3uFFy/7mCp4LqlFFyvBILrfkFwPegIrs8VguurgMH16HxwbZ1b1plCcGVrWaXB +VdOyrgQMrjcKwVWiiq8LQkwjuKTa11rLkmxcTwWC66FCcA2rhBlblvQsK0LjumEcXCWNq2TGlTG4 +WudaPcHV0rJ65lphlDBayyoNrsgtq2aupRVcb5wbVwRVvLfxaVz7WpZk4/LQwxBKqBlc2ieGWYLr +qmNw/ZYguLRU8adgwbWmitEH8mGUMNqJYRY9lJxrZQ4uixPGEYPL8iRRbK61HTSsoraskrDSOD2M +ooqtwaUx7+oJrjsDBJflSaLYXCuiEkrqoXZY1bask4rgkmxZEsF11TG4vAb1rQuoUsF1P2BwaQzk +i1tWNCWMooenlcHlNcuSCK7SGZfVAmqmQX1N49I6YYwWXKp6GE0JZ1p1iBJcf1QGl7YqZtjpirga +kSW4HvcE18inhNFPDDXnWpbBVauKnvOukkF95C36kvcWRwmuNEoYaZYVpWVFDq5og3rNeVe0139q +g0t76VR9rrUNFlaaejhCy6odyEsE15XAwXU9YXDd2fi8tyjZsp57zbW2m9gtK+NeltYQvqdlWZ4q +SgRX9MXUnuB6rRBctaqYVg9nOSWMvOowU3Bl2u/S3qLXCK61xpV1rhVeCSMO4bVb1gzBlXHeFeme +rt7GlWEgf6EeRlXCUVrWbMEVURulg8vzhFFqOC8RXLW3m5YO5C/Uw8hhNULL6tHD1oG8Z3C1LqO2 +BFeWGyRGCa4QehhZCWcewve0rFEa12g3SGQLLks9LF572CYIq5mH8BLBdSwUXLPPu6yC67ZTcHnO +tZ6UNq4sYTX7EF5CD3sbV8b2pTHvinRrhGRwaQ7kpX6pJ40SZr/oL4IengQLrshLqiXzLqk7uzSu +dK4JLsm5Vu1dW9VzrW2ysNK8ycHiVgfp4DoaLLg83m20/FWgCKooOZCX0MOq+7VmD6vzLcvj9NBT +FTW08U+FENOefVlqY4TG5T2Q77pfa0tYdZ8Y9uih90AebezXRq15l/SlgpIniW56mE0JNW5y8Fp1 +kG5ZkqqINuYNLo25VslJosnaQ1YlzH4PvHZwaQ7qI2ujVvsq0Uar4LplEFzR5lpplVB7vcGzZWUJ +Ls325Tn7qtHGCKsRGo0r+lzrSdZTwsg3lEoF11HC4IoYYt6Nq/eE0VIVpRdNxedaWcMq8ms7kfVQ +O7hGWlj1GNRrz7gkB/JWevhRcG2Th1XUWZaGHmqromWIZWpflsGl3bisFk3VtuK3hJVqy5IMLtrX +eL/PaNW4rOdaanqIEhJctC+beVdP46rdnI841xI5PUQJCa5oIRahfWnMuzSCS3MFQus9xK7TwxGU +0KJlSc21RgqujCEWYd5lGVw9jUt6X0tED0cIq4wt651CWFkO6iPNwQgu3ZPE1rmWih6OooS0rPjt +K+IAX3velSG4tOZaKqeHoyhh5pZ1PrgOJwguS4W0nHf1njB6BZf0QF7q9xB3tqyRwsri5Wjt4Hrn +EFyeIfY2QXAdb+QH9ZaNS+MksXeu1fojF0MpoUfjOlQOLgtVPA0aXJFf3O5tXxKNq3R3y2OuVXLb +Q4seDqeEXno4gipmaF8at61e3sTSxtLgijzXUlsuHTWsrPXQShWtG1e09qVx2+pJoOC6FiS4pN5D +FD89HF0JrRuXtiqeBgquaOsTnnfdS6uiV3BJvYeodnq4nSSsRmpZUYIrSxMjuMoH8lIvUEucHu7U +w1nCyqNlWQbXYeDgGmGYrxlcVw2DS3uupa6HKOEYwZWtfUVRS+1BvdQ6ROsNqNZzLXU9RAnzz7Uy +Ble0hqatjdqq6LWvZa6HKOGYLSuLNo50D1j24EqhhzMpoeeqg1fLGjXEtHVSe94lMePynGu56eFM +Smj1M2ERWxZNzD7EtGdcPdvyXmsP3Xo4W1hFmGVFD67Rm5j1wqr0e4u1jUtyIG+1Fb9XD2dTwqjB +lT3EMoWbVIhpNK6S9hVhIC/x0nTTL/JsJw2raMG1a8aVKcRaw200hZQOLq+BvMVcq+nK5dnDKnLj +OkseVhkDTbp99e50WZ0ker7OU/XS9JawCrP2kH3eNeoMzWpN4tgwuLRf51Fbe0AJ4+phybzrgBAz +C7QMjat0IK+9r6W29kBY5Quu86p4NllYRWhlHq8CRRzIu6w9oIS59HBNFQ8ILrMQszphzDSQb73t +oVgPUcLcLWvfoP6AECsOsQiD+p6Wpd24LOZaxb+BSEDlblkz7H3N0L4k1iEsB/Jur/OghGO0LM0Q +m1E/MwZX60liqtd5UMIcL01H1MyziYLrcKDgst7XEl17IJRQRcvVixHWMyIFl/arPZav8xTpIUpI +WLFvlje4tOdalq/zFOkhSshca+QWN1JwWehh+LkWQURwzRBu0eddXnOtLGsP/821UEKdgTyBhmZe +GjS4XF/nQQnHutEUjrOf1tq4og3kta+pqdJDQgZVhG10MstAXvJ1HnE9RAnZ3YJt2le0k0SvuVar +Hn4ILpSQdQjY9pePspwkhpxrESaoIjxO4xp+roUSElzweI0r0lxLdO0BJWTGBccYzksHV2Q9bN6K +J0Dity8CjeBqWYGw2tcy3YpHCeO3L4b2BJfHXMtr7eHC2x5QwthLp2thVdK+aGjjD+ejrj30/Or0 +Tj0kKOLPtS4KnJL2RUPL376kNuQj6mHV6SFKyIxLs4mVBO9sDRA9LNfD/7UslHCcGVevHr4XCJyL +/m/7/p81DbP2dDViGM6qhyJb8YTAXGr5XjhwtIJXqnmO+IveWdYerm0U1h5QQgJtpuY5QuOyWnuI +tlz6IbhQQpjQZq7lfXpYfFc8X2AY9g+xnhWIjFvxzaeHKCEMx7thw3rtQVsPxbbiUUIYbt+L02pi +LJfu0UO+nDDc3r7eBwou7dPDCFfT3EAJYTj++54RTg8jXLn8BiWE4Rx3nbFcyhcMhtME1wynh6tr +DyghDOc5YZz+9BAlhGFaVho95AsGwwRXhNPDIj1ECWE4Z3BF0cPW08OmtQeUEIZzzrWy62HT2gNf +JBi2b1nbTdzl0p6bS9X1ECWE4fyNK3rLEtNDlBCG0UPJlqWqh3x5YBg9tLwfvksPUUIYRg8z6OGH +4EIJYXistYfs98NfuBXPFwaGaVler/BU6yFKCMNzt6xUeogSwjCnhxIty0QP+ZLA8JgtK9oQXkQP +UUIYRg8j3KNVpIcoIQwzhJfWw5OO4LpQD/liwDCzrDR6iBLCMPdoRdvR2quHKCEMc81ya8sy10O+ +GDBMy0qjhyghDNOyIu9ofRRcKCEM07KitKzV4OKLAcNzBpdGy1LXQ5QQhll1sBzCd717iBLCMC3L +o2U1zbX4MsDwvMGl2bJU5looIQyjhxotS+r08AQlhGHCqlUPTz1PD/kCwDBh1aKH0jtaRcGFEsIw +v7bTOoSXbFlFwYUSwjCNy6JliZwe8qHDMGGVZkcLJYRh1hvS6CFKCMO0LImwMtFDPnQYJqykZlnq +eogSwjAnhhla1hFKCMNjtCzNE8Mor/C85UOHYQbv3kP4quBCCWGYWVYEPSyaa6GEMEzLijKEX21Z +fOgwTMtK07JQQhimZaVpWSghDBNcaYKLDxqGCa40wYUSwjBzLY+5VlNwoYQwTMvyaFlNA3k+XBim +ZaVpWSghDBNW3i2rOLhQQhhGCb1bVrEe8uHCMC0rTctCCWGYlpUmuFBCGCa40pwe8oHCMHqYZrkU +JYRhWlaa4EIJYZiWleEkESWE4YnDKuVAHiWE4TmV0KNxde9roYQwzCzLumU1Ny4+RBgmuNLMtVBC +GIbTnB6ihDAMe7asquDiw4JhOI0eooQwDEdqWQcoIQzDGVrWauPiw4JhOErLWp1roYQwDO9qWduI +wYUSwjCcQRVRQhiGc6kiSgjDcJqBPEoIw3CalsUHAcMwSgjD8PCnh+aqiBLCMNzauMzbF398GIbT +DOFRQhiG01y5jBLCMCwx1zJpX/zxYRhOc6qIEsIwnEYVUUIYhtOoIn9kGIbTqCJKCMNwmutrUEIY +htOEGH80GIbTLKaihDAMpwkulBCG4TSDev4gMAynmXGhhDAMp2GUEIbhNMwfAYbhNIwSwjCMEsIw +DKOEMAyjhPxBYBhGCWEYhlFCGIZRQhiGYZQQhmEYJYRhGCWEYRhGCWEYhlFCGIZRQhiGYZQQhmEY +JYRhGCWEYRhGCWEYhlFCGIZH4r8FGAC7SCQOa4wLsAAAAABJRU5ErkJggg==</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>200</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>3577</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>300</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-down.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-down.png.xml new file mode 100644 index 0000000000..4b7400e3bc --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-down.png.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210885.63</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>scroll-down.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAA +AAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oECBcmNcNB6TQAAAAidEVYdENv +bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVAgb24gYSBNYWOHqHdDAAAAYUlEQVQY083QIRKDYBCD0azn +ElwMyU3Q9T0Dd8JwB+TD/IOgFERN43bmy2yS5C9USYI+yfuGG6tqOS7MrjV/WNFjO4Fb+5orw3SC +p6/B0GFt4IrutjGGBg+P86DwQv208w5Vk3NaFii+RwAAAABJRU5ErkJggg==</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>11</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>271</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>11</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-left.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-left.png.xml new file mode 100644 index 0000000000..4ee4c14b1d --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-left.png.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210900.0</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>scroll-left.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAA +AAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oECBcvHr4/qz0AAAAidEVYdENv +bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVAgb24gYSBNYWOHqHdDAAAAS0lEQVQY063QsQmAMBCG0di7 +RMCxHMfeTVwiuziC7bOwCpxioq/+OI4/pb9gehNlbChP0YgFh0uJogEzdrUwXsU+Xm76uWuNrp3v +nLqfjttDMYDKAAAAAElFTkSuQmCC</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>11</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>249</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>11</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-right.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-right.png.xml new file mode 100644 index 0000000000..0bd79bc122 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-right.png.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210912.76</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>scroll-right.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAA +AAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oECBcvBTRaYtEAAAAidEVYdENv +bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVAgb24gYSBNYWOHqHdDAAAARklEQVQY063QsQ2AMBAEwSen +CSSXRTnk7oQm6IUSSIfI+YG88eh1+qq/oX3BF05sKYYHB9YEj27sWBI86tMux5vjb7Sa1Qu2gI7b +PwSb/gAAAABJRU5ErkJggg==</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>11</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>244</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>11</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-up.png.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-up.png.xml new file mode 100644 index 0000000000..cedce0e9e1 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/images/scroll-up.png.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="Image" module="OFS.Image"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts81210924.98</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>scroll-up.png</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>image/png</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> <string encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAA +AAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oECBckIeutX8sAAAAidEVYdENv +bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVAgb24gYSBNYWOHqHdDAAAAXUlEQVQY083Nuw2AIBhF4fsn +liTMwGJsQ+0ijOAuNuxAeSiUQoOPxMZTf7lX+hJgwAzYGxzZik/QAWXHBXB3OHEsXcEA1BOuQBjh +zLjczdRXJXlJy+DUA8HMVv2jBsm9dlXl5Y2nAAAAAElFTkSuQmCC</string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>11</int> </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>267</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>11</int> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/theme.less.xml b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/theme.less.xml new file mode 100644 index 0000000000..88396d4bf9 --- /dev/null +++ b/bt5/erp5_bespin/SkinTemplateItem/portal_skins/erp5_bespin/resources/screen_theme/theme.less.xml @@ -0,0 +1,307 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="DTMLDocument" module="OFS.DTMLDocument"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>__name__</string> </key> + <value> <string>theme.less</string> </value> + </item> + <item> + <key> <string>_vars</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>globals</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>raw</string> </key> + <value> <string>/* ***** BEGIN LICENSE BLOCK *****\n + * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n + *\n + * The contents of this file are subject to the Mozilla Public License Version\n + * 1.1 (the "License"); you may not use this file except in compliance with\n + * the License. You may obtain a copy of the License at\n + * http://www.mozilla.org/MPL/\n + *\n + * Software distributed under the License is distributed on an "AS IS" basis,\n + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n + * for the specific language governing rights and limitations under the\n + * License.\n + *\n + * The Original Code is Bespin.\n + *\n + * The Initial Developer of the Original Code is\n + * Mozilla.\n + * Portions created by the Initial Developer are Copyright (C) 2009\n + * the Initial Developer. All Rights Reserved.\n + *\n + * Contributor(s):\n + * Bespin Team (bespin@mozilla.com)\n + *\n + * Alternatively, the contents of this file may be used under the terms of\n + * either the GNU General Public License Version 2 or later (the "GPL"), or\n + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\n + * in which case the provisions of the GPL or the LGPL are applicable instead\n + * of those above. If you wish to allow use of your version of this file only\n + * under the terms of either the GPL or the LGPL, and not to allow others to\n + * use your version of this file under the terms of the MPL, indicate your\n + * decision by deleting the provisions above and replace them with the notice\n + * and other provisions required by the GPL or the LGPL. If you do not delete\n + * the provisions above, a recipient may use your version of this file under\n + * the terms of any one of the MPL, the GPL or the LGPL.\n + *\n + * ***** END LICENSE BLOCK ***** */\n +\n +.bespin {\n + .container {\n + font-family: @container_font;\n + font-size: @container_font_size;\n +\n + color: @container_color;\n + background: @container_bg;\n + line-height: @container_line_height;\n +\n + display: -moz-box;\n + -moz-box-orient: vertical;\n + display: -webkit-box;\n + -webkit-box-orient: vertical;\n + width: 100%;\n + height: 100%;\n + margin: 0;\n + }\n +\n + .container .north {\n + -moz-box-ordinal-group: 1;\n + -webkit-box-ordinal-group: 1;\n + }\n +\n + .container .center-container {\n + display: -moz-box;\n + -moz-box-orient: horizontal;\n + -moz-box-ordinal-group: 2;\n + -moz-box-flex: 1;\n + display: -webkit-box;\n + -webkit-box-orient: horizontal;\n + -webkit-box-ordinal-group: 2;\n + -webkit-box-flex: 1;\n + }\n +\n + .container .south {\n + -moz-box-ordinal-group: 3;\n + -webkit-box-ordinal-group: 3;\n + }\n +\n + .container .center-container .west {\n + -moz-box-ordinal-group: 1;\n + -webkit-box-ordinal-group: 1;\n + }\n +\n + .container .center-container .center {\n + -moz-box-flex: 1;\n + -moz-box-ordinal-group: 2;\n + -webkit-box-flex: 1;\n + -webkit-box-ordinal-group: 2;\n + }\n +\n + .container .center-container .east {\n + -moz-box-ordinal-group: 3;\n + -webkit-box-ordinal-group: 3;\n + }\n +\n + input, textarea {\n + display: block;\n + border: 0px;\n + width: 200px;\n + padding: 4px;\n + color: @control_color;\n + background: @control_bg;\n + border: @control_border;\n + font-size: 8pt;\n + -moz-border-radius: @control_border_radius;\n + -webkit-border-radius: @control_border_radius;\n + box-shadow:\n + rgba(255,255,255,0.3) 0px 0px 2px,\n + inset rgba(0,0,0,0.3) 0px 0px 4px;\n + -moz-box-shadow:\n + rgba(255,255,255,0.3) 0px 0px 2px,\n + inset rgba(0,0,0,0.3) 0px 0px 4px;\n + -webkit-box-shadow:\n + rgba(255,255,255,0.3) 0px 0px 2px,\n + inset rgba(0,0,0,0.3) 0px 0px 4px;\n + }\n +\n + input:focus, textarea:focus {\n + color: @control_active_color;\n + border: @control_active_border;\n + background: @control_active_bg;\n + outline: none;\n + box-shadow: opacity(@control_active_inset_color, 0.6) 0px 0px 2px,\n + inset opacity(@control_active_inset_color, 0.3) 0px 0px 6px;\n + -moz-box-shadow: opacity(@control_active_inset_color, 0.6) 0px 0px 2px,\n + inset opacity(@control_active_inset_color, 0.3) 0px 0px 6px;\n + -webkit-box-shadow: opacity(@control_active_inset_color, 0.6) 0px 0px 2px,\n + inset opacity(@control_active_inset_color, 0.3) 0px 0px 6px;\n + }\n +\n + input[type=submit], input[type=button] {\n + font-family: @button_font;\n + font-size: @button_font_size;\n + text-shadow: 1px 1px rgba(0, 0, 0, 0.4);\n +\n + padding: 8px 12px;\n + margin-left: 8px;\n + color: @button_color;\n + background: transparent -moz-linear-gradient(top, @button_bg, @button_bg2);\n + background: transparent -webkit-gradient(linear, 50% 0%, 50% 100%, from(@button_bg), to(@button_bg2));\n +\n + border: 1px solid @button_border;\n + -moz-border-radius: @control_border_radius;\n + -webkit-border-radius: @control_border_radius;\n + -moz-box-shadow:\n + inset rgba(255, 255, 255, 0.2) 0 1px 0px,\n + inset rgba(0, 0, 0, 0.2) 0 -1px 0px,\n + rgba(0, 0, 0, 0.1) 0px 1px 2px;\n + -webkit-box-shadow:\n + inset rgba(255, 255, 255, 0.2) 0 1px 0px,\n + inset rgba(0, 0, 0, 0.2) 0 -1px 0px,\n + rgba(0, 0, 0, 0.1) 0px 1px 2px;\n + box-shadow:\n + inset rgba(255, 255, 255, 0.2) 0 1px 0px,\n + inset rgba(0, 0, 0, 0.2) 0 -1px 0px,\n + rgba(0, 0, 0, 0.1) 0px 1px 2px;\n + }\n +\n + .pane {\n + font-size: @pane_font_size;\n + font-family: @pane_font;\n + border-top: 1px solid rgba(255,255,255,0.1);\n + border-left: 1px solid rgba(0, 0, 0, 0.1);\n + border-right: 1px solid rgba(0, 0, 0, 0.1);\n + border-bottom: 2px solid rgba(0, 0, 0, 0.1);\n + background-color: @pane_bg;\n + overflow: visible;\n + padding: 15px;\n +\n + color: @pane_color;\n + line-height: @pane_line_height;\n +\n + margin-bottom: 6px;\n + margin-top: 6px;\n + text-shadow: @pane_text_shadow;\n +\n + -moz-border-radius: @pane_border_radius;\n + -webkit-border-radius: @pane_border_radius;\n + -moz-box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;\n + -webkit-box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;\n +\n + a {\n + color: @pane_a_color;\n + }\n +\n + h1 {\n + font-family: @pane_h1_font;\n + font-size: @pane_h1_font_size;\n + color: @pane_h1_color;\n +\n + letter-spacing: -1.25px;\n + line-height: 1.0;\n + margin-top: 0px;\n + margin-left: 10px;\n + margin-bottom: 25px;\n + margin-top: 10px;\n + text-shadow: @pane_text_shadow;\n + }\n +\n + p {\n + margin-left: 10px;\n + }\n + }\n +\n +\n + .form {\n + font-family: @form_font;\n + font-size: @form_font_size;\n + line-height: @form_line_height;\n + color: @form_color;\n + text-shadow: @form_text_shadow;\n +\n + fieldset, p {\n + color: @form_color;\n + margin-bottom: 6px;\n + margin-top: 6px;\n + text-shadow: form_text_shadow;\n + }\n + }\n +\n + /*\n + * The state classes are a little bit complex, because of the doubble class bug in IE6\n + * The state class looks like this:\n + *\n + * .ui-radio-state[-checked][-disabled][-hover] or .ui-checkbox-state[-checked][-disabled][-hover]\n + *\n + * Examples:\n + *\n + * .ui-radio-state-checked (simply checked)\n + * .ui-radio-state-checked-hover (checked and hovered/focused)\n + * .ui-radio-state-hover (unchecked and hovered/focused)\n + *\n + * If you don´t have to deal with the doubble class bug of IE6 you can also use the simple ui-checkbox-checked, ui-checkbox-disabled, ui-checkbox-hover state-classnames (or: ui-radio-checked...)\n + * and the ui-radio/ui-checkbox role-classnames.\n + *\n + */\n +\n + span.ui-checkbox,\n + span.ui-radio {\n + display: block;\n + float: left;\n + width: 24px;\n + height: 24px;\n + background: url(images/radio-unselected.png) no-repeat;\n + }\n +\n + span.ui-checkbox {\n + background: url(images/check-unselected.png) no-repeat;\n + }\n +\n + span.ui-helper-hidden {\n + display: none;\n + }\n +\n + span.ui-checkbox-state-checked,\n + span.ui-checkbox-state-checked-hover {\n + background: url(images/check-selected.png) no-repeat;\n + }\n +\n + span.ui-radio-state-checked,\n + span.ui-radio-state-checked-hover {\n + background: url(images/radio-selected.png) no-repeat;\n + }\n +\n + .ui-helper-hidden-accessible {\n + position: absolute;\n + left: -999em;\n + }\n +}\n +\n +</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_bespin/bt/categories_list b/bt5/erp5_bespin/bt/categories_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/change_log b/bt5/erp5_bespin/bt/change_log new file mode 100644 index 0000000000..790d60448b --- /dev/null +++ b/bt5/erp5_bespin/bt/change_log @@ -0,0 +1,2 @@ +2010-08-15 rafael +* The initial version. \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/comment b/bt5/erp5_bespin/bt/comment new file mode 100644 index 0000000000..276b686247 --- /dev/null +++ b/bt5/erp5_bespin/bt/comment @@ -0,0 +1 @@ +Still Experimental \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/copyright_list b/bt5/erp5_bespin/bt/copyright_list new file mode 100644 index 0000000000..fe948b9fb7 --- /dev/null +++ b/bt5/erp5_bespin/bt/copyright_list @@ -0,0 +1 @@ +Copyright (c) 2010 Nexedi SA \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/dependency_list b/bt5/erp5_bespin/bt/dependency_list new file mode 100644 index 0000000000..db80eea7f7 --- /dev/null +++ b/bt5/erp5_bespin/bt/dependency_list @@ -0,0 +1 @@ +erp5_view_style \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/description b/bt5/erp5_bespin/bt/description new file mode 100644 index 0000000000..7e1cc3ce0b --- /dev/null +++ b/bt5/erp5_bespin/bt/description @@ -0,0 +1 @@ +Files for integration of Bespin Text Editor (http://mozillalabs.com/bespin) with ERP5 \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/license b/bt5/erp5_bespin/bt/license new file mode 100644 index 0000000000..3a3e12bcad --- /dev/null +++ b/bt5/erp5_bespin/bt/license @@ -0,0 +1 @@ +GPL \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/maintainer_list b/bt5/erp5_bespin/bt/maintainer_list new file mode 100644 index 0000000000..23a62fbb45 --- /dev/null +++ b/bt5/erp5_bespin/bt/maintainer_list @@ -0,0 +1 @@ +rafael \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/provision_list b/bt5/erp5_bespin/bt/provision_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/publication_url b/bt5/erp5_bespin/bt/publication_url new file mode 100644 index 0000000000..4af18322e3 --- /dev/null +++ b/bt5/erp5_bespin/bt/publication_url @@ -0,0 +1 @@ +None \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/revision b/bt5/erp5_bespin/bt/revision new file mode 100644 index 0000000000..9d607966b7 --- /dev/null +++ b/bt5/erp5_bespin/bt/revision @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/template_action_path_list b/bt5/erp5_bespin/bt/template_action_path_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_base_category_list b/bt5/erp5_bespin/bt/template_base_category_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_datetime_key_list b/bt5/erp5_bespin/bt/template_catalog_datetime_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_full_text_key_list b/bt5/erp5_bespin/bt/template_catalog_full_text_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_keyword_key_list b/bt5/erp5_bespin/bt/template_catalog_keyword_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_local_role_key_list b/bt5/erp5_bespin/bt/template_catalog_local_role_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_method_id_list b/bt5/erp5_bespin/bt/template_catalog_method_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_multivalue_key_list b/bt5/erp5_bespin/bt/template_catalog_multivalue_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_related_key_list b/bt5/erp5_bespin/bt/template_catalog_related_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_request_key_list b/bt5/erp5_bespin/bt/template_catalog_request_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_result_key_list b/bt5/erp5_bespin/bt/template_catalog_result_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_result_table_list b/bt5/erp5_bespin/bt/template_catalog_result_table_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_role_key_list b/bt5/erp5_bespin/bt/template_catalog_role_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_scriptable_key_list b/bt5/erp5_bespin/bt/template_catalog_scriptable_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_catalog_topic_key_list b/bt5/erp5_bespin/bt/template_catalog_topic_key_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_constraint_id_list b/bt5/erp5_bespin/bt/template_constraint_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_document_id_list b/bt5/erp5_bespin/bt/template_document_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_extension_id_list b/bt5/erp5_bespin/bt/template_extension_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_format_version b/bt5/erp5_bespin/bt/template_format_version new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/bt5/erp5_bespin/bt/template_format_version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/template_local_role_list b/bt5/erp5_bespin/bt/template_local_role_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_local_roles_list b/bt5/erp5_bespin/bt/template_local_roles_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_message_translation_list b/bt5/erp5_bespin/bt/template_message_translation_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_module_id_list b/bt5/erp5_bespin/bt/template_module_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_path_list b/bt5/erp5_bespin/bt/template_path_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_allowed_content_type_list b/bt5/erp5_bespin/bt/template_portal_type_allowed_content_type_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_base_category_list b/bt5/erp5_bespin/bt/template_portal_type_base_category_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_hidden_content_type_list b/bt5/erp5_bespin/bt/template_portal_type_hidden_content_type_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_id_list b/bt5/erp5_bespin/bt/template_portal_type_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_property_sheet_list b/bt5/erp5_bespin/bt/template_portal_type_property_sheet_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_role_list b/bt5/erp5_bespin/bt/template_portal_type_role_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_roles_list b/bt5/erp5_bespin/bt/template_portal_type_roles_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_portal_type_workflow_chain_list b/bt5/erp5_bespin/bt/template_portal_type_workflow_chain_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_preference_list b/bt5/erp5_bespin/bt/template_preference_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_product_id_list b/bt5/erp5_bespin/bt/template_product_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_property_sheet_id_list b/bt5/erp5_bespin/bt/template_property_sheet_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_registered_skin_selection_list b/bt5/erp5_bespin/bt/template_registered_skin_selection_list new file mode 100644 index 0000000000..3b0002a93a --- /dev/null +++ b/bt5/erp5_bespin/bt/template_registered_skin_selection_list @@ -0,0 +1 @@ +erp5_bespin | View \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/template_role_list b/bt5/erp5_bespin/bt/template_role_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_site_property_id_list b/bt5/erp5_bespin/bt/template_site_property_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_skin_id_list b/bt5/erp5_bespin/bt/template_skin_id_list new file mode 100644 index 0000000000..91f4c19fdc --- /dev/null +++ b/bt5/erp5_bespin/bt/template_skin_id_list @@ -0,0 +1 @@ +erp5_bespin \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/template_test_id_list b/bt5/erp5_bespin/bt/template_test_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_tool_id_list b/bt5/erp5_bespin/bt/template_tool_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/template_update_business_template_workflow b/bt5/erp5_bespin/bt/template_update_business_template_workflow new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/bt5/erp5_bespin/bt/template_update_business_template_workflow @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/template_update_tool b/bt5/erp5_bespin/bt/template_update_tool new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/bt5/erp5_bespin/bt/template_update_tool @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/template_workflow_id_list b/bt5/erp5_bespin/bt/template_workflow_id_list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bt5/erp5_bespin/bt/title b/bt5/erp5_bespin/bt/title new file mode 100644 index 0000000000..91f4c19fdc --- /dev/null +++ b/bt5/erp5_bespin/bt/title @@ -0,0 +1 @@ +erp5_bespin \ No newline at end of file diff --git a/bt5/erp5_bespin/bt/version b/bt5/erp5_bespin/bt/version new file mode 100644 index 0000000000..9f8e9b69a3 --- /dev/null +++ b/bt5/erp5_bespin/bt/version @@ -0,0 +1 @@ +1.0 \ No newline at end of file -- 2.30.9